diff --git a/.env b/.env
new file mode 100755
index 0000000..9323cbf
--- /dev/null
+++ b/.env
@@ -0,0 +1,60 @@
+APP_DEBUG = true
+DEV_MODE = false
+
+[APP]
+DEFAULT_TIMEZONE = Asia/Shanghai
+
+[DATABASE]
+TYPE = mysql
+HOSTNAME = "127.0.0.1"
+DATABASE = "zhncxt"
+USERNAME = "zhncxt"
+PASSWORD = "zhncxt"
+
+
+
+#HOSTNAME =
+#DATABASE =
+#USERNAME =
+#PASSWORD =
+HOSTPORT = 3306
+CHARSET = utf8mb4
+DEBUG = true
+PREFIX = ims_
+
+[LANG]
+default_lang = zh-cn
+
+[CACHE]
+driver = redis
+host = 127.0.0.1
+passwd =
+prefix = longyiyi_
+expire = 0
+
+[SESSION]
+NAME = longyiyiSession
+TYPE = redis
+EXPIRE = 3600
+PREFIX = longyiyiSession_
+
+[RABBIT]
+RABBIT_HOST = 127.0.0.1
+RABBIT_PORT = 5672
+RABBIT_LOGIN = guest
+RABBIT_PASSWORD = guest
+RABBIT_VHOST = 'longyiyi'
+RABBIT_QOS_LIMIT = 1
+EXCHANGE_NAME = longyiyi_exchange
+QUERY_NAME = longyiyi_query
+KEY = key
+
+[SCHEDULER]
+
+[swoole]
+port = 8001
+host = 0.0.0.0
+daemonize = false
+
+[log]
+channel = file
diff --git a/.env.example b/.env.example
new file mode 100755
index 0000000..74581d9
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,53 @@
+APP_DEBUG = true
+
+[APP]
+DEFAULT_TIMEZONE = Asia/Shanghai
+
+[DATABASE]
+TYPE = mysql
+HOSTNAME = "127.0.0.1"
+DATABASE = "longbingtest"
+USERNAME = "longbingtest"
+PASSWORD = "123"
+#HOSTNAME =
+#DATABASE =
+#USERNAME =
+#PASSWORD =
+HOSTPORT = 3306
+CHARSET = utf8mb4
+DEBUG = true
+PREFIX = ims_
+
+[LANG]
+default_lang = zh-cn
+
+[CACHE]
+driver = redis
+host = 127.0.0.1
+passwd =
+prefix = longbing_
+expire = 0
+
+[SESSION]
+NAME = lonngbingSession
+TYPE = redis
+EXPIRE = 3600
+PREFIX = LongBingSession_
+
+[RABBIT]
+RABBIT_HOST = 127.0.0.1
+RABBIT_PORT = 5672
+RABBIT_LOGIN = guest
+RABBIT_PASSWORD = guest
+RABBIT_VHOST = '/'
+RABBIT_QOS_LIMIT = 1
+EXCHANGE_NAME = longbing_exchange
+QUERY_NAME = longbing_query
+KEY = key
+
+[SCHEDULER]
+
+[SWOOLE]
+PORT = 8005
+HOST = 0.0.0.0
+
diff --git a/ErBiao-0.0.1-SNAPSHOT.jar b/ErBiao-0.0.1-SNAPSHOT.jar
new file mode 100755
index 0000000..d1a5ca8
Binary files /dev/null and b/ErBiao-0.0.1-SNAPSHOT.jar differ
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100755
index 0000000..574a39c
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,32 @@
+
+ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
+版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
+All rights reserved。
+ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
+
+Apache Licence是著名的非盈利开源组织Apache采用的协议。
+该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
+允许代码修改,再作为开源或商业软件发布。需要满足
+的条件:
+1. 需要给代码的用户一份Apache Licence ;
+2. 如果你修改了代码,需要在被修改的文件中说明;
+3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
+带有原来代码中的协议,商标,专利声明和其他原来作者规
+定需要包含的说明;
+4. 如果再发布的产品中包含一个Notice文件,则在Notice文
+件中需要带有本协议内容。你可以在Notice中增加自己的
+许可,但不可以表现为对Apache Licence构成更改。
+具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Schema/AdminAdminCreateUserRequest.json b/Schema/AdminAdminCreateUserRequest.json
new file mode 100755
index 0000000..be86bac
--- /dev/null
+++ b/Schema/AdminAdminCreateUserRequest.json
@@ -0,0 +1,79 @@
+{
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "object",
+ "properties": {
+ "account": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 32
+ },
+ "passwd": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 6,
+ "maxLength": 32
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 32
+ },
+ "department_id": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 32,
+ "maxLength": 32
+ },
+ "status": {
+ "type": "integer"
+ },
+ "certificate_type": {
+ "type": "integer"
+ },
+ "certificate_num": {
+ "type": "string"
+ "minLength": 1,
+ "maxLength": 32
+ },
+ "nickname": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 32
+ },
+ "wechat": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 1,
+ "maxLength": 100
+ },
+ "email": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/i",
+ "minLength": 5,
+ "maxLength": 32
+ },
+ "qq": {
+ "type": "integer"
+ },
+ "mobile": {
+ "type": "string",
+ "minLength": 8,
+ "maxLength": 20
+ },
+ "role_id": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 32,
+ "maxLength": 32
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/AdminAdminUpdateUserRequest.json b/Schema/AdminAdminUpdateUserRequest.json
new file mode 100755
index 0000000..52b7a5d
--- /dev/null
+++ b/Schema/AdminAdminUpdateUserRequest.json
@@ -0,0 +1,87 @@
+{
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "object",
+ "properties": {
+ "passwd": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "name": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "department_id": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "status": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "certificate_type": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "certificate_num": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "nickname": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "wechat": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "qq": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "mobile": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ },
+ "role_id": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/AdminAuthAuthRequest.json b/Schema/AdminAuthAuthRequest.json
new file mode 100755
index 0000000..d9680c6
--- /dev/null
+++ b/Schema/AdminAuthAuthRequest.json
@@ -0,0 +1,24 @@
+{
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "object",
+ "properties": {
+ "account": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "\/^[a-z0-9]+$\/i",
+ "minLength": 0,
+ "maxLength": 15
+ },
+ "passwd": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "\/^[a-z0-9]+$\/i",
+ "minLength": 0,
+ "maxLength": 32
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/AdminConfigSetAppConfigRequest.json b/Schema/AdminConfigSetAppConfigRequest.json
new file mode 100755
index 0000000..a60a94b
--- /dev/null
+++ b/Schema/AdminConfigSetAppConfigRequest.json
@@ -0,0 +1,416 @@
+{
+ "type": "object",
+ "properties": {
+ "app_config": {
+ "type": "object",
+ "properties": {
+ "multi": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "create_time": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "update_time": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "show_card": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "copyright": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "mini_template_id": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "mini_app_name": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 30
+ },
+ "status": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "allow_create": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "create_text": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "logo_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "logo_text": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "logo_phone": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "notice_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "notice_i": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "min_tmppid": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "order_overtime": {
+ "type": "integer",
+ "default": 1800,
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "collage_overtime": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "force_phone": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "staff_extract": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "first_extract": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 3
+ },
+ "sec_extract": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "code": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "corpid": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "corpsecret": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "agentid": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "wx_appid": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "wx_tplid": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "redis_pas": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "cash_mini": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 9999999999
+ },
+ "admin_account": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "plug_form": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "btn_consult": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "btn_sale": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "btn_code_err": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "btn_code_miss": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "preview_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9999
+ },
+ "btn_talk": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "receiving": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "ios_pay": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "android_pay": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "self_text": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "default_video": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "default_voice": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "card_type": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "order_pwd": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 40
+ },
+ "exchange_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "motto_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "default_voice_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "myshop_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "aliyun_sms_access_key_id": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 50
+ },
+ "aliyun_sms_access_key_secret": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 50
+ },
+ "default_shop_name": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "default_shop_pic": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "default_video_cover": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "appoint_pic": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "appoint_name": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "click_copy_way": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "click_copy_show_img": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "click_copy_content": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "question_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 1
+ },
+ "question_text": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ },
+ "shop_version": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "shop_carousel_more": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 300
+ },
+ "exchange_btn": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 40
+ },
+ "my_shop_limit": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "autograph": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "signature": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "vr_tittle": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 50
+ },
+ "vr_cover": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 300
+ },
+ "vr_path": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 300
+ },
+ "vr_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "qr_avatar_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "coupon_pass": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "auto_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "auto_switch_way": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "job_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "appid": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 40
+ },
+ "app_secret": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 40
+ },
+ "chat_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ },
+ "auth_switch": {
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 999
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/AdminConfigSetTabbarRequest.json b/Schema/AdminConfigSetTabbarRequest.json
new file mode 100755
index 0000000..fb59b08
--- /dev/null
+++ b/Schema/AdminConfigSetTabbarRequest.json
@@ -0,0 +1,50 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "minItems": 0,
+ "maxItems": 20,
+ "items": {
+ "type": "object",
+ "properties": {
+ "menu_name": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 32
+ },
+ "is_show": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 1
+ },
+ "name": {
+ "type": "string",
+ "pattern": "\/^[a-z0-9]+$\/i",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "url": {
+ "type": "string",
+ "pattern": "\/^[a-z0-9]+$\/i",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "url_out": {
+ "type": "string",
+ "pattern": "\/^[a-z0-9]+$\/i",
+ "minLength": 0,
+ "maxLength": 500
+ },
+ "url_jump_way": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 999
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminAddQuestionnairRequest.json b/Schema/CustomerAdminAddQuestionnairRequest.json
new file mode 100755
index 0000000..9a48f7f
--- /dev/null
+++ b/Schema/CustomerAdminAddQuestionnairRequest.json
@@ -0,0 +1,30 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100
+ },
+ "question": {
+ "type": "array",
+ "minItems": 0,
+ "maxItems": 200,
+ "items": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminAddRelyTypeRequest.json b/Schema/CustomerAdminAddRelyTypeRequest.json
new file mode 100755
index 0000000..37f905a
--- /dev/null
+++ b/Schema/CustomerAdminAddRelyTypeRequest.json
@@ -0,0 +1,21 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 20
+ },
+ "top": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 999999999
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminAddReplyRequest.json b/Schema/CustomerAdminAddReplyRequest.json
new file mode 100755
index 0000000..a9b5141
--- /dev/null
+++ b/Schema/CustomerAdminAddReplyRequest.json
@@ -0,0 +1,27 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "content": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "top": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "type": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9999999999
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminSetQuestionnairConfigRequest.json b/Schema/CustomerAdminSetQuestionnairConfigRequest.json
new file mode 100755
index 0000000..b034486
--- /dev/null
+++ b/Schema/CustomerAdminSetQuestionnairConfigRequest.json
@@ -0,0 +1,21 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "question_switch": {
+ "type": "integer",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1
+ },
+ "question_text": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 200
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminUpdateQuestionnairRequest.json b/Schema/CustomerAdminUpdateQuestionnairRequest.json
new file mode 100755
index 0000000..5ef2b3f
--- /dev/null
+++ b/Schema/CustomerAdminUpdateQuestionnairRequest.json
@@ -0,0 +1,54 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "default": 1,
+ "minimum": 1,
+ "maximum": 99999999999
+ },
+ "title": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "status": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 999
+ },
+ "question": {
+ "type": "array",
+ "minItems": 0,
+ "maxItems": 200,
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 99999999999
+ },
+ "title": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 100
+ },
+ "status": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminUpdateRelyTypeRequest.json b/Schema/CustomerAdminUpdateRelyTypeRequest.json
new file mode 100755
index 0000000..719b1a8
--- /dev/null
+++ b/Schema/CustomerAdminUpdateRelyTypeRequest.json
@@ -0,0 +1,33 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9223372036854775807
+ },
+ "title": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 20
+ },
+ "top": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "status": {
+ "type": "integer",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 999
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/CustomerAdminUpdateReplyRequest.json b/Schema/CustomerAdminUpdateReplyRequest.json
new file mode 100755
index 0000000..a1b58c0
--- /dev/null
+++ b/Schema/CustomerAdminUpdateReplyRequest.json
@@ -0,0 +1,33 @@
+{
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "content": {
+ "type": "string",
+ "minLength": 0,
+ "maxLength": 100
+ },
+ "top": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9999999999
+ },
+ "type": {
+ "type": "integer",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 9999999999
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/DynamicAdminoffUpdateContentRequest.json b/Schema/DynamicAdminoffUpdateContentRequest.json
new file mode 100755
index 0000000..e69de29
diff --git a/Schema/TestRequest.json b/Schema/TestRequest.json
new file mode 100755
index 0000000..b52a196
--- /dev/null
+++ b/Schema/TestRequest.json
@@ -0,0 +1,17 @@
+{
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "object",
+ "properties": {
+ "account": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/UserTestRequest.json b/Schema/UserTestRequest.json
new file mode 100755
index 0000000..b52a196
--- /dev/null
+++ b/Schema/UserTestRequest.json
@@ -0,0 +1,17 @@
+{
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "object",
+ "properties": {
+ "account": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Schema/UserUserRequest.json b/Schema/UserUserRequest.json
new file mode 100755
index 0000000..b52a196
--- /dev/null
+++ b/Schema/UserUserRequest.json
@@ -0,0 +1,17 @@
+{
+ "type": "object",
+ "properties": {
+ "user": {
+ "type": "object",
+ "properties": {
+ "account": {
+ "type": "string",
+ "format": "regex",
+ "pattern": "/^[a-z0-9]+$/i",
+ "minLength": 0,
+ "maxLength": 9223372036854775807
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/AdminRest.php b/app/AdminRest.php
new file mode 100755
index 0000000..84489a8
--- /dev/null
+++ b/app/AdminRest.php
@@ -0,0 +1,274 @@
+ 无限开版 其他 = 几开版
+ * @var array
+ */
+ protected $card_auth_version = 0;
+
+ /**
+ * 可开通名片数量
+ * 0 => 无限开版 其他 = 名片数量
+ * @var array
+ */
+ protected $card_auth_card = 0;
+
+ public function __construct ( App $app )
+ {
+
+
+ parent::__construct( $app );
+
+ //获取method
+ $this->_method = $this->request->method( true );
+
+ $this->_is_weiqin = longbingIsWeiqin();
+ //获取app名称
+ $this->_app = $app->http->getName();
+ //获取controller
+ $this->_controller = $this->request->controller();
+ //获取action名称
+ $this->_action = $this->request->action();
+ //获取param
+ $this->_param = $this->request->param();
+ //获取body参数
+ $this->_input = json_decode( $this->request->getInput(), true );
+ //获取头部信息
+ $this->_header = $this->request->header();
+ //获取请求host
+ $this->_host = $this->_header[ 'host' ];
+ //获取访问ip
+ $this->_ip = $_SERVER[ 'REMOTE_ADDR' ];
+
+ if ( $this->_is_weiqin ) {
+
+ global $_GPC, $_W;
+
+ $this->_uniacid = $_W[ 'uniacid' ];
+
+ if (empty($_W['user']) || empty($_W[ 'uniacid' ])) {
+
+ echo json_encode(['code' => 401, 'error' => '请登录管理系统!']);
+ exit;
+ }
+
+ }else{
+
+ //获取token 通过header获取token,如果不存在,则从param中获取。
+ if ( !isset( $this->_header[ 'token' ] ) || empty($this->_header[ 'token' ]))
+ {
+ if(!isset( $this->_param[ 'token' ] ) || empty($this->_param[ 'token' ]))
+ {
+ //返回数数据
+ echo json_encode(['code' => 401, 'error' => '请重新登录!']);
+ exit;
+ }else{
+ $this->_header[ 'token' ] = $this->_param[ 'token' ];
+ }
+ }
+
+ //获取token
+ $this->_token = $this->_header[ 'token' ] ;
+ //语言
+ if ( isset( $this->_header[ 'lang' ] ) ) $this->_lang = $this->_header[ 'lang' ];
+ //获取用户信息
+ $this->_user = getUserForToken( $this->_token );
+
+ if ($this->_user == null) {
+
+ echo json_encode(['code' => 401, 'error' => '请登录系统!']);
+ exit;
+ }
+
+ $this->_uniacid = !empty( $this->_user ) && isset( $this->_user[ 'uniacid' ] ) ? $this->_user[ 'uniacid' ] : 2;
+ }
+
+ landNotice($this->_uniacid);
+
+
+
+ }
+
+ //返回请求成功的数据
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', 200 );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+ /**
+ * REST 调用
+ * @access public
+ * @param string $method 方法名
+ * @return mixed
+ * @throws \Exception
+ */
+ public function _empty ( $method )
+ {
+ if ( method_exists( $this, $method . '_' . $this->method . '_' . $this->type ) ) {
+ // RESTFul方法支持
+ $fun = $method . '_' . $this->method . '_' . $this->type;
+ }
+ elseif ( $this->method == $this->restDefaultMethod && method_exists( $this, $method . '_' . $this->type ) ) {
+ $fun = $method . '_' . $this->type;
+ }
+ elseif ( $this->type == $this->restDefaultType && method_exists( $this, $method . '_' . $this->method ) ) {
+ $fun = $method . '_' . $this->method;
+ }
+ if ( isset( $fun ) ) {
+ return App::invokeMethod( [
+ $this,
+ $fun
+ ]
+ );
+ }
+ else {
+ // 抛出异常
+ throw new \Exception( 'error action :' . $method );
+ }
+ }
+
+
+
+ /**
+ *
+ * 获取支付信息
+ */
+ public function payConfig (){
+ $uniacid_id = !empty($uniacid)?$uniacid:$this->_uniacid;
+
+ $pay = Db::name('lbfarm_pay_config')->where(['uniacid'=>$uniacid_id])->find();
+
+ $config = Db::name( 'lbfarm_config')->where(['uniacid' => $uniacid_id])->find();
+
+ if(empty($pay[ 'mch_id' ])||empty($pay[ 'pay_key' ])){
+ $this->errorMsg('未配置支付信息');
+ }
+ $setting[ 'payment' ][ 'merchant_id' ] = $pay[ 'mch_id' ];
+ $setting[ 'payment' ][ 'key' ] = $pay[ 'pay_key' ];
+ $setting[ 'payment' ][ 'cert_path' ] = $pay[ 'cert_path' ];
+ $setting[ 'payment' ][ 'key_path' ] = $pay[ 'key_path' ];
+ $setting[ 'app_id' ] = $config['appid'];
+ $setting[ 'secret' ] = $config['appsecret'];
+ Log::write($setting);
+ return $setting;
+ }
+
+
+ /**
+ * User: chenniang
+ * Date: 2019-09-12 20:37
+ * @param string $msg
+ * @return void
+ * descption:直接抛出异常
+ */
+ protected function errorMsg($msg = '',$code = 400){
+ $msg = Lang::get($msg);
+ $this->results($msg,$code);
+ }
+
+ /**
+ * 返回封装后的 API 数据到客户端
+ * @access protected
+ * @param mixed $msg 提示信息
+ * @param mixed $data 要返回的数据
+ * @param int $code 错误码,默认为0
+ * @param string $type 输出类型,支持json/xml/jsonp
+ * @param array $header 发送的 Header 信息
+ * @return void
+ * @throws HttpResponseException
+ */
+ protected function results($msg, $code, array $header = [])
+ {
+ $result = [
+ 'error' => $msg,
+ 'code' => $code,
+ ];
+ $response = Response::create($result, 'json', 200)->header($header);
+ throw new HttpResponseException($response);
+ }
+}
diff --git a/app/AgentRest.php b/app/AgentRest.php
new file mode 100755
index 0000000..c34f053
--- /dev/null
+++ b/app/AgentRest.php
@@ -0,0 +1,325 @@
+_header = $this->request->header();
+ if (defined('IS_WEIQIN')) {
+ global $_GPC, $_W;
+ $this->_uniacid = $_W[ 'uniacid' ];
+ $this->_user = $_W['user'];
+ $role_map = [
+ 'founder' => 'admin',
+ 'operator' => 'guest',
+ ];
+ $this->_role = $role_map[$_W['role']] ?? 'guest';
+
+ if (empty($this->_user)) {
+ echo json_encode(['code' => 401, 'error' => '用户没有登录']);
+ exit;
+ }
+ if (!$_W['isfounder']) {
+ echo json_encode(['code' => 401, 'error' => '非超级管理员']);
+ exit;
+ }
+ $this->_user['role_name']='admin';
+ } else {
+ //获取token
+ if ( isset( $this->_header[ 'token' ] ) ) $this->_token = $this->_header[ 'token' ];
+
+
+ //获取用户信息
+ if ( !empty( $this->_token ) ) $this->_user = getUserForToken( $this->_token );
+ //获取角色名称
+ if ( !empty( $this->_user ) && isset( $this->_user[ 'role_name' ] ) ) $this->_role = $this->_user[ 'role_name' ];
+
+
+ if ($this->_user == null) {
+ echo json_encode(['code' => 401, 'error' => '用户没有登录']);
+ exit;
+ }
+
+ $this->_uniacid = !empty( $this->_user ) && isset( $this->_user[ 'uniacid' ] ) ? $this->_user[ 'uniacid' ] : -1;
+
+// if ($this->_user['role_name'] != 'admin') {
+// echo json_encode(['code' => 401, 'error' => '非超级管理员']);
+// exit;
+// }
+ }
+
+ //获取app名称
+// $this->_app = $this->request->app();
+ $this->_app = $app->http->getName();
+ //获取controller
+ $this->_controller = $this->request->controller();
+ //获取action名称
+ $this->_action = $this->request->action();
+
+ //获取method
+ $this->_method = $this->request->method( true );
+ //获取param
+ $this->_param = $this->request->param();
+
+ //获取配置信息
+ $this->_config = Db::name( 'longbing_card_config' )
+ ->where( [ 'uniacid' => $this->_uniacid ] )
+ ->find();
+
+ if(in_array($this->_method,['options','Options','OPTIONS'])){
+ echo true;exit;
+ }
+ //获取body参数
+ $this->_input = json_decode( $this->request->getInput(), true );
+
+ // //判断是否为json
+ // if(!isset($this->request->header()['Content-Type'])) {
+ // $this->_header['Content-Type'] = 'application/json';
+ // $this->app->request->withHeader($this->_header);
+ // }
+
+ //获取该应用下面所有的uniacid
+ $this->_uniacid_arr = $this->getUniacid();
+ //语言
+ if ( isset( $this->_header[ 'lang' ] ) ) $this->_token = $this->_header[ 'lang' ];
+ //获取请求host
+ $this->_host = $this->_header[ 'host' ];
+ //获取访问ip
+ $this->_ip = $_SERVER[ 'REMOTE_ADDR' ];
+ // 控制器初始化
+ $this->initialize();
+ //是否是微擎
+ $this->_is_weiqin = longbingIsWeiqin();
+ }
+
+ //返回请求成功的数据
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+// dd($this->request);die;
+// var_dump($this->_app ,$this->_controller ,$this->_action);die;
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', 200 );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+ /**
+ * REST 调用
+ * @access public
+ * @param string $method 方法名
+ * @return mixed
+ * @throws \Exception
+ */
+ public function _empty ( $method )
+ {
+ if ( method_exists( $this, $method . '_' . $this->method . '_' . $this->type ) ) {
+ // RESTFul方法支持
+ $fun = $method . '_' . $this->method . '_' . $this->type;
+ }
+ elseif ( $this->method == $this->restDefaultMethod && method_exists( $this, $method . '_' . $this->type ) ) {
+ $fun = $method . '_' . $this->type;
+ }
+ elseif ( $this->type == $this->restDefaultType && method_exists( $this, $method . '_' . $this->method ) ) {
+ $fun = $method . '_' . $this->method;
+ }
+ if ( isset( $fun ) ) {
+ return App::invokeMethod( [
+ $this,
+ $fun
+ ]
+ );
+ }
+ else {
+ // 抛出异常
+ throw new \Exception( 'error action :' . $method );
+ }
+ }
+
+ /**
+ * @Purpose: 获取formId
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+
+ public function getFormId ( $to_uid )
+ {
+ // 七天前开始的的时间戳
+ // $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - 6, date( 'Y' ) );
+ $beginTime = strtotime(date('Y-m-d',time()))-86400*6;
+ $formId = Db::name( 'longbing_card_formId' )
+ ->where( [ 'user_id' => $to_uid ] )
+ ->order( 'id desc' )
+ ->select();
+ if ( empty( $formId ) )
+ {
+ return false;
+ }
+ if ( $formId[ 0 ][ 'create_time' ] < $beginTime )
+ {
+ Db::name( 'longbing_card_formId' )
+ ->where( [ 'id' => $formId[ 0 ][ 'id' ] ] )
+ ->delete();
+ $this->getFormId( $to_uid );
+ }
+ else
+ {
+ Db::name( 'longbing_card_formId' )
+ ->where( [ 'id' => $formId[ 0 ][ 'id' ] ] )
+ ->delete();
+ return $formId[ 0 ][ 'formId' ];
+ }
+ }
+
+ /**
+ *
+ * 获取支付信息
+ */
+ public function payConfig (){
+ $pay = Db::name('longbing_card_config_pay')->where(['uniacid'=>$this->_uniacid])->find();
+ if(empty($pay)){
+ $this->errorMsg('no config of pay');
+ }
+ $setting[ 'payment' ][ 'merchant_id' ] = $pay[ 'mch_id' ];
+ $setting[ 'payment' ][ 'key' ] = $pay[ 'pay_key' ];
+ $setting[ 'payment' ][ 'cert_path' ] = $pay[ 'cert_path' ];
+ $setting[ 'payment' ][ 'key_path' ] = $pay[ 'key_path' ];
+ $setting[ 'app_id' ] = $this->_config['appid'];
+ $setting[ 'secret' ] = $this->_config['app_secret'];
+ return $setting;
+ }
+
+
+ /**
+ * User: chenniang
+ * Date: 2019-09-12 20:37
+ * @param string $msg
+ * @return void
+ * descption:直接抛出异常
+ */
+ protected function errorMsg($msg = '',$code = 400){
+ $msg = Lang::get($msg);
+ $this->results($msg,$code);
+ }
+
+ /**
+ * 返回封装后的 API 数据到客户端
+ * @access protected
+ * @param mixed $msg 提示信息
+ * @param mixed $data 要返回的数据
+ * @param int $code 错误码,默认为0
+ * @param string $type 输出类型,支持json/xml/jsonp
+ * @param array $header 发送的 Header 信息
+ * @return void
+ * @throws HttpResponseException
+ */
+ protected function results($msg, $code, array $header = [])
+ {
+ $result = [
+ 'error' => $msg,
+ 'code' => $code,
+ ];
+ $response = Response::create($result, 'json', 200)->header($header);
+ throw new HttpResponseException($response);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-05 09:13
+ * @功能说明:获取微擎的uniacid(同应用下面的)array
+ */
+ public function getUniacid(){
+
+ if(defined('IS_WEIQIN')){
+ //模块名字
+ $app_model_name = APP_MODEL_NAME;
+
+ $dis[] = ['modules','like','%'.$app_model_name.'%'];
+ //获取该应用下面的所有uniacid
+ $uniacid = Db::name('wxapp_versions')->where($dis)->column('uniacid');
+ }else{
+
+ $uniacid = [$this->_user['uniacid']];
+ }
+ return $uniacid;
+ }
+}
diff --git a/app/ApiRest.php b/app/ApiRest.php
new file mode 100755
index 0000000..a0f8150
--- /dev/null
+++ b/app/ApiRest.php
@@ -0,0 +1,573 @@
+ 'https://retail.xiaochengxucms.com/defaultAvatar.png',
+ // 默认内容图片
+ 'image' => 'https://retail.xiaochengxucms.com/lbCardDefaultImage.png',
+ );
+
+ protected $_is_weiqin = false ;
+
+ protected $check_url = "";
+
+ /**
+ * 无需登录的方法,同时也就不需要鉴权了
+ * @var array
+ */
+ protected $noNeedLogin = ['getMonitorInfo','earTagTest'];
+
+
+ public function __construct ( App $app )
+ {
+
+
+ parent::__construct( $app );
+
+ if(in_array($this->_method,['options','Options','OPTIONS'])){
+
+ echo true;exit;
+ }
+
+ //获取param
+ $this->_param = $this->request->param();
+ //获取body参数
+ $this->_input = json_decode( $this->request->getInput(), true );
+ //获取头部信息
+ $this->_header = $this->request->header();
+
+
+ $this->is_app = !empty($this->_header['isapp'])?$this->_header['isapp']:0;
+
+ if ( defined( 'IS_WEIQIN' ) )
+ {
+ global $_GPC, $_W;
+ $this->_uniacid = $_W[ 'uniacid' ];
+ }
+ else
+ {
+ if(isset($this->_param[ 'i' ]))
+ {
+ $this->_uniacid = $this->_param[ 'i' ];
+ }
+
+ }
+
+ if ( defined( 'LONGBING_CARD_UNIACID' ) )
+ {
+
+ define( 'LONGBING_CARD_UNIACID', $this->_uniacid );
+ }
+
+ // $this->shareChangeData($this->_param);
+ //获取autograph 小程序用户唯一标示
+ if ( isset( $this->_header[ 'autograph' ] ) && $this->_header[ 'autograph' ])
+ {
+ $this->autograph = $this->_header['autograph'];
+ }
+ else
+ {
+ if(!$this->match($this->noNeedLogin)){
+
+ $this->errorMsg('need login',401);
+
+ }
+ }
+ //获取配置信息
+ $this->_config = longbingGetAppConfig($this->_uniacid);
+ //语言
+ if ( isset( $this->_header[ 'lang' ] ) ) $this->_token = $this->_header[ 'lang' ];
+
+ if(!empty($this->autograph)&&!$this->match($this->noNeedLogin)){
+
+ $this->_user_id = $this->getUserId();
+
+ $this->_user = $this->getUserInfo();
+ }
+
+ landNotice($this->_uniacid);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-21 17:43
+ * @功能说明:
+ */
+ public function shareChangeData($input){
+
+ $arr = [
+
+ 'farm/app/Index/getYsToken',
+
+ 'farm/app/Index/ysStartTurn',
+
+ 'farm/app/Index/ysStopTurn',
+
+ 'farm/app/Index/getMonitorInfo',
+
+ 'farm/app/Index/index',
+
+ 'farm/app/Index/couponList',
+
+ 'farm/app/IndexClaim/claimCateList',
+
+ 'farm/app/IndexLand/landList',
+
+ 'farm/app/IndexClaim/claimBanner',
+
+ 'farm/app/IndexClaim/claimCateList',
+
+ 'farm/app/IndexClaim/claimList',
+
+ 'farm/app/IndexGoods/goodsIndex',
+
+ 'farm/app/IndexGoods/carInfo',
+
+ 'farm/app/IndexGoods/goodsList',
+
+ 'farm/app/IndexUser/userInfo',
+
+ 'farm/app/IndexUser/index',
+
+ 'farm/app/IndexUser/farmerInfo',
+
+ 'farm/app/Index/configInfo',
+ ];
+
+ if(!empty($input['s'])&&in_array($input['s'],$arr)){
+
+ $input['s'] = trim(strrchr($input['s'], '/'),'/');
+
+ $this->noNeedLogin[] = $input['s'];
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-09 12:00
+ * @功能说明:检测方法传递
+ */
+ public function match($arr){
+
+
+ $arr = is_array($arr) ? $arr : explode(',', $arr);
+ if (!$arr)
+ {
+ return FALSE;
+ }
+ $arr = array_map('strtolower', $arr);
+ // 是否存在
+ if (in_array(strtolower($this->request->action()), $arr) || in_array('*', $arr))
+ {
+ return TRUE;
+ }
+
+ // 没找到匹配
+ return FALSE;
+ }
+
+ //返回请求成功的数据
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = LongbingGetWxApiReturnData($data);
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+// $result[ 'error' ] = Lang::get($msg);
+// $result[ 'code' ] = $code;
+ $result = $this->getErrorData($msg, $code);
+ return $this->response( $result, 'json', 200 );
+ }
+
+ public function getErrorData($msg, $code = 400)
+ {
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $result;
+ }
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+ /**
+ * REST 调用
+ * @access public
+ * @param string $method 方法名
+ * @return mixed
+ * @throws \Exception
+ */
+ public function _empty ( $method )
+ {
+ if ( method_exists( $this, $method . '_' . $this->method . '_' . $this->type ) )
+ {
+ // RESTFul方法支持
+ $fun = $method . '_' . $this->method . '_' . $this->type;
+ }
+ elseif ( $this->method == $this->restDefaultMethod && method_exists( $this, $method . '_' . $this->type ) )
+ {
+ $fun = $method . '_' . $this->type;
+ }
+ elseif ( $this->type == $this->restDefaultType && method_exists( $this, $method . '_' . $this->method ) )
+ {
+ $fun = $method . '_' . $this->method;
+ }
+ if ( isset( $fun ) )
+ {
+ return App::invokeMethod( [ $this, $fun ]
+ );
+ }
+ else
+ {
+ // 抛出异常
+ throw new \Exception( 'error action :' . $method );
+ }
+ }
+
+ /**
+ * @Purpose: 通过小程序端的用户标示获取用户信息
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ protected function getUserInfo ()
+ {
+
+ $value = getCache($this->autograph, $this->_uniacid);
+
+ if(empty($value)){
+
+ $this->errorMsg('need login',401);
+ }
+
+ if(empty($value['phone'])){
+
+ // $this->errorMsg('need phone',403);
+
+ }
+
+ $user_model = new \app\farm\model\User();
+
+ $value['balance'] = $user_model->where(['id'=>$value['id']])->value('balance');
+
+ return $value;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:22
+ * @功能说明:获取当前的门店信息
+ */
+ public function getStoreInfo($err=1){
+
+ $user_id = $this->getUserId();
+
+ $user_model = new \app\farm\model\User();
+
+ $cap_id = $user_model->where(['id'=>$user_id])->value('last_store_id');
+
+ $cap_info = [];
+
+ if(!empty($cap_id)){
+
+ $cap_model = new Farmer();
+
+ $dis = [
+
+ 'id' => $cap_id,
+
+ 'status' => 2,
+
+ 'business_status' => 1,
+
+ 'type' => 2,
+ ];
+
+ $cap_info = $cap_model->dataInfo($dis);
+ }
+
+ if(empty($cap_info)&&$err==1){
+
+ // $this->errorMsg('请选择店铺',-407);
+
+ }
+
+ return $cap_info;
+
+ }
+
+
+
+ /**
+ * @Purpose: 通过小程序端的用户标示获取用户id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ protected function getUserId ()
+ {
+
+ $value = getCache( $this->autograph, $this->_uniacid );
+
+ if($this->is_app==1){
+
+
+ $user_model = new \app\farm\model\User();
+
+ $id = $user_model->where(['check'=>1])->value('id');
+
+ return $id;
+ }
+
+ if ( ($value === false &&!$this->match($this->noNeedLogin)))
+ {
+
+ $this->errorMsg('need login',401);
+
+ }
+
+
+// if($this->match($this->noNeedLogin)&&empty($value)){
+//
+// $user_model = new \app\farm\model\User();
+//
+// $value =$user_model->dataInfo(['uniacid'=>$this->_uniacid,'check'=>1]);
+//
+// // setCache($this->autograph,$value,7200,$this->_uniacid);
+// }
+
+// if ( (!empty($value['check']) &&!$this->match($this->noNeedLogin)))
+// {
+//
+// $this->errorMsg('need login',401);
+//
+// }
+
+
+ return !empty($value[ 'id' ])?$value[ 'id' ]:0;
+ }
+ /**
+ *
+ * 获取支付信息
+ */
+
+
+
+ public function payConfig ($uniacid = '1',$is_app=7){
+
+ if($is_app==7){
+
+ $is_app = $this->is_app;
+ }
+
+ $uniacid_id = !empty($uniacid)?$uniacid:$this->_uniacid;
+
+ $pay = Db::name('lbfarm_pay_config')->where(['uniacid'=>$uniacid_id])->find();
+
+ $config = Db::name( 'lbfarm_config')->where(['uniacid' => $uniacid_id])->find();
+
+ if(empty($pay[ 'mch_id' ])||empty($pay[ 'pay_key' ])){
+
+ // $this->errorMsg('未配置支付信息');
+ }
+
+ $setting[ 'payment' ][ 'merchant_id' ] = $pay[ 'mch_id' ];
+
+ $setting[ 'payment' ][ 'key' ] = $pay[ 'pay_key' ];
+
+ $setting[ 'payment' ][ 'cert_path' ] = $pay[ 'cert_path' ];
+
+ $setting[ 'payment' ][ 'key_path' ] = $pay[ 'key_path' ];
+
+ $setting[ 'payment' ][ 'ali_appid' ] = $pay[ 'ali_appid' ];
+
+ $setting[ 'payment' ][ 'ali_privatekey' ] = $pay[ 'ali_privatekey' ];
+
+ $setting[ 'payment' ][ 'ali_publickey' ] = $pay[ 'ali_publickey' ];
+
+ if($is_app==0){
+
+ $setting[ 'app_id' ] = $config['appid'];
+
+ $setting[ 'secret' ] = $config['appsecret'];
+
+ }elseif($is_app==1){
+
+ $setting[ 'app_id' ] = $config['app_app_id'];
+
+ $setting[ 'secret' ] = $config['app_app_secret'];
+
+ }else{
+
+ $setting[ 'app_id' ] = $config['web_app_id'];
+
+ $setting[ 'secret' ] = $config['web_app_secret'];
+
+ }
+
+ $setting[ 'is_app' ]= $is_app;
+
+ return $setting;
+ }
+
+ /**
+ * @Purpose: 获取formId
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+
+ public function getFormId ( $to_uid )
+ {
+ return [];
+ // 七天前开始的的时间戳
+ // $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - 6, date( 'Y' ) );
+ $beginTime = strtotime(date('Y-m-d',time()))-86400*6;
+ $formId = Db::name( 'longbing_card_formId' )
+ ->where( [ 'user_id' => $to_uid ] )
+ ->order( 'id desc' )
+ ->select();
+ if ( empty( $formId ) )
+ {
+ return false;
+ }
+ if ( $formId[ 0 ][ 'create_time' ] < $beginTime )
+ {
+ Db::name( 'longbing_card_formId' )
+ ->where( [ 'id' => $formId[ 0 ][ 'id' ] ] )
+ ->delete();
+ $this->getFormId( $to_uid );
+ }
+ else
+ {
+ Db::name( 'longbing_card_formId' )
+ ->where( [ 'id' => $formId[ 0 ][ 'id' ] ] )
+ ->delete();
+ return $formId[ 0 ][ 'formId' ];
+ }
+ }
+ /**
+ * User: chenniang
+ * Date: 2019-09-12 20:37
+ * @param string $msg
+ * @return void
+ * descption:直接抛出异常
+ */
+ protected function errorMsg($msg = '',$code = 400){
+ $msg = Lang::get($msg);
+ $this->results($msg,$code);
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-09-12 20:42
+ * @param $msg
+ * @param int $code
+ * @param array $header
+ * @return void
+ * descption:直接抛出状态
+ */
+ protected function results($msg, $code, array $header = [])
+ {
+ $result = [
+ 'error' => $msg,
+ 'code' => $code,
+ ];
+ $response = Response::create($result, 'json', 200)->header($header);
+ throw new HttpResponseException($response);
+ }
+}
diff --git a/app/BaseController.php b/app/BaseController.php
new file mode 100755
index 0000000..7403416
--- /dev/null
+++ b/app/BaseController.php
@@ -0,0 +1,113 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types = 1);
+
+namespace app;
+
+use think\App;
+use think\exception\ValidateException;
+use think\Validate;
+
+/**
+ * 控制器基础类
+ */
+abstract class BaseController
+{
+ /**
+ * Request实例
+ * @var \think\Request
+ */
+ protected $request;
+
+ /**
+ * 应用实例
+ * @var \think\App
+ */
+ protected $app;
+
+ /**
+ * 是否批量验证
+ * @var bool
+ */
+ protected $batchValidate = false;
+
+ /**
+ * 控制器中间件
+ * @var array
+ */
+ protected $middleware = [];
+
+ /**
+ * 构造方法
+ * @access public
+ * @param App $app 应用对象
+ */
+ public function __construct(App $app)
+ {
+
+ longbing_check_install();
+
+ $this->app = $app;
+
+ $this->request = $this->app->request;
+
+ $this->_method = $this->request->method( true );
+
+ if(in_array($this->_method,['options','Options','OPTIONS'])){
+ echo true;exit;
+ }
+ // 控制器初始化
+ $this->initialize();
+
+ }
+
+ // 初始化
+ protected function initialize()
+ {}
+
+ /**
+ * 验证数据
+ * @access protected
+ * @param array $data 数据
+ * @param string|array $validate 验证器名或者验证规则数组
+ * @param array $message 提示信息
+ * @param bool $batch 是否批量验证
+ * @return array|string|true
+ * @throws ValidateException
+ */
+ protected function validate(array $data, $validate, array $message = [], bool $batch = false)
+ {
+ if (is_array($validate)) {
+ $v = new Validate();
+ $v->rule($validate);
+ } else {
+ if (strpos($validate, '.')) {
+ // 支持场景
+ list($validate, $scene) = explode('.', $validate);
+ }
+ $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
+ $v = new $class();
+ if (!empty($scene)) {
+ $v->scene($scene);
+ }
+ }
+
+ $v->message($message);
+
+ // 是否批量验证
+ if ($batch || $this->batchValidate) {
+ $v->batch(true);
+ }
+
+ return $v->failException(true)->check($data);
+ }
+
+}
diff --git a/app/BaseControllerV2.php b/app/BaseControllerV2.php
new file mode 100755
index 0000000..16a64ff
--- /dev/null
+++ b/app/BaseControllerV2.php
@@ -0,0 +1,80 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types = 1);
+
+namespace app;
+
+use think\Request;
+
+/**
+ * 控制器基础类
+ */
+abstract class BaseControllerV2
+{
+
+//唯一app标示
+ public $_uniacid = 0;
+ //query参数
+ public $_param = [];
+ //头部token
+ public $_token = null;
+ //
+ public $_autograph = null;
+ //请求对象 $request 兼容处理,即将废弃
+ protected $request;
+ protected $_request;
+
+ public function __construct(Request $request)
+ {
+
+ $this->request = $request;
+ $this->_request = $this->request;
+ $this->_param = $this->request->param();
+ $this->_token = $this->request->header('token');
+ $this->_autograph = $this->request->header('autograph');
+ $this->_uniacid = intval( $this->request->param('i') ) ;
+ $this->_uniacid = $this->_uniacid ? $this->_uniacid : intval( $this->request->param('uniacid') );
+
+ //兼容微擎新版本
+ if(empty($this->_uniacid)&&longbingIsWeiqin()){
+
+ global $_GPC, $_W;
+ $this->_uniacid = $_W[ 'uniacid' ];
+
+ }
+
+ //独立版拿不到uniacid
+ if(empty($this->_uniacid)){
+
+ $user_info = getUserForToken($this->_token);
+
+ $this->_uniacid = $user_info['uniacid'];
+
+ }
+ }
+
+ /**
+ * 获取用户ID
+ *
+ * @return int
+ * @author shuixian
+ * @DataTime: 2019/12/24 12:45
+ */
+ protected function getUserId()
+ {
+ $value = getCache($this->_autograph, $this->_uniacid);
+
+ if ($value === false) {
+ return 0;
+ }
+ return $value['id'];
+ }
+}
diff --git a/app/BaseModel.php b/app/BaseModel.php
new file mode 100755
index 0000000..493a1c6
--- /dev/null
+++ b/app/BaseModel.php
@@ -0,0 +1,121 @@
+ 'int',
+ 'update_time' => 'int',
+ 'delete_time' => 'int',
+ 'deleted' => 'int'
+ ];
+ //设置操作时间
+// public $time;
+// function __construct() {
+// parent::__construct();
+// $this->time = time();
+// }
+// //获取详情
+// public function getRow($filter) {
+// $filter['deleted'] = 0;
+// return $this->where($filter)->find();
+// }
+// //获取列表
+// public function listRow($filter ,$field = []) {
+// $filter['deleted'] = 0;
+// return $this->where($filter)
+// ->order('create_time', 'asc')
+// ->field($field)
+// ->select();
+// }
+// //创建
+// public function createRow($data) {
+// $data['create_time'] = time();
+// return $this->save($data);
+// }
+// //批量创建
+// public function createRows($datas) {
+// return $this->saveAll($datas);
+// }
+//
+// //更新
+// public function updateRow($filter ,$data) {
+// $filter['deleted'] = 0;
+// $data['update_time'] = time();
+// $result = $this->where($filter)->update($data);
+// return $result;
+// }
+// //删除
+// public function deleteRow($filter) {
+// $filter['deleted'] = 0;
+// return $this->updateRow($filter ,['delete_time' => time() ,'deleted' => 1]);
+// }
+
+ //获取详情
+ public function getRow($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this
+ ->where($filter)
+ ->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //获取列表
+ public function listRow($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this
+ ->where($filter)
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //创建
+ public function createRow($data)
+ {
+ if(!empty($data['create_time'])){
+ $data['create_time'] = time();
+ }
+ return $this->save($data);
+ }
+ //批量创建
+ public function createRows($datas)
+ {
+ return $this->saveAll($datas);
+ }
+ public function upsave($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ if(empty($result)) return false;
+ return true;
+ }
+ //更新
+ public function updateRow($filter ,$data)
+ {
+ $filter['deleted'] = 0;
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ if(empty($result)) return false;
+ return true;
+ }
+ //删除
+ public function deleteRow($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->updateRow($filter ,['delete_time' => time() ,'deleted' => 1]);
+ if(empty($result)) return false;
+ return true;
+ }
+
+ //真删除
+ public function destroyRow($filter)
+ {
+ $result = $this->where($filter)->delete();
+ if(empty($result)) return false;
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/ArticleFromUrl.php b/app/Common/ArticleFromUrl.php
new file mode 100755
index 0000000..6d65efb
--- /dev/null
+++ b/app/Common/ArticleFromUrl.php
@@ -0,0 +1,152 @@
+html = file_get_contents( $url );
+ }
+
+ /**
+ * @Purpose: 获取文章内容
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getArticle ()
+ {
+ $file = $this->html;
+
+ $file = str_replace( "data-src", "src", $file );
+ $file = str_replace( "data-croporisrc", "src", $file );
+ $file = str_replace( "preview.html", "player.html", $file );
+ $file = str_replace( "display: inline-block;", "display: block;", $file );
+
+ $html = '';
+
+ $title = $this->get_between( $file, '
" );
+
+
+ if(strpos($file,'') !== false){
+ $html_content = '
';
+ }else{
+ $html_content = '
';
+
+ }
+// $html_content = str_replace('style="visibility: hidden;"','','
');
+// dump($html_content);exit;
+// $content = $this->get_between( $file, '
get_between( $file, $html_content, "var first_sceen__time = (+new Date());" );
+ $res = file_put_contents( 'tmp_article.txt', $content );
+ if ( $res ) {
+ $content = file( 'tmp_article.txt' );
+ unset( $content[ count( $content ) - 1 ] );
+ unset( $content[ count( $content ) - 1 ] );
+ unset( $content[ count( $content ) - 1 ] );
+ }
+ $res = file_put_contents( 'tmp_article.txt', $content );
+ if ( $res ) {
+ $content = file_get_contents( 'tmp_article.txt' );
+ }
+ @unlink( 'tmp_article.txt' );
+
+ $html = $content;
+
+ $cover = '';
+
+ $title = trim( $title );
+ $cover = trim( $cover );
+ $html = trim( $html );
+ return [ 'cover' => $cover, 'title' => $title, 'content' => $html ];
+ }
+
+
+ /**
+ * @Purpose: php截取指定两个字符之间字符串
+ *
+ * @Param: string $input 字符串
+ * @Param: int $start 开始截取位置
+ * @Param: int $end 结束截取位置
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ protected function get_between ( $input, $start, $end )
+ {
+
+ $substr = substr( $input, strlen( $start ) + strpos( $input, $start ), ( strlen( $input ) - strpos( $input, $end ) ) * ( -1 ) );
+// $substr = substr( $input, strpos( $input, $start ), ( strlen( $input ) - strpos( $input, $end ) ) * ( -1 ) );
+
+ return $substr;
+ }
+
+ protected function getImageDown ( $str )
+ {
+
+ if ( !is_dir( ATTACHMENT_ROOT . '/' . "images" ) ) {
+ mkdir( ATTACHMENT_ROOT . '/' . "images" );
+ }
+ if ( !is_dir( ATTACHMENT_ROOT . '/' . "images/a_qr" ) ) {
+ mkdir( ATTACHMENT_ROOT . '/' . "images/a_qr" );
+ }
+ if ( !is_dir( ATTACHMENT_ROOT . '/' . "images/a_image/" ) ) {
+ mkdir( ATTACHMENT_ROOT . '/' . "images/a_image/" );
+ }
+
+ $preg = '/
/i';//匹配img标签的正则表达式
+
+ preg_match_all( $preg, $str, $allImg );//这里匹配所有的img
+
+ $allImg = $allImg[ 1 ];
+ $allImgNot = array();
+ $destination_folder = ATTACHMENT_ROOT . '/images' . "/a_image/";
+
+ foreach ( $allImg as $index2 => $item2 ) {
+ $ftype = '.png';
+ $res = getimagesize( $item2 );
+
+ if ( isset( $res[ 'mime' ] ) ) {
+ if ( strpos( $res[ 'mime' ], 'gif' ) ) {
+ $ftype = '.gif';
+ }
+ }
+ $name = str_shuffle( time() . rand( 111111, 999999 ) ) . $ftype;
+ $destination = $destination_folder . $name;
+ $file = file_get_contents( $item2 );
+ file_put_contents( $destination, $file );
+ $image = 'images' . "/a_image/" . $name;
+ array_push( $allImgNot, $image );
+ $image = tomedia( $image );
+ $allImg[ $index2 ] = $image;
+ $str = str_replace( $item2, $image, $str );
+ }
+ return [ $str, $allImg, $allImgNot ];
+ }
+
+}
\ No newline at end of file
diff --git a/app/Common/ComsumerApi.php b/app/Common/ComsumerApi.php
new file mode 100755
index 0000000..0ea17d7
--- /dev/null
+++ b/app/Common/ComsumerApi.php
@@ -0,0 +1,43 @@
+ Config::get('rabbit.rabbit_host'),
+ 'port' => Config::get('rabbit.rabbit_port'),
+ 'login' => Config::get('rabbit.rabbit_login'),
+ 'password' => Config::get('rabbit.rabbit_passwd'),
+ 'vhost' => Config::get('rabbit.rabbit_vhost')
+ );
+ $this->e_name = Config::get('rabbit.rabbit_exchange_name');
+ $this->q_name = Config::get('rabbit.rabbit_query_name');
+ $this->k_route = Config::get('rabbit.rabbit_key');
+ $this->conn = new AMQPConnection($conn_args);
+ if (!$this->conn->connect()) {
+ die("Cannot connect to the broker!\n");
+ }
+ }
+ public function consumerMessage(){
+ $channel = new AMQPChannel($this->conn);
+ $q = new AMQPQueue($channel);
+ $q->setName($this->q_name);
+ $q->setFlags(AMQP_DURABLE);
+ while($a=$q->declare())
+ {
+ $gets = $q->get(AMQP_AUTOACK);
+ $messages[] = $gets->getBody();
+ }
+
+ $this->conn->disconnect();
+ return $messages;
+ }
+}
diff --git a/app/Common/JsonSchema.php b/app/Common/JsonSchema.php
new file mode 100755
index 0000000..0ca085f
--- /dev/null
+++ b/app/Common/JsonSchema.php
@@ -0,0 +1,641 @@
+ errors = array();
+ $this -> complexTypes = array();
+ $this -> json = json_decode($json);
+
+ }
+
+ /**
+ * Generate JSON Schema
+ *
+ * @return string JSON Schema
+ */
+ public function getSchema() {
+ $schema = null;
+ $schema = $this -> genByType($this -> json);
+ return json_encode($schema);
+ }
+
+ /**
+ * Generate JSON Schema by type
+ * @param mixed $value
+ * @return object
+ */
+ private function genByType($value) {
+ $type = gettype($value);
+ $schema = array();
+ switch ($type) {
+ case 'boolean' :
+ $schema['type'] = 'boolean';
+ $schema['default'] = false;
+ break;
+ case 'integer' :
+ $schema['type'] = 'integer';
+ $schema['default'] = 0;
+ $schema['minimum'] = 0;
+ $schema['maximum'] = PHP_INT_MAX;
+ $schema['exclusiveMinimum'] = 0;
+ $schema['exclusiveMaximum'] = PHP_INT_MAX;
+ break;
+ case 'double' :
+ $schema['type'] = 'number';
+ $schema['default'] = 0;
+ $schema['minimum'] = 0;
+ $schema['maximum'] = PHP_INT_MAX;
+ $schema['exclusiveMinimum'] = 0;
+ $schema['exclusiveMaximum'] = PHP_INT_MAX;
+ break;
+ case 'string' :
+ $schema['type'] = 'string';
+ $schema['format'] = 'regex';
+ $schema['pattern'] = '/^[a-z0-9]+$/i';
+ $schema['minLength'] = 0;
+ $schema['maxLength'] = PHP_INT_MAX;
+ break;
+ case 'array' :
+ $schema['type'] = 'array';
+ $schema['minItems'] = 0;
+ $schema['maxItems'] = 20;
+ $items = array();
+ foreach ($value as $value) {
+ $items = $this -> genByType($value);
+ break;
+ }
+ $schema['items'] = $items;
+ break;
+ case 'object' :
+ $schema['type'] = 'object';
+ $items = array();
+ $value = get_object_vars($value);
+ foreach ($value as $key => $value) {
+ $items[$key] = $this -> genByType($value);
+ }
+ $schema['properties'] = $items;
+ break;
+ case 'null' :
+ // any in union types
+ $schema['type'] = 'null';
+ break;
+ default :
+ break;
+ }
+ return $schema;
+ }
+
+ /**
+ * Set type schema
+ * @param string $typeSchema
+ */
+ public function addType($typeSchema) {
+ if (empty($typeSchema)) {
+ return;
+ }
+ $typeSchema = json_decode($typeSchema, true);
+ if (is_array($typeSchema) && isset($typeSchema['id'])) {
+ $this -> complexTypes[$typeSchema['id']] = $typeSchema;
+ }
+ }
+
+ /**
+ * Get type schema
+ *
+ * @param string ref
+ * @return string schema
+ */
+ private function getType($ref) {
+ if (isset($this -> complexTypes[$ref])) {
+ return $this -> complexTypes[$ref];
+ }
+ return null;
+ }
+
+ /**
+ * Validate JSON
+ *
+ * @param string $schema JSON Schema
+ * @return boolean
+ */
+ public function validate($schema) {
+ $isVali = false;
+ do {
+ $schema = json_decode($schema, true);
+ if (!is_array($schema) || !isset($schema['type'])) {
+ $this -> addError('100', 'schema parse error. (PHP 5 >= 5.3.0) see json_last_error(void).');
+ break;
+ }
+
+ $isVali = $this -> checkByType($this -> json, $key = null, $schema);
+ } while (false);
+ return $isVali;
+ }
+
+ /**
+ * check type: string
+ * http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1
+ *
+ * @param string $value
+ * @param array $schema
+ */
+ private function checkString($value, $key, $schema) {
+ // string
+ $isVali = false;
+ do {
+ if (!is_string($value) && !is_numeric($value)) {
+ $this -> addError('101', $key . ' : ' . json_encode($value) . ' is not a string.', $key);
+ break;
+ }
+ $len = strlen(trim($value));
+ if (isset($schema['minLength'])) {
+ if ($schema['minLength'] > $len) {
+ $this -> addError('102', $key . ': ' . json_encode($value) . ' is too short.', $key);
+ break;
+ }
+ }
+ if (isset($schema['maxLength'])) {
+ if ($schema['maxLength'] < $len) {
+ $this -> addError('102', $key . ': ' . json_encode($value) . ' is too long.', $key);
+ break;
+ }
+ }
+
+ if (isset($schema['format'])) {
+ switch ($schema['format']) {
+
+ case 'date-time' :
+ /**
+ * date-time This SHOULD be a date in ISO 8601 format of YYYY-MM-
+ * DDThh:mm:ssZ in UTC time. This is the recommended form of date/
+ * timestamp.
+ */
+ break;
+ case 'date' :
+ /**
+ * date This SHOULD be a date in the format of YYYY-MM-DD. It is
+ * recommended that you use the"date-time"format instead of"date"
+ * unless you need to transfer only the date part.
+ */
+ break;
+ case 'time' :
+ /**
+ * time This SHOULD be a time in the format of hh:mm:ss. It is
+ * recommended that you use the"date-time"format instead of"time"
+ * unless you need to transfer only the time part.
+ */
+ break;
+ case 'utc-millisec' :
+ /**
+ * utc-millisec This SHOULD be the difference, measured in
+ * milliseconds, between the specified time and midnight, 00:00 of
+ * January 1, 1970 UTC. The value SHOULD be a number (integer or
+ * float).
+ */
+ break;
+ case 'regex' :
+ /**
+ * regex A regular expression, following the regular expression
+ * specification from ECMA 262/Perl 5.
+ */
+ if (isset($schema['pattern'])) {
+ $pattern = $schema['pattern'];
+
+ if (preg_match($pattern, $value)) {
+ $isVali = true;
+ } else {
+ $this -> addError('101', $key . ':' . $value . ' does not match ' . $pattern, $key);
+ }
+ } else {
+ $this -> addError('101', 'format-regex: pattern is undefined.', $key);
+ }
+
+ break;
+ case 'color' :
+ /**
+ * color This is a CSS color (like"#FF0000"or"red"), based on CSS
+ * 2.1 [W3C.CR-CSS21-20070719].
+ */
+ break;
+ case 'style' :
+ /**
+ * style This is a CSS style definition (like"color: red; background-
+ * color:#FFF"), based on CSS 2.1 [W3C.CR-CSS21-20070719].
+ */
+ break;
+ case 'phone' :
+ /**
+ * phone This SHOULD be a phone number (format MAY follow E.123).
+ * http://en.wikipedia.org/wiki/E.123
+ */
+ if (preg_match("/^((0?[0-9]{2}) d{3,4}s?d{4}|+d{2} d{2} d{3,4}s?d{4})$/", $value)) {
+ $isVali = true;
+ } else {
+ $this -> addError('101', $key . ': ' . $value . ' is not a phone number.', $key);
+ }
+ break;
+ case 'uri' :
+ /**
+ * uri This value SHOULD be a URI..
+ */
+ if (filter_var($value, FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED)) {
+ $isVali = true;
+ } else {
+ $this -> addError('101', $key . ': ' . $value . ' is not a URI.', $key);
+ }
+ break;
+ case 'email' :
+ /**
+ * email This SHOULD be an email address.
+ */
+ if (filter_var($value, FILTER_VALIDATE_EMAIL)) {
+ $isVali = true;
+ } else {
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not a email.', $key);
+ }
+ break;
+ case 'ip-address' :
+ /**
+ * ip-address This SHOULD be an ip version 4 address.
+ */
+ if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
+ $isVali = true;
+ } else {
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not a ipv4 address.', $key);
+ }
+
+ break;
+ case 'ipv6' :
+ /**
+ * ipv6 This SHOULD be an ip version 6 address.
+ */
+ if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ $isVali = true;
+ } else {
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not a ipv6 address.', $key);
+ }
+ break;
+ case 'host-name' :
+ /**
+ * host-name This SHOULD be a host-name.
+ */
+ break;
+
+ default :
+ $this -> addError('101', $schema['format'] . ' is undefined.', $key);
+ break;
+ }
+ break;
+ }
+
+ $isVali = true;
+ } while (false);
+ return $isVali;
+ }
+
+ /**
+ * check type: integer/double
+ *
+ * @param number $value
+ * @param array $schema
+ * @return boolean
+ */
+ private function checkNumber($value, $key, $schema = null) {
+ // number
+ $isVali = false;
+ do {
+
+ if (!is_numeric($value)) {
+ $this -> addError($value . ' is not a number.');
+ break;
+ }
+ if (isset($schema['minimum'])) {
+ if ($schema['minimum'] > $value) {
+ $this -> addError('103', $key . ':' . json_encode($value) . ' is less than ' . $schema['minimum'], $key);
+ break;
+ }
+ }
+ if (isset($schema['maximum'])) {
+ if ($schema['maximum'] < $value) {
+ $this -> addError('103', $key . ':' . json_encode($value) . ' is bigger than ' . $schema['maximum'], $key);
+ break;
+ }
+ }
+ if (isset($schema['exclusiveMinimum'])) {
+ if ($schema['exclusiveMinimum'] >= $value) {
+ $this -> addError('103', $key . ':' . json_encode($value) . ' is less or than ' . $schema['exclusiveMinimum'] . ' or equal', $key);
+ break;
+ }
+ }
+ if (isset($schema['exclusiveMaximum'])) {
+ if ($schema['exclusiveMaximum'] <= $value) {
+ $this -> addError('103', $key . ':' . $value . ' is bigger than ' . $schema['exclusiveMaximum'] . ' or equal', $key);
+ break;
+ }
+ }
+ $isVali = true;
+ } while (false);
+
+ return $isVali;
+ }
+
+ /**
+ * check type: integer
+ *
+ * @param integer $value
+ * @param array $schema
+ * @return boolean
+ */
+ private function checkInteger($value, $key, $schema) {
+ // integer
+ if (!is_integer($value)) {
+ $this -> addError('101', $key . ': ' . $value . ' is not a integer', $key);
+ return false;
+ }
+ return $this -> checkNumber($value, $schema);
+ }
+
+ /**
+ * check type: boolean
+ *
+ * @param boolean $value
+ * @param array $schema
+ * @return boolean
+ */
+ private function checkBoolean($value, $key, $schema) {
+ // boolean
+ if (!is_bool($value)) {
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not a boolean.', $key);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * check type: object
+ *
+ * @param object $valueProp
+ * @param array $schema
+ * @return boolean
+ */
+ private function checkObject($value, $key = null, $schema = null) {
+ // object
+ $isVali = false;
+
+ do {
+ if (!is_object($value)) {
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not an object.', $key);
+ break;
+ }
+ if (isset($schema['properties']) && !empty($schema['properties'])) {
+ $schemaProp = $schema['properties'];
+ // 正确的required应该与properties同级
+ if (!isset($schema['required']))
+ $schema['required'] = null;
+ if (!isset($schemaProp['required']))
+ $schemaProp['required'] = null;
+ $requireds = $schemaProp['required'] ? : $schema['required'];
+ $valueProp = get_object_vars($value);
+ $valueKeys = array_keys($valueProp);
+ $schemaKeys = array_keys($schemaProp);
+ $diffKeys = array_diff($valueKeys, $schemaKeys);
+ if (!empty($diffKeys)) {
+ foreach ($diffKeys as $key) {
+ // property not defined / not optional
+
+ if (!isset($schemaProp[$key]) || !isset($schemaProp[$key]['optional']) || !$schemaProp[$key]['optional']) {
+
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not exist,And its not a optional property.', $key);
+ break 2;
+ }
+ }
+ }
+ if (is_array($requireds)) {
+ if (is_object($value)) {
+ foreach ($value as $key => $v) {
+ if (isset($v)) {
+ } else {
+ if (in_array($key, $requireds)) {
+ $this -> addError('101', $key . ': ' . json_encode($value) . ' is not exist,And its not a optional property.', $key);
+ break 2;
+ }
+ }
+ $key_arr[] = $key;
+ }
+ foreach ($requireds as $reval) {
+ if (!in_array($reval, $key_arr)) {
+ $this -> addError('101', $reval . ' is not exist,And its not a optional property.', $reval);
+ break 2;
+ }
+ }
+ }
+ }
+
+ foreach ($schemaProp as $key => $sch) {
+ if (!isset($valueProp[$key])) {
+ continue;
+ }
+
+ if (!$this -> checkByType($valueProp[$key], $key, $sch)) {
+ break 2;
+ }
+ }
+ }
+ $isVali = true;
+ } while (false);
+ return $isVali;
+ }
+
+ /**
+ * check type: array
+ *
+ * @param array $value
+ * @param array $schema
+ * @return boolean
+ */
+ private function checkArray($value, $key, $schema) {
+ $isVali = false;
+ do {
+ if (!is_array($value)) {
+ $this -> addError('101', $key . ' : ' . json_encode($value) . ' is not an array.', $key);
+ break;
+ }
+
+ if (!isset($schema['items'])) {
+ $this -> addError('101', $this -> error('schema: items schema is undefined.'), $key);
+ break;
+ }
+ $size = count($value);
+ if (isset($schema['minItems'])) {
+ if ($schema['minItems'] > $size) {
+ $this -> addError('102', $this -> error('array size: ') . $size . $this -> error(' is less than ') . $schema['minItems'] . '.', $key);
+ break;
+ }
+ }
+ if (isset($schema['maxItems'])) {
+ if ($schema['maxItems'] < $size) {
+ $this -> addError('102', $this -> error('array size: ') . $size . $this -> error(' is bigger than ') . $schema['maxItems'] . '.', $key);
+ break;
+ }
+ }
+
+ foreach ($value as $val) {
+ if (!$this -> checkByType($val, '', $schema['items'])) {
+ break 2;
+ }
+ }
+
+ $isVali = true;
+ } while (false);
+ return $isVali;
+ }
+
+ /**
+ * check value based on type
+ *
+ * @param mixed $value
+ * @param array $schema
+ * @return boolean
+ */
+ private function checkByType($value, $key = null, $schema) {
+
+ $isVali = false;
+ if ($schema && isset($schema['type'])) {
+ // union types 联合类型
+ if (is_array($schema['type'])) {
+ $types = $schema['type'];
+ foreach ($types as $type) {
+
+ $schema['type'] = $type;
+ $isVali = $this -> checkByType($value, $key, $schema);
+
+ if ($isVali) {
+ break;
+ }
+ }
+ } else {
+ $type = $schema['type'];
+
+ switch ($type) {
+ case 'boolean' :
+ $isVali = $this -> checkBoolean($value, $key, $schema);
+ break;
+ case 'integer' :
+ if (preg_match("/^[0-9]+$/", $value)) {
+ $value = intval($value);
+ }
+ $isVali = $this -> checkInteger($value, $key, $schema);
+ break;
+ case 'number' :
+ $isVali = $this -> checkNumber($value, $key, $schema);
+ break;
+ case 'string' :
+ $isVali = $this -> checkString($value, $key, $schema);
+ break;
+ case 'array' :
+ $isVali = $this -> checkArray($value, $key, $schema);
+ break;
+ case 'object' :
+ $isVali = $this -> checkObject($value, $key, $schema);
+
+ break;
+ case 'enum' :
+ $isVali = is_null($value);
+ break;
+ case 'null' :
+ $isVali = is_null($value);
+ break;
+ case 'any' :
+ $isVali = true;
+ break;
+ default :
+ $this -> addError('101', $this -> error('type_schema : ') . $value . $this -> error(' is undefined.'), $key);
+ break;
+ }
+ }
+ }
+ if (isset($schema['$ref'])) {
+ $isVali = $this -> checkByType($value, $key, $this -> getType($schema['$ref']));
+ }
+ return $isVali;
+ }
+
+ /**
+ * Get errors
+ *
+ * @return array errors
+ */
+ public function getErrors() {
+
+ return json_encode(['error' => $this -> errors], true);
+ }
+ /**
+ * add error message
+ * @param string $msg
+ */
+ protected function addError($code = null, $msg = null, $key = null) {
+ $this -> errors = array('contents' => $this -> error('validate fail'), 'return_code' => '1100', 'message' => $this -> error($key) . $this -> error(': the format is not correct.'), 'timestamp' => time());
+ }
+
+ /**
+ * 报错信息
+ */
+ protected function error($message) {
+ // 入口已经处理了语种,这里再加没有意义
+ // $header = getallheaders();
+ // //获取头部信息,得到需要返回的语言
+ // $lan = $header['lan'];
+ // if($lan == 'zh_CN'){
+ // putenv('LANG=zh_CN');
+ // setlocale(LC_ALL, 'zh_CN'); //指定要用的语系,如:en_US、zh_CN、zh_TW
+ // }elseif ($lan == 'zh_TW'){
+ // putenv('LANG=zh_TW');
+ // setlocale(LC_ALL, 'zh_TW'); //指定要用的语系,如:en_US、zh_CN、zh_TW
+ // }elseif ($lan == 'en_US') {
+ // putenv('LANG=en_US');
+ // setlocale(LC_ALL, 'en_US'); //指定要用的语系,如:en_US、zh_CN、zh_TW
+ // }
+ // if ($lan == null) {
+ // putenv('LANG=en_US');
+ // setlocale(LC_ALL, 'en_US');
+ // }
+ // //默认开启zh_CN
+ // $locale = "zh_CN.utf8";
+ // setlocale(LC_ALL, $locale);
+ // //设置翻译文本域,下面的代码就会让程序去locale/zh_CN/LC_MESSAGES/default.mo去寻找翻译文件
+ // bindtextdomain("Education", $_SERVER['DOCUMENT_ROOT'].'locale');
+ // textdomain("Education");
+ $message = _($message);
+ return $message;
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/app/Common/LongbingCurl.php b/app/Common/LongbingCurl.php
new file mode 100755
index 0000000..656456c
--- /dev/null
+++ b/app/Common/LongbingCurl.php
@@ -0,0 +1,72 @@
+_error ? (object) [
+ 'errno' => $this->_errno,
+ 'error' => $this->_error
+ ] : NULL;
+ }
+ //基础请求
+ public function crulGetData($url, $post, $method, $header=1){
+ $this->_errno = NULL;
+ $this->_error = NULL;
+ $ch = curl_init($url);
+
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+ if($post != NULL)
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
+ curl_setopt($ch, CURLOPT_AUTOREFERER,true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 120);
+
+ if($header)
+ curl_setopt($ch, CURLOPT_HEADER, false);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+ 'Content-type: application/json',
+ )
+ );
+ $result = curl_exec($ch);
+ return $result;
+ }
+ //get请求
+ public function curlGet($url,$post=NULL){
+ $result = $this->crulGetData($url,$post,'GET');
+ return $result;
+ }
+ //post请求
+ public function curlPost($url,$post=NULL){
+ $result = $this->crulGetData($url,$post,'POST');
+ return $result;
+ }
+ //patch请求
+ public function curlPatch($url,$post){
+ $result = $this->crulGetData($url,$post,'PATCH');
+ return $result;
+ }
+ //put请求
+ public function curlPut($url,$post){
+ $result = $this->crulGetData($url,$post,'PUT');
+ return $result;
+ }
+ //deletd请求
+ public function curlDelete($url,$post){
+ $result = $this->crulGetData($url,$post,'DELETE',$heard=1);
+ return $result;
+ }
+
+ public function curlPublic($url,$post,$method = 'GET'){
+ $result = $this->crulGetData($url,$post,$method,$heard=1);
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/LongbingServiceNotice.php b/app/Common/LongbingServiceNotice.php
new file mode 100755
index 0000000..6748982
--- /dev/null
+++ b/app/Common/LongbingServiceNotice.php
@@ -0,0 +1,1100 @@
+uniacid = $uniacid;
+ $this->config = $this->getConfig($this->uniacid);
+ $this->appid = $this->getAppid();
+ $this->appsecret = $this->getAppsecret();
+ }
+
+ //获取appid
+ protected function getAppid()
+ {
+ if(isset($this->config['appid'])) return $this->config['appid'];
+ return null;
+ }
+
+ //获取appsecret
+ protected function getAppsecret()
+ {
+ if(isset($this->config['app_secret'])) return $this->config['app_secret'];
+ return null;
+ }
+
+ //获取config信息
+ public function getConfig($uniacid)
+ {
+
+ //config key
+ $key = 'longbing_card_app_config_' . $uniacid;
+ //获取config
+ $config = getCache($key, $uniacid);
+
+ //判断缓存是否存在
+ if(!empty($config)) return $config;
+ //不存在时查询数据库
+ //生成操作模型
+ $config_model = new AppConfig();
+ //获取数据
+ $config = $config_model -> getConfigByUniacid($uniacid);
+
+ //判断数据是否存在
+ if(!empty($config)) setCache($key ,$config ,3600,$uniacid);
+ //返回数据
+ return $config;
+ }
+
+ //检查信息是否存在
+ function checkConfig()
+ {
+ $result = true;
+ if(empty($this->uniacid) || empty($this->appid) || empty($this->appsecret)) $result = false;
+ return $result;
+ }
+
+ /**
+ * @Purpose: 获取用户的AccessToken
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ function lbSingleGetAccessToken ()
+ {
+
+ $setting = new WxSetting($this->uniacid);
+
+ $token = $setting->lbSingleGetAccessToken();
+
+ return $token;
+
+
+ //基础检查
+ if(!$this->checkConfig()) return false;
+ //appid
+ $appid = $this->appid;
+ //生成md5文件
+ $key = 'longbing_app_access_' . md5( $appid );
+ //生成必要文件
+ $access_token = null;
+ $ac_time = 0;
+ //获取access-data缓存
+ $access_data = getCache($key ,$this->uniacid);
+ //判断缓存是否存在
+ if(isset($access_data['access_token'])) $access_token = $access_data['access_token']; //access_token
+ if(isset($access_data['access_token'])) $ac_time = $access_data['ac_time']; //access_token 有效期
+ //判断缓存是否有效
+
+ if ( empty($access_token) || empty($ac_time) || $ac_time < time())
+ {
+ $access_token = $this->lbSingleGetAccessTokenNew();
+ }
+ return $access_token;
+ }
+ //生成新的token
+ function lbSingleGetAccessTokenNew ()
+ {
+ //基础检查
+ if(!$this->checkConfig()) return false;
+ //appid
+ $appid = $this->appid;
+ //appsecret
+ $appsecret = $this->appsecret;
+ //生成key
+ $key = 'longbing_app_access_' . md5( $appid );
+ $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
+ $data = file_get_contents( $url );
+ $data = json_decode( $data, true );
+ if ( !isset( $data[ 'access_token' ] ) )
+ {
+ return false;
+ }
+ //获取access_token
+ $access_data['access_token'] = $access_token = $data[ 'access_token' ];
+ $access_data['ac_time'] = time() + 7200;
+ //设置缓存
+ $result = setCache($key ,$access_data , 7200,$this->uniacid);
+ return $access_token;
+ return false;
+ }
+
+ //发送微信服务通知
+ public function sendServiceNoticeToStaff($count_id ,$to_user = null ,$extra_data = [])
+ {
+ //获取count
+ $count_model = new LongbingCardCount();
+ $count = $count_model->getCount(['id' => $count_id]);
+ //判断count是否存在
+ if(empty($count) || empty($count['user_id']) || empty($count['to_uid'])) return false;
+ if($count['user_id'] == $count['to_uid']) $to_user = false;
+ //判断是第几次
+ $check_where = ['user_id' => $count[ 'user_id' ],
+ 'to_uid' => $count[ 'to_uid' ],
+ 'type' => $count[ 'type' ],
+ 'uniacid' => $count[ 'uniacid' ],
+ 'target' => $count[ 'target' ],
+ 'sign' => $count[ 'sign' ] ];
+ if ( ( $count[ 'type' ] == 18 || $count[ 'type' ] == 19 || $count[ 'type' ] == 20 ) && $count[ 'sign' ] == 'view' )
+ {
+ unset( $check_where[ 'target' ] );
+ }
+ $count_num = $count_model->getCountNum($check_where);
+ if(empty($count_num)) $count_num = 1;
+ //获取client
+ $client_info_model = new LongbingClientInfo();
+ $client_info = $client_info_model->getClientInfo(['user_id' => $count['user_id'] ,'staff_id' => $count['to_uid']]);
+ //
+// $send = true;
+ if(!empty($client_info) && isset($client_info[ 'is_mask' ]) && !empty($client_info['is_make'])) return false;
+ //获取发送数据
+ $send_body = $this->lbSingleGetSendBody($count , 0 ,$extra_data);
+
+
+
+ if(empty($send_body)) return false;
+
+// if ( $count[ 'sign' ] != 'order' && $count[ 'type' ] < 18 && !( $count[ 'sign' ] == 'praise' && $count[ 'type' ] == 8 ) )
+// {
+// $send_body = '第' . $count_num . '次' . $send_body;
+// }
+ //获取用户信息
+ $user = longbingGetUser($count['user_id'] ,$this->uniacid);
+ //员工信息
+ $staff = longbingGetUser($count['to_uid'] ,$this->uniacid);
+ if(!empty($to_user)) $this->sendServiceNoticeToUser($count ,$count_num ,$send_body ,$user);
+
+// dump($send_body,$user['nickName']);exit;
+
+ switch($this->config['notice_switch'])
+ {
+ //发送公众号通知
+ case 1:
+ if(!isset($staff['openid'])) break;
+ $this->sendWxOAServiceNotice($staff['openid'] ,$user['nickName'] ,$send_body ,$count['update_time']);
+ break;
+ //发送企业微信通知
+ case 2:
+ $this->sendWxEnterpriseServiceNotice($count['to_uid'] ,$user['nickName'] ,$send_body ,$count);
+ break;
+ //发送微信服务通知
+ case 3:
+ $from_id = $this->lbSingleGetFormId($count['to_uid']);
+ if(!isset($staff['openid']) || empty($from_id)) break;
+ $this->sendWxService($staff['openid'] ,$from_id ,$user['nickName'] ,$send_body ,$count['update_time']);
+ break;
+ case 4:
+ $this->sendCompanyWxEnterpriseServiceNotice($count['to_uid'] ,$user['nickName'] ,$send_body);
+ break;
+ default:
+ $from_id = $this->lbSingleGetFormId($count['to_uid']);
+ if(!isset($staff['openid']) || empty($from_id)) break;
+ $this->sendWxService($staff['openid'] ,$from_id ,$user['nickName'] ,$send_body ,$count['update_time']);
+ break;
+ }
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-06 13:14
+ * @功能说明:发送企业微信小程序通知
+ */
+ public function sendCompanyWxEnterpriseServiceNotice($to_uid,$nick_name,$send_body){
+
+ $wx_msg = new WxMsg( $this->uniacid);
+ //获取用户详情
+ $user_info_model = new LongbingUserInfo();
+
+ $user_info = $user_info_model->getUser(['fans_id' => $to_uid]);
+ //判断用户是否存在
+ $touser = null;
+ if(isset($user_info['ww_account'])) $touser = $user_info['ww_account'];
+ //判断数据是否存在
+ if(empty($touser)) return false;
+
+ $content = [
+
+ [
+ 'key' => '访问用户',
+
+ 'value' => $nick_name
+
+ ],
+ [
+ 'key' => '内容',
+
+ 'value' => $send_body
+
+ ],
+ ];
+
+ $res = $wx_msg->WxMsg($touser,'访问通知','pages/admin/radar/radar',date('Y-m-d H:i:s',time()),$content);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-06 13:14
+ * @功能说明:发送企业微信小程序通知
+ */
+ public function sendCompanyWxEnterpriseServiceNoticeIm($to_uid,$nick_name,$send_body){
+
+ $wx_msg = new WxMsg( $this->uniacid);
+ //获取用户详情
+ $user_info_model = new LongbingUserInfo();
+
+ $user_info = $user_info_model->getUser(['fans_id' => $to_uid]);
+ //判断用户是否存在
+ $touser = null;
+
+ if(isset($user_info['ww_account'])) $touser = $user_info['ww_account'];
+ //判断数据是否存在
+ if(empty($touser)) return false;
+
+ $content = [
+
+ [
+ 'key' => '访问用户',
+
+ 'value' => $nick_name
+
+ ],
+ [
+ 'key' => '内容',
+
+ 'value' => $send_body
+
+ ],
+ ];
+
+ $res = $wx_msg->WxMsg($touser,'聊天通知','pages/admin/chat/chat',date('Y-m-d H:i:s',time()),$content);
+
+ return $res;
+
+ }
+
+
+ //发送微信服务通知
+ public function sendImMessageServiceNoticeToStaff( $staff_id ,$message, $name = '')
+ {
+
+ //判断是否为员工,是员工才发送
+
+ if(LongbingUserInfoService::isStraffByUserId($staff_id)) {
+
+
+ $openid = LongbingUserService::getUserOpenId($staff_id);
+ $name = empty($name) ? LongbingUserInfoService::getNameByUserId($staff_id) : $name;
+ $time = LongbingTime::getChinaNowTime();
+
+ switch ($this->config['notice_switch']) {
+ //发送公众号通知
+ case 1:
+ $this->sendWxOAServiceNotice($openid, $name, $message, $time);
+ break;
+ //发送企业微信通知
+ case 2:
+ $count = [
+
+ 'sign' => 'view',
+
+ 'type' => 10000,
+ ];
+
+ $this->sendWxEnterpriseServiceNotice($staff_id, $name, $message, $count);
+ break;
+ case 4:
+ //企业微信小程序通知
+ $this->sendCompanyWxEnterpriseServiceNoticeIm($staff_id ,$name ,$message);
+ break;
+
+ }
+
+ }
+ }
+
+
+ //向用户发送服务通知
+ public function sendServiceNoticeToUser($count ,$count_num ,$send_body ,$user)
+ {
+ //获取uniacid
+ $uniacid = $this->uniacid;
+ //判断是第几次
+ if(empty($count_num)) $count_num = 1;
+ //判断send_body是否存在
+ if(empty($send_body)) return false;
+ //判断count是否存在
+ if(empty($count) || !isset($count['user_id'])) return false;
+ //获取open_id
+ if(!isset($user['openid']) || !isset($user['nickName'])) return false;
+ $openid = $user['openid'];
+ //获取时间
+ if(!isset($count[ 'create_time' ]) || empty($count[ 'create_time' ])) $count[ 'create_time' ] = time();
+ //获取FromId
+ $from_id = $this->lbSingleGetFormId($count['user_id']);
+ //判断from_id是否存在
+ if(empty($from_id)) return false;
+ //发送数据
+ return $this->sendWxService($openid ,$from_id ,$user['nickName'] ,$send_body ,$count[ 'create_time' ]);
+ }
+
+ //发送聊天服务通知
+ public function sendMessageServiceNotice($message)
+ {
+ //获取uniacid
+ $uniacid = $this->uniacid;
+ //判断send_body是否存在
+ if(empty($message) || !isset($message['content'])) return false;
+ //获取用户信息
+ $user = longbingGetUser($message['user_id'] ,$this->uniacid);
+// var_dump(1111111);die;
+ //判断User是否存在
+ if(empty($user) || !isset($user['nickName'])) return false;
+ //获取open_id
+ $to_user = longbingGetUser($message['to_user_id'] ,$this->uniacid);
+ if(!isset($to_user['openid']) || !isset($to_user['id'])) return false;
+ $openid = $to_user['openid'];
+ //获取时间
+ if(!isset($message[ 'create_time' ]) || empty($message[ 'create_time' ])) $message[ 'create_time' ] = time();
+ //获取FromId
+ $from_id = $this->lbSingleGetFormId($to_user['id']);
+ //判断from_id是否存在
+ if(empty($from_id)) return false;
+ //跳转地址
+ $page = "pages/user/home";
+ if(isset($to_user['is_staff']) && !empty($to_user['is_staff']))
+ {
+ $page = "pages/admin/chat/chat";
+ }
+ //发送数据
+ return $this->sendWxService($openid ,$from_id ,$user['nickName'] ,$message['content'] ,$message[ 'create_time' ] ,$page);
+ }
+
+
+
+ /*
+ * 发送微信服务通知
+ * openid 微信openid
+ * from fromid
+ * nickName 昵称
+ * sendbody 数据
+ * date 消息产生的时间
+ */
+ public function sendWxService($openid ,$form ,$nickName ,$send_body ,$time = null ,$page_data = null)
+ {
+ //获取access_token
+ $access_token = $this->lbSingleGetAccessToken();
+ //判断access_token是否存在
+ if(empty($access_token)) return false;
+ //判断mini_template_id是否存在
+ if(!isset($this->config[ 'mini_template_id' ])) return false;
+ //生成请求url
+ $url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={$access_token}";
+// $page = "longbing_card/pages/index/index?to_uid={$count_info['to_uid']}¤tTabBar=toCard";
+ $page = "pages/admin/radar/radar";
+ if(!empty($page_data)) $page = $page_data;
+ //获取时间
+ if(empty($time) || !is_int($time)) $time = time();
+ $date = date( 'Y-m-d H:i', $time );
+ $postData = [ 'touser' => $openid,
+ 'template_id' => $this->config[ 'mini_template_id' ],
+ 'page' => $page,
+ 'form_id' => $form,
+ 'data' => [ 'keyword1' => [ 'value' => $nickName ], 'keyword2' => [ 'value' => $send_body ],
+ 'keyword3' => [ 'value' => $date ], ], ];
+ //封装数据
+ $postData = json_encode( $postData, JSON_UNESCAPED_UNICODE );
+ //请求数据
+ $response = $this->curlPost( $url, $postData );
+ return $response;
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-12-25 11:52
+ * @param $data
+ * @return bool|string
+ * descrption:添加模版 返回模版消息id
+ */
+ public function addTmpl($data){
+ $access_token = $this->lbSingleGetAccessToken();
+
+ $url = "https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate?access_token={$access_token}";
+// $data = [
+// 'tid' => '1754',
+// 'kidList' => [4,2,1,3],
+// 'sceneDesc'=>'test'
+// ];
+ $data = json_encode( $data, JSON_UNESCAPED_UNICODE );
+
+ $res = $this->curlPost( $url,$data );
+ return $res;
+
+ }
+
+
+
+
+
+
+ //发送公众号通知 (WeChat Official Account)
+ public function sendWxOAServiceNotice($openid ,$nickName ,$send_body ,$time = null)
+ {
+ //微信公众号appid
+ $wx_appid = null;
+ //wx_tplid
+ $wx_tplid = null;
+ if(isset($this->config['wx_appid'])) $wx_appid = $this->config['wx_appid'];
+ if(isset($this->config['wx_tplid'])) $wx_tplid = $this->config['wx_tplid'];
+ //判断关键数据是否存在
+ if(empty($wx_appid) || empty($wx_tplid)) return false;
+ //获取access_token
+ $access_token = $this->lbSingleGetAccessToken();
+ if(empty($access_token)) return false;
+ //请求地址
+ $url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token={$access_token}";
+ //获取时间
+ if(empty($time) || !is_int($time)) $time = time();
+ $date = date( 'Y-m-d H:i', $time);
+ $page = "pages/admin/radar/radar";
+
+ $data = [ 'touser' => $openid,
+ 'mp_template_msg' => [ 'appid' => $wx_appid,
+ "url" => "http://weixin.qq.com/download",
+ 'template_id' => $wx_tplid,
+ 'miniprogram' => [ 'appid' => $this->appid, 'pagepath' => $page, ],
+ 'data' => array( 'first' => array( 'value' => '' ,'color' => '#c27ba0', ),
+ 'keyword1' => array( 'value' => $nickName ,'color' => '#93c47d', ),
+ 'keyword2' => array( 'value' => $send_body ,'color' => '#0000ff', ),
+ 'remark' => array( 'value' => $date ,'color' => '#45818e', ), ) ], ];
+ //数据转化
+ $data = json_encode( $data, JSON_UNESCAPED_UNICODE );
+ //发送数据
+ $res = $this->curlPost( $url, $data );
+ }
+
+ //发送企业微信通知
+ public function sendWxEnterpriseServiceNotice($to_uid ,$nick_name ,$send_body ,$count_info)
+ {
+ //获取appid
+ $app_id = null;
+ //获取appsecret
+ $appsecret = null;
+ //获取agentid
+ $agentid = null;
+ //获取数据
+ if(isset($this->config['corpid'])) $app_id = $this->config['corpid'];
+ if(isset($this->config['corpsecret'])) $appsecret = $this->config['corpsecret'];
+ if(isset($this->config['agentid'])) $agentid = $this->config['agentid'];
+ //判断数据是否存在
+ if(empty($app_id) || empty($appsecret) || empty($agentid)) return false;
+ //获取用户详情
+ $user_info_model = new LongbingUserInfo();
+
+ $user_info = $user_info_model->getUser(['fans_id' => $to_uid]);
+
+ //判断用户是否存在
+ $touser = null;
+
+
+ if(isset($user_info['ww_account'])) $touser = $user_info['ww_account'];
+ //判断数据是否存在
+ if(empty($touser)) return false;
+ //封装数据
+ $data = array( 'touser' => $touser, 'msgtype' => 'text', 'agentid' => $agentid,
+ 'text' => array( 'content' => $nick_name . ',' . $send_body, ), );
+
+
+
+ //获取count
+ if ( $count_info[ 'sign' ] == 'view' && $count_info[ 'type' ] )
+ {
+
+ if(in_array($count_info[ 'type' ],[662,663,664,665,666])){
+
+ $table_name = 'longbing_card_shortvideo';
+
+ }elseif(in_array($count_info[ 'type' ],[1,19,21,22,23,24])){
+
+ $table_name = 'longbing_card_goods';
+ }
+
+ if(!empty($table_name)){
+
+ $info = $this->longbingGetRow( $table_name, [ 'id' => $count_info[ 'target' ] ] );
+ }
+
+ if(!empty($info['cover'])){
+
+ $info = transImagesOne($info,['cover']);
+
+ $cover = $info['cover'];
+ }
+
+ $data = array(
+ 'touser' => $touser,
+
+ 'msgtype' => 'news',
+
+ 'agentid' => $agentid,
+
+ 'news' => array(
+ 'articles' => array(
+ array(
+ 'title' => $nick_name,
+
+ 'description' => $send_body,
+
+// 'url' => $cover,
+//
+// 'picurl' => $cover,
+ ),
+ ),
+ ),
+ );
+
+ }
+
+ if(!empty($cover)){
+
+ $data['news']['articles'][0]['url'] = $cover;
+
+ $data['news']['articles'][0]['picurl'] = $cover;
+
+ }
+// include_once APP_PATH . '/Common/extend/wxWork/work.weixin.class.php';
+ $work = new work( $app_id, $appsecret );
+ $result = $work->send( $data );
+
+
+ }
+
+ public function lbSingleAutoDelFromId()
+ {
+ $from_id_model = new LongbingCardFromId();
+ //获取数据
+ $from_id_model->autoDelFromId();
+ }
+
+ //获取fromid
+ public function lbSingleGetFormId ( $to_uid )
+ {
+ // 七天前开始的的时间戳
+ $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - 6, date( 'Y' ) );
+ //自动删除
+ $this->lbSingleAutoDelFromId();
+ //生成fromId模型
+ $from_id_model = new LongbingCardFromId();
+ //获取数据
+ $from_id = $from_id_model->getFromId([ 'user_id' => $to_uid ]);
+ if ( empty( $from_id ) )
+ {
+ return false;
+ }
+ if ( $from_id[ 'create_time' ] < $beginTime )
+ {
+ $from_id_model->delFromId(['id' => $from_id['id']]);
+ return $this->lbSingleGetFormId ( $to_uid );
+ }
+ else
+ {
+ $from_id_model->delFromId(['id' => $from_id['id']]);
+ return $from_id[ 'formId' ];
+ }
+ return false;
+ }
+
+ public function longbingGetRow($table_name ,$filter)
+ {
+ if(empty($table_name) || empty($filter) || !is_array($filter)) return false;
+ $common_model = new LongbingCardCommonModel();
+ return $common_model->getRows($table_name ,$filter);
+ }
+
+
+ /**
+ * @Purpose: 给员工发送内容
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ function lbSingleGetSendBody ( $count_info = array(), $count_id = 0, $extra_data = [] )
+ {
+ //获取uniacid
+ $uniacid = $this->uniacid;
+ //获取数据
+ $tabbar_model = new LongbingTabbar();
+ $tabbar = $tabbar_model->getTabbar(['uniacid' => $uniacid]);
+ if ( empty( $count_info ) && $count_id == 0 )
+ {
+ return false;
+ }
+ if ( empty( $count_info ) && $count_id != 0 )
+ {
+ $count_model = new LongbingCardCount();
+ $count_info = $count_model->getCount(['id' => $count_id]);
+ if ( !$count_info )
+ {
+ return false;
+ }
+ }
+ //修改雷达文案
+ $datas = lbHandelRadarMsg([$count_info]);
+
+ $body = '';
+
+ if(!empty($datas[0]['radar_arr'])){
+
+ foreach ($datas[0]['radar_arr'] as $value){
+
+ $body.= $value['title'];
+
+ }
+
+ }
+
+ return $body;
+
+ if ( $count_info[ 'sign' ] == 'praise' )
+ {
+ switch ( $count_info[ 'type' ] )
+ {
+ case 2:
+ $body = '浏览你的名片';
+ break;
+ case 4:
+ $body = '分享你的名片';
+ break;
+
+ case 5:
+ $body = '资讯你的房产';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_house', [ 'id' => $count_info[ 'target' ] ] );
+// $info = $this->longbingGetHouse($count_info[ 'target' ]);
+ if ( $info )
+ {
+ $body .= $info[ 'title' ];
+ }
+ }
+
+ break;
+ case 6:
+ $body = '收藏你的房产';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_house', [ 'id' => $count_info[ 'target' ] ] );
+// $info = $this->longbingGetHouse($count_info[ 'target' ]);
+ if ( $info )
+ {
+ $body .= $info[ 'title' ];
+ }
+ }
+ break;
+ case 7:
+ $body = '拨打你的房产';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_house', [ 'id' => $count_info[ 'target' ] ] );
+// $info = $this->longbingGetHouse($count_info[ 'target' ]);
+ if ( $info )
+ {
+ $body .= $info[ 'title' ];
+ }
+ }
+ break;
+ case 8:
+ $time = time();
+ if(!empty($count_info['update_time'])) $time = $count_info['update_time'];
+ $time = date('Y/m/d-h:i' ,$time);
+ $body = '于' . $time . '预约看房 ';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_house', [ 'id' => $count_info[ 'target' ] ] );
+// $info = $this->longbingGetHouse($count_info[ 'target' ]);
+ if ( $info )
+ {
+ $body .= $info[ 'title' ];
+ }
+ }
+ break;
+ }
+ }
+
+ if ( $count_info[ 'sign' ] == 'view' )
+ {
+ switch ( $count_info[ 'type' ] )
+ {
+ case 1:
+ $body = '浏览' . $tabbar[ 'menu2_name' ] . '列表';
+ break;
+ case 2:
+ $body = '浏览' . $tabbar[ 'menu2_name' ] . '详情';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_goods', [ 'id' => $count_info[ 'target' ] ] );
+// $info = $this->longbingGetGoods($count_info[ 'target' ]);
+ $body .= ':' . $info[ 'name' ];
+ }
+ break;
+ case 3:
+ $body = '浏览' . $tabbar[ 'menu3_name' ] . '列表';
+ break;
+ case 4:
+ $body = '点赞' . $tabbar[ 'menu3_name' ];
+ break;
+ case 5:
+ $body = $tabbar[ 'menu3_name' ] . '留言';
+ break;
+ case 6:
+ $body = '浏览公司' . $tabbar[ 'menu4_name' ];
+ break;
+ case 7:
+ $body = '浏览' . $tabbar[ 'menu3_name' ] . '详情';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_timeline', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ];
+ }
+ break;
+ case 8:
+ $body = '浏览' . $tabbar[ 'menu3_name' ] . '视频详情';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_timeline', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ];
+ }
+ break;
+ case 9:
+ $body = '浏览' . $tabbar[ 'menu3_name' ] . '外链详情';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_timeline', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ];
+ }
+ break;
+ case 10:
+ $body = '浏览' . $tabbar[ 'menu3_name' ] . '跳转小程序';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_timeline', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ];
+ }
+ break;
+ case 12:
+ $body = '浏览' . $tabbar[ 'menu3_name' ] . '获客文章';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_timeline', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ];
+ }
+ break;
+ case 15:
+ $body = '浏览预约全部列表';
+ break;
+ case 16:
+ $body = '浏览预约分类';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'lb_appoint_classify', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ] . '列表';
+ }
+ break;
+ case 17:
+ $body = '浏览预约项目';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'lb_appoint_project', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ':' . $info[ 'title' ];
+ }
+ break;
+ case 18:
+ $body = '在官网留言';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_form', [ 'id' => $count_info[ 'target' ] ] );
+ $body .= ', 姓名: ' . $info[ 'name' ] . ', 手机号: ' . $info[ 'phone' ] . ', 内容: ' . $info[ 'content' ];
+ }
+ break;
+ case 19:
+ $body = '订单已发货';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ] . '...';
+ }
+ }
+ break;
+ case 20:
+ $body = '订单已自提';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ] . '...';
+ }
+ }
+ break;
+ case 21:
+ $body = '退款申请已提交, 请等待管理员审核';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ] . '...';
+ }
+ }
+ break;
+ case 22:
+ $body = '退款申请已取消';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ] . '...';
+ }
+ }
+ break;
+ case 23:
+ $body = '退款申请已被拒绝';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ] . '...';
+ }
+ }
+ break;
+ case 24:
+ $body = '退款已成功, 请注意查收';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ] . '...';
+ }
+ }
+ break;
+ case 25:
+ $body = '浏览' . $tabbar[ 'menu_activity_name' ] . '全部列表';
+ break;
+ case 26:
+ $body = '浏览' . $tabbar[ 'menu_activity_name' ] . '分类: ';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'lb_activity_classify', [ 'id' => $count_info[ 'target' ] ] );
+
+ if ( $info )
+ {
+ $body .= $info[ 'title' ] . '列表';
+ }
+ }
+ break;
+ case 27:
+ $body = '浏览' . $tabbar[ 'menu_activity_name' ] . ', ';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'lb_activity_activity', [ 'id' => $count_info[ 'target' ] ] );
+
+ if ( $info )
+ {
+ $body .= $info[ 'title' ] . '详情';
+ }
+ }
+ break;
+ case 28:
+ $body = '报名参加' . $tabbar[ 'menu_activity_name' ] . ': ';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'lb_activity_activity', [ 'id' => $count_info[ 'target' ] ] );
+
+ if ( $info )
+ {
+ $body .= $info[ 'title' ];
+ }
+ }
+ break;
+
+ case 29:
+ $body = '查看房产首页';
+ break;
+
+ case 30:
+ $body = '查看房产';
+ if ( $count_info[ 'target' ] )
+ {
+ $info = $this->longbingGetRow( 'longbing_card_house', [ 'id' => $count_info[ 'target' ] ] );
+ if ( $info )
+ {
+ $body .= $info[ 'title' ];
+ }
+ }
+ break;
+ }
+ }
+
+ if ( $count_info[ 'sign' ] == 'copy' )
+ {
+ switch ( $count_info[ 'type' ] )
+ {
+ case 1:
+ $body = '同步到通讯录';
+ break;
+ case 2:
+ $body = '拨打手机号';
+ break;
+ case 3:
+ $body = '拨打座机号';
+ break;
+ case 4:
+ $body = '复制微信';
+ break;
+ case 5:
+ $body = '复制邮箱';
+ break;
+ case 6:
+ $body = '复制公司名';
+ break;
+ case 7:
+ $body = '查看定位';
+ break;
+ case 8:
+ $body = '咨询产品';
+ break;
+ case 9:
+ $body = '播放语音';
+ break;
+ case 10:
+ $body = '保存名片海报';
+ break;
+ case 11:
+ $body = '拨打400热线';
+ break;
+ }
+ }
+ if ( $count_info[ 'sign' ] == 'order' )
+ {
+ switch ( $count_info[ 'type' ] )
+ {
+ case 1:
+ $body = '购买商品';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ // $body .= ',订单号:' . $order_info[ 'transaction_id' ];
+
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ];
+ }
+ }
+ break;
+ case 2:
+ $body = '参与拼团';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'longbing_card_shop_order', [ 'id' => $count_info[ 'target' ] ] );
+ $target_info = $this->longbingGetRow( 'longbing_card_shop_order_item', [ 'order_id' => $order_info[ 'id' ] ] );
+
+ if ( $order_info )
+ {
+ // $body .= ',订单号:' . $order_info[ 'transaction_id' ];
+
+ $body .= ',商品:' . $target_info[ 'name' ] . '-' . $target_info[ 'content' ];
+ }
+ }
+ break;
+ case 3:
+ $body = '预约订单';
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'lb_appoint_record', [ 'id' => $count_info[ 'target' ] ] );
+ $info = $this->longbingGetRow( 'lb_appoint_project', [ 'id' => $order_info[ 'project_id' ] ] );
+ $body .= ', 预约开始时间: ' . date( 'Y-m-d H:i:s', $order_info[ 'start_time' ] );
+ if ( $order_info[ 'remark' ] )
+ {
+ $body .= ', 预约备注信息: ' . $order_info[ 'remark' ];
+ }
+
+ $body .= ', 预约项目: ' . $info[ 'title' ];
+
+ }
+ break;
+ }
+
+ }
+
+ // 扫码支付
+ if ( $count_info[ 'sign' ] == 'qr' )
+ {
+ if ( $count_info[ 'target' ] )
+ {
+ $order_info = $this->longbingGetRow( 'lb_pay_qr_record', [ 'id' => $count_info[ 'target' ] ] );
+ $body = '扫码支付: ¥' . $order_info[ 'money' ];
+
+ }
+ }
+ if ( $body )
+ {
+ return $body;
+ }
+ return false;
+ }
+
+
+}
diff --git a/app/Common/PublisherApi.php b/app/Common/PublisherApi.php
new file mode 100755
index 0000000..598148d
--- /dev/null
+++ b/app/Common/PublisherApi.php
@@ -0,0 +1,205 @@
+configs = array(
+ 'host' => Config::get('rabbit.rabbit_host'),
+ 'port' => Config::get('rabbit.rabbit_port'),
+ 'login' => Config::get('rabbit.rabbit_login'),
+ 'password' => Config::get('rabbit.rabbit_passwd'),
+ 'vhost' => Config::get('rabbit.rabbit_vhost')
+ );
+ $this->qos_limit = Config::get('rabbit.rabbit_qos_limit');
+ $this->exchangeName = Config::get('rabbit.rabbit_exchange_name');
+ $this->queueName = Config::get('rabbit.rabbit_query_name');
+ $this->routingKey = Config::get('rabbit.rabbit_key');
+ }
+ public function publishMessage($message) {
+ $this->connection = new AMQPStreamConnection(
+ $this->configs['host'],
+ $this->configs['port'],
+ $this->configs['login'],
+ $this->configs['password'],
+ $this->configs['vhost']
+ );
+ // $channel = new \AMQPChannel($this->conn);
+ // $ex = new \AMQPExchange($channel);
+ // $ex->setName($this->exchangeName);
+ // $ex->setType(AMQP_EX_TYPE_DIRECT);
+ // $ex->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
+ // $ex->declare();
+ // $q = new \AMQPQueue($channel);
+ // $q->setName($this->queueName);
+ // $q->setFlags(AMQP_DURABLE | AMQP_AUTODELETE);
+ // $q->declare();
+ // $q->bind($this->exchangeName, $this->routingKey);
+ // $ex->publish($message, $this->routingKey);
+ // $this->conn->disconnect();
+ $connection = $this->connection;
+ $channel = $connection->channel();
+ $channel->exchange_declare($this->exchangeName, 'direct', false, false, false);
+ $channel->queue_declare($this->queueName, false, true, false, false, false);
+ $channel->queue_bind($this->queueName, $this->exchangeName, $this->routingKey);
+
+ $msg = new AMQPMessage($message, array(
+ 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
+ ));
+
+ $channel->basic_publish($msg, $this->exchangeName, $this->routingKey);
+
+ $channel->close();
+ $connection->close();
+ }
+ public function delayMessage($message, $expiration = 10000) {
+ $this->connection = new AMQPStreamConnection(
+ $this->configs['host'],
+ $this->configs['port'],
+ $this->configs['login'],
+ $this->configs['password'],
+ $this->configs['vhost']
+ );
+ $connection = $this->connection;
+// var_dump($connection);die;
+ $channel = $connection->channel();
+
+ $cache_exchange_name = 'cache_exchange' . $expiration;
+
+ $cache_queue_name = 'cache_queue' . $expiration;
+ $channel->exchange_declare($this->exchangeName, 'direct', false, false, false);
+ $channel->exchange_declare($cache_exchange_name, 'direct', false, false, false);
+
+ $tale = new AMQPTable();
+ $tale->set('x-dead-letter-exchange', $this->exchangeName);
+ $tale->set('x-dead-letter-routing-key', $this->routingKey);
+ $tale->set('x-message-ttl', $expiration);
+ $channel->queue_declare($cache_queue_name, false, true, false, false, false,$tale);
+ $channel->queue_bind($cache_queue_name, $cache_exchange_name, '');
+
+ $channel->queue_declare($this->queueName, false, true, false, false, false);
+ $channel->queue_bind($this->queueName, $this->exchangeName, $this->routingKey);
+
+ $msg = new AMQPMessage($message, array(
+ 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
+ ));
+
+ $channel->basic_publish($msg, $cache_exchange_name, '');
+
+ $channel->close();
+ $connection->close();
+ }
+ public function scheduleMessage($message, $taskName, $expiration = 10000) {
+ $this->connection = new AMQPStreamConnection(
+ $this->configs['host'],
+ $this->configs['port'],
+ $this->configs['login'],
+ $this->configs['password'],
+ $this->configs['vhost']
+ );
+ $connection = $this->connection;
+ $channel = $connection->channel();
+
+ $schedule_exchange_name = 'schedule_exchange_' . $taskName;
+ $schedule_queue_name = 'schedule_queue_' . $taskName;
+
+ $channel->exchange_declare($this->exchangeName, 'direct', false, false, false);
+ $channel->exchange_declare($schedule_exchange_name, 'direct', false, false, false);
+
+ $tale = new AMQPTable();
+ $tale->set('x-dead-letter-exchange', $this->exchangeName);
+ $tale->set('x-dead-letter-routing-key', $this->routingKey);
+ $tale->set('x-message-ttl', $expiration);
+
+ $channel->queue_declare($schedule_queue_name, false, false, false, false, false,$tale);
+ $channel->queue_bind($schedule_queue_name, $schedule_exchange_name, '');
+
+ $channel->queue_declare($this->queueName, false, true, false, false, false);
+ $channel->queue_bind($this->queueName, $this->exchangeName, $this->routingKey);
+
+ $msg = new AMQPMessage($message, array(
+ 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
+ ));
+
+ $channel->basic_publish($msg, $schedule_exchange_name, '');
+
+ $channel->close();
+ $connection->close();
+ }
+ public function scheduleInfo($taskName, $expiration = 10000) {
+ $this->connection = new AMQPStreamConnection(
+ $this->configs['host'],
+ $this->configs['port'],
+ $this->configs['login'],
+ $this->configs['password'],
+ $this->configs['vhost']
+ );
+ $connection = $this->connection;
+ $channel = $connection->channel();
+
+ $schedule_queue_name = 'schedule_queue_' . $taskName;
+
+ $tale = new AMQPTable();
+ $tale->set('x-dead-letter-exchange', $this->exchangeName);
+ $tale->set('x-dead-letter-routing-key', $this->routingKey);
+ $tale->set('x-message-ttl', $expiration);
+ $result = $channel->queue_declare($schedule_queue_name, false, false, false, false, false,$tale);
+
+ $channel->close();
+ $connection->close();
+ $result = $result ?: [0, 0];
+ return [
+ 'ready' => $result[1],
+ 'unacked' => $result[2]
+ ];
+ }
+ public function consumer() {
+ $this->connection = new AMQPStreamConnection(
+ $this->configs['host'],
+ $this->configs['port'],
+ $this->configs['login'],
+ $this->configs['password'],
+ $this->configs['vhost'],
+ false, // insist
+ 'AMQPLAIN', // login_method
+ null, // login_response
+ 'en_US', // locale
+ 3, // connection_timeout
+ 360, // read_write_timeout
+ null, // context
+ false, // keepalive
+ 180 // heartbeat
+ );
+ $connection = $this->connection;
+ $channel = $connection->channel();
+ $channel->exchange_declare($this->exchangeName, 'direct', false, false, false);
+ $channel->queue_declare($this->queueName, false, true, false, false, false);
+ $channel->queue_bind($this->queueName, $this->exchangeName, $this->routingKey);
+ $callback = function ($msg) {
+ // message原文位于消息对象body属性中
+ messagesProcess($msg);
+ };
+
+ //流量控制
+ $channel->basic_qos(null, $this->qos_limit, null);
+ $channel->basic_consume($this->queueName, '', false, false, false, false, $callback);
+ while (count($channel->callbacks)) {
+ $channel->wait();
+ }
+ $channel->close();
+ $connection->close();
+ }
+}
+
diff --git a/app/Common/Rsa2.php b/app/Common/Rsa2.php
new file mode 100755
index 0000000..d02c056
--- /dev/null
+++ b/app/Common/Rsa2.php
@@ -0,0 +1,26 @@
+ "sha512",
+ "private_key_bits" =>2048,
+ "private_key_type" => OPENSSL_KEYTYPE_RSA
+ );
+
+ function __construct(){
+ $res = openssl_pkey_new($this->config);
+ //生成私钥
+ openssl_pkey_export($res, $this->private_key, null, $this->config);
+ //生成公钥
+ $this->public_key = openssl_pkey_get_details($res)['key'];
+ }
+ public function getKeys() {
+ $result = [];
+ if(!empty($this->private_key)) $result['private_key'] =$this->private_key;
+ if(!empty($this->public_key)) $result['public_key'] =$this->public_key;
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/Rsa2Sign.php b/app/Common/Rsa2Sign.php
new file mode 100755
index 0000000..b8f0c57
--- /dev/null
+++ b/app/Common/Rsa2Sign.php
@@ -0,0 +1,98 @@
+PRIVATE_KEY = $keys['private_key'];
+ $this->PUBLIC_KEY = $keys['public_key'];
+ }
+ /**
+ * 获取私钥
+ * @return bool|resource
+ */
+ private function getPrivateKey()
+ {
+ return openssl_pkey_get_private($this->PRIVATE_KEY);
+ }
+ /**
+ * 获取公钥
+ * @return bool|resource
+ */
+ private function getPublicKey()
+ {
+ return openssl_pkey_get_public($this->PUBLIC_KEY);
+ }
+ /**
+ * 创建签名
+ * @param string $data 数据
+ * @return null|string
+ */
+ public function createSign($data = '')
+ {
+ // var_dump(self::getPrivateKey());die;
+ if (!is_string($data)) {
+ return null;
+ }
+ return openssl_sign($data, $sign, $this->getPrivateKey(),OPENSSL_ALGO_SHA256 ) ? base64_encode(base64_encode($sign)) : null;
+ }
+ /**
+ * 验证签名
+ * @param string $data 数据
+ * @param string $sign 签名
+ * @return bool
+ */
+ public function verifySign($data = '', $sign = '')
+ {
+ if (!is_string($sign) || !is_string($sign)) {
+ return false;
+ }
+ $sign = base64_decode($sign);
+ return (bool)openssl_verify(
+ $data,
+ base64_decode($sign),
+ $this->getPublicKey(),
+ OPENSSL_ALGO_SHA256
+ );
+ }
+ /**
+ * 加密
+ * @param string $data 数据
+ * @return string $result
+ */
+ public function encrypt($data){
+ $key = openssl_pkey_get_public($this->PUBLIC_KEY);
+ if (!$key) {
+ return false;
+ }
+ $return_en = openssl_public_encrypt($data, $crypted, $key);
+ if (!$return_en) {
+ return false;
+ }
+ $eb64_cry = base64_encode($crypted);
+ return $eb64_cry;
+ }
+ /**
+ * 解密
+ * @param string $data 数据
+ * @return string $result
+ */
+ public function decrypt($data){
+ $private_key = openssl_pkey_get_private($this->PRIVATE_KEY);
+ if (!$private_key) {
+ return false;
+ }
+ $return_check = openssl_private_decrypt(base64_decode($data), $decrypted, $private_key);
+ if (!$return_check) {
+ return false;
+ }
+ return $decrypted;
+ }
+}
diff --git a/app/Common/UniPush.php b/app/Common/UniPush.php
new file mode 100755
index 0000000..6ead2e8
--- /dev/null
+++ b/app/Common/UniPush.php
@@ -0,0 +1,68 @@
+set_appId(APPID);//应用appid
+ $template->set_appkey(APPKEY);//应用appkey
+ $template->set_transmissionType(2);//透传消息类型:1为激活客户端启动
+
+ //为了保证应用切换到后台时接收到个推在线推送消息,转换为{title:'',content:'',payload:''}格式数据,UniPush将在系统通知栏显示
+ //如果开发者不希望由UniPush处理,则不需要转换为上述格式数据(将触发receive事件,由应用业务逻辑处理)
+ //注意:iOS在线时转换为此格式也触发receive事件
+ $payload = array('title'=>$t, 'content'=>$c);
+ $pj = json_decode($p, TRUE);
+ $payload['payload'] = is_array($pj)?$pj:$p;
+ $template->set_transmissionContent(json_encode($payload));//透传内容
+
+ //兼容使用厂商通道传输
+ $notify = new IGtNotify();
+ $notify->set_title($t);
+ $notify->set_content($c);
+ $notify->set_intent($i);
+ $notify->set_type(NotifyInfo_type::_intent);
+ $template->set3rdNotifyInfo($notify);
+
+
+ //iOS平台设置APN信息,如果应用离线(不在前台运行)则通过APNS下发推送消息
+ $apn = new IGtAPNPayload();
+ $apn->alertMsg = new DictionaryAlertMsg();
+ $apn->alertMsg->body = $c;
+ $apn->add_customMsg('payload', is_array($pj)?json_encode($pj):$p);//payload兼容json格式字符串
+ $template->set_apnInfo($apn);
+ //个推老版本接口: $template ->set_pushInfo($actionLocKey,$badge,$message,$sound,$payload,$locKey,$locArgs,$launchImage);
+ //$template->set_pushInfo('', 0, $c, '', $p, '', '', '');
+
+ return $template;
+ }
+
+ public function push()
+ {
+ // 生成指定格式的intent支持厂商推送通道
+ $intent = "intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component={$package}/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title={$title};S.content={$content};S.payload={$payload};end";
+ pushMessageToSingle(createPushMessage($payload,$intent,$title,$content), $cid);
+ }
+}
diff --git a/app/Common/Upload.php b/app/Common/Upload.php
new file mode 100755
index 0000000..c2476f2
--- /dev/null
+++ b/app/Common/Upload.php
@@ -0,0 +1,359 @@
+uniacid = $uniacid;
+ $this->config = longbingGetOssConfig($uniacid);
+ $this->is_weiqin = longbingIsWeiqin();
+ }
+
+ //上传
+ public function upload($type ,$file,$config=array())
+ {
+
+ if(!empty($config)){
+
+ $this->config = $config;
+
+ }
+ $base_path = '/';
+ $type_data = 1;
+ switch($type)
+ {
+ //图片
+ case 'picture':
+ $base_path = $base_path . 'image/';
+ $type_data = 1;
+ break;
+ //音频
+ case 'audio':
+ $base_path = $base_path . 'audio/';
+ $type_data = 2;
+ break;
+ //视频
+ case 'video':
+ $base_path = $base_path . 'video/';
+ $type_data = 3;
+ break;
+ //证书
+ case 'cert':
+ $base_path = $base_path . 'cert/';
+ $type_data = 4;
+ break;
+ //证书
+ case 'wxuploadkey':
+ $base_path = $base_path . 'wxuploadkey/';
+ $type_data = 4;
+ break;
+ default:
+ $base_path = $base_path . 'image/';
+ $type_data = 1;
+ break;
+ }
+ //根据时间生成路径
+ $base_path = $base_path . $this->uniacid . '/' . date('y') . '/' . date('m');
+
+ $info = null;
+ $upload_status = false;
+
+// dump($this->checkFile($type ,$file));exit;
+ //数据检查
+ if($this->checkFile($type ,$file))
+ {
+ $file_name = null;
+ //本地保存
+ if(in_array($type, ['cert','wxuploadkey'])){
+ $file_name = $this->uniacid . '_' . $file->getOriginalName();
+ $this->config['open_oss'] = 0;
+ }
+ $info_path = $this->fileLoaclSave($base_path ,$file ,$file_name);
+ //获取数据
+ $info = $this->fileInfo($info_path ,$file->getOriginalName() ,$type_data);
+ //云服务器上传
+ if(isset($this->config['open_oss']))
+ {
+ switch($this->config['open_oss'])
+ {
+ //本地
+ case 0:
+ $upload_status = true;
+ $info['longbing_driver'] = 'loacl';
+ break;
+ case 1:
+ $oss_res = $this->aliyunUpload($info_path);
+
+ if(isset($this->config['aliyun_base_dir']) && !empty($this->config['aliyun_base_dir'])) $info_path = $this->config['aliyun_base_dir'] . '/' . $info_path;
+ if(in_array(substr($info_path,0,1) ,['/' ,"/"])) {
+ $info_path = substr($info_path,1,(strlen($info_path)-1));
+ }
+ $info['attachment'] = $info_path;
+ $info['longbing_driver'] = 'aliyun';
+ if(isset($oss_res['info']['url'])) $upload_status = true;
+ break;
+ case 2:
+ $oss_res = $this->qiniuUpload($info_path);
+ $info['longbing_driver'] = 'qiniuyun';
+ if(!empty($oss_res) && empty($oss_res[1])) $upload_status = true;
+ break;
+ case 3:
+ $oss_res = $this->tenxunUpoload($info_path);
+
+ $info['longbing_driver'] = 'tengxunyun';
+ if(isset($oss_res['ETag']) && isset($oss_res['ObjectURL'])) $upload_status = true;
+ break;
+ default:
+ $info['longbing_driver'] = 'loacl';
+ $upload_status = true;
+ break;
+ }
+ }else{
+ $upload_status = true;
+ $info['longbing_driver'] = 'loacl';
+ }
+ }
+ if(!$upload_status) $info = null;
+
+// dump($info);exit;
+ return $info;
+ }
+
+ //检查上传
+ public function uploadFile($info_path){
+ $info = [];
+ $upload_status = false;
+ if(isset($this->config['open_oss']))
+ {
+ switch($this->config['open_oss'])
+ {
+ //本地
+ case 0:
+ $upload_status = true;
+ $info['longbing_driver'] = 'loacl';
+ break;
+ case 1:
+ $oss_res = $this->aliyunUpload($info_path);
+ if(isset($this->config['aliyun_base_dir']) && !empty($this->config['aliyun_base_dir'])) $info_path = $this->config['aliyun_base_dir'] . '/' . $info_path;
+ if(in_array(substr($info_path,0,1) ,['/' ,"/"])) {
+ $info_path = substr($info_path,1,(strlen($info_path)-1));
+ }
+ $info['attachment'] = $info_path;
+ $info['longbing_driver'] = 'aliyun';
+ if(isset($oss_res['info']['url'])) $upload_status = true;
+ break;
+ case 2:
+ $oss_res = $this->qiniuUpload($info_path);
+ $info['longbing_driver'] = 'qiniuyun';
+ if(empty($oss_res[1])) $upload_status = true;
+ break;
+ case 3:
+ $oss_res = $this->tenxunUpoload($info_path);
+ $info['longbing_driver'] = 'tengxunyun';
+ if(isset($oss_res['ETag']) && isset($oss_res['ObjectURL'])) $upload_status = true;
+ break;
+ default:
+ $info['longbing_driver'] = 'loacl';
+ $upload_status = true;
+ break;
+ }
+ }else{
+ $upload_status = true;
+ $info['longbing_driver'] = 'loacl';
+ }
+ return $upload_status;
+ }
+ //检查
+ public function checkFile($type ,$file)
+ {
+ $result = false;
+ switch($type)
+ {
+ case 'picture':
+ $result = validate(['image'=>'filesize:2097152|fileExt:jpg,jpeg,bmp,png|image:*'])->check([$file]);
+ break;
+ case 'audio':
+ $result = validate(['audio'=>'filesize:2097152|fileExt:mp3,wma,wav,m4a'])->check([$file]);
+ break;
+ case 'video':
+ $result = validate(['video'=>'filesize:2097152|fileExt:wmv,mp4,avi,mpg,rmvb'])->check([$file]);
+ break;
+ case 'cert':
+ $result = validate(['cert'=>'filesize:2097152|fileExt:cert'])->check([$file]);
+ break;
+ case 'wxuploadkey':
+ $result = validate(['cert'=>'filesize:2097152|fileExt:cert'])->check([$file]);
+ break;
+ default:
+ break;
+ }
+ return $result;
+ }
+
+ //生成返回数据
+ public function fileInfo($path ,$file_name ,$type_data)
+ {
+ $result = array(
+ 'attachment' => ltrim($path,'/'),
+ 'uniacid' => $this->config['uniacid'],
+ 'filename' => $file_name,
+ 'createtime' => time(),
+ 'type' => $type_data
+ );
+ return $result;
+ }
+
+
+
+ //本地保存
+ public function fileLoaclSave($path ,$file ,$file_name = null)
+ {
+ if(empty($file_name)) $file_name = uuid() . '.' . $file->getOriginalExtension();
+
+// dump($path ,$file ,$file_name);exit;
+ //保存
+ $info = Filesystem::disk('longbing')->putFileAs($path ,$file ,$file_name);
+ return $info;
+ }
+
+ //阿里云上传
+ public function aliyunUpload($path)
+ {
+ //左边的/去掉
+ $path = ltrim($path,'/');
+ try{
+ $bucket = $this->config['aliyun_bucket'];
+ $filePath = FILE_UPLOAD_PATH . $path;
+ if(isset($this->config['aliyun_base_dir']) && !empty($this->config['aliyun_base_dir'])) $path = $this->config['aliyun_base_dir'] . '/' . $path;
+ if(in_array(substr($path,0,1) ,['/' ,"/"])) {
+ $path = substr($path,1,(strlen($path)-1));
+ }
+ if (file_exists($filePath)) {
+ //实例化OSS
+ require_once dirname(__FILE__) . '/extend/aliyuncs/oss-sdk-php/autoload.php';
+ $ossClient =new \OSS\OssClient($this->config['aliyun_access_key_id']
+ ,$this->config['aliyun_access_key_secret']
+ ,$this->config['aliyun_endpoint']);
+ //uploadFile的上传方法
+ $res=$ossClient->uploadFile($bucket, $path, $filePath);
+ if(is_file($filePath)){
+ unlink($filePath);
+ }
+ return $res;
+ }
+ }catch(OssException $e) {
+ //如果出错这里返回报错信息
+ return false;
+ //return $e->getMessage();
+ }
+ //否则,完成上传操作
+ return false;
+
+ }
+
+ //七牛云上传
+ public function qiniuUpload($path)
+ {
+ try{
+ //加载驱动
+ require_once dirname(__FILE__) . '/extend/qiniu/autoload.php';
+ //左边的/去掉
+ $path = ltrim($path,'/');
+ // 需要填写你的 Access Key 和 Secret Key
+ $accessKey = $this->config['qiniu_accesskey'];
+ $secretKey = $this->config['qiniu_secretkey'];
+ $bucket = $this->config['qiniu_bucket'];
+ // 构建鉴权对象
+ $auth = new Auth($accessKey, $secretKey);
+ // 生成上传 Token
+ $token = $auth->uploadToken($bucket);
+ //获取本地文件
+ $filePath = FILE_UPLOAD_PATH . $path;
+ //上传
+ $client = new UploadManager();
+ list($ret, $err) = $client->putFile($token, $path, $filePath);
+ if(is_file($filePath)){
+ unlink($filePath);
+ }
+ return array($ret,$err);
+ }catch (\Exception $e){
+ return false;
+ }
+
+ }
+
+ //腾讯云上传
+ public function tenxunUpoload($path)
+ {
+ try{
+ $path = ltrim($path,'/');//左边的/去掉
+ //加载驱动
+ require dirname(__FILE__) . '/extend/tencentcloud/vendor/autoload.php';
+
+ // dump(dirname(__FILE__) . '/extend/tencentcloud/vendor/autoload.php');exit;
+ // 需要填写你的 Access Key 和 Secret Key
+ $appid = $this->config['tenxunyun_appid'];
+ $secretid = $this->config['tenxunyun_secretid'];
+ $secretkey= $this->config['tenxunyun_secretkey'];
+ $bucket = $this->config['tenxunyun_bucket'];
+ $region = $this->config['tenxunyun_region'];
+ $yuming = $this->config['tenxunyun_yuming'];
+
+ //初始化对象
+ $cosClient = new Client(array(
+ 'region' => $region, #地域,如ap-guangzhou,ap-beijing-1
+ 'credentials' => array(
+ 'secretId' => $secretid,
+ 'secretKey'=> $secretkey,
+ ),
+ ));
+
+ // 若初始化 Client 时未填写 appId,则 bucket 的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
+ // $bucket = $bucket . '-' . $appid;
+ // 要上传文件的本地路径
+ $body = FILE_UPLOAD_PATH . $path;
+
+
+ try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $path,
+ 'Body' => file_get_contents($body)
+ ));
+
+ if(is_file($body)){
+ unlink($body);
+ }
+ return $result;
+ } catch (\Exception $e) {
+ return false;
+ }
+ }catch(\Exception $e){
+ return false;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/Common/WeChatCode.php b/app/Common/WeChatCode.php
new file mode 100755
index 0000000..123ae25
--- /dev/null
+++ b/app/Common/WeChatCode.php
@@ -0,0 +1,75 @@
+uniacid = $uniacid;
+ $this->config = longbingGetAppConfig($uniacid);
+ $this->access_token = $this->getAccessToken();
+ }
+
+ //获取accesstoken
+ public function getAccessToken()
+ {
+ return longbingGetAccessToken($this->uniacid ,true);
+ }
+
+ //获取code (方法一)
+ public function getQRCode($path ,$width = 430)
+ {
+ //url
+ $url = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token={$this->access_token}";
+ $post_data = ['path' => $path ,'width' => $width];
+ //发送数据
+ $result = longbingCurl($url ,json_encode($post_data ,true) ,'POTH');
+ return $result;
+ }
+ //获取code (方法二)
+ public function getWxCode($path ,$width = 430 ,$auto_color = true ,$line_color = null ,$is_hyaline = false)
+ {
+ //url
+ $url = "https://api.weixin.qq.com/wxa/getwxacode?access_token={$this->access_token}";
+ $post_data = ['path' => $path ,
+ 'width' => $width ,
+ 'auto_color' => $auto_color ,
+ 'line_color' => $line_color ,
+ 'is_hyaline' => $is_hyaline];
+ //生成
+ $result = longbingCurl($url ,json_encode($post_data ,true) ,'POTH');
+ return $result;
+ }
+ //获取code (方法三)
+ public function getUnlimitedCode($scene ,$path = '',$width = 430 ,$auto_color = false ,$line_color = '{"r":0,"g":0,"b":0}' ,$is_hyaline = true)
+ {
+ $access_token = $this->access_token;
+
+
+// $access_token = '123';
+ $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$access_token}";
+ $post_data = ['scene' => $scene ];
+ if(!empty($width)) $post_data['width'] = $width;
+ if(!empty($auto_color)) $post_data['auto_color'] = $auto_color;
+// if(!empty($line_color)) $post_data['line_color'] = $line_color;
+ if(!empty($is_hyaline)) $post_data['is_hyaline'] = $is_hyaline;
+// if(!empty($auto_color)) unset($post_data['line_color']);
+ if(!empty($path)) $post_data['page'] = $path;
+ //生成
+ $result = longbingCurl($url ,json_encode($post_data ,true) ,'POST');
+ return $result;
+ }
+
+}
diff --git a/app/Common/addUserInfo.inc.php b/app/Common/addUserInfo.inc.php
new file mode 100755
index 0000000..059de60
--- /dev/null
+++ b/app/Common/addUserInfo.inc.php
@@ -0,0 +1,52 @@
+
+
+ * -41001: encodingAesKey 非法
+ * -41003: aes 解密失败
+ * -41004: 解密后得到的buffer非法
+ * -41005: base64加密失败
+ * -41016: base64解密失败
+ *
+ */
+
+class ErrorCode
+{
+ public static $OK = 0;
+ public static $IllegalAesKey = -41001;
+ public static $IllegalIv = -41002;
+ public static $IllegalBuffer = -41003;
+ public static $DecodeBase64Error = -41004;
+}
+
+?>
\ No newline at end of file
diff --git a/app/Common/extend/LongbingUpgrade.php b/app/Common/extend/LongbingUpgrade.php
new file mode 100755
index 0000000..37dce3b
--- /dev/null
+++ b/app/Common/extend/LongbingUpgrade.php
@@ -0,0 +1,620 @@
+is_debug = $is_debug ;
+
+ $this->token_path = dirname(__FILE__).'/token.key';
+
+ $this->uniacid = $uniacid .'';
+
+ $this->goods_name = $goodsName;
+ $this->base_url = 'http://shouquan.migugu.com/';
+ $this->base_url = $this->is_debug ? 'http://shouquan.migugu.com/' : 'http://auth.soqq.com.cn/' ;
+ $this->base_url = 'http://auth.soqq.com.cn/'; //ToDo 调试模式 线下接口 授权接口写死
+
+ $this->check_url = $this->base_url .'auth/home.Index/index';
+ $this->uploadWxapp_url = $this->base_url .'auth/home.Index/uploadWxapp';
+ $this->get_auth_url = $this->base_url .'auth/home.Index/getAuth' ;
+ $this->get_domain_param_url = $this->base_url .'auth/home.Index/domain_param' ;
+ $this->get_wxapp_version_url = $this->base_url .'auth/home.Index/getWxappVersion' ;
+ $this->clear_up_token = $this->base_url .'auth/home.Index/clearToken' ;
+
+
+ $this->http_host = $_SERVER['HTTP_HOST'];
+ $this->server_name = $_SERVER['SERVER_NAME'];
+ $this->request_time = $_SERVER['REQUEST_TIME'].'';
+
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-08 13:12
+ * @功能说明:
+ */
+ public function checkAuth(){
+ try {
+ //清除双方授权token --重新获取
+ $this->clearUp();
+
+ $this->public_key = $this->getPublicKey();
+ $this->getUpgradeMsg();
+
+ if(empty($this->public_key)){
+ return $this->returnErrorDataInfo( '(001)'.$this->errorMsg );
+ }else{
+
+ $data['domain'] = $this->domain_name_info ;
+ $data['version'] = $this->goods_version_info ;
+
+ return $this->returnDataInfo($data);
+ }
+ }catch (\Exception $e){
+ return $this->returnErrorDataInfo( "请用授权域名登陆 进行站点绑定" );
+ }
+
+ }
+
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-08 11:52
+ * @功能说明: 站点授权信息
+ */
+ private function getAuthMsg(){
+ if(empty($this->domain_name_info) || count($this->domain_name_info) == 0 ){
+ return $this->returnDataInfo([],'(002)'.$this->errorMsg);
+ }else{
+ return $this->returnDataInfo($this->domain_name_info);
+ }
+ }
+
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 12:55
+ * @功能说明:
+ */
+ private function getUpgradeMsg(){
+
+ try{
+
+ $this->public_key = $this->getPublicKey();
+ if(!$this->public_key){
+ return $this->returnErrorDataInfo( "请用授权域名登陆 进行站点绑定" );
+ }
+
+ $siginStr = $this->getSiginData([]);
+ $result = $this->curl_post($this->check_url ,$this->getPostData($siginStr)) ;
+ $result = json_decode( $result,true);
+
+ $data = $result['data'];
+
+ openssl_public_decrypt(base64_decode($data['goods_version_updata_info']), $sigin, $this->public_key);
+
+ $sigin = json_decode($sigin , true) ;
+
+ $this->goods_version_info = $data['goods_version_info'];
+ $this->goods_version_updata_info = $sigin;
+
+ return $this->returnDataInfo($this->goods_version_info);
+
+ }catch (Exception $e){
+ return $this->returnErrorDataInfo( "获取更新信息异常" );
+ }
+
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 14:09
+ * @功能说明: 开始升级
+ */
+ public function update($toFilePath = null , $tempPaht = null){
+ //获取升级包信息
+ //检查权限
+ //下载升级包
+ //解压升级包
+ //写入版本文件
+
+ if(!$this->goods_version_info && !$this->goods_version_updata_info){
+ $this->getUpgradeMsg();
+ }
+
+ //状态码判断 2020/6/18 16:45 / lichuanming
+ if($this->goods_version_updata_info['url'] === 'ae40000001'){
+ return $this->returnErrorDataInfo ('升级服务已到期') ;
+ }
+
+ $result = $this->get_file($this->goods_version_updata_info['url'] , $tempPaht);
+
+ if($result === false){
+ return $this->returnErrorDataInfo ('下载文件失败') ;
+ }
+
+ $toFilePath = empty($toFilePath) ? './' : $toFilePath ;
+ $this->unzip($result , $toFilePath , $this->goods_version_updata_info['password'] );
+
+ return $this->returnDataInfo([],'更新成功' , '200') ;
+ }
+
+ /**
+ * @param array $data
+ * @param string $msg
+ * @param int $code
+ * @功能说明: 返回 json 数据
+ * @author jingshuixian
+ * @DataTime: 2020-06-06 21:25
+ */
+ public function returnDataInfo($data = [] , $msg = '' , $code = 20000){
+ $resultData = [
+ 'code' => $code ,
+ 'msg' => $msg,
+ 'data' => $data
+ ];
+ return $resultData ;
+ }
+
+ public function returnErrorDataInfo($msg = '' , $code = -1 , $data = []){
+ return $this->returnDataInfo($data ,$msg ,$code);
+ }
+
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 16:02
+ * @功能说明:上传微信小程序
+ */
+ public function uploadWxapp($uploadInfo,$wxapp_version = '')
+ {
+
+ //获取当前系统版本信息
+ //提交需要上传的版本信息
+ //验证系统的平台ID 版本ID 域名 平台ID 模块ID 上传KEY
+ //加密签名
+ //提交上传
+
+ /*try{
+ if(!$this->goods_version_updata_info){
+ $this->getUpgradeMsg();
+ }
+
+ $siginStr = $this->getSiginData();
+
+ $postData = $this->getPostData($siginStr);
+ $uploadInfo = $this->getSiginDataByOpenSSL($uploadInfo);
+ $this->log("uploadWxapp = uploadInfo", $uploadInfo);
+ $postData['ext_data'] = $uploadInfo;
+
+ $this->log("uploadWxapp = postData", $postData);
+
+ $result = $this->curl_post( $this->uploadWxapp_url ,$postData) ;
+
+ $this->log( "获取授权信息一" ,$result);
+
+ $result = json_decode( $result,true);
+
+ $this->log( "获取授权信息二" ,$result);
+
+ return $this->returnDataInfo($result);
+ }catch (\Exception $e){
+ return $this->returnErrorDataInfo('上传失败');
+ }*/
+
+
+ try{
+ $postData = $this->getPostData('');
+ $postData['ext_data'] = json_encode($uploadInfo);
+ $postData['wxapp_version'] = $wxapp_version; //新增微信版本号
+
+ $this->log("uploadWxapp = postData", $postData);
+
+ $result = $this->curl_post( $this->uploadWxapp_url ,$postData) ;
+
+ $this->log( "获取授权信息一" ,$result);
+
+ $result = json_decode( $result,true);
+
+ $this->log( "获取授权信息二" ,$result);
+
+ return empty($result) ? $this->returnErrorDataInfo('上传繁忙,稍后再试。。(001)') : $result;
+ }catch (\Exception $e){
+ return $this->returnErrorDataInfo('上传繁忙,稍后再试。。(002)');
+ }
+
+ }
+
+ /**
+ **@param $version_no
+ * @功能说明: 当前系统版本号
+ * @author lichuanming
+ * @DataTime: 2020/6/22 17:31
+ */
+ public function getWxappVersion($version_no){
+ try{
+ $postData = $this->getPostData('');
+
+ $postData['version'] = $version_no;
+ $this->log("uploadWxapp = postData", $postData);
+
+ $result = $this->curl_post( $this->get_wxapp_version_url ,$postData) ;
+ $this->log( "获取版本信息一" ,$result);
+
+ $result = json_decode( $result,true);
+
+ $this->log( "获取版本信息二" ,$result);
+
+ return $result['data'];
+ }catch (\Exception $e){
+ return $this->returnErrorDataInfo('无法获取小程序版本信息');
+ }
+ }
+
+
+ /**
+ **@author lichuanming
+ * @DataTime: 2020/6/18 19:13
+ * @功能说明: 获取saas端的值
+ */
+ public function getsAuthConfig(){
+
+ $this->public_key = $this->getPublicKey();
+
+ if(empty($this->public_key )){
+
+ return [];
+ }
+
+ $siginStr = $this->getSiginData([]);
+
+ $result = $this->curl_post($this->get_domain_param_url ,$this->getPostData($siginStr)) ;
+
+ $result = json_decode( $result,true);
+
+ $param_list = $result['data']['param_list'];
+
+ if(is_array($param_list)){
+ foreach ($param_list as $key =>$item){
+ $param = '';
+ openssl_public_decrypt(base64_decode($item), $param, $this->public_key);
+ $param_list[$key] = $param;
+ }
+ }
+
+ return $param_list;
+ }
+
+
+
+
+ /**
+ * @param $siginStr
+ * @功能说明: 获取提交信息
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 16:35
+ */
+ private function getPostData($siginStr)
+ {
+
+ $postData = $this->getPublicPostData();
+ $postData['sigin' ] = $siginStr;
+
+ return $postData ;
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 16:13
+ * @功能说明: 获取签名信息
+ */
+ private function getSiginData($extData = [] , $siginType = 1 )
+ {
+
+ $data = $this->getPublicPostData();
+ if (!empty($extData)){
+ $data['ext_data'] = $extData ;
+ }
+
+ ksort($data);
+ $str_data = json_encode($data);
+
+ //$siginType = 1 采用 公钥加密
+
+ if($siginType == 1 ){
+ openssl_public_encrypt($str_data, $encrypted, $this->public_key);
+
+ if(empty($encrypted)){
+ return false ;
+ }
+ //处理特殊字符
+ $encrypted = base64_encode($encrypted);
+
+ }else{ #其他只做数据签名,不做信息加密
+ $encrypted =$this->getSiginDataByHash($data);
+ }
+ return $encrypted ;
+
+ }
+
+
+ private function getSiginDataByOpenSSL($data){
+ $str_data = is_array($data) ? json_encode($data) : $data;
+ openssl_public_encrypt($str_data, $encrypted, $this->public_key);
+ if(empty($encrypted)){
+ return false ;
+ }
+ //处理特殊字符
+ $encrypted = base64_encode($encrypted);
+ return $encrypted;
+ }
+
+
+ /**
+ * @param $data
+ * @功能说明: 普通数据签名算法(只支持 str 和数组 签名 )
+ * @author jingshuixian
+ * @DataTime: 2020-06-06 15:10
+ */
+ private function getSiginDataByHash($data){
+ $data['token'] = $data['token']?$data['token']:'';
+ $this->log( 'getSiginDataByHash data ' , $data);
+ $data = is_array( $data ) ? json_encode($data) : (is_string($data) ? $data : time() . '') . 'LongbingShuixian';
+
+ $siginStr = hash( 'sha256', $data) ;
+
+ return $siginStr ;
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-06 14:45
+ * @功能说明: 获取公共提交数据
+ */
+ private function getPublicPostData(){
+ $app_model_name = config('app.AdminModelList')['app_model_name'];
+ $token = @file_get_contents($this->token_path) ;
+ $token = $token?json_decode($token,true):'';
+ if(!empty($token)){
+ $token = $token['token'];
+ }
+
+ $data = [
+ 'uniacid' => $this->uniacid ,
+ 'app_model_name' => $app_model_name , //2020/6/22 新增参数 By.lichuanming
+ 'goods_name' => $this->goods_name,
+ 'http_host' => $this->http_host ,
+ 'server_name' => $this->server_name ,
+ 'request_time' => $this->request_time ,
+ 'token' => $token
+ ];
+ return $data ;
+ }
+
+ /**
+ * @param $url
+ * @param string $folder
+ * @功能说明: 下载文件
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 14:15
+ */
+ private function get_file($url, $folder = './data/upgradex/') {
+ set_time_limit(24 * 60 * 60);
+ $target_dir = $folder . '';
+ if (!is_dir($target_dir)) {
+ mkdir($target_dir, 0777, true);
+ }
+ $newfname = date('Ymd') . rand(1000, 10000000) . uniqid() . '.zip';
+ $newfname = $target_dir . $newfname;
+ $file = @fopen($url, "rb");
+ if ($file) {
+ $newf = fopen($newfname, "wb");
+ if ($newf) while (!feof($file)) {
+ fwrite($newf, fread($file, 1024 * 8) , 1024 * 8);
+ }
+
+ fclose($file);
+ if ($newf) {
+ fclose($newf);
+ }
+
+ }else{
+ return false ;
+ }
+
+ return $newfname;
+ }
+
+ /**
+ * @param $filename
+ * @param $toFilepath
+ * @param null $password 解压密码
+ * @功能说明: 解压文件
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 14:44
+ */
+ private function unzip($filename , $toFilepath , $password = null){
+ $zip = new ZipArchive;
+ $res = $zip->open($filename);
+ if ($res === true){
+ $password && $zip->setPassword($password); //解压密码
+ $zip->extractTo($toFilepath);
+ $zip->close();
+ }
+
+ return true ;
+ }
+
+ /**
+ * @param $key
+ * @param $value
+ * @功能说明: 打印日志
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 13:29
+ */
+ public function log($key , $value){
+ //关闭和开启调试
+ if($this->is_debug)
+ {
+ echo $key ." = " .(is_array($value) ? json_encode($value) : $value) . ' ';
+ }else{
+ return false ;
+ }
+
+
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 13:34
+ * @功能说明: 获取秘钥
+ */
+ private function getPublicKey(){
+
+
+ if(!empty($this->public_key)){
+ $this->log( "已经获得 " , $this->public_key);
+ return $this->public_key ;
+ }
+
+ $this->log('获取秘钥:' ,'开始');
+ $siginStr = $this->getSiginData([] , 2);
+ $this->log('获取秘钥 sigin:' ,$siginStr);
+
+ $result = $this->curl_post($this->get_auth_url ,$this->getPostData($siginStr) ) ;
+ $this->log('获取秘钥 result:' ,$result);
+
+ $result = json_decode( $result,true);
+ // todo 需要判断返回结果是否正确
+
+ $this->domain_name_info = $result['data']['domain_name_info'];
+
+ //写入token文件
+ $this->log("获取秘钥 保持token路径: " , dirname(__FILE__));
+
+ $token = $result['data']['token'];
+ $resultWriteToken = $this->writein_token($token);
+ $this->log("获取秘钥 写入token: " , $resultWriteToken ? '成功' : '失败' );
+
+ $this->public_key = $result['data']['public_key'];
+ return $this->public_key;
+
+ }
+
+ /**
+ * @param $url
+ * @param array $data
+ * @功能说明: post 请求
+ * @author jingshuixian
+ * @DataTime: 2020-06-05 12:53
+ */
+ private function curl_post($url , $data=array()){
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+
+ // POST数据
+ curl_setopt($ch, CURLOPT_POST, 1);
+ // 把post的变量加上
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+
+ $output = curl_exec($ch);
+
+ curl_close($ch);
+
+ return $output;
+
+ }
+
+ /**
+ **@param array $token
+ * @功能说明: token写入
+ * @author lichuanming
+ * @DataTime: 2020/6/19 11:35
+ */
+ private function writein_token($token):bool {
+ $resultWriteToken = false;
+ if(is_array($token)){
+ //数据正常 直接保存
+ $resultWriteToken = file_put_contents($this->token_path , json_encode($token));
+
+ }else{
+ //读取原有token 数据
+ $token = @file_get_contents($this->token_path) ;
+ $token = $token?json_decode($token,true):'';
+
+ if(!empty($token)){
+ if($token['token_expiration_time'] < time()){
+ $token['token'] = '';
+ //写入空token
+ $resultWriteToken = file_put_contents($this->token_path , json_encode($token));
+ }
+ }
+ }
+
+ return $resultWriteToken?true:false;
+ }
+
+ /**
+ **@author lichuanming
+ * @DataTime: 2020/6/23 14:33
+ * @功能说明: 重置双方通讯token
+ */
+ private function clearUp(){
+ //读取原有token 数据
+ $token = @file_get_contents($this->token_path) ;
+ $token = $token?json_decode($token,true):'';
+
+ if(!empty($token)){
+ if($token['token_expiration_time'] < time() || !$token['token']){ //token 过期
+ $this->public_key = $this->getPublicKey();
+ $siginStr = $this->getSiginData([]);
+
+ $result = $this->curl_post($this->clear_up_token,$this->getPostData($siginStr));
+ $result = json_decode($result,true);
+ if($result['data']['clear']){ //清除成功
+ $this->public_key = null;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/alibabacloud/client/CHANGELOG.md b/app/Common/extend/alibabacloud/client/CHANGELOG.md
new file mode 100755
index 0000000..e36c884
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/CHANGELOG.md
@@ -0,0 +1,256 @@
+# CHANGELOG
+
+## 1.5.16 - 2019-08-21
+- Updated Endpoints Data.
+
+## 1.5.15 - 2019-08-14
+- Improved Client.
+
+
+## 1.5.14 - 2019-07-25
+- Improved Credential Filter.
+
+
+## 1.5.13 - 2019-07-18
+- Improved API Resolver.
+
+
+## 1.5.12 - 2019-06-20
+- Fixed Signature for ROA.
+
+
+## 1.5.11 - 2019-06-14
+- Added endpoint rules.
+
+
+## 1.5.10 - 2019-06-13
+- Improved `Resovler`.
+- Updated `endpoints`.
+
+
+## 1.5.9 - 2019-06-04
+- Improved `UUID`.
+
+
+## 1.5.8 - 2019-05-30
+- Improved `Arrays`.
+
+
+## 1.5.7 - 2019-05-29
+- Improved `uuid`.
+
+
+## 1.5.6 - 2019-05-29
+- Fixed `uuid` version lock.
+
+
+## 1.5.5 - 2019-05-23
+- Improved `Signature`.
+
+
+## 1.5.4 - 2019-05-22
+- Updated `Endpoints`.
+- Fixed `Content-Type` in header.
+
+
+## 1.5.3 - 2019-05-13
+- Improved `Endpoint` tips.
+- Improved `Endpoints` for `STS`.
+
+
+## 1.5.2 - 2019-05-10
+- Improved `Result` object.
+
+
+## 1.5.1 - 2019-05-09
+- Supported `Resolver` for Third-party dependencies.
+
+
+## 1.5.0 - 2019-05-07
+- Improved `Resolver` for products.
+
+
+## 1.4.0 - 2019-05-06
+- Support `Retry` and `Asynchronous` for Request.
+
+
+## 1.3.1 - 2019-04-30
+- Allow timeouts to be set in microseconds.
+
+
+## 1.3.0 - 2019-04-18
+- Improved parameters methods.
+- Optimized the logic for body encode.
+
+
+## 1.2.1 - 2019-04-11
+- Improve exception code and message for `Region ID`.
+
+
+## 1.2.0 - 2019-04-11
+- Improve exception message for `Region ID`.
+
+
+## 1.1.1 - 2019-04-02
+- Added endpoints for `batchcomputenew`, `privatelink`.
+- Improve Region ID tips.
+
+
+## 1.1.0 - 2019-04-01
+- Updated `composer.json`.
+
+
+## 1.0.27 - 2019-03-31
+- Support `Policy` for `ramRoleArnClient`.
+
+
+## 1.0.26 - 2019-03-27
+- Support `pid`, `cost`, `start_time` for Log.
+
+
+## 1.0.25 - 2019-03-27
+- Updated default log format.
+- Add endpoints for `dbs`.
+
+
+## 1.0.24 - 2019-03-26
+- Support Log.
+
+
+## 1.0.23 - 2019-03-23
+- Remove SVG.
+
+
+## 1.0.22 - 2019-03-20
+- Add endpoint `cn-hangzhou` for `idaas` .
+
+
+## 1.0.21 - 2019-03-19
+- Installing by Using the ZIP file.
+- Update Docs.
+
+
+## 1.0.20 - 2019-03-13
+- Improve Tests.
+- Update Docs.
+
+
+## 1.0.19 - 2019-03-12
+- Add SSL Verify Option `verify()`.
+
+
+## 1.0.18 - 2019-03-11
+- Add endpoints for `acr`.
+- Add endpoints for `faas`.
+- Add endpoints for `ehs`.
+- SSL certificates are not validated by default.
+
+
+## 1.0.17 - 2019-03-08
+- Support Mock for Test.
+
+
+## 1.0.16 - 2019-03-07
+- Support Credential Provider Chain.
+- Support `CCC`.
+- Add `ap-south-1` for `cas`.
+- Add `ap-southeast-1` for `waf`.
+- Update Docs.
+
+
+## 1.0.15 - 2019-02-27
+- Add endpoints for `Chatbot`.
+- Change endpoints for `drdspost` and `drdspre`.
+
+
+## 1.0.14 - 2019-02-21
+- Enable debug mode by set environment variable `DEBUG=sdk`.
+
+
+## 1.0.13 - 2019-02-18
+- Support Release Script `composer release`.
+- Add endpoints for apigateway in `drdspre` in `cn-qingdao`.
+- Add endpoints for apigateway in `drdspre` in `cn-beijing`.
+- Add endpoints for apigateway in `drdspre` in `cn-hangzhou`.
+- Add endpoints for apigateway in `drdspre` in `cn-shanghai`.
+- Add endpoints for apigateway in `drdspre` in `cn-shenzhen`.
+- Add endpoints for apigateway in `drdspre` in `cn-hongkong`.
+- Add endpoints for apigateway in `drdspost` in `ap-southeast-1`.
+- Add endpoints for apigateway in `drdspost` in `cn-shanghai`.
+- Add endpoints for apigateway in `drdspost` in `cn-hongkong`.
+- Add endpoints for apigateway in `vod` in `ap-southeast-1`.
+- Add endpoints for apigateway in `vod` in `eu-central-1`.
+
+
+## 1.0.12 - 2019-02-16
+- Support `open_basedir`.
+
+
+## 1.0.11 - 2019-02-13
+- Improve User Agent.
+
+
+## 1.0.10 - 2019-02-12
+- `userAgentAppend` is renamed to `appendUserAgent`.
+
+
+## 1.0.9 - 2019-02-12
+- `userAgent` is renamed to `userAgentAppend`.
+
+
+## 1.0.8 - 2019-02-11
+- `userAgent` - Support DIY User Agent.
+- Add endpoints for apigateway in Zhangjiakou.
+- Add endpoints for apigateway in Hu He Hao Te.
+- Add endpoints for vod in Hu He Hao Te.
+- Add endpoints for hsm in Zhangjiakou.
+- Add endpoints for luban in Germany.
+- Add endpoints for linkwan in Hangzhou.
+- Add endpoints for drdspost in Singapore.
+
+
+## 1.0.7 - 2019-01-28
+- Add endpoints for gpdb in Tokyo.
+- Add endpoints for elasticsearch in Beijing.
+
+
+## 1.0.6 - 2019-01-23
+- Add endpoints for dysmsapi in Singapore.
+- Add endpoints for dybaseapi.
+- Add endpoints for dyiotapi.
+- Add endpoints for dycdpapi.
+- Add endpoints for dyplsapi.
+- Add endpoints for dypnsapi.
+- Add endpoints for dyvmsapi.
+- Add endpoints for snsuapi.
+
+
+## 1.0.5 - 2019-01-21
+- Add endpoints for ApiGateway in Silicon Valley, Virginia.
+- Add endpoints for Image Search in Shanghai.
+
+
+## 1.0.4 - 2019-01-17
+- Support fixer all.
+- Add Endpoints.
+
+
+## 1.0.3 - 2019-01-15
+- Update Endpoints.
+- Update README.md.
+- Update Return Result Message.
+
+
+## 1.0.2 - 2019-01-15
+- Optimize the documentation.
+- Adjust the CI configuration.
+
+
+## 1.0.1 - 2019-01-09
+- Distinguish credential error.
+- Add endpoints for NLS.
+- Add not found product tip.
+
+
+## 1.0.0 - 2019-01-07
+- Initial release of the Alibaba Cloud Client for PHP Version 1.0.0 on Packagist See for more information.
diff --git a/app/Common/extend/alibabacloud/client/CONTRIBUTING.md b/app/Common/extend/alibabacloud/client/CONTRIBUTING.md
new file mode 100755
index 0000000..a1c52a0
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+# Contributing to the Alibaba Cloud Client for PHP
+
+We work hard to provide a high-quality and useful SDK for Alibaba Cloud, and
+we greatly value feedback and contributions from our community. Please submit
+your [issues][issues] or [pull requests][pull-requests] through GitHub.
+
+## Tips
+
+- The SDK is released under the [Apache license][license]. Any code you submit
+ will be released under that license. For substantial contributions, we may
+ ask you to sign a [Alibaba Documentation Corporate Contributor License
+ Agreement (CLA)][cla].
+- We follow all of the relevant PSR recommendations from the [PHP Framework
+ Interop Group][php-fig]. Please submit code that follows these standards.
+ The [PHP CS Fixer][cs-fixer] tool can be helpful for formatting your code.
+ Your can use `composer fixer` to fix code.
+- We maintain a high percentage of code coverage in our unit tests. If you make
+ changes to the code, please add, update, and/or remove tests as appropriate.
+- If your code does not conform to the PSR standards, does not include adequate
+ tests, or does not contain a changelog document, we may ask you to update
+ your pull requests before we accept them. We also reserve the right to deny
+ any pull requests that do not align with our standards or goals.
+
+[issues]: https://github.com/aliyun/openapi-sdk-php-client/issues
+[pull-requests]: https://github.com/aliyun/openapi-sdk-php-client/pulls
+[license]: http://www.apache.org/licenses/LICENSE-2.0
+[cla]: https://alibaba-cla-2018.oss-cn-beijing.aliyuncs.com/Alibaba_Documentation_Open_Source_Corporate_CLA.pdf
+[php-fig]: http://php-fig.org
+[cs-fixer]: http://cs.sensiolabs.org/
+[docs-readme]: https://github.com/aliyun/openapi-sdk-php-client/blob/master/README.md
diff --git a/app/Common/extend/alibabacloud/client/LICENSE.md b/app/Common/extend/alibabacloud/client/LICENSE.md
new file mode 100755
index 0000000..47ee76d
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/LICENSE.md
@@ -0,0 +1,13 @@
+Copyright 1999-2019 Alibaba Group Holding Ltd.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/app/Common/extend/alibabacloud/client/NOTICE.md b/app/Common/extend/alibabacloud/client/NOTICE.md
new file mode 100755
index 0000000..c0622c9
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/NOTICE.md
@@ -0,0 +1,88 @@
+# Alibaba Cloud Client for PHP
+
+
+
+Copyright 1999-2019 Alibaba Group. or its affiliates. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License").
+You may not use this file except in compliance with the License.
+A copy of the License is located at
+
+
+
+or in the "license" file accompanying this file. This file is distributed
+on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+express or implied. See the License for the specific language governing
+permissions and limitations under the License.
+
+# Guzzle
+
+
+
+Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+# jmespath.php
+
+
+
+Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+# Dot
+
+
+
+Copyright (c) 2016-2019 Riku Särkinen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/app/Common/extend/alibabacloud/client/README-zh-CN.md b/app/Common/extend/alibabacloud/client/README-zh-CN.md
new file mode 100755
index 0000000..2d553b7
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/README-zh-CN.md
@@ -0,0 +1,161 @@
+[English](/README.md) | 简体中文
+
+
+# Alibaba Cloud Client for PHP
+[](https://packagist.org/packages/alibabacloud/client)
+[](https://packagist.org/packages/alibabacloud/client)
+[](https://packagist.org/packages/alibabacloud/client)
+[](https://packagist.org/packages/alibabacloud/client)
+[](https://codecov.io/gh/aliyun/openapi-sdk-php-client)
+[](https://travis-ci.org/aliyun/openapi-sdk-php-client)
+[](https://ci.appveyor.com/project/aliyun/openapi-sdk-php-client/branch/master)
+
+
+
+
+
+Alibaba Cloud Client for PHP 是帮助 PHP 开发者管理凭据、发送请求的客户端工具,[Alibaba Cloud SDK for PHP][SDK] 由本工具提供底层支持。
+
+
+## 在线示例
+[API Explorer](https://api.aliyun.com) 提供在线调用阿里云产品,并动态生成 SDK 代码和快速检索接口等能力,能显著降低使用云 API 的难度。
+
+
+## 先决条件
+您的系统需要满足[先决条件](/docs/zh-CN/0-Prerequisites.md),包括 PHP> = 5.5。 我们强烈建议使用cURL扩展,并使用TLS后端编译cURL 7.16.2+。
+
+
+## 安装依赖
+如果已在系统上[全局安装 Composer](https://getcomposer.org/doc/00-intro.md#globally),请直接在项目目录中运行以下内容来安装 Alibaba Cloud Client for PHP 作为依赖项:
+```
+composer require alibabacloud/client
+```
+> 一些用户可能由于网络问题无法安装,可以使用[阿里云 Composer 全量镜像](https://developer.aliyun.com/composer)。
+
+请看[安装](/docs/zh-CN/1-Installation.md)有关通过 Composer 和其他方式安装的详细信息。
+
+
+## 快速使用
+在您开始之前,您需要注册阿里云帐户并获取您的[凭证](https://usercenter.console.aliyun.com/#/manage/ak)。
+
+```php
+asDefaultClient();
+```
+
+## ROA 请求
+```php
+regionId('cn-hangzhou') // 指定请求的区域,不指定则使用客户端区域、默认区域
+ ->product('CS') // 指定产品
+ ->version('2015-12-15') // 指定产品版本
+ ->action('DescribeClusterServices') // 指定产品接口
+ ->serviceCode('cs') // 设置 ServiceCode 以备寻址,非必须
+ ->endpointType('openAPI') // 设置类型,非必须
+ ->method('GET') // 指定请求方式
+ ->host('cs.aliyun.com') // 指定域名则不会寻址,如认证方式为 Bearer Token 的服务则需要指定
+ ->pathPattern('/clusters/[ClusterId]/services') // 指定ROA风格路径规则
+ ->withClusterId('123456') // 为路径中参数赋值,方法名:with + 参数
+ ->request(); // 发起请求并返回结果对象,请求需要放在设置的最后面
+
+ print_r($result->toArray());
+
+} catch (ClientException $exception) {
+ print_r($exception->getErrorMessage());
+} catch (ServerException $exception) {
+ print_r($exception->getErrorMessage());
+}
+```
+
+## RPC 请求
+```php
+product('Cdn')
+ ->version('2014-11-11')
+ ->action('DescribeCdnService')
+ ->method('POST')
+ ->request();
+
+ print_r($result->toArray());
+
+} catch (ClientException $exception) {
+ print_r($exception->getErrorMessage());
+} catch (ServerException $exception) {
+ print_r($exception->getErrorMessage());
+}
+```
+
+
+## 文档
+* [先决条件](/docs/zh-CN/0-Prerequisites.md)
+* [安装](/docs/zh-CN/1-Installation.md)
+* [客户端](/docs/zh-CN/2-Client.md)
+* [请求](/docs/zh-CN/3-Request.md)
+* [结果](/docs/zh-CN/4-Result.md)
+* [区域](/docs/zh-CN/5-Region.md)
+* [域名](/docs/zh-CN/6-Host.md)
+* [SSL 验证](/docs/zh-CN/7-Verify.md)
+* [调试](/docs/zh-CN/8-Debug.md)
+* [日志](/docs/zh-CN/9-Log.md)
+* [测试](/docs/zh-CN/10-Test.md)
+
+
+## 问题
+[提交 Issue](https://github.com/aliyun/openapi-sdk-php-client/issues/new/choose),不符合指南的问题可能会立即关闭。
+
+
+## 发行说明
+每个版本的详细更改记录在[发行说明](/CHANGELOG.md)中。
+
+
+## 贡献
+提交 Pull Request 之前请阅读[贡献指南](/CONTRIBUTING.md)。
+
+
+## 相关
+* [阿里云服务 Regions & Endpoints][endpoints]
+* [OpenAPI Explorer][open-api]
+* [Packagist][packagist]
+* [Composer][composer]
+* [Guzzle中文文档][guzzle-docs]
+* [最新源码][latest-release]
+
+
+## 许可证
+[Apache-2.0](/LICENSE.md)
+
+版权所有 1999-2019 阿里巴巴集团
+
+
+[SDK]: https://github.com/aliyun/openapi-sdk-php
+[open-api]: https://api.aliyun.com
+[latest-release]: https://github.com/aliyun/openapi-sdk-php-client
+[guzzle-docs]: https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html
+[composer]: https://getcomposer.org
+[packagist]: https://packagist.org/packages/alibabacloud/sdk
+[home]: https://home.console.aliyun.com
+[aliyun]: https://www.aliyun.com
+[regions]: https://help.aliyun.com/document_detail/40654.html
+[endpoints]: https://developer.aliyun.com/endpoints
+[cURL]: http://php.net/manual/zh/book.curl.php
+[OPCache]: http://php.net/manual/zh/book.opcache.php
+[xdebug]: http://xdebug.org
+[OpenSSL]: http://php.net/manual/zh/book.openssl.php
+[client]: https://github.com/aliyun/openapi-sdk-php-client
diff --git a/app/Common/extend/alibabacloud/client/README.md b/app/Common/extend/alibabacloud/client/README.md
new file mode 100755
index 0000000..6246579
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/README.md
@@ -0,0 +1,170 @@
+English | [简体中文](/README-zh-CN.md)
+
+
+
+
+
+
+Alibaba Cloud Client for PHP
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Alibaba Cloud Client for PHP is a client tool that helps PHP developers manage credentials and send requests, [Alibaba Cloud SDK for PHP][SDK] dependency on this tool.
+
+
+## Online Demo
+[API Explorer](https://api.aliyun.com) provides the ability to call the cloud product OpenAPI online, and dynamically generate SDK Example code and quick retrieval interface, which can significantly reduce the difficulty of using the cloud API.
+
+
+## Prerequisites
+Your system will need to meet the [Prerequisites](/docs/en-US/0-Prerequisites.md), including having PHP >= 5.5. We highly recommend having it compiled with the cURL extension and cURL 7.16.2+.
+
+
+## Installation
+If Composer is already [installed globally on your system](https://getcomposer.org/doc/00-intro.md#globally), run the following in the base directory of your project to install Alibaba Cloud Client for PHP as a dependency:
+```
+composer require alibabacloud/client
+```
+> Some users may not be able to install due to network problems, you can try to switch the Composer mirror.
+
+Please see the [Installation](/docs/en-US/1-Installation.md) for more detailed information about installing the Alibaba Cloud Client for PHP through Composer and other means.
+
+
+## Quick Examples
+Before you begin, you need to sign up for an Alibaba Cloud account and retrieve your [Credentials](https://usercenter.console.aliyun.com/#/manage/ak).
+
+### Create Client
+```php
+asDefaultClient();
+```
+
+### ROA Request
+```php
+regionId('cn-hangzhou') // Specify the requested regionId, if not specified, use the client regionId, then default regionId
+ ->product('CS') // Specify product
+ ->version('2015-12-15') // Specify product version
+ ->action('DescribeClusterServices') // Specify product interface
+ ->serviceCode('cs') // Set ServiceCode for addressing, optional
+ ->endpointType('openAPI') // Set type, optional
+ ->method('GET') // Set request method
+ ->host('cs.aliyun.com') // Location Service will not be enabled if the host is specified. For example, service with a Certification type-Bearer Token should be specified
+ ->pathPattern('/clusters/[ClusterId]/services') // Specify path rule with ROA-style
+ ->withClusterId('123456') // Assign values to parameters in the path. Method: with + Parameter
+ ->request(); // Make a request and return to result object. The request is to be placed at the end of the setting
+
+ print_r($result->toArray());
+
+} catch (ClientException $exception) {
+ print_r($exception->getErrorMessage());
+} catch (ServerException $exception) {
+ print_r($exception->getErrorMessage());
+}
+```
+
+### RPC Request
+```php
+product('Cdn')
+ ->version('2014-11-11')
+ ->action('DescribeCdnService')
+ ->method('POST')
+ ->request();
+
+ print_r($result->toArray());
+
+} catch (ClientException $exception) {
+ print_r($exception->getErrorMessage());
+} catch (ServerException $exception) {
+ print_r($exception->getErrorMessage());
+}
+```
+
+
+## Documentation
+* [Prerequisites](/docs/en-US/0-Prerequisites.md)
+* [Installation](/docs/en-US/1-Installation.md)
+* [Client](/docs/en-US/2-Client.md)
+* [Request](/docs/en-US/3-Request.md)
+* [Result](/docs/en-US/4-Result.md)
+* [Region](/docs/en-US/5-Region.md)
+* [Host](/docs/en-US/6-Host.md)
+* [SSL Verify](/docs/en-US/7-Verify.md)
+* [Debug](/docs/en-US/8-Debug.md)
+* [Log](/docs/en-US/9-Log.md)
+* [Test](/docs/en-US/10-Test.md)
+
+
+## Issues
+[Opening an Issue](https://github.com/aliyun/openapi-sdk-php-client/issues/new/choose), Issues not conforming to the guidelines may be closed immediately.
+
+
+## Changelog
+Detailed changes for each release are documented in the [release notes](/CHANGELOG.md).
+
+
+## Contribution
+Please make sure to read the [Contributing Guide](/CONTRIBUTING.md) before making a pull request.
+
+
+## References
+* [Alibaba Cloud Regions & Endpoints][endpoints]
+* [OpenAPI Explorer][open-api]
+* [Packagist][packagist]
+* [Composer][composer]
+* [Guzzle Documentation][guzzle-docs]
+* [Latest Release][latest-release]
+
+
+## License
+[Apache-2.0](/LICENSE.md)
+
+Copyright 1999-2019 Alibaba Group Holding Ltd.
+
+
+[SDK]: https://github.com/aliyun/openapi-sdk-php
+[open-api]: https://api.alibabacloud.com
+[latest-release]: https://github.com/aliyun/openapi-sdk-php-client
+[guzzle-docs]: http://docs.guzzlephp.org/en/stable/request-options.html
+[composer]: https://getcomposer.org
+[packagist]: https://packagist.org/packages/alibabacloud/sdk
+[home]: https://home.console.aliyun.com
+[alibabacloud]: https://www.alibabacloud.com
+[regions]: https://www.alibabacloud.com/help/doc-detail/40654.html
+[endpoints]: https://developer.aliyun.com/endpoints
+[cURL]: http://php.net/manual/en/book.curl.php
+[OPCache]: http://php.net/manual/en/book.opcache.php
+[xdebug]: http://xdebug.org
+[OpenSSL]: http://php.net/manual/en/book.openssl.php
+[client]: https://github.com/aliyun/openapi-sdk-php-client
diff --git a/app/Common/extend/alibabacloud/client/UPGRADING.md b/app/Common/extend/alibabacloud/client/UPGRADING.md
new file mode 100755
index 0000000..08c1bb3
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/UPGRADING.md
@@ -0,0 +1,6 @@
+Upgrading Guide
+===============
+
+1.x
+-----------------------
+- This is the first version. See for more information.
diff --git a/app/Common/extend/alibabacloud/client/composer.json b/app/Common/extend/alibabacloud/client/composer.json
new file mode 100755
index 0000000..0f5eb3c
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/composer.json
@@ -0,0 +1,116 @@
+{
+ "name": "alibabacloud/client",
+ "homepage": "https://www.alibabacloud.com/",
+ "description": "Alibaba Cloud Client for PHP - Use Alibaba Cloud in your PHP project",
+ "keywords": [
+ "sdk",
+ "tool",
+ "cloud",
+ "client",
+ "aliyun",
+ "library",
+ "alibaba",
+ "alibabacloud"
+ ],
+ "type": "library",
+ "license": "Apache-2.0",
+ "support": {
+ "source": "https://github.com/aliyun/openapi-sdk-php-client",
+ "issues": "https://github.com/aliyun/openapi-sdk-php-client/issues"
+ },
+ "authors": [
+ {
+ "name": "Alibaba Cloud SDK",
+ "email": "sdk-team@alibabacloud.com",
+ "homepage": "http://www.alibabacloud.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.5",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-openssl": "*",
+ "ext-mbstring": "*",
+ "ext-simplexml": "*",
+ "ext-xmlwriter": "*",
+ "guzzlehttp/guzzle": "^6.3",
+ "danielstjules/stringy": "^3.1",
+ "mtdowling/jmespath.php": "^2.4",
+ "adbario/php-dot-notation": "^2.2",
+ "clagiordano/weblibs-configmanager": "^1.0"
+ },
+ "require-dev": {
+ "ext-spl": "*",
+ "ext-dom": "*",
+ "ext-pcre": "*",
+ "psr/cache": "^1.0",
+ "ext-sockets": "*",
+ "drupal/coder": "^8.3",
+ "symfony/dotenv": "^3.4",
+ "league/climate": "^3.2.4",
+ "phpunit/phpunit": "^4.8.35|^5.4.3",
+ "monolog/monolog": "^1.24",
+ "composer/composer": "^1.8",
+ "mikey179/vfsstream": "^1.6",
+ "symfony/var-dumper": "^3.4"
+ },
+ "suggest": {
+ "ext-sockets": "To use client-side monitoring"
+ },
+ "autoload": {
+ "psr-4": {
+ "AlibabaCloud\\Client\\": "src"
+ },
+ "files": [
+ "src/Functions.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "AlibabaCloud\\Client\\Tests\\": "tests/"
+ }
+ },
+ "config": {
+ "preferred-install": "dist",
+ "optimize-autoloader": true
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true,
+ "scripts-descriptions": {
+ "cs": "Tokenizes PHP, JavaScript and CSS files to detect violations of a defined coding standard.",
+ "cbf": "Automatically correct coding standard violations.",
+ "fixer": "Fixes code to follow standards.",
+ "test": "Run all tests.",
+ "unit": "Run Unit tests.",
+ "feature": "Run Feature tests.",
+ "clearCache": "Clear cache like coverage.",
+ "coverage": "Show Coverage html.",
+ "endpoints": "Update endpoints from OSS."
+ },
+ "scripts": {
+ "cs": "phpcs --standard=PSR2 -n ./",
+ "cbf": "phpcbf --standard=PSR2 -n ./",
+ "fixer": "php-cs-fixer fix ./",
+ "test": [
+ "phpunit --colors=always"
+ ],
+ "unit": [
+ "@clearCache",
+ "phpunit --testsuite=Unit --colors=always"
+ ],
+ "feature": [
+ "@clearCache",
+ "phpunit --testsuite=Feature --colors=always"
+ ],
+ "coverage": "open cache/coverage/index.html",
+ "clearCache": "rm -rf cache/*",
+ "endpoints": [
+ "AlibabaCloud\\Client\\Regions\\LocationService::updateEndpoints",
+ "@fixer"
+ ],
+ "release": [
+ "AlibabaCloud\\Client\\Release::release"
+ ]
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Accept.php b/app/Common/extend/alibabacloud/client/src/Accept.php
new file mode 100755
index 0000000..e7c5261
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Accept.php
@@ -0,0 +1,53 @@
+format = $format;
+ }
+
+ /**
+ * @param $format
+ *
+ * @return Accept
+ */
+ public static function create($format)
+ {
+ return new static($format);
+ }
+
+ /**
+ * @return mixed|string
+ */
+ public function toString()
+ {
+ $key = \strtoupper($this->format);
+
+ $list = [
+ 'JSON' => 'application/json',
+ 'XML' => 'application/xml',
+ 'RAW' => 'application/octet-stream',
+ 'FORM' => 'application/x-www-form-urlencoded'
+ ];
+
+ return isset($list[$key]) ? $list[$key] : $list['RAW'];
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/AlibabaCloud.php b/app/Common/extend/alibabacloud/client/src/AlibabaCloud.php
new file mode 100755
index 0000000..95e8610
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/AlibabaCloud.php
@@ -0,0 +1,63 @@
+credential = $credential;
+ $this->signature = $signature;
+ $this->options['connect_timeout'] = Request::CONNECT_TIMEOUT;
+ $this->options['timeout'] = Request::TIMEOUT;
+ $this->options['verify'] = false;
+ }
+
+ /**
+ * @return AccessKeyCredential|BearerTokenCredential|CredentialsInterface|EcsRamRoleCredential|RamRoleArnCredential|RsaKeyPairCredential|StsCredential
+ */
+ public function getCredential()
+ {
+ return $this->credential;
+ }
+
+ /**
+ * @return SignatureInterface|BearerTokenSignature|ShaHmac1Signature|ShaHmac256Signature|ShaHmac256WithRsaSignature
+ */
+ public function getSignature()
+ {
+ return $this->signature;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Clients/EcsRamRoleClient.php b/app/Common/extend/alibabacloud/client/src/Clients/EcsRamRoleClient.php
new file mode 100755
index 0000000..e97cd6c
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Clients/EcsRamRoleClient.php
@@ -0,0 +1,26 @@
+credential)) {
+ case EcsRamRoleCredential::class:
+ return (new EcsRamRoleProvider($this))->get();
+ case RamRoleArnCredential::class:
+ return (new RamRoleArnProvider($this))->get($timeout, $connectTimeout);
+ case RsaKeyPairCredential::class:
+ return (new RsaKeyPairProvider($this))->get($timeout, $connectTimeout);
+ default:
+ return $this->credential;
+ }
+ }
+
+ /**
+ * @return static
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function asGlobalClient()
+ {
+ return $this->asDefaultClient();
+ }
+
+ /**
+ * Set the current client as the default client.
+ *
+ * @return static
+ * @throws ClientException
+ */
+ public function asDefaultClient()
+ {
+ return $this->name(CredentialsProvider::getDefaultName());
+ }
+
+ /**
+ * Naming clients.
+ *
+ * @param string $name
+ *
+ * @return static
+ * @throws ClientException
+ */
+ public function name($name)
+ {
+ Filter::name($name);
+
+ return AlibabaCloud::set($name, $this);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDebug()
+ {
+ if (isset($this->options['debug'])) {
+ return $this->options['debug'] === true && PHP_SAPI === 'cli';
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Clients/RamRoleArnClient.php b/app/Common/extend/alibabacloud/client/src/Clients/RamRoleArnClient.php
new file mode 100755
index 0000000..b7d3087
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Clients/RamRoleArnClient.php
@@ -0,0 +1,33 @@
+getValue(
+ \strtolower($configPath),
+ $defaultValue
+ );
+ }
+
+ /**
+ * @return ConfigManager
+ */
+ private static function getConfigManager()
+ {
+ if (!self::$configManager instanceof ConfigManager) {
+ self::$configManager = new ConfigManager(__DIR__ . DIRECTORY_SEPARATOR . 'Data.php');
+ }
+
+ return self::$configManager;
+ }
+
+ /**
+ * @param string $configPath
+ * @param mixed $newValue
+ *
+ * @return ConfigManager
+ * @throws Exception
+ */
+ public static function set($configPath, $newValue)
+ {
+ self::getConfigManager()->setValue(\strtolower($configPath), $newValue);
+
+ return self::getConfigManager()->saveConfigFile();
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Config/Data.php b/app/Common/extend/alibabacloud/client/src/Config/Data.php
new file mode 100755
index 0000000..80c1274
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Config/Data.php
@@ -0,0 +1,2429 @@
+
+ [
+ 'dysmsapi' =>
+ [
+ 'global' => 'dysmsapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dysmsapi.aliyuncs.com',
+ 'ap-southeast-1' => 'dysmsapi.ap-southeast-1.aliyuncs.com',
+ ],
+ 'ccc' =>
+ [
+ 'global' => 'ccc.cn-shanghai.aliyuncs.com',
+ 'cn-shanghai' => 'ccc.cn-shanghai.aliyuncs.com',
+ ],
+ 'dbs' =>
+ [
+ 'cn-hangzhou' => 'dbs-api.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'dbs-api.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'dbs-api.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'dbs-api.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'dbs-api.cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'dbs-api.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'dbs-api.ap-southeast-1.aliyuncs.com',
+ 'ap-northeast-1' => 'dbs-api.ap-northeast-1.aliyuncs.com',
+ ],
+ 'dybaseapi' =>
+ [
+ 'global' => 'dybaseapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dybaseapi.aliyuncs.com',
+ ],
+ 'dyiotapi' =>
+ [
+ 'global' => 'dyiotapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dyiotapi.aliyuncs.com',
+ ],
+ 'dycdpapi' =>
+ [
+ 'global' => 'dycdpapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dycdpapi.aliyuncs.com',
+ ],
+ 'dyplsapi' =>
+ [
+ 'global' => 'dyplsapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dyplsapi.aliyuncs.com',
+ ],
+ 'dypnsapi' =>
+ [
+ 'global' => 'dypnsapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dypnsapi.aliyuncs.com',
+ ],
+ 'dyvmsapi' =>
+ [
+ 'global' => 'dyvmsapi.aliyuncs.com',
+ 'cn-hangzhou' => 'dyvmsapi.aliyuncs.com',
+ ],
+ 'snsuapi' =>
+ [
+ 'global' => 'snsuapi.aliyuncs.com',
+ 'cn-hangzhou' => 'snsuapi.aliyuncs.com',
+ ],
+ 'ecs' =>
+ [
+ 'jp-fudao-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'me-east-1' => 'ecs.me-east-1.aliyuncs.com',
+ 'us-east-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'ap-northeast-1' => 'ecs.ap-northeast-1.aliyuncs.com',
+ 'cn-hangzhou-bj-b01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-nu16-b01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-am13-c01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'in-west-antgroup-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-guizhou-gov' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'in-west-antgroup-2' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'tw-snowcloud-kaohsiung' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-finance-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-guizhou' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-fujian' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'in-mumbai-alipay' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-anhui-gov-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-haidian-cm12-c01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-anhui-gov' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-2' => 'ecs.ap-southeast-2.aliyuncs.com',
+ 'cn-qingdao' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-su18-b02' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-su18-b03' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-su18-b01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-antgroup-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-henan-am12001' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-gansu-am6' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-ningxiazhongwei' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-ningxia-am7-c01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-finance-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-st4-d01' => 'ecs-cn-hangzhou.aliyuncs.com',
+ 'eu-central-1' => 'ecs.eu-central-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'ecs.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'ecs.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-3' => 'ecs.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'ecs.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'ecs.eu-west-1.aliyuncs.com',
+ 'ap-south-1' => 'ecs.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'ecs.cn-chengdu.aliyuncs.com',
+ ],
+ 'rds' =>
+ [
+ 'me-east-1' => 'rds.me-east-1.aliyuncs.com',
+ 'us-east-1' => 'rds.aliyuncs.com',
+ 'ap-northeast-1' => 'rds.ap-northeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'rds.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'rds.aliyuncs.com',
+ 'cn-shanghai-finance-1' => 'rds.aliyuncs.com',
+ 'cn-beijing-gov-1' => 'rds.aliyuncs.com',
+ 'cn-shanghai' => 'rds.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'rds.aliyuncs.com',
+ 'cn-fujian' => 'rds.aliyuncs.com',
+ 'us-west-1' => 'rds.aliyuncs.com',
+ 'cn-shanghai-inner' => 'rds.aliyuncs.com',
+ 'cn-hangzhou' => 'rds.aliyuncs.com',
+ 'cn-beijing-inner' => 'rds.aliyuncs.com',
+ 'cn-haidian-cm12-c01' => 'rds.aliyuncs.com',
+ 'cn-shenzhen' => 'rds.aliyuncs.com',
+ 'ap-southeast-2' => 'rds.ap-southeast-2.aliyuncs.com',
+ 'cn-qingdao' => 'rds.aliyuncs.com',
+ 'cn-beijing' => 'rds.aliyuncs.com',
+ 'cn-hangzhou-d' => 'rds.aliyuncs.com',
+ 'cn-gansu-am6' => 'rds.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'rds.aliyuncs.com',
+ 'cn-shenzhen-finance-1' => 'rds.aliyuncs.com',
+ 'ap-southeast-1' => 'rds.aliyuncs.com',
+ 'eu-central-1' => 'rds.eu-central-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'rds.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'rds.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-3' => 'rds.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'rds.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'rds.eu-west-1.aliyuncs.com',
+ 'ap-south-1' => 'rds.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'rds.cn-chengdu.aliyuncs.com',
+ ],
+ 'vpc' =>
+ [
+ 'me-east-1' => 'vpc.me-east-1.aliyuncs.com',
+ 'us-east-1' => 'vpc.aliyuncs.com',
+ 'ap-northeast-1' => 'vpc.ap-northeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'vpc.aliyuncs.com',
+ 'cn-beijing-am13-c01' => 'vpc.aliyuncs.com',
+ 'cn-guizhou-gov' => 'vpc.aliyuncs.com',
+ 'cn-shanghai-finance-1' => 'vpc.aliyuncs.com',
+ 'cn-guizhou' => 'vpc.aliyuncs.com',
+ 'cn-shanghai' => 'vpc.aliyuncs.com',
+ 'us-west-1' => 'vpc.aliyuncs.com',
+ 'cn-hangzhou' => 'vpc.aliyuncs.com',
+ 'cn-haidian-cm12-c01' => 'vpc.aliyuncs.com',
+ 'cn-anhui-gov' => 'vpc.aliyuncs.com',
+ 'cn-shenzhen' => 'vpc.aliyuncs.com',
+ 'ap-southeast-2' => 'vpc.ap-southeast-2.aliyuncs.com',
+ 'cn-henan-am12001' => 'vpc.aliyuncs.com',
+ 'cn-beijing' => 'vpc.aliyuncs.com',
+ 'cn-gansu-am6' => 'vpc.aliyuncs.com',
+ 'cn-ningxiazhongwei' => 'vpc.aliyuncs.com',
+ 'cn-ningxia-am7-c01' => 'vpc.aliyuncs.com',
+ 'cn-shenzhen-finance-1' => 'vpc.aliyuncs.com',
+ 'ap-southeast-1' => 'vpc.aliyuncs.com',
+ 'eu-central-1' => 'vpc.eu-central-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'vpc.cn-zhangjiakou.aliyuncs.com',
+ 'cn-qingdao' => 'vpc.aliyuncs.com',
+ 'cn-huhehaote' => 'vpc.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-3' => 'vpc.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'vpc.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'vpc.eu-west-1.aliyuncs.com',
+ 'ap-south-1' => 'vpc.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'vpc.cn-chengdu.aliyuncs.com',
+ ],
+ 'kms' =>
+ [
+ 'me-east-1' => 'kms.me-east-1.aliyuncs.com',
+ 'ap-northeast-1' => 'kms.ap-northeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'kms.cn-hongkong.aliyuncs.com',
+ 'cn-shanghai-finance-1' => 'kms.cn-shanghai-finance-1.aliyuncs.com',
+ 'cn-shanghai' => 'kms.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'kms.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'kms.cn-shenzhen.aliyuncs.com',
+ 'ap-southeast-2' => 'kms.ap-southeast-2.aliyuncs.com',
+ 'cn-beijing' => 'kms.cn-beijing.aliyuncs.com',
+ 'cn-shenzhen-finance-1' => 'kms.cn-shenzhen-finance-1.aliyuncs.com',
+ 'ap-southeast-1' => 'kms.ap-southeast-1.aliyuncs.com',
+ 'eu-central-1' => 'kms.eu-central-1.aliyuncs.com',
+ 'cn-qingdao' => 'kms.cn-qingdao.aliyuncs.com',
+ 'cn-zhangjiakou' => 'kms.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'kms.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-3' => 'kms.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'kms.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'kms.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'kms.us-west-1.aliyuncs.com',
+ 'us-east-1' => 'kms.us-east-1.aliyuncs.com',
+ 'ap-south-1' => 'kms.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'kms.cn-chengdu.aliyuncs.com',
+ ],
+ 'cms' =>
+ [
+ 'me-east-1' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'us-east-1' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'ap-northeast-1' => 'metrics.ap-northeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'metrics.aliyuncs.com',
+ 'cn-shanghai' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'metrics.aliyuncs.com',
+ 'us-west-1' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'metrics.aliyuncs.com',
+ 'cn-hangzhou' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'metrics.aliyuncs.com',
+ 'cn-shenzhen' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-2' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'metrics.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'metrics.aliyuncs.com',
+ 'ap-southeast-1' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'eu-central-1' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-zhangjiakou' => 'metrics.cn-hangzhou.aliyuncs.com',
+ 'cn-huhehaote' => 'metrics.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-3' => 'metrics.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'metrics.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'metrics.eu-west-1.aliyuncs.com',
+ 'ap-south-1' => 'metrics.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'metrics.cn-chengdu.aliyuncs.com',
+ ],
+ 'slb' =>
+ [
+ 'me-east-1' => 'slb.me-east-1.aliyuncs.com',
+ 'us-east-1' => 'slb.aliyuncs.com',
+ 'ap-northeast-1' => 'slb.ap-northeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'slb.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'slb.aliyuncs.com',
+ 'cn-shanghai' => 'slb.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'slb.aliyuncs.com',
+ 'us-west-1' => 'slb.aliyuncs.com',
+ 'cn-shanghai-inner' => 'slb.aliyuncs.com',
+ 'cn-hangzhou' => 'slb.aliyuncs.com',
+ 'cn-beijing-inner' => 'slb.aliyuncs.com',
+ 'cn-shenzhen' => 'slb.aliyuncs.com',
+ 'ap-southeast-2' => 'slb.ap-southeast-2.aliyuncs.com',
+ 'cn-qingdao' => 'slb.aliyuncs.com',
+ 'cn-beijing' => 'slb.aliyuncs.com',
+ 'cn-hangzhou-d' => 'slb.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'slb.aliyuncs.com',
+ 'ap-southeast-1' => 'slb.aliyuncs.com',
+ 'eu-central-1' => 'slb.eu-central-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'slb.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'slb.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-3' => 'slb.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'slb.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'slb.eu-west-1.aliyuncs.com',
+ 'ap-south-1' => 'slb.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'slb.cn-chengdu.aliyuncs.com',
+ ],
+ 'cs' =>
+ [
+ 'us-east-1' => 'cs.aliyuncs.com',
+ 'cn-hongkong' => 'cs.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'cs.aliyuncs.com',
+ 'cn-shanghai' => 'cs.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'cs.aliyuncs.com',
+ 'us-west-1' => 'cs.aliyuncs.com',
+ 'cn-shanghai-inner' => 'cs.aliyuncs.com',
+ 'cn-hangzhou' => 'cs.aliyuncs.com',
+ 'cn-beijing-inner' => 'cs.aliyuncs.com',
+ 'cn-shenzhen' => 'cs.aliyuncs.com',
+ 'cn-qingdao' => 'cs.aliyuncs.com',
+ 'cn-beijing' => 'cs.aliyuncs.com',
+ 'cn-hangzhou-d' => 'cs.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'cs.aliyuncs.com',
+ 'ap-southeast-1' => 'cs.aliyuncs.com',
+ ],
+ 'push' =>
+ [
+ 'us-east-1' => 'cloudpush.aliyuncs.com',
+ 'cn-hongkong' => 'cloudpush.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'cloudpush.aliyuncs.com',
+ 'cn-shanghai' => 'cloudpush.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'cloudpush.aliyuncs.com',
+ 'us-west-1' => 'cloudpush.aliyuncs.com',
+ 'cn-shanghai-inner' => 'cloudpush.aliyuncs.com',
+ 'cn-hangzhou' => 'cloudpush.aliyuncs.com',
+ 'cn-beijing-inner' => 'cloudpush.aliyuncs.com',
+ 'cn-shenzhen' => 'cloudpush.aliyuncs.com',
+ 'cn-qingdao' => 'cloudpush.aliyuncs.com',
+ 'cn-beijing' => 'cloudpush.aliyuncs.com',
+ 'cn-hangzhou-d' => 'cloudpush.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'cloudpush.aliyuncs.com',
+ 'ap-southeast-1' => 'cloudpush.aliyuncs.com',
+ ],
+ 'cos' =>
+ [
+ 'us-east-1' => 'cos.aliyuncs.com',
+ 'cn-hongkong' => 'cos.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'cos.aliyuncs.com',
+ 'cn-shanghai' => 'cos.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'cos.aliyuncs.com',
+ 'us-west-1' => 'cos.aliyuncs.com',
+ 'cn-shanghai-inner' => 'cos.aliyuncs.com',
+ 'cn-hangzhou' => 'cos.aliyuncs.com',
+ 'cn-beijing-inner' => 'cos.aliyuncs.com',
+ 'cn-shenzhen' => 'cos.aliyuncs.com',
+ 'cn-qingdao' => 'cos.aliyuncs.com',
+ 'cn-beijing' => 'cos.aliyuncs.com',
+ 'cn-hangzhou-d' => 'cos.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'cos.aliyuncs.com',
+ 'ap-southeast-1' => 'cos.aliyuncs.com',
+ ],
+ 'ess' =>
+ [
+ 'us-east-1' => 'ess.aliyuncs.com',
+ 'cn-hongkong' => 'ess.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ess.aliyuncs.com',
+ 'cn-shanghai' => 'ess.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ess.aliyuncs.com',
+ 'us-west-1' => 'ess.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ess.aliyuncs.com',
+ 'cn-hangzhou' => 'ess.aliyuncs.com',
+ 'cn-beijing-inner' => 'ess.aliyuncs.com',
+ 'cn-shenzhen' => 'ess.aliyuncs.com',
+ 'cn-qingdao' => 'ess.aliyuncs.com',
+ 'cn-beijing' => 'ess.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ess.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ess.aliyuncs.com',
+ 'ap-southeast-1' => 'ess.aliyuncs.com',
+ 'cn-zhangjiakou' => 'ess.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'ess.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-2' => 'ess.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'ess.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'ess.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'ess.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'ess.eu-west-1.aliyuncs.com',
+ 'eu-central-1' => 'ess.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'ess.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'ess.ap-south-1.aliyuncs.com',
+ ],
+ 'ace-ops' =>
+ [
+ 'us-east-1' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ace-ops.cn-hangzhou.aliyuncs.com',
+ ],
+ 'billing' =>
+ [
+ 'us-east-1' => 'billing.aliyuncs.com',
+ 'cn-hongkong' => 'billing.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'billing.aliyuncs.com',
+ 'cn-shanghai' => 'billing.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'billing.aliyuncs.com',
+ 'us-west-1' => 'billing.aliyuncs.com',
+ 'cn-shanghai-inner' => 'billing.aliyuncs.com',
+ 'cn-hangzhou' => 'billing.aliyuncs.com',
+ 'cn-beijing-inner' => 'billing.aliyuncs.com',
+ 'cn-beijing' => 'billing.aliyuncs.com',
+ 'cn-hangzhou-d' => 'billing.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'billing.aliyuncs.com',
+ 'ap-southeast-1' => 'billing.aliyuncs.com',
+ ],
+ 'dqs' =>
+ [
+ 'us-east-1' => 'dqs.aliyuncs.com',
+ 'cn-hongkong' => 'dqs.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'dqs.aliyuncs.com',
+ 'cn-shanghai' => 'dqs.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'dqs.aliyuncs.com',
+ 'us-west-1' => 'dqs.aliyuncs.com',
+ 'cn-shanghai-inner' => 'dqs.aliyuncs.com',
+ 'cn-hangzhou' => 'dqs.aliyuncs.com',
+ 'cn-beijing-inner' => 'dqs.aliyuncs.com',
+ 'cn-shenzhen' => 'dqs.aliyuncs.com',
+ 'cn-qingdao' => 'dqs.aliyuncs.com',
+ 'cn-beijing' => 'dqs.aliyuncs.com',
+ 'cn-hangzhou-d' => 'dqs.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'dqs.aliyuncs.com',
+ 'ap-southeast-1' => 'dqs.aliyuncs.com',
+ ],
+ 'dds' =>
+ [
+ 'us-east-1' => 'mongodb.aliyuncs.com',
+ 'cn-hongkong' => 'mongodb.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'mongodb.aliyuncs.com',
+ 'cn-shanghai' => 'mongodb.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'mongodb.aliyuncs.com',
+ 'us-west-1' => 'mongodb.aliyuncs.com',
+ 'cn-shanghai-inner' => 'mongodb.aliyuncs.com',
+ 'cn-hangzhou' => 'mongodb.aliyuncs.com',
+ 'cn-beijing-inner' => 'mongodb.aliyuncs.com',
+ 'cn-shenzhen' => 'mongodb.aliyuncs.com',
+ 'cn-qingdao' => 'mongodb.aliyuncs.com',
+ 'cn-beijing' => 'mongodb.aliyuncs.com',
+ 'cn-hangzhou-d' => 'mongodb.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'mongodb.aliyuncs.com',
+ 'ap-southeast-1' => 'mongodb.aliyuncs.com',
+ 'cn-zhangjiakou' => 'mongodb.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'mongodb.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-2' => 'mongodb.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'mongodb.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'mongodb.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'mongodb.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'mongodb.eu-west-1.aliyuncs.com',
+ 'eu-central-1' => 'mongodb.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'mongodb.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'mongodb.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'mongodb.cn-chengdu.aliyuncs.com',
+ ],
+ 'emr' =>
+ [
+ 'us-east-1' => 'emr.us-east-1.aliyuncs.com',
+ 'cn-hongkong' => 'emr.cn-hongkong.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'emr.aliyuncs.com',
+ 'cn-shanghai' => 'emr.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'emr.aliyuncs.com',
+ 'us-west-1' => 'emr.aliyuncs.com',
+ 'cn-shanghai-inner' => 'emr.aliyuncs.com',
+ 'cn-hangzhou' => 'emr.aliyuncs.com',
+ 'cn-beijing-inner' => 'emr.aliyuncs.com',
+ 'cn-shenzhen' => 'emr.aliyuncs.com',
+ 'cn-qingdao' => 'emr.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'emr.aliyuncs.com',
+ 'cn-hangzhou-d' => 'emr.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'emr.aliyuncs.com',
+ 'ap-southeast-1' => 'emr.aliyuncs.com',
+ 'cn-zhangjiakou' => 'emr.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'emr.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-2' => 'emr.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'emr.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'emr.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'emr.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'emr.eu-west-1.aliyuncs.com',
+ 'eu-central-1' => 'emr.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'emr.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'emr.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'emr.cn-chengdu.aliyuncs.com',
+ ],
+ 'sms' =>
+ [
+ 'us-east-1' => 'sms.aliyuncs.com',
+ 'cn-hongkong' => 'sms.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'sms.aliyuncs.com',
+ 'cn-shanghai' => 'sms.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'sms.aliyuncs.com',
+ 'us-west-1' => 'sms.aliyuncs.com',
+ 'cn-shanghai-inner' => 'sms.aliyuncs.com',
+ 'cn-hangzhou' => 'sms.aliyuncs.com',
+ 'cn-beijing-inner' => 'sms.aliyuncs.com',
+ 'cn-shenzhen' => 'sms.aliyuncs.com',
+ 'cn-qingdao' => 'sms.aliyuncs.com',
+ 'cn-beijing' => 'sms.aliyuncs.com',
+ 'cn-hangzhou-d' => 'sms.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'sms.aliyuncs.com',
+ 'ap-southeast-1' => 'sms.aliyuncs.com',
+ ],
+ 'jaq' =>
+ [
+ 'us-east-1' => 'jaq.aliyuncs.com',
+ 'cn-hongkong' => 'jaq.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'jaq.aliyuncs.com',
+ 'cn-shanghai' => 'jaq.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'jaq.aliyuncs.com',
+ 'us-west-1' => 'jaq.aliyuncs.com',
+ 'cn-shanghai-inner' => 'jaq.aliyuncs.com',
+ 'cn-hangzhou' => 'jaq.aliyuncs.com',
+ 'cn-beijing-inner' => 'jaq.aliyuncs.com',
+ 'cn-shenzhen' => 'jaq.aliyuncs.com',
+ 'cn-qingdao' => 'jaq.aliyuncs.com',
+ 'cn-beijing' => 'jaq.aliyuncs.com',
+ 'cn-hangzhou-d' => 'jaq.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'jaq.aliyuncs.com',
+ 'ap-southeast-1' => 'jaq.aliyuncs.com',
+ ],
+ 'hpc' =>
+ [
+ 'us-east-1' => 'hpc.aliyuncs.com',
+ 'cn-hongkong' => 'hpc.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'hpc.aliyuncs.com',
+ 'cn-shanghai' => 'hpc.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'hpc.aliyuncs.com',
+ 'us-west-1' => 'hpc.aliyuncs.com',
+ 'cn-shanghai-inner' => 'hpc.aliyuncs.com',
+ 'cn-hangzhou' => 'hpc.aliyuncs.com',
+ 'cn-beijing-inner' => 'hpc.aliyuncs.com',
+ 'cn-shenzhen' => 'hpc.aliyuncs.com',
+ 'cn-qingdao' => 'hpc.aliyuncs.com',
+ 'cn-beijing' => 'hpc.aliyuncs.com',
+ 'cn-hangzhou-d' => 'hpc.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'hpc.aliyuncs.com',
+ 'ap-southeast-1' => 'hpc.aliyuncs.com',
+ ],
+ 'location' =>
+ [
+ 'us-east-1' => 'location.aliyuncs.com',
+ 'cn-hongkong' => 'location.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'location.aliyuncs.com',
+ 'cn-shanghai' => 'location.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'location.aliyuncs.com',
+ 'us-west-1' => 'location.aliyuncs.com',
+ 'cn-shanghai-inner' => 'location.aliyuncs.com',
+ 'cn-hangzhou' => 'location.aliyuncs.com',
+ 'cn-beijing-inner' => 'location.aliyuncs.com',
+ 'cn-shenzhen' => 'location.aliyuncs.com',
+ 'cn-qingdao' => 'location.aliyuncs.com',
+ 'cn-beijing' => 'location.aliyuncs.com',
+ 'cn-hangzhou-d' => 'location.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'location.aliyuncs.com',
+ 'ap-southeast-1' => 'location.aliyuncs.com',
+ ],
+ 'chargingservice' =>
+ [
+ 'us-east-1' => 'chargingservice.aliyuncs.com',
+ 'cn-hongkong' => 'chargingservice.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'chargingservice.aliyuncs.com',
+ 'cn-shanghai' => 'chargingservice.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'chargingservice.aliyuncs.com',
+ 'us-west-1' => 'chargingservice.aliyuncs.com',
+ 'cn-shanghai-inner' => 'chargingservice.aliyuncs.com',
+ 'cn-hangzhou' => 'chargingservice.aliyuncs.com',
+ 'cn-beijing-inner' => 'chargingservice.aliyuncs.com',
+ 'cn-beijing' => 'chargingservice.aliyuncs.com',
+ 'cn-hangzhou-d' => 'chargingservice.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'chargingservice.aliyuncs.com',
+ 'ap-southeast-1' => 'chargingservice.aliyuncs.com',
+ ],
+ 'msg' =>
+ [
+ 'us-east-1' => 'msg-inner.aliyuncs.com',
+ 'cn-hongkong' => 'msg-inner.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'msg-inner.aliyuncs.com',
+ 'cn-shanghai' => 'msg-inner.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'msg-inner.aliyuncs.com',
+ 'us-west-1' => 'msg-inner.aliyuncs.com',
+ 'cn-shanghai-inner' => 'msg-inner.aliyuncs.com',
+ 'cn-hangzhou' => 'msg-inner.aliyuncs.com',
+ 'cn-beijing-inner' => 'msg-inner.aliyuncs.com',
+ 'cn-beijing' => 'msg-inner.aliyuncs.com',
+ 'cn-hangzhou-d' => 'msg-inner.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'msg-inner.aliyuncs.com',
+ 'ap-southeast-1' => 'msg-inner.aliyuncs.com',
+ ],
+ 'commondriver' =>
+ [
+ 'us-east-1' => 'common.driver.aliyuncs.com',
+ 'cn-hongkong' => 'common.driver.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'common.driver.aliyuncs.com',
+ 'cn-shanghai' => 'common.driver.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'common.driver.aliyuncs.com',
+ 'us-west-1' => 'common.driver.aliyuncs.com',
+ 'cn-shanghai-inner' => 'common.driver.aliyuncs.com',
+ 'cn-hangzhou' => 'common.driver.aliyuncs.com',
+ 'cn-beijing-inner' => 'common.driver.aliyuncs.com',
+ 'cn-shenzhen' => 'common.driver.aliyuncs.com',
+ 'cn-qingdao' => 'common.driver.aliyuncs.com',
+ 'cn-beijing' => 'common.driver.aliyuncs.com',
+ 'cn-hangzhou-d' => 'common.driver.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'common.driver.aliyuncs.com',
+ 'ap-southeast-1' => 'common.driver.aliyuncs.com',
+ ],
+ 'r-kvstore' =>
+ [
+ 'us-east-1' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'r-kvstore-cn-hangzhou.aliyuncs.com',
+ ],
+ 'bss' =>
+ [
+ 'us-east-1' => 'bss.aliyuncs.com',
+ 'cn-hongkong' => 'bss.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'bss.aliyuncs.com',
+ 'cn-shanghai' => 'bss.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'bss.aliyuncs.com',
+ 'us-west-1' => 'bss.aliyuncs.com',
+ 'cn-shanghai-inner' => 'bss.aliyuncs.com',
+ 'cn-hangzhou' => 'bss.aliyuncs.com',
+ 'cn-beijing-inner' => 'bss.aliyuncs.com',
+ 'cn-shenzhen' => 'bss.aliyuncs.com',
+ 'cn-qingdao' => 'bss.aliyuncs.com',
+ 'cn-beijing' => 'bss.aliyuncs.com',
+ 'cn-hangzhou-d' => 'bss.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'bss.aliyuncs.com',
+ 'ap-southeast-1' => 'bss.aliyuncs.com',
+ ],
+ 'workorder' =>
+ [
+ 'us-east-1' => 'workorder.aliyuncs.com',
+ 'cn-hongkong' => 'workorder.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'workorder.aliyuncs.com',
+ 'cn-shanghai' => 'workorder.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'workorder.aliyuncs.com',
+ 'us-west-1' => 'workorder.aliyuncs.com',
+ 'cn-shanghai-inner' => 'workorder.aliyuncs.com',
+ 'cn-hangzhou' => 'workorder.aliyuncs.com',
+ 'cn-beijing-inner' => 'workorder.aliyuncs.com',
+ 'cn-beijing' => 'workorder.aliyuncs.com',
+ 'cn-hangzhou-d' => 'workorder.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'workorder.aliyuncs.com',
+ 'ap-southeast-1' => 'workorder.aliyuncs.com',
+ ],
+ 'ocs' =>
+ [
+ 'us-east-1' => 'm-kvstore.aliyuncs.com',
+ 'cn-hongkong' => 'm-kvstore.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'm-kvstore.aliyuncs.com',
+ 'cn-shanghai' => 'm-kvstore.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'm-kvstore.aliyuncs.com',
+ 'us-west-1' => 'm-kvstore.aliyuncs.com',
+ 'cn-shanghai-inner' => 'm-kvstore.aliyuncs.com',
+ 'cn-hangzhou' => 'm-kvstore.aliyuncs.com',
+ 'cn-beijing-inner' => 'm-kvstore.aliyuncs.com',
+ 'cn-shenzhen' => 'm-kvstore.aliyuncs.com',
+ 'cn-qingdao' => 'm-kvstore.aliyuncs.com',
+ 'cn-beijing' => 'm-kvstore.aliyuncs.com',
+ 'cn-hangzhou-d' => 'm-kvstore.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'm-kvstore.aliyuncs.com',
+ 'ap-southeast-1' => 'm-kvstore.aliyuncs.com',
+ ],
+ 'yundun' =>
+ [
+ 'us-east-1' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'yundun-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'yundun-cn-hangzhou.aliyuncs.com',
+ ],
+ 'ubsms-inner' =>
+ [
+ 'us-east-1' => 'ubsms-inner.aliyuncs.com',
+ 'cn-hongkong' => 'ubsms-inner.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ubsms-inner.aliyuncs.com',
+ 'cn-shanghai' => 'ubsms-inner.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ubsms-inner.aliyuncs.com',
+ 'us-west-1' => 'ubsms-inner.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ubsms-inner.aliyuncs.com',
+ 'cn-hangzhou' => 'ubsms-inner.aliyuncs.com',
+ 'cn-beijing-inner' => 'ubsms-inner.aliyuncs.com',
+ 'cn-shenzhen' => 'ubsms-inner.aliyuncs.com',
+ 'cn-qingdao' => 'ubsms-inner.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'ubsms-inner.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ubsms-inner.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ubsms-inner.aliyuncs.com',
+ 'ap-southeast-1' => 'ubsms-inner.aliyuncs.com',
+ ],
+ 'dm' =>
+ [
+ 'us-east-1' => 'dm.aliyuncs.com',
+ 'cn-hongkong' => 'dm.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'dm.aliyuncs.com',
+ 'cn-shanghai' => 'dm.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'dm.aliyuncs.com',
+ 'us-west-1' => 'dm.aliyuncs.com',
+ 'cn-shanghai-inner' => 'dm.aliyuncs.com',
+ 'cn-hangzhou' => 'dm.aliyuncs.com',
+ 'cn-beijing-inner' => 'dm.aliyuncs.com',
+ 'cn-shenzhen' => 'dm.aliyuncs.com',
+ 'cn-qingdao' => 'dm.aliyuncs.com',
+ 'cn-beijing' => 'dm.aliyuncs.com',
+ 'cn-hangzhou-d' => 'dm.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'dm.aliyuncs.com',
+ 'ap-southeast-1' => 'dm.aliyuncs.com',
+ ],
+ 'green' =>
+ [
+ 'us-east-1' => 'green.aliyuncs.com',
+ 'cn-hongkong' => 'green.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'green.aliyuncs.com',
+ 'cn-shanghai' => 'green.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'green.aliyuncs.com',
+ 'us-west-1' => 'green.us-west-1.aliyuncs.com',
+ 'cn-shanghai-inner' => 'green.aliyuncs.com',
+ 'cn-hangzhou' => 'green.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'green.aliyuncs.com',
+ 'cn-shenzhen' => 'green.aliyuncs.com',
+ 'cn-qingdao' => 'green.aliyuncs.com',
+ 'cn-beijing' => 'green.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou-d' => 'green.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'green.aliyuncs.com',
+ 'ap-southeast-1' => 'green.ap-southeast-1.aliyuncs.com',
+ ],
+ 'risk' =>
+ [
+ 'us-east-1' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'risk-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'risk-cn-hangzhou.aliyuncs.com',
+ ],
+ 'oceanbase' =>
+ [
+ 'us-east-1' => 'oceanbase.aliyuncs.com',
+ 'cn-hongkong' => 'oceanbase.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'oceanbase.aliyuncs.com',
+ 'cn-shanghai' => 'oceanbase.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'oceanbase.aliyuncs.com',
+ 'us-west-1' => 'oceanbase.aliyuncs.com',
+ 'cn-shanghai-inner' => 'oceanbase.aliyuncs.com',
+ 'cn-hangzhou' => 'oceanbase.aliyuncs.com',
+ 'cn-beijing-inner' => 'oceanbase.aliyuncs.com',
+ 'cn-shenzhen' => 'oceanbase.aliyuncs.com',
+ 'cn-qingdao' => 'oceanbase.aliyuncs.com',
+ 'cn-beijing' => 'oceanbase.aliyuncs.com',
+ 'cn-hangzhou-d' => 'oceanbase.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'oceanbase.aliyuncs.com',
+ 'ap-southeast-1' => 'oceanbase.aliyuncs.com',
+ ],
+ 'msc' =>
+ [
+ 'us-east-1' => 'msc-inner.aliyuncs.com',
+ 'cn-hongkong' => 'msc-inner.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'msc-inner.aliyuncs.com',
+ 'cn-shanghai' => 'msc-inner.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'msc-inner.aliyuncs.com',
+ 'us-west-1' => 'msc-inner.aliyuncs.com',
+ 'cn-shanghai-inner' => 'msc-inner.aliyuncs.com',
+ 'cn-hangzhou' => 'msc-inner.aliyuncs.com',
+ 'cn-beijing-inner' => 'msc-inner.aliyuncs.com',
+ 'cn-beijing' => 'msc-inner.aliyuncs.com',
+ 'cn-hangzhou-d' => 'msc-inner.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'msc-inner.aliyuncs.com',
+ 'ap-southeast-1' => 'msc-inner.aliyuncs.com',
+ ],
+ 'yundunhsm' =>
+ [
+ 'us-east-1' => 'yundunhsm.aliyuncs.com',
+ 'cn-hongkong' => 'yundunhsm.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'yundunhsm.aliyuncs.com',
+ 'cn-shanghai' => 'yundunhsm.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'yundunhsm.aliyuncs.com',
+ 'us-west-1' => 'yundunhsm.aliyuncs.com',
+ 'cn-shanghai-inner' => 'yundunhsm.aliyuncs.com',
+ 'cn-hangzhou' => 'yundunhsm.aliyuncs.com',
+ 'cn-beijing-inner' => 'yundunhsm.aliyuncs.com',
+ 'cn-beijing' => 'yundunhsm.aliyuncs.com',
+ 'cn-hangzhou-d' => 'yundunhsm.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'yundunhsm.aliyuncs.com',
+ 'ap-southeast-1' => 'yundunhsm.aliyuncs.com',
+ ],
+ 'iot' =>
+ [
+ 'cn-hongkong' => 'iot.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'iot.aliyuncs.com',
+ 'cn-shanghai' => 'iot.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'iot.aliyuncs.com',
+ 'us-west-1' => 'iot.us-west-1.aliyuncs.com',
+ 'cn-shanghai-inner' => 'iot.aliyuncs.com',
+ 'cn-hangzhou' => 'iot.aliyuncs.com',
+ 'cn-beijing-inner' => 'iot.aliyuncs.com',
+ 'cn-shenzhen' => 'iot.aliyuncs.com',
+ 'cn-qingdao' => 'iot.aliyuncs.com',
+ 'cn-beijing' => 'iot.aliyuncs.com',
+ 'cn-hangzhou-d' => 'iot.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'iot.aliyuncs.com',
+ 'ap-southeast-1' => 'iot.ap-southeast-1.aliyuncs.com',
+ 'ap-northeast-1' => 'iot.ap-northeast-1.aliyuncs.com',
+ 'us-east-1' => 'iot.us-east-1.aliyuncs.com',
+ 'eu-central-1' => 'iot.eu-central-1.aliyuncs.com',
+ ],
+ 'oms' =>
+ [
+ 'us-east-1' => 'oms.aliyuncs.com',
+ 'cn-hongkong' => 'oms.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'oms.aliyuncs.com',
+ 'cn-shanghai' => 'oms.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'oms.aliyuncs.com',
+ 'us-west-1' => 'oms.aliyuncs.com',
+ 'cn-shanghai-inner' => 'oms.aliyuncs.com',
+ 'cn-hangzhou' => 'oms.aliyuncs.com',
+ 'cn-beijing-inner' => 'oms.aliyuncs.com',
+ 'cn-shenzhen' => 'oms.aliyuncs.com',
+ 'cn-qingdao' => 'oms.aliyuncs.com',
+ 'cn-beijing' => 'oms.aliyuncs.com',
+ 'cn-hangzhou-d' => 'oms.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'oms.aliyuncs.com',
+ 'ap-southeast-1' => 'oms.aliyuncs.com',
+ ],
+ 'live' =>
+ [
+ 'us-east-1' => 'live.aliyuncs.com',
+ 'cn-hongkong' => 'live.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'live.aliyuncs.com',
+ 'cn-shanghai' => 'live.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'live.aliyuncs.com',
+ 'us-west-1' => 'live.aliyuncs.com',
+ 'cn-shanghai-inner' => 'live.aliyuncs.com',
+ 'cn-hangzhou' => 'live.aliyuncs.com',
+ 'cn-beijing-inner' => 'live.aliyuncs.com',
+ 'cn-shenzhen' => 'live.aliyuncs.com',
+ 'cn-qingdao' => 'live.aliyuncs.com',
+ 'cn-beijing' => 'live.aliyuncs.com',
+ 'cn-hangzhou-d' => 'live.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'live.aliyuncs.com',
+ 'ap-southeast-1' => 'live.aliyuncs.com',
+ 'ap-northeast-1' => 'live.aliyuncs.com',
+ 'eu-central-1' => 'live.aliyuncs.com',
+ 'ap-southeast-5' => 'live.aliyuncs.com',
+ 'ap-south-1' => 'live.aliyuncs.com',
+ ],
+ 'ubsms' =>
+ [
+ 'us-east-1' => 'ubsms.aliyuncs.com',
+ 'cn-hongkong' => 'ubsms.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ubsms.aliyuncs.com',
+ 'cn-shanghai' => 'ubsms.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ubsms.aliyuncs.com',
+ 'us-west-1' => 'ubsms.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ubsms.aliyuncs.com',
+ 'cn-hangzhou' => 'ubsms.aliyuncs.com',
+ 'cn-beijing-inner' => 'ubsms.aliyuncs.com',
+ 'cn-shenzhen' => 'ubsms.aliyuncs.com',
+ 'cn-qingdao' => 'ubsms.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'ubsms.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ubsms.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ubsms.aliyuncs.com',
+ 'ap-southeast-1' => 'ubsms.aliyuncs.com',
+ ],
+ 'alert' =>
+ [
+ 'us-east-1' => 'alert.aliyuncs.com',
+ 'cn-hongkong' => 'alert.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'alert.aliyuncs.com',
+ 'cn-shanghai' => 'alert.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'alert.aliyuncs.com',
+ 'us-west-1' => 'alert.aliyuncs.com',
+ 'cn-shanghai-inner' => 'alert.aliyuncs.com',
+ 'cn-hangzhou' => 'alert.aliyuncs.com',
+ 'cn-beijing-inner' => 'alert.aliyuncs.com',
+ 'cn-shenzhen' => 'alert.aliyuncs.com',
+ 'cn-qingdao' => 'alert.aliyuncs.com',
+ 'cn-beijing' => 'alert.aliyuncs.com',
+ 'cn-hangzhou-d' => 'alert.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'alert.aliyuncs.com',
+ 'ap-southeast-1' => 'alert.aliyuncs.com',
+ ],
+ 'ace' =>
+ [
+ 'us-east-1' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ace.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'ace.cn-hangzhou.aliyuncs.com',
+ ],
+ 'ams' =>
+ [
+ 'us-east-1' => 'ams.aliyuncs.com',
+ 'cn-hongkong' => 'ams.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ams.aliyuncs.com',
+ 'cn-shanghai' => 'ams.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ams.aliyuncs.com',
+ 'us-west-1' => 'ams.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ams.aliyuncs.com',
+ 'cn-hangzhou' => 'ams.aliyuncs.com',
+ 'cn-beijing-inner' => 'ams.aliyuncs.com',
+ 'cn-beijing' => 'ams.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ams.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ams.aliyuncs.com',
+ 'ap-southeast-1' => 'ams.aliyuncs.com',
+ ],
+ 'ros' =>
+ [
+ 'us-east-1' => 'ros.aliyuncs.com',
+ 'cn-hongkong' => 'ros.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ros.aliyuncs.com',
+ 'cn-shanghai' => 'ros.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ros.aliyuncs.com',
+ 'us-west-1' => 'ros.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ros.aliyuncs.com',
+ 'cn-hangzhou' => 'ros.aliyuncs.com',
+ 'cn-beijing-inner' => 'ros.aliyuncs.com',
+ 'cn-shenzhen' => 'ros.aliyuncs.com',
+ 'cn-qingdao' => 'ros.aliyuncs.com',
+ 'cn-beijing' => 'ros.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ros.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ros.aliyuncs.com',
+ 'ap-southeast-1' => 'ros.aliyuncs.com',
+ ],
+ 'pts' =>
+ [
+ 'us-east-1' => 'pts.aliyuncs.com',
+ 'cn-hongkong' => 'pts.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'pts.aliyuncs.com',
+ 'cn-shanghai' => 'pts.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'pts.aliyuncs.com',
+ 'us-west-1' => 'pts.aliyuncs.com',
+ 'cn-shanghai-inner' => 'pts.aliyuncs.com',
+ 'cn-hangzhou' => 'pts.aliyuncs.com',
+ 'cn-beijing-inner' => 'pts.aliyuncs.com',
+ 'cn-shenzhen' => 'pts.aliyuncs.com',
+ 'cn-qingdao' => 'pts.aliyuncs.com',
+ 'cn-beijing' => 'pts.aliyuncs.com',
+ 'cn-hangzhou-d' => 'pts.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'pts.aliyuncs.com',
+ 'ap-southeast-1' => 'pts.aliyuncs.com',
+ ],
+ 'qualitycheck' =>
+ [
+ 'us-east-1' => 'qualitycheck.aliyuncs.com',
+ 'cn-hongkong' => 'qualitycheck.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'qualitycheck.aliyuncs.com',
+ 'cn-shanghai' => 'qualitycheck.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'qualitycheck.aliyuncs.com',
+ 'us-west-1' => 'qualitycheck.aliyuncs.com',
+ 'cn-shanghai-inner' => 'qualitycheck.aliyuncs.com',
+ 'cn-hangzhou' => 'qualitycheck.aliyuncs.com',
+ 'cn-beijing-inner' => 'qualitycheck.aliyuncs.com',
+ 'cn-hangzhou-d' => 'qualitycheck.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'qualitycheck.aliyuncs.com',
+ 'ap-southeast-1' => 'qualitycheck.aliyuncs.com',
+ ],
+ 'm-kvstore' =>
+ [
+ 'us-east-1' => 'm-kvstore.aliyuncs.com',
+ 'cn-hongkong' => 'm-kvstore.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'm-kvstore.aliyuncs.com',
+ 'cn-shanghai' => 'm-kvstore.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'm-kvstore.aliyuncs.com',
+ 'us-west-1' => 'm-kvstore.aliyuncs.com',
+ 'cn-shanghai-inner' => 'm-kvstore.aliyuncs.com',
+ 'cn-hangzhou' => 'm-kvstore.aliyuncs.com',
+ 'cn-beijing-inner' => 'm-kvstore.aliyuncs.com',
+ 'cn-shenzhen' => 'm-kvstore.aliyuncs.com',
+ 'cn-qingdao' => 'm-kvstore.aliyuncs.com',
+ 'cn-beijing' => 'm-kvstore.aliyuncs.com',
+ 'cn-hangzhou-d' => 'm-kvstore.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'm-kvstore.aliyuncs.com',
+ 'ap-southeast-1' => 'm-kvstore.aliyuncs.com',
+ ],
+ 'highddos' =>
+ [
+ 'us-east-1' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'yd-highddos-cn-hangzhou.aliyuncs.com',
+ ],
+ 'cmssitemonitor' =>
+ [
+ 'us-east-1' => 'sitemonitor.aliyuncs.com',
+ 'cn-hongkong' => 'sitemonitor.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'sitemonitor.aliyuncs.com',
+ 'cn-shanghai' => 'sitemonitor.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'sitemonitor.aliyuncs.com',
+ 'us-west-1' => 'sitemonitor.aliyuncs.com',
+ 'cn-shanghai-inner' => 'sitemonitor.aliyuncs.com',
+ 'cn-hangzhou' => 'sitemonitor.aliyuncs.com',
+ 'cn-beijing-inner' => 'sitemonitor.aliyuncs.com',
+ 'cn-shenzhen' => 'sitemonitor.aliyuncs.com',
+ 'cn-qingdao' => 'sitemonitor.aliyuncs.com',
+ 'cn-beijing' => 'sitemonitor.aliyuncs.com',
+ 'cn-hangzhou-d' => 'sitemonitor.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'sitemonitor.aliyuncs.com',
+ 'ap-southeast-1' => 'sitemonitor.aliyuncs.com',
+ ],
+ 'batchcompute' =>
+ [
+ 'us-east-1' => 'batchCompute.us-east-1.aliyuncs.com',
+ 'cn-hongkong' => 'batchCompute.cn-hongkong.aliyuncs.com',
+ 'cn-shanghai' => 'batchCompute.cn-shanghai.aliyuncs.com',
+ 'us-west-1' => 'batchCompute.us-west-1.aliyuncs.com',
+ 'cn-hangzhou' => 'batchCompute.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'batchcompute.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'batchcompute.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'batchCompute.cn-beijing.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'batchCompute.cn-shanghai-et2-b01.aliyuncs.com',
+ 'ap-southeast-1' => 'batchCompute.ap-southeast-1.aliyuncs.com',
+ ],
+ 'cf' =>
+ [
+ 'us-east-1' => 'cf.aliyuncs.com',
+ 'cn-hongkong' => 'cf.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'cf.aliyuncs.com',
+ 'cn-shanghai' => 'cf.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'cf.aliyuncs.com',
+ 'us-west-1' => 'cf.aliyuncs.com',
+ 'cn-shanghai-inner' => 'cf.aliyuncs.com',
+ 'cn-hangzhou' => 'cf.aliyuncs.com',
+ 'cn-beijing-inner' => 'cf.aliyuncs.com',
+ 'cn-shenzhen' => 'cf.aliyuncs.com',
+ 'cn-qingdao' => 'cf.aliyuncs.com',
+ 'cn-beijing' => 'cf.aliyuncs.com',
+ 'cn-hangzhou-d' => 'cf.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'cf.aliyuncs.com',
+ 'ap-southeast-1' => 'cf.aliyuncs.com',
+ ],
+ 'drds' =>
+ [
+ 'us-east-1' => 'drds.aliyuncs.com',
+ 'cn-hongkong' => 'drds.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'drds.aliyuncs.com',
+ 'cn-shanghai' => 'drds.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'drds.aliyuncs.com',
+ 'us-west-1' => 'drds.aliyuncs.com',
+ 'cn-shanghai-inner' => 'drds.aliyuncs.com',
+ 'cn-hangzhou' => 'drds.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'drds.aliyuncs.com',
+ 'cn-shenzhen' => 'drds.aliyuncs.com',
+ 'cn-qingdao' => 'drds.aliyuncs.com',
+ 'cn-beijing' => 'drds.aliyuncs.com',
+ 'cn-hangzhou-d' => 'drds.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'drds.aliyuncs.com',
+ 'ap-southeast-1' => 'drds.aliyuncs.com',
+ ],
+ 'acs' =>
+ [
+ 'us-east-1' => 'acs.aliyun-inc.com',
+ 'cn-hongkong' => 'acs.aliyun-inc.com',
+ 'cn-shanghai' => 'acs.aliyun-inc.com',
+ 'us-west-1' => 'acs.aliyun-inc.com',
+ 'cn-hangzhou' => 'acs.aliyun-inc.com',
+ 'cn-shenzhen' => 'acs.aliyun-inc.com',
+ 'cn-qingdao' => 'acs.aliyun-inc.com',
+ 'cn-beijing' => 'acs.aliyun-inc.com',
+ 'cn-shanghai-et2-b01' => 'acs.aliyun-inc.com',
+ ],
+ 'httpdns' =>
+ [
+ 'us-east-1' => 'httpdns-api.aliyuncs.com',
+ 'cn-hongkong' => 'httpdns-api.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'httpdns-api.aliyuncs.com',
+ 'cn-shanghai' => 'httpdns-api.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'httpdns-api.aliyuncs.com',
+ 'us-west-1' => 'httpdns-api.aliyuncs.com',
+ 'cn-shanghai-inner' => 'httpdns-api.aliyuncs.com',
+ 'cn-hangzhou' => 'httpdns-api.aliyuncs.com',
+ 'cn-beijing-inner' => 'httpdns-api.aliyuncs.com',
+ 'cn-shenzhen' => 'httpdns-api.aliyuncs.com',
+ 'cn-qingdao' => 'httpdns-api.aliyuncs.com',
+ 'cn-beijing' => 'httpdns-api.aliyuncs.com',
+ 'cn-hangzhou-d' => 'httpdns-api.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'httpdns-api.aliyuncs.com',
+ 'ap-southeast-1' => 'httpdns-api.aliyuncs.com',
+ ],
+ 'location-inner' =>
+ [
+ 'us-east-1' => 'location-inner.aliyuncs.com',
+ 'cn-hongkong' => 'location-inner.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'location-inner.aliyuncs.com',
+ 'cn-shanghai' => 'location-inner.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'location-inner.aliyuncs.com',
+ 'us-west-1' => 'location-inner.aliyuncs.com',
+ 'cn-shanghai-inner' => 'location-inner.aliyuncs.com',
+ 'cn-hangzhou' => 'location-inner.aliyuncs.com',
+ 'cn-beijing-inner' => 'location-inner.aliyuncs.com',
+ 'cn-shenzhen' => 'location-inner.aliyuncs.com',
+ 'cn-qingdao' => 'location-inner.aliyuncs.com',
+ 'cn-beijing' => 'location-inner.aliyuncs.com',
+ 'cn-hangzhou-d' => 'location-inner.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'location-inner.aliyuncs.com',
+ 'ap-southeast-1' => 'location-inner.aliyuncs.com',
+ ],
+ 'aas' =>
+ [
+ 'us-east-1' => 'aas.aliyuncs.com',
+ 'cn-hongkong' => 'aas.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'aas.aliyuncs.com',
+ 'cn-shanghai' => 'aas.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'aas.aliyuncs.com',
+ 'us-west-1' => 'aas.aliyuncs.com',
+ 'cn-shanghai-inner' => 'aas.aliyuncs.com',
+ 'cn-hangzhou' => 'aas.aliyuncs.com',
+ 'cn-beijing-inner' => 'aas.aliyuncs.com',
+ 'cn-shenzhen' => 'aas.aliyuncs.com',
+ 'cn-qingdao' => 'aas.aliyuncs.com',
+ 'cn-beijing' => 'aas.aliyuncs.com',
+ 'cn-hangzhou-d' => 'aas.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'aas.aliyuncs.com',
+ 'ap-southeast-1' => 'aas.aliyuncs.com',
+ ],
+ 'sts' =>
+ [
+ 'cn-hangzhou' => 'sts.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'sts.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'sts.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'sts.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'sts.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'sts.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'sts.cn-huhehaote.aliyuncs.com',
+ 'cn-hongkong' => 'sts.cn-hongkong.aliyuncs.com',
+ 'cn-chengdu' => 'sts.cn-chengdu.aliyuncs.com',
+ 'ap-southeast-1' => 'sts.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'sts.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'sts.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'sts.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'sts.ap-northeast-1.aliyuncs.com',
+ 'ap-south-1' => 'sts.ap-south-1.aliyuncs.com',
+ 'us-west-1' => 'sts.us-west-1.aliyuncs.com',
+ 'us-east-1' => 'sts.us-east-1.aliyuncs.com',
+ 'eu-central-1' => 'sts.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'sts.me-east-1.aliyuncs.com',
+ 'eu-west-1' => 'sts.eu-west-1.aliyuncs.com',
+ ],
+ 'dts' =>
+ [
+ 'us-east-1' => 'dts.aliyuncs.com',
+ 'cn-hongkong' => 'dts.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'dts.aliyuncs.com',
+ 'cn-shanghai' => 'dts.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'dts.aliyuncs.com',
+ 'us-west-1' => 'dts.aliyuncs.com',
+ 'cn-shanghai-inner' => 'dts.aliyuncs.com',
+ 'cn-hangzhou' => 'dts.aliyuncs.com',
+ 'cn-beijing-inner' => 'dts.aliyuncs.com',
+ 'cn-shenzhen' => 'dts.aliyuncs.com',
+ 'cn-qingdao' => 'dts.aliyuncs.com',
+ 'cn-beijing' => 'dts.aliyuncs.com',
+ 'cn-hangzhou-d' => 'dts.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'dts.aliyuncs.com',
+ 'ap-southeast-1' => 'dts.aliyuncs.com',
+ ],
+ 'drc' =>
+ [
+ 'us-east-1' => 'drc.aliyuncs.com',
+ 'cn-hongkong' => 'drc.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'drc.aliyuncs.com',
+ 'cn-shanghai' => 'drc.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'drc.aliyuncs.com',
+ 'us-west-1' => 'drc.aliyuncs.com',
+ 'cn-shanghai-inner' => 'drc.aliyuncs.com',
+ 'cn-hangzhou' => 'drc.aliyuncs.com',
+ 'cn-beijing-inner' => 'drc.aliyuncs.com',
+ 'cn-shenzhen' => 'drc.aliyuncs.com',
+ 'cn-qingdao' => 'drc.aliyuncs.com',
+ 'cn-beijing' => 'drc.aliyuncs.com',
+ 'cn-hangzhou-d' => 'drc.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'drc.aliyuncs.com',
+ 'ap-southeast-1' => 'drc.aliyuncs.com',
+ ],
+ 'vpc-inner' =>
+ [
+ 'us-east-1' => 'vpc-inner.aliyuncs.com',
+ 'cn-hongkong' => 'vpc-inner.aliyuncs.com',
+ 'cn-shanghai' => 'vpc-inner.aliyuncs.com',
+ 'us-west-1' => 'vpc-inner.aliyuncs.com',
+ 'cn-hangzhou' => 'vpc-inner.aliyuncs.com',
+ 'cn-shenzhen' => 'vpc-inner.aliyuncs.com',
+ 'cn-qingdao' => 'vpc-inner.aliyuncs.com',
+ 'cn-beijing' => 'vpc-inner.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'vpc-inner.aliyuncs.com',
+ ],
+ 'crm' =>
+ [
+ 'us-east-1' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'crm-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'crm-cn-hangzhou.aliyuncs.com',
+ ],
+ 'domain' =>
+ [
+ 'us-east-1' => 'domain.aliyuncs.com',
+ 'cn-hongkong' => 'domain.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'domain.aliyuncs.com',
+ 'cn-shanghai' => 'domain.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'domain.aliyuncs.com',
+ 'us-west-1' => 'domain.aliyuncs.com',
+ 'cn-shanghai-inner' => 'domain.aliyuncs.com',
+ 'cn-hangzhou' => 'domain.aliyuncs.com',
+ 'cn-beijing-inner' => 'domain.aliyuncs.com',
+ 'cn-shenzhen' => 'domain.aliyuncs.com',
+ 'cn-qingdao' => 'domain.aliyuncs.com',
+ 'cn-beijing' => 'domain.aliyuncs.com',
+ 'cn-hangzhou-d' => 'domain.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'domain.aliyuncs.com',
+ 'ap-southeast-1' => 'domain.aliyuncs.com',
+ ],
+ 'ots' =>
+ [
+ 'us-east-1' => 'ots.us-east-1.aliyuncs.com',
+ 'cn-hongkong' => 'ots-pop.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ots-pop.aliyuncs.com',
+ 'cn-shanghai' => 'ots.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ots-pop.aliyuncs.com',
+ 'us-west-1' => 'ots.us-west-1.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ots-pop.aliyuncs.com',
+ 'cn-hangzhou' => 'ots.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'ots-pop.aliyuncs.com',
+ 'cn-shenzhen' => 'ots.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'ots-pop.aliyuncs.com',
+ 'cn-beijing' => 'ots.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ots-pop.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ots-pop.aliyuncs.com',
+ 'ap-southeast-1' => 'ots.ap-southeast-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'ots.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'ots.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-2' => 'ots.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'ots.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'ots.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'ots.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'ots.eu-west-1.aliyuncs.com',
+ 'eu-central-1' => 'ots.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'ots.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'ots.ap-south-1.aliyuncs.com',
+ ],
+ 'oss' =>
+ [
+ 'us-east-1' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'oss-cn-hongkong.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-finance' => 'oss-cn-qdjbp-a.aliyuncs.com',
+ 'cn-beijing-gov-1' => 'oss-cn-haidian-a.aliyuncs.com',
+ 'cn-shanghai' => 'oss-cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'oss-us-west-1.aliyuncs.com',
+ 'cn-shanghai-inner' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-finance' => 'oss-cn-hzjbp-b-console.aliyuncs.com',
+ 'cn-hangzhou' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'oss-cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'oss-cn-qingdao.aliyuncs.com',
+ 'oss-cn-bjzwy' => 'oss-cn-bjzwy.aliyuncs.com',
+ 'cn-beijing' => 'oss-cn-beijing.aliyuncs.com',
+ 'cn-hangzhou-d' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'oss-cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'oss-ap-southeast-1.aliyuncs.com',
+ ],
+ 'ram' =>
+ [
+ 'global' => 'ram.aliyuncs.com',
+ 'us-east-1' => 'ram.aliyuncs.com',
+ 'cn-hongkong' => 'ram.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ram.aliyuncs.com',
+ 'cn-shanghai' => 'ram.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ram.aliyuncs.com',
+ 'us-west-1' => 'ram.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ram.aliyuncs.com',
+ 'cn-hangzhou' => 'ram.aliyuncs.com',
+ 'cn-beijing-inner' => 'ram.aliyuncs.com',
+ 'cn-shenzhen' => 'ram.aliyuncs.com',
+ 'cn-qingdao' => 'ram.aliyuncs.com',
+ 'cn-beijing' => 'ram.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ram.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ram.aliyuncs.com',
+ 'ap-southeast-1' => 'ram.aliyuncs.com',
+ ],
+ 'sales' =>
+ [
+ 'us-east-1' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'sales.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'sales.cn-hangzhou.aliyuncs.com',
+ ],
+ 'ossadmin' =>
+ [
+ 'us-east-1' => 'oss-admin.aliyuncs.com',
+ 'cn-hongkong' => 'oss-admin.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'oss-admin.aliyuncs.com',
+ 'cn-shanghai' => 'oss-admin.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'oss-admin.aliyuncs.com',
+ 'us-west-1' => 'oss-admin.aliyuncs.com',
+ 'cn-shanghai-inner' => 'oss-admin.aliyuncs.com',
+ 'cn-hangzhou' => 'oss-admin.aliyuncs.com',
+ 'cn-beijing-inner' => 'oss-admin.aliyuncs.com',
+ 'cn-shenzhen' => 'oss-admin.aliyuncs.com',
+ 'cn-qingdao' => 'oss-admin.aliyuncs.com',
+ 'cn-beijing' => 'oss-admin.aliyuncs.com',
+ 'cn-hangzhou-d' => 'oss-admin.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'oss-admin.aliyuncs.com',
+ 'ap-southeast-1' => 'oss-admin.aliyuncs.com',
+ ],
+ 'alidns' =>
+ [
+ 'us-east-1' => 'alidns.aliyuncs.com',
+ 'cn-hongkong' => 'alidns.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'alidns.aliyuncs.com',
+ 'cn-shanghai' => 'alidns.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'alidns.aliyuncs.com',
+ 'us-west-1' => 'alidns.aliyuncs.com',
+ 'cn-shanghai-inner' => 'alidns.aliyuncs.com',
+ 'cn-hangzhou' => 'alidns.aliyuncs.com',
+ 'cn-beijing-inner' => 'alidns.aliyuncs.com',
+ 'cn-shenzhen' => 'alidns.aliyuncs.com',
+ 'cn-qingdao' => 'alidns.aliyuncs.com',
+ 'cn-beijing' => 'alidns.aliyuncs.com',
+ 'cn-hangzhou-d' => 'alidns.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'alidns.aliyuncs.com',
+ 'ap-southeast-1' => 'alidns.aliyuncs.com',
+ ],
+ 'ons' =>
+ [
+ 'us-east-1' => 'ons.us-east-1.aliyuncs.com',
+ 'cn-hongkong' => 'ons.cn-hongkong.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'ons.aliyuncs.com',
+ 'cn-shanghai' => 'ons.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'ons.aliyuncs.com',
+ 'us-west-1' => 'ons.us-west-1.aliyuncs.com',
+ 'cn-shanghai-inner' => 'ons.aliyuncs.com',
+ 'cn-hangzhou' => 'ons.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'ons.aliyuncs.com',
+ 'cn-shenzhen' => 'ons.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'ons.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'ons.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou-d' => 'ons.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'ons.aliyuncs.com',
+ 'ap-southeast-1' => 'ons.ap-southeast-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'ons.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'ons.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-2' => 'ons.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'ons.ap-southeast-3.aliyuncs.com',
+ 'ap-northeast-1' => 'ons.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'ons.eu-west-1.aliyuncs.com',
+ 'eu-central-1' => 'ons.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'ons.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'ons.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'ons.cn-chengdu.aliyuncs.com',
+ ],
+ 'cdn' =>
+ [
+ 'global' => 'cdn.aliyuncs.com',
+ 'us-east-1' => 'cdn.aliyuncs.com',
+ 'cn-hongkong' => 'cdn.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'cdn.aliyuncs.com',
+ 'cn-shanghai' => 'cdn.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'cdn.aliyuncs.com',
+ 'us-west-1' => 'cdn.aliyuncs.com',
+ 'cn-shanghai-inner' => 'cdn.aliyuncs.com',
+ 'cn-hangzhou' => 'cdn.aliyuncs.com',
+ 'cn-beijing-inner' => 'cdn.aliyuncs.com',
+ 'cn-shenzhen' => 'cdn.aliyuncs.com',
+ 'cn-qingdao' => 'cdn.aliyuncs.com',
+ 'cn-beijing' => 'cdn.aliyuncs.com',
+ 'cn-hangzhou-d' => 'cdn.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'cdn.aliyuncs.com',
+ 'ap-southeast-1' => 'cdn.aliyuncs.com',
+ ],
+ 'yundunddos' =>
+ [
+ 'us-east-1' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'us-west-1' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-inner' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou-d' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com',
+ ],
+ 'kvstore' =>
+ [
+ 'ap-northeast-1' => 'r-kvstore.ap-northeast-1.aliyuncs.com',
+ ],
+ 'cloudapi' =>
+ [
+ 'cn-hongkong' => 'apigateway.cn-hongkong.aliyuncs.com',
+ 'cn-shanghai' => 'apigateway.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'apigateway.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'apigateway.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'apigateway.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'apigateway.cn-beijing.aliyuncs.com',
+ 'ap-southeast-1' => 'apigateway.ap-southeast-1.aliyuncs.com',
+ ],
+ 'mts' =>
+ [
+ 'cn-hongkong' => 'mts.cn-hongkong.aliyuncs.com',
+ 'cn-qingdao-cm9' => 'mts.cn-qingdao.aliyuncs.com',
+ 'cn-shanghai' => 'mts.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen-inner' => 'mts.cn-shenzhen.aliyuncs.com',
+ 'us-west-1' => 'mts.us-west-1.aliyuncs.com',
+ 'cn-shanghai-inner' => 'mts.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'mts.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing-inner' => 'mts.cn-beijing.aliyuncs.com',
+ 'cn-shenzhen' => 'mts.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'mts.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'mts.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou-d' => 'mts.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai-et2-b01' => 'mts.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'mts.ap-southeast-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'mts.cn-zhangjiakou.aliyuncs.com',
+ 'ap-northeast-1' => 'mts.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'mts.eu-west-1.aliyuncs.com',
+ 'eu-central-1' => 'mts.eu-central-1.aliyuncs.com',
+ 'ap-south-1' => 'mts.ap-south-1.aliyuncs.com',
+ 'ap-southeast-5' => 'mts.ap-southeast-5.aliyuncs.com',
+ ],
+ 'saf' =>
+ [
+ 'cn-shanghai' => 'saf.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'saf.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'saf.cn-shenzhen.aliyuncs.com',
+ 'ap-southeast-1' => 'riskcontrol-share.aliyuncs.com',
+ ],
+ 'arms' =>
+ [
+ 'cn-shanghai' => 'arms.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'arms.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'arms.cn-shenzhen.aliyuncs.com',
+ 'cn-beijing' => 'arms.cn-beijing.aliyuncs.com',
+ ],
+ 'apigateway' =>
+ [
+ 'cn-shanghai' => 'apigateway.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'apigateway.cn-hangzhou.aliyuncs.com',
+ 'cn-shenzhen' => 'apigateway.cn-shenzhen.aliyuncs.com',
+ 'cn-qingdao' => 'apigateway.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'apigateway.cn-beijing.aliyuncs.com',
+ 'ap-southeast-1' => 'apigateway.ap-southeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'apigateway.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-2' => 'apigateway.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'apigateway.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'apigateway.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'apigateway.ap-northeast-1.aliyuncs.com',
+ 'eu-central-1' => 'apigateway.eu-central-1.aliyuncs.com',
+ 'ap-south-1' => 'apigateway.ap-south-1.aliyuncs.com',
+ 'eu-west-1' => 'apigateway.eu-west-1.aliyuncs.com',
+ 'me-east-1' => 'apigateway.me-east-1.aliyuncs.com',
+ 'us-east-1' => 'apigateway.us-east-1.aliyuncs.com',
+ 'us-west-1' => 'apigateway.us-west-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'apigateway.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'apigateway.cn-huhehaote.aliyuncs.com',
+ 'cn-chengdu' => 'apigateway.cn-chengdu.aliyuncs.com',
+ ],
+ 'vod' =>
+ [
+ 'cn-shanghai' => 'vod.cn-shanghai.aliyuncs.com',
+ 'cn-beijing' => 'vod.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'vod.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'vod.cn-shanghai.aliyuncs.com',
+ 'ap-southeast-1' => 'vod.ap-southeast-1.aliyuncs.com',
+ 'eu-central-1' => 'vod.eu-central-1.aliyuncs.com',
+ 'cn-zhangjiakou' => 'vod.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hongkong' => 'vod.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-5' => 'vod.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'vod.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'vod.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'vod.us-west-1.aliyuncs.com',
+ 'ap-south-1' => 'vod.ap-south-1.aliyuncs.com',
+ ],
+ 'afs' =>
+ [
+ 'cn-hangzhou' => 'afs.aliyuncs.com',
+ ],
+ 'oas' =>
+ [
+ 'cn-hangzhou' => 'cn-hangzhou.oas.aliyuncs.com',
+ 'cn-shenzhen' => 'cn-shenzhen.oas.aliyuncs.com',
+ 'cn-beijing' => 'cn-beijing.oas.aliyuncs.com',
+ ],
+ 'alikafka' =>
+ [
+ 'cn-qingdao' => 'alikafka.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'alikafka.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'alikafka.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'alikafka.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'alikafka.cn-shenzhen.aliyuncs.com',
+ 'cn-zhangjiakou' => 'alikafka.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'alikafka.cn-huhehaote.aliyuncs.com',
+ 'cn-hongkong' => 'alikafka.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'alikafka.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-5' => 'alikafka.ap-southeast-5.aliyuncs.com',
+ 'ap-south-1' => 'alikafka.ap-south-1.aliyuncs.com',
+ ],
+ 'cbn' =>
+ [
+ 'cn-qingdao' => 'cbn.aliyuncs.com',
+ 'cn-beijing' => 'cbn.aliyuncs.com',
+ 'cn-zhangjiakou' => 'cbn.aliyuncs.com',
+ 'cn-huhehaote' => 'cbn.aliyuncs.com',
+ 'cn-hangzhou' => 'cbn.aliyuncs.com',
+ 'cn-shanghai' => 'cbn.aliyuncs.com',
+ 'cn-shenzhen' => 'cbn.aliyuncs.com',
+ 'cn-hongkong' => 'cbn.aliyuncs.com',
+ 'ap-southeast-1' => 'cbn.aliyuncs.com',
+ 'ap-southeast-2' => 'cbn.aliyuncs.com',
+ 'ap-southeast-3' => 'cbn.aliyuncs.com',
+ 'ap-southeast-5' => 'cbn.aliyuncs.com',
+ 'ap-northeast-1' => 'cbn.aliyuncs.com',
+ 'eu-west-1' => 'cbn.aliyuncs.com',
+ 'us-west-1' => 'cbn.aliyuncs.com',
+ 'us-east-1' => 'cbn.aliyuncs.com',
+ 'eu-central-1' => 'cbn.aliyuncs.com',
+ 'me-east-1' => 'cbn.aliyuncs.com',
+ 'ap-south-1' => 'cbn.aliyuncs.com',
+ 'cn-chengdu' => 'cbn.aliyuncs.com',
+ ],
+ 'onsvip' =>
+ [
+ 'cn-qingdao' => 'ons.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'ons.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'ons.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'ons.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'ons.cn-shenzhen.aliyuncs.com',
+ 'ap-southeast-1' => 'ons.ap-southeast-1.aliyuncs.com',
+ ],
+ 'ddosbgp' =>
+ [
+ 'cn-qingdao' => 'ddosbgp.aliyuncs.com',
+ 'cn-beijing' => 'ddosbgp.aliyuncs.com',
+ 'cn-zhangjiakou' => 'ddosbgp.aliyuncs.com',
+ 'cn-huhehaote' => 'ddosbgp.aliyuncs.com',
+ 'cn-hangzhou' => 'ddosbgp.aliyuncs.com',
+ 'cn-shanghai' => 'ddosbgp.aliyuncs.com',
+ 'cn-shenzhen' => 'ddosbgp.aliyuncs.com',
+ 'cn-hongkong' => 'ddosbgp.cn-hongkong.aliyuncs.com',
+ 'us-west-1' => 'ddosbgp.us-west-1.aliyuncs.com',
+ 'ap-southeast-1' => 'ddosbgp.ap-southeast-1.aliyuncs.com',
+ 'us-east-1' => 'ddosbgp.us-east-1.aliyuncs.com',
+ ],
+ 'ehs' =>
+ [
+ 'cn-qingdao' => 'ehpc.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'ehpc.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'ehpc.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'ehpc.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'ehpc.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'ehpc.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'ehpc.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'ehpc.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'ehpc.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'ehpc.ap-southeast-2.aliyuncs.com',
+ 'eu-central-1' => 'ehpc.eu-central-1.aliyuncs.com',
+ 'ap-northeast-1' => 'ehpc.ap-northeast-1.aliyuncs.com',
+ ],
+ 'redisa' =>
+ [
+ 'cn-qingdao' => 'r-kvstore.aliyuncs.com',
+ 'cn-beijing' => 'r-kvstore.aliyuncs.com',
+ 'cn-zhangjiakou' => 'r-kvstore.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'r-kvstore.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'r-kvstore.aliyuncs.com',
+ 'cn-shanghai' => 'r-kvstore.aliyuncs.com',
+ 'cn-shenzhen' => 'r-kvstore.aliyuncs.com',
+ 'cn-hongkong' => 'r-kvstore.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'r-kvstore.aliyuncs.com',
+ 'ap-southeast-2' => 'r-kvstore.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'r-kvstore.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'r-kvstore.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'r-kvstore.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'r-kvstore.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'r-kvstore.aliyuncs.com',
+ 'us-east-1' => 'r-kvstore.aliyuncs.com',
+ 'eu-central-1' => 'r-kvstore.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'r-kvstore.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'r-kvstore.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'r-kvstore.cn-chengdu.aliyuncs.com',
+ ],
+ 'nas' =>
+ [
+ 'cn-qingdao' => 'nas.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'nas.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'nas.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'nas.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'nas.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'nas.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'nas.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'nas.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'nas.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'nas.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'nas.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'nas.ap-southeast-5.aliyuncs.com',
+ 'us-east-1' => 'nas.us-east-1.aliyuncs.com',
+ 'eu-central-1' => 'nas.eu-central-1.aliyuncs.com',
+ 'ap-south-1' => 'nas.ap-south-1.aliyuncs.com',
+ 'ap-northeast-1' => 'nas.ap-northeast-1.aliyuncs.com',
+ 'us-west-1' => 'nas.us-west-1.aliyuncs.com',
+ ],
+ 'hbase' =>
+ [
+ 'cn-qingdao' => 'hbase.aliyuncs.com',
+ 'cn-beijing' => 'hbase.aliyuncs.com',
+ 'cn-huhehaote' => 'hbase.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'hbase.aliyuncs.com',
+ 'cn-shanghai' => 'hbase.aliyuncs.com',
+ 'cn-shenzhen' => 'hbase.aliyuncs.com',
+ 'ap-southeast-1' => 'hbase.aliyuncs.com',
+ 'ap-southeast-2' => 'hbase.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'hbase.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'hbase.ap-southeast-5.aliyuncs.com',
+ 'us-west-1' => 'hbase.aliyuncs.com',
+ 'us-east-1' => 'hbase.aliyuncs.com',
+ 'eu-central-1' => 'hbase.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'hbase.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'hbase.ap-south-1.aliyuncs.com',
+ 'eu-west-1' => 'hbase.eu-west-1.aliyuncs.com',
+ ],
+ 'ddosbasic' =>
+ [
+ 'cn-qingdao' => 'antiddos.aliyuncs.com',
+ 'cn-beijing' => 'antiddos.aliyuncs.com',
+ 'cn-zhangjiakou' => 'antiddos-openapi.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'antiddos-openapi.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'antiddos.aliyuncs.com',
+ 'cn-shanghai' => 'antiddos.aliyuncs.com',
+ 'cn-shenzhen' => 'antiddos.aliyuncs.com',
+ 'cn-hongkong' => 'antiddos.aliyuncs.com',
+ 'ap-southeast-1' => 'antiddos.aliyuncs.com',
+ 'ap-southeast-2' => 'antiddos-openapi.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'antiddos-openapi.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'antiddos-openapi.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'antiddos-openapi.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'antiddos-openapi.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'antiddos.aliyuncs.com',
+ 'us-east-1' => 'antiddos.aliyuncs.com',
+ 'eu-central-1' => 'antiddos-openapi.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'antiddos-openapi.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'antiddos-openapi.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'antiddos-openapi.cn-chengdu.aliyuncs.com',
+ ],
+ 'polardb' =>
+ [
+ 'cn-qingdao' => 'polardb.aliyuncs.com',
+ 'cn-beijing' => 'polardb.aliyuncs.com',
+ 'cn-huhehaote' => 'polardb.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'polardb.aliyuncs.com',
+ 'cn-shanghai' => 'polardb.aliyuncs.com',
+ 'cn-shenzhen' => 'polardb.aliyuncs.com',
+ 'cn-hongkong' => 'polardb.aliyuncs.com',
+ 'cn-zhangjiakou' => 'polardb.cn-zhangjiakou.aliyuncs.com',
+ 'ap-southeast-1' => 'polardb.aliyuncs.com',
+ 'ap-southeast-3' => 'polardb.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'polardb.ap-southeast-5.aliyuncs.com',
+ 'us-west-1' => 'polardb.us-west-1.aliyuncs.com',
+ ],
+ 'actiontrail' =>
+ [
+ 'cn-qingdao' => 'actiontrail.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'actiontrail.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'actiontrail.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'actiontrail.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'actiontrail.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'actiontrail.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'actiontrail.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'actiontrail.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'actiontrail.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'actiontrail.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'actiontrail.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'actiontrail.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'actiontrail.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'actiontrail.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'actiontrail.us-west-1.aliyuncs.com',
+ 'us-east-1' => 'actiontrail.us-east-1.aliyuncs.com',
+ 'eu-central-1' => 'actiontrail.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'actiontrail.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'actiontrail.ap-south-1.aliyuncs.com',
+ 'cn-chengdu' => 'actiontrail.cn-chengdu.aliyuncs.com',
+ ],
+ 'codepipeline' =>
+ [
+ 'cn-beijing' => 'cds.cn-beijing.aliyuncs.com',
+ ],
+ 'hcs_sgw' =>
+ [
+ 'cn-beijing' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'cn-zhangjiakou' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'cn-shanghai' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'cn-hongkong' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'ap-southeast-1' => 'sgw.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'sgw.ap-southeast-2.aliyuncs.com',
+ 'eu-central-1' => 'sgw.eu-central-1.aliyuncs.com',
+ 'cn-qingdao' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'sgw.cn-shanghai.aliyuncs.com',
+ 'cn-huhehaote' => 'sgw.cn-shanghai.aliyuncs.com',
+ ],
+ 'openanalytics' =>
+ [
+ 'cn-beijing' => 'openanalytics.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'openanalytics.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hangzhou' => 'openanalytics.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'openanalytics.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'openanalytics.cn-shenzhen.aliyuncs.com',
+ 'ap-southeast-1' => 'openanalytics.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-3' => 'openanalytics.ap-southeast-3.aliyuncs.com',
+ 'eu-west-1' => 'openanalytics.eu-west-1.aliyuncs.com',
+ 'cn-hongkong' => 'openanalytics.cn-hongkong.aliyuncs.com',
+ 'us-west-1' => 'openanalytics.us-west-1.aliyuncs.com',
+ ],
+ 'clouddesktop' =>
+ [
+ 'cn-beijing' => 'clouddesktop.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'clouddesktop.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'clouddesktop.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'clouddesktop.cn-shenzhen.aliyuncs.com',
+ ],
+ 'ivision' =>
+ [
+ 'cn-beijing' => 'ivision.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'ivision.cn-hangzhou.aliyuncs.com',
+ ],
+ 'fc' =>
+ [
+ 'cn-beijing' => 'cn-beijing.fc.aliyuncs.com',
+ 'cn-hangzhou' => 'cn-hangzhou.fc.aliyuncs.com',
+ 'cn-shanghai' => 'cn-shanghai.fc.aliyuncs.com',
+ 'cn-shenzhen' => 'cn-shenzhen.fc.aliyuncs.com',
+ 'ap-southeast-2' => 'ap-southeast-2.fc.aliyuncs.com',
+ 'cn-huhehaote' => 'cn-huhehaote.fc.aliyuncs.com',
+ ],
+ 'hsm' =>
+ [
+ 'cn-beijing' => 'hsm.aliyuncs.com',
+ 'cn-hangzhou' => 'hsm.aliyuncs.com',
+ 'cn-shanghai' => 'hsm.aliyuncs.com',
+ 'cn-shenzhen' => 'hsm.aliyuncs.com',
+ 'cn-hongkong' => 'hsm.aliyuncs.com',
+ 'ap-southeast-1' => 'hsm.aliyuncs.com',
+ ],
+ 'petadata' =>
+ [
+ 'cn-beijing' => 'petadata.aliyuncs.com',
+ 'cn-zhangjiakou' => 'petadata.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'petadata.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'petadata.aliyuncs.com',
+ 'cn-shanghai' => 'petadata.aliyuncs.com',
+ 'cn-shenzhen' => 'petadata.aliyuncs.com',
+ 'ap-southeast-1' => 'petadata.aliyuncs.com',
+ 'ap-southeast-2' => 'petadata.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-5' => 'petadata.ap-southeast-5.aliyuncs.com',
+ 'us-west-1' => 'petadata.aliyuncs.com',
+ 'us-east-1' => 'petadata.aliyuncs.com',
+ 'eu-central-1' => 'petadata.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'petadata.me-east-1.aliyuncs.com',
+ 'cn-hongkong' => 'petadata.aliyuncs.com',
+ 'cn-qingdao' => 'petadata.aliyuncs.com',
+ ],
+ 'gpdb' =>
+ [
+ 'cn-beijing' => 'gpdb.aliyuncs.com',
+ 'cn-zhangjiakou' => 'gpdb.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'gpdb.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'gpdb.aliyuncs.com',
+ 'cn-shanghai' => 'gpdb.aliyuncs.com',
+ 'cn-shenzhen' => 'gpdb.aliyuncs.com',
+ 'ap-southeast-1' => 'gpdb.aliyuncs.com',
+ 'ap-southeast-2' => 'gpdb.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'gpdb.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'gpdb.ap-southeast-5.aliyuncs.com',
+ 'eu-west-1' => 'gpdb.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'gpdb.aliyuncs.com',
+ 'us-east-1' => 'gpdb.aliyuncs.com',
+ 'eu-central-1' => 'gpdb.eu-central-1.aliyuncs.com',
+ 'ap-south-1' => 'gpdb.ap-south-1.aliyuncs.com',
+ 'ap-northeast-1' => 'gpdb.ap-northeast-1.aliyuncs.com',
+ 'cn-hongkong' => 'gpdb.aliyuncs.com',
+ 'cn-chengdu' => 'gpdb.cn-chengdu.aliyuncs.com',
+ ],
+ 'eci' =>
+ [
+ 'cn-beijing' => 'eci.aliyuncs.com',
+ 'cn-hangzhou' => 'eci.aliyuncs.com',
+ 'cn-shanghai' => 'eci.aliyuncs.com',
+ 'cn-shenzhen' => 'eci.aliyuncs.com',
+ 'ap-southeast-1' => 'eci.aliyuncs.com',
+ 'us-west-1' => 'eci.aliyuncs.com',
+ 'cn-hongkong' => 'eci.aliyuncs.com',
+ 'cn-zhangjiakou' => 'eci.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'eci.cn-huhehaote.aliyuncs.com',
+ 'ap-southeast-2' => 'eci.ap-southeast-2.aliyuncs.com',
+ 'eu-west-1' => 'eci.eu-west-1.aliyuncs.com',
+ 'us-east-1' => 'eci.aliyuncs.com',
+ 'eu-central-1' => 'eci.eu-central-1.aliyuncs.com',
+ 'cn-chengdu' => 'eci.cn-chengdu.aliyuncs.com',
+ ],
+ 'airec' =>
+ [
+ 'cn-beijing' => 'airec.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'airec.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'airec.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'airec.cn-shenzhen.aliyuncs.com',
+ ],
+ 'imm' =>
+ [
+ 'cn-beijing' => 'imm.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'imm.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hangzhou' => 'imm.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'imm.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'imm.cn-shenzhen.aliyuncs.com',
+ 'ap-southeast-1' => 'imm.ap-southeast-1.aliyuncs.com',
+ ],
+ 'gameshield' =>
+ [
+ 'cn-zhangjiakou' => 'gameshield.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hangzhou' => 'gameshield.aliyuncs.com',
+ ],
+ 'ims' =>
+ [
+ 'cn-hangzhou' => 'ims.aliyuncs.com',
+ ],
+ 'cloudfirewall' =>
+ [
+ 'cn-hangzhou' => 'cloudfw.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'cloudfw.ap-southeast-1.aliyuncs.com',
+ ],
+ 'ens' =>
+ [
+ 'cn-hangzhou' => 'ens.aliyuncs.com',
+ ],
+ 'hitsdb' =>
+ [
+ 'cn-hangzhou' => 'hitsdb.aliyuncs.com',
+ ],
+ 'ddos' =>
+ [
+ 'cn-hangzhou' => 'ddospro.cn-hangzhou.aliyuncs.com',
+ 'cn-hongkong' => 'ddospro.cn-hongkong.aliyuncs.com',
+ ],
+ 'rtc' =>
+ [
+ 'cn-hangzhou' => 'rtc.aliyuncs.com',
+ ],
+ 'emas' =>
+ [
+ 'cn-hangzhou' => 'mhub.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'mhub.cn-shanghai.aliyuncs.com',
+ ],
+ 'vipaegis' =>
+ [
+ 'cn-hangzhou' => 'aegis.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-3' => 'aegis.ap-southeast-3.aliyuncs.com',
+ ],
+ 'ddosrewards' =>
+ [
+ 'cn-hangzhou' => 'ddosright.cn-hangzhou.aliyuncs.com',
+ ],
+ 'cloudap' =>
+ [
+ 'cn-hangzhou' => 'cloudwf.aliyuncs.com',
+ ],
+ 'ensdisk' =>
+ [
+ 'cn-hangzhou' => 'ens.aliyuncs.com',
+ ],
+ 'bastionhost' =>
+ [
+ 'cn-hangzhou' => 'yundun-bastionhost.aliyuncs.com',
+ ],
+ 'pvtz' =>
+ [
+ 'cn-hangzhou' => 'pvtz.aliyuncs.com',
+ ],
+ 'ccs' =>
+ [
+ 'cn-hangzhou' => 'ccs.aliyuncs.com',
+ ],
+ 'yunmarket' =>
+ [
+ 'cn-hangzhou' => 'market.aliyuncs.com',
+ ],
+ 'cas' =>
+ [
+ 'cn-hangzhou' => 'cas.aliyuncs.com',
+ 'ap-southeast-2' => 'cas.ap-southeast-2.aliyuncs.com',
+ 'ap-northeast-1' => 'cas.ap-northeast-1.aliyuncs.com',
+ 'eu-central-1' => 'cas.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'cas.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'cas.ap-south-1.aliyuncs.com',
+ ],
+ 'ddoscoo' =>
+ [
+ 'cn-hangzhou' => 'ddoscoo.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'ddoscoo.ap-southeast-1.aliyuncs.com',
+ ],
+ 'waf' =>
+ [
+ 'cn-hangzhou' => 'wafopenapi.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com',
+ ],
+ 'xianzhi' =>
+ [
+ 'cn-hangzhou' => 'xianzhi.aliyuncs.com',
+ ],
+ 'sas' =>
+ [
+ 'cn-hangzhou' => 'sas.aliyuncs.com',
+ ],
+ 'cloudauth' =>
+ [
+ 'cn-hangzhou' => 'cloudauth.aliyuncs.com',
+ ],
+ 'dmsenterprise' =>
+ [
+ 'cn-hangzhou' => 'dms-enterprise.aliyuncs.com',
+ 'cn-shanghai' => 'dms-enterprise.aliyuncs.com',
+ 'cn-shenzhen' => 'dms-enterprise.aliyuncs.com',
+ 'cn-beijing' => 'dms-enterprise.aliyuncs.com',
+ 'cn-qingdao' => 'dms-enterprise.aliyuncs.com',
+ 'ap-northeast-1' => 'dms-enterprise.aliyuncs.com',
+ ],
+ 'baas' =>
+ [
+ 'cn-hangzhou' => 'baas.cn-hangzhou.aliyuncs.com',
+ 'ap-southeast-1' => 'baas.ap-southeast-1.aliyuncs.com',
+ 'ap-northeast-1' => 'baas.ap-northeast-1.aliyuncs.com',
+ 'cn-beijing' => 'baas.aliyuncs.com',
+ 'cn-shanghai' => 'baas.aliyuncs.com',
+ 'cn-shenzhen' => 'baas.aliyuncs.com',
+ 'cn-hongkong' => 'baas.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-2' => 'baas.ap-southeast-2.aliyuncs.com',
+ 'us-east-1' => 'baas.us-east-1.aliyuncs.com',
+ 'eu-central-1' => 'baas.aliyuncs.com',
+ 'cn-qingdao' => 'baas.aliyuncs.com',
+ 'cn-zhangjiakou' => 'baas.aliyuncs.com',
+ 'cn-huhehaote' => 'baas.aliyuncs.com',
+ 'eu-west-1' => 'baas.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'baas.aliyuncs.com',
+ 'ap-south-1' => 'baas.aliyuncs.com',
+ ],
+ 'alimt' =>
+ [
+ 'cn-hangzhou' => 'mt.cn-hangzhou.aliyuncs.com',
+ ],
+ 'dcdn' =>
+ [
+ 'cn-hangzhou' => 'dcdn.aliyuncs.com',
+ ],
+ 'hcs_mgw' =>
+ [
+ 'cn-hangzhou' => 'mgw.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'mgw.cn-shanghai.aliyuncs.com',
+ 'ap-southeast-1' => 'mgw.ap-southeast-1.aliyuncs.com',
+ ],
+ 'linkedmall' =>
+ [
+ 'cn-hangzhou' => 'linkedmall.aliyuncs.com',
+ 'cn-shanghai' => 'linkedmall.aliyuncs.com',
+ ],
+ 'cps' =>
+ [
+ 'cn-hangzhou' => 'cloudpush.aliyuncs.com',
+ ],
+ 'scdn' =>
+ [
+ 'cn-hangzhou' => 'scdn.aliyuncs.com',
+ ],
+ 'trademark' =>
+ [
+ 'cn-hangzhou' => 'trademark.aliyuncs.com',
+ ],
+ 'elasticsearch' =>
+ [
+ 'cn-hangzhou' => 'elasticsearch.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'elasticsearch.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'elasticsearch.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'elasticsearch.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'elasticsearch.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'elasticsearch.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'elasticsearch.ap-southeast-3.aliyuncs.com',
+ 'ap-northeast-1' => 'elasticsearch.ap-northeast-1.aliyuncs.com',
+ 'us-west-1' => 'elasticsearch.us-west-1.aliyuncs.com',
+ 'eu-central-1' => 'elasticsearch.eu-central-1.aliyuncs.com',
+ 'ap-south-1' => 'elasticsearch.ap-south-1.aliyuncs.com',
+ 'cn-qingdao' => 'elasticsearch.cn-qingdao.aliyuncs.com',
+ 'ap-southeast-5' => 'elasticsearch.ap-southeast-5.aliyuncs.com',
+ 'cn-beijing' => 'elasticsearch.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'elasticsearch.cn-zhangjiakou.aliyuncs.com',
+ ],
+ 'luban' =>
+ [
+ 'cn-hangzhou' => 'luban.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'luban.cn-shanghai.aliyuncs.com',
+ ],
+ 'pcdn' =>
+ [
+ 'cn-hangzhou' => 'pcdn.aliyuncs.com',
+ ],
+ 'uis' =>
+ [
+ 'cn-hangzhou' => 'uis.cn-hangzhou.aliyuncs.com',
+ ],
+ 'beebot' =>
+ [
+ 'cn-hangzhou' => 'chatbot.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'chatbot.cn-shanghai.aliyuncs.com',
+ ],
+ 'chatbot' =>
+ [
+ 'global' => 'chatbot.cn-shanghai.aliyuncs.com',
+ 'cn-shanghai' => 'chatbot.cn-shanghai.aliyuncs.com',
+ ],
+ 'alidnsgtm' =>
+ [
+ 'cn-hangzhou' => 'alidns.aliyuncs.com',
+ ],
+ 'sca' =>
+ [
+ 'cn-hangzhou' => 'qualitycheck.cn-hangzhou.aliyuncs.com',
+ ],
+ 'cccvn' =>
+ [
+ 'cn-shanghai' => 'voicenavigator.cn-shanghai.aliyuncs.com',
+ ],
+ 'cloudphoto' =>
+ [
+ 'cn-shanghai' => 'cloudphoto.cn-shanghai.aliyuncs.com',
+ ],
+ 'smartag' =>
+ [
+ 'cn-shanghai' => 'smartag.cn-shanghai.aliyuncs.com',
+ 'cn-hongkong' => 'smartag.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'smartag.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'smartag.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'smartag.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'smartag.ap-southeast-5.aliyuncs.com',
+ 'eu-central-1' => 'smartag.eu-central-1.aliyuncs.com',
+ ],
+ 'nlp' =>
+ [
+ 'cn-shanghai' => 'nlp.cn-shanghai.aliyuncs.com',
+ ],
+ 'nls-cloud-meta' =>
+ [
+ 'cn-shanghai' => 'nls-meta.cn-shanghai.aliyuncs.com',
+ ],
+ 'nls-filetrans' =>
+ [
+ 'cn-shanghai' => 'filetrans.cn-shanghai.aliyuncs.com',
+ ],
+ 'linkwan' =>
+ [
+ 'cn-shanghai' => 'linkwan.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'linkwan.cn-hangzhou.aliyuncs.com',
+ ],
+ 'hdm' =>
+ [
+ 'cn-shanghai' => 'hdm-api.aliyuncs.com',
+ ],
+ 'iovcc' =>
+ [
+ 'cn-shanghai' => 'iovcc.cn-shanghai.aliyuncs.com',
+ ],
+ 'ddosdip' =>
+ [
+ 'ap-southeast-1' => 'ddosdip.ap-southeast-1.aliyuncs.com',
+ ],
+ 'imagesearch' =>
+ [
+ 'ap-southeast-1' => 'imagesearch.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'imagesearch.ap-southeast-2.aliyuncs.com',
+ 'ap-northeast-1' => 'imagesearch.ap-northeast-1.aliyuncs.com',
+ 'cn-shanghai' => 'imagesearch.cn-shanghai.aliyuncs.com',
+ ],
+ 'alidfs' =>
+ [
+ 'cn-beijing' => 'dfs.cn-beijing.aliyuncs.com',
+ 'cn-shanghai' => 'dfs.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'dfs.cn-hangzhou.aliyuncs.com',
+ ],
+ 'vs' =>
+ [
+ 'cn-hangzhou' => 'vs.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'vs.cn-shanghai.aliyuncs.com',
+ 'cn-qingdao' => 'vs.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'vs.cn-beijing.aliyuncs.com',
+ 'cn-shenzhen' => 'vs.cn-shenzhen.aliyuncs.com',
+ ],
+ 'foas' =>
+ [
+ 'cn-qingdao' => 'foas.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'foas.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'foas.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hangzhou' => 'foas.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'foas.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'foas.cn-shenzhen.aliyuncs.com',
+ 'ap-northeast-1' => 'foas.ap-northeast-1.aliyuncs.com',
+ 'ap-southeast-1' => 'foas.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-3' => 'foas.ap-southeast-3.aliyuncs.com',
+ ],
+ 'iotid' =>
+ [
+ 'cn-hangzhou' => 'iotid.cn-hangzhou.aliyuncs.com',
+ ],
+ 'drdspost' =>
+ [
+ 'ap-southeast-1' => 'drds.ap-southeast-1.aliyuncs.com',
+ 'cn-shanghai' => 'drds.cn-shanghai.aliyuncs.com',
+ 'cn-hongkong' => 'drds.cn-hangzhou.aliyuncs.com',
+ 'cn-huhehaote' => 'drds.cn-huhehaote.aliyuncs.com',
+ ],
+ 'drdspre' =>
+ [
+ 'cn-qingdao' => 'drds.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'drds.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'drds.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'drds.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'drds.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'drds.cn-hangzhou.aliyuncs.com',
+ 'cn-huhehaote' => 'drds.cn-huhehaote.aliyuncs.com',
+ ],
+ 'acr' =>
+ [
+ 'cn-qingdao' => 'cr.cn-qingdao.aliyuncs.com',
+ 'cn-beijing' => 'cr.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'cr.cn-zhangjiakou.aliyuncs.com',
+ 'cn-huhehaote' => 'cr.cn-huhehaote.aliyuncs.com',
+ 'cn-hangzhou' => 'cr.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'cr.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'cr.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'cr.cn-hongkong.aliyuncs.com',
+ 'ap-southeast-1' => 'cr.ap-southeast-1.aliyuncs.com',
+ 'ap-southeast-2' => 'cr.ap-southeast-2.aliyuncs.com',
+ 'ap-southeast-3' => 'cr.ap-southeast-3.aliyuncs.com',
+ 'ap-southeast-5' => 'cr.ap-southeast-5.aliyuncs.com',
+ 'ap-northeast-1' => 'cr.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'cr.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'cr.us-west-1.aliyuncs.com',
+ 'us-east-1' => 'cr.us-east-1.aliyuncs.com',
+ 'eu-central-1' => 'cr.eu-central-1.aliyuncs.com',
+ 'me-east-1' => 'cr.me-east-1.aliyuncs.com',
+ 'ap-south-1' => 'cr.ap-south-1.aliyuncs.com',
+ ],
+ 'faas' =>
+ [
+ 'cn-beijing' => 'faas.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'faas.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hangzhou' => 'faas.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'faas.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'faas.cn-shenzhen.aliyuncs.com',
+ ],
+ 'idaas' =>
+ [
+ 'cn-hangzhou' => 'idaas.aliyuncs.com',
+ ],
+ 'privatelink' =>
+ [
+ 'cn-hangzhou' => 'privatelink.cn-hangzhou.aliyuncs.com',
+ 'cn-huhehaote' => 'privatelink.cn-huhehaote.aliyuncs.com',
+ 'eu-west-1' => 'privatelink.eu-west-1.aliyuncs.com',
+ ],
+ 'batchcomputenew' =>
+ [
+ 'cn-hongkong' => 'batchcompute.cn-hongkong.aliyuncs.com',
+ ],
+ 'vcs' =>
+ [
+ 'cn-hangzhou' => 'vcs.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'vcs.cn-shanghai.aliyuncs.com',
+ ],
+ 'vds' =>
+ [
+ 'cn-hangzhou' => 'vds.aliyuncs.com',
+ 'cn-shanghai' => 'vds.cn-shanghai.aliyuncs.com',
+ ],
+ 'vcsbasic' =>
+ [
+ 'cn-hangzhou' => 'vcsbasic.aliyuncs.com',
+ 'cn-shanghai' => 'vcs.cn-shanghai.aliyuncs.com',
+ ],
+ 'hbr' =>
+ [
+ 'cn-qingdao' => 'hbr.cn-shanghai.aliyuncs.com',
+ 'cn-beijing' => 'hbr.cn-beijing.aliyuncs.com',
+ 'cn-zhangjiakou' => 'hbr.cn-shanghai.aliyuncs.com',
+ 'cn-huhehaote' => 'hbr.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'hbr.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'hbr.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'hbr.cn-shenzhen.aliyuncs.com',
+ 'ap-southeast-1' => 'hbr.ap-southeast-1.aliyuncs.com',
+ ],
+ 'image' =>
+ [
+ 'cn-shanghai' => 'image.cn-shanghai.aliyuncs.com',
+ ],
+ 'webx' =>
+ [
+ 'cn-shenzhen' => 'webplus.cn-hangzhou.aliyuncs.com',
+ 'cn-beijing' => 'webplus.cn-hangzhou.aliyuncs.com',
+ 'cn-zhangjiakou' => 'webplus.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'webplus.cn-hangzhou.aliyuncs.com',
+ 'cn-hangzhou' => 'webplus.cn-hangzhou.aliyuncs.com',
+ ],
+ 'sddp' =>
+ [
+ 'cn-zhangjiakou' => 'sddp.cn-zhangjiakou.aliyuncs.com',
+ ],
+ 'oos' =>
+ [
+ 'cn-hangzhou' => 'oos.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'oos.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'oos.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'oos.cn-hongkong.aliyuncs.com',
+ 'us-east-1' => 'oos.us-east-1.aliyuncs.com',
+ ],
+ 'fnf' =>
+ [
+ 'cn-hangzhou' => 'cn-hangzhou.fnf.aliyuncs.com',
+ 'cn-shanghai' => 'cn-shanghai.gamma.test.fnf.aliyun-inc.com',
+ 'cn-shenzhen' => 'cn-shenzhen.fnf.aliyuncs.com',
+ ],
+ 'smc' =>
+ [
+ 'cn-huhehaote' => 'smc.aliyuncs.com',
+ 'cn-hangzhou' => 'smc.aliyuncs.com',
+ 'cn-qingdao' => 'smc.aliyuncs.com',
+ 'cn-beijing' => 'smc.aliyuncs.com',
+ 'cn-zhangjiakou' => 'smc.aliyuncs.com',
+ 'cn-shanghai' => 'smc.aliyuncs.com',
+ 'cn-shenzhen' => 'smc.aliyuncs.com',
+ 'cn-hongkong' => 'smc.aliyuncs.com',
+ 'ap-southeast-1' => 'smc.aliyuncs.com',
+ 'ap-southeast-2' => 'smc.aliyuncs.com',
+ 'ap-southeast-3' => 'smc.aliyuncs.com',
+ 'ap-southeast-5' => 'smc.aliyuncs.com',
+ 'ap-northeast-1' => 'smc.aliyuncs.com',
+ 'eu-west-1' => 'smc.aliyuncs.com',
+ 'us-west-1' => 'smc.aliyuncs.com',
+ 'us-east-1' => 'smc.aliyuncs.com',
+ 'eu-central-1' => 'smc.aliyuncs.com',
+ 'me-east-1' => 'smc.aliyuncs.com',
+ 'ap-south-1' => 'smc.aliyuncs.com',
+ 'cn-chengdu' => 'smc.aliyuncs.com',
+ ],
+ 'foasconsole' =>
+ [
+ 'cn-beijing' => 'foasconsole.aliyuncs.com',
+ 'cn-zhangjiakou' => 'foasconsole.aliyuncs.com',
+ 'cn-hangzhou' => 'foasconsole.aliyuncs.com',
+ 'cn-shanghai' => 'foasconsole.aliyuncs.com',
+ 'cn-shenzhen' => 'foasconsole.aliyuncs.com',
+ 'cn-hongkong' => 'foasconsole.aliyuncs.com',
+ 'ap-southeast-1' => 'foasconsole.aliyuncs.com',
+ 'ap-southeast-3' => 'foasconsole.aliyuncs.com',
+ 'ap-northeast-1' => 'foasconsole.aliyuncs.com',
+ ],
+ 'serverless' =>
+ [
+ 'cn-beijing' => 'sae.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'sae.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'sae.cn-shanghai.aliyuncs.com',
+ ],
+ 'ivpd' =>
+ [
+ 'cn-huhehaote' => 'ivpd.cn-huhehaote.aliyuncs.com',
+ 'cn-shanghai' => 'ivpd.cn-shanghai.aliyuncs.com',
+ 'cn-hangzhou' => 'ivpd.cn-hangzhou.aliyuncs.com',
+ ],
+ 'hivisengine' =>
+ [
+ 'cn-huhehaote' => 'hivisengine.aliyuncs.com',
+ 'cn-shanghai' => 'hivisengine.cn-shanghai.aliyuncs.com',
+ ],
+ 'hiknoengine' =>
+ [
+ 'cn-huhehaote' => 'hiknoengine.aliyuncs.com',
+ 'cn-shanghai' => 'hiknoengine.cn-shanghai.aliyuncs.com',
+ ],
+ 'clouddev' =>
+ [
+ 'cn-hangzhou' => 'mpserverless.aliyuncs.com',
+ 'cn-shanghai' => 'mpserverless.aliyuncs.com',
+ ],
+ 'premiumpics' =>
+ [
+ 'cn-hangzhou' => 'premiumpics.aliyuncs.com',
+ ],
+ 'composer' =>
+ [
+ 'cn-hangzhou' => 'composer.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'composer.cn-shanghai.aliyuncs.com',
+ ],
+ 'cloudesl' =>
+ [
+ 'cn-hangzhou' => 'cloudesl.cn-hangzhou.aliyuncs.com',
+ ],
+ 'amscloudapp' =>
+ [
+ 'cn-hangzhou' => 'mpca.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'mpca.cn-shanghai.aliyuncs.com',
+ ],
+ 'mse' =>
+ [
+ 'cn-hangzhou' => 'mse.cn-hangzhou.aliyuncs.com',
+ ],
+ 'dg' =>
+ [
+ 'cn-hangzhou' => 'dg.cn-hangzhou.aliyuncs.com',
+ ],
+ 'graphcompute' =>
+ [
+ 'cn-shanghai' => 'gcs.cn-shanghai.aliyuncs.com',
+ ],
+ 'cds' =>
+ [
+ 'ap-southeast-1' => 'cassandra.aliyuncs.com',
+ 'cn-qingdao' => 'cassandra.aliyuncs.com',
+ 'cn-beijing' => 'cassandra.aliyuncs.com',
+ 'cn-hangzhou' => 'cassandra.aliyuncs.com',
+ 'cn-shanghai' => 'cassandra.aliyuncs.com',
+ 'cn-shenzhen' => 'cassandra.aliyuncs.com',
+ ],
+ 'ads' =>
+ [
+ 'cn-qingdao' => 'adb.aliyuncs.com',
+ 'cn-beijing' => 'adb.aliyuncs.com',
+ 'cn-zhangjiakou' => 'adb.cn-zhangjiakou.aliyuncs.com',
+ 'cn-hangzhou' => 'adb.aliyuncs.com',
+ 'cn-shanghai' => 'adb.aliyuncs.com',
+ 'cn-shenzhen' => 'adb.aliyuncs.com',
+ 'cn-hongkong' => 'adb.aliyuncs.com',
+ 'ap-southeast-1' => 'adb.aliyuncs.com',
+ 'ap-northeast-1' => 'adb.ap-northeast-1.aliyuncs.com',
+ 'eu-west-1' => 'adb.eu-west-1.aliyuncs.com',
+ 'us-west-1' => 'adb.aliyuncs.com',
+ 'us-east-1' => 'adb.aliyuncs.com',
+ ],
+ 'csb' =>
+ [
+ 'cn-beijing' => 'csb.cn-beijing.aliyuncs.com',
+ 'cn-hangzhou' => 'csb.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'csb.cn-shanghai.aliyuncs.com',
+ 'cn-shenzhen' => 'csb.cn-shenzhen.aliyuncs.com',
+ 'cn-hongkong' => 'csb.cn-hongkong.aliyuncs.com',
+ ],
+ 'cityvisual' =>
+ [
+ 'cn-hangzhou' => 'cityvisual.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'cityvisual.cn-shanghai.aliyuncs.com',
+ ],
+ 'dbaudit' =>
+ [
+ 'cn-hangzhou' => 'yundun-dbaudit.aliyuncs.com',
+ ],
+ 'bssopenapi' =>
+ [
+ 'cn-hangzhou' => 'business.aliyuncs.com',
+ 'cn-shanghai' => 'business.aliyuncs.com',
+ 'ap-southeast-1' => 'business.ap-southeast-1.aliyuncs.com',
+ ],
+ 'indvi' =>
+ [
+ 'cn-hangzhou' => 'indvi.cn-hangzhou.aliyuncs.com',
+ ],
+ 'swcopyright' =>
+ [
+ 'cn-hangzhou' => 'copyright.aliyuncs.com',
+ ],
+ 'multimediaai' =>
+ [
+ 'cn-beijing' => 'multimediaai.cn-beijing.aliyuncs.com',
+ ],
+ 'rsimganalys' =>
+ [
+ 'cn-hangzhou' => 'rsimganalys.cn-hangzhou.aliyuncs.com',
+ 'cn-shanghai' => 'rsimganalys.cn-hangzhou.aliyuncs.com',
+ ],
+ 'tdsr' =>
+ [
+ 'cn-hangzhou' => 'lyj.cn-hangzhou.aliyuncs.com',
+ ],
+ ],
+];
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/AccessKeyCredential.php b/app/Common/extend/alibabacloud/client/src/Credentials/AccessKeyCredential.php
new file mode 100755
index 0000000..bacaecc
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/AccessKeyCredential.php
@@ -0,0 +1,65 @@
+accessKeyId = $accessKeyId;
+ $this->accessKeySecret = $accessKeySecret;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeyId()
+ {
+ return $this->accessKeyId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeySecret()
+ {
+ return $this->accessKeySecret;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return "$this->accessKeyId#$this->accessKeySecret";
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/BearerTokenCredential.php b/app/Common/extend/alibabacloud/client/src/Credentials/BearerTokenCredential.php
new file mode 100755
index 0000000..db69a7c
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/BearerTokenCredential.php
@@ -0,0 +1,66 @@
+bearerToken = $bearerToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBearerToken()
+ {
+ return $this->bearerToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeyId()
+ {
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeySecret()
+ {
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return "bearerToken#$this->bearerToken";
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/CredentialsInterface.php b/app/Common/extend/alibabacloud/client/src/Credentials/CredentialsInterface.php
new file mode 100755
index 0000000..96ee50a
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/CredentialsInterface.php
@@ -0,0 +1,18 @@
+roleName = $roleName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRoleName()
+ {
+ return $this->roleName;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return "roleName#$this->roleName";
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Ini/CreateTrait.php b/app/Common/extend/alibabacloud/client/src/Credentials/Ini/CreateTrait.php
new file mode 100755
index 0000000..2ec7511
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Ini/CreateTrait.php
@@ -0,0 +1,181 @@
+missingRequired('type', $clientName);
+ }
+
+ return $this->createClientByType($clientName, $credential)->name($clientName);
+ }
+
+ /**
+ * @param string $clientName
+ * @param array $credential
+ *
+ * @return AccessKeyClient|BearerTokenClient|EcsRamRoleClient|RamRoleArnClient|RsaKeyPairClient
+ * @throws ClientException
+ */
+ private function createClientByType($clientName, array $credential)
+ {
+ switch (\strtolower($credential['type'])) {
+ case 'access_key':
+ return $this->accessKeyClient($clientName, $credential);
+ case 'ecs_ram_role':
+ return $this->ecsRamRoleClient($clientName, $credential);
+ case 'ram_role_arn':
+ return $this->ramRoleArnClient($clientName, $credential);
+ case 'bearer_token':
+ return $this->bearerTokenClient($clientName, $credential);
+ case 'rsa_key_pair':
+ return $this->rsaKeyPairClient($clientName, $credential);
+ default:
+ throw new ClientException(
+ "Invalid type '{$credential['type']}' for '$clientName' in {$this->filename}",
+ SDK::INVALID_CREDENTIAL
+ );
+ }
+ }
+
+ /**
+ * @param array $credential
+ * @param string $clientName
+ *
+ * @return AccessKeyClient
+ * @throws ClientException
+ */
+ private function accessKeyClient($clientName, array $credential)
+ {
+ if (!isset($credential['access_key_id'])) {
+ $this->missingRequired('access_key_id', $clientName);
+ }
+
+ if (!isset($credential['access_key_secret'])) {
+ $this->missingRequired('access_key_secret', $clientName);
+ }
+
+ return new AccessKeyClient(
+ $credential['access_key_id'],
+ $credential['access_key_secret']
+ );
+ }
+
+ /**
+ * @param string $clientName
+ * @param array $credential
+ *
+ * @return EcsRamRoleClient
+ * @throws ClientException
+ */
+ private function ecsRamRoleClient($clientName, array $credential)
+ {
+ if (!isset($credential['role_name'])) {
+ $this->missingRequired('role_name', $clientName);
+ }
+
+ return new EcsRamRoleClient($credential['role_name']);
+ }
+
+ /**
+ * @param string $clientName
+ * @param array $credential
+ *
+ * @return RamRoleArnClient
+ * @throws ClientException
+ */
+ private function ramRoleArnClient($clientName, array $credential)
+ {
+ if (!isset($credential['access_key_id'])) {
+ $this->missingRequired('access_key_id', $clientName);
+ }
+
+ if (!isset($credential['access_key_secret'])) {
+ $this->missingRequired('access_key_secret', $clientName);
+ }
+
+ if (!isset($credential['role_arn'])) {
+ $this->missingRequired('role_arn', $clientName);
+ }
+
+ if (!isset($credential['role_session_name'])) {
+ $this->missingRequired('role_session_name', $clientName);
+ }
+
+ return new RamRoleArnClient(
+ $credential['access_key_id'],
+ $credential['access_key_secret'],
+ $credential['role_arn'],
+ $credential['role_session_name']
+ );
+ }
+
+ /**
+ * @param string $clientName
+ * @param array $credential
+ *
+ * @return BearerTokenClient
+ * @throws ClientException
+ */
+ private function bearerTokenClient($clientName, array $credential)
+ {
+ if (!isset($credential['bearer_token'])) {
+ $this->missingRequired('bearer_token', $clientName);
+ }
+
+ return new BearerTokenClient($credential['bearer_token']);
+ }
+
+ /**
+ * @param array $credential
+ * @param string $clientName
+ *
+ * @return RsaKeyPairClient
+ * @throws ClientException
+ */
+ private function rsaKeyPairClient($clientName, array $credential)
+ {
+ if (!isset($credential['public_key_id'])) {
+ $this->missingRequired('public_key_id', $clientName);
+ }
+
+ if (!isset($credential['private_key_file'])) {
+ $this->missingRequired('private_key_file', $clientName);
+ }
+
+ return new RsaKeyPairClient(
+ $credential['public_key_id'],
+ $credential['private_key_file']
+ );
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Ini/IniCredential.php b/app/Common/extend/alibabacloud/client/src/Credentials/Ini/IniCredential.php
new file mode 100755
index 0000000..94ec7fb
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Ini/IniCredential.php
@@ -0,0 +1,209 @@
+filename = $filename ?: $this->getDefaultFile();
+ }
+
+ /**
+ * Get the default credential file.
+ *
+ * @return string
+ */
+ public function getDefaultFile()
+ {
+ return self::getHomeDirectory() . DIRECTORY_SEPARATOR . '.alibabacloud' . DIRECTORY_SEPARATOR . 'credentials';
+ }
+
+ /**
+ * Gets the environment's HOME directory.
+ *
+ * @return null|string
+ */
+ private static function getHomeDirectory()
+ {
+ if (getenv('HOME')) {
+ return getenv('HOME');
+ }
+
+ return (getenv('HOMEDRIVE') && getenv('HOMEPATH'))
+ ? getenv('HOMEDRIVE') . getenv('HOMEPATH')
+ : null;
+ }
+
+ /**
+ * Clear credential cache.
+ *
+ * @return void
+ */
+ public static function forgetLoadedCredentialsFile()
+ {
+ self::$hasLoaded = [];
+ }
+
+ /**
+ * Get the credential file.
+ *
+ * @return string
+ */
+ public function getFilename()
+ {
+ return $this->filename;
+ }
+
+ /**
+ * @param array $array
+ * @param string $key
+ *
+ * @return bool
+ */
+ protected static function isNotEmpty(array $array, $key)
+ {
+ return isset($array[$key]) && !empty($array[$key]);
+ }
+
+ /**
+ * @param string $key
+ * @param string $clientName
+ *
+ * @throws ClientException
+ */
+ public function missingRequired($key, $clientName)
+ {
+ throw new ClientException(
+ "Missing required '$key' option for '$clientName' in " . $this->getFilename(),
+ SDK::INVALID_CREDENTIAL
+ );
+ }
+
+ /**
+ * @return array|mixed
+ * @throws ClientException
+ */
+ public function load()
+ {
+ // If it has been loaded, assign the client directly.
+ if (isset(self::$hasLoaded[$this->filename])) {
+ /**
+ * @var $client Client
+ */
+ foreach (self::$hasLoaded[$this->filename] as $projectName => $client) {
+ $client->name($projectName);
+ }
+
+ return self::$hasLoaded[$this->filename];
+ }
+
+ return $this->loadFile();
+ }
+
+ /**
+ * Exceptions will be thrown if the file is unreadable and not the default file.
+ *
+ * @return array|mixed
+ * @throws ClientException
+ */
+ private function loadFile()
+ {
+ if (!\AlibabaCloud\Client\inOpenBasedir($this->filename)) {
+ return [];
+ }
+
+ if (!\is_readable($this->filename) || !\is_file($this->filename)) {
+ if ($this->filename === $this->getDefaultFile()) {
+ // @codeCoverageIgnoreStart
+ return [];
+ // @codeCoverageIgnoreEnd
+ }
+ throw new ClientException(
+ 'Credential file is not readable: ' . $this->getFilename(),
+ SDK::INVALID_CREDENTIAL
+ );
+ }
+
+ return $this->parseFile();
+ }
+
+ /**
+ * Decode the ini file into an array.
+ *
+ * @return array|mixed
+ * @throws ClientException
+ */
+ private function parseFile()
+ {
+ try {
+ $file = \parse_ini_file($this->filename, true);
+ if (\is_array($file) && $file !== []) {
+ return $this->initClients($file);
+ }
+ throw new ClientException(
+ 'Format error: ' . $this->getFilename(),
+ SDK::INVALID_CREDENTIAL
+ );
+ } catch (\Exception $e) {
+ throw new ClientException(
+ $e->getMessage(),
+ SDK::INVALID_CREDENTIAL,
+ $e
+ );
+ }
+ }
+
+ /**
+ * Initialize clients.
+ *
+ * @param array $array
+ *
+ * @return array|mixed
+ * @throws ClientException
+ */
+ private function initClients($array)
+ {
+ foreach (\array_change_key_case($array) as $clientName => $configures) {
+ $configures = \array_change_key_case($configures);
+ $clientInstance = $this->createClient($clientName, $configures);
+ if ($clientInstance instanceof Client) {
+ self::$hasLoaded[$this->filename][$clientName] = $clientInstance;
+ self::setClientAttributes($configures, $clientInstance);
+ self::setCert($configures, $clientInstance);
+ self::setProxy($configures, $clientInstance);
+ }
+ }
+
+ return isset(self::$hasLoaded[$this->filename])
+ ? self::$hasLoaded[$this->filename]
+ : [];
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Ini/OptionsTrait.php b/app/Common/extend/alibabacloud/client/src/Credentials/Ini/OptionsTrait.php
new file mode 100755
index 0000000..192d494
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Ini/OptionsTrait.php
@@ -0,0 +1,111 @@
+regionId($configures['region_id']);
+ }
+
+ if (isset($configures['debug'])) {
+ $client->options(
+ [
+ 'debug' => (bool)$configures['debug'],
+ ]
+ );
+ }
+
+ if (self::isNotEmpty($configures, 'timeout')) {
+ $client->options(
+ [
+ 'timeout' => $configures['timeout'],
+ ]
+ );
+ }
+
+ if (self::isNotEmpty($configures, 'connect_timeout')) {
+ $client->options(
+ [
+ 'connect_timeout' => $configures['connect_timeout'],
+ ]
+ );
+ }
+ }
+
+ /**
+ * @param array $configures
+ * @param Client $client
+ */
+ private static function setProxy($configures, Client $client)
+ {
+ if (self::isNotEmpty($configures, 'proxy')) {
+ $client->options(
+ [
+ 'proxy' => $configures['proxy'],
+ ]
+ );
+ }
+ $proxy = [];
+ if (self::isNotEmpty($configures, 'proxy_http')) {
+ $proxy['http'] = $configures['proxy_http'];
+ }
+ if (self::isNotEmpty($configures, 'proxy_https')) {
+ $proxy['https'] = $configures['proxy_https'];
+ }
+ if (self::isNotEmpty($configures, 'proxy_no')) {
+ $proxy['no'] = \explode(',', $configures['proxy_no']);
+ }
+ if ($proxy !== []) {
+ $client->options(
+ [
+ 'proxy' => $proxy,
+ ]
+ );
+ }
+ }
+
+ /**
+ * @param array $configures
+ * @param Client $client
+ */
+ private static function setCert($configures, Client $client)
+ {
+ if (self::isNotEmpty($configures, 'cert_file') && !self::isNotEmpty($configures, 'cert_password')) {
+ $client->options(
+ [
+ 'cert' => $configures['cert_file'],
+ ]
+ );
+ }
+
+ if (self::isNotEmpty($configures, 'cert_file') && self::isNotEmpty($configures, 'cert_password')) {
+ $client->options(
+ [
+ 'cert' => [
+ $configures['cert_file'],
+ $configures['cert_password'],
+ ],
+ ]
+ );
+ }
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Providers/CredentialsProvider.php b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/CredentialsProvider.php
new file mode 100755
index 0000000..21aec9b
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/CredentialsProvider.php
@@ -0,0 +1,170 @@
+asDefaultClient();
+ }
+ };
+ }
+
+ /**
+ * @return Closure
+ */
+ public static function ini()
+ {
+ return static function () {
+ $ini = \AlibabaCloud\Client\envNotEmpty('ALIBABA_CLOUD_CREDENTIALS_FILE');
+
+ if ($ini) {
+ AlibabaCloud::load($ini);
+ } else {
+ // @codeCoverageIgnoreStart
+ AlibabaCloud::load();
+ // @codeCoverageIgnoreEnd
+ }
+
+ self::compatibleWithGlobal();
+ };
+ }
+
+ /**
+ * @codeCoverageIgnore
+ *
+ * Compatible with global
+ *
+ * @throws ClientException
+ */
+ private static function compatibleWithGlobal()
+ {
+ if (AlibabaCloud::has('global') && !AlibabaCloud::has(self::getDefaultName())) {
+ AlibabaCloud::get('global')->name(self::getDefaultName());
+ }
+ }
+
+ /**
+ * @return array|false|string
+ * @throws ClientException
+ */
+ public static function getDefaultName()
+ {
+ $name = \AlibabaCloud\Client\envNotEmpty('ALIBABA_CLOUD_PROFILE');
+
+ if ($name) {
+ return $name;
+ }
+
+ return 'default';
+ }
+
+ /**
+ * @return Closure
+ */
+ public static function instance()
+ {
+ return static function () {
+ $instance = \AlibabaCloud\Client\envNotEmpty('ALIBABA_CLOUD_ECS_METADATA');
+ if ($instance) {
+ AlibabaCloud::ecsRamRoleClient($instance)->asDefaultClient();
+ }
+ };
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php
new file mode 100755
index 0000000..26bb675
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php
@@ -0,0 +1,128 @@
+getCredentialsInCache();
+
+ if ($result === null) {
+ $result = $this->request();
+
+ if (!isset($result['AccessKeyId'], $result['AccessKeySecret'], $result['SecurityToken'])) {
+ throw new ServerException($result, $this->error, SDK::INVALID_CREDENTIAL);
+ }
+
+ $this->cache($result->toArray());
+ }
+
+ return new StsCredential(
+ $result['AccessKeyId'],
+ $result['AccessKeySecret'],
+ $result['SecurityToken']
+ );
+ }
+
+ /**
+ * Get credentials by request.
+ *
+ * @return Result
+ * @throws ClientException
+ * @throws ServerException
+ */
+ public function request()
+ {
+ $result = $this->getResponse();
+
+ if ($result->getStatusCode() === 404) {
+ $message = 'The role was not found in the instance';
+ throw new ClientException($message, SDK::INVALID_CREDENTIAL);
+ }
+
+ if (!$result->isSuccess()) {
+ $message = 'Error retrieving credentials from result';
+ throw new ServerException($result, $message, SDK::INVALID_CREDENTIAL);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get data from meta.
+ *
+ * @return mixed|ResponseInterface
+ * @throws ClientException
+ * @throws Exception
+ */
+ public function getResponse()
+ {
+ /**
+ * @var EcsRamRoleCredential $credential
+ */
+ $credential = $this->client->getCredential();
+ $url = $this->uri . $credential->getRoleName();
+
+ $options = [
+ 'http_errors' => false,
+ 'timeout' => 1,
+ 'connect_timeout' => 1,
+ 'debug' => $this->client->isDebug(),
+ ];
+
+ try {
+ return RpcRequest::createClient()->request('GET', $url, $options);
+ } catch (GuzzleException $exception) {
+ if (Stringy::create($exception->getMessage())->contains('timed')) {
+ $message = 'Timeout or instance does not belong to Alibaba Cloud';
+ } else {
+ $message = $exception->getMessage();
+ }
+
+ throw new ClientException(
+ $message,
+ SDK::SERVER_UNREACHABLE,
+ $exception
+ );
+ }
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Providers/Provider.php b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/Provider.php
new file mode 100755
index 0000000..b64dab8
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/Provider.php
@@ -0,0 +1,88 @@
+client = $client;
+ }
+
+ /**
+ * Get the credentials from the cache in the validity period.
+ *
+ * @return array|null
+ */
+ public function getCredentialsInCache()
+ {
+ if (isset(self::$credentialsCache[$this->key()])) {
+ $result = self::$credentialsCache[$this->key()];
+ if (\strtotime($result['Expiration']) - \time() >= $this->expirationSlot) {
+ return $result;
+ }
+ unset(self::$credentialsCache[$this->key()]);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the toString of the credentials as the key.
+ *
+ * @return string
+ */
+ protected function key()
+ {
+ return (string)$this->client->getCredential();
+ }
+
+ /**
+ * Cache credentials.
+ *
+ * @param array $credential
+ */
+ protected function cache(array $credential)
+ {
+ self::$credentialsCache[$this->key()] = $credential;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Providers/RamRoleArnProvider.php b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/RamRoleArnProvider.php
new file mode 100755
index 0000000..ce4de41
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/RamRoleArnProvider.php
@@ -0,0 +1,84 @@
+getCredentialsInCache();
+
+ if (null === $credential) {
+ $result = $this->request($timeout, $connectTimeout);
+
+ if (!isset($result['Credentials']['AccessKeyId'],
+ $result['Credentials']['AccessKeySecret'],
+ $result['Credentials']['SecurityToken'])) {
+ throw new ServerException($result, $this->error, SDK::INVALID_CREDENTIAL);
+ }
+
+ $credential = $result['Credentials'];
+ $this->cache($credential);
+ }
+
+ return new StsCredential(
+ $credential['AccessKeyId'],
+ $credential['AccessKeySecret'],
+ $credential['SecurityToken']
+ );
+ }
+
+ /**
+ * Get credentials by request.
+ *
+ * @param $timeout
+ * @param $connectTimeout
+ *
+ * @return Result
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function request($timeout, $connectTimeout)
+ {
+ $clientName = __CLASS__ . \uniqid('ak', true);
+ $credential = $this->client->getCredential();
+
+ AlibabaCloud::accessKeyClient(
+ $credential->getAccessKeyId(),
+ $credential->getAccessKeySecret()
+ )->name($clientName);
+
+ return (new AssumeRole($credential))
+ ->client($clientName)
+ ->timeout($timeout)
+ ->connectTimeout($connectTimeout)
+ ->debug($this->client->isDebug())
+ ->request();
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Providers/RsaKeyPairProvider.php b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/RsaKeyPairProvider.php
new file mode 100755
index 0000000..e78fc1c
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Providers/RsaKeyPairProvider.php
@@ -0,0 +1,86 @@
+getCredentialsInCache();
+
+ if ($credential === null) {
+ $result = $this->request($timeout, $connectTimeout);
+
+ if (!isset($result['SessionAccessKey']['SessionAccessKeyId'],
+ $result['SessionAccessKey']['SessionAccessKeySecret'])) {
+ throw new ServerException($result, $this->error, SDK::INVALID_CREDENTIAL);
+ }
+
+ $credential = $result['SessionAccessKey'];
+ $this->cache($credential);
+ }
+
+ return new StsCredential(
+ $credential['SessionAccessKeyId'],
+ $credential['SessionAccessKeySecret']
+ );
+ }
+
+ /**
+ * Get credentials by request.
+ *
+ * @param $timeout
+ * @param $connectTimeout
+ *
+ * @return Result
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function request($timeout, $connectTimeout)
+ {
+ $clientName = __CLASS__ . \uniqid('rsa', true);
+ $credential = $this->client->getCredential();
+
+ AlibabaCloud::client(
+ new AccessKeyCredential(
+ $credential->getPublicKeyId(),
+ $credential->getPrivateKey()
+ ),
+ new ShaHmac256WithRsaSignature()
+ )->name($clientName);
+
+ return (new GenerateSessionAccessKey($credential->getPublicKeyId()))
+ ->client($clientName)
+ ->timeout($timeout)
+ ->connectTimeout($connectTimeout)
+ ->debug($this->client->isDebug())
+ ->request();
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/RamRoleArnCredential.php b/app/Common/extend/alibabacloud/client/src/Credentials/RamRoleArnCredential.php
new file mode 100755
index 0000000..6bdf5be
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/RamRoleArnCredential.php
@@ -0,0 +1,110 @@
+accessKeyId = $accessKeyId;
+ $this->accessKeySecret = $accessKeySecret;
+ $this->roleArn = $roleArn;
+ $this->roleSessionName = $roleSessionName;
+ $this->policy = $policy;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeyId()
+ {
+ return $this->accessKeyId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeySecret()
+ {
+ return $this->accessKeySecret;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRoleArn()
+ {
+ return $this->roleArn;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRoleSessionName()
+ {
+ return $this->roleSessionName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPolicy()
+ {
+ return $this->policy;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return "$this->accessKeyId#$this->accessKeySecret#$this->roleArn#$this->roleSessionName";
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Requests/AssumeRole.php b/app/Common/extend/alibabacloud/client/src/Credentials/Requests/AssumeRole.php
new file mode 100755
index 0000000..a3935aa
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Requests/AssumeRole.php
@@ -0,0 +1,47 @@
+product('Sts');
+ $this->version('2015-04-01');
+ $this->action('AssumeRole');
+ $this->host('sts.aliyuncs.com');
+ $this->scheme('https');
+ $this->regionId('cn-hangzhou');
+ $this->options['verify'] = false;
+ $this->options['query']['RoleArn'] = $arnCredential->getRoleArn();
+ $this->options['query']['RoleSessionName'] = $arnCredential->getRoleSessionName();
+ $this->options['query']['DurationSeconds'] = Provider::DURATION_SECONDS;
+ if ($arnCredential->getPolicy()) {
+ if (is_array($arnCredential->getPolicy())) {
+ $this->options['query']['Policy'] = json_encode($arnCredential->getPolicy());
+ }
+ if (is_string($arnCredential->getPolicy())) {
+ $this->options['query']['Policy'] = $arnCredential->getPolicy();
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/Requests/GenerateSessionAccessKey.php b/app/Common/extend/alibabacloud/client/src/Credentials/Requests/GenerateSessionAccessKey.php
new file mode 100755
index 0000000..4ac1ee1
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/Requests/GenerateSessionAccessKey.php
@@ -0,0 +1,37 @@
+product('Sts');
+ $this->version('2015-04-01');
+ $this->action('GenerateSessionAccessKey');
+ $this->host('sts.ap-northeast-1.aliyuncs.com');
+ $this->scheme('https');
+ $this->regionId('cn-hangzhou');
+ $this->options['verify'] = false;
+ $this->options['query']['PublicKeyId'] = $publicKeyId;
+ $this->options['query']['DurationSeconds'] = Provider::DURATION_SECONDS;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/RsaKeyPairCredential.php b/app/Common/extend/alibabacloud/client/src/Credentials/RsaKeyPairCredential.php
new file mode 100755
index 0000000..876909e
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/RsaKeyPairCredential.php
@@ -0,0 +1,75 @@
+publicKeyId = $publicKeyId;
+ try {
+ $this->privateKey = file_get_contents($privateKeyFile);
+ } catch (Exception $exception) {
+ throw new ClientException(
+ $exception->getMessage(),
+ SDK::INVALID_CREDENTIAL
+ );
+ }
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getPrivateKey()
+ {
+ return $this->privateKey;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPublicKeyId()
+ {
+ return $this->publicKeyId;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return "publicKeyId#$this->publicKeyId";
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Credentials/StsCredential.php b/app/Common/extend/alibabacloud/client/src/Credentials/StsCredential.php
new file mode 100755
index 0000000..d333fa8
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Credentials/StsCredential.php
@@ -0,0 +1,80 @@
+accessKeyId = $accessKeyId;
+ $this->accessKeySecret = $accessKeySecret;
+ $this->securityToken = $securityToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeyId()
+ {
+ return $this->accessKeyId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getAccessKeySecret()
+ {
+ return $this->accessKeySecret;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSecurityToken()
+ {
+ return $this->securityToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return "$this->accessKeyId#$this->accessKeySecret#$this->securityToken";
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/DefaultAcsClient.php b/app/Common/extend/alibabacloud/client/src/DefaultAcsClient.php
new file mode 100755
index 0000000..ff5ecd7
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/DefaultAcsClient.php
@@ -0,0 +1,55 @@
+randClientName = \uniqid('', true);
+ $client->name($this->randClientName);
+ }
+
+ /**
+ * @param Request|Result $request
+ *
+ * @return Result|string
+ * @throws ClientException
+ * @throws ServerException
+ */
+ public function getAcsResponse($request)
+ {
+ if ($request instanceof Result) {
+ return $request;
+ }
+
+ return $request->client($this->randClientName)->request();
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Encode.php b/app/Common/extend/alibabacloud/client/src/Encode.php
new file mode 100755
index 0000000..ef589d2
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Encode.php
@@ -0,0 +1,64 @@
+data = $data;
+ }
+
+ /**
+ * @return bool|string
+ */
+ public function toString()
+ {
+ $string = '';
+ foreach ($this->data as $key => $value) {
+ $encode = rawurlencode($value);
+ $string .= "$key=$encode&";
+ }
+
+ if (0 < count($this->data)) {
+ $string = substr($string, 0, -1);
+ }
+
+ return $string;
+ }
+
+ /**
+ * @return $this
+ */
+ public function ksort()
+ {
+ ksort($this->data);
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Exception/AlibabaCloudException.php b/app/Common/extend/alibabacloud/client/src/Exception/AlibabaCloudException.php
new file mode 100755
index 0000000..cee21d8
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Exception/AlibabaCloudException.php
@@ -0,0 +1,70 @@
+errorCode;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated
+ */
+ public function setErrorCode()
+ {
+ throw new RuntimeException('deprecated since 2.0.');
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorMessage()
+ {
+ return $this->errorMessage;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ *
+ * @param $errorMessage
+ *
+ * @deprecated
+ */
+ public function setErrorMessage($errorMessage)
+ {
+ $this->errorMessage = $errorMessage;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated
+ */
+ public function setErrorType()
+ {
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Exception/ClientException.php b/app/Common/extend/alibabacloud/client/src/Exception/ClientException.php
new file mode 100755
index 0000000..0877e87
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Exception/ClientException.php
@@ -0,0 +1,38 @@
+errorMessage = $errorMessage;
+ $this->errorCode = $errorCode;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated
+ */
+ public function getErrorType()
+ {
+ return 'Client';
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Exception/ServerException.php b/app/Common/extend/alibabacloud/client/src/Exception/ServerException.php
new file mode 100755
index 0000000..37db53e
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Exception/ServerException.php
@@ -0,0 +1,158 @@
+result = $result;
+ $this->errorMessage = $errorMessage;
+ $this->errorCode = $errorCode;
+ $this->resolvePropertiesByReturn();
+ $this->distinguishSignatureErrors();
+ $this->bodyAsErrorMessage();
+
+ parent::__construct(
+ $this->getMessageString(),
+ $this->result->getStatusCode()
+ );
+ }
+
+ /**
+ * Resolve the error message based on the return of the server.
+ *
+ * @return void
+ */
+ private function resolvePropertiesByReturn()
+ {
+ if (isset($this->result['message'])) {
+ $this->errorMessage = $this->result['message'];
+ $this->errorCode = $this->result['code'];
+ }
+ if (isset($this->result['Message'])) {
+ $this->errorMessage = $this->result['Message'];
+ $this->errorCode = $this->result['Code'];
+ }
+ if (isset($this->result['errorMsg'])) {
+ $this->errorMessage = $this->result['errorMsg'];
+ $this->errorCode = $this->result['errorCode'];
+ }
+ if (isset($this->result['requestId'])) {
+ $this->requestId = $this->result['requestId'];
+ }
+ if (isset($this->result['RequestId'])) {
+ $this->requestId = $this->result['RequestId'];
+ }
+ }
+
+ /**
+ * If the string to be signed are the same with server's, it is considered a credential error.
+ */
+ private function distinguishSignatureErrors()
+ {
+ if ($this->result->getRequest()
+ && Stringy::create($this->errorMessage)->contains($this->result->getRequest()->stringToSign())) {
+ $this->errorCode = 'InvalidAccessKeySecret';
+ $this->errorMessage = 'Specified Access Key Secret is not valid.';
+ }
+ }
+
+ /**
+ * If the error message matches the default message and
+ * the server has returned content, use the return content
+ */
+ private function bodyAsErrorMessage()
+ {
+ $body = (string)$this->result->getBody();
+ if ($this->errorMessage === SDK::RESPONSE_EMPTY && $body) {
+ $this->errorMessage = $body;
+ }
+ }
+
+ /**
+ * Get standard exception message.
+ *
+ * @return string
+ */
+ private function getMessageString()
+ {
+ $message = "$this->errorCode: $this->errorMessage RequestId: $this->requestId";
+
+ if ($this->getResult()->getRequest()) {
+ $method = $this->getResult()->getRequest()->method;
+ $uri = (string)$this->getResult()->getRequest()->uri;
+ $message .= " $method \"$uri\"";
+ if ($this->result) {
+ $message .= ' ' . $this->result->getStatusCode();
+ }
+ }
+
+ return $message;
+ }
+
+ /**
+ * @return Result
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRequestId()
+ {
+ return $this->requestId;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated
+ */
+ public function getErrorType()
+ {
+ return 'Server';
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @deprecated
+ */
+ public function getHttpStatus()
+ {
+ return $this->getResult()->getStatusCode();
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Filter/ApiFilter.php b/app/Common/extend/alibabacloud/client/src/Filter/ApiFilter.php
new file mode 100755
index 0000000..c12327f
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Filter/ApiFilter.php
@@ -0,0 +1,245 @@
+endsWith(DIRECTORY_SEPARATOR)) {
+ $dir .= DIRECTORY_SEPARATOR;
+ }
+
+ if (0 === strpos($filename, $dir)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * @return bool
+ */
+function isWindows()
+{
+ return PATH_SEPARATOR === ';';
+}
+
+/**
+ * @return CLImate
+ */
+function cliMate()
+{
+ return new CLImate();
+}
+
+/**
+ * @param string $string
+ * @param string|null $flank
+ * @param string|null $char
+ * @param int|null $length
+ *
+ * @return void
+ */
+function backgroundRed($string, $flank = null, $char = null, $length = null)
+{
+ cliMate()->br();
+ if ($flank !== null) {
+ cliMate()->backgroundRed()->flank($flank, $char, $length);
+ cliMate()->br();
+ }
+ cliMate()->backgroundRed($string);
+ cliMate()->br();
+}
+
+/**
+ * @param string $string
+ * @param string|null $flank
+ * @param string|null $char
+ * @param int|null $length
+ *
+ * @return void
+ */
+function backgroundGreen($string, $flank = null, $char = null, $length = null)
+{
+ cliMate()->br();
+ if ($flank !== null) {
+ cliMate()->backgroundGreen()->flank($flank, $char, $length);
+ }
+ cliMate()->backgroundGreen($string);
+ cliMate()->br();
+}
+
+/**
+ * @param string $string
+ * @param string|null $flank
+ * @param string|null $char
+ * @param int|null $length
+ *
+ * @return void
+ */
+function backgroundBlue($string, $flank = null, $char = null, $length = null)
+{
+ cliMate()->br();
+ if ($flank !== null) {
+ cliMate()->backgroundBlue()->flank($flank, $char, $length);
+ }
+ cliMate()->backgroundBlue($string);
+ cliMate()->br();
+}
+
+/**
+ * @param string $string
+ * @param string|null $flank
+ * @param string|null $char
+ * @param int|null $length
+ *
+ * @return void
+ */
+function backgroundMagenta($string, $flank = null, $char = null, $length = null)
+{
+ cliMate()->br();
+ if ($flank !== null) {
+ cliMate()->backgroundMagenta()->flank($flank, $char, $length);
+ }
+ cliMate()->backgroundMagenta($string);
+ cliMate()->br();
+}
+
+/**
+ * @param array $array
+ */
+function json(array $array)
+{
+ cliMate()->br();
+ cliMate()->backgroundGreen()->json($array);
+ cliMate()->br();
+}
+
+/**
+ * @param array $array
+ *
+ * @return void
+ */
+function redTable($array)
+{
+ /**
+ * @noinspection PhpUndefinedMethodInspection
+ */
+ cliMate()->redTable($array);
+}
+
+/**
+ * @param mixed $result
+ * @param string $title
+ *
+ * @return void
+ */
+function block($result, $title)
+{
+ cliMate()->backgroundGreen()->flank($title, '--', 20);
+ dump($result);
+}
+
+/**
+ * Gets the value of an environment variable.
+ *
+ * @param string $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+function env($key, $default = null)
+{
+ $value = getenv($key);
+
+ if ($value === false) {
+ return value($default);
+ }
+
+ if (envSubstr($value)) {
+ return substr($value, 1, -1);
+ }
+
+ return envConversion($value);
+}
+
+/**
+ * @param $value
+ *
+ * @return bool|string|null
+ */
+function envConversion($value)
+{
+ $key = strtolower($value);
+
+ if ($key === 'null' || $key === '(null)') {
+ return null;
+ }
+
+ $list = [
+ 'true' => true,
+ '(true)' => true,
+ 'false' => false,
+ '(false)' => false,
+ 'empty' => '',
+ '(empty)' => '',
+ ];
+
+ return isset($list[$key]) ? $list[$key] : $value;
+}
+
+/**
+ * @param $key
+ *
+ * @return bool|mixed
+ * @throws ClientException
+ */
+function envNotEmpty($key)
+{
+ $value = env($key, false);
+ if ($value !== false && !$value) {
+ throw new ClientException(
+ "Environment variable '$key' cannot be empty",
+ SDK::INVALID_ARGUMENT
+ );
+ }
+ if ($value) {
+ return $value;
+ }
+
+ return false;
+}
+
+/**
+ * @param $value
+ *
+ * @return bool
+ */
+function envSubstr($value)
+{
+ return ($valueLength = strlen($value)) > 1 && strpos($value, '"') === 0 && $value[$valueLength - 1] === '"';
+}
+
+/**
+ * Return the default value of the given value.
+ *
+ * @param mixed $value
+ *
+ * @return mixed
+ */
+function value($value)
+{
+ return $value instanceof Closure ? $value() : $value;
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Log/LogFormatter.php b/app/Common/extend/alibabacloud/client/src/Log/LogFormatter.php
new file mode 100755
index 0000000..a17a1b3
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Log/LogFormatter.php
@@ -0,0 +1,78 @@
+template = $template;
+ $timezone = new DateTimeZone(date_default_timezone_get() ?: 'UTC');
+ if (PHP_VERSION_ID < 70100) {
+ self::$ts = DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), $timezone);
+ } else {
+ self::$ts = new DateTime(null, $timezone);
+ }
+ }
+
+ /**
+ * Returns a formatted message string.
+ *
+ * @param RequestInterface $request Request that was sent
+ * @param ResponseInterface $response Response that was received
+ * @param Exception $error Exception that was received
+ *
+ * @return string
+ */
+ public function format(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ Exception $error = null
+ ) {
+ $this->template = str_replace('{pid}', getmypid(), $this->template);
+ $this->template = str_replace('{cost}', self::getCost(), $this->template);
+ $this->template = str_replace('{start_time}', self::$ts->format('Y-m-d H:i:s.u'), $this->template);
+
+ return (new MessageFormatter($this->template))->format($request, $response, $error);
+ }
+
+ /**
+ * @return float|mixed
+ */
+ private static function getCost()
+ {
+ return microtime(true) - self::$logStartTime;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Profile/DefaultProfile.php b/app/Common/extend/alibabacloud/client/src/Profile/DefaultProfile.php
new file mode 100755
index 0000000..b1b3707
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Profile/DefaultProfile.php
@@ -0,0 +1,74 @@
+regionId($regionId);
+ }
+
+ /**
+ * @param string $regionId
+ * @param string $accessKeyId
+ * @param string $accessKeySecret
+ * @param string $roleArn
+ * @param string $roleSessionName
+ *
+ * @return Client
+ * @throws ClientException
+ */
+ public static function getRamRoleArnProfile($regionId, $accessKeyId, $accessKeySecret, $roleArn, $roleSessionName)
+ {
+ return AlibabaCloud::ramRoleArnClient($accessKeyId, $accessKeySecret, $roleArn, $roleSessionName)
+ ->regionId($regionId);
+ }
+
+ /**
+ * @param string $regionId
+ * @param string $roleName
+ *
+ * @return Client
+ * @throws ClientException
+ */
+ public static function getEcsRamRoleProfile($regionId, $roleName)
+ {
+ return AlibabaCloud::ecsRamRoleClient($roleName)
+ ->regionId($regionId);
+ }
+
+ /**
+ * @param string $regionId
+ * @param string $bearerToken
+ *
+ * @return Client
+ * @throws ClientException
+ */
+ public static function getBearerTokenProfile($regionId, $bearerToken)
+ {
+ return AlibabaCloud::bearerTokenClient($bearerToken)
+ ->regionId($regionId);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Regions/EndpointProvider.php b/app/Common/extend/alibabacloud/client/src/Regions/EndpointProvider.php
new file mode 100755
index 0000000..5e8e555
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Regions/EndpointProvider.php
@@ -0,0 +1,18 @@
+request = $request;
+ }
+
+ /**
+ * @param Request $request
+ * @param string $domain
+ *
+ * @return string
+ * @throws ClientException
+ * @throws ServerException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public static function findProductDomain(Request $request, $domain = 'location.aliyuncs.com')
+ {
+ return self::resolveHost($request, $domain);
+ }
+
+ /**
+ * @param $regionId
+ * @param $product
+ * @param $domain
+ *
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public static function addEndPoint($regionId, $product, $domain)
+ {
+ self::addHost($product, $domain, $regionId);
+ }
+
+
+ /**
+ * @param Request $request
+ * @param string $domain
+ *
+ * @return string
+ * @throws ClientException
+ * @throws ServerException
+ */
+ public static function resolveHost(Request $request, $domain = 'location.aliyuncs.com')
+ {
+ $locationService = new static($request);
+ $product = $locationService->request->product;
+ $regionId = $locationService->request->realRegionId();
+
+ if (!isset(self::$hosts[$product][$regionId])) {
+ self::$hosts[$product][$regionId] = self::getResult($locationService, $domain);
+ }
+
+ return self::$hosts[$product][$regionId];
+ }
+
+ /**
+ * @param static $locationService
+ * @param string $domain
+ *
+ * @return string
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private static function getResult($locationService, $domain)
+ {
+ $locationRequest = new LocationServiceRequest($locationService->request, $domain);
+
+ $result = $locationRequest->request();
+
+ if (!isset($result['Endpoints']['Endpoint'][0]['Endpoint'])) {
+ throw new ClientException(
+ 'Not found Region ID in ' . $domain,
+ SDK::INVALID_REGION_ID
+ );
+ }
+
+ return $result['Endpoints']['Endpoint'][0]['Endpoint'];
+ }
+
+ /**
+ * @param string $product
+ * @param string $host
+ * @param string $regionId
+ *
+ * @throws ClientException
+ */
+ public static function addHost($product, $host, $regionId = self::GLOBAL_REGION)
+ {
+ ApiFilter::product($product);
+
+ HttpFilter::host($host);
+
+ ClientFilter::regionId($regionId);
+
+ self::$hosts[$product][$regionId] = $host;
+ }
+
+ /**
+ * Update endpoints from OSS.
+ *
+ * @codeCoverageIgnore
+ * @throws Exception
+ */
+ public static function updateEndpoints()
+ {
+ $ossUrl = 'https://openapi-endpoints.oss-cn-hangzhou.aliyuncs.com/endpoints.json';
+ $json = \file_get_contents($ossUrl);
+ $list = \json_decode($json, true);
+
+ foreach ($list['endpoints'] as $endpoint) {
+ Config::set(
+ "endpoints.{$endpoint['service']}.{$endpoint['regionid']}",
+ \strtolower($endpoint['endpoint'])
+ );
+ }
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Regions/LocationServiceRequest.php b/app/Common/extend/alibabacloud/client/src/Regions/LocationServiceRequest.php
new file mode 100755
index 0000000..94a267d
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Regions/LocationServiceRequest.php
@@ -0,0 +1,46 @@
+product('Location');
+ $this->version('2015-06-12');
+ $this->action('DescribeEndpoints');
+ $this->regionId('cn-hangzhou');
+ $this->format('JSON');
+ $this->options['query']['Id'] = $request->realRegionId();
+ $this->options['query']['ServiceCode'] = $request->serviceCode;
+ $this->options['query']['Type'] = $request->endpointType;
+ $this->client($request->client);
+ $this->host($domain);
+ if (isset($request->options['timeout'])) {
+ $this->timeout($request->options['timeout']);
+ }
+
+ if (isset($request->options['connect_timeout'])) {
+ $this->connectTimeout($request->options['connect_timeout']);
+ }
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Release.php b/app/Common/extend/alibabacloud/client/src/Release.php
new file mode 100755
index 0000000..0be9c1b
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Release.php
@@ -0,0 +1,112 @@
+getArguments();
+ if (count($arguments) <= 1) {
+ echo 'Missing ChangeLog';
+
+ return;
+ }
+ self::updateChangelogFile($arguments[0], $arguments[1]);
+ self::changeVersionInCode($arguments[0]);
+ }
+
+ /**
+ * @param $version
+ * @param $changeLog
+ */
+ private static function updateChangelogFile($version, $changeLog)
+ {
+ $content = preg_replace(
+ '/# CHANGELOG/',
+ '# CHANGELOG'
+ . "\n"
+ . "\n"
+ . "## $version - " . date('Y-m-d')
+ . self::log($changeLog),
+ self::getChangeLogContent()
+ );
+
+ file_put_contents(self::getChangeLogFile(), $content);
+ }
+
+ /**
+ * @param $changeLog
+ *
+ * @return string
+ */
+ private static function log($changeLog)
+ {
+ $logs = explode('|', $changeLog);
+ $string = "\n";
+ foreach ($logs as $log) {
+ if ($log) {
+ $string .= "- $log." . "\n";
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * @return string
+ */
+ private static function getChangeLogContent()
+ {
+ return file_get_contents(self::getChangeLogFile());
+ }
+
+ /**
+ * @return string
+ */
+ private static function getChangeLogFile()
+ {
+ return __DIR__ . '/../CHANGELOG.md';
+ }
+
+ /**
+ * @param $version
+ */
+ private static function changeVersionInCode($version)
+ {
+ $content = preg_replace(
+ "/const VERSION = \'(.*)\';/",
+ "const VERSION = '" . $version . "';",
+ self::getCodeContent()
+ );
+
+ file_put_contents(self::getCodeFile(), $content);
+ }
+
+ /**
+ * @return string
+ */
+ private static function getCodeContent()
+ {
+ return file_get_contents(self::getCodeFile());
+ }
+
+ /**
+ * @return string
+ */
+ private static function getCodeFile()
+ {
+ return __DIR__ . '/AlibabaCloud.php';
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/Request.php b/app/Common/extend/alibabacloud/client/src/Request/Request.php
new file mode 100755
index 0000000..94ec12c
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/Request.php
@@ -0,0 +1,445 @@
+client = CredentialsProvider::getDefaultName();
+ $this->uri = new Uri();
+ $this->uri = $this->uri->withScheme($this->scheme);
+ $this->options['http_errors'] = false;
+ $this->options['connect_timeout'] = self::CONNECT_TIMEOUT;
+ $this->options['timeout'] = self::TIMEOUT;
+
+ // Turn on debug mode based on environment variable.
+ if (strtolower(\AlibabaCloud\Client\env('DEBUG')) === 'sdk') {
+ $this->options['debug'] = true;
+ }
+
+ // Rewrite configuration if the user has a configuration.
+ if ($options !== []) {
+ $this->options($options);
+ }
+ }
+
+ /**
+ * @param string $name
+ * @param string $value
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function appendUserAgent($name, $value)
+ {
+ $filter_name = Filter::name($name);
+
+ if (!UserAgent::isGuarded($filter_name)) {
+ $this->userAgent[$filter_name] = Filter::value($value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array $userAgent
+ *
+ * @return $this
+ */
+ public function withUserAgent(array $userAgent)
+ {
+ $this->userAgent = UserAgent::clean($userAgent);
+
+ return $this;
+ }
+
+ /**
+ * Set Accept format.
+ *
+ * @param string $format
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function format($format)
+ {
+ $this->format = ApiFilter::format($format);
+
+ return $this;
+ }
+
+ /**
+ * @param $contentType
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function contentType($contentType)
+ {
+ $this->options['headers']['Content-Type'] = HttpFilter::contentType($contentType);
+
+ return $this;
+ }
+
+ /**
+ * @param string $accept
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function accept($accept)
+ {
+ $this->options['headers']['Accept'] = HttpFilter::accept($accept);
+
+ return $this;
+ }
+
+ /**
+ * Set the request body.
+ *
+ * @param string $body
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function body($body)
+ {
+ $this->options['body'] = HttpFilter::body($body);
+
+ return $this;
+ }
+
+ /**
+ * Set the json as body.
+ *
+ * @param array|object $content
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function jsonBody($content)
+ {
+ if (!\is_array($content) && !\is_object($content)) {
+ throw new ClientException(
+ 'jsonBody only accepts an array or object',
+ SDK::INVALID_ARGUMENT
+ );
+ }
+
+ return $this->body(\json_encode($content));
+ }
+
+ /**
+ * Set the request scheme.
+ *
+ * @param string $scheme
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function scheme($scheme)
+ {
+ $this->scheme = HttpFilter::scheme($scheme);
+ $this->uri = $this->uri->withScheme($scheme);
+
+ return $this;
+ }
+
+ /**
+ * Set the request host.
+ *
+ * @param string $host
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function host($host)
+ {
+ $this->uri = $this->uri->withHost(HttpFilter::host($host));
+
+ return $this;
+ }
+
+ /**
+ * @param string $method
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function method($method)
+ {
+ $this->method = HttpFilter::method($method);
+
+ return $this;
+ }
+
+ /**
+ * @param string $clientName
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function client($clientName)
+ {
+ $this->client = ClientFilter::clientName($clientName);
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ * @throws ClientException
+ */
+ public function isDebug()
+ {
+ if (isset($this->options['debug'])) {
+ return $this->options['debug'] === true;
+ }
+
+ if (isset($this->httpClient()->options['debug'])) {
+ return $this->httpClient()->options['debug'] === true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @throws ClientException
+ * @throws ServerException
+ */
+ public function resolveOption()
+ {
+ $this->options['headers']['User-Agent'] = UserAgent::toString($this->userAgent);
+
+ $this->cleanQuery();
+ $this->cleanFormParams();
+ $this->resolveHost();
+ $this->resolveParameter();
+
+ if (isset($this->options['form_params'])) {
+ $this->options['form_params'] = \GuzzleHttp\Psr7\parse_query(
+ Encode::create($this->options['form_params'])->toString()
+ );
+ }
+
+ $this->mergeOptionsIntoClient();
+ }
+
+ /**
+ * @return Result
+ * @throws ClientException
+ * @throws ServerException
+ */
+ public function request()
+ {
+ $this->resolveOption();
+ $result = $this->response();
+
+ if ($this->shouldServerRetry($result)) {
+ return $this->request();
+ }
+
+ if (!$result->isSuccess()) {
+ throw new ServerException($result);
+ }
+
+ return $result;
+ }
+
+ /***
+ * @return PromiseInterface
+ * @throws Exception
+ */
+ public function requestAsync()
+ {
+ $this->resolveOption();
+
+ return self::createClient($this)->requestAsync(
+ $this->method,
+ (string)$this->uri,
+ $this->options
+ );
+ }
+
+ /**
+ * @param Request $request
+ *
+ * @return Client
+ * @throws Exception
+ */
+ public static function createClient(Request $request = null)
+ {
+ if (AlibabaCloud::hasMock()) {
+ $stack = HandlerStack::create(AlibabaCloud::getMock());
+ } else {
+ $stack = HandlerStack::create();
+ }
+
+ if (AlibabaCloud::isRememberHistory()) {
+ $stack->push(Middleware::history(AlibabaCloud::referenceHistory()));
+ }
+
+ if (AlibabaCloud::getLogger()) {
+ $stack->push(Middleware::log(
+ AlibabaCloud::getLogger(),
+ new LogFormatter(AlibabaCloud::getLogFormat())
+ ));
+ }
+
+ $stack->push(Middleware::mapResponse(static function (ResponseInterface $response) use ($request) {
+ return new Result($response, $request);
+ }));
+
+ self::$config['handler'] = $stack;
+
+ return new Client(self::$config);
+ }
+
+ /**
+ * @throws ClientException
+ * @throws Exception
+ */
+ private function response()
+ {
+ try {
+ return self::createClient($this)->request(
+ $this->method,
+ (string)$this->uri,
+ $this->options
+ );
+ } catch (GuzzleException $exception) {
+ if ($this->shouldClientRetry($exception)) {
+ return $this->response();
+ }
+ throw new ClientException(
+ $exception->getMessage(),
+ SDK::SERVER_UNREACHABLE,
+ $exception
+ );
+ }
+ }
+
+ /**
+ * Remove redundant Query
+ *
+ * @codeCoverageIgnore
+ */
+ private function cleanQuery()
+ {
+ if (isset($this->options['query']) && $this->options['query'] === []) {
+ unset($this->options['query']);
+ }
+ }
+
+ /**
+ * Remove redundant Headers
+ *
+ * @codeCoverageIgnore
+ */
+ private function cleanFormParams()
+ {
+ if (isset($this->options['form_params']) && $this->options['form_params'] === []) {
+ unset($this->options['form_params']);
+ }
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/RoaRequest.php b/app/Common/extend/alibabacloud/client/src/Request/RoaRequest.php
new file mode 100755
index 0000000..a6af50e
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/RoaRequest.php
@@ -0,0 +1,335 @@
+resolveQuery();
+ $this->resolveHeaders();
+ $this->resolveBody();
+ $this->resolveUri();
+ $this->resolveSignature();
+ }
+
+ private function resolveQuery()
+ {
+ if (!isset($this->options['query']['Version'])) {
+ $this->options['query']['Version'] = $this->version;
+ }
+ }
+
+ private function resolveBody()
+ {
+ // If the body has already been specified, it will not be resolved.
+ if (isset($this->options['body'])) {
+ return;
+ }
+
+ if (!isset($this->options['form_params'])) {
+ return;
+ }
+
+ // Merge data, compatible with parameters set from constructor.
+ $params = Arrays::merge(
+ [
+ $this->data,
+ $this->options['form_params']
+ ]
+ );
+
+ $this->encodeBody($params);
+
+ unset($this->options['form_params']);
+ }
+
+ /**
+ * Determine the body format based on the Content-Type and calculate the MD5 value.
+ *
+ * @param array $params
+ */
+ private function encodeBody(array $params)
+ {
+ $stringy = Stringy::create($this->options['headers']['Content-Type']);
+
+ if ($stringy->contains('application/json', false)) {
+ $this->options['body'] = json_encode($params);
+ $this->options['headers']['Content-MD5'] = base64_encode(md5($this->options['body'], true));
+
+ return;
+ }
+
+ $this->options['body'] = Encode::create($params)->ksort()->toString();
+ $this->options['headers']['Content-MD5'] = base64_encode(md5($this->options['body'], true));
+ $this->options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
+ }
+
+ /**
+ * @throws ClientException
+ * @throws ServerException
+ * @throws Exception
+ */
+ private function resolveHeaders()
+ {
+ $this->options['headers']['x-acs-version'] = $this->version;
+ $this->options['headers']['x-acs-region-id'] = $this->realRegionId();
+ $this->options['headers']['Date'] = gmdate($this->dateTimeFormat);
+
+ $signature = $this->httpClient()->getSignature();
+ $this->options['headers']['x-acs-signature-method'] = $signature->getMethod();
+ $this->options['headers']['x-acs-signature-nonce'] = Sign::uuid($this->product . $this->realRegionId());
+ $this->options['headers']['x-acs-signature-version'] = $signature->getVersion();
+ if ($signature->getType()) {
+ $this->options['headers']['x-acs-signature-type'] = $signature->getType();
+ }
+
+ $this->resolveAccept();
+ $this->resolveContentType();
+ $this->resolveSecurityToken();
+ $this->resolveBearerToken();
+ }
+
+ /**
+ * @throws ClientException
+ * @throws Exception
+ */
+ private function resolveSignature()
+ {
+ $this->options['headers']['Authorization'] = $this->signature();
+ }
+
+ /**
+ * If accept is not specified, it is determined by format.
+ */
+ private function resolveAccept()
+ {
+ if (!isset($this->options['headers']['Accept'])) {
+ $this->options['headers']['Accept'] = Accept::create($this->format)->toString();
+ }
+ }
+
+ /**
+ * If the Content-Type is not specified, it is determined according to accept.
+ */
+ private function resolveContentType()
+ {
+ if (!isset($this->options['headers']['Content-Type'])) {
+ $this->options['headers']['Content-Type'] = "{$this->options['headers']['Accept']}; charset=utf-8";
+ }
+ }
+
+ /**
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function resolveSecurityToken()
+ {
+ if (!$this->credential() instanceof StsCredential) {
+ return;
+ }
+
+ if (!$this->credential()->getSecurityToken()) {
+ return;
+ }
+
+ $this->options['headers']['x-acs-security-token'] = $this->credential()->getSecurityToken();
+ }
+
+ /**
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function resolveBearerToken()
+ {
+ if ($this->credential() instanceof BearerTokenCredential) {
+ $this->options['headers']['x-acs-bearer-token'] = $this->credential()->getBearerToken();
+ }
+ }
+
+ /**
+ * Sign the request message.
+ *
+ * @return string
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function signature()
+ {
+ /**
+ * @var AccessKeyCredential $credential
+ */
+ $credential = $this->credential();
+ $access_key_id = $credential->getAccessKeyId();
+ $signature = $this->httpClient()
+ ->getSignature()
+ ->sign(
+ $this->stringToSign(),
+ $credential->getAccessKeySecret()
+ );
+
+ return "acs $access_key_id:$signature";
+ }
+
+ /**
+ * @return void
+ */
+ private function resolveUri()
+ {
+ $path = Path::assign($this->pathPattern, $this->pathParameters);
+
+ $this->uri = $this->uri->withPath($path)
+ ->withQuery(
+ $this->queryString()
+ );
+ }
+
+ /**
+ * @return string
+ */
+ public function stringToSign()
+ {
+ $request = new \GuzzleHttp\Psr7\Request(
+ $this->method,
+ $this->uri,
+ $this->options['headers']
+ );
+
+ return Sign::roaString($request);
+ }
+
+ /**
+ * @return bool|string
+ */
+ private function queryString()
+ {
+ $query = isset($this->options['query'])
+ ? $this->options['query']
+ : [];
+
+ return Encode::create($query)->ksort()->toString();
+ }
+
+ /**
+ * Set path parameter by name.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @return RoaRequest
+ * @throws ClientException
+ */
+ public function pathParameter($name, $value)
+ {
+ Filter::name($name);
+
+ if ($value === '') {
+ throw new ClientException(
+ 'Value cannot be empty',
+ SDK::INVALID_ARGUMENT
+ );
+ }
+
+ $this->pathParameters[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Set path pattern.
+ *
+ * @param string $pattern
+ *
+ * @return self
+ * @throws ClientException
+ */
+ public function pathPattern($pattern)
+ {
+ ApiFilter::pattern($pattern);
+
+ $this->pathPattern = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Magic method for set or get request parameters.
+ *
+ * @param string $name
+ * @param mixed $arguments
+ *
+ * @return $this
+ */
+ public function __call($name, $arguments)
+ {
+ if (strncmp($name, 'get', 3) === 0) {
+ $parameter_name = \mb_strcut($name, 3);
+
+ return $this->__get($parameter_name);
+ }
+
+ if (strncmp($name, 'with', 4) === 0) {
+ $parameter_name = \mb_strcut($name, 4);
+ $this->__set($parameter_name, $arguments[0]);
+ $this->pathParameters[$parameter_name] = $arguments[0];
+
+ return $this;
+ }
+
+ if (strncmp($name, 'set', 3) === 0) {
+ $parameter_name = \mb_strcut($name, 3);
+ $with_method = "with$parameter_name";
+
+ throw new RuntimeException("Please use $with_method instead of $name");
+ }
+
+ throw new RuntimeException('Call to undefined method ' . __CLASS__ . '::' . $name . '()');
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/RpcRequest.php b/app/Common/extend/alibabacloud/client/src/Request/RpcRequest.php
new file mode 100755
index 0000000..b9d7369
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/RpcRequest.php
@@ -0,0 +1,203 @@
+resolveBoolInParameters();
+ $this->resolveCommonParameters();
+ $this->repositionParameters();
+ }
+
+ /**
+ * Convert a Boolean value to a string
+ */
+ private function resolveBoolInParameters()
+ {
+ if (isset($this->options['query'])) {
+ $this->options['query'] = array_map(
+ static function ($value) {
+ return self::boolToString($value);
+ },
+ $this->options['query']
+ );
+ }
+ }
+
+ /**
+ * Convert a Boolean value to a string.
+ *
+ * @param bool|string $value
+ *
+ * @return string
+ */
+ public static function boolToString($value)
+ {
+ if (is_bool($value)) {
+ return $value ? 'true' : 'false';
+ }
+
+ return $value;
+ }
+
+ /**
+ * Resolve Common Parameters.
+ *
+ * @throws ClientException
+ * @throws Exception
+ */
+ private function resolveCommonParameters()
+ {
+ $signature = $this->httpClient()->getSignature();
+ $this->options['query']['RegionId'] = $this->realRegionId();
+ $this->options['query']['Format'] = $this->format;
+ $this->options['query']['SignatureMethod'] = $signature->getMethod();
+ $this->options['query']['SignatureVersion'] = $signature->getVersion();
+ $this->options['query']['SignatureNonce'] = Sign::uuid($this->product . $this->realRegionId());
+ $this->options['query']['Timestamp'] = gmdate($this->dateTimeFormat);
+ $this->options['query']['Action'] = $this->action;
+ if ($this->credential()->getAccessKeyId()) {
+ $this->options['query']['AccessKeyId'] = $this->credential()->getAccessKeyId();
+ }
+ if ($signature->getType()) {
+ $this->options['query']['SignatureType'] = $signature->getType();
+ }
+ if (!isset($this->options['query']['Version'])) {
+ $this->options['query']['Version'] = $this->version;
+ }
+ $this->resolveSecurityToken();
+ $this->resolveBearerToken();
+ $this->options['query']['Signature'] = $this->signature();
+ }
+
+ /**
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function resolveSecurityToken()
+ {
+ if (!$this->credential() instanceof StsCredential) {
+ return;
+ }
+
+ if (!$this->credential()->getSecurityToken()) {
+ return;
+ }
+
+ $this->options['query']['SecurityToken'] = $this->credential()->getSecurityToken();
+ }
+
+ /**
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function resolveBearerToken()
+ {
+ if ($this->credential() instanceof BearerTokenCredential) {
+ $this->options['query']['BearerToken'] = $this->credential()->getBearerToken();
+ }
+ }
+
+ /**
+ * Sign the parameters.
+ *
+ * @return mixed
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function signature()
+ {
+ return $this->httpClient()
+ ->getSignature()
+ ->sign(
+ $this->stringToSign(),
+ $this->credential()->getAccessKeySecret() . '&'
+ );
+ }
+
+ /**
+ * @return string
+ */
+ public function stringToSign()
+ {
+ $query = isset($this->options['query']) ? $this->options['query'] : [];
+ $form_params = isset($this->options['form_params']) ? $this->options['form_params'] : [];
+ $parameters = Arrays::merge([$query, $form_params]);
+
+ return Sign::rpcString($this->method, $parameters);
+ }
+
+ /**
+ * Adjust parameter position
+ */
+ private function repositionParameters()
+ {
+ if ($this->method === 'POST' || $this->method === 'PUT') {
+ foreach ($this->options['query'] as $api_key => $api_value) {
+ $this->options['form_params'][$api_key] = $api_value;
+ }
+ unset($this->options['query']);
+ }
+ }
+
+ /**
+ * Magic method for set or get request parameters.
+ *
+ * @param string $name
+ * @param mixed $arguments
+ *
+ * @return $this
+ */
+ public function __call($name, $arguments)
+ {
+ if (strncmp($name, 'get', 3) === 0) {
+ $parameter_name = \mb_strcut($name, 3);
+
+ return $this->__get($parameter_name);
+ }
+
+ if (strncmp($name, 'with', 4) === 0) {
+ $parameter_name = \mb_strcut($name, 4);
+ $this->__set($parameter_name, $arguments[0]);
+ $this->options['query'][$parameter_name] = $arguments[0];
+
+ return $this;
+ }
+
+ if (strncmp($name, 'set', 3) === 0) {
+ $parameter_name = \mb_strcut($name, 3);
+ $with_method = "with$parameter_name";
+
+ throw new RuntimeException("Please use $with_method instead of $name");
+ }
+
+ throw new RuntimeException('Call to undefined method ' . __CLASS__ . '::' . $name . '()');
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/Traits/AcsTrait.php b/app/Common/extend/alibabacloud/client/src/Request/Traits/AcsTrait.php
new file mode 100755
index 0000000..5644e72
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/Traits/AcsTrait.php
@@ -0,0 +1,237 @@
+action = ApiFilter::action($action);
+
+ return $this;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ *
+ * @param string $endpointSuffix
+ *
+ * @return AcsTrait
+ * @throws ClientException
+ */
+ public function endpointSuffix($endpointSuffix)
+ {
+ $this->endpointSuffix = ApiFilter::endpointSuffix($endpointSuffix);
+
+ return $this;
+ }
+
+ /**
+ * @param string $network
+ */
+ public function network($network)
+ {
+ $this->network = ApiFilter::network($network);
+
+ return $this;
+ }
+
+ /**
+ * @param string $version
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function version($version)
+ {
+ $this->version = ApiFilter::version($version);
+
+ return $this;
+ }
+
+ /**
+ * @param string $product
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function product($product)
+ {
+ $this->product = ApiFilter::product($product);
+
+ return $this;
+ }
+
+ /**
+ * @param string $endpointType
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function endpointType($endpointType)
+ {
+ $this->endpointType = ApiFilter::endpointType($endpointType);
+
+ return $this;
+ }
+
+ /**
+ * @param string $serviceCode
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function serviceCode($serviceCode)
+ {
+ $this->serviceCode = ApiFilter::serviceCode($serviceCode);
+
+ return $this;
+ }
+
+ /**
+ * Resolve Host.
+ *
+ * @throws ClientException
+ * @throws ServerException
+ */
+ public function resolveHost()
+ {
+ // Return if specified
+ if ($this->uri->getHost() !== 'localhost') {
+ return;
+ }
+
+ $region_id = $this->realRegionId();
+ $host = '';
+
+ $this->resolveHostWays($host, $region_id);
+
+ if (!$host) {
+ throw new ClientException(
+ "No host found for {$this->product} in the {$region_id}, you can specify host by host() method. " .
+ 'Like $request->host(\'xxx.xxx.aliyuncs.com\')',
+ SDK::HOST_NOT_FOUND
+ );
+ }
+
+ $this->uri = $this->uri->withHost($host);
+ }
+
+ /**
+ * @param string $host
+ * @param string $region_id
+ *
+ * @throws ClientException
+ * @throws ServerException
+ */
+ private function resolveHostWays(&$host, $region_id)
+ {
+ // 1. Find host by map.
+ if ($this->network === 'public' && isset($this->endpointMap[$region_id])) {
+ $host = $this->endpointMap[$region_id];
+ }
+
+ // 2. Find host by rules.
+ if (!$host && $this->endpointRegional !== null) {
+ $host = AlibabaCloud::resolveHostByRule($this);
+ }
+
+ // 3. Find in the local array file.
+ if (!$host) {
+ $host = AlibabaCloud::resolveHost($this->product, $region_id);
+ }
+
+ // 4. Find in the Location service.
+ if (!$host && $this->serviceCode) {
+ $host = LocationService::resolveHost($this);
+ }
+ }
+
+ /**
+ * @return string
+ * @throws ClientException
+ */
+ public function realRegionId()
+ {
+ if ($this->regionId !== null) {
+ return $this->regionId;
+ }
+
+ if ($this->httpClient()->regionId !== null) {
+ return $this->httpClient()->regionId;
+ }
+
+ if (AlibabaCloud::getDefaultRegionId() !== null) {
+ return AlibabaCloud::getDefaultRegionId();
+ }
+
+ throw new ClientException("Missing required 'RegionId' for Request", SDK::INVALID_REGION_ID);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/Traits/ClientTrait.php b/app/Common/extend/alibabacloud/client/src/Request/Traits/ClientTrait.php
new file mode 100755
index 0000000..37a2d22
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/Traits/ClientTrait.php
@@ -0,0 +1,98 @@
+httpClient()->getCredential();
+ }
+
+ $timeout = isset($this->options['timeout'])
+ ? $this->options['timeout']
+ : Request::TIMEOUT;
+
+ $connectTimeout = isset($this->options['connect_timeout'])
+ ? $this->options['connect_timeout']
+ : Request::CONNECT_TIMEOUT;
+
+ return $this->httpClient()->getSessionCredential($timeout, $connectTimeout);
+ }
+
+ /**
+ * Get the client based on the request's settings.
+ *
+ * @return Client
+ * @throws ClientException
+ */
+ public function httpClient()
+ {
+ if (!AlibabaCloud::all()) {
+ if (CredentialsProvider::hasCustomChain()) {
+ CredentialsProvider::customProvider($this->client);
+ } else {
+ CredentialsProvider::defaultProvider($this->client);
+ }
+ }
+
+ return AlibabaCloud::get($this->client);
+ }
+
+ /**
+ * Merged with the client's options, the same name will be overwritten.
+ *
+ * @throws ClientException
+ */
+ public function mergeOptionsIntoClient()
+ {
+ $this->options = Arrays::merge(
+ [
+ $this->httpClient()->options,
+ $this->options
+ ]
+ );
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/Traits/DeprecatedRoaTrait.php b/app/Common/extend/alibabacloud/client/src/Request/Traits/DeprecatedRoaTrait.php
new file mode 100755
index 0000000..ee64e52
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/Traits/DeprecatedRoaTrait.php
@@ -0,0 +1,55 @@
+pathParameter($name, $value);
+ }
+
+ /**
+ * @param $pathPattern
+ *
+ * @return $this
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setUriPattern($pathPattern)
+ {
+ return $this->pathPattern($pathPattern);
+ }
+
+ /**
+ * @return string
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getUriPattern()
+ {
+ return $this->pathPattern;
+ }
+
+ /**
+ * @return array
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getPathParameters()
+ {
+ return $this->pathParameters;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/Traits/DeprecatedTrait.php b/app/Common/extend/alibabacloud/client/src/Request/Traits/DeprecatedTrait.php
new file mode 100755
index 0000000..406e6ed
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/Traits/DeprecatedTrait.php
@@ -0,0 +1,246 @@
+body($content);
+ }
+
+ /**
+ * @param $method
+ *
+ * @return $this
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setMethod($method)
+ {
+ return $this->method($method);
+ }
+
+ /**
+ * @param $scheme
+ *
+ * @return $this
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setProtocol($scheme)
+ {
+ return $this->scheme($scheme);
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getProtocolType()
+ {
+ return $this->uri->getScheme();
+ }
+
+ /**
+ * @param $scheme
+ *
+ * @return $this
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setProtocolType($scheme)
+ {
+ return $this->scheme($scheme);
+ }
+
+ /**
+ * @param $actionName
+ *
+ * @return $this
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setActionName($actionName)
+ {
+ return $this->action($actionName);
+ }
+
+ /**
+ * @param $format
+ *
+ * @return $this
+ * @throws ClientException
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setAcceptFormat($format)
+ {
+ return $this->format($format);
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getProtocol()
+ {
+ return $this->uri->getScheme();
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getContent()
+ {
+ return isset($this->options['body'])
+ ? $this->options['body']
+ : null;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getHeaders()
+ {
+ return isset($this->options['headers'])
+ ? $this->options['headers']
+ : [];
+ }
+
+ /**
+ * @param $headerKey
+ * @param $headerValue
+ *
+ * @return $this
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function addHeader($headerKey, $headerValue)
+ {
+ $this->options['headers'][$headerKey] = $headerValue;
+
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getQueryParameters()
+ {
+ return isset($this->options['query'])
+ ? $this->options['query']
+ : [];
+ }
+
+ /**
+ * @param $name
+ * @param $value
+ *
+ * @return $this
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setQueryParameters($name, $value)
+ {
+ $this->options['query'][$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getDomainParameter()
+ {
+ return isset($this->options['form_params'])
+ ? $this->options['form_params']
+ : [];
+ }
+
+ /**
+ * @param $name
+ * @param $value
+ *
+ * @return $this
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function putDomainParameters($name, $value)
+ {
+ $this->options['form_params'][$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getActionName()
+ {
+ return $this->action;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getAcceptFormat()
+ {
+ return $this->format;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getLocationEndpointType()
+ {
+ return $this->endpointType;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getLocationServiceCode()
+ {
+ return $this->serviceCode;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/Traits/RetryTrait.php b/app/Common/extend/alibabacloud/client/src/Request/Traits/RetryTrait.php
new file mode 100755
index 0000000..ff35b64
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/Traits/RetryTrait.php
@@ -0,0 +1,149 @@
+serverRetry = ClientFilter::retry($times);
+ $this->serverRetryStrings = $strings;
+ $this->serverRetryStatusCodes = $statusCodes;
+
+ return $this;
+ }
+
+ /**
+ * @param int $times
+ * @param array $strings
+ * @param array $codes
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function retryByClient($times, array $strings, array $codes = [])
+ {
+ $this->clientRetry = ClientFilter::retry($times);
+ $this->clientRetryStrings = $strings;
+ $this->clientRetryStatusCodes = $codes;
+
+ return $this;
+ }
+
+ /**
+ * @param Result $result
+ *
+ * @return bool
+ */
+ private function shouldServerRetry(Result $result)
+ {
+ if ($this->serverRetry <= 0) {
+ return false;
+ }
+
+ if (in_array($result->getStatusCode(), $this->serverRetryStatusCodes)) {
+ $this->serverRetry--;
+
+ return true;
+ }
+
+ foreach ($this->serverRetryStrings as $message) {
+ if (Stringy::create($result->getBody())->contains($message)) {
+ $this->serverRetry--;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param Exception $exception
+ *
+ * @return bool
+ */
+ private function shouldClientRetry(Exception $exception)
+ {
+ if ($this->clientRetry <= 0) {
+ return false;
+ }
+
+ if (in_array($exception->getCode(), $this->clientRetryStatusCodes, true)) {
+ $this->clientRetry--;
+
+ return true;
+ }
+
+ foreach ($this->clientRetryStrings as $message) {
+ if (Stringy::create($exception->getMessage())->contains($message)) {
+ $this->clientRetry--;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Request/UserAgent.php b/app/Common/extend/alibabacloud/client/src/Request/UserAgent.php
new file mode 100755
index 0000000..beb3283
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Request/UserAgent.php
@@ -0,0 +1,142 @@
+ $value) {
+ if ($value === null) {
+ $newUserAgent[] = $key;
+ continue;
+ }
+ $newUserAgent[] = "$key/$value";
+ }
+
+ return $userAgent . \implode(' ', $newUserAgent);
+ }
+
+ /**
+ * UserAgent constructor.
+ */
+ private static function defaultFields()
+ {
+ if (self::$userAgent === []) {
+ self::$userAgent = [
+ 'Client' => AlibabaCloud::VERSION,
+ 'PHP' => \PHP_VERSION,
+ ];
+ }
+ }
+
+ /**
+ * @param array $append
+ *
+ * @return array
+ */
+ public static function clean(array $append)
+ {
+ foreach ($append as $key => $value) {
+ if (self::isGuarded($key)) {
+ unset($append[$key]);
+ continue;
+ }
+ }
+
+ return $append;
+ }
+
+ /**
+ * @param $name
+ *
+ * @return bool
+ */
+ public static function isGuarded($name)
+ {
+ return in_array(strtolower($name), self::$guard, true);
+ }
+
+ /**
+ * set User Agent of Alibaba Cloud.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @throws ClientException
+ */
+ public static function append($name, $value)
+ {
+ Filter::name($name);
+ Filter::value($value);
+
+ self::defaultFields();
+
+ if (!self::isGuarded($name)) {
+ self::$userAgent[$name] = $value;
+ }
+ }
+
+ /**
+ * @param array $userAgent
+ */
+ public static function with(array $userAgent)
+ {
+ self::$userAgent = self::clean($userAgent);
+ }
+
+ /**
+ * Clear all of the User Agent.
+ */
+ public static function clear()
+ {
+ self::$userAgent = [];
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Resolver/ActionResolverTrait.php b/app/Common/extend/alibabacloud/client/src/Resolver/ActionResolverTrait.php
new file mode 100755
index 0000000..f375567
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Resolver/ActionResolverTrait.php
@@ -0,0 +1,50 @@
+action) {
+ $array = explode('\\', get_class($this));
+ $this->action = array_pop($array);
+ }
+ }
+
+ /**
+ * Append SDK version into User-Agent
+ *
+ * @throws ClientException
+ * @throws ReflectionException
+ */
+ private function appendSdkUA()
+ {
+ if (!(new ReflectionClass(AlibabaCloud::class))->hasMethod('appendUserAgent')) {
+ return;
+ }
+
+ if (!class_exists('AlibabaCloud\Release')) {
+ return;
+ }
+
+ AlibabaCloud::appendUserAgent('SDK', \AlibabaCloud\Release::VERSION);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Resolver/ApiResolver.php b/app/Common/extend/alibabacloud/client/src/Resolver/ApiResolver.php
new file mode 100755
index 0000000..7a2bc2b
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Resolver/ApiResolver.php
@@ -0,0 +1,113 @@
+__call($name, $arguments);
+ }
+
+ /**
+ * @param $api
+ * @param $arguments
+ *
+ * @return mixed
+ * @throws ClientException
+ */
+ public function __call($api, $arguments)
+ {
+ $product_name = $this->getProductName();
+ $class = $this->getNamespace() . '\\' . \ucfirst($api);
+
+ if (\class_exists($class)) {
+ if (isset($arguments[0])) {
+ return $this->warpEndpoint(new $class($arguments[0]));
+ }
+
+ return $this->warpEndpoint(new $class());
+ }
+
+ throw new ClientException(
+ "{$product_name} contains no $api",
+ 'SDK.ApiNotFound'
+ );
+ }
+
+ /**
+ * @param Request $request
+ *
+ * @return Request
+ */
+ public function warpEndpoint(Request $request)
+ {
+ $reflect = new ReflectionObject($request);
+ $product_dir = dirname(dirname($reflect->getFileName()));
+ $endpoints_json = "$product_dir/endpoints.json";
+ if (file_exists($endpoints_json)) {
+ $endpoints = json_decode(file_get_contents($endpoints_json), true);
+ if (isset($endpoints['endpoint_map'])) {
+ $request->endpointMap = $endpoints['endpoint_map'];
+ }
+ if (isset($endpoints['endpoint_regional'])) {
+ $request->endpointRegional = $endpoints['endpoint_regional'];
+ }
+ }
+
+ return $request;
+ }
+
+ /**
+ * @return mixed
+ * @throws ClientException
+ */
+ private function getProductName()
+ {
+ $array = \explode('\\', \get_class($this));
+ if (isset($array[3])) {
+ return str_replace('ApiResolver', '', $array[3]);
+ }
+ throw new ClientException(
+ 'Service name not found.',
+ 'SDK.ServiceNotFound'
+ );
+ }
+
+ /**
+ * @return string
+ * @throws ClientException
+ */
+ private function getNamespace()
+ {
+ $array = \explode('\\', \get_class($this));
+
+ if (!isset($array[3])) {
+ throw new ClientException(
+ 'Get namespace error.',
+ 'SDK.ParseError'
+ );
+ }
+
+ unset($array[3]);
+
+ return \implode('\\', $array);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Resolver/CallTrait.php b/app/Common/extend/alibabacloud/client/src/Resolver/CallTrait.php
new file mode 100755
index 0000000..33afdce
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Resolver/CallTrait.php
@@ -0,0 +1,67 @@
+__get($parameter);
+ }
+
+ if (strncmp($name, 'with', 4) === 0) {
+ $parameter = \mb_strcut($name, 4);
+
+ $value = $this->getCallArguments($name, $arguments);
+ $this->data[$parameter] = $value;
+ $this->parameterPosition()[$parameter] = $value;
+
+ return $this;
+ }
+
+ if (strncmp($name, 'set', 3) === 0) {
+ $parameter = \mb_strcut($name, 3);
+ $with_method = "with$parameter";
+
+ return $this->$with_method($this->getCallArguments($name, $arguments));
+ }
+
+ throw new RuntimeException('Call to undefined method ' . __CLASS__ . '::' . $name . '()');
+ }
+
+ /**
+ * @param string $name
+ * @param array $arguments
+ * @param int $index
+ *
+ * @return mixed
+ */
+ private function getCallArguments($name, array $arguments, $index = 0)
+ {
+ if (!isset($arguments[$index])) {
+ throw new ArgumentCountError("Missing arguments to method $name");
+ }
+
+ return $arguments[$index];
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Resolver/Roa.php b/app/Common/extend/alibabacloud/client/src/Resolver/Roa.php
new file mode 100755
index 0000000..719cb0a
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Resolver/Roa.php
@@ -0,0 +1,43 @@
+resolveActionName();
+ $this->appendSdkUA();
+ }
+
+ /**
+ * @return mixed
+ */
+ private function ¶meterPosition()
+ {
+ return $this->pathParameters;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Resolver/Rpc.php b/app/Common/extend/alibabacloud/client/src/Resolver/Rpc.php
new file mode 100755
index 0000000..0926ca4
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Resolver/Rpc.php
@@ -0,0 +1,41 @@
+resolveActionName();
+ $this->appendSdkUA();
+ }
+
+ /**
+ * @return mixed
+ */
+ private function ¶meterPosition()
+ {
+ return $this->options['query'];
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Resolver/VersionResolver.php b/app/Common/extend/alibabacloud/client/src/Resolver/VersionResolver.php
new file mode 100755
index 0000000..cc66c64
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Resolver/VersionResolver.php
@@ -0,0 +1,73 @@
+__call($name, $arguments);
+ }
+
+ /**
+ * @param string $version
+ * @param array $arguments
+ *
+ * @return mixed
+ * @throws ClientException
+ */
+ public function __call($version, $arguments)
+ {
+ $version = \ucfirst($version);
+ $product = $this->getProductName();
+
+ $position = strpos($product, 'Version');
+ if ($position !== false && $position !== 0) {
+ $product = \str_replace('Version', '', $product);
+ }
+
+ $class = "AlibabaCloud\\{$product}\\$version\\{$product}ApiResolver";
+
+ if (\class_exists($class)) {
+ return new $class();
+ }
+
+ throw new ClientException(
+ "$product Versions contains no {$version}",
+ 'SDK.VersionNotFound'
+ );
+ }
+
+ /**
+ * @return mixed
+ * @throws ClientException
+ */
+ private function getProductName()
+ {
+ $array = \explode('\\', \get_class($this));
+
+ if (isset($array[1])) {
+ return $array[1];
+ }
+
+ throw new ClientException(
+ 'Service name not found.',
+ 'SDK.ServiceNotFound'
+ );
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Result/Result.php b/app/Common/extend/alibabacloud/client/src/Result/Result.php
new file mode 100755
index 0000000..7c2910e
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Result/Result.php
@@ -0,0 +1,151 @@
+getStatusCode(),
+ $response->getHeaders(),
+ $response->getBody(),
+ $response->getProtocolVersion(),
+ $response->getReasonPhrase()
+ );
+
+ $this->request = $request;
+
+ $this->resolveData();
+ }
+
+ private function resolveData()
+ {
+ $content = $this->getBody()->getContents();
+
+ switch ($this->getRequestFormat()) {
+ case 'JSON':
+ $result_data = $this->jsonToArray($content);
+ break;
+ case 'XML':
+ $result_data = $this->xmlToArray($content);
+ break;
+ case 'RAW':
+ $result_data = $this->jsonToArray($content);
+ break;
+ default:
+ $result_data = $this->jsonToArray($content);
+ }
+
+ if (!$result_data) {
+ $result_data = [];
+ }
+
+ $this->dot($result_data);
+ }
+
+ /**
+ * @return string
+ */
+ private function getRequestFormat()
+ {
+ return ($this->request instanceof Request)
+ ? \strtoupper($this->request->format)
+ : 'JSON';
+ }
+
+ /**
+ * @param string $response
+ *
+ * @return array
+ */
+ private function jsonToArray($response)
+ {
+ try {
+ return \GuzzleHttp\json_decode($response, true);
+ } catch (InvalidArgumentException $exception) {
+ return [];
+ }
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return array
+ */
+ private function xmlToArray($string)
+ {
+ try {
+ return json_decode(json_encode(simplexml_load_string($string)), true);
+ } catch (Exception $exception) {
+ return [];
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return (string)$this->getBody();
+ }
+
+ /**
+ * @return Request
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ * @return Response
+ * @deprecated
+ */
+ public function getResponse()
+ {
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isSuccess()
+ {
+ return 200 <= $this->getStatusCode()
+ && 300 > $this->getStatusCode();
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/SDK.php b/app/Common/extend/alibabacloud/client/src/SDK.php
new file mode 100755
index 0000000..8976cd0
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/SDK.php
@@ -0,0 +1,57 @@
+getMessage(),
+ SDK::INVALID_CREDENTIAL
+ );
+ }
+
+ return base64_encode($binarySignature);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Signature/Signature.php b/app/Common/extend/alibabacloud/client/src/Signature/Signature.php
new file mode 100755
index 0000000..3b01e69
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Signature/Signature.php
@@ -0,0 +1,49 @@
+sign($string, $accessKeySecret);
+
+ return "acs $accessKeyId:$signature";
+ }
+
+ /**
+ * @codeCoverageIgnore
+ *
+ * @param string $accessKeySecret
+ * @param string $method
+ * @param array $parameters
+ *
+ * @return string
+ */
+ public function rpc($accessKeySecret, $method, array $parameters)
+ {
+ $string = Sign::rpcString($method, $parameters);
+
+ return $this->sign($string, $accessKeySecret . '&');
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Signature/SignatureInterface.php b/app/Common/extend/alibabacloud/client/src/Signature/SignatureInterface.php
new file mode 100755
index 0000000..afa82c8
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Signature/SignatureInterface.php
@@ -0,0 +1,35 @@
+ $value) {
+ if (is_int($key)) {
+ $result[] = $value;
+ continue;
+ }
+
+ if (isset($result[$key]) && is_array($result[$key])) {
+ $result[$key] = self::merge(
+ [$result[$key], $value]
+ );
+ continue;
+ }
+
+ $result[$key] = $value;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Support/Path.php b/app/Common/extend/alibabacloud/client/src/Support/Path.php
new file mode 100755
index 0000000..e1a6464
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Support/Path.php
@@ -0,0 +1,28 @@
+ $value) {
+ $pattern = str_replace("[$key]", $value, $pattern);
+ }
+
+ return $pattern;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Support/Sign.php b/app/Common/extend/alibabacloud/client/src/Support/Sign.php
new file mode 100755
index 0000000..450929f
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Support/Sign.php
@@ -0,0 +1,140 @@
+ $headerValue) {
+ $key = strtolower($headerKey);
+ if (strncmp($key, 'x-acs-', 6) === 0) {
+ $array[$key] = $headerValue;
+ }
+ }
+ ksort($array);
+ $string = '';
+ foreach ($array as $sortMapKey => $sortMapValue) {
+ $string .= $sortMapKey . ':' . $sortMapValue[0] . self::$headerSeparator;
+ }
+
+ return $string;
+ }
+
+ /**
+ * @param UriInterface $uri
+ *
+ * @return string
+ */
+ private static function resourceString(UriInterface $uri)
+ {
+ return $uri->getPath() . '?' . rawurldecode($uri->getQuery());
+ }
+
+ /**
+ * @param string $method
+ * @param array $headers
+ *
+ * @return string
+ */
+ private static function headerString($method, array $headers)
+ {
+ $string = $method . self::$headerSeparator;
+ if (isset($headers['Accept'][0])) {
+ $string .= $headers['Accept'][0];
+ }
+ $string .= self::$headerSeparator;
+
+ if (isset($headers['Content-MD5'][0])) {
+ $string .= $headers['Content-MD5'][0];
+ }
+ $string .= self::$headerSeparator;
+
+ if (isset($headers['Content-Type'][0])) {
+ $string .= $headers['Content-Type'][0];
+ }
+ $string .= self::$headerSeparator;
+
+ if (isset($headers['Date'][0])) {
+ $string .= $headers['Date'][0];
+ }
+ $string .= self::$headerSeparator;
+
+ $string .= self::acsHeaderString($headers);
+
+ return $string;
+ }
+
+ /**
+ * @param string $string
+ *
+ * @return null|string|string[]
+ */
+ private static function percentEncode($string)
+ {
+ $result = urlencode($string);
+ $result = str_replace(['+', '*'], ['%20', '%2A'], $result);
+ $result = preg_replace('/%7E/', '~', $result);
+
+ return $result;
+ }
+
+ /**
+ * @param string $method
+ * @param array $parameters
+ *
+ * @return string
+ */
+ public static function rpcString($method, array $parameters)
+ {
+ ksort($parameters);
+ $canonicalized = '';
+ foreach ($parameters as $key => $value) {
+ $canonicalized .= '&' . self::percentEncode($key) . '=' . self::percentEncode($value);
+ }
+
+ return $method . '&%2F&' . self::percentEncode(substr($canonicalized, 1));
+ }
+
+ /**
+ * @param Request $request
+ *
+ * @return string
+ */
+ public static function roaString(Request $request)
+ {
+ return self::headerString($request->getMethod(), $request->getHeaders()) .
+ self::resourceString($request->getUri());
+ }
+
+ /**
+ * @param string $salt
+ *
+ * @return string
+ */
+ public static function uuid($salt)
+ {
+ return md5($salt . uniqid(md5(microtime(true)), true));
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/ArrayAccessTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/ArrayAccessTrait.php
new file mode 100755
index 0000000..d6f6908
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/ArrayAccessTrait.php
@@ -0,0 +1,57 @@
+data[$offset])) {
+ return $this->data[$offset];
+ }
+
+ $value = null;
+
+ return $value;
+ }
+
+ /**
+ * @param string $offset
+ * @param string|mixed $value
+ */
+ public function offsetSet($offset, $value)
+ {
+ $this->data[$offset] = $value;
+ }
+
+ /**
+ * @param string $offset
+ *
+ * @return bool
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->data[$offset]);
+ }
+
+ /**
+ * @param string $offset
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->data[$offset]);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/ClientTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/ClientTrait.php
new file mode 100755
index 0000000..2336d17
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/ClientTrait.php
@@ -0,0 +1,273 @@
+load();
+ }
+ $list = [];
+ foreach (\func_get_args() as $filename) {
+ $list[$filename] = (new IniCredential($filename))->load();
+ }
+
+ return $list;
+ }
+
+ /**
+ * Custom Client.
+ *
+ * @param CredentialsInterface $credentials
+ * @param SignatureInterface $signature
+ *
+ * @return Client
+ */
+ public static function client(CredentialsInterface $credentials, SignatureInterface $signature)
+ {
+ return new Client($credentials, $signature);
+ }
+
+ /**
+ * Use the AccessKey to complete the authentication.
+ *
+ * @param string $accessKeyId
+ * @param string $accessKeySecret
+ *
+ * @return AccessKeyClient
+ * @throws ClientException
+ */
+ public static function accessKeyClient($accessKeyId, $accessKeySecret)
+ {
+ if (strpos($accessKeyId, ' ') !== false) {
+ throw new ClientException(
+ 'AccessKey ID format is invalid',
+ SDK::INVALID_ARGUMENT
+ );
+ }
+
+ if (strpos($accessKeySecret, ' ') !== false) {
+ throw new ClientException(
+ 'AccessKey Secret format is invalid',
+ SDK::INVALID_ARGUMENT
+ );
+ }
+
+ return new AccessKeyClient($accessKeyId, $accessKeySecret);
+ }
+
+ /**
+ * Use the AssumeRole of the RAM account to complete the authentication.
+ *
+ * @param string $accessKeyId
+ * @param string $accessKeySecret
+ * @param string $roleArn
+ * @param string $roleSessionName
+ * @param string|array $policy
+ *
+ * @return RamRoleArnClient
+ * @throws ClientException
+ */
+ public static function ramRoleArnClient($accessKeyId, $accessKeySecret, $roleArn, $roleSessionName, $policy = '')
+ {
+ return new RamRoleArnClient($accessKeyId, $accessKeySecret, $roleArn, $roleSessionName, $policy);
+ }
+
+ /**
+ * Use the RAM role of an ECS instance to complete the authentication.
+ *
+ * @param string $roleName
+ *
+ * @return EcsRamRoleClient
+ * @throws ClientException
+ */
+ public static function ecsRamRoleClient($roleName)
+ {
+ return new EcsRamRoleClient($roleName);
+ }
+
+ /**
+ * Use the Bearer Token to complete the authentication.
+ *
+ * @param string $bearerToken
+ *
+ * @return BearerTokenClient
+ * @throws ClientException
+ */
+ public static function bearerTokenClient($bearerToken)
+ {
+ return new BearerTokenClient($bearerToken);
+ }
+
+ /**
+ * Use the STS Token to complete the authentication.
+ *
+ * @param string $accessKeyId Access key ID
+ * @param string $accessKeySecret Access Key Secret
+ * @param string $securityToken Security Token
+ *
+ * @return StsClient
+ * @throws ClientException
+ */
+ public static function stsClient($accessKeyId, $accessKeySecret, $securityToken = '')
+ {
+ return new StsClient($accessKeyId, $accessKeySecret, $securityToken);
+ }
+
+ /**
+ * Use the RSA key pair to complete the authentication (supported only on Japanese site)
+ *
+ * @param string $publicKeyId
+ * @param string $privateKeyFile
+ *
+ * @return RsaKeyPairClient
+ * @throws ClientException
+ */
+ public static function rsaKeyPairClient($publicKeyId, $privateKeyFile)
+ {
+ return new RsaKeyPairClient($publicKeyId, $privateKeyFile);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/DefaultRegionTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/DefaultRegionTrait.php
new file mode 100755
index 0000000..5d5c75a
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/DefaultRegionTrait.php
@@ -0,0 +1,66 @@
+realRegionId();
+ $network = $request->network ?: 'public';
+ $suffix = $request->endpointSuffix;
+ if ($network === 'public') {
+ $network = '';
+ }
+
+ if ($request->endpointRegional === 'regional') {
+ return "{$request->product}{$suffix}{$network}.{$regionId}.aliyuncs.com";
+ }
+
+ if ($request->endpointRegional === 'central') {
+ return "{$request->product}{$suffix}{$network}.aliyuncs.com";
+ }
+
+ throw new InvalidArgumentException('endpointRegional is invalid.');
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/HasDataTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/HasDataTrait.php
new file mode 100755
index 0000000..81a03ea
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/HasDataTrait.php
@@ -0,0 +1,317 @@
+dot->all());
+ }
+
+ /**
+ * Delete the contents of a given key or keys
+ *
+ * @param array|int|string|null $keys
+ */
+ public function clear($keys = null)
+ {
+ $this->dot->clear($keys);
+ }
+
+ /**
+ * Flatten an array with the given character as a key delimiter
+ *
+ * @param string $delimiter
+ * @param array|null $items
+ * @param string $prepend
+ *
+ * @return array
+ */
+ public function flatten($delimiter = '.', $items = null, $prepend = '')
+ {
+ return $this->dot->flatten($delimiter, $items, $prepend);
+ }
+
+ /**
+ * Return the value of a given key
+ *
+ * @param int|string|null $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ public function get($key = null, $default = null)
+ {
+ return $this->dot->get($key, $default);
+ }
+
+ /**
+ * Set a given key / value pair or pairs
+ *
+ * @param array|int|string $keys
+ * @param mixed $value
+ */
+ public function set($keys, $value = null)
+ {
+ $this->dot->set($keys, $value);
+ }
+
+ /**
+ * Check if a given key or keys are empty
+ *
+ * @param array|int|string|null $keys
+ *
+ * @return bool
+ */
+ public function isEmpty($keys = null)
+ {
+ return $this->dot->isEmpty($keys);
+ }
+
+ /**
+ * Replace all items with a given array as a reference
+ *
+ * @param array $items
+ */
+ public function setReference(array &$items)
+ {
+ $this->dot->setReference($items);
+ }
+
+ /**
+ * Return the value of a given key or all the values as JSON
+ *
+ * @param mixed $key
+ * @param int $options
+ *
+ * @return string
+ */
+ public function toJson($key = null, $options = 0)
+ {
+ return $this->dot->toJson($key, $options);
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->dot->all();
+ }
+
+ /**
+ * Check if a given key exists
+ *
+ * @param int|string $key
+ *
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ return $this->dot->has($key);
+ }
+
+ /**
+ * Return the value of a given key
+ *
+ * @param int|string $key
+ *
+ * @return mixed
+ */
+ public function offsetGet($key)
+ {
+ return $this->dot->offsetGet($key);
+ }
+
+ /**
+ * Set a given value to the given key
+ *
+ * @param int|string|null $key
+ * @param mixed $value
+ */
+ public function offsetSet($key, $value)
+ {
+ $this->dot->offsetSet($key, $value);
+ }
+
+ /**
+ * Delete the given key
+ *
+ * @param int|string $key
+ */
+ public function offsetUnset($key)
+ {
+ $this->delete($key);
+ }
+
+ /**
+ * Delete the given key or keys
+ *
+ * @param array|int|string $keys
+ */
+ public function delete($keys)
+ {
+ $this->dot->delete($keys);
+ }
+
+ /*
+ * --------------------------------------------------------------
+ * ArrayAccess interface
+ * --------------------------------------------------------------
+ */
+
+ /**
+ * Return the number of items in a given key
+ *
+ * @param int|string|null $key
+ *
+ * @return int
+ */
+ public function count($key = null)
+ {
+ return $this->dot->count($key);
+ }
+
+ /**
+ * Get an iterator for the stored items
+ *
+ * @return ArrayIterator
+ */
+ public function getIterator()
+ {
+ return $this->dot->getIterator();
+ }
+
+ /**
+ * Return items for JSON serialization
+ *
+ * @return array
+ */
+ public function jsonSerialize()
+ {
+ return $this->dot->jsonSerialize();
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return mixed|null
+ */
+ public function __get($name)
+ {
+ if (!isset($this->all()[$name])) {
+ return null;
+ }
+
+ return \json_decode(\json_encode($this->all()))->$name;
+ }
+
+ /*
+ * --------------------------------------------------------------
+ * Countable interface
+ * --------------------------------------------------------------
+ */
+
+ /**
+ * Return all the stored items
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->dot->all();
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ */
+ public function __set($name, $value)
+ {
+ $this->add($name, $value);
+ }
+
+ /**
+ * Set a given key / value pair or pairs
+ * if the key doesn't exist already
+ *
+ * @param array|int|string $keys
+ * @param mixed $value
+ */
+ public function add($keys, $value = null)
+ {
+ $this->dot->add($keys, $value);
+ }
+
+
+ /*
+ * --------------------------------------------------------------
+ * ObjectAccess
+ * --------------------------------------------------------------
+ */
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return $this->has($name);
+ }
+
+ /**
+ * Check if a given key or keys exists
+ *
+ * @param array|int|string $keys
+ *
+ * @return bool
+ */
+ public function has($keys)
+ {
+ return $this->dot->has($keys);
+ }
+
+ /**
+ * @param $name
+ *
+ * @return void
+ */
+ public function __unset($name)
+ {
+ $this->delete($name);
+ }
+
+ /**
+ * @param array $data
+ */
+ protected function dot(array $data = [])
+ {
+ $this->dot = new Dot($data);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/HistoryTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/HistoryTrait.php
new file mode 100755
index 0000000..f70bb1d
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/HistoryTrait.php
@@ -0,0 +1,68 @@
+options['timeout'] = ClientFilter::timeout($seconds);
+
+ return $this;
+ }
+
+ /**
+ * @param int $milliseconds
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function timeoutMilliseconds($milliseconds)
+ {
+ ClientFilter::milliseconds($milliseconds);
+ $seconds = $milliseconds / 1000;
+
+ return $this->timeout($seconds);
+ }
+
+ /**
+ * @param int|float $seconds
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function connectTimeout($seconds)
+ {
+ $this->options['connect_timeout'] = ClientFilter::connectTimeout($seconds);
+
+ return $this;
+ }
+
+ /**
+ * @param int $milliseconds
+ *
+ * @return $this
+ * @throws ClientException
+ */
+ public function connectTimeoutMilliseconds($milliseconds)
+ {
+ ClientFilter::milliseconds($milliseconds);
+ $seconds = $milliseconds / 1000;
+
+ return $this->connectTimeout($seconds);
+ }
+
+ /**
+ * @param bool $debug
+ *
+ * @return $this
+ */
+ public function debug($debug)
+ {
+ $this->options['debug'] = $debug;
+
+ return $this;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ *
+ * @param array $cert
+ *
+ * @return $this
+ */
+ public function cert($cert)
+ {
+ $this->options['cert'] = $cert;
+
+ return $this;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ *
+ * @param array|string $proxy
+ *
+ * @return $this
+ */
+ public function proxy($proxy)
+ {
+ $this->options['proxy'] = $proxy;
+
+ return $this;
+ }
+
+ /**
+ * @param mixed $verify
+ *
+ * @return $this
+ */
+ public function verify($verify)
+ {
+ $this->options['verify'] = $verify;
+
+ return $this;
+ }
+
+ /**
+ * @param array $options
+ *
+ * @return $this
+ */
+ public function options(array $options)
+ {
+ if ($options !== []) {
+ $this->options = Arrays::merge([$this->options, $options]);
+ }
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/LogTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/LogTrait.php
new file mode 100755
index 0000000..c2b778f
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/LogTrait.php
@@ -0,0 +1,64 @@
+data[$name])) {
+ return null;
+ }
+
+ return \json_decode(\json_encode($this->data))->$name;
+ }
+
+ /**
+ * @param string $name
+ * @param mixed $value
+ */
+ public function __set($name, $value)
+ {
+ $this->data[$name] = $value;
+ }
+
+ /**
+ * @param string $name
+ *
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return isset($this->data[$name]);
+ }
+
+ /**
+ * @param $name
+ *
+ * @return void
+ */
+ public function __unset($name)
+ {
+ unset($this->data[$name]);
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/RegionTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/RegionTrait.php
new file mode 100755
index 0000000..da6bee4
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/RegionTrait.php
@@ -0,0 +1,33 @@
+regionId = ClientFilter::regionId($regionId);
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/alibabacloud/client/src/Traits/RequestTrait.php b/app/Common/extend/alibabacloud/client/src/Traits/RequestTrait.php
new file mode 100755
index 0000000..afcb9a4
--- /dev/null
+++ b/app/Common/extend/alibabacloud/client/src/Traits/RequestTrait.php
@@ -0,0 +1,90 @@
+"; ;
+$accessKeySecret = "<您从OSS获得的AccessKeySecret>";
+$endpoint = "<您选定的OSS数据中心访问域名,例如oss-cn-hangzhou.aliyuncs.com>";
+try {
+ $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
+} catch (OssException $e) {
+ print $e->getMessage();
+}
+```
+
+### 文件操作
+
+文件(又称对象,Object)是OSS中最基本的数据单元,您可以把它简单地理解为文件,用下面代码可以实现一个Object的上传:
+
+```php
+";
+$object = "<您使用的Object名字,注意命名规范>";
+$content = "Hello, OSS!"; // 上传的文件内容
+try {
+ $ossClient->putObject($bucket, $object, $content);
+} catch (OssException $e) {
+ print $e->getMessage();
+}
+```
+
+### 存储空间操作
+
+存储空间(又称Bucket)是一个用户用来管理所存储Object的存储空间,对于用户来说是一个管理Object的单元,所有的Object都必须隶属于某个Bucket。您可以按照下面的代码新建一个Bucket:
+
+```php
+";
+try {
+ $ossClient->createBucket($bucket);
+} catch (OssException $e) {
+ print $e->getMessage();
+}
+```
+
+### 返回结果处理
+
+OssClient提供的接口返回返回数据分为两种:
+
+* Put,Delete类接口,接口返回null,如果没有OssException,即可认为操作成功
+* Get,List类接口,接口返回对应的数据,如果没有OssException,即可认为操作成功,举个例子:
+
+```php
+listBuckets();
+$bucketList = $bucketListInfo->getBucketList();
+foreach($bucketList as $bucket) {
+ print($bucket->getLocation() . "\t" . $bucket->getName() . "\t" . $bucket->getCreatedate() . "\n");
+}
+```
+上面代码中的$bucketListInfo的数据类型是 `OSS\Model\BucketListInfo`
+
+
+### 运行Sample程序
+
+1. 修改 `samples/Config.php`, 补充配置信息
+2. 执行 `cd samples/ && php RunAll.php`
+
+### 运行单元测试
+
+1. 执行`composer install`下载依赖的库
+2. 设置环境变量
+
+ export OSS_ACCESS_KEY_ID=access-key-id
+ export OSS_ACCESS_KEY_SECRET=access-key-secret
+ export OSS_ENDPOINT=endpoint
+ export OSS_BUCKET=bucket-name
+
+3. 执行 `php vendor/bin/phpunit`
+
+## 贡献代码
+
+0. 开发流程参考:https://github.com/rockuw/oss-sdk-status#development-oss-members-only
+1. 提交代码后,确保travis CI是PASS的
+2. 每发布一个新的版本:
+ - 运行`build-phar.sh`生成相应的phar包(需要安装[phar-composer][phar-composer])
+ - 在[Release页面][releases-page]发布一个版本
+ - 将生成的phar包上传到相应的Release下面
+
+## 联系我们
+
+- [阿里云OSS官方网站](http://oss.aliyun.com)
+- [阿里云OSS官方论坛](http://bbs.aliyun.com)
+- [阿里云OSS官方文档中心](http://www.aliyun.com/product/oss#Docs)
+- 阿里云官方技术支持:[提交工单](https://workorder.console.aliyun.com/#/ticket/createIndex)
+
+[releases-page]: https://github.com/aliyun/aliyun-oss-php-sdk/releases
+[phar-composer]: https://github.com/clue/phar-composer
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/autoload.php b/app/Common/extend/aliyuncs/oss-sdk-php/autoload.php
new file mode 100755
index 0000000..ec13201
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/autoload.php
@@ -0,0 +1,11 @@
+=5.3"
+ },
+ "require-dev" : {
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "~1.0"
+ },
+ "minimum-stability": "stable",
+ "autoload": {
+ "psr-4": {"OSS\\": "src/OSS"}
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/example.jpg b/app/Common/extend/aliyuncs/oss-sdk-php/example.jpg
new file mode 100755
index 0000000..ffd46a2
Binary files /dev/null and b/app/Common/extend/aliyuncs/oss-sdk-php/example.jpg differ
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/index.php b/app/Common/extend/aliyuncs/oss-sdk-php/index.php
new file mode 100755
index 0000000..cdc28bc
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/index.php
@@ -0,0 +1,3 @@
+
+
+
+
+
+
+ ./src
+
+
+
+
+
+
+
+ ./tests
+ ./tests/OSS/Tests/BucketCnameTest.php
+
+
+
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/Bucket.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Bucket.php
new file mode 100755
index 0000000..bd16e65
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Bucket.php
@@ -0,0 +1,167 @@
+createBucket($bucket, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE);
+Common::println("bucket $bucket created");
+
+// 判断Bucket是否存在
+$doesExist = $ossClient->doesBucketExist($bucket);
+Common::println("bucket $bucket exist? " . ($doesExist ? "yes" : "no"));
+
+// 获取Bucket列表
+$bucketListInfo = $ossClient->listBuckets();
+
+// 设置bucket的ACL
+$ossClient->putBucketAcl($bucket, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE);
+Common::println("bucket $bucket acl put");
+// 获取bucket的ACL
+$acl = $ossClient->getBucketAcl($bucket);
+Common::println("bucket $bucket acl get: " . $acl);
+
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+createBucket($ossClient, $bucket);
+doesBucketExist($ossClient, $bucket);
+deleteBucket($ossClient, $bucket);
+putBucketAcl($ossClient, $bucket);
+getBucketAcl($ossClient, $bucket);
+listBuckets($ossClient);
+
+/**
+ * 创建一个存储空间
+ * acl 指的是bucket的访问控制权限,有三种,私有读写,公共读私有写,公共读写。
+ * 私有读写就是只有bucket的拥有者或授权用户才有权限操作
+ * 三种权限分别对应 (OssClient::OSS_ACL_TYPE_PRIVATE,OssClient::OSS_ACL_TYPE_PUBLIC_READ, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE)
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 要创建的存储空间名称
+ * @return null
+ */
+function createBucket($ossClient, $bucket)
+{
+ try {
+ $ossClient->createBucket($bucket, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 判断Bucket是否存在
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ */
+function doesBucketExist($ossClient, $bucket)
+{
+ try {
+ $res = $ossClient->doesBucketExist($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ if ($res === true) {
+ print(__FUNCTION__ . ": OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": FAILED" . "\n");
+ }
+}
+
+/**
+ * 删除bucket,如果bucket不为空则bucket无法删除成功, 不为空表示bucket既没有object,也没有未完成的multipart上传时的parts
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 待删除的存储空间名称
+ * @return null
+ */
+function deleteBucket($ossClient, $bucket)
+{
+ try {
+ $ossClient->deleteBucket($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 设置bucket的acl配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function putBucketAcl($ossClient, $bucket)
+{
+ $acl = OssClient::OSS_ACL_TYPE_PRIVATE;
+ try {
+ $ossClient->putBucketAcl($bucket, $acl);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * 获取bucket的acl配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getBucketAcl($ossClient, $bucket)
+{
+ try {
+ $res = $ossClient->getBucketAcl($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ print('acl: ' . $res);
+}
+
+
+/**
+ * 列出用户所有的Bucket
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @return null
+ */
+function listBuckets($ossClient)
+{
+ $bucketList = null;
+ try {
+ $bucketListInfo = $ossClient->listBuckets();
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ $bucketList = $bucketListInfo->getBucketList();
+ foreach ($bucketList as $bucket) {
+ print($bucket->getLocation() . "\t" . $bucket->getName() . "\t" . $bucket->getCreatedate() . "\n");
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketCors.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketCors.php
new file mode 100755
index 0000000..cc5c0b9
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketCors.php
@@ -0,0 +1,108 @@
+addAllowedHeader("x-oss-header");
+$rule->addAllowedOrigin("http://www.b.com");
+$rule->addAllowedMethod("POST");
+$rule->setMaxAgeSeconds(10);
+$corsConfig->addRule($rule);
+$ossClient->putBucketCors($bucket, $corsConfig);
+Common::println("bucket $bucket corsConfig created:" . $corsConfig->serializeToXml());
+
+// 获取cors配置
+$corsConfig = $ossClient->getBucketCors($bucket);
+Common::println("bucket $bucket corsConfig fetched:" . $corsConfig->serializeToXml());
+
+// 删除cors配置
+$ossClient->deleteBucketCors($bucket);
+Common::println("bucket $bucket corsConfig deleted");
+
+//******************************* 完整用法参考下面函数 *****************************************************
+
+putBucketCors($ossClient, $bucket);
+getBucketCors($ossClient, $bucket);
+deleteBucketCors($ossClient, $bucket);
+getBucketCors($ossClient, $bucket);
+
+/**
+ * 设置bucket的cors配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function putBucketCors($ossClient, $bucket)
+{
+ $corsConfig = new CorsConfig();
+ $rule = new CorsRule();
+ $rule->addAllowedHeader("x-oss-header");
+ $rule->addAllowedOrigin("http://www.b.com");
+ $rule->addAllowedMethod("POST");
+ $rule->setMaxAgeSeconds(10);
+ $corsConfig->addRule($rule);
+
+ try {
+ $ossClient->putBucketCors($bucket, $corsConfig);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 获取并打印bucket的cors配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getBucketCors($ossClient, $bucket)
+{
+ $corsConfig = null;
+ try {
+ $corsConfig = $ossClient->getBucketCors($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ print($corsConfig->serializeToXml() . "\n");
+}
+
+/**
+ * 删除bucket的所有的cors配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteBucketCors($ossClient, $bucket)
+{
+ try {
+ $ossClient->deleteBucketCors($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketLifecycle.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketLifecycle.php
new file mode 100755
index 0000000..ec0c37f
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketLifecycle.php
@@ -0,0 +1,109 @@
+addRule($lifecycleRule);
+$ossClient->putBucketLifecycle($bucket, $lifecycleConfig);
+Common::println("bucket $bucket lifecycleConfig created:" . $lifecycleConfig->serializeToXml());
+
+//获取lifecycle规则
+$lifecycleConfig = $ossClient->getBucketLifecycle($bucket);
+Common::println("bucket $bucket lifecycleConfig fetched:" . $lifecycleConfig->serializeToXml());
+
+//删除bucket的lifecycle配置
+$ossClient->deleteBucketLifecycle($bucket);
+Common::println("bucket $bucket lifecycleConfig deleted");
+
+
+//***************************** 完整用法参考下面函数 ***********************************************
+
+putBucketLifecycle($ossClient, $bucket);
+getBucketLifecycle($ossClient, $bucket);
+deleteBucketLifecycle($ossClient, $bucket);
+getBucketLifecycle($ossClient, $bucket);
+
+/**
+ * 设置bucket的生命周期配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function putBucketLifecycle($ossClient, $bucket)
+{
+ $lifecycleConfig = new LifecycleConfig();
+ $actions = array();
+ $actions[] = new LifecycleAction(OssClient::OSS_LIFECYCLE_EXPIRATION, OssClient::OSS_LIFECYCLE_TIMING_DAYS, 3);
+ $lifecycleRule = new LifecycleRule("delete obsoleted files", "obsoleted/", "Enabled", $actions);
+ $lifecycleConfig->addRule($lifecycleRule);
+ $actions = array();
+ $actions[] = new LifecycleAction(OssClient::OSS_LIFECYCLE_EXPIRATION, OssClient::OSS_LIFECYCLE_TIMING_DATE, '2022-10-12T00:00:00.000Z');
+ $lifecycleRule = new LifecycleRule("delete temporary files", "temporary/", "Enabled", $actions);
+ $lifecycleConfig->addRule($lifecycleRule);
+ try {
+ $ossClient->putBucketLifecycle($bucket, $lifecycleConfig);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 获取bucket的生命周期配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getBucketLifecycle($ossClient, $bucket)
+{
+ $lifecycleConfig = null;
+ try {
+ $lifecycleConfig = $ossClient->getBucketLifecycle($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ print($lifecycleConfig->serializeToXml() . "\n");
+}
+
+/**
+ * 删除bucket的生命周期配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteBucketLifecycle($ossClient, $bucket)
+{
+ try {
+ $ossClient->deleteBucketLifecycle($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketLogging.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketLogging.php
new file mode 100755
index 0000000..406e1d4
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketLogging.php
@@ -0,0 +1,95 @@
+putBucketLogging($bucket, $bucket, "access.log", array());
+Common::println("bucket $bucket lifecycleConfig created");
+
+// 获取Bucket访问日志记录规则
+$loggingConfig = $ossClient->getBucketLogging($bucket, array());
+Common::println("bucket $bucket lifecycleConfig fetched:" . $loggingConfig->serializeToXml());
+
+// 删除Bucket访问日志记录规则
+$loggingConfig = $ossClient->getBucketLogging($bucket, array());
+Common::println("bucket $bucket lifecycleConfig deleted");
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+putBucketLogging($ossClient, $bucket);
+getBucketLogging($ossClient, $bucket);
+deleteBucketLogging($ossClient, $bucket);
+getBucketLogging($ossClient, $bucket);
+
+/**
+ * 设置bucket的Logging配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function putBucketLogging($ossClient, $bucket)
+{
+ $option = array();
+ //访问日志存放在本bucket下
+ $targetBucket = $bucket;
+ $targetPrefix = "access.log";
+
+ try {
+ $ossClient->putBucketLogging($bucket, $targetBucket, $targetPrefix, $option);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 获取bucket的Logging配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getBucketLogging($ossClient, $bucket)
+{
+ $loggingConfig = null;
+ $options = array();
+ try {
+ $loggingConfig = $ossClient->getBucketLogging($bucket, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ print($loggingConfig->serializeToXml() . "\n");
+}
+
+/**
+ * 删除bucket的Logging配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteBucketLogging($ossClient, $bucket)
+{
+ try {
+ $ossClient->deleteBucketLogging($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketReferer.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketReferer.php
new file mode 100755
index 0000000..3828df6
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketReferer.php
@@ -0,0 +1,101 @@
+setAllowEmptyReferer(true);
+$refererConfig->addReferer("www.aliiyun.com");
+$refererConfig->addReferer("www.aliiyuncs.com");
+$ossClient->putBucketReferer($bucket, $refererConfig);
+Common::println("bucket $bucket refererConfig created:" . $refererConfig->serializeToXml());
+//获取Referer白名单
+$refererConfig = $ossClient->getBucketReferer($bucket);
+Common::println("bucket $bucket refererConfig fetched:" . $refererConfig->serializeToXml());
+
+//删除referer白名单
+$refererConfig = new RefererConfig();
+$ossClient->putBucketReferer($bucket, $refererConfig);
+Common::println("bucket $bucket refererConfig deleted");
+
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+putBucketReferer($ossClient, $bucket);
+getBucketReferer($ossClient, $bucket);
+deleteBucketReferer($ossClient, $bucket);
+getBucketReferer($ossClient, $bucket);
+
+/**
+ * 设置bucket的防盗链配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function putBucketReferer($ossClient, $bucket)
+{
+ $refererConfig = new RefererConfig();
+ $refererConfig->setAllowEmptyReferer(true);
+ $refererConfig->addReferer("www.aliiyun.com");
+ $refererConfig->addReferer("www.aliiyuncs.com");
+ try {
+ $ossClient->putBucketReferer($bucket, $refererConfig);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 获取bucket的防盗链配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getBucketReferer($ossClient, $bucket)
+{
+ $refererConfig = null;
+ try {
+ $refererConfig = $ossClient->getBucketReferer($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ print($refererConfig->serializeToXml() . "\n");
+}
+
+/**
+ * 删除bucket的防盗链配置
+ * Referer白名单不能直接清空,只能通过重新设置来覆盖之前的规则。
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteBucketReferer($ossClient, $bucket)
+{
+ $refererConfig = new RefererConfig();
+ try {
+ $ossClient->putBucketReferer($bucket, $refererConfig);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketWebsite.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketWebsite.php
new file mode 100755
index 0000000..54706f8
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/BucketWebsite.php
@@ -0,0 +1,92 @@
+putBucketWebsite($bucket, $websiteConfig);
+Common::println("bucket $bucket websiteConfig created:" . $websiteConfig->serializeToXml());
+
+// 查看Bucket的静态网站托管状态
+$websiteConfig = $ossClient->getBucketWebsite($bucket);
+Common::println("bucket $bucket websiteConfig fetched:" . $websiteConfig->serializeToXml());
+
+// 删除Bucket的静态网站托管模式
+$ossClient->deleteBucketWebsite($bucket);
+Common::println("bucket $bucket websiteConfig deleted");
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+putBucketWebsite($ossClient, $bucket);
+getBucketWebsite($ossClient, $bucket);
+deleteBucketWebsite($ossClient, $bucket);
+getBucketWebsite($ossClient, $bucket);
+
+/**
+ * 设置bucket的静态网站托管模式配置
+ *
+ * @param $ossClient OssClient
+ * @param $bucket string 存储空间名称
+ * @return null
+ */
+function putBucketWebsite($ossClient, $bucket)
+{
+ $websiteConfig = new WebsiteConfig("index.html", "error.html");
+ try {
+ $ossClient->putBucketWebsite($bucket, $websiteConfig);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 获取bucket的静态网站托管状态
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getBucketWebsite($ossClient, $bucket)
+{
+ $websiteConfig = null;
+ try {
+ $websiteConfig = $ossClient->getBucketWebsite($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ print($websiteConfig->serializeToXml() . "\n");
+}
+
+/**
+ * 删除bucket的静态网站托管模式配置
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteBucketWebsite($ossClient, $bucket)
+{
+ try {
+ $ossClient->deleteBucketWebsite($bucket);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/Callback.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Callback.php
new file mode 100755
index 0000000..8612a1c
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Callback.php
@@ -0,0 +1,83 @@
+ $url,
+ OssClient::OSS_CALLBACK_VAR => $var
+ );
+$result = $ossClient->putObject($bucket, "b.file", "random content", $options);
+Common::println($result['body']);
+Common::println($result['info']['http_code']);
+
+/**
+ * completeMultipartUpload 使用callback上传内容到oss文件
+ * callbackurl参数指定请求回调的服务器url
+ * callbackbodytype参数可为application/json或application/x-www-form-urlencoded, 可选参数,默认为application/x-www-form-urlencoded
+ * OSS_CALLBACK_VAR参数可以不设置
+ */
+$object = "multipart-callback-test.txt";
+$copiedObject = "multipart-callback-test.txt.copied";
+$ossClient->putObject($bucket, $copiedObject, file_get_contents(__FILE__));
+
+/**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+$upload_id = $ossClient->initiateMultipartUpload($bucket, $object);
+
+/**
+ * step 2. uploadPartCopy
+ */
+$copyId = 1;
+$eTag = $ossClient->uploadPartCopy($bucket, $copiedObject, $bucket, $object, $copyId, $upload_id);
+$upload_parts[] = array(
+ 'PartNumber' => $copyId,
+ 'ETag' => $eTag,
+ );
+$listPartsInfo = $ossClient->listParts($bucket, $object, $upload_id);
+
+/**
+ * step 3.
+ */
+$json =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size},\"x:var1\":${x:var1},\"x:var2\":${x:var2}}",
+ "callbackBodyType":"application/json"
+ }';
+$var =
+ '{
+ "x:var1":"value1",
+ "x:var2":"值2"
+ }';
+$options = array(OssClient::OSS_CALLBACK => $json,
+ OssClient::OSS_CALLBACK_VAR => $var);
+
+$result = $ossClient->completeMultipartUpload($bucket, $object, $upload_id, $upload_parts, $options);
+Common::println($result['body']);
+Common::println($result['info']['http_code']);
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/Common.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Common.php
new file mode 100755
index 0000000..f419d17
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Common.php
@@ -0,0 +1,84 @@
+getMessage() . "\n");
+ return null;
+ }
+ return $ossClient;
+ }
+
+ public static function getBucketName()
+ {
+ return self::bucket;
+ }
+
+ /**
+ * 工具方法,创建一个存储空间,如果发生异常直接exit
+ */
+ public static function createBucket()
+ {
+ $ossClient = self::getOssClient();
+ if (is_null($ossClient)) exit(1);
+ $bucket = self::getBucketName();
+ $acl = OssClient::OSS_ACL_TYPE_PUBLIC_READ;
+ try {
+ $ossClient->createBucket($bucket, $acl);
+ } catch (OssException $e) {
+
+ $message = $e->getMessage();
+ if (\OSS\Core\OssUtil::startsWith($message, 'http status: 403')) {
+ echo "Please Check your AccessKeyId and AccessKeySecret" . "\n";
+ exit(0);
+ } elseif (strpos($message, "BucketAlreadyExists") !== false) {
+ echo "Bucket already exists. Please check whether the bucket belongs to you, or it was visited with correct endpoint. " . "\n";
+ exit(0);
+ }
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ }
+
+ public static function println($message)
+ {
+ if (!empty($message)) {
+ echo strval($message) . "\n";
+ }
+ }
+}
+
+Common::createBucket();
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/Config.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Config.php
new file mode 100755
index 0000000..35c0dc7
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Config.php
@@ -0,0 +1,15 @@
+uploadFile($bucketName, $object, "example.jpg");
+
+// 图片缩放
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/resize,m_fixed,h_100,w_100", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("imageResize",$download_file);
+
+// 图片裁剪
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/crop,w_100,h_100,x_100,y_100,r_1", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("iamgeCrop", $download_file);
+
+// 图片旋转
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/rotate,90", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("imageRotate", $download_file);
+
+// 图片锐化
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/sharpen,100", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("imageSharpen", $download_file);
+
+// 图片水印
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("imageWatermark", $download_file);
+
+// 图片格式转换
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/format,png", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("imageFormat", $download_file);
+
+// 获取图片信息
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $download_file,
+ OssClient::OSS_PROCESS => "image/info", );
+$ossClient->getObject($bucketName, $object, $options);
+printImage("imageInfo", $download_file);
+
+
+/**
+ * 生成一个带签名的可用于浏览器直接打开的url, URL的有效期是3600秒
+ */
+ $timeout = 3600;
+$options = array(
+ OssClient::OSS_PROCESS => "image/resize,m_lfit,h_100,w_100",
+ );
+$signedUrl = $ossClient->signUrl($bucketName, $object, $timeout, "GET", $options);
+Common::println("rtmp url: \n" . $signedUrl);
+
+//最后删除上传的$object
+$ossClient->deleteObject($bucketName, $object);
+
+function printImage($func, $imageFile)
+{
+ $array = getimagesize($imageFile);
+ Common::println("$func, image width: " . $array[0]);
+ Common::println("$func, image height: " . $array[1]);
+ Common::println("$func, image type: " . ($array[2] === 2 ? 'jpg' : 'png'));
+ Common::println("$func, image size: " . ceil(filesize($imageFile)));
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/LiveChannel.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/LiveChannel.php
new file mode 100755
index 0000000..2f7d3a8
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/LiveChannel.php
@@ -0,0 +1,125 @@
+ 'live channel test',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+$info = $ossClient->putBucketLiveChannel($bucket, 'test_rtmp_live', $config);
+Common::println("bucket $bucket liveChannel created:\n" .
+"live channel name: ". $info->getName() . "\n" .
+"live channel description: ". $info->getDescription() . "\n" .
+"publishurls: ". $info->getPublishUrls()[0] . "\n" .
+"playurls: ". $info->getPlayUrls()[0] . "\n");
+
+/**
+ 对创建好的频道,可以使用listBucketLiveChannels来进行列举已达到管理的目的。
+ prefix可以按照前缀过滤list出来的频道。
+ max_keys表示迭代器内部一次list出来的频道的最大数量,这个值最大不能超过1000,不填写的话默认为100。
+ */
+$list = $ossClient->listBucketLiveChannels($bucket);
+Common::println("bucket $bucket listLiveChannel:\n" .
+"list live channel prefix: ". $list->getPrefix() . "\n" .
+"list live channel marker: ". $list->getMarker() . "\n" .
+"list live channel maxkey: ". $list->getMaxKeys() . "\n" .
+"list live channel IsTruncated: ". $list->getIsTruncated() . "\n" .
+"list live channel getNextMarker: ". $list->getNextMarker() . "\n");
+
+foreach($list->getChannelList() as $list)
+{
+ Common::println("bucket $bucket listLiveChannel:\n" .
+ "list live channel IsTruncated: ". $list->getName() . "\n" .
+ "list live channel Description: ". $list->getDescription() . "\n" .
+ "list live channel Status: ". $list->getStatus() . "\n" .
+ "list live channel getNextMarker: ". $list->getLastModified() . "\n");
+}
+/**
+ 创建直播频道之后拿到推流用的play_url(rtmp推流的url,如果Bucket不是公共读写权限那么还需要带上签名,见下文示例)和推流用的publish_url(推流产生的m3u8文件的url)
+ */
+$play_url = $ossClient->signRtmpUrl($bucket, "test_rtmp_live", 3600, array('params' => array('playlistName' => 'playlist.m3u8')));
+Common::println("bucket $bucket rtmp url: \n" . $play_url);
+$play_url = $ossClient->signRtmpUrl($bucket, "test_rtmp_live", 3600);
+Common::println("bucket $bucket rtmp url: \n" . $play_url);
+
+/**
+ 创建好直播频道,如果想把这个频道禁用掉(断掉正在推的流或者不再允许向一个地址推流),应该使用putLiveChannelStatus接口,将频道的status改成“Disabled”,如果要将一个禁用状态的频道启用,那么也是调用这个接口,将status改成“Enabled”
+ */
+$resp = $ossClient->putLiveChannelStatus($bucket, "test_rtmp_live", "enabled");
+
+/**
+ 创建好直播频道之后调用getLiveChannelInfo可以得到频道相关的信息
+ */
+$info = $ossClient->getLiveChannelInfo($bucket, 'test_rtmp_live');
+Common::println("bucket $bucket LiveChannelInfo:\n" .
+"live channel info description: ". $info->getDescription() . "\n" .
+"live channel info status: ". $info->getStatus() . "\n" .
+"live channel info type: ". $info->getType() . "\n" .
+"live channel info fragDuration: ". $info->getFragDuration() . "\n" .
+"live channel info fragCount: ". $info->getFragCount() . "\n" .
+"live channel info playListName: ". $info->getPlayListName() . "\n");
+
+/**
+ 如果想查看一个频道历史推流记录,可以调用getLiveChannelHistory。目前最多可以看到10次推流的记录
+ */
+$history = $ossClient->getLiveChannelHistory($bucket, "test_rtmp_live");
+if (count($history->getLiveRecordList()) != 0)
+{
+ foreach($history->getLiveRecordList() as $recordList)
+ {
+ Common::println("bucket $bucket liveChannelHistory:\n" .
+ "live channel history startTime: ". $recordList->getStartTime() . "\n" .
+ "live channel history endTime: ". $recordList->getEndTime() . "\n" .
+ "live channel history remoteAddr: ". $recordList->getRemoteAddr() . "\n");
+ }
+}
+
+/**
+ 对于正在推流的频道调用get_live_channel_stat可以获得流的状态信息。
+ 如果频道正在推流,那么stat_result中的所有字段都有意义。
+ 如果频道闲置或者处于“Disabled”状态,那么status为“Idle”或“Disabled”,其他字段无意义。
+ */
+$status = $ossClient->getLiveChannelStatus($bucket, "test_rtmp_live");
+Common::println("bucket $bucket listLiveChannel:\n" .
+"live channel status status: ". $status->getStatus() . "\n" .
+"live channel status ConnectedTime: ". $status->getConnectedTime() . "\n" .
+"live channel status VideoWidth: ". $status->getVideoWidth() . "\n" .
+"live channel status VideoHeight: ". $status->getVideoHeight() . "\n" .
+"live channel status VideoFrameRate: ". $status->getVideoFrameRate() . "\n" .
+"live channel status VideoBandwidth: ". $status->getVideoBandwidth() . "\n" .
+"live channel status VideoCodec: ". $status->getVideoCodec() . "\n" .
+"live channel status AudioBandwidth: ". $status->getAudioBandwidth() . "\n" .
+"live channel status AudioSampleRate: ". $status->getAudioSampleRate() . "\n" .
+"live channel status AdioCodec: ". $status->getAudioCodec() . "\n");
+
+/**
+ * 如果希望利用直播推流产生的ts文件生成一个点播列表,可以使用postVodPlaylist方法。
+ * 指定起始时间为当前时间减去60秒,结束时间为当前时间,这意味着将生成一个长度为60秒的点播视频。
+ * 播放列表指定为“vod_playlist.m3u8”,也就是说这个接口调用成功之后会在OSS上生成一个名叫“vod_playlist.m3u8”的播放列表文件。
+ */
+$current_time = time();
+$ossClient->postVodPlaylist($bucket,
+ "test_rtmp_live", "vod_playlist.m3u8",
+ array('StartTime' => $current_time - 60,
+ 'EndTime' => $current_time)
+);
+
+/**
+ * 如果一个直播频道已经不打算再使用了,那么可以调用delete_live_channel来删除频道。
+ */
+$ossClient->deleteBucketLiveChannel($bucket, "test_rtmp_live");
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/MultipartUpload.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/MultipartUpload.php
new file mode 100755
index 0000000..e8d69a3
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/MultipartUpload.php
@@ -0,0 +1,182 @@
+multiuploadFile($bucket, "file.php", __FILE__, array());
+Common::println("local file " . __FILE__ . " is uploaded to the bucket $bucket, file.php");
+
+
+// 上传本地目录到bucket内的targetdir子目录中
+$ossClient->uploadDir($bucket, "targetdir", __DIR__);
+Common::println("local dir " . __DIR__ . " is uploaded to the bucket $bucket, targetdir/");
+
+
+// 列出当前未完成的分片上传
+$listMultipartUploadInfo = $ossClient->listMultipartUploads($bucket, array());
+
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+multiuploadFile($ossClient, $bucket);
+putObjectByRawApis($ossClient, $bucket);
+uploadDir($ossClient, $bucket);
+listMultipartUploads($ossClient, $bucket);
+
+/**
+ * 通过multipart上传文件
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function multiuploadFile($ossClient, $bucket)
+{
+ $object = "test/multipart-test.txt";
+ $file = __FILE__;
+ $options = array();
+
+ try {
+ $ossClient->multiuploadFile($bucket, $object, $file, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 使用基本的api分阶段进行分片上传
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @throws OssException
+ */
+function putObjectByRawApis($ossClient, $bucket)
+{
+ $object = "test/multipart-test.txt";
+ /**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+ try {
+ $uploadId = $ossClient->initiateMultipartUpload($bucket, $object);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": initiateMultipartUpload FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": initiateMultipartUpload OK" . "\n");
+ /*
+ * step 2. 上传分片
+ */
+ $partSize = 10 * 1024 * 1024;
+ $uploadFile = __FILE__;
+ $uploadFileSize = filesize($uploadFile);
+ $pieces = $ossClient->generateMultiuploadParts($uploadFileSize, $partSize);
+ $responseUploadPart = array();
+ $uploadPosition = 0;
+ $isCheckMd5 = true;
+ foreach ($pieces as $i => $piece) {
+ $fromPos = $uploadPosition + (integer)$piece[$ossClient::OSS_SEEK_TO];
+ $toPos = (integer)$piece[$ossClient::OSS_LENGTH] + $fromPos - 1;
+ $upOptions = array(
+ $ossClient::OSS_FILE_UPLOAD => $uploadFile,
+ $ossClient::OSS_PART_NUM => ($i + 1),
+ $ossClient::OSS_SEEK_TO => $fromPos,
+ $ossClient::OSS_LENGTH => $toPos - $fromPos + 1,
+ $ossClient::OSS_CHECK_MD5 => $isCheckMd5,
+ );
+ if ($isCheckMd5) {
+ $contentMd5 = OssUtil::getMd5SumForFile($uploadFile, $fromPos, $toPos);
+ $upOptions[$ossClient::OSS_CONTENT_MD5] = $contentMd5;
+ }
+ //2. 将每一分片上传到OSS
+ try {
+ $responseUploadPart[] = $ossClient->uploadPart($bucket, $object, $uploadId, $upOptions);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ printf(__FUNCTION__ . ": initiateMultipartUpload, uploadPart - part#{$i} OK\n");
+ }
+ $uploadParts = array();
+ foreach ($responseUploadPart as $i => $eTag) {
+ $uploadParts[] = array(
+ 'PartNumber' => ($i + 1),
+ 'ETag' => $eTag,
+ );
+ }
+ /**
+ * step 3. 完成上传
+ */
+ try {
+ $ossClient->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": completeMultipartUpload FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ printf(__FUNCTION__ . ": completeMultipartUpload OK\n");
+}
+
+/**
+ * 按照目录上传文件
+ *
+ * @param OssClient $ossClient OssClient
+ * @param string $bucket 存储空间名称
+ *
+ */
+function uploadDir($ossClient, $bucket)
+{
+ $localDirectory = ".";
+ $prefix = "samples/codes";
+ try {
+ $ossClient->uploadDir($bucket, $prefix, $localDirectory);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ printf(__FUNCTION__ . ": completeMultipartUpload OK\n");
+}
+
+/**
+ * 获取当前未完成的分片上传列表
+ *
+ * @param $ossClient OssClient
+ * @param $bucket string
+ */
+function listMultipartUploads($ossClient, $bucket)
+{
+ $options = array(
+ 'max-uploads' => 100,
+ 'key-marker' => '',
+ 'prefix' => '',
+ 'upload-id-marker' => ''
+ );
+ try {
+ $listMultipartUploadInfo = $ossClient->listMultipartUploads($bucket, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": listMultipartUploads FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ printf(__FUNCTION__ . ": listMultipartUploads OK\n");
+ $listUploadInfo = $listMultipartUploadInfo->getUploads();
+ var_dump($listUploadInfo);
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/Object.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Object.php
new file mode 100755
index 0000000..68e1ed3
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/Object.php
@@ -0,0 +1,451 @@
+putObject($bucket, "b.file", "hi, oss");
+Common::println("b.file is created");
+Common::println($result['x-oss-request-id']);
+Common::println($result['etag']);
+Common::println($result['content-md5']);
+Common::println($result['body']);
+
+// 上传本地文件
+$result = $ossClient->uploadFile($bucket, "c.file", __FILE__);
+Common::println("c.file is created");
+Common::println("b.file is created");
+Common::println($result['x-oss-request-id']);
+Common::println($result['etag']);
+Common::println($result['content-md5']);
+Common::println($result['body']);
+
+// 下载object到本地变量
+$content = $ossClient->getObject($bucket, "b.file");
+Common::println("b.file is fetched, the content is: " . $content);
+
+
+// 下载object到本地文件
+$options = array(
+ OssClient::OSS_FILE_DOWNLOAD => "./c.file.localcopy",
+);
+$ossClient->getObject($bucket, "c.file", $options);
+Common::println("b.file is fetched to the local file: c.file.localcopy");
+Common::println("b.file is created");
+
+// 拷贝object
+$result = $ossClient->copyObject($bucket, "c.file", $bucket, "c.file.copy");
+Common::println("lastModifiedTime: " . $result[0]);
+Common::println("ETag: " . $result[1]);
+
+// 判断object是否存在
+$doesExist = $ossClient->doesObjectExist($bucket, "c.file.copy");
+Common::println("file c.file.copy exist? " . ($doesExist ? "yes" : "no"));
+
+// 删除object
+$result = $ossClient->deleteObject($bucket, "c.file.copy");
+Common::println("c.file.copy is deleted");
+Common::println("b.file is created");
+Common::println($result['x-oss-request-id']);
+
+// 判断object是否存在
+$doesExist = $ossClient->doesObjectExist($bucket, "c.file.copy");
+Common::println("file c.file.copy exist? " . ($doesExist ? "yes" : "no"));
+
+// 批量删除object
+$result = $ossClient->deleteObjects($bucket, array("b.file", "c.file"));
+foreach($result as $object)
+ Common::println($object);
+
+sleep(2);
+unlink("c.file.localcopy");
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+listObjects($ossClient, $bucket);
+listAllObjects($ossClient, $bucket);
+createObjectDir($ossClient, $bucket);
+putObject($ossClient, $bucket);
+uploadFile($ossClient, $bucket);
+getObject($ossClient, $bucket);
+getObjectToLocalFile($ossClient, $bucket);
+copyObject($ossClient, $bucket);
+modifyMetaForObject($ossClient, $bucket);
+getObjectMeta($ossClient, $bucket);
+deleteObject($ossClient, $bucket);
+deleteObjects($ossClient, $bucket);
+doesObjectExist($ossClient, $bucket);
+
+/**
+ * 创建虚拟目录
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function createObjectDir($ossClient, $bucket)
+{
+ try {
+ $ossClient->createObjectDir($bucket, "dir");
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 把本地变量的内容到文件
+ *
+ * 简单上传,上传指定变量的内存值作为object的内容
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function putObject($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $content = file_get_contents(__FILE__);
+ $options = array();
+ try {
+ $ossClient->putObject($bucket, $object, $content, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * 上传指定的本地文件内容
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function uploadFile($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $filePath = __FILE__;
+ $options = array();
+
+ try {
+ $ossClient->uploadFile($bucket, $object, $filePath, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 列出Bucket内所有目录和文件, 注意如果符合条件的文件数目超过设置的max-keys, 用户需要使用返回的nextMarker作为入参,通过
+ * 循环调用ListObjects得到所有的文件,具体操作见下面的 listAllObjects 示例
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function listObjects($ossClient, $bucket)
+{
+ $prefix = 'oss-php-sdk-test/';
+ $delimiter = '/';
+ $nextMarker = '';
+ $maxkeys = 1000;
+ $options = array(
+ 'delimiter' => $delimiter,
+ 'prefix' => $prefix,
+ 'max-keys' => $maxkeys,
+ 'marker' => $nextMarker,
+ );
+ try {
+ $listObjectInfo = $ossClient->listObjects($bucket, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ $objectList = $listObjectInfo->getObjectList(); // 文件列表
+ $prefixList = $listObjectInfo->getPrefixList(); // 目录列表
+ if (!empty($objectList)) {
+ print("objectList:\n");
+ foreach ($objectList as $objectInfo) {
+ print($objectInfo->getKey() . "\n");
+ }
+ }
+ if (!empty($prefixList)) {
+ print("prefixList: \n");
+ foreach ($prefixList as $prefixInfo) {
+ print($prefixInfo->getPrefix() . "\n");
+ }
+ }
+}
+
+/**
+ * 列出Bucket内所有目录和文件, 根据返回的nextMarker循环得到所有Objects
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function listAllObjects($ossClient, $bucket)
+{
+ //构造dir下的文件和虚拟目录
+ for ($i = 0; $i < 100; $i += 1) {
+ $ossClient->putObject($bucket, "dir/obj" . strval($i), "hi");
+ $ossClient->createObjectDir($bucket, "dir/obj" . strval($i));
+ }
+
+ $prefix = 'dir/';
+ $delimiter = '/';
+ $nextMarker = '';
+ $maxkeys = 30;
+
+ while (true) {
+ $options = array(
+ 'delimiter' => $delimiter,
+ 'prefix' => $prefix,
+ 'max-keys' => $maxkeys,
+ 'marker' => $nextMarker,
+ );
+ var_dump($options);
+ try {
+ $listObjectInfo = $ossClient->listObjects($bucket, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ // 得到nextMarker,从上一次listObjects读到的最后一个文件的下一个文件开始继续获取文件列表
+ $nextMarker = $listObjectInfo->getNextMarker();
+ $listObject = $listObjectInfo->getObjectList();
+ $listPrefix = $listObjectInfo->getPrefixList();
+ var_dump(count($listObject));
+ var_dump(count($listPrefix));
+ if ($nextMarker === '') {
+ break;
+ }
+ }
+}
+
+/**
+ * 获取object的内容
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getObject($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $options = array();
+ try {
+ $content = $ossClient->getObject($bucket, $object, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ if (file_get_contents(__FILE__) === $content) {
+ print(__FUNCTION__ . ": FileContent checked OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": FileContent checked FAILED" . "\n");
+ }
+}
+
+/**
+ * get_object_to_local_file
+ *
+ * 获取object
+ * 将object下载到指定的文件
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getObjectToLocalFile($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $localfile = "upload-test-object-name.txt";
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $localfile,
+ );
+
+ try {
+ $ossClient->getObject($bucket, $object, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK, please check localfile: 'upload-test-object-name.txt'" . "\n");
+ if (file_get_contents($localfile) === file_get_contents(__FILE__)) {
+ print(__FUNCTION__ . ": FileContent checked OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": FileContent checked FAILED" . "\n");
+ }
+ if (file_exists($localfile)) {
+ unlink($localfile);
+ }
+}
+
+/**
+ * 拷贝object
+ * 当目的object和源object完全相同时,表示修改object的meta信息
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function copyObject($ossClient, $bucket)
+{
+ $fromBucket = $bucket;
+ $fromObject = "oss-php-sdk-test/upload-test-object-name.txt";
+ $toBucket = $bucket;
+ $toObject = $fromObject . '.copy';
+ $options = array();
+
+ try {
+ $ossClient->copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 修改Object Meta
+ * 利用copyObject接口的特性:当目的object和源object完全相同时,表示修改object的meta信息
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function modifyMetaForObject($ossClient, $bucket)
+{
+ $fromBucket = $bucket;
+ $fromObject = "oss-php-sdk-test/upload-test-object-name.txt";
+ $toBucket = $bucket;
+ $toObject = $fromObject;
+ $copyOptions = array(
+ OssClient::OSS_HEADERS => array(
+ 'Cache-Control' => 'max-age=60',
+ 'Content-Disposition' => 'attachment; filename="xxxxxx"',
+ ),
+ );
+ try {
+ $ossClient->copyObject($fromBucket, $fromObject, $toBucket, $toObject, $copyOptions);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 获取object meta, 也就是getObjectMeta接口
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function getObjectMeta($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ try {
+ $objectMeta = $ossClient->getObjectMeta($bucket, $object);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ if (isset($objectMeta[strtolower('Content-Disposition')]) &&
+ 'attachment; filename="xxxxxx"' === $objectMeta[strtolower('Content-Disposition')]
+ ) {
+ print(__FUNCTION__ . ": ObjectMeta checked OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": ObjectMeta checked FAILED" . "\n");
+ }
+}
+
+/**
+ * 删除object
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteObject($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ try {
+ $ossClient->deleteObject($bucket, $object);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * 批量删除object
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function deleteObjects($ossClient, $bucket)
+{
+ $objects = array();
+ $objects[] = "oss-php-sdk-test/upload-test-object-name.txt";
+ $objects[] = "oss-php-sdk-test/upload-test-object-name.txt.copy";
+ try {
+ $ossClient->deleteObjects($bucket, $objects);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * 判断object是否存在
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ */
+function doesObjectExist($ossClient, $bucket)
+{
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ try {
+ $exist = $ossClient->doesObjectExist($bucket, $object);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ var_dump($exist);
+}
+
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/samples/RunAll.php b/app/Common/extend/aliyuncs/oss-sdk-php/samples/RunAll.php
new file mode 100755
index 0000000..a4d6d9b
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/samples/RunAll.php
@@ -0,0 +1,13 @@
+uploadFile($bucket, "a.file", __FILE__);
+
+// 生成GetObject的签名url,用户可以使用这个url直接在浏览器下载
+$signedUrl = $ossClient->signUrl($bucket, "a.file", 3600);
+Common::println($signedUrl);
+
+// 生成用于putObject的签名URL,用户可以直接用put方法使用这个url上传文件到 "a.file"
+$signedUrl = $ossClient->signUrl($bucket, "a.file", "3600", "PUT");
+Common::println($signedUrl);
+
+// 生成从本地文件上传PutObject的签名url, 用户可以直接使用这个url把本地文件上传到 "a.file"
+$signedUrl = $ossClient->signUrl($bucket, "a.file", 3600, "PUT", array('Content-Type' => 'txt'));
+Common::println($signedUrl);
+
+//******************************* 完整用法参考下面函数 ****************************************************
+
+getSignedUrlForPuttingObject($ossClient, $bucket);
+getSignedUrlForPuttingObjectFromFile($ossClient, $bucket);
+getSignedUrlForGettingObject($ossClient, $bucket);
+
+/**
+ * 生成GetObject的签名url,主要用于私有权限下的读访问控制
+ *
+ * @param $ossClient OssClient OssClient实例
+ * @param $bucket string 存储空间名称
+ * @return null
+ */
+function getSignedUrlForGettingObject($ossClient, $bucket)
+{
+ $object = "test/test-signature-test-upload-and-download.txt";
+ $timeout = 3600;
+ try {
+ $signedUrl = $ossClient->signUrl($bucket, $object, $timeout);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": signedUrl: " . $signedUrl . "\n");
+ /**
+ * 可以类似的代码来访问签名的URL,也可以输入到浏览器中去访问
+ */
+ $request = new RequestCore($signedUrl);
+ $request->set_method('GET');
+ $request->add_header('Content-Type', '');
+ $request->send_request();
+ $res = new ResponseCore($request->get_response_header(), $request->get_response_body(), $request->get_response_code());
+ if ($res->isOK()) {
+ print(__FUNCTION__ . ": OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": FAILED" . "\n");
+ };
+}
+
+/**
+ * 生成PutObject的签名url,主要用于私有权限下的写访问控制
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @return null
+ * @throws OssException
+ */
+function getSignedUrlForPuttingObject($ossClient, $bucket)
+{
+ $object = "test/test-signature-test-upload-and-download.txt";
+ $timeout = 3600;
+ $options = NULL;
+ try {
+ $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT");
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": signedUrl: " . $signedUrl . "\n");
+ $content = file_get_contents(__FILE__);
+
+ $request = new RequestCore($signedUrl);
+ $request->set_method('PUT');
+ $request->add_header('Content-Type', '');
+ $request->add_header('Content-Length', strlen($content));
+ $request->set_body($content);
+ $request->send_request();
+ $res = new ResponseCore($request->get_response_header(),
+ $request->get_response_body(), $request->get_response_code());
+ if ($res->isOK()) {
+ print(__FUNCTION__ . ": OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": FAILED" . "\n");
+ };
+}
+
+/**
+ * 生成PutObject的签名url,主要用于私有权限下的写访问控制, 用户可以利用生成的signedUrl
+ * 从文件上传文件
+ *
+ * @param OssClient $ossClient OssClient实例
+ * @param string $bucket 存储空间名称
+ * @throws OssException
+ */
+function getSignedUrlForPuttingObjectFromFile($ossClient, $bucket)
+{
+ $file = __FILE__;
+ $object = "test/test-signature-test-upload-and-download.txt";
+ $timeout = 3600;
+ $options = array('Content-Type' => 'txt');
+ try {
+ $signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "PUT", $options);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": signedUrl: " . $signedUrl . "\n");
+
+ $request = new RequestCore($signedUrl);
+ $request->set_method('PUT');
+ $request->add_header('Content-Type', 'txt');
+ $request->set_read_file($file);
+ $request->set_read_stream_size(filesize($file));
+ $request->send_request();
+ $res = new ResponseCore($request->get_response_header(),
+ $request->get_response_body(), $request->get_response_code());
+ if ($res->isOK()) {
+ print(__FUNCTION__ . ": OK" . "\n");
+ } else {
+ print(__FUNCTION__ . ": FAILED" . "\n");
+ };
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/MimeTypes.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/MimeTypes.php
new file mode 100755
index 0000000..e9b88ff
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/MimeTypes.php
@@ -0,0 +1,262 @@
+ 1) {
+ $ext = strtolower(end($parts));
+ if (isset(self::$mime_types[$ext])) {
+ return self::$mime_types[$ext];
+ }
+ }
+
+ return null;
+ }
+
+ private static $mime_types = array(
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+ 'apk' => 'application/vnd.android.package-archive',
+ 'hqx' => 'application/mac-binhex40',
+ 'cpt' => 'application/mac-compactpro',
+ 'doc' => 'application/msword',
+ 'ogg' => 'audio/ogg',
+ 'pdf' => 'application/pdf',
+ 'rtf' => 'text/rtf',
+ 'mif' => 'application/vnd.mif',
+ 'xls' => 'application/vnd.ms-excel',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'sxw' => 'application/vnd.sun.xml.writer',
+ 'stw' => 'application/vnd.sun.xml.writer.template',
+ 'sxc' => 'application/vnd.sun.xml.calc',
+ 'stc' => 'application/vnd.sun.xml.calc.template',
+ 'sxd' => 'application/vnd.sun.xml.draw',
+ 'std' => 'application/vnd.sun.xml.draw.template',
+ 'sxi' => 'application/vnd.sun.xml.impress',
+ 'sti' => 'application/vnd.sun.xml.impress.template',
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
+ 'sxm' => 'application/vnd.sun.xml.math',
+ 'sis' => 'application/vnd.symbian.install',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
+ 'bcpio' => 'application/x-bcpio',
+ 'torrent' => 'application/x-bittorrent',
+ 'bz2' => 'application/x-bzip2',
+ 'vcd' => 'application/x-cdlink',
+ 'pgn' => 'application/x-chess-pgn',
+ 'cpio' => 'application/x-cpio',
+ 'csh' => 'application/x-csh',
+ 'dvi' => 'application/x-dvi',
+ 'spl' => 'application/x-futuresplash',
+ 'gtar' => 'application/x-gtar',
+ 'hdf' => 'application/x-hdf',
+ 'jar' => 'application/java-archive',
+ 'jnlp' => 'application/x-java-jnlp-file',
+ 'js' => 'application/javascript',
+ 'json' => 'application/json',
+ 'ksp' => 'application/x-kspread',
+ 'chrt' => 'application/x-kchart',
+ 'kil' => 'application/x-killustrator',
+ 'latex' => 'application/x-latex',
+ 'rpm' => 'application/x-rpm',
+ 'sh' => 'application/x-sh',
+ 'shar' => 'application/x-shar',
+ 'swf' => 'application/x-shockwave-flash',
+ 'sit' => 'application/x-stuffit',
+ 'sv4cpio' => 'application/x-sv4cpio',
+ 'sv4crc' => 'application/x-sv4crc',
+ 'tar' => 'application/x-tar',
+ 'tcl' => 'application/x-tcl',
+ 'tex' => 'application/x-tex',
+ 'man' => 'application/x-troff-man',
+ 'me' => 'application/x-troff-me',
+ 'ms' => 'application/x-troff-ms',
+ 'ustar' => 'application/x-ustar',
+ 'src' => 'application/x-wais-source',
+ 'zip' => 'application/zip',
+ 'm3u' => 'audio/x-mpegurl',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'wav' => 'audio/x-wav',
+ 'wma' => 'audio/x-ms-wma',
+ 'wax' => 'audio/x-ms-wax',
+ 'pdb' => 'chemical/x-pdb',
+ 'xyz' => 'chemical/x-xyz',
+ 'bmp' => 'image/bmp',
+ 'gif' => 'image/gif',
+ 'ief' => 'image/ief',
+ 'png' => 'image/png',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'ras' => 'image/x-cmu-raster',
+ 'pnm' => 'image/x-portable-anymap',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pgm' => 'image/x-portable-graymap',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'rgb' => 'image/x-rgb',
+ 'xbm' => 'image/x-xbitmap',
+ 'xpm' => 'image/x-xpixmap',
+ 'xwd' => 'image/x-xwindowdump',
+ 'css' => 'text/css',
+ 'rtx' => 'text/richtext',
+ 'tsv' => 'text/tab-separated-values',
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
+ 'wml' => 'text/vnd.wap.wml',
+ 'wmls' => 'text/vnd.wap.wmlscript',
+ 'etx' => 'text/x-setext',
+ 'mxu' => 'video/vnd.mpegurl',
+ 'flv' => 'video/x-flv',
+ 'wm' => 'video/x-ms-wm',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wvx' => 'video/x-ms-wvx',
+ 'avi' => 'video/x-msvideo',
+ 'movie' => 'video/x-sgi-movie',
+ 'ice' => 'x-conference/x-cooltalk',
+ '3gp' => 'video/3gpp',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'asc' => 'text/plain',
+ 'atom' => 'application/atom+xml',
+ 'au' => 'audio/basic',
+ 'bin' => 'application/octet-stream',
+ 'cdf' => 'application/x-netcdf',
+ 'cgm' => 'image/cgm',
+ 'class' => 'application/octet-stream',
+ 'dcr' => 'application/x-director',
+ 'dif' => 'video/x-dv',
+ 'dir' => 'application/x-director',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'dll' => 'application/octet-stream',
+ 'dmg' => 'application/octet-stream',
+ 'dms' => 'application/octet-stream',
+ 'dtd' => 'application/xml-dtd',
+ 'dv' => 'video/x-dv',
+ 'dxr' => 'application/x-director',
+ 'eps' => 'application/postscript',
+ 'exe' => 'application/octet-stream',
+ 'ez' => 'application/andrew-inset',
+ 'gram' => 'application/srgs',
+ 'grxml' => 'application/srgs+xml',
+ 'gz' => 'application/x-gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ifb' => 'text/calendar',
+ 'iges' => 'model/iges',
+ 'igs' => 'model/iges',
+ 'jp2' => 'image/jp2',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'kar' => 'audio/midi',
+ 'lha' => 'application/octet-stream',
+ 'lzh' => 'application/octet-stream',
+ 'm4a' => 'audio/mp4a-latm',
+ 'm4p' => 'audio/mp4a-latm',
+ 'm4u' => 'video/vnd.mpegurl',
+ 'm4v' => 'video/x-m4v',
+ 'mac' => 'image/x-macpaint',
+ 'mathml' => 'application/mathml+xml',
+ 'mesh' => 'model/mesh',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpga' => 'audio/mpeg',
+ 'msh' => 'model/mesh',
+ 'nc' => 'application/x-netcdf',
+ 'oda' => 'application/oda',
+ 'ogv' => 'video/ogv',
+ 'pct' => 'image/pict',
+ 'pic' => 'image/pict',
+ 'pict' => 'image/pict',
+ 'pnt' => 'image/x-macpaint',
+ 'pntg' => 'image/x-macpaint',
+ 'ps' => 'application/postscript',
+ 'qt' => 'video/quicktime',
+ 'qti' => 'image/x-quicktime',
+ 'qtif' => 'image/x-quicktime',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rdf' => 'application/rdf+xml',
+ 'rm' => 'application/vnd.rn-realmedia',
+ 'roff' => 'application/x-troff',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'silo' => 'model/mesh',
+ 'skd' => 'application/x-koan',
+ 'skm' => 'application/x-koan',
+ 'skp' => 'application/x-koan',
+ 'skt' => 'application/x-koan',
+ 'smi' => 'application/smil',
+ 'smil' => 'application/smil',
+ 'snd' => 'audio/basic',
+ 'so' => 'application/octet-stream',
+ 'svg' => 'image/svg+xml',
+ 't' => 'application/x-troff',
+ 'texi' => 'application/x-texinfo',
+ 'texinfo' => 'application/x-texinfo',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'tr' => 'application/x-troff',
+ 'txt' => 'text/plain',
+ 'vrml' => 'model/vrml',
+ 'vxml' => 'application/voicexml+xml',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wrl' => 'model/vrml',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xml' => 'application/xml',
+ 'xsl' => 'application/xml',
+ 'xslt' => 'application/xslt+xml',
+ 'xul' => 'application/vnd.mozilla.xul+xml',
+ );
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/OssException.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/OssException.php
new file mode 100755
index 0000000..b0e9e8b
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/OssException.php
@@ -0,0 +1,54 @@
+details = $details;
+ } else {
+ $message = $details;
+ parent::__construct($message);
+ }
+ }
+
+ public function getHTTPStatus()
+ {
+ return isset($this->details['status']) ? $this->details['status'] : '';
+ }
+
+ public function getRequestId()
+ {
+ return isset($this->details['request-id']) ? $this->details['request-id'] : '';
+ }
+
+ public function getErrorCode()
+ {
+ return isset($this->details['code']) ? $this->details['code'] : '';
+ }
+
+ public function getErrorMessage()
+ {
+ return isset($this->details['message']) ? $this->details['message'] : '';
+ }
+
+ public function getDetails()
+ {
+ return isset($this->details['body']) ? $this->details['body'] : '';
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/OssUtil.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/OssUtil.php
new file mode 100755
index 0000000..b70680e
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Core/OssUtil.php
@@ -0,0 +1,448 @@
+ $value) {
+ if (is_string($key) && !is_array($value)) {
+ $temp[] = rawurlencode($key) . '=' . rawurlencode($value);
+ }
+ }
+ return implode('&', $temp);
+ }
+
+ /**
+ * 转义字符替换
+ *
+ * @param string $subject
+ * @return string
+ */
+ public static function sReplace($subject)
+ {
+ $search = array('<', '>', '&', '\'', '"');
+ $replace = array('<', '>', '&', ''', '"');
+ return str_replace($search, $replace, $subject);
+ }
+
+ /**
+ * 检查是否是中文编码
+ *
+ * @param $str
+ * @return int
+ */
+ public static function chkChinese($str)
+ {
+ return preg_match('/[\x80-\xff]./', $str);
+ }
+
+ /**
+ * 检测是否GB2312编码
+ *
+ * @param string $str
+ * @return boolean false UTF-8编码 TRUE GB2312编码
+ */
+ public static function isGb2312($str)
+ {
+ for ($i = 0; $i < strlen($str); $i++) {
+ $v = ord($str[$i]);
+ if ($v > 127) {
+ if (($v >= 228) && ($v <= 233)) {
+ if (($i + 2) >= (strlen($str) - 1)) return true; // not enough characters
+ $v1 = ord($str[$i + 1]);
+ $v2 = ord($str[$i + 2]);
+ if (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191))
+ return false;
+ else
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 检测是否GBK编码
+ *
+ * @param string $str
+ * @param boolean $gbk
+ * @return boolean
+ */
+ public static function checkChar($str, $gbk = true)
+ {
+ for ($i = 0; $i < strlen($str); $i++) {
+ $v = ord($str[$i]);
+ if ($v > 127) {
+ if (($v >= 228) && ($v <= 233)) {
+ if (($i + 2) >= (strlen($str) - 1)) return $gbk ? true : FALSE; // not enough characters
+ $v1 = ord($str[$i + 1]);
+ $v2 = ord($str[$i + 2]);
+ if ($gbk) {
+ return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? FALSE : TRUE;//GBK
+ } else {
+ return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? TRUE : FALSE;
+ }
+ }
+ }
+ }
+ return $gbk ? TRUE : FALSE;
+ }
+
+ /**
+ * 检验bucket名称是否合法
+ * bucket的命名规范:
+ * 1. 只能包括小写字母,数字
+ * 2. 必须以小写字母或者数字开头
+ * 3. 长度必须在3-63字节之间
+ *
+ * @param string $bucket Bucket名称
+ * @return boolean
+ */
+ public static function validateBucket($bucket)
+ {
+ $pattern = '/^[a-z0-9][a-z0-9-]{2,62}$/';
+ if (!preg_match($pattern, $bucket)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 检验object名称是否合法
+ * object命名规范:
+ * 1. 规则长度必须在1-1023字节之间
+ * 2. 使用UTF-8编码
+ * 3. 不能以 "/" "\\"开头
+ *
+ * @param string $object Object名称
+ * @return boolean
+ */
+ public static function validateObject($object)
+ {
+ $pattern = '/^.{1,1023}$/';
+ if (empty($object) || !preg_match($pattern, $object) ||
+ self::startsWith($object, '/') || self::startsWith($object, '\\')
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * 判断字符串$str是不是以$findMe开始
+ *
+ * @param string $str
+ * @param string $findMe
+ * @return bool
+ */
+ public static function startsWith($str, $findMe)
+ {
+ if (strpos($str, $findMe) === 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 检验$options
+ *
+ * @param array $options
+ * @throws OssException
+ * @return boolean
+ */
+ public static function validateOptions($options)
+ {
+ //$options
+ if ($options != NULL && !is_array($options)) {
+ throw new OssException ($options . ':' . 'option must be array');
+ }
+ }
+
+ /**
+ * 检查上传文件的内容是否合法
+ *
+ * @param $content string
+ * @throws OssException
+ */
+ public static function validateContent($content)
+ {
+ if (empty($content)) {
+ throw new OssException("http body content is invalid");
+ }
+ }
+
+ /**
+ * 校验BUCKET/OBJECT/OBJECT GROUP是否为空
+ *
+ * @param string $name
+ * @param string $errMsg
+ * @throws OssException
+ * @return void
+ */
+ public static function throwOssExceptionWithMessageIfEmpty($name, $errMsg)
+ {
+ if (empty($name)) {
+ throw new OssException($errMsg);
+ }
+ }
+
+ /**
+ * 仅供测试使用的接口,请勿使用
+ *
+ * @param $filename
+ * @param $size
+ */
+ public static function generateFile($filename, $size)
+ {
+ if (file_exists($filename) && $size == filesize($filename)) {
+ echo $filename . " already exists, no need to create again. ";
+ return;
+ }
+ $part_size = 1 * 1024 * 1024;
+ $fp = fopen($filename, "w");
+ $characters = << 0) {
+ if ($size < $part_size) {
+ $write_size = $size;
+ } else {
+ $write_size = $part_size;
+ }
+ $size -= $write_size;
+ $a = $characters[rand(0, $charactersLength - 1)];
+ $content = str_repeat($a, $write_size);
+ $flag = fwrite($fp, $content);
+ if (!$flag) {
+ echo "write to " . $filename . " failed. ";
+ break;
+ }
+ }
+ } else {
+ echo "open " . $filename . " failed. ";
+ }
+ fclose($fp);
+ }
+
+ /**
+ * 得到文件的md5编码
+ *
+ * @param $filename
+ * @param $from_pos
+ * @param $to_pos
+ * @return string
+ */
+ public static function getMd5SumForFile($filename, $from_pos, $to_pos)
+ {
+ $content_md5 = "";
+ if (($to_pos - $from_pos) > self::OSS_MAX_PART_SIZE) {
+ return $content_md5;
+ }
+ $filesize = filesize($filename);
+ if ($from_pos >= $filesize || $to_pos >= $filesize || $from_pos < 0 || $to_pos < 0) {
+ return $content_md5;
+ }
+
+ $total_length = $to_pos - $from_pos + 1;
+ $buffer = 8192;
+ $left_length = $total_length;
+ if (!file_exists($filename)) {
+ return $content_md5;
+ }
+
+ if (false === $fh = fopen($filename, 'rb')) {
+ return $content_md5;
+ }
+
+ fseek($fh, $from_pos);
+ $data = '';
+ while (!feof($fh)) {
+ if ($left_length >= $buffer) {
+ $read_length = $buffer;
+ } else {
+ $read_length = $left_length;
+ }
+ if ($read_length <= 0) {
+ break;
+ } else {
+ $data .= fread($fh, $read_length);
+ $left_length = $left_length - $read_length;
+ }
+ }
+ fclose($fh);
+ $content_md5 = base64_encode(md5($data, true));
+ return $content_md5;
+ }
+
+ /**
+ * 检测是否windows系统,因为windows系统默认编码为GBK
+ *
+ * @return bool
+ */
+ public static function isWin()
+ {
+ return strtoupper(substr(PHP_OS, 0, 3)) == "WIN";
+ }
+
+ /**
+ * 主要是由于windows系统编码是gbk,遇到中文时候,如果不进行转换处理会出现找不到文件的问题
+ *
+ * @param $file_path
+ * @return string
+ */
+ public static function encodePath($file_path)
+ {
+ if (self::chkChinese($file_path) && self::isWin()) {
+ $file_path = iconv('utf-8', 'gbk', $file_path);
+ }
+ return $file_path;
+ }
+
+ /**
+ * 判断用户输入的endpoint是否是 xxx.xxx.xxx.xxx:port 或者 xxx.xxx.xxx.xxx的ip格式
+ *
+ * @param string $endpoint 需要做判断的endpoint
+ * @return boolean
+ */
+ public static function isIPFormat($endpoint)
+ {
+ $ip_array = explode(":", $endpoint);
+ $hostname = $ip_array[0];
+ $ret = filter_var($hostname, FILTER_VALIDATE_IP);
+ if (!$ret) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * 生成DeleteMultiObjects接口的xml消息
+ *
+ * @param string[] $objects
+ * @param bool $quiet
+ * @return string
+ */
+ public static function createDeleteObjectsXmlBody($objects, $quiet)
+ {
+ $xml = new \SimpleXMLElement(' ');
+ $xml->addChild('Quiet', $quiet);
+ foreach ($objects as $object) {
+ $sub_object = $xml->addChild('Object');
+ $object = OssUtil::sReplace($object);
+ $sub_object->addChild('Key', $object);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * 生成CompleteMultipartUpload接口的xml消息
+ *
+ * @param array[] $listParts
+ * @return string
+ */
+ public static function createCompleteMultipartUploadXmlBody($listParts)
+ {
+ $xml = new \SimpleXMLElement(' ');
+ foreach ($listParts as $node) {
+ $part = $xml->addChild('Part');
+ $part->addChild('PartNumber', $node['PartNumber']);
+ $part->addChild('ETag', $node['ETag']);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * 读取目录
+ *
+ * @param string $dir
+ * @param string $exclude
+ * @param bool $recursive
+ * @return string[]
+ */
+ public static function readDir($dir, $exclude = ".|..|.svn|.git", $recursive = false)
+ {
+ $file_list_array = array();
+ $base_path = $dir;
+ $exclude_array = explode("|", $exclude);
+ $exclude_array = array_unique(array_merge($exclude_array, array('.', '..')));
+
+ if ($recursive) {
+ foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir)) as $new_file) {
+ if ($new_file->isDir()) continue;
+ $object = str_replace($base_path, '', $new_file);
+ if (!in_array(strtolower($object), $exclude_array)) {
+ $object = ltrim($object, '/');
+ if (is_file($new_file)) {
+ $key = md5($new_file . $object, false);
+ $file_list_array[$key] = array('path' => $new_file, 'file' => $object,);
+ }
+ }
+ }
+ } else if ($handle = opendir($dir)) {
+ while (false !== ($file = readdir($handle))) {
+ if (!in_array(strtolower($file), $exclude_array)) {
+ $new_file = $dir . '/' . $file;
+ $object = $file;
+ $object = ltrim($object, '/');
+ if (is_file($new_file)) {
+ $key = md5($new_file . $object, false);
+ $file_list_array[$key] = array('path' => $new_file, 'file' => $object,);
+ }
+ }
+ }
+ closedir($handle);
+ }
+ return $file_list_array;
+ }
+
+ /**
+ * Decode key based on the encoding type
+ *
+ * @param string $key
+ * @param string $encoding
+ * @return string
+ */
+ public static function decodeKey($key, $encoding)
+ {
+ if ($encoding == "") {
+ return $key;
+ }
+
+ if ($encoding == "url") {
+ return rawurldecode($key);
+ } else {
+ throw new OssException("Unrecognized encoding type: " . $encoding);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/LICENSE b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/LICENSE
new file mode 100755
index 0000000..49b38bd
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2006-2010 Ryan Parman, Foleeo Inc., and contributors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ * Neither the name of Ryan Parman, Foleeo Inc. nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php
new file mode 100755
index 0000000..8ed41fc
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php
@@ -0,0 +1,897 @@
+).
+ */
+ public $request_class = 'OSS\Http\RequestCore';
+
+ /**
+ * The default class to use for HTTP Responses (defaults to ).
+ */
+ public $response_class = 'OSS\Http\ResponseCore';
+
+ /**
+ * Default useragent string to use.
+ */
+ public $useragent = 'RequestCore/1.4.3';
+
+ /**
+ * File to read from while streaming up.
+ */
+ public $read_file = null;
+
+ /**
+ * The resource to read from while streaming up.
+ */
+ public $read_stream = null;
+
+ /**
+ * The size of the stream to read from.
+ */
+ public $read_stream_size = null;
+
+ /**
+ * The length already read from the stream.
+ */
+ public $read_stream_read = 0;
+
+ /**
+ * File to write to while streaming down.
+ */
+ public $write_file = null;
+
+ /**
+ * The resource to write to while streaming down.
+ */
+ public $write_stream = null;
+
+ /**
+ * Stores the intended starting seek position.
+ */
+ public $seek_position = null;
+
+ /**
+ * The location of the cacert.pem file to use.
+ */
+ public $cacert_location = false;
+
+ /**
+ * The state of SSL certificate verification.
+ */
+ public $ssl_verification = true;
+
+ /**
+ * The user-defined callback function to call when a stream is read from.
+ */
+ public $registered_streaming_read_callback = null;
+
+ /**
+ * The user-defined callback function to call when a stream is written to.
+ */
+ public $registered_streaming_write_callback = null;
+
+ /**
+ * 请求超时时间, 默认是5184000秒,6天
+ *
+ * @var int
+ */
+ public $timeout = 5184000;
+
+ /**
+ * 连接超时时间,默认是10秒
+ *
+ * @var int
+ */
+ public $connect_timeout = 10;
+
+ /*%******************************************************************************************%*/
+ // CONSTANTS
+
+ /**
+ * GET HTTP Method
+ */
+ const HTTP_GET = 'GET';
+
+ /**
+ * POST HTTP Method
+ */
+ const HTTP_POST = 'POST';
+
+ /**
+ * PUT HTTP Method
+ */
+ const HTTP_PUT = 'PUT';
+
+ /**
+ * DELETE HTTP Method
+ */
+ const HTTP_DELETE = 'DELETE';
+
+ /**
+ * HEAD HTTP Method
+ */
+ const HTTP_HEAD = 'HEAD';
+
+
+ /*%******************************************************************************************%*/
+ // CONSTRUCTOR/DESTRUCTOR
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param string $url (Optional) The URL to request or service endpoint to query.
+ * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`
+ * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class.
+ * @return $this A reference to the current instance.
+ */
+ public function __construct($url = null, $proxy = null, $helpers = null)
+ {
+ // Set some default values.
+ $this->request_url = $url;
+ $this->method = self::HTTP_GET;
+ $this->request_headers = array();
+ $this->request_body = '';
+
+ // Set a new Request class if one was set.
+ if (isset($helpers['request']) && !empty($helpers['request'])) {
+ $this->request_class = $helpers['request'];
+ }
+
+ // Set a new Request class if one was set.
+ if (isset($helpers['response']) && !empty($helpers['response'])) {
+ $this->response_class = $helpers['response'];
+ }
+
+ if ($proxy) {
+ $this->set_proxy($proxy);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Destructs the instance. Closes opened file handles.
+ *
+ * @return $this A reference to the current instance.
+ */
+ public function __destruct()
+ {
+ if (isset($this->read_file) && isset($this->read_stream)) {
+ fclose($this->read_stream);
+ }
+
+ if (isset($this->write_file) && isset($this->write_stream)) {
+ fclose($this->write_stream);
+ }
+
+ return $this;
+ }
+
+
+ /*%******************************************************************************************%*/
+ // REQUEST METHODS
+
+ /**
+ * Sets the credentials to use for authentication.
+ *
+ * @param string $user (Required) The username to authenticate with.
+ * @param string $pass (Required) The password to authenticate with.
+ * @return $this A reference to the current instance.
+ */
+ public function set_credentials($user, $pass)
+ {
+ $this->username = $user;
+ $this->password = $pass;
+ return $this;
+ }
+
+ /**
+ * Adds a custom HTTP header to the cURL request.
+ *
+ * @param string $key (Required) The custom HTTP header to set.
+ * @param mixed $value (Required) The value to assign to the custom HTTP header.
+ * @return $this A reference to the current instance.
+ */
+ public function add_header($key, $value)
+ {
+ $this->request_headers[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * Removes an HTTP header from the cURL request.
+ *
+ * @param string $key (Required) The custom HTTP header to set.
+ * @return $this A reference to the current instance.
+ */
+ public function remove_header($key)
+ {
+ if (isset($this->request_headers[$key])) {
+ unset($this->request_headers[$key]);
+ }
+ return $this;
+ }
+
+ /**
+ * Set the method type for the request.
+ *
+ * @param string $method (Required) One of the following constants: , , , , .
+ * @return $this A reference to the current instance.
+ */
+ public function set_method($method)
+ {
+ $this->method = strtoupper($method);
+ return $this;
+ }
+
+ /**
+ * Sets a custom useragent string for the class.
+ *
+ * @param string $ua (Required) The useragent string to use.
+ * @return $this A reference to the current instance.
+ */
+ public function set_useragent($ua)
+ {
+ $this->useragent = $ua;
+ return $this;
+ }
+
+ /**
+ * Set the body to send in the request.
+ *
+ * @param string $body (Required) The textual content to send along in the body of the request.
+ * @return $this A reference to the current instance.
+ */
+ public function set_body($body)
+ {
+ $this->request_body = $body;
+ return $this;
+ }
+
+ /**
+ * Set the URL to make the request to.
+ *
+ * @param string $url (Required) The URL to make the request to.
+ * @return $this A reference to the current instance.
+ */
+ public function set_request_url($url)
+ {
+ $this->request_url = $url;
+ return $this;
+ }
+
+ /**
+ * Set additional CURLOPT settings. These will merge with the default settings, and override if
+ * there is a duplicate.
+ *
+ * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings.
+ * @return $this A reference to the current instance.
+ */
+ public function set_curlopts($curlopts)
+ {
+ $this->curlopts = $curlopts;
+ return $this;
+ }
+
+ /**
+ * Sets the length in bytes to read from the stream while streaming up.
+ *
+ * @param integer $size (Required) The length in bytes to read from the stream.
+ * @return $this A reference to the current instance.
+ */
+ public function set_read_stream_size($size)
+ {
+ $this->read_stream_size = $size;
+
+ return $this;
+ }
+
+ /**
+ * Sets the resource to read from while streaming up. Reads the stream from its current position until
+ * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and
+ * .
+ *
+ * @param resource $resource (Required) The readable resource to read from.
+ * @param integer $size (Optional) The size of the stream to read.
+ * @return $this A reference to the current instance.
+ */
+ public function set_read_stream($resource, $size = null)
+ {
+ if (!isset($size) || $size < 0) {
+ $stats = fstat($resource);
+
+ if ($stats && $stats['size'] >= 0) {
+ $position = ftell($resource);
+
+ if ($position !== false && $position >= 0) {
+ $size = $stats['size'] - $position;
+ }
+ }
+ }
+
+ $this->read_stream = $resource;
+
+ return $this->set_read_stream_size($size);
+ }
+
+ /**
+ * Sets the file to read from while streaming up.
+ *
+ * @param string $location (Required) The readable location to read from.
+ * @return $this A reference to the current instance.
+ */
+ public function set_read_file($location)
+ {
+ $this->read_file = $location;
+ $read_file_handle = fopen($location, 'r');
+
+ return $this->set_read_stream($read_file_handle);
+ }
+
+ /**
+ * Sets the resource to write to while streaming down.
+ *
+ * @param resource $resource (Required) The writeable resource to write to.
+ * @return $this A reference to the current instance.
+ */
+ public function set_write_stream($resource)
+ {
+ $this->write_stream = $resource;
+
+ return $this;
+ }
+
+ /**
+ * Sets the file to write to while streaming down.
+ *
+ * @param string $location (Required) The writeable location to write to.
+ * @return $this A reference to the current instance.
+ */
+ public function set_write_file($location)
+ {
+ $this->write_file = $location;
+ }
+
+ /**
+ * Set the proxy to use for making requests.
+ *
+ * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`
+ * @return $this A reference to the current instance.
+ */
+ public function set_proxy($proxy)
+ {
+ $proxy = parse_url($proxy);
+ $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null;
+ $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null;
+ $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null;
+ $this->proxy = $proxy;
+ return $this;
+ }
+
+ /**
+ * Set the intended starting seek position.
+ *
+ * @param integer $position (Required) The byte-position of the stream to begin reading from.
+ * @return $this A reference to the current instance.
+ */
+ public function set_seek_position($position)
+ {
+ $this->seek_position = isset($position) ? (integer)$position : null;
+
+ return $this;
+ }
+
+ /**
+ * A callback function that is invoked by cURL for streaming up.
+ *
+ * @param resource $curl_handle (Required) The cURL handle for the request.
+ * @param resource $header_content (Required) The header callback result.
+ * @return headers from a stream.
+ */
+ public function streaming_header_callback($curl_handle, $header_content)
+ {
+ $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
+
+ if (isset($this->write_file) && intval($code) / 100 == 2 && !isset($this->write_file_handle))
+ {
+ $this->write_file_handle = fopen($this->write_file, 'w');
+ $this->set_write_stream($this->write_file_handle);
+ }
+
+ $this->response_raw_headers .= $header_content;
+ return strlen($header_content);
+ }
+
+
+ /**
+ * Register a callback function to execute whenever a data stream is read from using
+ * .
+ *
+ * The user-defined callback function should accept three arguments:
+ *
+ *
+ * $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
+ * $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
+ * $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
+ *
+ *
+ * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
+ * The name of a global function to execute, passed as a string.
+ * A method to execute, passed as array('ClassName', 'MethodName').
+ * An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance.
+ */
+ public function register_streaming_read_callback($callback)
+ {
+ $this->registered_streaming_read_callback = $callback;
+
+ return $this;
+ }
+
+ /**
+ * Register a callback function to execute whenever a data stream is written to using
+ * .
+ *
+ * The user-defined callback function should accept two arguments:
+ *
+ *
+ * $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
+ * $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
+ *
+ *
+ * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
+ * The name of a global function to execute, passed as a string.
+ * A method to execute, passed as array('ClassName', 'MethodName').
+ * An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance.
+ */
+ public function register_streaming_write_callback($callback)
+ {
+ $this->registered_streaming_write_callback = $callback;
+
+ return $this;
+ }
+
+
+ /*%******************************************************************************************%*/
+ // PREPARE, SEND, AND PROCESS REQUEST
+
+ /**
+ * A callback function that is invoked by cURL for streaming up.
+ *
+ * @param resource $curl_handle (Required) The cURL handle for the request.
+ * @param resource $file_handle (Required) The open file handle resource.
+ * @param integer $length (Required) The maximum number of bytes to read.
+ * @return binary Binary data from a stream.
+ */
+ public function streaming_read_callback($curl_handle, $file_handle, $length)
+ {
+ // Once we've sent as much as we're supposed to send...
+ if ($this->read_stream_read >= $this->read_stream_size) {
+ // Send EOF
+ return '';
+ }
+
+ // If we're at the beginning of an upload and need to seek...
+ if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) {
+ if (fseek($this->read_stream, $this->seek_position) !== 0) {
+ throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.');
+ }
+ }
+
+ $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size
+ $this->read_stream_read += strlen($read);
+
+ $out = $read === false ? '' : $read;
+
+ // Execute callback function
+ if ($this->registered_streaming_read_callback) {
+ call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out);
+ }
+
+ return $out;
+ }
+
+ /**
+ * A callback function that is invoked by cURL for streaming down.
+ *
+ * @param resource $curl_handle (Required) The cURL handle for the request.
+ * @param binary $data (Required) The data to write.
+ * @return integer The number of bytes written.
+ */
+ public function streaming_write_callback($curl_handle, $data)
+ {
+ $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
+
+ if (intval($code) / 100 != 2)
+ {
+ $this->response_error_body .= $data;
+ return strlen($data);
+ }
+
+ $length = strlen($data);
+ $written_total = 0;
+ $written_last = 0;
+
+ while ($written_total < $length) {
+ $written_last = fwrite($this->write_stream, substr($data, $written_total));
+
+ if ($written_last === false) {
+ return $written_total;
+ }
+
+ $written_total += $written_last;
+ }
+
+ // Execute callback function
+ if ($this->registered_streaming_write_callback) {
+ call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total);
+ }
+
+ return $written_total;
+ }
+
+ /**
+ * Prepares and adds the details of the cURL request. This can be passed along to a
+ * function.
+ *
+ * @return resource The handle for the cURL object.
+ *
+ */
+ public function prep_request()
+ {
+ $curl_handle = curl_init();
+
+ // Set default options.
+ curl_setopt($curl_handle, CURLOPT_URL, $this->request_url);
+ curl_setopt($curl_handle, CURLOPT_FILETIME, true);
+ curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false);
+// curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
+ curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5);
+ curl_setopt($curl_handle, CURLOPT_HEADER, true);
+ curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl_handle, CURLOPT_TIMEOUT, $this->timeout);
+ curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
+ curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true);
+ curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url);
+ curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent);
+ curl_setopt($curl_handle, CURLOPT_HEADERFUNCTION, array($this, 'streaming_header_callback'));
+ curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback'));
+
+ // Verification of the SSL cert
+ if ($this->ssl_verification) {
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false);
+ }
+
+ // chmod the file as 0755
+ if ($this->cacert_location === true) {
+ curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
+ } elseif (is_string($this->cacert_location)) {
+ curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location);
+ }
+
+ // Debug mode
+ if ($this->debug_mode) {
+ curl_setopt($curl_handle, CURLOPT_VERBOSE, true);
+ }
+
+ // Handle open_basedir & safe mode
+ if (!ini_get('safe_mode') && !ini_get('open_basedir')) {
+ curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
+ }
+
+ // Enable a proxy connection if requested.
+ if ($this->proxy) {
+ curl_setopt($curl_handle, CURLOPT_HTTPPROXYTUNNEL, true);
+
+ $host = $this->proxy['host'];
+ $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : '';
+ curl_setopt($curl_handle, CURLOPT_PROXY, $host);
+
+ if (isset($this->proxy['user']) && isset($this->proxy['pass'])) {
+ curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']);
+ }
+ }
+
+ // Set credentials for HTTP Basic/Digest Authentication.
+ if ($this->username && $this->password) {
+ curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+ curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password);
+ }
+
+ // Handle the encoding if we can.
+ if (extension_loaded('zlib')) {
+ curl_setopt($curl_handle, CURLOPT_ENCODING, '');
+ }
+
+ // Process custom headers
+ if (isset($this->request_headers) && count($this->request_headers)) {
+ $temp_headers = array();
+
+ foreach ($this->request_headers as $k => $v) {
+ $temp_headers[] = $k . ': ' . $v;
+ }
+
+ curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers);
+ }
+
+ switch ($this->method) {
+ case self::HTTP_PUT:
+ //unset($this->read_stream);
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT');
+ if (isset($this->read_stream)) {
+ if (!isset($this->read_stream_size) || $this->read_stream_size < 0) {
+ throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.');
+ }
+ curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size);
+ curl_setopt($curl_handle, CURLOPT_UPLOAD, true);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);
+ }
+ break;
+
+ case self::HTTP_POST:
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'POST');
+ if (isset($this->read_stream)) {
+ if (!isset($this->read_stream_size) || $this->read_stream_size < 0) {
+ throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.');
+ }
+ curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size);
+ curl_setopt($curl_handle, CURLOPT_UPLOAD, true);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);
+ }
+ break;
+
+ case self::HTTP_HEAD:
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD);
+ curl_setopt($curl_handle, CURLOPT_NOBODY, 1);
+ break;
+
+ default: // Assumed GET
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method);
+ if (isset($this->write_stream) || isset($this->write_file)) {
+ curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback'));
+ curl_setopt($curl_handle, CURLOPT_HEADER, false);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);
+ }
+ break;
+ }
+
+ // Merge in the CURLOPTs
+ if (isset($this->curlopts) && sizeof($this->curlopts) > 0) {
+ foreach ($this->curlopts as $k => $v) {
+ curl_setopt($curl_handle, $k, $v);
+ }
+ }
+
+ return $curl_handle;
+ }
+
+ /**
+ * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the
+ * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via
+ * parameters.
+ *
+ * @param resource $curl_handle (Optional) The reference to the already executed cURL request.
+ * @param string $response (Optional) The actual response content itself that needs to be parsed.
+ * @return ResponseCore A object containing a parsed HTTP response.
+ */
+ public function process_response($curl_handle = null, $response = null)
+ {
+ // Accept a custom one if it's passed.
+ if ($curl_handle && $response) {
+ $this->response = $response;
+ }
+
+ // As long as this came back as a valid resource...
+ if (is_resource($curl_handle)) {
+ // Determine what's what.
+ $header_size = curl_getinfo($curl_handle, CURLINFO_HEADER_SIZE);
+ $this->response_headers = substr($this->response, 0, $header_size);
+ $this->response_body = substr($this->response, $header_size);
+ $this->response_code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
+ $this->response_info = curl_getinfo($curl_handle);
+
+ if (intval($this->response_code) / 100 != 2 && isset($this->write_file))
+ {
+ $this->response_headers = $this->response_raw_headers;
+ $this->response_body = $this->response_error_body;
+ }
+
+ // Parse out the headers
+ $this->response_headers = explode("\r\n\r\n", trim($this->response_headers));
+ $this->response_headers = array_pop($this->response_headers);
+ $this->response_headers = explode("\r\n", $this->response_headers);
+ array_shift($this->response_headers);
+
+ // Loop through and split up the headers.
+ $header_assoc = array();
+ foreach ($this->response_headers as $header) {
+ $kv = explode(': ', $header);
+ $header_assoc[strtolower($kv[0])] = isset($kv[1]) ? $kv[1] : '';
+ }
+
+ // Reset the headers to the appropriate property.
+ $this->response_headers = $header_assoc;
+ $this->response_headers['info'] = $this->response_info;
+ $this->response_headers['info']['method'] = $this->method;
+
+ if ($curl_handle && $response) {
+ return new ResponseCore($this->response_headers, $this->response_body, $this->response_code);
+ }
+ }
+
+ // Return false
+ return false;
+ }
+
+ /**
+ * Sends the request, calling necessary utility functions to update built-in properties.
+ *
+ * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not.
+ * @return string The resulting unparsed data from the request.
+ */
+ public function send_request($parse = false)
+ {
+ set_time_limit(0);
+
+ $curl_handle = $this->prep_request();
+ $this->response = curl_exec($curl_handle);
+
+ if ($this->response === false) {
+ throw new RequestCore_Exception('cURL resource: ' . (string)$curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')');
+ }
+
+ $parsed_response = $this->process_response($curl_handle, $this->response);
+
+ curl_close($curl_handle);
+
+ if ($parse) {
+ return $parsed_response;
+ }
+
+ return $this->response;
+ }
+
+ /*%******************************************************************************************%*/
+ // RESPONSE METHODS
+
+ /**
+ * Get the HTTP response headers from the request.
+ *
+ * @param string $header (Optional) A specific header value to return. Defaults to all headers.
+ * @return string|array All or selected header values.
+ */
+ public function get_response_header($header = null)
+ {
+ if ($header) {
+ return $this->response_headers[strtolower($header)];
+ }
+ return $this->response_headers;
+ }
+
+ /**
+ * Get the HTTP response body from the request.
+ *
+ * @return string The response body.
+ */
+ public function get_response_body()
+ {
+ return $this->response_body;
+ }
+
+ /**
+ * Get the HTTP response code from the request.
+ *
+ * @return string The HTTP response code.
+ */
+ public function get_response_code()
+ {
+ return $this->response_code;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore_Exception.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore_Exception.php
new file mode 100755
index 0000000..cb4e83c
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore_Exception.php
@@ -0,0 +1,8 @@
+).
+ * @param string $body (Required) XML-formatted response from AWS.
+ * @param integer $status (Optional) HTTP response status code from the request.
+ * @return Mixed Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code.
+ */
+ public function __construct($header, $body, $status = null)
+ {
+ $this->header = $header;
+ $this->body = $body;
+ $this->status = $status;
+
+ return $this;
+ }
+
+ /**
+ * Did we receive the status code we expected?
+ *
+ * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values.
+ * @return boolean Whether we received the expected status code or not.
+ */
+ public function isOK($codes = array(200, 201, 204, 206))
+ {
+ if (is_array($codes)) {
+ return in_array($this->status, $codes);
+ }
+
+ return $this->status === $codes;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/BucketInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/BucketInfo.php
new file mode 100755
index 0000000..9b89674
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/BucketInfo.php
@@ -0,0 +1,78 @@
+location = $location;
+ $this->name = $name;
+ $this->createDate = $createDate;
+ }
+
+ /**
+ * 得到bucket所在的region
+ *
+ * @return string
+ */
+ public function getLocation()
+ {
+ return $this->location;
+ }
+
+ /**
+ * 得到bucket的名称
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * 得到bucket的创建时间
+ *
+ * @return string
+ */
+ public function getCreateDate()
+ {
+ return $this->createDate;
+ }
+
+ /**
+ * bucket所在的region
+ *
+ * @var string
+ */
+ private $location;
+ /**
+ * bucket的名称
+ *
+ * @var string
+ */
+ private $name;
+
+ /**
+ * bucket的创建事件
+ *
+ * @var string
+ */
+ private $createDate;
+
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/BucketListInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/BucketListInfo.php
new file mode 100755
index 0000000..910717f
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/BucketListInfo.php
@@ -0,0 +1,39 @@
+bucketList = $bucketList;
+ }
+
+ /**
+ * 得到BucketInfo列表
+ *
+ * @return BucketInfo[]
+ */
+ public function getBucketList()
+ {
+ return $this->bucketList;
+ }
+
+ /**
+ * BucketInfo信息列表
+ *
+ * @var array
+ */
+ private $bucketList = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CnameConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CnameConfig.php
new file mode 100755
index 0000000..f3597d2
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CnameConfig.php
@@ -0,0 +1,99 @@
+cnameList = array();
+ }
+
+ /**
+ * @return array
+ * @example
+ * array(2) {
+ * [0]=>
+ * array(3) {
+ * ["Domain"]=>
+ * string(11) "www.foo.com"
+ * ["Status"]=>
+ * string(7) "enabled"
+ * ["LastModified"]=>
+ * string(8) "20150101"
+ * }
+ * [1]=>
+ * array(3) {
+ * ["Domain"]=>
+ * string(7) "bar.com"
+ * ["Status"]=>
+ * string(8) "disabled"
+ * ["LastModified"]=>
+ * string(8) "20160101"
+ * }
+ * }
+ */
+ public function getCnames()
+ {
+ return $this->cnameList;
+ }
+
+
+ public function addCname($cname)
+ {
+ if (count($this->cnameList) >= self::OSS_MAX_RULES) {
+ throw new OssException(
+ "num of cname in the config exceeds self::OSS_MAX_RULES: " . strval(self::OSS_MAX_RULES));
+ }
+ $this->cnameList[] = array('Domain' => $cname);
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->Cname)) return;
+ foreach ($xml->Cname as $entry) {
+ $cname = array();
+ foreach ($entry as $key => $value) {
+ $cname[strval($key)] = strval($value);
+ }
+ $this->cnameList[] = $cname;
+ }
+ }
+
+ public function serializeToXml()
+ {
+ $strXml = <<
+
+
+EOF;
+ $xml = new \SimpleXMLElement($strXml);
+ foreach ($this->cnameList as $cname) {
+ $node = $xml->addChild('Cname');
+ foreach ($cname as $key => $value) {
+ $node->addChild($key, $value);
+ }
+ }
+ return $xml->asXML();
+ }
+
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ const OSS_MAX_RULES = 10;
+
+ private $cnameList = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CorsConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CorsConfig.php
new file mode 100755
index 0000000..c44c10a
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CorsConfig.php
@@ -0,0 +1,113 @@
+rules = array();
+ }
+
+ /**
+ * 得到CorsRule列表
+ *
+ * @return CorsRule[]
+ */
+ public function getRules()
+ {
+ return $this->rules;
+ }
+
+
+ /**
+ * 添加一条CorsRule
+ *
+ * @param CorsRule $rule
+ * @throws OssException
+ */
+ public function addRule($rule)
+ {
+ if (count($this->rules) >= self::OSS_MAX_RULES) {
+ throw new OssException("num of rules in the config exceeds self::OSS_MAX_RULES: " . strval(self::OSS_MAX_RULES));
+ }
+ $this->rules[] = $rule;
+ }
+
+ /**
+ * 从xml数据中解析出CorsConfig
+ *
+ * @param string $strXml
+ * @throws OssException
+ * @return null
+ */
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->CORSRule)) return;
+ foreach ($xml->CORSRule as $rule) {
+ $corsRule = new CorsRule();
+ foreach ($rule as $key => $value) {
+ if ($key === self::OSS_CORS_ALLOWED_HEADER) {
+ $corsRule->addAllowedHeader(strval($value));
+ } elseif ($key === self::OSS_CORS_ALLOWED_METHOD) {
+ $corsRule->addAllowedMethod(strval($value));
+ } elseif ($key === self::OSS_CORS_ALLOWED_ORIGIN) {
+ $corsRule->addAllowedOrigin(strval($value));
+ } elseif ($key === self::OSS_CORS_EXPOSE_HEADER) {
+ $corsRule->addExposeHeader(strval($value));
+ } elseif ($key === self::OSS_CORS_MAX_AGE_SECONDS) {
+ $corsRule->setMaxAgeSeconds(strval($value));
+ }
+ }
+ $this->addRule($corsRule);
+ }
+ return;
+ }
+
+ /**
+ * 生成xml字符串
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ foreach ($this->rules as $rule) {
+ $xmlRule = $xml->addChild('CORSRule');
+ $rule->appendToXml($xmlRule);
+ }
+ return $xml->asXML();
+ }
+
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ const OSS_CORS_ALLOWED_ORIGIN = 'AllowedOrigin';
+ const OSS_CORS_ALLOWED_METHOD = 'AllowedMethod';
+ const OSS_CORS_ALLOWED_HEADER = 'AllowedHeader';
+ const OSS_CORS_EXPOSE_HEADER = 'ExposeHeader';
+ const OSS_CORS_MAX_AGE_SECONDS = 'MaxAgeSeconds';
+ const OSS_MAX_RULES = 10;
+
+ /**
+ * orsRule列表
+ *
+ * @var CorsRule[]
+ */
+ private $rules = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CorsRule.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CorsRule.php
new file mode 100755
index 0000000..2cbe1c1
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/CorsRule.php
@@ -0,0 +1,150 @@
+allowedOrigins[] = $allowedOrigin;
+ }
+ }
+
+ /**
+ * Rule中增加一条allowedMethod
+ *
+ * @param string $allowedMethod
+ */
+ public function addAllowedMethod($allowedMethod)
+ {
+ if (!empty($allowedMethod)) {
+ $this->allowedMethods[] = $allowedMethod;
+ }
+ }
+
+ /**
+ * Rule中增加一条allowedHeader
+ *
+ * @param string $allowedHeader
+ */
+ public function addAllowedHeader($allowedHeader)
+ {
+ if (!empty($allowedHeader)) {
+ $this->allowedHeaders[] = $allowedHeader;
+ }
+ }
+
+ /**
+ * Rule中增加一条exposeHeader
+ *
+ * @param string $exposeHeader
+ */
+ public function addExposeHeader($exposeHeader)
+ {
+ if (!empty($exposeHeader)) {
+ $this->exposeHeaders[] = $exposeHeader;
+ }
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxAgeSeconds()
+ {
+ return $this->maxAgeSeconds;
+ }
+
+ /**
+ * @param int $maxAgeSeconds
+ */
+ public function setMaxAgeSeconds($maxAgeSeconds)
+ {
+ $this->maxAgeSeconds = $maxAgeSeconds;
+ }
+
+ /**
+ * 得到AllowedHeaders列表
+ *
+ * @return string[]
+ */
+ public function getAllowedHeaders()
+ {
+ return $this->allowedHeaders;
+ }
+
+ /**
+ * 得到AllowedOrigins列表
+ *
+ * @return string[]
+ */
+ public function getAllowedOrigins()
+ {
+ return $this->allowedOrigins;
+ }
+
+ /**
+ * 得到AllowedMethods列表
+ *
+ * @return string[]
+ */
+ public function getAllowedMethods()
+ {
+ return $this->allowedMethods;
+ }
+
+ /**
+ * 得到ExposeHeaders列表
+ *
+ * @return string[]
+ */
+ public function getExposeHeaders()
+ {
+ return $this->exposeHeaders;
+ }
+
+ /**
+ * 根据提供的xmlRule, 把this按照一定的规则插入到$xmlRule中
+ *
+ * @param \SimpleXMLElement $xmlRule
+ * @throws OssException
+ */
+ public function appendToXml(&$xmlRule)
+ {
+ if (!isset($this->maxAgeSeconds)) {
+ throw new OssException("maxAgeSeconds is not set in the Rule");
+ }
+ foreach ($this->allowedOrigins as $allowedOrigin) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_ORIGIN, $allowedOrigin);
+ }
+ foreach ($this->allowedMethods as $allowedMethod) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_METHOD, $allowedMethod);
+ }
+ foreach ($this->allowedHeaders as $allowedHeader) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_HEADER, $allowedHeader);
+ }
+ foreach ($this->exposeHeaders as $exposeHeader) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_EXPOSE_HEADER, $exposeHeader);
+ }
+ $xmlRule->addChild(CorsConfig::OSS_CORS_MAX_AGE_SECONDS, strval($this->maxAgeSeconds));
+ }
+
+ private $allowedHeaders = array();
+ private $allowedOrigins = array();
+ private $allowedMethods = array();
+ private $exposeHeaders = array();
+ private $maxAgeSeconds = null;
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelHistory.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelHistory.php
new file mode 100755
index 0000000..6643444
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelHistory.php
@@ -0,0 +1,34 @@
+liveRecordList;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+
+ if (isset($xml->LiveRecord)) {
+ foreach ($xml->LiveRecord as $record) {
+ $liveRecord = new LiveChannelHistory();
+ $liveRecord->parseFromXmlNode($record);
+ $this->liveRecordList[] = $liveRecord;
+ }
+ }
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $liveRecordList = array();
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelInfo.php
new file mode 100755
index 0000000..0b5edfc
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelInfo.php
@@ -0,0 +1,68 @@
+description;
+ }
+
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ public function getFragDuration()
+ {
+ return $this->fragDuration;
+ }
+
+ public function getFragCount()
+ {
+ return $this->fragCount;
+ }
+
+ public function getPlayListName()
+ {
+ return $this->playlistName;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+
+ $this->description = strval($xml->Description);
+ $this->status = strval($xml->Status);
+
+ if (isset($xml->Target)) {
+ foreach ($xml->Target as $target) {
+ $this->type = strval($target->Type);
+ $this->fragDuration = strval($target->FragDuration);
+ $this->fragCount = strval($target->FragCount);
+ $this->playlistName = strval($target->PlaylistName);
+ }
+ }
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $description;
+ private $status;
+ private $type;
+ private $fragDuration;
+ private $fragCount;
+ private $playlistName;
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelStatus.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelStatus.php
new file mode 100755
index 0000000..2ee7a68
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/GetLiveChannelStatus.php
@@ -0,0 +1,107 @@
+status;
+ }
+
+ public function getConnectedTime()
+ {
+ return $this->connectedTime;
+ }
+
+ public function getRemoteAddr()
+ {
+ return $this->remoteAddr;
+ }
+
+ public function getVideoWidth()
+ {
+ return $this->videoWidth;
+ }
+ public function getVideoHeight()
+ {
+ return $this->videoHeight;
+ }
+ public function getVideoFrameRate()
+ {
+ return $this->videoFrameRate;
+ }
+ public function getVideoBandwidth()
+ {
+ return $this->videoBandwidth;
+ }
+ public function getVideoCodec()
+ {
+ return $this->videoCodec;
+ }
+
+ public function getAudioBandwidth()
+ {
+ return $this->audioBandwidth;
+ }
+ public function getAudioSampleRate()
+ {
+ return $this->audioSampleRate;
+ }
+ public function getAudioCodec()
+ {
+ return $this->audioCodec;
+ }
+
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->status = strval($xml->Status);
+ $this->connectedTime = strval($xml->ConnectedTime);
+ $this->remoteAddr = strval($xml->RemoteAddr);
+
+ if (isset($xml->Video)) {
+ foreach ($xml->Video as $video) {
+ $this->videoWidth = intval($video->Width);
+ $this->videoHeight = intval($video->Height);
+ $this->videoFrameRate = intval($video->FrameRate);
+ $this->videoBandwidth = intval($video->Bandwidth);
+ $this->videoCodec = strval($video->Codec);
+ }
+ }
+
+ if (isset($xml->Video)) {
+ foreach ($xml->Audio as $audio) {
+ $this->audioBandwidth = intval($audio->Bandwidth);
+ $this->audioSampleRate = intval($audio->SampleRate);
+ $this->audioCodec = strval($audio->Codec);
+ }
+ }
+
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $status;
+ private $connectedTime;
+ private $remoteAddr;
+
+ private $videoWidth;
+ private $videoHeight;
+ private $videoFrameRate;
+ private $videoBandwidth;
+ private $videoCodec;
+
+ private $audioBandwidth;
+ private $audioSampleRate;
+ private $audioCodec;
+
+
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleAction.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleAction.php
new file mode 100755
index 0000000..5abd825
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleAction.php
@@ -0,0 +1,88 @@
+action = $action;
+ $this->timeSpec = $timeSpec;
+ $this->timeValue = $timeValue;
+ }
+
+ /**
+ * @return LifecycleAction
+ */
+ public function getAction()
+ {
+ return $this->action;
+ }
+
+ /**
+ * @param string $action
+ */
+ public function setAction($action)
+ {
+ $this->action = $action;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTimeSpec()
+ {
+ return $this->timeSpec;
+ }
+
+ /**
+ * @param string $timeSpec
+ */
+ public function setTimeSpec($timeSpec)
+ {
+ $this->timeSpec = $timeSpec;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTimeValue()
+ {
+ return $this->timeValue;
+ }
+
+ /**
+ * @param string $timeValue
+ */
+ public function setTimeValue($timeValue)
+ {
+ $this->timeValue = $timeValue;
+ }
+
+ /**
+ * appendToXml 把actions插入到xml中
+ *
+ * @param \SimpleXMLElement $xmlRule
+ */
+ public function appendToXml(&$xmlRule)
+ {
+ $xmlAction = $xmlRule->addChild($this->action);
+ $xmlAction->addChild($this->timeSpec, $this->timeValue);
+ }
+
+ private $action;
+ private $timeSpec;
+ private $timeValue;
+
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleConfig.php
new file mode 100755
index 0000000..fc4f575
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleConfig.php
@@ -0,0 +1,107 @@
+rules = array();
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->Rule)) return;
+ $this->rules = array();
+ foreach ($xml->Rule as $rule) {
+ $id = strval($rule->ID);
+ $prefix = strval($rule->Prefix);
+ $status = strval($rule->Status);
+ $actions = array();
+ foreach ($rule as $key => $value) {
+ if ($key === 'ID' || $key === 'Prefix' || $key === 'Status') continue;
+ $action = $key;
+ $timeSpec = null;
+ $timeValue = null;
+ foreach ($value as $timeSpecKey => $timeValueValue) {
+ $timeSpec = $timeSpecKey;
+ $timeValue = strval($timeValueValue);
+ }
+ $actions[] = new LifecycleAction($action, $timeSpec, $timeValue);
+ }
+ $this->rules[] = new LifecycleRule($id, $prefix, $status, $actions);
+ }
+ return;
+ }
+
+
+ /**
+ * 生成xml字符串
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+
+ $xml = new \SimpleXMLElement(' ');
+ foreach ($this->rules as $rule) {
+ $xmlRule = $xml->addChild('Rule');
+ $rule->appendToXml($xmlRule);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ *
+ * 添加LifecycleRule
+ *
+ * @param LifecycleRule $lifecycleRule
+ * @throws OssException
+ */
+ public function addRule($lifecycleRule)
+ {
+ if (!isset($lifecycleRule)) {
+ throw new OssException("lifecycleRule is null");
+ }
+ $this->rules[] = $lifecycleRule;
+ }
+
+ /**
+ * 将配置转换成字符串,便于用户查看
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * 得到所有的生命周期规则
+ *
+ * @return LifecycleRule[]
+ */
+ public function getRules()
+ {
+ return $this->rules;
+ }
+
+ /**
+ * @var LifecycleRule[]
+ */
+ private $rules;
+}
+
+
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleRule.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleRule.php
new file mode 100755
index 0000000..ec615b9
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LifecycleRule.php
@@ -0,0 +1,126 @@
+id;
+ }
+
+ /**
+ * @param string $id 规则ID
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ }
+
+ /**
+ * 得到文件前缀
+ *
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * 设置文件前缀
+ *
+ * @param string $prefix 文件前缀
+ */
+ public function setPrefix($prefix)
+ {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * Lifecycle规则的状态
+ *
+ * @return string
+ */
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * 设置Lifecycle规则状态
+ *
+ * @param string $status
+ */
+ public function setStatus($status)
+ {
+ $this->status = $status;
+ }
+
+ /**
+ *
+ * @return LifecycleAction[]
+ */
+ public function getActions()
+ {
+ return $this->actions;
+ }
+
+ /**
+ * @param LifecycleAction[] $actions
+ */
+ public function setActions($actions)
+ {
+ $this->actions = $actions;
+ }
+
+
+ /**
+ * LifecycleRule constructor.
+ *
+ * @param string $id 规则ID
+ * @param string $prefix 文件前缀
+ * @param string $status 规则状态,可选[self::LIFECYCLE_STATUS_ENABLED, self::LIFECYCLE_STATUS_DISABLED]
+ * @param LifecycleAction[] $actions
+ */
+ public function __construct($id, $prefix, $status, $actions)
+ {
+ $this->id = $id;
+ $this->prefix = $prefix;
+ $this->status = $status;
+ $this->actions = $actions;
+ }
+
+ /**
+ * @param \SimpleXMLElement $xmlRule
+ */
+ public function appendToXml(&$xmlRule)
+ {
+ $xmlRule->addChild('ID', $this->id);
+ $xmlRule->addChild('Prefix', $this->prefix);
+ $xmlRule->addChild('Status', $this->status);
+ foreach ($this->actions as $action) {
+ $action->appendToXml($xmlRule);
+ }
+ }
+
+ private $id;
+ private $prefix;
+ private $status;
+ private $actions = array();
+
+ const LIFECYCLE_STATUS_ENABLED = 'Enabled';
+ const LIFECYCLE_STATUS_DISABLED = 'Disabled';
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ListMultipartUploadInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ListMultipartUploadInfo.php
new file mode 100755
index 0000000..105d005
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ListMultipartUploadInfo.php
@@ -0,0 +1,134 @@
+bucket = $bucket;
+ $this->keyMarker = $keyMarker;
+ $this->uploadIdMarker = $uploadIdMarker;
+ $this->nextKeyMarker = $nextKeyMarker;
+ $this->nextUploadIdMarker = $nextUploadIdMarker;
+ $this->delimiter = $delimiter;
+ $this->prefix = $prefix;
+ $this->maxUploads = $maxUploads;
+ $this->isTruncated = $isTruncated;
+ $this->uploads = $uploads;
+ }
+
+ /**
+ * 得到bucket名称
+ *
+ * @return string
+ */
+ public function getBucket()
+ {
+ return $this->bucket;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKeyMarker()
+ {
+ return $this->keyMarker;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getUploadIdMarker()
+ {
+ return $this->uploadIdMarker;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextKeyMarker()
+ {
+ return $this->nextKeyMarker;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextUploadIdMarker()
+ {
+ return $this->nextUploadIdMarker;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDelimiter()
+ {
+ return $this->delimiter;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxUploads()
+ {
+ return $this->maxUploads;
+ }
+
+ /**
+ * @return string
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * @return UploadInfo[]
+ */
+ public function getUploads()
+ {
+ return $this->uploads;
+ }
+
+ private $bucket = "";
+ private $keyMarker = "";
+ private $uploadIdMarker = "";
+ private $nextKeyMarker = "";
+ private $nextUploadIdMarker = "";
+ private $delimiter = "";
+ private $prefix = "";
+ private $maxUploads = 0;
+ private $isTruncated = "false";
+ private $uploads = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ListPartsInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ListPartsInfo.php
new file mode 100755
index 0000000..f1d10ee
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ListPartsInfo.php
@@ -0,0 +1,97 @@
+bucket = $bucket;
+ $this->key = $key;
+ $this->uploadId = $uploadId;
+ $this->nextPartNumberMarker = $nextPartNumberMarker;
+ $this->maxParts = $maxParts;
+ $this->isTruncated = $isTruncated;
+ $this->listPart = $listPart;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBucket()
+ {
+ return $this->bucket;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUploadId()
+ {
+ return $this->uploadId;
+ }
+
+ /**
+ * @return int
+ */
+ public function getNextPartNumberMarker()
+ {
+ return $this->nextPartNumberMarker;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxParts()
+ {
+ return $this->maxParts;
+ }
+
+ /**
+ * @return string
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * @return array
+ */
+ public function getListPart()
+ {
+ return $this->listPart;
+ }
+
+ private $bucket = "";
+ private $key = "";
+ private $uploadId = "";
+ private $nextPartNumberMarker = 0;
+ private $maxParts = 0;
+ private $isTruncated = "";
+ private $listPart = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelConfig.php
new file mode 100755
index 0000000..dadedc9
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelConfig.php
@@ -0,0 +1,121 @@
+description = $option['description'];
+ }
+ if (isset($option['status'])) {
+ $this->status = $option['status'];
+ }
+ if (isset($option['type'])) {
+ $this->type = $option['type'];
+ }
+ if (isset($option['fragDuration'])) {
+ $this->fragDuration = $option['fragDuration'];
+ }
+ if (isset($option['fragCount'])) {
+ $this->fragCount = $option['fragCount'];
+ }
+ if (isset($option['playListName'])) {
+ $this->playListName = $option['playListName'];
+ }
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ public function getFragDuration()
+ {
+ return $this->fragDuration;
+ }
+
+ public function getFragCount()
+ {
+ return $this->fragCount;
+ }
+
+ public function getPlayListName()
+ {
+ return $this->playListName;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->description = strval($xml->Description);
+ $this->status = strval($xml->Status);
+ $target = $xml->Target;
+ $this->type = strval($target->Type);
+ $this->fragDuration = intval($target->FragDuration);
+ $this->fragCount = intval($target->FragCount);
+ $this->playListName = strval($target->PlayListName);
+ }
+
+ public function serializeToXml()
+ {
+ $strXml = <<
+
+
+EOF;
+ $xml = new \SimpleXMLElement($strXml);
+ if (isset($this->description)) {
+ $xml->addChild('Description', $this->description);
+ }
+
+ if (isset($this->status)) {
+ $xml->addChild('Status', $this->status);
+ }
+
+ $node = $xml->addChild('Target');
+ $node->addChild('Type', $this->type);
+
+ if (isset($this->fragDuration)) {
+ $node->addChild('FragDuration', $this->fragDuration);
+ }
+
+ if (isset($this->fragCount)) {
+ $node->addChild('FragCount', $this->fragCount);
+ }
+
+ if (isset($this->playListName)) {
+ $node->addChild('PlayListName', $this->playListName);
+ }
+
+ return $xml->asXML();
+ }
+
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ private $description;
+ private $status = "enabled";
+ private $type;
+ private $fragDuration = 5;
+ private $fragCount = 3;
+ private $playListName = "playlist.m3u8";
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelHistory.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelHistory.php
new file mode 100755
index 0000000..1c1fd4d
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelHistory.php
@@ -0,0 +1,59 @@
+startTime;
+ }
+
+ public function getEndTime()
+ {
+ return $this->endTime;
+ }
+
+ public function getRemoteAddr()
+ {
+ return $this->remoteAddr;
+ }
+
+ public function parseFromXmlNode($xml)
+ {
+ if (isset($xml->StartTime)) {
+ $this->startTime = strval($xml->StartTime);
+ }
+
+ if (isset($xml->EndTime)) {
+ $this->endTime = strval($xml->EndTime);
+ }
+
+ if (isset($xml->RemoteAddr)) {
+ $this->remoteAddr = strval($xml->RemoteAddr);
+ }
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->parseFromXmlNode($xml);
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $startTime;
+ private $endTime;
+ private $remoteAddr;
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelInfo.php
new file mode 100755
index 0000000..c63ec54
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelInfo.php
@@ -0,0 +1,107 @@
+name = $name;
+ $this->description = $description;
+ $this->publishUrls = array();
+ $this->playUrls = array();
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ public function getPublishUrls()
+ {
+ return $this->publishUrls;
+ }
+
+ public function getPlayUrls()
+ {
+ return $this->playUrls;
+ }
+
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function getLastModified()
+ {
+ return $this->lastModified;
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ public function setDescription($description)
+ {
+ $this->description = $description;
+ }
+
+ public function parseFromXmlNode($xml)
+ {
+ if (isset($xml->Name)) {
+ $this->name = strval($xml->Name);
+ }
+
+ if (isset($xml->Description)) {
+ $this->description = strval($xml->Description);
+ }
+
+ if (isset($xml->Status)) {
+ $this->status = strval($xml->Status);
+ }
+
+ if (isset($xml->LastModified)) {
+ $this->lastModified = strval($xml->LastModified);
+ }
+
+ if (isset($xml->PublishUrls)) {
+ foreach ($xml->PublishUrls as $url) {
+ $this->publishUrls[] = strval($url->Url);
+ }
+ }
+
+ if (isset($xml->PlayUrls)) {
+ foreach ($xml->PlayUrls as $url) {
+ $this->playUrls[] = strval($url->Url);
+ }
+ }
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->parseFromXmlNode($xml);
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $name;
+ private $description;
+ private $publishUrls;
+ private $playUrls;
+ private $status;
+ private $lastModified;
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelListInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelListInfo.php
new file mode 100755
index 0000000..bb5093a
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LiveChannelListInfo.php
@@ -0,0 +1,107 @@
+bucket;
+ }
+
+ public function setBucketName($name)
+ {
+ $this->bucket = $name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxKeys()
+ {
+ return $this->maxKeys;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * @return LiveChannelInfo[]
+ */
+ public function getChannelList()
+ {
+ return $this->channelList;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+
+ $this->prefix = strval($xml->Prefix);
+ $this->marker = strval($xml->Marker);
+ $this->maxKeys = intval($xml->MaxKeys);
+ $this->isTruncated = (strval($xml->IsTruncated) == 'true');
+ $this->nextMarker = strval($xml->NextMarker);
+
+ if (isset($xml->LiveChannel)) {
+ foreach ($xml->LiveChannel as $chan) {
+ $channel = new LiveChannelInfo();
+ $channel->parseFromXmlNode($chan);
+ $this->channelList[] = $channel;
+ }
+ }
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $bucket = '';
+ private $prefix = '';
+ private $marker = '';
+ private $nextMarker = '';
+ private $maxKeys = 100;
+ private $isTruncated = 'false';
+ private $channelList = array();
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LoggingConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LoggingConfig.php
new file mode 100755
index 0000000..978421a
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/LoggingConfig.php
@@ -0,0 +1,86 @@
+targetBucket = $targetBucket;
+ $this->targetPrefix = $targetPrefix;
+ }
+
+ /**
+ * @param $strXml
+ * @return null
+ */
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->LoggingEnabled)) return;
+ foreach ($xml->LoggingEnabled as $status) {
+ foreach ($status as $key => $value) {
+ if ($key === 'TargetBucket') {
+ $this->targetBucket = strval($value);
+ } elseif ($key === 'TargetPrefix') {
+ $this->targetPrefix = strval($value);
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * 序列化成xml字符串
+ *
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ if (isset($this->targetBucket) && isset($this->targetPrefix)) {
+ $loggingEnabled = $xml->addChild('LoggingEnabled');
+ $loggingEnabled->addChild('TargetBucket', $this->targetBucket);
+ $loggingEnabled->addChild('TargetPrefix', $this->targetPrefix);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * @return string
+ */
+ public function getTargetBucket()
+ {
+ return $this->targetBucket;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTargetPrefix()
+ {
+ return $this->targetPrefix;
+ }
+
+ private $targetBucket = "";
+ private $targetPrefix = "";
+
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectInfo.php
new file mode 100755
index 0000000..2ae6c99
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectInfo.php
@@ -0,0 +1,93 @@
+key = $key;
+ $this->lastModified = $lastModified;
+ $this->eTag = $eTag;
+ $this->type = $type;
+ $this->size = $size;
+ $this->storageClass = $storageClass;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastModified()
+ {
+ return $this->lastModified;
+ }
+
+ /**
+ * @return string
+ */
+ public function getETag()
+ {
+ return $this->eTag;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * @return string
+ */
+ public function getStorageClass()
+ {
+ return $this->storageClass;
+ }
+
+ private $key = "";
+ private $lastModified = "";
+ private $eTag = "";
+ private $type = "";
+ private $size = 0;
+ private $storageClass = "";
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectListInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectListInfo.php
new file mode 100755
index 0000000..dbe7c7a
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectListInfo.php
@@ -0,0 +1,126 @@
+bucketName = $bucketName;
+ $this->prefix = $prefix;
+ $this->marker = $marker;
+ $this->nextMarker = $nextMarker;
+ $this->maxKeys = $maxKeys;
+ $this->delimiter = $delimiter;
+ $this->isTruncated = $isTruncated;
+ $this->objectList = $objectList;
+ $this->prefixList = $prefixList;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBucketName()
+ {
+ return $this->bucketName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxKeys()
+ {
+ return $this->maxKeys;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDelimiter()
+ {
+ return $this->delimiter;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * 返回ListObjects接口返回数据中的ObjectInfo列表
+ *
+ * @return ObjectInfo[]
+ */
+ public function getObjectList()
+ {
+ return $this->objectList;
+ }
+
+ /**
+ * 返回ListObjects接口返回数据中的PrefixInfo列表
+ *
+ * @return PrefixInfo[]
+ */
+ public function getPrefixList()
+ {
+ return $this->prefixList;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ private $bucketName = "";
+ private $prefix = "";
+ private $marker = "";
+ private $nextMarker = "";
+ private $maxKeys = 0;
+ private $delimiter = "";
+ private $isTruncated = null;
+ private $objectList = array();
+ private $prefixList = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/PartInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/PartInfo.php
new file mode 100755
index 0000000..439a84d
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/PartInfo.php
@@ -0,0 +1,63 @@
+partNumber = $partNumber;
+ $this->lastModified = $lastModified;
+ $this->eTag = $eTag;
+ $this->size = $size;
+ }
+
+ /**
+ * @return int
+ */
+ public function getPartNumber()
+ {
+ return $this->partNumber;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastModified()
+ {
+ return $this->lastModified;
+ }
+
+ /**
+ * @return string
+ */
+ public function getETag()
+ {
+ return $this->eTag;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ private $partNumber = 0;
+ private $lastModified = "";
+ private $eTag = "";
+ private $size = 0;
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/PrefixInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/PrefixInfo.php
new file mode 100755
index 0000000..e61eac4
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/PrefixInfo.php
@@ -0,0 +1,36 @@
+prefix = $prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ private $prefix;
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/RefererConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/RefererConfig.php
new file mode 100755
index 0000000..1d7d975
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/RefererConfig.php
@@ -0,0 +1,93 @@
+AllowEmptyReferer)) return;
+ if (!isset($xml->RefererList)) return;
+ $this->allowEmptyReferer =
+ (strval($xml->AllowEmptyReferer) === 'TRUE' || strval($xml->AllowEmptyReferer) === 'true') ? true : false;
+
+ foreach ($xml->RefererList->Referer as $key => $refer) {
+ $this->refererList[] = strval($refer);
+ }
+ }
+
+
+ /**
+ * 把RefererConfig序列化成xml
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ if ($this->allowEmptyReferer) {
+ $xml->addChild('AllowEmptyReferer', 'true');
+ } else {
+ $xml->addChild('AllowEmptyReferer', 'false');
+ }
+ $refererList = $xml->addChild('RefererList');
+ foreach ($this->refererList as $referer) {
+ $refererList->addChild('Referer', $referer);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * @return string
+ */
+ function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * @param boolean $allowEmptyReferer
+ */
+ public function setAllowEmptyReferer($allowEmptyReferer)
+ {
+ $this->allowEmptyReferer = $allowEmptyReferer;
+ }
+
+ /**
+ * @param string $referer
+ */
+ public function addReferer($referer)
+ {
+ $this->refererList[] = $referer;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isAllowEmptyReferer()
+ {
+ return $this->allowEmptyReferer;
+ }
+
+ /**
+ * @return array
+ */
+ public function getRefererList()
+ {
+ return $this->refererList;
+ }
+
+ private $allowEmptyReferer = true;
+ private $refererList = array();
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/UploadInfo.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/UploadInfo.php
new file mode 100755
index 0000000..8eaa363
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/UploadInfo.php
@@ -0,0 +1,55 @@
+key = $key;
+ $this->uploadId = $uploadId;
+ $this->initiated = $initiated;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUploadId()
+ {
+ return $this->uploadId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getInitiated()
+ {
+ return $this->initiated;
+ }
+
+ private $key = "";
+ private $uploadId = "";
+ private $initiated = "";
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/WebsiteConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/WebsiteConfig.php
new file mode 100755
index 0000000..8ea08a0
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/WebsiteConfig.php
@@ -0,0 +1,76 @@
+indexDocument = $indexDocument;
+ $this->errorDocument = $errorDocument;
+ }
+
+ /**
+ * @param string $strXml
+ * @return null
+ */
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (isset($xml->IndexDocument) && isset($xml->IndexDocument->Suffix)) {
+ $this->indexDocument = strval($xml->IndexDocument->Suffix);
+ }
+ if (isset($xml->ErrorDocument) && isset($xml->ErrorDocument->Key)) {
+ $this->errorDocument = strval($xml->ErrorDocument->Key);
+ }
+ }
+
+ /**
+ * 把WebsiteConfig序列化成xml
+ *
+ * @return string
+ * @throws OssException
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ $index_document_part = $xml->addChild('IndexDocument');
+ $error_document_part = $xml->addChild('ErrorDocument');
+ $index_document_part->addChild('Suffix', $this->indexDocument);
+ $error_document_part->addChild('Key', $this->errorDocument);
+ return $xml->asXML();
+ }
+
+ /**
+ * @return string
+ */
+ public function getIndexDocument()
+ {
+ return $this->indexDocument;
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorDocument()
+ {
+ return $this->errorDocument;
+ }
+
+ private $indexDocument = "";
+ private $errorDocument = "";
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/XmlConfig.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/XmlConfig.php
new file mode 100755
index 0000000..d353a22
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Model/XmlConfig.php
@@ -0,0 +1,27 @@
+hostname = $this->checkEndpoint($endpoint, $isCName);
+ $this->accessKeyId = $accessKeyId;
+ $this->accessKeySecret = $accessKeySecret;
+ $this->securityToken = $securityToken;
+ self::checkEnv();
+ }
+
+ /**
+ * 列举用户所有的Bucket[GetService], Endpoint类型为cname不能进行此操作
+ *
+ * @param array $options
+ * @throws OssException
+ * @return BucketListInfo
+ */
+ public function listBuckets($options = NULL)
+ {
+ if ($this->hostType === self::OSS_HOST_TYPE_CNAME) {
+ throw new OssException("operation is not permitted with CName host");
+ }
+ $this->precheckOptions($options);
+ $options[self::OSS_BUCKET] = '';
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $response = $this->auth($options);
+ $result = new ListBucketsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 创建bucket,默认创建的bucket的ACL是OssClient::OSS_ACL_TYPE_PRIVATE
+ *
+ * @param string $bucket
+ * @param string $acl
+ * @param array $options
+ * @return null
+ */
+ public function createBucket($bucket, $acl = self::OSS_ACL_TYPE_PRIVATE, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl);
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除bucket
+ * 如果Bucket不为空(Bucket中有Object,或者有分块上传的碎片),则Bucket无法删除,
+ * 必须删除Bucket中的所有Object以及碎片后,Bucket才能成功删除。
+ *
+ * @param string $bucket
+ * @param array $options
+ * @return null
+ */
+ public function deleteBucket($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 判断bucket是否存在
+ *
+ * @param string $bucket
+ * @return bool
+ * @throws OssException
+ */
+ public function doesBucketExist($bucket)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new ExistResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket的ACL配置情况
+ *
+ * @param string $bucket
+ * @param array $options
+ * @throws OssException
+ * @return string
+ */
+ public function getBucketAcl($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new AclResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置bucket的ACL配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param string $acl 读写权限,可选值 ['private', 'public-read', 'public-read-write']
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketAcl($bucket, $acl, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl);
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取object的ACL属性
+ *
+ * @param string $bucket
+ * @param string $object
+ * @throws OssException
+ * @return string
+ */
+ public function getObjectAcl($bucket, $object)
+ {
+ $options = array();
+ $this->precheckCommon($bucket, $object, $options, true);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new AclResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置object的ACL属性
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $acl 读写权限,可选值 ['default', 'private', 'public-read', 'public-read-write']
+ * @throws OssException
+ * @return null
+ */
+ public function putObjectAcl($bucket, $object, $acl)
+ {
+ $this->precheckCommon($bucket, $object, $options, true);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_ACL => $acl);
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的访问日志配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return LoggingConfig
+ */
+ public function getBucketLogging($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'logging';
+ $response = $this->auth($options);
+ $result = new GetLoggingResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 开启Bucket访问日志记录功能,只有Bucket的所有者才能更改
+ *
+ * @param string $bucket bucket名称
+ * @param string $targetBucket 日志文件存放的bucket
+ * @param string $targetPrefix 日志的文件前缀
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketLogging($bucket, $targetBucket, $targetPrefix, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $this->precheckBucket($targetBucket, 'targetbucket is not allowed empty');
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'logging';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+
+ $loggingConfig = new LoggingConfig($targetBucket, $targetPrefix);
+ $options[self::OSS_CONTENT] = $loggingConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 关闭bucket访问日志记录功能
+ *
+ * @param string $bucket bucket名称
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketLogging($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'logging';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 将bucket设置成静态网站托管模式
+ *
+ * @param string $bucket bucket名称
+ * @param WebsiteConfig $websiteConfig
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketWebsite($bucket, $websiteConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'website';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $websiteConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket的静态网站托管状态
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return WebsiteConfig
+ */
+ public function getBucketWebsite($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'website';
+ $response = $this->auth($options);
+ $result = new GetWebsiteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 关闭bucket的静态网站托管模式
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketWebsite($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'website';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 在指定的bucket上设定一个跨域资源共享(CORS)的规则,如果原规则存在则覆盖原规则
+ *
+ * @param string $bucket bucket名称
+ * @param CorsConfig $corsConfig 跨域资源共享配置,具体规则参见SDK文档
+ * @param array $options array
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketCors($bucket, $corsConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cors';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $corsConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的CORS配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return CorsConfig
+ */
+ public function getBucketCors($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cors';
+ $response = $this->auth($options);
+ $result = new GetCorsResult($response, __FUNCTION__);
+ return $result->getData();
+ }
+
+ /**
+ * 关闭指定Bucket对应的CORS功能并清空所有规则
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketCors($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cors';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 为指定Bucket增加CNAME绑定
+ *
+ * @param string $bucket bucket名称
+ * @param string $cname
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function addBucketCname($bucket, $cname, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cname';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $cnameConfig = new CnameConfig();
+ $cnameConfig->addCname($cname);
+ $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml();
+ $options[self::OSS_COMP] = 'add';
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取指定Bucket已绑定的CNAME列表
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return CnameConfig
+ */
+ public function getBucketCname($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cname';
+ $response = $this->auth($options);
+ $result = new GetCnameResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 解除指定Bucket的CNAME绑定
+ *
+ * @param string $bucket bucket名称
+ * @param CnameConfig $cnameConfig
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketCname($bucket, $cname, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cname';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $cnameConfig = new CnameConfig();
+ $cnameConfig->addCname($cname);
+ $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml();
+ $options[self::OSS_COMP] = 'delete';
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 为指定Bucket创建LiveChannel
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param LiveChannelConfig $channelConfig
+ * @param array $options
+ * @throws OssException
+ * @return LiveChannelInfo
+ */
+ public function putBucketLiveChannel($bucket, $channelName, $channelConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $channelConfig->serializeToXml();
+
+ $response = $this->auth($options);
+ $result = new PutLiveChannelResult($response);
+ $info = $result->getData();
+ $info->setName($channelName);
+ $info->setDescription($channelConfig->getDescription());
+
+ return $info;
+ }
+
+ /**
+ * 设置LiveChannel的status
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param string channelStatus $channelStatus 为enabled或disabled
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function putLiveChannelStatus($bucket, $channelName, $channelStatus, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_LIVE_CHANNEL_STATUS] = $channelStatus;
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取LiveChannel信息
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return GetLiveChannelInfo
+ */
+ public function getLiveChannelInfo($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+
+ $response = $this->auth($options);
+ $result = new GetLiveChannelInfoResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取LiveChannel状态信息
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return GetLiveChannelStatus
+ */
+ public function getLiveChannelStatus($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_COMP] = 'stat';
+
+ $response = $this->auth($options);
+ $result = new GetLiveChannelStatusResult($response);
+ return $result->getData();
+ }
+
+ /**
+ *获取LiveChannel推流记录
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return GetLiveChannelHistory
+ */
+ public function getLiveChannelHistory($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_COMP] = 'history';
+
+ $response = $this->auth($options);
+ $result = new GetLiveChannelHistoryResult($response);
+ return $result->getData();
+ }
+
+ /**
+ *获取指定Bucket下的live channel列表
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return LiveChannelListInfo
+ */
+ public function listBucketLiveChannels($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_QUERY_STRING] = array(
+ 'prefix' => isset($options['prefix']) ? $options['prefix'] : '',
+ 'marker' => isset($options['marker']) ? $options['marker'] : '',
+ 'max-keys' => isset($options['max-keys']) ? $options['max-keys'] : '',
+ );
+ $response = $this->auth($options);
+ $result = new ListLiveChannelResult($response);
+ $list = $result->getData();
+ $list->setBucketName($bucket);
+
+ return $list;
+ }
+
+ /**
+ * 为指定LiveChannel生成播放列表
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param string $playlistName 指定生成的点播播放列表的名称,必须以“.m3u8”结尾
+ * @param array $setTime startTime和EndTime以unix时间戳格式给定,跨度不能超过一天
+ * @throws OssException
+ * @return null
+ */
+ public function postVodPlaylist($bucket, $channelName, $playlistName, $setTime)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = $channelName . '/' . $playlistName;
+ $options[self::OSS_SUB_RESOURCE] = 'vod';
+ $options[self::OSS_LIVE_CHANNEL_END_TIME] = $setTime['EndTime'];
+ $options[self::OSS_LIVE_CHANNEL_START_TIME] = $setTime['StartTime'];
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除指定Bucket的LiveChannel
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketLiveChannel($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 生成带签名的推流地址
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param int timeout 设置超时时间,单位为秒
+ * @param array $options
+ * @throws OssException
+ * @return 推流地址
+ */
+ public function signRtmpUrl($bucket, $channelName, $timeout = 60, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $channelName, $options, false);
+ $expires = time() + $timeout;
+ $proto = 'rtmp://';
+ $hostname = $this->generateHostname($bucket);
+ $cano_params = '';
+ $query_items = array();
+ $params = isset($options['params']) ? $options['params'] : array();
+ uksort($params, 'strnatcasecmp');
+ foreach ($params as $key => $value) {
+ $cano_params = $cano_params . $key . ':' . $value . "\n";
+ $query_items[] = rawurlencode($key) . '=' . rawurlencode($value);
+ }
+ $resource = '/' . $bucket . '/' . $channelName;
+
+ $string_to_sign = $expires . "\n" . $cano_params . $resource;
+ $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));
+
+ $query_items[] = 'OSSAccessKeyId=' . rawurlencode($this->accessKeyId);
+ $query_items[] = 'Expires=' . rawurlencode($expires);
+ $query_items[] = 'Signature=' . rawurlencode($signature);
+
+ return $proto . $hostname . '/live/' . $channelName . '?' . implode('&', $query_items);
+ }
+
+ /**
+ * 检验跨域资源请求, 发送跨域请求之前会发送一个preflight请求(OPTIONS)并带上特定的来源域,
+ * HTTP方法和header信息等给OSS以决定是否发送真正的请求。 OSS可以通过putBucketCors接口
+ * 来开启Bucket的CORS支持,开启CORS功能之后,OSS在收到浏览器preflight请求时会根据设定的
+ * 规则评估是否允许本次请求
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $origin 请求来源域
+ * @param string $request_method 表明实际请求中会使用的HTTP方法
+ * @param string $request_headers 表明实际请求中会使用的除了简单头部之外的headers
+ * @param array $options
+ * @return array
+ * @throws OssException
+ * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/OptionObject.html
+ */
+ public function optionsObject($bucket, $object, $origin, $request_method, $request_headers, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_OPTIONS;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_HEADERS] = array(
+ self::OSS_OPTIONS_ORIGIN => $origin,
+ self::OSS_OPTIONS_REQUEST_HEADERS => $request_headers,
+ self::OSS_OPTIONS_REQUEST_METHOD => $request_method
+ );
+ $response = $this->auth($options);
+ $result = new HeaderResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置Bucket的Lifecycle配置
+ *
+ * @param string $bucket bucket名称
+ * @param LifecycleConfig $lifecycleConfig Lifecycle配置类
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketLifecycle($bucket, $lifecycleConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'lifecycle';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $lifecycleConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的Lifecycle配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return LifecycleConfig
+ */
+ public function getBucketLifecycle($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'lifecycle';
+ $response = $this->auth($options);
+ $result = new GetLifecycleResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除指定Bucket的生命周期配置
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketLifecycle($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'lifecycle';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置一个bucket的referer访问白名单和是否允许referer字段为空的请求访问
+ * Bucket Referer防盗链具体见OSS防盗链
+ *
+ * @param string $bucket bucket名称
+ * @param RefererConfig $refererConfig
+ * @param array $options
+ * @return ResponseCore
+ * @throws null
+ */
+ public function putBucketReferer($bucket, $refererConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'referer';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $refererConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的Referer配置情况
+ * Bucket Referer防盗链具体见OSS防盗链
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return RefererConfig
+ */
+ public function getBucketReferer($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'referer';
+ $response = $this->auth($options);
+ $result = new GetRefererResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket下的object列表
+ *
+ * @param string $bucket
+ * @param array $options
+ * 其中options中的参数如下
+ * $options = array(
+ * 'max-keys' => max-keys用于限定此次返回object的最大数,如果不设定,默认为100,max-keys取值不能大于1000。
+ * 'prefix' => 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。
+ * 'delimiter' => 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素
+ * 'marker' => 用户设定结果从marker之后按字母排序的第一个开始返回。
+ *)
+ * 其中 prefix,marker用来实现分页显示效果,参数的长度必须小于256字节。
+ * @throws OssException
+ * @return ObjectListInfo
+ */
+ public function listObjects($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_HEADERS] = array(
+ self::OSS_DELIMITER => isset($options[self::OSS_DELIMITER]) ? $options[self::OSS_DELIMITER] : '/',
+ self::OSS_PREFIX => isset($options[self::OSS_PREFIX]) ? $options[self::OSS_PREFIX] : '',
+ self::OSS_MAX_KEYS => isset($options[self::OSS_MAX_KEYS]) ? $options[self::OSS_MAX_KEYS] : self::OSS_MAX_KEYS_VALUE,
+ self::OSS_MARKER => isset($options[self::OSS_MARKER]) ? $options[self::OSS_MARKER] : '',
+ );
+ $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array();
+ $options[self::OSS_QUERY_STRING] = array_merge(
+ $query,
+ array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL)
+ );
+
+ $response = $this->auth($options);
+ $result = new ListObjectsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 创建虚拟目录 (本函数会在object名称后增加'/', 所以创建目录的object名称不需要'/'结尾,否则,目录名称会变成'//')
+ *
+ * 暂不开放此接口
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options
+ * @return null
+ */
+ public function createObjectDir($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $object . '/';
+ $options[self::OSS_CONTENT_LENGTH] = array(self::OSS_CONTENT_LENGTH => 0);
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 上传内存中的内容
+ *
+ * @param string $bucket bucket名称
+ * @param string $object objcet名称
+ * @param string $content 上传的内容
+ * @param array $options
+ * @return null
+ */
+ public function putObject($bucket, $object, $content, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+
+ OssUtil::validateContent($content);
+ $options[self::OSS_CONTENT] = $content;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $object;
+
+ if (!isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);
+ } else {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ }
+
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5($content, true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);
+ }
+ $response = $this->auth($options);
+
+ if (isset($options[self::OSS_CALLBACK]) && !empty($options[self::OSS_CALLBACK])) {
+ $result = new CallbackResult($response);
+ } else {
+ $result = new PutSetDeleteResult($response);
+ }
+
+ return $result->getData();
+ }
+
+ /**
+ * 上传本地文件
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $file 本地文件路径
+ * @param array $options
+ * @return null
+ * @throws OssException
+ */
+ public function uploadFile($bucket, $object, $file, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ OssUtil::throwOssExceptionWithMessageIfEmpty($file, "file path is invalid");
+ $file = OssUtil::encodePath($file);
+ if (!file_exists($file)) {
+ throw new OssException($file . " file does not exist");
+ }
+ $options[self::OSS_FILE_UPLOAD] = $file;
+ $file_size = filesize($options[self::OSS_FILE_UPLOAD]);
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file);
+ }
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_CONTENT_LENGTH] = $file_size;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 追加上传内存中的内容
+ *
+ * @param string $bucket bucket名称
+ * @param string $object objcet名称
+ * @param string $content 本次追加上传的内容
+ * @param array $options
+ * @return int next append position
+ * @throws OssException
+ */
+ public function appendObject($bucket, $object, $content, $position, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+
+ OssUtil::validateContent($content);
+ $options[self::OSS_CONTENT] = $content;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = 'append';
+ $options[self::OSS_POSITION] = strval($position);
+
+ if (!isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);
+ } else {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ }
+
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5($content, true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);
+ }
+ $response = $this->auth($options);
+ $result = new AppendResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 追加上传本地文件
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $file 追加上传的本地文件路径
+ * @param array $options
+ * @return int next append position
+ * @throws OssException
+ */
+ public function appendFile($bucket, $object, $file, $position, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+
+ OssUtil::throwOssExceptionWithMessageIfEmpty($file, "file path is invalid");
+ $file = OssUtil::encodePath($file);
+ if (!file_exists($file)) {
+ throw new OssException($file . " file does not exist");
+ }
+ $options[self::OSS_FILE_UPLOAD] = $file;
+ $file_size = filesize($options[self::OSS_FILE_UPLOAD]);
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file);
+ }
+
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_CONTENT_LENGTH] = $file_size;
+ $options[self::OSS_SUB_RESOURCE] = 'append';
+ $options[self::OSS_POSITION] = strval($position);
+
+ $response = $this->auth($options);
+ $result = new AppendResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 拷贝一个在OSS上已经存在的object成另外一个object
+ *
+ * @param string $fromBucket 源bucket名称
+ * @param string $fromObject 源object名称
+ * @param string $toBucket 目标bucket名称
+ * @param string $toObject 目标object名称
+ * @param array $options
+ * @return null
+ * @throws OssException
+ */
+ public function copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options = NULL)
+ {
+ $this->precheckCommon($fromBucket, $fromObject, $options);
+ $this->precheckCommon($toBucket, $toObject, $options);
+ $options[self::OSS_BUCKET] = $toBucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $toObject;
+ if (isset($options[self::OSS_HEADERS])) {
+ $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject;
+ } else {
+ $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_COPY_SOURCE => '/' . $fromBucket . '/' . $fromObject);
+ }
+ $response = $this->auth($options);
+ $result = new CopyObjectResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Object的Meta信息
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $options 具体参考SDK文档
+ * @return array
+ */
+ public function getObjectMeta($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;
+ $options[self::OSS_OBJECT] = $object;
+ $response = $this->auth($options);
+ $result = new HeaderResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除某个Object
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options
+ * @return null
+ */
+ public function deleteObject($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = $object;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除同一个Bucket中的多个Object
+ *
+ * @param string $bucket bucket名称
+ * @param array $objects object列表
+ * @param array $options
+ * @return ResponseCore
+ * @throws null
+ */
+ public function deleteObjects($bucket, $objects, $options = null)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ if (!is_array($objects) || !$objects) {
+ throw new OssException('objects must be array');
+ }
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'delete';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $quiet = 'false';
+ if (isset($options['quiet'])) {
+ if (is_bool($options['quiet'])) { //Boolean
+ $quiet = $options['quiet'] ? 'true' : 'false';
+ } elseif (is_string($options['quiet'])) { // string
+ $quiet = ($options['quiet'] === 'true') ? 'true' : 'false';
+ }
+ }
+ $xmlBody = OssUtil::createDeleteObjectsXmlBody($objects, $quiet);
+ $options[self::OSS_CONTENT] = $xmlBody;
+ $response = $this->auth($options);
+ $result = new DeleteObjectsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获得Object内容
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options 该参数中必须设置ALIOSS::OSS_FILE_DOWNLOAD,ALIOSS::OSS_RANGE可选,可以根据实际情况设置;如果不设置,默认会下载全部内容
+ * @return string
+ */
+ public function getObject($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $object;
+ if (isset($options[self::OSS_LAST_MODIFIED])) {
+ $options[self::OSS_HEADERS][self::OSS_IF_MODIFIED_SINCE] = $options[self::OSS_LAST_MODIFIED];
+ unset($options[self::OSS_LAST_MODIFIED]);
+ }
+ if (isset($options[self::OSS_ETAG])) {
+ $options[self::OSS_HEADERS][self::OSS_IF_NONE_MATCH] = $options[self::OSS_ETAG];
+ unset($options[self::OSS_ETAG]);
+ }
+ if (isset($options[self::OSS_RANGE])) {
+ $range = $options[self::OSS_RANGE];
+ $options[self::OSS_HEADERS][self::OSS_RANGE] = "bytes=$range";
+ unset($options[self::OSS_RANGE]);
+ }
+ $response = $this->auth($options);
+ $result = new BodyResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 检测Object是否存在
+ * 通过获取Object的Meta信息来判断Object是否存在, 用户需要自行解析ResponseCore判断object是否存在
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options
+ * @return bool
+ */
+ public function doesObjectExist($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;
+ $options[self::OSS_OBJECT] = $object;
+ $response = $this->auth($options);
+ $result = new ExistResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取分片大小,根据用户提供的part_size,重新计算一个更合理的partsize
+ *
+ * @param int $partSize
+ * @return int
+ */
+ private function computePartSize($partSize)
+ {
+ $partSize = (integer)$partSize;
+ if ($partSize <= self::OSS_MIN_PART_SIZE) {
+ $partSize = self::OSS_MIN_PART_SIZE;
+ } elseif ($partSize > self::OSS_MAX_PART_SIZE) {
+ $partSize = self::OSS_MAX_PART_SIZE;
+ }
+ return $partSize;
+ }
+
+ /**
+ * 计算文件可以分成多少个part,以及每个part的长度以及起始位置
+ * 方法必须在 中调用
+ *
+ * @param integer $file_size 文件大小
+ * @param integer $partSize part大小,默认5M
+ * @return array An array 包含 key-value 键值对. Key 为 `seekTo` 和 `length`.
+ */
+ public function generateMultiuploadParts($file_size, $partSize = 5242880)
+ {
+ $i = 0;
+ $size_count = $file_size;
+ $values = array();
+ $partSize = $this->computePartSize($partSize);
+ while ($size_count > 0) {
+ $size_count -= $partSize;
+ $values[] = array(
+ self::OSS_SEEK_TO => ($partSize * $i),
+ self::OSS_LENGTH => (($size_count > 0) ? $partSize : ($size_count + $partSize)),
+ );
+ $i++;
+ }
+ return $values;
+ }
+
+ /**
+ * 初始化multi-part upload
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param array $options Key-Value数组
+ * @throws OssException
+ * @return string 返回uploadid
+ */
+ public function initiateMultipartUpload($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = 'uploads';
+ $options[self::OSS_CONTENT] = '';
+
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);
+ }
+ if (!isset($options[self::OSS_HEADERS])) {
+ $options[self::OSS_HEADERS] = array();
+ }
+ $response = $this->auth($options);
+ $result = new InitiateMultipartUploadResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 分片上传的块上传接口
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId
+ * @param array $options Key-Value数组
+ * @return string eTag
+ * @throws OssException
+ */
+ public function uploadPart($bucket, $object, $uploadId, $options = null)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $this->precheckParam($options, self::OSS_FILE_UPLOAD, __FUNCTION__);
+ $this->precheckParam($options, self::OSS_PART_NUM, __FUNCTION__);
+
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+
+ if (isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ }
+ $response = $this->auth($options);
+ $result = new UploadPartResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取已成功上传的part
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId uploadId
+ * @param array $options Key-Value数组
+ * @return ListPartsInfo
+ * @throws OssException
+ */
+ public function listParts($bucket, $object, $uploadId, $options = null)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+ $options[self::OSS_QUERY_STRING] = array();
+ foreach (array('max-parts', 'part-number-marker') as $param) {
+ if (isset($options[$param])) {
+ $options[self::OSS_QUERY_STRING][$param] = $options[$param];
+ unset($options[$param]);
+ }
+ }
+ $response = $this->auth($options);
+ $result = new ListPartsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 中止进行一半的分片上传操作
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId uploadId
+ * @param array $options Key-Value数组
+ * @return null
+ * @throws OssException
+ */
+ public function abortMultipartUpload($bucket, $object, $uploadId, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 在将所有数据Part都上传完成后,调用此接口完成本次分块上传
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId uploadId
+ * @param array $listParts array( array("PartNumber"=> int, "ETag"=>string))
+ * @param array $options Key-Value数组
+ * @throws OssException
+ * @return null
+ */
+ public function completeMultipartUpload($bucket, $object, $uploadId, $listParts, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ if (!is_array($listParts)) {
+ throw new OssException("listParts must be array type");
+ }
+ $options[self::OSS_CONTENT] = OssUtil::createCompleteMultipartUploadXmlBody($listParts);
+ $response = $this->auth($options);
+ if (isset($options[self::OSS_CALLBACK]) && !empty($options[self::OSS_CALLBACK])) {
+ $result = new CallbackResult($response);
+ } else {
+ $result = new PutSetDeleteResult($response);
+ }
+ return $result->getData();
+ }
+
+ /**
+ * 罗列出所有执行中的Multipart Upload事件,即已经被初始化的Multipart Upload但是未被
+ * Complete或者Abort的Multipart Upload事件
+ *
+ * @param string $bucket bucket
+ * @param array $options 关联数组
+ * @throws OssException
+ * @return ListMultipartUploadInfo
+ */
+ public function listMultipartUploads($bucket, $options = null)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'uploads';
+
+ foreach (array('delimiter', 'key-marker', 'max-uploads', 'prefix', 'upload-id-marker') as $param) {
+ if (isset($options[$param])) {
+ $options[self::OSS_QUERY_STRING][$param] = $options[$param];
+ unset($options[$param]);
+ }
+ }
+ $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array();
+ $options[self::OSS_QUERY_STRING] = array_merge(
+ $query,
+ array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL)
+ );
+
+ $response = $this->auth($options);
+ $result = new ListMultipartUploadResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 从一个已存在的Object中拷贝数据来上传一个Part
+ *
+ * @param string $fromBucket 源bucket名称
+ * @param string $fromObject 源object名称
+ * @param string $toBucket 目标bucket名称
+ * @param string $toObject 目标object名称
+ * @param int $partNumber 分块上传的块id
+ * @param string $uploadId 初始化multipart upload返回的uploadid
+ * @param array $options Key-Value数组
+ * @return null
+ * @throws OssException
+ */
+ public function uploadPartCopy($fromBucket, $fromObject, $toBucket, $toObject, $partNumber, $uploadId, $options = NULL)
+ {
+ $this->precheckCommon($fromBucket, $fromObject, $options);
+ $this->precheckCommon($toBucket, $toObject, $options);
+
+ //如果没有设置$options['isFullCopy'],则需要强制判断copy的起止位置
+ $start_range = "0";
+ if (isset($options['start'])) {
+ $start_range = $options['start'];
+ }
+ $end_range = "";
+ if (isset($options['end'])) {
+ $end_range = $options['end'];
+ }
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_BUCKET] = $toBucket;
+ $options[self::OSS_OBJECT] = $toObject;
+ $options[self::OSS_PART_NUM] = $partNumber;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+
+ if (!isset($options[self::OSS_HEADERS])) {
+ $options[self::OSS_HEADERS] = array();
+ }
+
+ $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject;
+ $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE_RANGE] = "bytes=" . $start_range . "-" . $end_range;
+ $response = $this->auth($options);
+ $result = new UploadPartResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * multipart上传统一封装,从初始化到完成multipart,以及出错后中止动作
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $file 需要上传的本地文件的路径
+ * @param array $options Key-Value数组
+ * @return null
+ * @throws OssException
+ */
+ public function multiuploadFile($bucket, $object, $file, $options = null)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ if (isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ unset($options[self::OSS_LENGTH]);
+ }
+ if (empty($file)) {
+ throw new OssException("parameter invalid, file is empty");
+ }
+ $uploadFile = OssUtil::encodePath($file);
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $uploadFile);
+ }
+
+ $upload_position = isset($options[self::OSS_SEEK_TO]) ? (integer)$options[self::OSS_SEEK_TO] : 0;
+
+ if (isset($options[self::OSS_CONTENT_LENGTH])) {
+ $upload_file_size = (integer)$options[self::OSS_CONTENT_LENGTH];
+ } else {
+ $upload_file_size = filesize($uploadFile);
+ if ($upload_file_size !== false) {
+ $upload_file_size -= $upload_position;
+ }
+ }
+
+ if ($upload_position === false || !isset($upload_file_size) || $upload_file_size === false || $upload_file_size < 0) {
+ throw new OssException('The size of `fileUpload` cannot be determined in ' . __FUNCTION__ . '().');
+ }
+ // 处理partSize
+ if (isset($options[self::OSS_PART_SIZE])) {
+ $options[self::OSS_PART_SIZE] = $this->computePartSize($options[self::OSS_PART_SIZE]);
+ } else {
+ $options[self::OSS_PART_SIZE] = self::OSS_MID_PART_SIZE;
+ }
+
+ $is_check_md5 = $this->isCheckMD5($options);
+ // 如果上传的文件小于partSize,则直接使用普通方式上传
+ if ($upload_file_size < $options[self::OSS_PART_SIZE] && !isset($options[self::OSS_UPLOAD_ID])) {
+ return $this->uploadFile($bucket, $object, $uploadFile, $options);
+ }
+
+ // 初始化multipart
+ if (isset($options[self::OSS_UPLOAD_ID])) {
+ $uploadId = $options[self::OSS_UPLOAD_ID];
+ } else {
+ // 初始化
+ $uploadId = $this->initiateMultipartUpload($bucket, $object, $options);
+ }
+
+ // 获取的分片
+ $pieces = $this->generateMultiuploadParts($upload_file_size, (integer)$options[self::OSS_PART_SIZE]);
+ $response_upload_part = array();
+ foreach ($pieces as $i => $piece) {
+ $from_pos = $upload_position + (integer)$piece[self::OSS_SEEK_TO];
+ $to_pos = (integer)$piece[self::OSS_LENGTH] + $from_pos - 1;
+ $up_options = array(
+ self::OSS_FILE_UPLOAD => $uploadFile,
+ self::OSS_PART_NUM => ($i + 1),
+ self::OSS_SEEK_TO => $from_pos,
+ self::OSS_LENGTH => $to_pos - $from_pos + 1,
+ self::OSS_CHECK_MD5 => $is_check_md5,
+ );
+ if ($is_check_md5) {
+ $content_md5 = OssUtil::getMd5SumForFile($uploadFile, $from_pos, $to_pos);
+ $up_options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+ $response_upload_part[] = $this->uploadPart($bucket, $object, $uploadId, $up_options);
+ }
+
+ $uploadParts = array();
+ foreach ($response_upload_part as $i => $etag) {
+ $uploadParts[] = array(
+ 'PartNumber' => ($i + 1),
+ 'ETag' => $etag,
+ );
+ }
+ return $this->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
+ }
+
+ /**
+ * 上传本地目录内的文件或者目录到指定bucket的指定prefix的object中
+ *
+ * @param string $bucket bucket名称
+ * @param string $prefix 需要上传到的object的key前缀,可以理解成bucket中的子目录,结尾不能是'/',接口中会补充'/'
+ * @param string $localDirectory 需要上传的本地目录
+ * @param string $exclude 需要排除的目录
+ * @param bool $recursive 是否递归的上传localDirectory下的子目录内容
+ * @param bool $checkMd5
+ * @return array 返回两个列表 array("succeededList" => array("object"), "failedList" => array("object"=>"errorMessage"))
+ * @throws OssException
+ */
+ public function uploadDir($bucket, $prefix, $localDirectory, $exclude = '.|..|.svn|.git', $recursive = false, $checkMd5 = true)
+ {
+ $retArray = array("succeededList" => array(), "failedList" => array());
+ if (empty($bucket)) throw new OssException("parameter error, bucket is empty");
+ if (!is_string($prefix)) throw new OssException("parameter error, prefix is not string");
+ if (empty($localDirectory)) throw new OssException("parameter error, localDirectory is empty");
+ $directory = $localDirectory;
+ $directory = OssUtil::encodePath($directory);
+ //判断是否目录
+ if (!is_dir($directory)) {
+ throw new OssException('parameter error: ' . $directory . ' is not a directory, please check it');
+ }
+ //read directory
+ $file_list_array = OssUtil::readDir($directory, $exclude, $recursive);
+ if (!$file_list_array) {
+ throw new OssException($directory . ' is empty...');
+ }
+ foreach ($file_list_array as $k => $item) {
+ if (is_dir($item['path'])) {
+ continue;
+ }
+ $options = array(
+ self::OSS_PART_SIZE => self::OSS_MIN_PART_SIZE,
+ self::OSS_CHECK_MD5 => $checkMd5,
+ );
+ $realObject = (!empty($prefix) ? $prefix . '/' : '') . $item['file'];
+
+ try {
+ $this->multiuploadFile($bucket, $realObject, $item['path'], $options);
+ $retArray["succeededList"][] = $realObject;
+ } catch (OssException $e) {
+ $retArray["failedList"][$realObject] = $e->getMessage();
+ }
+ }
+ return $retArray;
+ }
+
+ /**
+ * 支持生成get和put签名, 用户可以生成一个具有一定有效期的
+ * 签名过的url
+ *
+ * @param string $bucket
+ * @param string $object
+ * @param int $timeout
+ * @param string $method
+ * @param array $options Key-Value数组
+ * @return string
+ * @throws OssException
+ */
+ public function signUrl($bucket, $object, $timeout = 60, $method = self::OSS_HTTP_GET, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ //method
+ if (self::OSS_HTTP_GET !== $method && self::OSS_HTTP_PUT !== $method) {
+ throw new OssException("method is invalid");
+ }
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_METHOD] = $method;
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = '';
+ }
+ $timeout = time() + $timeout;
+ $options[self::OSS_PREAUTH] = $timeout;
+ $options[self::OSS_DATE] = $timeout;
+ $this->setSignStsInUrl(true);
+ return $this->auth($options);
+ }
+
+ /**
+ * 检测options参数
+ *
+ * @param array $options
+ * @throws OssException
+ */
+ private function precheckOptions(&$options)
+ {
+ OssUtil::validateOptions($options);
+ if (!$options) {
+ $options = array();
+ }
+ }
+
+ /**
+ * 校验bucket参数
+ *
+ * @param string $bucket
+ * @param string $errMsg
+ * @throws OssException
+ */
+ private function precheckBucket($bucket, $errMsg = 'bucket is not allowed empty')
+ {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($bucket, $errMsg);
+ }
+
+ /**
+ * 校验object参数
+ *
+ * @param string $object
+ * @throws OssException
+ */
+ private function precheckObject($object)
+ {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($object, "object name is empty");
+ }
+
+ /**
+ * 校验bucket,options参数
+ *
+ * @param string $bucket
+ * @param string $object
+ * @param array $options
+ * @param bool $isCheckObject
+ */
+ private function precheckCommon($bucket, $object, &$options, $isCheckObject = true)
+ {
+ if ($isCheckObject) {
+ $this->precheckObject($object);
+ }
+ $this->precheckOptions($options);
+ $this->precheckBucket($bucket);
+ }
+
+ /**
+ * 参数校验
+ *
+ * @param array $options
+ * @param string $param
+ * @param string $funcName
+ * @throws OssException
+ */
+ private function precheckParam($options, $param, $funcName)
+ {
+ if (!isset($options[$param])) {
+ throw new OssException('The `' . $param . '` options is required in ' . $funcName . '().');
+ }
+ }
+
+ /**
+ * 检测md5
+ *
+ * @param array $options
+ * @return bool|null
+ */
+ private function isCheckMD5($options)
+ {
+ return $this->getValue($options, self::OSS_CHECK_MD5, false, true, true);
+ }
+
+ /**
+ * 获取value
+ *
+ * @param array $options
+ * @param string $key
+ * @param string $default
+ * @param bool $isCheckEmpty
+ * @param bool $isCheckBool
+ * @return bool|null
+ */
+ private function getValue($options, $key, $default = NULL, $isCheckEmpty = false, $isCheckBool = false)
+ {
+ $value = $default;
+ if (isset($options[$key])) {
+ if ($isCheckEmpty) {
+ if (!empty($options[$key])) {
+ $value = $options[$key];
+ }
+ } else {
+ $value = $options[$key];
+ }
+ unset($options[$key]);
+ }
+ if ($isCheckBool) {
+ if ($value !== true && $value !== false) {
+ $value = false;
+ }
+ }
+ return $value;
+ }
+
+ /**
+ * 获取mimetype类型
+ *
+ * @param string $object
+ * @return string
+ */
+ private function getMimeType($object, $file = null)
+ {
+ if (!is_null($file)) {
+ $type = MimeTypes::getMimetype($file);
+ if (!is_null($type)) {
+ return $type;
+ }
+ }
+
+ $type = MimeTypes::getMimetype($object);
+ if (!is_null($type)) {
+ return $type;
+ }
+
+ return self::DEFAULT_CONTENT_TYPE;
+ }
+
+ /**
+ * 验证并且执行请求,按照OSS Api协议,执行操作
+ *
+ * @param array $options
+ * @return ResponseCore
+ * @throws OssException
+ * @throws RequestCore_Exception
+ */
+ private function auth($options)
+ {
+ OssUtil::validateOptions($options);
+ //验证bucket,list_bucket时不需要验证
+ $this->authPrecheckBucket($options);
+ //验证object
+ $this->authPrecheckObject($options);
+ //Object名称的编码必须是utf8
+ $this->authPrecheckObjectEncoding($options);
+ //验证ACL
+ $this->authPrecheckAcl($options);
+ // 获得当次请求使用的协议头,是https还是http
+ $scheme = $this->useSSL ? 'https://' : 'http://';
+ // 获得当次请求使用的hostname,如果是公共域名或者专有域名,bucket拼在前面构成三级域名
+ $hostname = $this->generateHostname($options[self::OSS_BUCKET]);
+ $string_to_sign = '';
+ $headers = $this->generateHeaders($options, $hostname);
+ $signable_query_string_params = $this->generateSignableQueryStringParam($options);
+ $signable_query_string = OssUtil::toQueryString($signable_query_string_params);
+ $resource_uri = $this->generateResourceUri($options);
+ //生成请求URL
+ $conjunction = '?';
+ $non_signable_resource = '';
+ if (isset($options[self::OSS_SUB_RESOURCE])) {
+ $conjunction = '&';
+ }
+ if ($signable_query_string !== '') {
+ $signable_query_string = $conjunction . $signable_query_string;
+ $conjunction = '&';
+ }
+ $query_string = $this->generateQueryString($options);
+ if ($query_string !== '') {
+ $non_signable_resource .= $conjunction . $query_string;
+ $conjunction = '&';
+ }
+ $this->requestUrl = $scheme . $hostname . $resource_uri . $signable_query_string . $non_signable_resource;
+
+ //创建请求
+ $request = new RequestCore($this->requestUrl);
+ $request->set_useragent($this->generateUserAgent());
+ // Streaming uploads
+ if (isset($options[self::OSS_FILE_UPLOAD])) {
+ if (is_resource($options[self::OSS_FILE_UPLOAD])) {
+ $length = null;
+
+ if (isset($options[self::OSS_CONTENT_LENGTH])) {
+ $length = $options[self::OSS_CONTENT_LENGTH];
+ } elseif (isset($options[self::OSS_SEEK_TO])) {
+ $stats = fstat($options[self::OSS_FILE_UPLOAD]);
+ if ($stats && $stats[self::OSS_SIZE] >= 0) {
+ $length = $stats[self::OSS_SIZE] - (integer)$options[self::OSS_SEEK_TO];
+ }
+ }
+ $request->set_read_stream($options[self::OSS_FILE_UPLOAD], $length);
+ } else {
+ $request->set_read_file($options[self::OSS_FILE_UPLOAD]);
+ $length = $request->read_stream_size;
+ if (isset($options[self::OSS_CONTENT_LENGTH])) {
+ $length = $options[self::OSS_CONTENT_LENGTH];
+ } elseif (isset($options[self::OSS_SEEK_TO]) && isset($length)) {
+ $length -= (integer)$options[self::OSS_SEEK_TO];
+ }
+ $request->set_read_stream_size($length);
+ }
+ }
+ if (isset($options[self::OSS_SEEK_TO])) {
+ $request->set_seek_position((integer)$options[self::OSS_SEEK_TO]);
+ }
+ if (isset($options[self::OSS_FILE_DOWNLOAD])) {
+ if (is_resource($options[self::OSS_FILE_DOWNLOAD])) {
+ $request->set_write_stream($options[self::OSS_FILE_DOWNLOAD]);
+ } else {
+ $request->set_write_file($options[self::OSS_FILE_DOWNLOAD]);
+ }
+ }
+
+ if (isset($options[self::OSS_METHOD])) {
+ $request->set_method($options[self::OSS_METHOD]);
+ $string_to_sign .= $options[self::OSS_METHOD] . "\n";
+ }
+
+ if (isset($options[self::OSS_CONTENT])) {
+ $request->set_body($options[self::OSS_CONTENT]);
+ if ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded') {
+ $headers[self::OSS_CONTENT_TYPE] = 'application/octet-stream';
+ }
+
+ $headers[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);
+ $headers[self::OSS_CONTENT_MD5] = base64_encode(md5($options[self::OSS_CONTENT], true));
+ }
+
+ if (isset($options[self::OSS_CALLBACK])) {
+ $headers[self::OSS_CALLBACK] = base64_encode($options[self::OSS_CALLBACK]);
+ }
+ if (isset($options[self::OSS_CALLBACK_VAR])) {
+ $headers[self::OSS_CALLBACK_VAR] = base64_encode($options[self::OSS_CALLBACK_VAR]);
+ }
+
+ if (!isset($headers[self::OSS_ACCEPT_ENCODING])) {
+ $headers[self::OSS_ACCEPT_ENCODING] = '';
+ }
+
+ uksort($headers, 'strnatcasecmp');
+
+ foreach ($headers as $header_key => $header_value) {
+ $header_value = str_replace(array("\r", "\n"), '', $header_value);
+ if ($header_value !== '' || $header_key === self::OSS_ACCEPT_ENCODING) {
+ $request->add_header($header_key, $header_value);
+ }
+
+ if (
+ strtolower($header_key) === 'content-md5' ||
+ strtolower($header_key) === 'content-type' ||
+ strtolower($header_key) === 'date' ||
+ (isset($options['self::OSS_PREAUTH']) && (integer)$options['self::OSS_PREAUTH'] > 0)
+ ) {
+ $string_to_sign .= $header_value . "\n";
+ } elseif (substr(strtolower($header_key), 0, 6) === self::OSS_DEFAULT_PREFIX) {
+ $string_to_sign .= strtolower($header_key) . ':' . $header_value . "\n";
+ }
+ }
+ // 生成 signable_resource
+ $signable_resource = $this->generateSignableResource($options);
+ $string_to_sign .= rawurldecode($signable_resource) . urldecode($signable_query_string);
+
+ //对?后面的要签名的string字母序排序
+ $string_to_sign_ordered = $this->stringToSignSorted($string_to_sign);
+
+ $signature = base64_encode(hash_hmac('sha1', $string_to_sign_ordered, $this->accessKeySecret, true));
+ $request->add_header('Authorization', 'OSS ' . $this->accessKeyId . ':' . $signature);
+
+ if (isset($options[self::OSS_PREAUTH]) && (integer)$options[self::OSS_PREAUTH] > 0) {
+ $signed_url = $this->requestUrl . $conjunction . self::OSS_URL_ACCESS_KEY_ID . '=' . rawurlencode($this->accessKeyId) . '&' . self::OSS_URL_EXPIRES . '=' . $options[self::OSS_PREAUTH] . '&' . self::OSS_URL_SIGNATURE . '=' . rawurlencode($signature);
+ return $signed_url;
+ } elseif (isset($options[self::OSS_PREAUTH])) {
+ return $this->requestUrl;
+ }
+
+ if ($this->timeout !== 0) {
+ $request->timeout = $this->timeout;
+ }
+ if ($this->connectTimeout !== 0) {
+ $request->connect_timeout = $this->connectTimeout;
+ }
+
+ try {
+ $request->send_request();
+ } catch (RequestCore_Exception $e) {
+ throw(new OssException('RequestCoreException: ' . $e->getMessage()));
+ }
+ $response_header = $request->get_response_header();
+ $response_header['oss-request-url'] = $this->requestUrl;
+ $response_header['oss-redirects'] = $this->redirects;
+ $response_header['oss-stringtosign'] = $string_to_sign;
+ $response_header['oss-requestheaders'] = $request->request_headers;
+
+ $data = new ResponseCore($response_header, $request->get_response_body(), $request->get_response_code());
+ //retry if OSS Internal Error
+ if ((integer)$request->get_response_code() === 500) {
+ if ($this->redirects <= $this->maxRetries) {
+ //设置休眠
+ $delay = (integer)(pow(4, $this->redirects) * 100000);
+ usleep($delay);
+ $this->redirects++;
+ $data = $this->auth($options);
+ }
+ }
+
+ $this->redirects = 0;
+ return $data;
+ }
+
+ /**
+ * 设置最大尝试次数
+ *
+ * @param int $maxRetries
+ * @return void
+ */
+ public function setMaxTries($maxRetries = 3)
+ {
+ $this->maxRetries = $maxRetries;
+ }
+
+ /**
+ * 获取最大尝试次数
+ *
+ * @return int
+ */
+ public function getMaxRetries()
+ {
+ return $this->maxRetries;
+ }
+
+ /**
+ * 打开sts enable标志,使用户构造函数中传入的$sts生效
+ *
+ * @param boolean $enable
+ */
+ public function setSignStsInUrl($enable)
+ {
+ $this->enableStsInUrl = $enable;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isUseSSL()
+ {
+ return $this->useSSL;
+ }
+
+ /**
+ * @param boolean $useSSL
+ */
+ public function setUseSSL($useSSL)
+ {
+ $this->useSSL = $useSSL;
+ }
+
+ /**
+ * 检查bucket名称格式是否正确,如果非法抛出异常
+ *
+ * @param $options
+ * @throws OssException
+ */
+ private function authPrecheckBucket($options)
+ {
+ if (!(('/' == $options[self::OSS_OBJECT]) && ('' == $options[self::OSS_BUCKET]) && ('GET' == $options[self::OSS_METHOD])) && !OssUtil::validateBucket($options[self::OSS_BUCKET])) {
+ throw new OssException('"' . $options[self::OSS_BUCKET] . '"' . 'bucket name is invalid');
+ }
+ }
+
+ /**
+ *
+ * 检查object名称格式是否正确,如果非法抛出异常
+ *
+ * @param $options
+ * @throws OssException
+ */
+ private function authPrecheckObject($options)
+ {
+ if (isset($options[self::OSS_OBJECT]) && $options[self::OSS_OBJECT] === '/') {
+ return;
+ }
+
+ if (isset($options[self::OSS_OBJECT]) && !OssUtil::validateObject($options[self::OSS_OBJECT])) {
+ throw new OssException('"' . $options[self::OSS_OBJECT] . '"' . ' object name is invalid');
+ }
+ }
+
+ /**
+ * 检查object的编码,如果是gbk或者gb2312则尝试将其转化为utf8编码
+ *
+ * @param mixed $options 参数
+ */
+ private function authPrecheckObjectEncoding(&$options)
+ {
+ $tmp_object = $options[self::OSS_OBJECT];
+ try {
+ if (OssUtil::isGb2312($options[self::OSS_OBJECT])) {
+ $options[self::OSS_OBJECT] = iconv('GB2312', "UTF-8//IGNORE", $options[self::OSS_OBJECT]);
+ } elseif (OssUtil::checkChar($options[self::OSS_OBJECT], true)) {
+ $options[self::OSS_OBJECT] = iconv('GBK', "UTF-8//IGNORE", $options[self::OSS_OBJECT]);
+ }
+ } catch (\Exception $e) {
+ try {
+ $tmp_object = iconv(mb_detect_encoding($tmp_object), "UTF-8", $tmp_object);
+ } catch (\Exception $e) {
+ }
+ }
+ $options[self::OSS_OBJECT] = $tmp_object;
+ }
+
+ /**
+ * 检查ACL是否是预定义中三种之一,如果不是抛出异常
+ *
+ * @param $options
+ * @throws OssException
+ */
+ private function authPrecheckAcl($options)
+ {
+ if (isset($options[self::OSS_HEADERS][self::OSS_ACL]) && !empty($options[self::OSS_HEADERS][self::OSS_ACL])) {
+ if (!in_array(strtolower($options[self::OSS_HEADERS][self::OSS_ACL]), self::$OSS_ACL_TYPES)) {
+ throw new OssException($options[self::OSS_HEADERS][self::OSS_ACL] . ':' . 'acl is invalid(private,public-read,public-read-write)');
+ }
+ }
+ }
+
+ /**
+ * 获得档次请求使用的域名
+ * bucket在前的三级域名,或者二级域名,如果是cname或者ip的话,则是二级域名
+ *
+ * @param $bucket
+ * @return string 剥掉协议头的域名
+ */
+ private function generateHostname($bucket)
+ {
+ if ($this->hostType === self::OSS_HOST_TYPE_IP) {
+ $hostname = $this->hostname;
+ } elseif ($this->hostType === self::OSS_HOST_TYPE_CNAME) {
+ $hostname = $this->hostname;
+ } else {
+ // 专有域或者官网endpoint
+ $hostname = ($bucket == '') ? $this->hostname : ($bucket . '.') . $this->hostname;
+ }
+ return $hostname;
+ }
+
+ /**
+ * 获得当次请求的资源定位字段
+ *
+ * @param $options
+ * @return string 资源定位字段
+ */
+ private function generateResourceUri($options)
+ {
+ $resource_uri = "";
+
+ // resource_uri + bucket
+ if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) {
+ if ($this->hostType === self::OSS_HOST_TYPE_IP) {
+ $resource_uri = '/' . $options[self::OSS_BUCKET];
+ }
+ }
+
+ // resource_uri + object
+ if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) {
+ $resource_uri .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT]));
+ }
+
+ // resource_uri + sub_resource
+ $conjunction = '?';
+ if (isset($options[self::OSS_SUB_RESOURCE])) {
+ $resource_uri .= $conjunction . $options[self::OSS_SUB_RESOURCE];
+ }
+ return $resource_uri;
+ }
+
+ /**
+ * 生成signalbe_query_string_param, array类型
+ *
+ * @param array $options
+ * @return array
+ */
+ private function generateSignableQueryStringParam($options)
+ {
+ $signableQueryStringParams = array();
+ $signableList = array(
+ self::OSS_PART_NUM,
+ 'response-content-type',
+ 'response-content-language',
+ 'response-cache-control',
+ 'response-content-encoding',
+ 'response-expires',
+ 'response-content-disposition',
+ self::OSS_UPLOAD_ID,
+ self::OSS_COMP,
+ self::OSS_LIVE_CHANNEL_STATUS,
+ self::OSS_LIVE_CHANNEL_START_TIME,
+ self::OSS_LIVE_CHANNEL_END_TIME,
+ self::OSS_PROCESS,
+ self::OSS_POSITION
+ );
+
+ foreach ($signableList as $item) {
+ if (isset($options[$item])) {
+ $signableQueryStringParams[$item] = $options[$item];
+ }
+ }
+
+ if ($this->enableStsInUrl && (!is_null($this->securityToken))) {
+ $signableQueryStringParams["security-token"] = $this->securityToken;
+ }
+
+ return $signableQueryStringParams;
+ }
+
+ /**
+ * 生成用于签名resource段
+ *
+ * @param mixed $options
+ * @return string
+ */
+ private function generateSignableResource($options)
+ {
+ $signableResource = "";
+ $signableResource .= '/';
+ if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) {
+ $signableResource .= $options[self::OSS_BUCKET];
+ // 如果操作没有Object操作的话,这里最后是否有斜线有个trick,ip的域名下,不需要加'/', 否则需要加'/'
+ if ($options[self::OSS_OBJECT] == '/') {
+ if ($this->hostType !== self::OSS_HOST_TYPE_IP) {
+ $signableResource .= "/";
+ }
+ }
+ }
+ //signable_resource + object
+ if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) {
+ $signableResource .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT]));
+ }
+ if (isset($options[self::OSS_SUB_RESOURCE])) {
+ $signableResource .= '?' . $options[self::OSS_SUB_RESOURCE];
+ }
+ return $signableResource;
+ }
+
+ /**
+ * 生成query_string
+ *
+ * @param mixed $options
+ * @return string
+ */
+ private function generateQueryString($options)
+ {
+ //请求参数
+ $queryStringParams = array();
+ if (isset($options[self::OSS_QUERY_STRING])) {
+ $queryStringParams = array_merge($queryStringParams, $options[self::OSS_QUERY_STRING]);
+ }
+ return OssUtil::toQueryString($queryStringParams);
+ }
+
+ private function stringToSignSorted($string_to_sign)
+ {
+ $queryStringSorted = '';
+ $explodeResult = explode('?', $string_to_sign);
+ $index = count($explodeResult);
+ if ($index === 1)
+ return $string_to_sign;
+
+ $queryStringParams = explode('&', $explodeResult[$index - 1]);
+ sort($queryStringParams);
+
+ foreach($queryStringParams as $params)
+ {
+ $queryStringSorted .= $params . '&';
+ }
+
+ $queryStringSorted = substr($queryStringSorted, 0, -1);
+
+ return $explodeResult[0] . '?' . $queryStringSorted;
+ }
+
+ /**
+ * 初始化headers
+ *
+ * @param mixed $options
+ * @param string $hostname hostname
+ * @return array
+ */
+ private function generateHeaders($options, $hostname)
+ {
+ $headers = array(
+ self::OSS_CONTENT_MD5 => '',
+ self::OSS_CONTENT_TYPE => isset($options[self::OSS_CONTENT_TYPE]) ? $options[self::OSS_CONTENT_TYPE] : self::DEFAULT_CONTENT_TYPE,
+ self::OSS_DATE => isset($options[self::OSS_DATE]) ? $options[self::OSS_DATE] : gmdate('D, d M Y H:i:s \G\M\T'),
+ self::OSS_HOST => $hostname,
+ );
+ if (isset($options[self::OSS_CONTENT_MD5])) {
+ $headers[self::OSS_CONTENT_MD5] = $options[self::OSS_CONTENT_MD5];
+ }
+
+ //添加stsSecurityToken
+ if ((!is_null($this->securityToken)) && (!$this->enableStsInUrl)) {
+ $headers[self::OSS_SECURITY_TOKEN] = $this->securityToken;
+ }
+ //合并HTTP headers
+ if (isset($options[self::OSS_HEADERS])) {
+ $headers = array_merge($headers, $options[self::OSS_HEADERS]);
+ }
+ return $headers;
+ }
+
+ /**
+ * 生成请求用的UserAgent
+ *
+ * @return string
+ */
+ private function generateUserAgent()
+ {
+ return self::OSS_NAME . "/" . self::OSS_VERSION . " (" . php_uname('s') . "/" . php_uname('r') . "/" . php_uname('m') . ";" . PHP_VERSION . ")";
+ }
+
+ /**
+ * 检查endpoint的种类
+ * 如有有协议头,剥去协议头
+ * 并且根据参数 is_cname 和endpoint本身,判定域名类型,是ip,cname,还是专有域或者官网域名
+ *
+ * @param string $endpoint
+ * @param boolean $isCName
+ * @return string 剥掉协议头的域名
+ */
+ private function checkEndpoint($endpoint, $isCName)
+ {
+ $ret_endpoint = null;
+ if (strpos($endpoint, 'http://') === 0) {
+ $ret_endpoint = substr($endpoint, strlen('http://'));
+ } elseif (strpos($endpoint, 'https://') === 0) {
+ $ret_endpoint = substr($endpoint, strlen('https://'));
+ $this->useSSL = true;
+ } else {
+ $ret_endpoint = $endpoint;
+ }
+
+ if ($isCName) {
+ $this->hostType = self::OSS_HOST_TYPE_CNAME;
+ } elseif (OssUtil::isIPFormat($ret_endpoint)) {
+ $this->hostType = self::OSS_HOST_TYPE_IP;
+ } else {
+ $this->hostType = self::OSS_HOST_TYPE_NORMAL;
+ }
+ return $ret_endpoint;
+ }
+
+ /**
+ * 用来检查sdk所以来的扩展是否打开
+ *
+ * @throws OssException
+ */
+ public static function checkEnv()
+ {
+ if (function_exists('get_loaded_extensions')) {
+ //检测curl扩展
+ $enabled_extension = array("curl");
+ $extensions = get_loaded_extensions();
+ if ($extensions) {
+ foreach ($enabled_extension as $item) {
+ if (!in_array($item, $extensions)) {
+ throw new OssException("Extension {" . $item . "} is not installed or not enabled, please check your php env.");
+ }
+ }
+ } else {
+ throw new OssException("function get_loaded_extensions not found.");
+ }
+ } else {
+ throw new OssException('Function get_loaded_extensions has been disabled, please check php config.');
+ }
+ }
+
+ /**
+ //* 设置http库的请求超时时间,单位秒
+ *
+ * @param int $timeout
+ */
+ public function setTimeout($timeout)
+ {
+ $this->timeout = $timeout;
+ }
+
+ /**
+ * 设置http库的连接超时时间,单位秒
+ *
+ * @param int $connectTimeout
+ */
+ public function setConnectTimeout($connectTimeout)
+ {
+ $this->connectTimeout = $connectTimeout;
+ }
+
+ // 生命周期相关常量
+ const OSS_LIFECYCLE_EXPIRATION = "Expiration";
+ const OSS_LIFECYCLE_TIMING_DAYS = "Days";
+ const OSS_LIFECYCLE_TIMING_DATE = "Date";
+ //OSS 内部常量
+ const OSS_BUCKET = 'bucket';
+ const OSS_OBJECT = 'object';
+ const OSS_HEADERS = OssUtil::OSS_HEADERS;
+ const OSS_METHOD = 'method';
+ const OSS_QUERY = 'query';
+ const OSS_BASENAME = 'basename';
+ const OSS_MAX_KEYS = 'max-keys';
+ const OSS_UPLOAD_ID = 'uploadId';
+ const OSS_PART_NUM = 'partNumber';
+ const OSS_COMP = 'comp';
+ const OSS_LIVE_CHANNEL_STATUS = 'status';
+ const OSS_LIVE_CHANNEL_START_TIME = 'startTime';
+ const OSS_LIVE_CHANNEL_END_TIME = 'endTime';
+ const OSS_POSITION = 'position';
+ const OSS_MAX_KEYS_VALUE = 100;
+ const OSS_MAX_OBJECT_GROUP_VALUE = OssUtil::OSS_MAX_OBJECT_GROUP_VALUE;
+ const OSS_MAX_PART_SIZE = OssUtil::OSS_MAX_PART_SIZE;
+ const OSS_MID_PART_SIZE = OssUtil::OSS_MID_PART_SIZE;
+ const OSS_MIN_PART_SIZE = OssUtil::OSS_MIN_PART_SIZE;
+ const OSS_FILE_SLICE_SIZE = 8192;
+ const OSS_PREFIX = 'prefix';
+ const OSS_DELIMITER = 'delimiter';
+ const OSS_MARKER = 'marker';
+ const OSS_ACCEPT_ENCODING = 'Accept-Encoding';
+ const OSS_CONTENT_MD5 = 'Content-Md5';
+ const OSS_SELF_CONTENT_MD5 = 'x-oss-meta-md5';
+ const OSS_CONTENT_TYPE = 'Content-Type';
+ const OSS_CONTENT_LENGTH = 'Content-Length';
+ const OSS_IF_MODIFIED_SINCE = 'If-Modified-Since';
+ const OSS_IF_UNMODIFIED_SINCE = 'If-Unmodified-Since';
+ const OSS_IF_MATCH = 'If-Match';
+ const OSS_IF_NONE_MATCH = 'If-None-Match';
+ const OSS_CACHE_CONTROL = 'Cache-Control';
+ const OSS_EXPIRES = 'Expires';
+ const OSS_PREAUTH = 'preauth';
+ const OSS_CONTENT_COING = 'Content-Coding';
+ const OSS_CONTENT_DISPOSTION = 'Content-Disposition';
+ const OSS_RANGE = 'range';
+ const OSS_ETAG = 'etag';
+ const OSS_LAST_MODIFIED = 'lastmodified';
+ const OS_CONTENT_RANGE = 'Content-Range';
+ const OSS_CONTENT = OssUtil::OSS_CONTENT;
+ const OSS_BODY = 'body';
+ const OSS_LENGTH = OssUtil::OSS_LENGTH;
+ const OSS_HOST = 'Host';
+ const OSS_DATE = 'Date';
+ const OSS_AUTHORIZATION = 'Authorization';
+ const OSS_FILE_DOWNLOAD = 'fileDownload';
+ const OSS_FILE_UPLOAD = 'fileUpload';
+ const OSS_PART_SIZE = 'partSize';
+ const OSS_SEEK_TO = 'seekTo';
+ const OSS_SIZE = 'size';
+ const OSS_QUERY_STRING = 'query_string';
+ const OSS_SUB_RESOURCE = 'sub_resource';
+ const OSS_DEFAULT_PREFIX = 'x-oss-';
+ const OSS_CHECK_MD5 = 'checkmd5';
+ const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
+
+ //私有URL变量
+ const OSS_URL_ACCESS_KEY_ID = 'OSSAccessKeyId';
+ const OSS_URL_EXPIRES = 'Expires';
+ const OSS_URL_SIGNATURE = 'Signature';
+ //HTTP方法
+ const OSS_HTTP_GET = 'GET';
+ const OSS_HTTP_PUT = 'PUT';
+ const OSS_HTTP_HEAD = 'HEAD';
+ const OSS_HTTP_POST = 'POST';
+ const OSS_HTTP_DELETE = 'DELETE';
+ const OSS_HTTP_OPTIONS = 'OPTIONS';
+ //其他常量
+ const OSS_ACL = 'x-oss-acl';
+ const OSS_OBJECT_ACL = 'x-oss-object-acl';
+ const OSS_OBJECT_GROUP = 'x-oss-file-group';
+ const OSS_MULTI_PART = 'uploads';
+ const OSS_MULTI_DELETE = 'delete';
+ const OSS_OBJECT_COPY_SOURCE = 'x-oss-copy-source';
+ const OSS_OBJECT_COPY_SOURCE_RANGE = "x-oss-copy-source-range";
+ const OSS_PROCESS = "x-oss-process";
+ const OSS_CALLBACK = "x-oss-callback";
+ const OSS_CALLBACK_VAR = "x-oss-callback-var";
+ //支持STS SecurityToken
+ const OSS_SECURITY_TOKEN = "x-oss-security-token";
+ const OSS_ACL_TYPE_PRIVATE = 'private';
+ const OSS_ACL_TYPE_PUBLIC_READ = 'public-read';
+ const OSS_ACL_TYPE_PUBLIC_READ_WRITE = 'public-read-write';
+ const OSS_ENCODING_TYPE = "encoding-type";
+ const OSS_ENCODING_TYPE_URL = "url";
+
+ // 域名类型
+ const OSS_HOST_TYPE_NORMAL = "normal";//http://bucket.oss-cn-hangzhou.aliyuncs.com/object
+ const OSS_HOST_TYPE_IP = "ip"; //http://1.1.1.1/bucket/object
+ const OSS_HOST_TYPE_SPECIAL = 'special'; //http://bucket.guizhou.gov/object
+ const OSS_HOST_TYPE_CNAME = "cname"; //http://mydomain.com/object
+ //OSS ACL数组
+ static $OSS_ACL_TYPES = array(
+ self::OSS_ACL_TYPE_PRIVATE,
+ self::OSS_ACL_TYPE_PUBLIC_READ,
+ self::OSS_ACL_TYPE_PUBLIC_READ_WRITE
+ );
+ // OssClient版本信息
+ const OSS_NAME = "aliyun-sdk-php";
+ const OSS_VERSION = "2.2.4";
+ const OSS_BUILD = "20170425";
+ const OSS_AUTHOR = "";
+ const OSS_OPTIONS_ORIGIN = 'Origin';
+ const OSS_OPTIONS_REQUEST_METHOD = 'Access-Control-Request-Method';
+ const OSS_OPTIONS_REQUEST_HEADERS = 'Access-Control-Request-Headers';
+
+ //是否使用ssl
+ private $useSSL = false;
+ private $maxRetries = 3;
+ private $redirects = 0;
+
+ // 用户提供的域名类型,有四种 OSS_HOST_TYPE_NORMAL, OSS_HOST_TYPE_IP, OSS_HOST_TYPE_SPECIAL, OSS_HOST_TYPE_CNAME
+ private $hostType = self::OSS_HOST_TYPE_NORMAL;
+ private $requestUrl;
+ private $accessKeyId;
+ private $accessKeySecret;
+ private $hostname;
+ private $securityToken;
+ private $enableStsInUrl = false;
+ private $timeout = 0;
+ private $connectTimeout = 0;
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/AclResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/AclResult.php
new file mode 100755
index 0000000..6da0860
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/AclResult.php
@@ -0,0 +1,32 @@
+rawResponse->body;
+ if (empty($content)) {
+ throw new OssException("body is null");
+ }
+ $xml = simplexml_load_string($content);
+ if (isset($xml->AccessControlList->Grant)) {
+ return strval($xml->AccessControlList->Grant);
+ } else {
+ throw new OssException("xml format exception");
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/AppendResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/AppendResult.php
new file mode 100755
index 0000000..433c03e
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/AppendResult.php
@@ -0,0 +1,27 @@
+rawResponse->header;
+ if (isset($header["x-oss-next-append-position"])) {
+ return intval($header["x-oss-next-append-position"]);
+ }
+ throw new OssException("cannot get next-append-position");
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/BodyResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/BodyResult.php
new file mode 100755
index 0000000..44ba15e
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/BodyResult.php
@@ -0,0 +1,19 @@
+rawResponse->body) ? "" : $this->rawResponse->body;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/CallbackResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/CallbackResult.php
new file mode 100755
index 0000000..514e985
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/CallbackResult.php
@@ -0,0 +1,21 @@
+rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 && (int)(intval($status)) !== 203) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/CopyObjectResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/CopyObjectResult.php
new file mode 100755
index 0000000..498723e
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/CopyObjectResult.php
@@ -0,0 +1,30 @@
+rawResponse->body;
+ $xml = simplexml_load_string($body);
+ $result = array();
+
+ if (isset($xml->LastModified)) {
+ $result[] = $xml->LastModified;
+ }
+ if (isset($xml->ETag)) {
+ $result[] = $xml->ETag;
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/DeleteObjectsResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/DeleteObjectsResult.php
new file mode 100755
index 0000000..dc373b8
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/DeleteObjectsResult.php
@@ -0,0 +1,27 @@
+rawResponse->body;
+ $xml = simplexml_load_string($body);
+ $objects = array();
+
+ if (isset($xml->Deleted)) {
+ foreach($xml->Deleted as $deleteKey)
+ $objects[] = $deleteKey->Key;
+ }
+ return $objects;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ExistResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ExistResult.php
new file mode 100755
index 0000000..f7aa287
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ExistResult.php
@@ -0,0 +1,35 @@
+rawResponse->status) === 200 ? true : false;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 判断是否存在的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetCnameResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetCnameResult.php
new file mode 100755
index 0000000..eed01f9
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetCnameResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $config = new CnameConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetCorsResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetCorsResult.php
new file mode 100755
index 0000000..a51afe2
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetCorsResult.php
@@ -0,0 +1,35 @@
+rawResponse->body;
+ $config = new CorsConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLifecycleResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLifecycleResult.php
new file mode 100755
index 0000000..6b440c3
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLifecycleResult.php
@@ -0,0 +1,41 @@
+rawResponse->body;
+ $config = new LifecycleConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelHistoryResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelHistoryResult.php
new file mode 100755
index 0000000..202a668
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelHistoryResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $channelList = new GetLiveChannelHistory();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelInfoResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelInfoResult.php
new file mode 100755
index 0000000..d5a9005
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelInfoResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $channelList = new GetLiveChannelInfo();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelStatusResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelStatusResult.php
new file mode 100755
index 0000000..6b8a60f
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLiveChannelStatusResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $channelList = new GetLiveChannelStatus();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLoggingResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLoggingResult.php
new file mode 100755
index 0000000..72fc3ae
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetLoggingResult.php
@@ -0,0 +1,41 @@
+rawResponse->body;
+ $config = new LoggingConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetRefererResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetRefererResult.php
new file mode 100755
index 0000000..aee50d3
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetRefererResult.php
@@ -0,0 +1,41 @@
+rawResponse->body;
+ $config = new RefererConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetWebsiteResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetWebsiteResult.php
new file mode 100755
index 0000000..3099172
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/GetWebsiteResult.php
@@ -0,0 +1,40 @@
+rawResponse->body;
+ $config = new WebsiteConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/HeaderResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/HeaderResult.php
new file mode 100755
index 0000000..c9aae56
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/HeaderResult.php
@@ -0,0 +1,23 @@
+rawResponse->header) ? array() : $this->rawResponse->header;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/InitiateMultipartUploadResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/InitiateMultipartUploadResult.php
new file mode 100755
index 0000000..af985f2
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/InitiateMultipartUploadResult.php
@@ -0,0 +1,29 @@
+rawResponse->body;
+ $xml = simplexml_load_string($content);
+ if (isset($xml->UploadId)) {
+ return strval($xml->UploadId);
+ }
+ throw new OssException("cannot get UploadId");
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListBucketsResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListBucketsResult.php
new file mode 100755
index 0000000..a58fb2d
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListBucketsResult.php
@@ -0,0 +1,33 @@
+rawResponse->body;
+ $xml = new \SimpleXMLElement($content);
+ if (isset($xml->Buckets) && isset($xml->Buckets->Bucket)) {
+ foreach ($xml->Buckets->Bucket as $bucket) {
+ $bucketInfo = new BucketInfo(strval($bucket->Location),
+ strval($bucket->Name),
+ strval($bucket->CreationDate));
+ $bucketList[] = $bucketInfo;
+ }
+ }
+ return new BucketListInfo($bucketList);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListLiveChannelResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListLiveChannelResult.php
new file mode 100755
index 0000000..1a6e2a4
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListLiveChannelResult.php
@@ -0,0 +1,16 @@
+rawResponse->body;
+ $channelList = new LiveChannelListInfo();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListMultipartUploadResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListMultipartUploadResult.php
new file mode 100755
index 0000000..bcb20bf
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListMultipartUploadResult.php
@@ -0,0 +1,55 @@
+rawResponse->body;
+ $xml = simplexml_load_string($content);
+
+ $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : "";
+ $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : "";
+ $keyMarker = isset($xml->KeyMarker) ? strval($xml->KeyMarker) : "";
+ $keyMarker = OssUtil::decodeKey($keyMarker, $encodingType);
+ $uploadIdMarker = isset($xml->UploadIdMarker) ? strval($xml->UploadIdMarker) : "";
+ $nextKeyMarker = isset($xml->NextKeyMarker) ? strval($xml->NextKeyMarker) : "";
+ $nextKeyMarker = OssUtil::decodeKey($nextKeyMarker, $encodingType);
+ $nextUploadIdMarker = isset($xml->NextUploadIdMarker) ? strval($xml->NextUploadIdMarker) : "";
+ $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : "";
+ $delimiter = OssUtil::decodeKey($delimiter, $encodingType);
+ $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : "";
+ $prefix = OssUtil::decodeKey($prefix, $encodingType);
+ $maxUploads = isset($xml->MaxUploads) ? intval($xml->MaxUploads) : 0;
+ $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
+ $listUpload = array();
+
+ if (isset($xml->Upload)) {
+ foreach ($xml->Upload as $upload) {
+ $key = isset($upload->Key) ? strval($upload->Key) : "";
+ $key = OssUtil::decodeKey($key, $encodingType);
+ $uploadId = isset($upload->UploadId) ? strval($upload->UploadId) : "";
+ $initiated = isset($upload->Initiated) ? strval($upload->Initiated) : "";
+ $listUpload[] = new UploadInfo($key, $uploadId, $initiated);
+ }
+ }
+ return new ListMultipartUploadInfo($bucket, $keyMarker, $uploadIdMarker,
+ $nextKeyMarker, $nextUploadIdMarker,
+ $delimiter, $prefix, $maxUploads, $isTruncated, $listUpload);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListObjectsResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListObjectsResult.php
new file mode 100755
index 0000000..fcf493d
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListObjectsResult.php
@@ -0,0 +1,71 @@
+rawResponse->body);
+ $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : "";
+ $objectList = $this->parseObjectList($xml, $encodingType);
+ $prefixList = $this->parsePrefixList($xml, $encodingType);
+ $bucketName = isset($xml->Name) ? strval($xml->Name) : "";
+ $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : "";
+ $prefix = OssUtil::decodeKey($prefix, $encodingType);
+ $marker = isset($xml->Marker) ? strval($xml->Marker) : "";
+ $marker = OssUtil::decodeKey($marker, $encodingType);
+ $maxKeys = isset($xml->MaxKeys) ? intval($xml->MaxKeys) : 0;
+ $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : "";
+ $delimiter = OssUtil::decodeKey($delimiter, $encodingType);
+ $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
+ $nextMarker = isset($xml->NextMarker) ? strval($xml->NextMarker) : "";
+ $nextMarker = OssUtil::decodeKey($nextMarker, $encodingType);
+ return new ObjectListInfo($bucketName, $prefix, $marker, $nextMarker, $maxKeys, $delimiter, $isTruncated, $objectList, $prefixList);
+ }
+
+ private function parseObjectList($xml, $encodingType)
+ {
+ $retList = array();
+ if (isset($xml->Contents)) {
+ foreach ($xml->Contents as $content) {
+ $key = isset($content->Key) ? strval($content->Key) : "";
+ $key = OssUtil::decodeKey($key, $encodingType);
+ $lastModified = isset($content->LastModified) ? strval($content->LastModified) : "";
+ $eTag = isset($content->ETag) ? strval($content->ETag) : "";
+ $type = isset($content->Type) ? strval($content->Type) : "";
+ $size = isset($content->Size) ? intval($content->Size) : 0;
+ $storageClass = isset($content->StorageClass) ? strval($content->StorageClass) : "";
+ $retList[] = new ObjectInfo($key, $lastModified, $eTag, $type, $size, $storageClass);
+ }
+ }
+ return $retList;
+ }
+
+ private function parsePrefixList($xml, $encodingType)
+ {
+ $retList = array();
+ if (isset($xml->CommonPrefixes)) {
+ foreach ($xml->CommonPrefixes as $commonPrefix) {
+ $prefix = isset($commonPrefix->Prefix) ? strval($commonPrefix->Prefix) : "";
+ $prefix = OssUtil::decodeKey($prefix, $encodingType);
+ $retList[] = new PrefixInfo($prefix);
+ }
+ }
+ return $retList;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListPartsResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListPartsResult.php
new file mode 100755
index 0000000..fd8a1b8
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/ListPartsResult.php
@@ -0,0 +1,42 @@
+rawResponse->body;
+ $xml = simplexml_load_string($content);
+ $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : "";
+ $key = isset($xml->Key) ? strval($xml->Key) : "";
+ $uploadId = isset($xml->UploadId) ? strval($xml->UploadId) : "";
+ $nextPartNumberMarker = isset($xml->NextPartNumberMarker) ? intval($xml->NextPartNumberMarker) : "";
+ $maxParts = isset($xml->MaxParts) ? intval($xml->MaxParts) : "";
+ $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
+ $partList = array();
+ if (isset($xml->Part)) {
+ foreach ($xml->Part as $part) {
+ $partNumber = isset($part->PartNumber) ? intval($part->PartNumber) : "";
+ $lastModified = isset($part->LastModified) ? strval($part->LastModified) : "";
+ $eTag = isset($part->ETag) ? strval($part->ETag) : "";
+ $size = isset($part->Size) ? intval($part->Size) : "";
+ $partList[] = new PartInfo($partNumber, $lastModified, $eTag, $size);
+ }
+ }
+ return new ListPartsInfo($bucket, $key, $uploadId, $nextPartNumberMarker, $maxParts, $isTruncated, $partList);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/PutLiveChannelResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/PutLiveChannelResult.php
new file mode 100755
index 0000000..dcac86b
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/PutLiveChannelResult.php
@@ -0,0 +1,16 @@
+rawResponse->body;
+ $channel = new LiveChannelInfo();
+ $channel->parseFromXml($content);
+ return $channel;
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/PutSetDeleteResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/PutSetDeleteResult.php
new file mode 100755
index 0000000..97af003
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/PutSetDeleteResult.php
@@ -0,0 +1,20 @@
+ $this->rawResponse->body);
+ return array_merge($this->rawResponse->header, $body);
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/Result.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/Result.php
new file mode 100755
index 0000000..491256f
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/Result.php
@@ -0,0 +1,175 @@
+rawResponse = $response;
+ $this->parseResponse();
+ }
+
+ /**
+ * 获取requestId
+ *
+ * @return string
+ */
+ public function getRequestId()
+ {
+ if (isset($this->rawResponse) &&
+ isset($this->rawResponse->header) &&
+ isset($this->rawResponse->header['x-oss-request-id'])
+ ) {
+ return $this->rawResponse->header['x-oss-request-id'];
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * 得到返回数据,不同的请求返回数据格式不同
+ *
+ * $return mixed
+ */
+ public function getData()
+ {
+ return $this->parsedData;
+ }
+
+ /**
+ * 由子类实现,不同的请求返回数据有不同的解析逻辑,由子类实现
+ *
+ * @return mixed
+ */
+ abstract protected function parseDataFromResponse();
+
+ /**
+ * 操作是否成功
+ *
+ * @return mixed
+ */
+ public function isOK()
+ {
+ return $this->isOk;
+ }
+
+ /**
+ * @throws OssException
+ */
+ public function parseResponse()
+ {
+ $this->isOk = $this->isResponseOk();
+ if ($this->isOk) {
+ $this->parsedData = $this->parseDataFromResponse();
+ } else {
+ $httpStatus = strval($this->rawResponse->status);
+ $requestId = strval($this->getRequestId());
+ $code = $this->retrieveErrorCode($this->rawResponse->body);
+ $message = $this->retrieveErrorMessage($this->rawResponse->body);
+ $body = $this->rawResponse->body;
+
+ $details = array(
+ 'status' => $httpStatus,
+ 'request-id' => $requestId,
+ 'code' => $code,
+ 'message' => $message,
+ 'body' => $body
+ );
+ throw new OssException($details);
+ }
+ }
+
+ /**
+ * 尝试从body中获取错误Message
+ *
+ * @param $body
+ * @return string
+ */
+ private function retrieveErrorMessage($body)
+ {
+ if (empty($body) || false === strpos($body, 'Message)) {
+ return strval($xml->Message);
+ }
+ return '';
+ }
+
+ /**
+ * 尝试从body中获取错误Code
+ *
+ * @param $body
+ * @return string
+ */
+ private function retrieveErrorCode($body)
+ {
+ if (empty($body) || false === strpos($body, 'Code)) {
+ return strval($xml->Code);
+ }
+ return '';
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 返回原始的返回数据
+ *
+ * @return ResponseCore
+ */
+ public function getRawResponse()
+ {
+ return $this->rawResponse;
+ }
+
+ /**
+ * 标示请求是否成功
+ */
+ protected $isOk = false;
+ /**
+ * 由子类解析过的数据
+ */
+ protected $parsedData = null;
+ /**
+ * 存放auth函数返回的原始Response
+ *
+ * @var ResponseCore
+ */
+ protected $rawResponse;
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/UploadPartResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/UploadPartResult.php
new file mode 100755
index 0000000..c6b66d4
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/src/OSS/Result/UploadPartResult.php
@@ -0,0 +1,28 @@
+rawResponse->header;
+ if (isset($header["etag"])) {
+ return $header["etag"];
+ }
+ throw new OssException("cannot get ETag");
+
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/AclResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/AclResultTest.php
new file mode 100755
index 0000000..12f4b1a
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/AclResultTest.php
@@ -0,0 +1,59 @@
+
+
+
+ 00220120222
+ user_example
+
+
+ public-read
+
+
+BBBB;
+
+ private $invalidXml = <<
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new AclResult($response);
+ $this->assertEquals("public-read", $result->getData());
+ }
+
+ public function testParseNullXml()
+ {
+ $response = new ResponseCore(array(), "", 200);
+ try {
+ new AclResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertEquals('body is null', $e->getMessage());
+ }
+ }
+
+ public function testParseInvalidXml()
+ {
+ $response = new ResponseCore(array(), $this->invalidXml, 200);
+ try {
+ new AclResult($response);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals("xml format exception", $e->getMessage());
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BodyResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BodyResultTest.php
new file mode 100755
index 0000000..af13d4d
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BodyResultTest.php
@@ -0,0 +1,26 @@
+assertTrue($result->isOK());
+ $this->assertEquals($result->getData(), "hi");
+ }
+
+ public function testParseInvalid404()
+ {
+ $response = new ResponseCore(array(), null, 200);
+ $result = new BodyResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertEquals($result->getData(), "");
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketCnameTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketCnameTest.php
new file mode 100755
index 0000000..87c9e54
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketCnameTest.php
@@ -0,0 +1,77 @@
+client = Common::getOssClient();
+ $this->bucketName = 'php-sdk-test-bucket-' . strval(rand(0, 10000));
+ $this->client->createBucket($this->bucketName);
+ }
+
+ public function tearDown()
+ {
+ $this->client->deleteBucket($this->bucketName);
+ }
+
+ public function testBucketWithoutCname()
+ {
+ $cnameConfig = $this->client->getBucketCname($this->bucketName);
+ $this->assertEquals(0, count($cnameConfig->getCnames()));
+ }
+
+ public function testAddCname()
+ {
+ $this->client->addBucketCname($this->bucketName, 'www.baidu.com');
+ $this->client->addBucketCname($this->bucketName, 'www.qq.com');
+
+ $ret = $this->client->getBucketCname($this->bucketName);
+ $this->assertEquals(2, count($ret->getCnames()));
+
+ // add another 2 cnames
+ $this->client->addBucketCname($this->bucketName, 'www.sina.com.cn');
+ $this->client->addBucketCname($this->bucketName, 'www.iqiyi.com');
+
+ $ret = $this->client->getBucketCname($this->bucketName);
+ $cnames = $ret->getCnames();
+ $cnameList = array();
+
+ foreach ($cnames as $c) {
+ $cnameList[] = $c['Domain'];
+ }
+ $should = array(
+ 'www.baidu.com',
+ 'www.qq.com',
+ 'www.sina.com.cn',
+ 'www.iqiyi.com'
+ );
+ $this->assertEquals(4, count($cnames));
+ $this->assertEquals(sort($should), sort($cnameList));
+ }
+
+ public function testDeleteCname()
+ {
+ $this->client->addBucketCname($this->bucketName, 'www.baidu.com');
+ $this->client->addBucketCname($this->bucketName, 'www.qq.com');
+
+ $ret = $this->client->getBucketCname($this->bucketName);
+ $this->assertEquals(2, count($ret->getCnames()));
+
+ // delete one cname
+ $this->client->deleteBucketCname($this->bucketName, 'www.baidu.com');
+
+ $ret = $this->client->getBucketCname($this->bucketName);
+ $this->assertEquals(1, count($ret->getCnames()));
+ $cnames = $ret->getCnames();
+ $this->assertEquals('www.qq.com', $cnames[0]['Domain']);
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketInfoTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketInfoTest.php
new file mode 100755
index 0000000..80fa25c
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketInfoTest.php
@@ -0,0 +1,21 @@
+assertNotNull($bucketInfo);
+ $this->assertEquals('cn-beijing', $bucketInfo->getLocation());
+ $this->assertEquals('name', $bucketInfo->getName());
+ $this->assertEquals('today', $bucketInfo->getCreateDate());
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketLiveChannelTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketLiveChannelTest.php
new file mode 100755
index 0000000..bed68b0
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/BucketLiveChannelTest.php
@@ -0,0 +1,283 @@
+client = Common::getOssClient();
+ $this->bucketName = 'php-sdk-test-rtmp-bucket-name-' . strval(rand(0, 10000));
+ $this->client->createBucket($this->bucketName);
+ Common::waitMetaSync();
+ }
+
+ public function tearDown()
+ {
+ ////to delete created bucket
+ //1. delele live channel
+ $list = $this->client->listBucketLiveChannels($this->bucketName);
+ if (count($list->getChannelList()) != 0)
+ {
+ foreach($list->getChannelList() as $list)
+ {
+ $this->client->deleteBucketLiveChannel($this->bucketName, $list->getName());
+ }
+ }
+ //2. delete exsited object
+ $prefix = 'live-test/';
+ $delimiter = '/';
+ $nextMarker = '';
+ $maxkeys = 1000;
+ $options = array(
+ 'delimiter' => $delimiter,
+ 'prefix' => $prefix,
+ 'max-keys' => $maxkeys,
+ 'marker' => $nextMarker,
+ );
+
+ try {
+ $listObjectInfo = $this->client->listObjects($this->bucketName, $options);
+ } catch (OssException $e) {
+ printf($e->getMessage() . "\n");
+ return;
+ }
+
+ $objectList = $listObjectInfo->getObjectList(); // 文件列表
+ if (!empty($objectList))
+ {
+ foreach($objectList as $objectInfo)
+ $this->client->deleteObject($this->bucketName, $objectInfo->getKey());
+ }
+ //3. delete the bucket
+ $this->client->deleteBucket($this->bucketName);
+ }
+
+ public function testPutLiveChannel()
+ {
+ $config = new LiveChannelConfig(array(
+ 'description' => 'live channel 1',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $info = $this->client->putBucketLiveChannel($this->bucketName, 'live-1', $config);
+ $this->client->deleteBucketLiveChannel($this->bucketName, 'live-1');
+
+ $this->assertEquals('live-1', $info->getName());
+ $this->assertEquals('live channel 1', $info->getDescription());
+ $this->assertEquals(1, count($info->getPublishUrls()));
+ $this->assertEquals(1, count($info->getPlayUrls()));
+ }
+
+ public function testPutLiveChannelWithDefaultParams()
+ {
+ $config = new LiveChannelConfig(array(
+ 'description' => 'live channel 1',
+ 'type' => 'HLS',
+ ));
+ $info = $this->client->putBucketLiveChannel($this->bucketName, 'live-1', $config);
+ $this->client->deleteBucketLiveChannel($this->bucketName, 'live-1');
+
+ $this->assertEquals('live-1', $info->getName());
+ $this->assertEquals('live channel 1', $info->getDescription());
+ $this->assertEquals(1, count($info->getPublishUrls()));
+ $this->assertEquals(1, count($info->getPlayUrls()));
+ }
+
+ public function testListLiveChannels()
+ {
+ $config = new LiveChannelConfig(array(
+ 'description' => 'live channel 1',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $this->client->putBucketLiveChannel($this->bucketName, 'live-1', $config);
+
+ $config = new LiveChannelConfig(array(
+ 'description' => 'live channel 2',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $this->client->putBucketLiveChannel($this->bucketName, 'live-2', $config);
+
+ $list = $this->client->listBucketLiveChannels($this->bucketName);
+
+ $this->assertEquals($this->bucketName, $list->getBucketName());
+ $this->assertEquals(false, $list->getIsTruncated());
+ $channels = $list->getChannelList();
+ $this->assertEquals(2, count($channels));
+
+ $chan1 = $channels[0];
+ $this->assertEquals('live-1', $chan1->getName());
+ $this->assertEquals('live channel 1', $chan1->getDescription());
+ $this->assertEquals(1, count($chan1->getPublishUrls()));
+ $this->assertEquals(1, count($chan1->getPlayUrls()));
+
+ $chan2 = $channels[1];
+ $this->assertEquals('live-2', $chan2->getName());
+ $this->assertEquals('live channel 2', $chan2->getDescription());
+ $this->assertEquals(1, count($chan2->getPublishUrls()));
+ $this->assertEquals(1, count($chan2->getPlayUrls()));
+
+ $list = $this->client->listBucketLiveChannels($this->bucketName, array(
+ 'prefix' => 'live-',
+ 'marker' => 'live-1',
+ 'max-keys' => 10
+ ));
+ $channels = $list->getChannelList();
+ $this->assertEquals(1, count($channels));
+ $chan2 = $channels[0];
+ $this->assertEquals('live-2', $chan2->getName());
+ $this->assertEquals('live channel 2', $chan2->getDescription());
+ $this->assertEquals(1, count($chan2->getPublishUrls()));
+ $this->assertEquals(1, count($chan2->getPlayUrls()));
+
+ $this->client->deleteBucketLiveChannel($this->bucketName, 'live-1');
+ $this->client->deleteBucketLiveChannel($this->bucketName, 'live-2');
+ $list = $this->client->listBucketLiveChannels($this->bucketName, array(
+ 'prefix' => 'live-'
+ ));
+ $this->assertEquals(0, count($list->getChannelList()));
+ }
+
+ public function testDeleteLiveChannel()
+ {
+ $channelName = 'live-to-delete';
+ $config = new LiveChannelConfig(array(
+ 'description' => 'live channel to delete',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $this->client->putBucketLiveChannel($this->bucketName, $channelName, $config);
+
+ $this->client->deleteBucketLiveChannel($this->bucketName, $channelName);
+ $list = $this->client->listBucketLiveChannels($this->bucketName, array(
+ 'prefix' => $channelName
+ ));
+
+ $this->assertEquals(0, count($list->getChannelList()));
+ }
+
+ public function testSignRtmpUrl()
+ {
+ $channelName = '90475';
+ $bucket = 'douyu';
+ $now = time();
+ $url = $this->client->signRtmpUrl($bucket, $channelName, 900, array(
+ 'params' => array(
+ 'playlistName' => 'playlist.m3u8'
+ )
+ ));
+
+ $ret = parse_url($url);
+ $this->assertEquals('rtmp', $ret['scheme']);
+ parse_str($ret['query'], $query);
+
+ $this->assertTrue(isset($query['OSSAccessKeyId']));
+ $this->assertTrue(isset($query['Signature']));
+ $this->assertTrue(intval($query['Expires']) - ($now + 900) < 3);
+ $this->assertEquals('playlist.m3u8', $query['playlistName']);
+ }
+
+ public function testLiveChannelInfo()
+ {
+ $channelName = 'live-to-put-status';
+ $config = new LiveChannelConfig(array(
+ 'description' => 'test live channel info',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $this->client->putBucketLiveChannel($this->bucketName, $channelName, $config);
+
+ $info = $this->client->getLiveChannelInfo($this->bucketName, $channelName);
+ $this->assertEquals('test live channel info', $info->getDescription());
+ $this->assertEquals('enabled', $info->getStatus());
+ $this->assertEquals('HLS', $info->getType());
+ $this->assertEquals(10, $info->getFragDuration());
+ $this->assertEquals(5, $info->getFragCount());
+ $this->assertEquals('playlist.m3u8', $info->getPlayListName());
+
+ $this->client->deleteBucketLiveChannel($this->bucketName, $channelName);
+ $list = $this->client->listBucketLiveChannels($this->bucketName, array(
+ 'prefix' => $channelName
+ ));
+ $this->assertEquals(0, count($list->getChannelList()));
+ }
+
+ public function testPutLiveChannelStatus()
+ {
+ $channelName = 'live-to-put-status';
+ $config = new LiveChannelConfig(array(
+ 'description' => 'test live channel info',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $this->client->putBucketLiveChannel($this->bucketName, $channelName, $config);
+
+ $info = $this->client->getLiveChannelInfo($this->bucketName, $channelName);
+ $this->assertEquals('test live channel info', $info->getDescription());
+ $this->assertEquals('enabled', $info->getStatus());
+ $this->assertEquals('HLS', $info->getType());
+ $this->assertEquals(10, $info->getFragDuration());
+ $this->assertEquals(5, $info->getFragCount());
+ $this->assertEquals('playlist.m3u8', $info->getPlayListName());
+ $status = $this->client->getLiveChannelStatus($this->bucketName, $channelName);
+ $this->assertEquals('Idle', $status->getStatus());
+
+
+ $resp = $this->client->putLiveChannelStatus($this->bucketName, $channelName, "disabled");
+ $info = $this->client->getLiveChannelInfo($this->bucketName, $channelName);
+ $this->assertEquals('test live channel info', $info->getDescription());
+ $this->assertEquals('disabled', $info->getStatus());
+ $this->assertEquals('HLS', $info->getType());
+ $this->assertEquals(10, $info->getFragDuration());
+ $this->assertEquals(5, $info->getFragCount());
+ $this->assertEquals('playlist.m3u8', $info->getPlayListName());
+
+ $status = $this->client->getLiveChannelStatus($this->bucketName, $channelName);
+ //getLiveChannelInfo
+ $this->assertEquals('Disabled', $status->getStatus());
+
+ $this->client->deleteBucketLiveChannel($this->bucketName, $channelName);
+ $list = $this->client->listBucketLiveChannels($this->bucketName, array(
+ 'prefix' => $channelName
+ ));
+ $this->assertEquals(0, count($list->getChannelList()));
+
+ }
+ public function testLiveChannelHistory()
+ {
+ $channelName = 'live-test-history';
+ $config = new LiveChannelConfig(array(
+ 'description' => 'test live channel info',
+ 'type' => 'HLS',
+ 'fragDuration' => 10,
+ 'fragCount' => 5,
+ 'playListName' => 'hello.m3u8'
+ ));
+ $this->client->putBucketLiveChannel($this->bucketName, $channelName, $config);
+
+ $history = $this->client->getLiveChannelHistory($this->bucketName, $channelName);
+ $this->assertEquals(0, count($history->getLiveRecordList()));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CallbackTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CallbackTest.php
new file mode 100755
index 0000000..491c4d9
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CallbackTest.php
@@ -0,0 +1,297 @@
+ossClient->putObject($this->bucket, $copiedObject, file_get_contents(__FILE__));
+
+ /**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+ try {
+ $upload_id = $this->ossClient->initiateMultipartUpload($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ /*
+ * step 2. uploadPartCopy
+ */
+ $copyId = 1;
+ $eTag = $this->ossClient->uploadPartCopy($this->bucket, $copiedObject, $this->bucket, $object, $copyId, $upload_id);
+ $upload_parts[] = array(
+ 'PartNumber' => $copyId,
+ 'ETag' => $eTag,
+ );
+
+ try {
+ $listPartsInfo = $this->ossClient->listParts($this->bucket, $object, $upload_id);
+ $this->assertNotNull($listPartsInfo);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ /**
+ * step 3.
+ */
+
+ $json =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size},\"x:var1\":${x:var1},\"x:var2\":${x:var2}}",
+ "callbackBodyType":"application/json"
+ }';
+
+ $var =
+ '{
+ "x:var1":"value1",
+ "x:var2":"值2"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $json,
+ OssClient::OSS_CALLBACK_VAR => $var
+ );
+
+ try {
+ $result = $this->ossClient->completeMultipartUpload($this->bucket, $object, $upload_id, $upload_parts, $options);
+ $this->assertEquals("200", $result['info']['http_code']);
+ $this->assertEquals("{\"Status\":\"OK\"}", $result['body']);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ public function testMultipartUploadCallbackFailed()
+ {
+ $object = "multipart-callback-test.txt";
+ $copiedObject = "multipart-callback-test.txt.copied";
+ $this->ossClient->putObject($this->bucket, $copiedObject, file_get_contents(__FILE__));
+
+ /**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+ try {
+ $upload_id = $this->ossClient->initiateMultipartUpload($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ /*
+ * step 2. uploadPartCopy
+ */
+ $copyId = 1;
+ $eTag = $this->ossClient->uploadPartCopy($this->bucket, $copiedObject, $this->bucket, $object, $copyId, $upload_id);
+ $upload_parts[] = array(
+ 'PartNumber' => $copyId,
+ 'ETag' => $eTag,
+ );
+
+ try {
+ $listPartsInfo = $this->ossClient->listParts($this->bucket, $object, $upload_id);
+ $this->assertNotNull($listPartsInfo);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ /**
+ * step 3.
+ */
+
+ $json =
+ '{
+ "callbackUrl":"www.baidu.com",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size},\"x:var1\":${x:var1},\"x:var2\":${x:var2}}",
+ "callbackBodyType":"application/json"
+ }';
+
+ $var =
+ '{
+ "x:var1":"value1",
+ "x:var2":"值2"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $json,
+ OssClient::OSS_CALLBACK_VAR => $var
+ );
+
+ try {
+ $result = $this->ossClient->completeMultipartUpload($this->bucket, $object, $upload_id, $upload_parts, $options);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertTrue(true);
+ $this->assertEquals("203", $e->getHTTPStatus());
+ }
+
+ }
+
+ public function testPutObjectCallbackNormal()
+ {
+ //json
+ {
+ $json =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}",
+ "callbackBodyType":"application/json"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $json);
+ $this->putObjectCallbackOk($options, "200");
+ }
+ //url
+ {
+ $url =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}",
+ "callbackBodyType":"application/x-www-form-urlencoded"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $url);
+ $this->putObjectCallbackOk($options, "200");
+ }
+ // Unspecified typre
+ {
+ $url =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $url);
+ $this->putObjectCallbackOk($options, "200");
+ }
+ //json and body is chinese
+ {
+ $json =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\" 春水碧于天,画船听雨眠。\":\"垆边人似月,皓腕凝霜雪。\"}",
+ "callbackBodyType":"application/json"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $json);
+ $this->putObjectCallbackOk($options, "200");
+ }
+ //url and body is chinese
+ {
+ $url =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"春水碧于天,画船听雨眠。垆边人似月,皓腕凝霜雪",
+ "callbackBodyType":"application/x-www-form-urlencoded"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $url);
+ $this->putObjectCallbackOk($options, "200");
+ }
+ //json and add callback_var
+ {
+ $json =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size},\"x:var1\":${x:var1},\"x:var2\":${x:var2}}",
+ "callbackBodyType":"application/json"
+ }';
+
+ $var =
+ '{
+ "x:var1":"value1",
+ "x:var2":"aliyun.com"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $json,
+ OssClient::OSS_CALLBACK_VAR => $var
+ );
+ $this->putObjectCallbackOk($options, "200");
+ }
+ //url and add callback_var
+ {
+ $url =
+ '{
+ "callbackUrl":"callback.oss-demo.com:23450",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var1=${x:var1}&my_var2=${x:var2}",
+ "callbackBodyType":"application/x-www-form-urlencoded"
+ }';
+ $var =
+ '{
+ "x:var1":"value1凌波不过横塘路,但目送,芳",
+ "x:var2":"值2"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $url,
+ OssClient::OSS_CALLBACK_VAR => $var
+ );
+ $this->putObjectCallbackOk($options, "200");
+ }
+
+ }
+
+ public function testPutCallbackWithCallbackFailed()
+ {
+ {
+ $json =
+ '{
+ "callbackUrl":"http://www.baidu.com",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"{\"mimeType\":${mimeType},\"size\":${size}}",
+ "callbackBodyType":"application/json"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $json);
+ $this->putObjectCallbackFailed($options, "203");
+ }
+
+ {
+ $url =
+ '{
+ "callbackUrl":"http://www.baidu.com",
+ "callbackHost":"oss-cn-hangzhou.aliyuncs.com",
+ "callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var1=${x:var1}&my_var2=${x:var2}",
+ "callbackBodyType":"application/x-www-form-urlencoded"
+ }';
+ $options = array(OssClient::OSS_CALLBACK => $url);
+ $this->putObjectCallbackFailed($options, "203");
+ }
+
+ }
+
+ private function putObjectCallbackOk($options, $status)
+ {
+ $object = "oss-php-sdk-callback-test.txt";
+ $content = file_get_contents(__FILE__);
+ try {
+ $result = $this->ossClient->putObject($this->bucket, $object, $content, $options);
+ $this->assertEquals($status, $result['info']['http_code']);
+ $this->assertEquals("{\"Status\":\"OK\"}", $result['body']);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ private function putObjectCallbackFailed($options, $status)
+ {
+ $object = "oss-php-sdk-callback-test.txt";
+ $content = file_get_contents(__FILE__);
+ try {
+ $result = $this->ossClient->putObject($this->bucket, $object, $content, $options);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertEquals($status, $e->getHTTPStatus());
+ $this->assertTrue(true);
+ }
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CnameConfigTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CnameConfigTest.php
new file mode 100755
index 0000000..e3c1ce9
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CnameConfigTest.php
@@ -0,0 +1,77 @@
+
+
+
+ www.foo.com
+ enabled
+ 20150101
+
+
+ bar.com
+ disabled
+ 20160101
+
+
+BBBB;
+
+ public function testFromXml()
+ {
+ $cnameConfig = new CnameConfig();
+ $cnameConfig->parseFromXml($this->xml1);
+
+ $cnames = $cnameConfig->getCnames();
+ $this->assertEquals(2, count($cnames));
+ $this->assertEquals('www.foo.com', $cnames[0]['Domain']);
+ $this->assertEquals('enabled', $cnames[0]['Status']);
+ $this->assertEquals('20150101', $cnames[0]['LastModified']);
+
+ $this->assertEquals('bar.com', $cnames[1]['Domain']);
+ $this->assertEquals('disabled', $cnames[1]['Status']);
+ $this->assertEquals('20160101', $cnames[1]['LastModified']);
+ }
+
+ public function testToXml()
+ {
+ $cnameConfig = new CnameConfig();
+ $cnameConfig->addCname('www.foo.com');
+ $cnameConfig->addCname('bar.com');
+
+ $xml = $cnameConfig->serializeToXml();
+ $comp = new CnameConfig();
+ $comp->parseFromXml($xml);
+
+ $cnames1 = $cnameConfig->getCnames();
+ $cnames2 = $comp->getCnames();
+
+ $this->assertEquals(count($cnames1), count($cnames2));
+ $this->assertEquals(count($cnames1[0]), count($cnames2[0]));
+ $this->assertEquals(1, count($cnames1[0]));
+ $this->assertEquals($cnames1[0]['Domain'], $cnames2[0]['Domain']);
+ }
+
+ public function testCnameNumberLimit()
+ {
+ $cnameConfig = new CnameConfig();
+ for ($i = 0; $i < CnameConfig::OSS_MAX_RULES; $i += 1) {
+ $cnameConfig->addCname(strval($i) . '.foo.com');
+ }
+ try {
+ $cnameConfig->addCname('www.foo.com');
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals(
+ $e->getMessage(),
+ "num of cname in the config exceeds self::OSS_MAX_RULES: " . strval(CnameConfig::OSS_MAX_RULES));
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/Common.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/Common.php
new file mode 100755
index 0000000..9d7190c
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/Common.php
@@ -0,0 +1,70 @@
+getMessage() . "\n");
+ return null;
+ }
+ return $ossClient;
+ }
+
+ public static function getBucketName()
+ {
+ return getenv('OSS_BUCKET');
+ }
+
+ /**
+ * 工具方法,创建一个bucket
+ */
+ public static function createBucket()
+ {
+ $ossClient = self::getOssClient();
+ if (is_null($ossClient)) exit(1);
+ $bucket = self::getBucketName();
+ $acl = OssClient::OSS_ACL_TYPE_PUBLIC_READ;
+ try {
+ $ossClient->createBucket($bucket, $acl);
+ } catch (OssException $e) {
+ printf(__FUNCTION__ . ": FAILED\n");
+ printf($e->getMessage() . "\n");
+ return;
+ }
+ print(__FUNCTION__ . ": OK" . "\n");
+ }
+
+ /**
+ * Wait for bucket meta sync
+ */
+ public static function waitMetaSync()
+ {
+ if (getenv('TRAVIS')) {
+ sleep(10);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ContentTypeTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ContentTypeTest.php
new file mode 100755
index 0000000..606c810
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ContentTypeTest.php
@@ -0,0 +1,133 @@
+/dev/null', $output, $status);
+
+ $this->assertEquals(0, $status);
+ }
+
+ private function getContentType($bucket, $object)
+ {
+ $client = Common::getOssClient();
+ $headers = $client->getObjectMeta($bucket, $object);
+ return $headers['content-type'];
+ }
+
+ public function testByFileName()
+ {
+ $client = Common::getOssClient();
+ $bucket = Common::getBucketName();
+
+ $file = '/tmp/x.html';
+ $object = 'test/x';
+ $this->runCmd('touch ' . $file);
+
+ $client->uploadFile($bucket, $object, $file);
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('text/html', $type);
+
+ $file = '/tmp/x.json';
+ $object = 'test/y';
+ $this->runCmd('dd if=/dev/urandom of=' . $file . ' bs=1024 count=100');
+
+ $client->multiuploadFile($bucket, $object, $file, array('partSize' => 100));
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('application/json', $type);
+ }
+
+ public function testByObjectKey()
+ {
+ $client = Common::getOssClient();
+ $bucket = Common::getBucketName();
+
+ $object = "test/x.txt";
+ $client->putObject($bucket, $object, "hello world");
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('text/plain', $type);
+
+ $file = '/tmp/x.html';
+ $object = 'test/x.txt';
+ $this->runCmd('touch ' . $file);
+
+ $client->uploadFile($bucket, $object, $file);
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('text/html', $type);
+
+ $file = '/tmp/x.none';
+ $object = 'test/x.txt';
+ $this->runCmd('touch ' . $file);
+
+ $client->uploadFile($bucket, $object, $file);
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('text/plain', $type);
+
+ $file = '/tmp/x.mp3';
+ $object = 'test/y.json';
+ $this->runCmd('dd if=/dev/urandom of=' . $file . ' bs=1024 count=100');
+
+ $client->multiuploadFile($bucket, $object, $file, array('partSize' => 100));
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('audio/mpeg', $type);
+
+ $file = '/tmp/x.none';
+ $object = 'test/y.json';
+ $this->runCmd('dd if=/dev/urandom of=' . $file . ' bs=1024 count=100');
+
+ $client->multiuploadFile($bucket, $object, $file, array('partSize' => 100));
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('application/json', $type);
+ }
+
+ public function testByUser()
+ {
+ $client = Common::getOssClient();
+ $bucket = Common::getBucketName();
+
+ $object = "test/x.txt";
+ $client->putObject($bucket, $object, "hello world", array(
+ 'Content-Type' => 'text/html'
+ ));
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('text/html', $type);
+
+ $file = '/tmp/x.html';
+ $object = 'test/x';
+ $this->runCmd('touch ' . $file);
+
+ $client->uploadFile($bucket, $object, $file, array(
+ 'Content-Type' => 'application/json'
+ ));
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('application/json', $type);
+
+ $file = '/tmp/x.json';
+ $object = 'test/y';
+ $this->runCmd('dd if=/dev/urandom of=' . $file . ' bs=1024 count=100');
+
+ $client->multiuploadFile($bucket, $object, $file, array(
+ 'partSize' => 100,
+ 'Content-Type' => 'audio/mpeg'
+ ));
+ $type = $this->getContentType($bucket, $object);
+
+ $this->assertEquals('audio/mpeg', $type);
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CopyObjectResult.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CopyObjectResult.php
new file mode 100755
index 0000000..171d4c8
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CopyObjectResult.php
@@ -0,0 +1,52 @@
+
+
+ Fri, 24 Feb 2012 07:18:48 GMT
+ "5B3C1A2E053D763E1B002CC607C5A0FE"
+
+BBBB;
+
+ public function testNullResponse()
+ {
+ $response = null;
+ try {
+ new CopyObjectResult($response);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('raw response is null', $e->getMessage());
+ }
+ }
+
+ public function testOkResponse()
+ {
+ $header= array();
+ $response = new ResponseCore($header, $this->body, 200);
+ $result = new CopyObjectResult($response);
+ $data = $result->getData();
+ $this->assertTrue($result->isOK());
+ $this->assertEquals("Fri, 24 Feb 2012 07:18:48 GMT", $data[0]);
+ $this->assertEquals("\"5B3C1A2E053D763E1B002CC607C5A0FE\"", $data[1]);
+ }
+
+ public function testFailResponse()
+ {
+ $response = new ResponseCore(array(), "", 404);
+ try {
+ new CopyObjectResult($response);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+
+ }
+ }
+
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CorsConfigTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CorsConfigTest.php
new file mode 100755
index 0000000..ddc4d3a
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/CorsConfigTest.php
@@ -0,0 +1,140 @@
+
+
+
+http://www.b.com
+http://www.a.com
+http://www.a.com
+GET
+PUT
+POST
+x-oss-test
+x-oss-test2
+x-oss-test2
+x-oss-test3
+x-oss-test1
+x-oss-test1
+x-oss-test2
+10
+
+
+http://www.b.com
+GET
+x-oss-test
+x-oss-test1
+110
+
+
+BBBB;
+
+ private $validXml2 = <<
+
+
+http://www.b.com
+http://www.a.com
+http://www.a.com
+GET
+PUT
+POST
+x-oss-test
+x-oss-test2
+x-oss-test2
+x-oss-test3
+x-oss-test1
+x-oss-test1
+x-oss-test2
+10
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $corsConfig = new CorsConfig();
+ $corsConfig->parseFromXml($this->validXml);
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($corsConfig->serializeToXml()));
+ $this->assertNotNull($corsConfig->getRules());
+ $rules = $corsConfig->getRules();
+ $this->assertNotNull($rules[0]->getAllowedHeaders());
+ $this->assertNotNull($rules[0]->getAllowedMethods());
+ $this->assertNotNull($rules[0]->getAllowedOrigins());
+ $this->assertNotNull($rules[0]->getExposeHeaders());
+ $this->assertNotNull($rules[0]->getMaxAgeSeconds());
+ }
+
+ public function testParseValidXml2()
+ {
+ $corsConfig = new CorsConfig();
+ $corsConfig->parseFromXml($this->validXml2);
+ $this->assertEquals($this->cleanXml($this->validXml2), $this->cleanXml($corsConfig->serializeToXml()));
+ }
+
+ public function testCreateCorsConfigFromMoreThan10Rules()
+ {
+ $corsConfig = new CorsConfig();
+ $rule = new CorsRule();
+ for ($i = 0; $i < CorsConfig::OSS_MAX_RULES; $i += 1) {
+ $corsConfig->addRule($rule);
+ }
+ try {
+ $corsConfig->addRule($rule);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals($e->getMessage(), "num of rules in the config exceeds self::OSS_MAX_RULES: " . strval(CorsConfig::OSS_MAX_RULES));
+ }
+ }
+
+ public function testCreateCorsConfigParamAbsent()
+ {
+ $corsConfig = new CorsConfig();
+ $rule = new CorsRule();
+ $corsConfig->addRule($rule);
+
+ try {
+ $xml = $corsConfig->serializeToXml();
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals($e->getMessage(), "maxAgeSeconds is not set in the Rule");
+ }
+ }
+
+ public function testCreateCorsConfigFromScratch()
+ {
+ $corsConfig = new CorsConfig();
+ $rule = new CorsRule();
+ $rule->addAllowedHeader("x-oss-test");
+ $rule->addAllowedHeader("x-oss-test2");
+ $rule->addAllowedHeader("x-oss-test2");
+ $rule->addAllowedHeader("x-oss-test3");
+ $rule->addAllowedOrigin("http://www.b.com");
+ $rule->addAllowedOrigin("http://www.a.com");
+ $rule->addAllowedOrigin("http://www.a.com");
+ $rule->addAllowedMethod("GET");
+ $rule->addAllowedMethod("PUT");
+ $rule->addAllowedMethod("POST");
+ $rule->addExposeHeader("x-oss-test1");
+ $rule->addExposeHeader("x-oss-test1");
+ $rule->addExposeHeader("x-oss-test2");
+ $rule->setMaxAgeSeconds(10);
+ $corsConfig->addRule($rule);
+ $this->assertEquals($this->cleanXml($this->validXml2), $this->cleanXml($corsConfig->serializeToXml()));
+ $this->assertEquals($this->cleanXml($this->validXml2), $this->cleanXml(strval($corsConfig)));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ExistResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ExistResultTest.php
new file mode 100755
index 0000000..e1b4e81
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ExistResultTest.php
@@ -0,0 +1,38 @@
+assertTrue($result->isOK());
+ $this->assertEquals($result->getData(), true);
+ }
+
+ public function testParseInvalid404()
+ {
+ $response = new ResponseCore(array(), "", 404);
+ $result = new ExistResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertEquals($result->getData(), false);
+ }
+
+ public function testInvalidResponse()
+ {
+ $response = new ResponseCore(array(), "", 300);
+ try {
+ new ExistResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetCorsResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetCorsResultTest.php
new file mode 100755
index 0000000..a3281c8
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetCorsResultTest.php
@@ -0,0 +1,67 @@
+
+
+
+http://www.b.com
+http://www.a.com
+http://www.a.com
+GET
+PUT
+POST
+x-oss-test
+x-oss-test2
+x-oss-test2
+x-oss-test3
+x-oss-test1
+x-oss-test1
+x-oss-test2
+10
+
+
+http://www.b.com
+GET
+x-oss-test
+x-oss-test1
+110
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new GetCorsResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $corsConfig = $result->getData();
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($corsConfig->serializeToXml()));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+
+ public function testInvalidResponse()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 300);
+ try {
+ new GetCorsResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetLifecycleResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetLifecycleResultTest.php
new file mode 100755
index 0000000..92ae208
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetLifecycleResultTest.php
@@ -0,0 +1,59 @@
+
+
+
+delete obsoleted files
+obsoleted/
+Enabled
+3
+
+
+delete temporary files
+temporary/
+Enabled
+2022-10-12T00:00:00.000Z
+2022-10-12T00:00:00.000Z
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new GetLifecycleResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $lifecycleConfig = $result->getData();
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($lifecycleConfig->serializeToXml()));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+
+ public function testInvalidResponse()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 300);
+ try {
+ new GetLifecycleResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetLoggingResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetLoggingResultTest.php
new file mode 100755
index 0000000..6195014
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetLoggingResultTest.php
@@ -0,0 +1,51 @@
+
+
+
+TargetBucket
+TargetPrefix
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new GetLoggingResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $loggingConfig = $result->getData();
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($loggingConfig->serializeToXml()));
+ $this->assertEquals("TargetBucket", $loggingConfig->getTargetBucket());
+ $this->assertEquals("TargetPrefix", $loggingConfig->getTargetPrefix());
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+
+ public function testInvalidResponse()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 300);
+ try {
+ new GetLoggingResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetRefererResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetRefererResultTest.php
new file mode 100755
index 0000000..072aa43
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetRefererResultTest.php
@@ -0,0 +1,51 @@
+
+
+true
+
+http://www.aliyun.com
+https://www.aliyun.com
+http://www.*.com
+https://www.?.aliyuncs.com
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new GetRefererResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $refererConfig = $result->getData();
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($refererConfig->serializeToXml()));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+
+ public function testInvalidResponse()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 300);
+ try {
+ new GetRefererResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetWebsiteResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetWebsiteResultTest.php
new file mode 100755
index 0000000..70e1559
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetWebsiteResultTest.php
@@ -0,0 +1,50 @@
+
+
+
+index.html
+
+
+errorDocument.html
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new GetWebsiteResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $websiteConfig = $result->getData();
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($websiteConfig->serializeToXml()));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+
+ public function testInvalidResponse()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 300);
+ try {
+ new GetWebsiteResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/HeaderResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/HeaderResultTest.php
new file mode 100755
index 0000000..dae4975
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/HeaderResultTest.php
@@ -0,0 +1,23 @@
+ 'value'), "", 200);
+ $result = new HeaderResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertTrue(is_array($result->getData()));
+ $data = $result->getData();
+ $this->assertEquals($data['key'], 'value');
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/HttpTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/HttpTest.php
new file mode 100755
index 0000000..a59dfcd
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/HttpTest.php
@@ -0,0 +1,77 @@
+assertFalse($res->isOK());
+ $this->assertTrue($res->isOK(500));
+ }
+
+ public function testGet()
+ {
+ $httpCore = new RequestCore("http://www.baidu.com");
+ $httpResponse = $httpCore->send_request();
+ $this->assertNotNull($httpResponse);
+ }
+
+ public function testSetProxyAndTimeout()
+ {
+ $httpCore = new RequestCore("http://www.baidu.com");
+ $httpCore->set_proxy("1.0.2.1:8888");
+ $httpCore->connect_timeout = 1;
+ try {
+ $httpResponse = $httpCore->send_request();
+ $this->assertTrue(false);
+ } catch (RequestCore_Exception $e) {
+
+ }
+ }
+
+ public function testGetParseTrue()
+ {
+ $httpCore = new RequestCore("http://www.baidu.com");
+ $httpCore->curlopts = array(CURLOPT_HEADER => true);
+ $url = $httpCore->send_request(true);
+ foreach ($httpCore->get_response_header() as $key => $value) {
+ $this->assertEquals($httpCore->get_response_header($key), $value);
+ }
+ $this->assertNotNull($url);
+ }
+
+ public function testParseResponse()
+ {
+ $httpCore = new RequestCore("http://www.baidu.com");
+ $response = $httpCore->send_request();
+ $parsed = $httpCore->process_response(null, $response);
+ $this->assertNotNull($parsed);
+ }
+
+ public function testExceptionGet()
+ {
+ $httpCore = null;
+ $exception = false;
+ try {
+ $httpCore = new RequestCore("http://www.notexistsitexx.com");
+ $httpCore->set_body("");
+ $httpCore->set_method("GET");
+ $httpCore->connect_timeout = 10;
+ $httpCore->timeout = 10;
+ $res = $httpCore->send_request();
+ } catch (RequestCore_Exception $e) {
+ $exception = true;
+ }
+ $this->assertTrue($exception);
+ }
+}
+
+
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/InitiateMultipartUploadResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/InitiateMultipartUploadResultTest.php
new file mode 100755
index 0000000..9f6c7a5
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/InitiateMultipartUploadResultTest.php
@@ -0,0 +1,47 @@
+
+
+ multipart_upload
+ multipart.data
+ 0004B9894A22E5B1888A1E29F8236E2D
+
+BBBB;
+
+ private $invalidXml = <<
+
+ multipart_upload
+ multipart.data
+
+BBBB;
+
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new InitiateMultipartUploadResult($response);
+ $this->assertEquals("0004B9894A22E5B1888A1E29F8236E2D", $result->getData());
+ }
+
+ public function testParseInvalidXml()
+ {
+ $response = new ResponseCore(array(), $this->invalidXml, 200);
+ try {
+ $result = new InitiateMultipartUploadResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LifecycleConfigTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LifecycleConfigTest.php
new file mode 100755
index 0000000..7bd0331
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LifecycleConfigTest.php
@@ -0,0 +1,130 @@
+
+
+
+delete obsoleted files
+obsoleted/
+Enabled
+3
+
+
+delete temporary files
+temporary/
+Enabled
+2022-10-12T00:00:00.000Z
+2022-10-12T00:00:00.000Z
+
+
+BBBB;
+
+ private $validLifecycle2 = <<
+
+delete temporary files
+temporary/
+Enabled
+2022-10-12T00:00:00.000Z
+2022-10-12T00:00:00.000Z
+
+
+BBBB;
+
+ private $nullLifecycle = <<
+
+BBBB;
+
+ public function testConstructValidConfig()
+ {
+ $lifecycleConfig = new LifecycleConfig();
+ $actions = array();
+ $actions[] = new LifecycleAction("Expiration", "Days", 3);
+ $lifecycleRule = new LifecycleRule("delete obsoleted files", "obsoleted/", "Enabled", $actions);
+ $lifecycleConfig->addRule($lifecycleRule);
+ $actions = array();
+ $actions[] = new LifecycleAction("Expiration", "Date", '2022-10-12T00:00:00.000Z');
+ $actions[] = new LifecycleAction("Expiration2", "Date", '2022-10-12T00:00:00.000Z');
+ $lifecycleRule = new LifecycleRule("delete temporary files", "temporary/", "Enabled", $actions);
+ $lifecycleConfig->addRule($lifecycleRule);
+ try {
+ $lifecycleConfig->addRule(null);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('lifecycleRule is null', $e->getMessage());
+ }
+ $this->assertEquals($this->cleanXml(strval($lifecycleConfig)), $this->cleanXml($this->validLifecycle));
+ }
+
+ public function testParseValidXml()
+ {
+ $lifecycleConfig = new LifecycleConfig();
+ $lifecycleConfig->parseFromXml($this->validLifecycle);
+ $this->assertEquals($this->cleanXml($lifecycleConfig->serializeToXml()), $this->cleanXml($this->validLifecycle));
+ $this->assertEquals(2, count($lifecycleConfig->getRules()));
+ $rules = $lifecycleConfig->getRules();
+ $this->assertEquals('delete temporary files', $rules[1]->getId());
+ }
+
+ public function testParseValidXml2()
+ {
+ $lifecycleConfig = new LifecycleConfig();
+ $lifecycleConfig->parseFromXml($this->validLifecycle2);
+ $this->assertEquals($this->cleanXml($lifecycleConfig->serializeToXml()), $this->cleanXml($this->validLifecycle2));
+ $this->assertEquals(1, count($lifecycleConfig->getRules()));
+ $rules = $lifecycleConfig->getRules();
+ $this->assertEquals('delete temporary files', $rules[0]->getId());
+ }
+
+ public function testParseNullXml()
+ {
+ $lifecycleConfig = new LifecycleConfig();
+ $lifecycleConfig->parseFromXml($this->nullLifecycle);
+ $this->assertEquals($this->cleanXml($lifecycleConfig->serializeToXml()), $this->cleanXml($this->nullLifecycle));
+ $this->assertEquals(0, count($lifecycleConfig->getRules()));
+ }
+
+ public function testLifecycleRule()
+ {
+ $lifecycleRule = new LifecycleRule("x", "x", "x", array('x'));
+ $lifecycleRule->setId("id");
+ $lifecycleRule->setPrefix("prefix");
+ $lifecycleRule->setStatus("Enabled");
+ $lifecycleRule->setActions(array());
+
+ $this->assertEquals('id', $lifecycleRule->getId());
+ $this->assertEquals('prefix', $lifecycleRule->getPrefix());
+ $this->assertEquals('Enabled', $lifecycleRule->getStatus());
+ $this->assertEmpty($lifecycleRule->getActions());
+ }
+
+ public function testLifecycleAction()
+ {
+ $action = new LifecycleAction('x', 'x', 'x');
+ $this->assertEquals($action->getAction(), 'x');
+ $this->assertEquals($action->getTimeSpec(), 'x');
+ $this->assertEquals($action->getTimeValue(), 'x');
+ $action->setAction('y');
+ $action->setTimeSpec('y');
+ $action->setTimeValue('y');
+ $this->assertEquals($action->getAction(), 'y');
+ $this->assertEquals($action->getTimeSpec(), 'y');
+ $this->assertEquals($action->getTimeValue(), 'y');
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListBucketsResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListBucketsResultTest.php
new file mode 100755
index 0000000..1abe1f5
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListBucketsResultTest.php
@@ -0,0 +1,97 @@
+
+
+
+ ut_test_put_bucket
+ ut_test_put_bucket
+
+
+
+ oss-cn-hangzhou-a
+ xz02tphky6fjfiuc0
+ 2014-05-15T11:18:32.000Z
+
+
+ oss-cn-hangzhou-a
+ xz02tphky6fjfiuc1
+ 2014-05-15T11:18:32.000Z
+
+
+
+BBBB;
+
+ private $nullXml = <<
+
+
+ ut_test_put_bucket
+ ut_test_put_bucket
+
+
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new ListBucketsResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $bucketListInfo = $result->getData();
+ $this->assertEquals(2, count($bucketListInfo->getBucketList()));
+ }
+
+ public function testParseNullXml()
+ {
+ $response = new ResponseCore(array(), $this->nullXml, 200);
+ $result = new ListBucketsResult($response);
+ $this->assertTrue($result->isOK());
+ $this->assertNotNull($result->getData());
+ $this->assertNotNull($result->getRawResponse());
+ $bucketListInfo = $result->getData();
+ $this->assertEquals(0, count($bucketListInfo->getBucketList()));
+ }
+
+ public function test403()
+ {
+ $errorHeader = array(
+ 'x-oss-request-id' => '1a2b-3c4d'
+ );
+
+ $errorBody = <<< BBBB
+
+
+ NoSuchBucket
+ The specified bucket does not exist.
+ 566B870D207FB3044302EB0A
+ hello.oss-test.aliyun-inc.com
+ hello
+
+BBBB;
+ $response = new ResponseCore($errorHeader, $errorBody, 403);
+ try {
+ new ListBucketsResult($response);
+ } catch (OssException $e) {
+ $this->assertEquals(
+ $e->getMessage(),
+ 'NoSuchBucket: The specified bucket does not exist. RequestId: 1a2b-3c4d');
+ $this->assertEquals($e->getHTTPStatus(), '403');
+ $this->assertEquals($e->getRequestId(), '1a2b-3c4d');
+ $this->assertEquals($e->getErrorCode(), 'NoSuchBucket');
+ $this->assertEquals($e->getErrorMessage(), 'The specified bucket does not exist.');
+ $this->assertEquals($e->getDetails(), $errorBody);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListMultipartUploadResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListMultipartUploadResultTest.php
new file mode 100755
index 0000000..5c757d3
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListMultipartUploadResultTest.php
@@ -0,0 +1,114 @@
+
+
+ oss-example
+ xx
+ 3
+ oss.avi
+ 0004B99B8E707874FC2D692FA5D77D3F
+ x
+ xx
+ 1000
+ false
+
+ multipart.data
+ 0004B999EF518A1FE585B0C9360DC4C8
+ 2012-02-23T04:18:23.000Z
+
+
+ multipart.data
+ 0004B999EF5A239BB9138C6227D69F95
+ 2012-02-23T04:18:23.000Z
+
+
+ oss.avi
+ 0004B99B8E707874FC2D692FA5D77D3F
+ 2012-02-23T06:14:27.000Z
+
+
+BBBB;
+
+ private $validXmlWithEncodedKey = <<
+
+ oss-example
+ url
+ php%2Bkey-marker
+ 3
+ php%2Bnext-key-marker
+ 0004B99B8E707874FC2D692FA5D77D3F
+ %2F
+ php%2Bprefix
+ 1000
+ true
+
+ php%2Bkey-1
+ 0004B999EF518A1FE585B0C9360DC4C8
+ 2012-02-23T04:18:23.000Z
+
+
+ php%2Bkey-2
+ 0004B999EF5A239BB9138C6227D69F95
+ 2012-02-23T04:18:23.000Z
+
+
+ php%2Bkey-3
+ 0004B99B8E707874FC2D692FA5D77D3F
+ 2012-02-23T06:14:27.000Z
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new ListMultipartUploadResult($response);
+ $listMultipartUploadInfo = $result->getData();
+ $this->assertEquals("oss-example", $listMultipartUploadInfo->getBucket());
+ $this->assertEquals("xx", $listMultipartUploadInfo->getKeyMarker());
+ $this->assertEquals(3, $listMultipartUploadInfo->getUploadIdMarker());
+ $this->assertEquals("oss.avi", $listMultipartUploadInfo->getNextKeyMarker());
+ $this->assertEquals("0004B99B8E707874FC2D692FA5D77D3F", $listMultipartUploadInfo->getNextUploadIdMarker());
+ $this->assertEquals("x", $listMultipartUploadInfo->getDelimiter());
+ $this->assertEquals("xx", $listMultipartUploadInfo->getPrefix());
+ $this->assertEquals(1000, $listMultipartUploadInfo->getMaxUploads());
+ $this->assertEquals("false", $listMultipartUploadInfo->getIsTruncated());
+ $uploads = $listMultipartUploadInfo->getUploads();
+ $this->assertEquals("multipart.data", $uploads[0]->getKey());
+ $this->assertEquals("0004B999EF518A1FE585B0C9360DC4C8", $uploads[0]->getUploadId());
+ $this->assertEquals("2012-02-23T04:18:23.000Z", $uploads[0]->getInitiated());
+ }
+
+ public function testParseValidXmlWithEncodedKey()
+ {
+ $response = new ResponseCore(array(), $this->validXmlWithEncodedKey, 200);
+ $result = new ListMultipartUploadResult($response);
+ $listMultipartUploadInfo = $result->getData();
+ $this->assertEquals("oss-example", $listMultipartUploadInfo->getBucket());
+ $this->assertEquals("php+key-marker", $listMultipartUploadInfo->getKeyMarker());
+ $this->assertEquals("php+next-key-marker", $listMultipartUploadInfo->getNextKeyMarker());
+ $this->assertEquals(3, $listMultipartUploadInfo->getUploadIdMarker());
+ $this->assertEquals("0004B99B8E707874FC2D692FA5D77D3F", $listMultipartUploadInfo->getNextUploadIdMarker());
+ $this->assertEquals("/", $listMultipartUploadInfo->getDelimiter());
+ $this->assertEquals("php+prefix", $listMultipartUploadInfo->getPrefix());
+ $this->assertEquals(1000, $listMultipartUploadInfo->getMaxUploads());
+ $this->assertEquals("true", $listMultipartUploadInfo->getIsTruncated());
+ $uploads = $listMultipartUploadInfo->getUploads();
+ $this->assertEquals("php+key-1", $uploads[0]->getKey());
+ $this->assertEquals("0004B999EF518A1FE585B0C9360DC4C8", $uploads[0]->getUploadId());
+ $this->assertEquals("2012-02-23T04:18:23.000Z", $uploads[0]->getInitiated());
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListObjectsResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListObjectsResultTest.php
new file mode 100755
index 0000000..85f262c
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListObjectsResultTest.php
@@ -0,0 +1,151 @@
+
+
+ testbucket-hf
+
+
+ 1000
+ /
+ false
+
+ oss-php-sdk-test/
+
+
+ test/
+
+
+BBBB;
+
+ private $validXml2 = <<
+
+ testbucket-hf
+ oss-php-sdk-test/
+ xx
+ 1000
+ /
+ false
+
+ oss-php-sdk-test/upload-test-object-name.txt
+ 2015-11-18T03:36:00.000Z
+ "89B9E567E7EB8815F2F7D41851F9A2CD"
+ Normal
+ 13115
+ Standard
+
+ cname_user
+ cname_user
+
+
+
+BBBB;
+
+ private $validXmlWithEncodedKey = <<
+
+ testbucket-hf
+ url
+ php%2Fprefix
+ php%2Fmarker
+ php%2Fnext-marker
+ 1000
+ %2F
+ true
+
+ php/a%2Bb
+ 2015-11-18T03:36:00.000Z
+ "89B9E567E7EB8815F2F7D41851F9A2CD"
+ Normal
+ 13115
+ Standard
+
+ cname_user
+ cname_user
+
+
+
+BBBB;
+
+ public function testParseValidXml1()
+ {
+ $response = new ResponseCore(array(), $this->validXml1, 200);
+ $result = new ListObjectsResult($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->getMarker());
+ $this->assertEquals(1000, $objectListInfo->getMaxKeys());
+ $this->assertEquals('/', $objectListInfo->getDelimiter());
+ $this->assertEquals('false', $objectListInfo->getIsTruncated());
+ $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 ListObjectsResult($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->getMarker());
+ $this->assertEquals(1000, $objectListInfo->getMaxKeys());
+ $this->assertEquals('/', $objectListInfo->getDelimiter());
+ $this->assertEquals('false', $objectListInfo->getIsTruncated());
+ $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 ListObjectsResult($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->getMarker());
+ $this->assertEquals('php/next-marker', $objectListInfo->getNextMarker());
+ $this->assertEquals(1000, $objectListInfo->getMaxKeys());
+ $this->assertEquals('/', $objectListInfo->getDelimiter());
+ $this->assertEquals('true', $objectListInfo->getIsTruncated());
+ $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());
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListPartsResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListPartsResultTest.php
new file mode 100755
index 0000000..c446714
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListPartsResultTest.php
@@ -0,0 +1,62 @@
+
+
+ multipart_upload
+ multipart.data
+ 0004B999EF5A239BB9138C6227D69F95
+ 5
+ 1000
+ false
+
+ 1
+ 2012-02-23T07:01:34.000Z
+ "3349DC700140D7F86A078484278075A9"
+ 6291456
+
+
+ 2
+ 2012-02-23T07:01:12.000Z
+ "3349DC700140D7F86A078484278075A9"
+ 6291456
+
+
+ 5
+ 2012-02-23T07:02:03.000Z
+ "7265F4D211B56873A381D321F586E4A9"
+ 1024
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $response = new ResponseCore(array(), $this->validXml, 200);
+ $result = new ListPartsResult($response);
+ $listPartsInfo = $result->getData();
+ $this->assertEquals("multipart_upload", $listPartsInfo->getBucket());
+ $this->assertEquals("multipart.data", $listPartsInfo->getKey());
+ $this->assertEquals("0004B999EF5A239BB9138C6227D69F95", $listPartsInfo->getUploadId());
+ $this->assertEquals(5, $listPartsInfo->getNextPartNumberMarker());
+ $this->assertEquals(1000, $listPartsInfo->getMaxParts());
+ $this->assertEquals("false", $listPartsInfo->getIsTruncated());
+ $this->assertEquals(3, count($listPartsInfo->getListPart()));
+ $parts = $listPartsInfo->getListPart();
+ $this->assertEquals(1, $parts[0]->getPartNumber());
+ $this->assertEquals('2012-02-23T07:01:34.000Z', $parts[0]->getLastModified());
+ $this->assertEquals('"3349DC700140D7F86A078484278075A9"', $parts[0]->getETag());
+ $this->assertEquals(6291456, $parts[0]->getSize());
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LiveChannelXmlTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LiveChannelXmlTest.php
new file mode 100755
index 0000000..cc3e219
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LiveChannelXmlTest.php
@@ -0,0 +1,249 @@
+
+
+ xxx
+ enabled
+
+ hls
+ 1000
+ 5
+ hello.m3u8
+
+
+BBBB;
+
+ private $info = <<
+
+ live-1
+ xxx
+
+ rtmp://bucket.oss-cn-hangzhou.aliyuncs.com/live/213443245345
+
+
+ http://bucket.oss-cn-hangzhou.aliyuncs.com/213443245345/播放列表.m3u8
+
+ enabled
+ 2015-11-24T14:25:31.000Z
+
+BBBB;
+
+ private $list = <<
+
+xxx
+ yyy
+ 100
+ false
+ 121312132
+
+ 12123214323431
+ xxx
+
+ rtmp://bucket.oss-cn-hangzhou.aliyuncs.com/live/1
+
+
+ http://bucket.oss-cn-hangzhou.aliyuncs.com/1/播放列表.m3u8
+
+ enabled
+ 2015-11-24T14:25:31.000Z
+
+
+ 432423432423
+ yyy
+
+ rtmp://bucket.oss-cn-hangzhou.aliyuncs.com/live/2
+
+
+ http://bucket.oss-cn-hangzhou.aliyuncs.com/2/播放列表.m3u8
+
+ enabled
+ 2016-11-24T14:25:31.000Z
+
+
+BBBB;
+
+ private $status = <<
+
+ Live
+ 2016-10-20T14:25:31.000Z
+ 10.1.2.4:47745
+
+ 1280
+ 536
+ 24
+ 72513
+ H264
+
+
+ 6519
+ 44100
+ AAC
+
+
+BBBB;
+
+ private $history = <<
+
+
+ 2013-11-24T14:25:31.000Z
+ 2013-11-24T15:25:31.000Z
+ 10.101.194.148:56861
+
+
+ 2014-11-24T14:25:31.000Z
+ 2014-11-24T15:25:31.000Z
+ 10.101.194.148:56862
+
+
+ 2015-11-24T14:25:31.000Z
+ 2015-11-24T15:25:31.000Z
+ 10.101.194.148:56863
+
+
+BBBB;
+
+ public function testLiveChannelStatus()
+ {
+ $stat = new GetLiveChannelStatus();
+ $stat->parseFromXml($this->status);
+
+ $this->assertEquals('Live', $stat->getStatus());
+ $this->assertEquals('2016-10-20T14:25:31.000Z', $stat->getConnectedTime());
+ $this->assertEquals('10.1.2.4:47745', $stat->getRemoteAddr());
+
+ $this->assertEquals(1280, $stat->getVideoWidth());
+ $this->assertEquals(536, $stat->getVideoHeight());
+ $this->assertEquals(24, $stat->getVideoFrameRate());
+ $this->assertEquals(72513, $stat->getVideoBandwidth());
+ $this->assertEquals('H264', $stat->getVideoCodec());
+ $this->assertEquals(6519, $stat->getAudioBandwidth());
+ $this->assertEquals(44100, $stat->getAudioSampleRate());
+ $this->assertEquals('AAC', $stat->getAudioCodec());
+
+ }
+
+ public function testLiveChannelHistory()
+ {
+ $history = new GetLiveChannelHistory();
+ $history->parseFromXml($this->history);
+
+ $recordList = $history->getLiveRecordList();
+ $this->assertEquals(3, count($recordList));
+
+ $list0 = $recordList[0];
+ $this->assertEquals('2013-11-24T14:25:31.000Z', $list0->getStartTime());
+ $this->assertEquals('2013-11-24T15:25:31.000Z', $list0->getEndTime());
+ $this->assertEquals('10.101.194.148:56861', $list0->getRemoteAddr());
+
+ $list1 = $recordList[1];
+ $this->assertEquals('2014-11-24T14:25:31.000Z', $list1->getStartTime());
+ $this->assertEquals('2014-11-24T15:25:31.000Z', $list1->getEndTime());
+ $this->assertEquals('10.101.194.148:56862', $list1->getRemoteAddr());
+
+ $list2 = $recordList[2];
+ $this->assertEquals('2015-11-24T14:25:31.000Z', $list2->getStartTime());
+ $this->assertEquals('2015-11-24T15:25:31.000Z', $list2->getEndTime());
+ $this->assertEquals('10.101.194.148:56863', $list2->getRemoteAddr());
+
+ }
+
+ public function testLiveChannelConfig()
+ {
+ $config = new LiveChannelConfig(array('name' => 'live-1'));
+ $config->parseFromXml($this->config);
+
+ $this->assertEquals('xxx', $config->getDescription());
+ $this->assertEquals('enabled', $config->getStatus());
+ $this->assertEquals('hls', $config->getType());
+ $this->assertEquals(1000, $config->getFragDuration());
+ $this->assertEquals(5, $config->getFragCount());
+ $this->assertEquals('hello.m3u8', $config->getPlayListName());
+
+ $xml = $config->serializeToXml();
+ $config2 = new LiveChannelConfig(array('name' => 'live-2'));
+ $config2->parseFromXml($xml);
+ $this->assertEquals('xxx', $config2->getDescription());
+ $this->assertEquals('enabled', $config2->getStatus());
+ $this->assertEquals('hls', $config2->getType());
+ $this->assertEquals(1000, $config2->getFragDuration());
+ $this->assertEquals(5, $config2->getFragCount());
+ $this->assertEquals('hello.m3u8', $config2->getPlayListName());
+ }
+
+ public function testLiveChannelInfo()
+ {
+ $info = new LiveChannelInfo(array('name' => 'live-1'));
+ $info->parseFromXml($this->info);
+
+ $this->assertEquals('live-1', $info->getName());
+ $this->assertEquals('xxx', $info->getDescription());
+ $this->assertEquals('enabled', $info->getStatus());
+ $this->assertEquals('2015-11-24T14:25:31.000Z', $info->getLastModified());
+ $pubs = $info->getPublishUrls();
+ $this->assertEquals(1, count($pubs));
+ $this->assertEquals('rtmp://bucket.oss-cn-hangzhou.aliyuncs.com/live/213443245345', $pubs[0]);
+
+ $plays = $info->getPlayUrls();
+ $this->assertEquals(1, count($plays));
+ $this->assertEquals('http://bucket.oss-cn-hangzhou.aliyuncs.com/213443245345/播放列表.m3u8', $plays[0]);
+ }
+
+ public function testLiveChannelList()
+ {
+ $list = new LiveChannelListInfo();
+ $list->parseFromXml($this->list);
+
+ $this->assertEquals('xxx', $list->getPrefix());
+ $this->assertEquals('yyy', $list->getMarker());
+ $this->assertEquals(100, $list->getMaxKeys());
+ $this->assertEquals(false, $list->getIsTruncated());
+ $this->assertEquals('121312132', $list->getNextMarker());
+
+ $channels = $list->getChannelList();
+ $this->assertEquals(2, count($channels));
+
+ $chan1 = $channels[0];
+ $this->assertEquals('12123214323431', $chan1->getName());
+ $this->assertEquals('xxx', $chan1->getDescription());
+ $this->assertEquals('enabled', $chan1->getStatus());
+ $this->assertEquals('2015-11-24T14:25:31.000Z', $chan1->getLastModified());
+ $pubs = $chan1->getPublishUrls();
+ $this->assertEquals(1, count($pubs));
+ $this->assertEquals('rtmp://bucket.oss-cn-hangzhou.aliyuncs.com/live/1', $pubs[0]);
+
+ $plays = $chan1->getPlayUrls();
+ $this->assertEquals(1, count($plays));
+ $this->assertEquals('http://bucket.oss-cn-hangzhou.aliyuncs.com/1/播放列表.m3u8', $plays[0]);
+
+ $chan2 = $channels[1];
+ $this->assertEquals('432423432423', $chan2->getName());
+ $this->assertEquals('yyy', $chan2->getDescription());
+ $this->assertEquals('enabled', $chan2->getStatus());
+ $this->assertEquals('2016-11-24T14:25:31.000Z', $chan2->getLastModified());
+ $pubs = $chan2->getPublishUrls();
+ $this->assertEquals(1, count($pubs));
+ $this->assertEquals('rtmp://bucket.oss-cn-hangzhou.aliyuncs.com/live/2', $pubs[0]);
+
+ $plays = $chan2->getPlayUrls();
+ $this->assertEquals(1, count($plays));
+ $this->assertEquals('http://bucket.oss-cn-hangzhou.aliyuncs.com/2/播放列表.m3u8', $plays[0]);
+ }
+
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LoggingConfigTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LoggingConfigTest.php
new file mode 100755
index 0000000..01496bb
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/LoggingConfigTest.php
@@ -0,0 +1,47 @@
+
+
+
+TargetBucket
+TargetPrefix
+
+
+BBBB;
+
+ private $nullXml = <<
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $loggingConfig = new LoggingConfig();
+ $loggingConfig->parseFromXml($this->validXml);
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml(strval($loggingConfig)));
+ }
+
+ public function testConstruct()
+ {
+ $loggingConfig = new LoggingConfig('TargetBucket', 'TargetPrefix');
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($loggingConfig->serializeToXml()));
+ }
+
+ public function testFailedConstruct()
+ {
+ $loggingConfig = new LoggingConfig('TargetBucket', null);
+ $this->assertEquals($this->cleanXml($this->nullXml), $this->cleanXml($loggingConfig->serializeToXml()));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/MimeTypesTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/MimeTypesTest.php
new file mode 100755
index 0000000..0697409
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/MimeTypesTest.php
@@ -0,0 +1,13 @@
+assertEquals('application/xml', MimeTypes::getMimetype('file.xml'));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ObjectAclTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ObjectAclTest.php
new file mode 100755
index 0000000..d397288
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/ObjectAclTest.php
@@ -0,0 +1,28 @@
+deleteObject($bucket, $object);
+ $client->putObject($bucket, $object, "hello world");
+
+ $acl = $client->getObjectAcl($bucket, $object);
+ $this->assertEquals('default', $acl);
+
+ $client->putObjectAcl($bucket, $object, 'public-read');
+ $acl = $client->getObjectAcl($bucket, $object);
+ $this->assertEquals('public-read', $acl);
+
+ $content = $client->getObject($bucket, $object);
+ $this->assertEquals('hello world', $content);
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketCorsTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketCorsTest.php
new file mode 100755
index 0000000..a32154b
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketCorsTest.php
@@ -0,0 +1,84 @@
+addAllowedHeader("x-oss-test");
+ $rule->addAllowedHeader("x-oss-test2");
+ $rule->addAllowedHeader("x-oss-test2");
+ $rule->addAllowedHeader("x-oss-test3");
+ $rule->addAllowedOrigin("http://www.b.com");
+ $rule->addAllowedOrigin("http://www.a.com");
+ $rule->addAllowedOrigin("http://www.a.com");
+ $rule->addAllowedMethod("GET");
+ $rule->addAllowedMethod("PUT");
+ $rule->addAllowedMethod("POST");
+ $rule->addExposeHeader("x-oss-test1");
+ $rule->addExposeHeader("x-oss-test1");
+ $rule->addExposeHeader("x-oss-test2");
+ $rule->setMaxAgeSeconds(10);
+ $corsConfig->addRule($rule);
+ $rule = new CorsRule();
+ $rule->addAllowedHeader("x-oss-test");
+ $rule->addAllowedMethod("GET");
+ $rule->addAllowedOrigin("http://www.b.com");
+ $rule->addExposeHeader("x-oss-test1");
+ $rule->setMaxAgeSeconds(110);
+ $corsConfig->addRule($rule);
+
+ try {
+ $this->ossClient->putBucketCors($this->bucket, $corsConfig);
+ } catch (OssException $e) {
+ $this->assertFalse(True);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $object = "cors/test.txt";
+ $this->ossClient->putObject($this->bucket, $object, file_get_contents(__FILE__));
+ $headers = $this->ossClient->optionsObject($this->bucket, $object, "http://www.a.com", "GET", "", null);
+ $this->assertNotEmpty($headers);
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ }
+
+ try {
+ Common::waitMetaSync();
+ $corsConfig2 = $this->ossClient->getBucketCors($this->bucket);
+ $this->assertNotNull($corsConfig2);
+ $this->assertEquals($corsConfig->serializeToXml(), $corsConfig2->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertFalse(True);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $this->ossClient->deleteBucketCors($this->bucket);
+ } catch (OssException $e) {
+ $this->assertFalse(True);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $corsConfig3 = $this->ossClient->getBucketCors($this->bucket);
+ $this->assertNotNull($corsConfig3);
+ $this->assertNotEquals($corsConfig->serializeToXml(), $corsConfig3->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertFalse(True);
+ }
+
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketLifecycleTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketLifecycleTest.php
new file mode 100755
index 0000000..46da1f0
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketLifecycleTest.php
@@ -0,0 +1,57 @@
+addRule($lifecycleRule);
+ $actions = array();
+ $actions[] = new LifecycleAction("Expiration", "Date", '2022-10-12T00:00:00.000Z');
+ $lifecycleRule = new LifecycleRule("delete temporary files", "temporary/", "Enabled", $actions);
+ $lifecycleConfig->addRule($lifecycleRule);
+
+ try {
+ $this->ossClient->putBucketLifecycle($this->bucket, $lifecycleConfig);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $lifecycleConfig2 = $this->ossClient->getBucketLifecycle($this->bucket);
+ $this->assertEquals($lifecycleConfig->serializeToXml(), $lifecycleConfig2->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $this->ossClient->deleteBucketLifecycle($this->bucket);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $lifecycleConfig3 = $this->ossClient->getBucketLifecycle($this->bucket);
+ $this->assertNotEquals($lifecycleConfig->serializeToXml(), $lifecycleConfig3->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketLoggingTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketLoggingTest.php
new file mode 100755
index 0000000..16a10eb
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketLoggingTest.php
@@ -0,0 +1,43 @@
+bucket, 'prefix');
+ try {
+ $this->ossClient->putBucketLogging($this->bucket, $this->bucket, 'prefix');
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $loggingConfig2 = $this->ossClient->getBucketLogging($this->bucket);
+ $this->assertEquals($loggingConfig->serializeToXml(), $loggingConfig2->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $this->ossClient->deleteBucketLogging($this->bucket);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $loggingConfig3 = $this->ossClient->getBucketLogging($this->bucket);
+ $this->assertNotEquals($loggingConfig->serializeToXml(), $loggingConfig3->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketRefererTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketRefererTest.php
new file mode 100755
index 0000000..ba7d14f
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketRefererTest.php
@@ -0,0 +1,48 @@
+addReferer('http://www.aliyun.com');
+
+ try {
+ $this->ossClient->putBucketReferer($this->bucket, $refererConfig);
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $refererConfig2 = $this->ossClient->getBucketReferer($this->bucket);
+ $this->assertEquals($refererConfig->serializeToXml(), $refererConfig2->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $nullRefererConfig = new RefererConfig();
+ $nullRefererConfig->setAllowEmptyReferer(false);
+ $this->ossClient->putBucketReferer($this->bucket, $nullRefererConfig);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $refererConfig3 = $this->ossClient->getBucketLogging($this->bucket);
+ $this->assertNotEquals($refererConfig->serializeToXml(), $refererConfig3->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketTest.php
new file mode 100755
index 0000000..b5e0862
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketTest.php
@@ -0,0 +1,49 @@
+ossClient->createBucket("s");
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('"s"bucket name is invalid', $e->getMessage());
+ }
+ }
+
+ public function testBucketWithInvalidACL()
+ {
+ try {
+ $this->ossClient->createBucket($this->bucket, "invalid");
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('invalid:acl is invalid(private,public-read,public-read-write)', $e->getMessage());
+ }
+ }
+
+ public function testBucket()
+ {
+ $this->ossClient->createBucket($this->bucket, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE);
+
+ $bucketListInfo = $this->ossClient->listBuckets();
+ $this->assertNotNull($bucketListInfo);
+ $bucketList = $bucketListInfo->getBucketList();
+ $this->assertTrue(is_array($bucketList));
+ $this->assertGreaterThan(0, count($bucketList));
+ $this->ossClient->putBucketAcl($this->bucket, OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE);
+ Common::waitMetaSync();
+ $this->assertEquals($this->ossClient->getBucketAcl($this->bucket), OssClient::OSS_ACL_TYPE_PUBLIC_READ_WRITE);
+
+ $this->assertTrue($this->ossClient->doesBucketExist($this->bucket));
+ $this->assertFalse($this->ossClient->doesBucketExist($this->bucket . '-notexist'));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketWebsiteTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketWebsiteTest.php
new file mode 100755
index 0000000..dfa9cc1
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketWebsiteTest.php
@@ -0,0 +1,46 @@
+ossClient->putBucketWebsite($this->bucket, $websiteConfig);
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertTrue(false);
+ }
+
+ try {
+ Common::waitMetaSync();
+ $websiteConfig2 = $this->ossClient->getBucketWebsite($this->bucket);
+ $this->assertEquals($websiteConfig->serializeToXml(), $websiteConfig2->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $this->ossClient->deleteBucketWebsite($this->bucket);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ try {
+ Common::waitMetaSync();
+ $websiteConfig3 = $this->ossClient->getBucketLogging($this->bucket);
+ $this->assertNotEquals($websiteConfig->serializeToXml(), $websiteConfig3->serializeToXml());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientImageTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientImageTest.php
new file mode 100755
index 0000000..575292b
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientImageTest.php
@@ -0,0 +1,100 @@
+client = Common::getOssClient();
+ $this->bucketName = 'php-sdk-test-bucket-image-' . strval(rand(0, 10000));
+ $this->client->createBucket($this->bucketName);
+ Common::waitMetaSync();
+ $this->local_file = "example.jpg";
+ $this->object = "oss-example.jpg";
+ $this->download_file = "image.jpg";
+
+ $this->client->uploadFile($this->bucketName, $this->object, $this->local_file);
+ }
+
+ public function tearDown()
+ {
+ $this->client->deleteObject($this->bucketName, $this->object);
+ $this->client->deleteBucket($this->bucketName);
+ }
+
+ public function testImageResize()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/resize,m_fixed,h_100,w_100", );
+ $this->check($options, 100, 100, 3587, 'jpg');
+ }
+
+ public function testImageCrop()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/crop,w_100,h_100,x_100,y_100,r_1", );
+ $this->check($options, 100, 100, 2281, 'jpg');
+ }
+
+ public function testImageRotate()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/rotate,90", );
+ $this->check($options, 267, 400, 21509, 'jpg');
+ }
+
+ public function testImageSharpen()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/sharpen,100", );
+ $this->check($options, 400, 267, 24183, 'jpg');
+ }
+
+ public function testImageWatermark()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ", );
+ $this->check($options, 400, 267, 26953, 'jpg');
+ }
+
+ public function testImageFormat()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/format,png", );
+ $this->check($options, 400, 267, 160733, 'png');
+ }
+
+ public function testImageTofile()
+ {
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $this->download_file,
+ OssClient::OSS_PROCESS => "image/resize,m_fixed,w_100,h_100", );
+ $this->check($options, 100, 100, 3587, 'jpg');
+ }
+
+ private function check($options, $width, $height, $size, $type)
+ {
+ $this->client->getObject($this->bucketName, $this->object, $options);
+ $array = getimagesize($this->download_file);
+ $this->assertEquals($width, $array[0]);
+ $this->assertEquals($height, $array[1]);
+ $this->assertEquals($type === 'jpg' ? 2 : 3, $array[2]);//2 <=> jpg
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientMultipartUploadTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientMultipartUploadTest.php
new file mode 100755
index 0000000..a95f412
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientMultipartUploadTest.php
@@ -0,0 +1,313 @@
+ossClient->uploadDir($this->bucket, "", "abc/ds/s/s/notexitst");
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals("parameter error: abc/ds/s/s/notexitst is not a directory, please check it", $e->getMessage());
+ }
+
+ }
+
+ public function testMultipartUploadBigFile()
+ {
+ $bigFileName = __DIR__ . DIRECTORY_SEPARATOR . "/bigfile.tmp";
+ $localFilename = __DIR__ . DIRECTORY_SEPARATOR . "/localfile.tmp";
+ OssUtil::generateFile($bigFileName, 6 * 1024 * 1024);
+ $object = 'mpu/multipart-bigfile-test.tmp';
+ try {
+ $this->ossClient->multiuploadFile($this->bucket, $object, $bigFileName, array(OssClient::OSS_PART_SIZE => 1));
+ $options = array(OssClient::OSS_FILE_DOWNLOAD => $localFilename);
+ $this->ossClient->getObject($this->bucket, $object, $options);
+ $this->assertEquals(md5_file($bigFileName), md5_file($localFilename));
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertFalse(true);
+ }
+ unlink($bigFileName);
+ unlink($localFilename);
+ }
+
+ public function testMultipartUploadBigFileWithMD5Check()
+ {
+ $bigFileName = __DIR__ . DIRECTORY_SEPARATOR . "/bigfile.tmp";
+ $localFilename = __DIR__ . DIRECTORY_SEPARATOR . "/localfile.tmp";
+ OssUtil::generateFile($bigFileName, 6 * 1024 * 1024);
+ $object = 'mpu/multipart-bigfile-test.tmp';
+ $options = array(
+ OssClient::OSS_CHECK_MD5 => true,
+ OssClient::OSS_PART_SIZE => 1,
+ );
+ try {
+ $this->ossClient->multiuploadFile($this->bucket, $object, $bigFileName, $options);
+ $options = array(OssClient::OSS_FILE_DOWNLOAD => $localFilename);
+ $this->ossClient->getObject($this->bucket, $object, $options);
+ $this->assertEquals(md5_file($bigFileName), md5_file($localFilename));
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertFalse(true);
+ }
+ unlink($bigFileName);
+ unlink($localFilename);
+ }
+
+ public function testCopyPart()
+ {
+ $object = "mpu/multipart-test.txt";
+ $copiedObject = "mpu/multipart-test.txt.copied";
+ $this->ossClient->putObject($this->bucket, $copiedObject, file_get_contents(__FILE__));
+ /**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+ try {
+ $upload_id = $this->ossClient->initiateMultipartUpload($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ /*
+ * step 2. uploadPartCopy
+ */
+ $copyId = 1;
+ $eTag = $this->ossClient->uploadPartCopy($this->bucket, $copiedObject, $this->bucket, $object, $copyId, $upload_id);
+ $upload_parts[] = array(
+ 'PartNumber' => $copyId,
+ 'ETag' => $eTag,
+ );
+
+ try {
+ $listPartsInfo = $this->ossClient->listParts($this->bucket, $object, $upload_id);
+ $this->assertNotNull($listPartsInfo);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ /**
+ * step 3.
+ */
+ try {
+ $this->ossClient->completeMultipartUpload($this->bucket, $object, $upload_id, $upload_parts);
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertTrue(false);
+ }
+
+ $this->assertEquals($this->ossClient->getObject($this->bucket, $object), file_get_contents(__FILE__));
+ $this->assertEquals($this->ossClient->getObject($this->bucket, $copiedObject), file_get_contents(__FILE__));
+ }
+
+ public function testAbortMultipartUpload()
+ {
+ $object = "mpu/multipart-test.txt";
+ /**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+ try {
+ $upload_id = $this->ossClient->initiateMultipartUpload($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ /*
+ * step 2. 上传分片
+ */
+ $part_size = 10 * 1024 * 1024;
+ $upload_file = __FILE__;
+ $upload_filesize = filesize($upload_file);
+ $pieces = $this->ossClient->generateMultiuploadParts($upload_filesize, $part_size);
+ $response_upload_part = array();
+ $upload_position = 0;
+ $is_check_md5 = true;
+ foreach ($pieces as $i => $piece) {
+ $from_pos = $upload_position + (integer)$piece[OssClient::OSS_SEEK_TO];
+ $to_pos = (integer)$piece[OssClient::OSS_LENGTH] + $from_pos - 1;
+ $up_options = array(
+ OssClient::OSS_FILE_UPLOAD => $upload_file,
+ OssClient::OSS_PART_NUM => ($i + 1),
+ OssClient::OSS_SEEK_TO => $from_pos,
+ OssClient::OSS_LENGTH => $to_pos - $from_pos + 1,
+ OssClient::OSS_CHECK_MD5 => $is_check_md5,
+ );
+ if ($is_check_md5) {
+ $content_md5 = OssUtil::getMd5SumForFile($upload_file, $from_pos, $to_pos);
+ $up_options[OssClient::OSS_CONTENT_MD5] = $content_md5;
+ }
+ //2. 将每一分片上传到OSS
+ try {
+ $response_upload_part[] = $this->ossClient->uploadPart($this->bucket, $object, $upload_id, $up_options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+ $upload_parts = array();
+ foreach ($response_upload_part as $i => $eTag) {
+ $upload_parts[] = array(
+ 'PartNumber' => ($i + 1),
+ 'ETag' => $eTag,
+ );
+ }
+
+ try {
+ $listPartsInfo = $this->ossClient->listParts($this->bucket, $object, $upload_id);
+ $this->assertNotNull($listPartsInfo);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ $this->assertEquals(1, count($listPartsInfo->getListPart()));
+
+ $numOfMultipartUpload1 = 0;
+ $options = null;
+ try {
+ $listMultipartUploadInfo = $listMultipartUploadInfo = $this->ossClient->listMultipartUploads($this->bucket, $options);
+ $this->assertNotNull($listMultipartUploadInfo);
+ $numOfMultipartUpload1 = count($listMultipartUploadInfo->getUploads());
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ try {
+ $this->ossClient->abortMultipartUpload($this->bucket, $object, $upload_id);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ $numOfMultipartUpload2 = 0;
+ try {
+ $listMultipartUploadInfo = $listMultipartUploadInfo = $this->ossClient->listMultipartUploads($this->bucket, $options);
+ $this->assertNotNull($listMultipartUploadInfo);
+ $numOfMultipartUpload2 = count($listMultipartUploadInfo->getUploads());
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ $this->assertEquals($numOfMultipartUpload1 - 1, $numOfMultipartUpload2);
+ }
+
+ public function testPutObjectByRawApis()
+ {
+ $object = "mpu/multipart-test.txt";
+ /**
+ * step 1. 初始化一个分块上传事件, 也就是初始化上传Multipart, 获取upload id
+ */
+ try {
+ $upload_id = $this->ossClient->initiateMultipartUpload($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ /*
+ * step 2. 上传分片
+ */
+ $part_size = 10 * 1024 * 1024;
+ $upload_file = __FILE__;
+ $upload_filesize = filesize($upload_file);
+ $pieces = $this->ossClient->generateMultiuploadParts($upload_filesize, $part_size);
+ $response_upload_part = array();
+ $upload_position = 0;
+ $is_check_md5 = true;
+ foreach ($pieces as $i => $piece) {
+ $from_pos = $upload_position + (integer)$piece[OssClient::OSS_SEEK_TO];
+ $to_pos = (integer)$piece[OssClient::OSS_LENGTH] + $from_pos - 1;
+ $up_options = array(
+ OssClient::OSS_FILE_UPLOAD => $upload_file,
+ OssClient::OSS_PART_NUM => ($i + 1),
+ OssClient::OSS_SEEK_TO => $from_pos,
+ OssClient::OSS_LENGTH => $to_pos - $from_pos + 1,
+ OssClient::OSS_CHECK_MD5 => $is_check_md5,
+ );
+ if ($is_check_md5) {
+ $content_md5 = OssUtil::getMd5SumForFile($upload_file, $from_pos, $to_pos);
+ $up_options[OssClient::OSS_CONTENT_MD5] = $content_md5;
+ }
+ //2. 将每一分片上传到OSS
+ try {
+ $response_upload_part[] = $this->ossClient->uploadPart($this->bucket, $object, $upload_id, $up_options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+ $upload_parts = array();
+ foreach ($response_upload_part as $i => $eTag) {
+ $upload_parts[] = array(
+ 'PartNumber' => ($i + 1),
+ 'ETag' => $eTag,
+ );
+ }
+
+ try {
+ $listPartsInfo = $this->ossClient->listParts($this->bucket, $object, $upload_id);
+ $this->assertNotNull($listPartsInfo);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ /**
+ * step 3.
+ */
+ try {
+ $this->ossClient->completeMultipartUpload($this->bucket, $object, $upload_id, $upload_parts);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ function testPutObjectsByDir()
+ {
+ $localDirectory = dirname(__FILE__);
+ $prefix = "samples/codes";
+ try {
+ $this->ossClient->uploadDir($this->bucket, $prefix, $localDirectory);
+ } catch (OssException $e) {
+ var_dump($e->getMessage());
+ $this->assertFalse(true);
+
+ }
+ $this->assertTrue($this->ossClient->doesObjectExist($this->bucket, 'samples/codes/' . "OssClientMultipartUploadTest.php"));
+ }
+
+ public function testPutObjectByMultipartUpload()
+ {
+ $object = "mpu/multipart-test.txt";
+ $file = __FILE__;
+ $options = array();
+
+ try {
+ $this->ossClient->multiuploadFile($this->bucket, $object, $file, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ public function testPutObjectByMultipartUploadWithMD5Check()
+ {
+ $object = "mpu/multipart-test.txt";
+ $file = __FILE__;
+ $options = array(OssClient::OSS_CHECK_MD5 => true);
+
+ try {
+ $this->ossClient->multiuploadFile($this->bucket, $object, $file, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ public function testListMultipartUploads()
+ {
+ $options = null;
+ try {
+ $listMultipartUploadInfo = $this->ossClient->listMultipartUploads($this->bucket, $options);
+ $this->assertNotNull($listMultipartUploadInfo);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientObjectTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientObjectTest.php
new file mode 100755
index 0000000..34e3ded
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientObjectTest.php
@@ -0,0 +1,588 @@
+ossClient->getObjectMeta($this->bucket, $object);
+ $this->assertEquals('200', $res['info']['http_code']);
+ $this->assertEquals('text/plain', $res['content-type']);
+ $this->assertEquals('Accept-Encoding', $res['vary']);
+ $this->assertTrue(isset($res['content-length']));
+ $this->assertFalse(isset($res['content-encoding']));
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ $options = array(OssClient::OSS_HEADERS => array(OssClient::OSS_ACCEPT_ENCODING => 'deflate, gzip'));
+
+ try {
+ $res = $this->ossClient->getObjectMeta($this->bucket, $object, $options);
+ $this->assertEquals('200', $res['info']['http_code']);
+ $this->assertEquals('text/plain', $res['content-type']);
+ $this->assertEquals('Accept-Encoding', $res['vary']);
+ $this->assertFalse(isset($res['content-length']));
+ $this->assertEquals('gzip', $res['content-encoding']);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ public function testGetObjectWithAcceptEncoding()
+ {
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $options = array(OssClient::OSS_HEADERS => array(OssClient::OSS_ACCEPT_ENCODING => 'deflate, gzip'));
+
+ try {
+ $res = $this->ossClient->getObject($this->bucket, $object, $options);
+ $this->assertEquals(file_get_contents(__FILE__), $res);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ public function testGetObjectWithHeader()
+ {
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ try {
+ $res = $this->ossClient->getObject($this->bucket, $object, array(OssClient::OSS_LAST_MODIFIED => "xx"));
+ $this->assertEquals(file_get_contents(__FILE__), $res);
+ } catch (OssException $e) {
+ $this->assertEquals('"/ilegal.txt" object name is invalid', $e->getMessage());
+ }
+ }
+
+ public function testGetObjectWithIleggalEtag()
+ {
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ try {
+ $res = $this->ossClient->getObject($this->bucket, $object, array(OssClient::OSS_ETAG => "xx"));
+ $this->assertEquals(file_get_contents(__FILE__), $res);
+ } catch (OssException $e) {
+ $this->assertEquals('"/ilegal.txt" object name is invalid', $e->getMessage());
+ }
+ }
+
+ public function testObject()
+ {
+ /**
+ * 上传本地变量到bucket
+ */
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $content = file_get_contents(__FILE__);
+ $options = array(
+ OssClient::OSS_LENGTH => strlen($content),
+ OssClient::OSS_HEADERS => array(
+ 'Expires' => 'Fri, 28 Feb 2020 05:38:42 GMT',
+ 'Cache-Control' => 'no-cache',
+ 'Content-Disposition' => 'attachment;filename=oss_download.log',
+ 'Content-Encoding' => 'utf-8',
+ 'Content-Language' => 'zh-CN',
+ 'x-oss-server-side-encryption' => 'AES256',
+ 'x-oss-meta-self-define-title' => 'user define meta info',
+ ),
+ );
+
+ try {
+ $this->ossClient->putObject($this->bucket, $object, $content, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ try {
+ $this->ossClient->putObject($this->bucket, $object, $content, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ try {
+ $result = $this->ossClient->deleteObjects($this->bucket, "stringtype", $options);
+ $this->assertEquals('stringtype', $result[0]);
+ } catch (OssException $e) {
+ $this->assertEquals('objects must be array', $e->getMessage());
+ }
+
+ try {
+ $result = $this->ossClient->deleteObjects($this->bucket, "stringtype", $options);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('objects must be array', $e->getMessage());
+ }
+
+ try {
+ $this->ossClient->uploadFile($this->bucket, $object, "notexist.txt", $options);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('notexist.txt file does not exist', $e->getMessage());
+ }
+
+ /**
+ * getObject到本地变量,检查是否match
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * getObject的前五个字节
+ */
+ try {
+ $options = array(OssClient::OSS_RANGE => '0-4');
+ $content = $this->ossClient->getObject($this->bucket, $object, $options);
+ $this->assertEquals($content, 'assertFalse(true);
+ }
+
+
+ /**
+ * 上传本地文件到object
+ */
+ try {
+ $this->ossClient->uploadFile($this->bucket, $object, __FILE__);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 下载文件到本地变量,检查是否match
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 下载文件到本地文件
+ */
+ $localfile = "upload-test-object-name.txt";
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $localfile,
+ );
+
+ try {
+ $this->ossClient->getObject($this->bucket, $object, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ $this->assertTrue(file_get_contents($localfile) === file_get_contents(__FILE__));
+ if (file_exists($localfile)) {
+ unlink($localfile);
+ }
+
+ /**
+ * 下载文件到本地文件 no such key
+ */
+ $localfile = "upload-test-object-name-no-such-key.txt";
+ $options = array(
+ OssClient::OSS_FILE_DOWNLOAD => $localfile,
+ );
+
+ try {
+ $this->ossClient->getObject($this->bucket, $object . "no-such-key", $options);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertTrue(true);
+ $this->assertFalse(file_exists($localfile));
+ if (strpos($e, "The specified key does not exist") == false)
+ {
+ $this->assertTrue(true);
+ }
+ }
+
+ /**
+ * 下载文件到内容 no such key
+ */
+ try {
+ $result = $this->ossClient->getObject($this->bucket, $object . "no-such-key");
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertTrue(true);
+ if (strpos($e, "The specified key does not exist") == false)
+ {
+ $this->assertTrue(true);
+ }
+ }
+
+ /**
+ * 复制object
+ */
+ $to_bucket = $this->bucket;
+ $to_object = $object . '.copy';
+ $options = array();
+ try {
+ $result = $this->ossClient->copyObject($this->bucket, $object, $to_bucket, $to_object, $options);
+ $this->assertFalse(empty($result));
+ $this->assertEquals(strlen("2016-11-21T03:46:58.000Z"), strlen($result[0]));
+ $this->assertEquals(strlen("\"5B3C1A2E053D763E1B002CC607C5A0FE\""), strlen($result[1]));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ var_dump($e->getMessage());
+
+ }
+
+ /**
+ * 检查复制的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $to_object);
+ $this->assertEquals($content, file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 列出bucket内的文件列表
+ */
+ $prefix = '';
+ $delimiter = '/';
+ $next_marker = '';
+ $maxkeys = 1000;
+ $options = array(
+ 'delimiter' => $delimiter,
+ 'prefix' => $prefix,
+ 'max-keys' => $maxkeys,
+ 'marker' => $next_marker,
+ );
+
+ try {
+ $listObjectInfo = $this->ossClient->listObjects($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));
+
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+
+ /**
+ * 设置文件的meta信息
+ */
+ $from_bucket = $this->bucket;
+ $from_object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $to_bucket = $from_bucket;
+ $to_object = $from_object;
+ $copy_options = array(
+ OssClient::OSS_HEADERS => array(
+ 'Expires' => '2012-10-01 08:00:00',
+ 'Content-Disposition' => 'attachment; filename="xxxxxx"',
+ ),
+ );
+ try {
+ $this->ossClient->copyObject($from_bucket, $from_object, $to_bucket, $to_object, $copy_options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 获取文件的meta信息
+ */
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ try {
+ $objectMeta = $this->ossClient->getObjectMeta($this->bucket, $object);
+ $this->assertEquals('attachment; filename="xxxxxx"', $objectMeta[strtolower('Content-Disposition')]);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除单个文件
+ */
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+
+ try {
+ $this->assertTrue($this->ossClient->doesObjectExist($this->bucket, $object));
+ $this->ossClient->deleteObject($this->bucket, $object);
+ $this->assertFalse($this->ossClient->doesObjectExist($this->bucket, $object));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除多个个文件
+ */
+ $object1 = "oss-php-sdk-test/upload-test-object-name.txt";
+ $object2 = "oss-php-sdk-test/upload-test-object-name.txt.copy";
+ $list = array($object1, $object2);
+ try {
+ $this->assertTrue($this->ossClient->doesObjectExist($this->bucket, $object2));
+
+ $result = $this->ossClient->deleteObjects($this->bucket, $list);
+ $this->assertEquals($list[1], $result[0]);
+ $this->assertEquals($list[0], $result[1]);
+
+ $result = $this->ossClient->deleteObjects($this->bucket, $list, array('quiet' => 'true'));
+ $this->assertEquals(array(), $result);
+ $this->assertFalse($this->ossClient->doesObjectExist($this->bucket, $object2));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ public function testAppendObject()
+ {
+ $object = "oss-php-sdk-test/append-test-object-name.txt";
+ $content_array = array('Hello OSS', 'Hi OSS', 'OSS OK');
+
+ /**
+ * 追加上传字符串
+ */
+ try {
+ $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[0], 0);
+ $this->assertEquals($position, strlen($content_array[0]));
+ $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[1], $position);
+ $this->assertEquals($position, strlen($content_array[0]) + strlen($content_array[1]));
+ $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[2], $position);
+ $this->assertEquals($position, strlen($content_array[0]) + strlen($content_array[1]) + strlen($content_array[1]));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 检查内容的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, implode($content_array));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+
+ /**
+ * 删除测试object
+ */
+ try {
+ $this->ossClient->deleteObject($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 追加上传本地文件
+ */
+ try {
+ $position = $this->ossClient->appendFile($this->bucket, $object, __FILE__, 0);
+ $this->assertEquals($position, filesize(__FILE__));
+ $position = $this->ossClient->appendFile($this->bucket, $object, __FILE__, $position);
+ $this->assertEquals($position, filesize(__FILE__) * 2);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 检查复制的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, file_get_contents(__FILE__) . file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除测试object
+ */
+ try {
+ $this->ossClient->deleteObject($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+
+ $options = array(
+ OssClient::OSS_HEADERS => array(
+ 'Expires' => '2012-10-01 08:00:00',
+ 'Content-Disposition' => 'attachment; filename="xxxxxx"',
+ ),
+ );
+
+ /**
+ * 带option的追加上传
+ */
+ try {
+ $position = $this->ossClient->appendObject($this->bucket, $object, "Hello OSS, ", 0, $options);
+ $position = $this->ossClient->appendObject($this->bucket, $object, "Hi OSS.", $position);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 获取文件的meta信息
+ */
+ try {
+ $objectMeta = $this->ossClient->getObjectMeta($this->bucket, $object);
+ $this->assertEquals('attachment; filename="xxxxxx"', $objectMeta[strtolower('Content-Disposition')]);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除测试object
+ */
+ try {
+ $this->ossClient->deleteObject($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ public function testPutIllelObject()
+ {
+ $object = "/ilegal.txt";
+ try {
+ $this->ossClient->putObject($this->bucket, $object, "hi", null);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('"/ilegal.txt" object name is invalid', $e->getMessage());
+ }
+ }
+
+ public function testCheckMD5()
+ {
+ $object = "oss-php-sdk-test/upload-test-object-name.txt";
+ $content = file_get_contents(__FILE__);
+ $options = array(OssClient::OSS_CHECK_MD5 => true);
+
+ /**
+ * 上传数据开启MD5
+ */
+ try {
+ $this->ossClient->putObject($this->bucket, $object, $content, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 检查复制的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 上传文件开启MD5
+ */
+ try {
+ $this->ossClient->uploadFile($this->bucket, $object, __FILE__, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 检查复制的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除测试object
+ */
+ try {
+ $this->ossClient->deleteObject($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ $object = "oss-php-sdk-test/append-test-object-name.txt";
+ $content_array = array('Hello OSS', 'Hi OSS', 'OSS OK');
+ $options = array(OssClient::OSS_CHECK_MD5 => true);
+
+ /**
+ * 追加上传字符串
+ */
+ try {
+ $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[0], 0, $options);
+ $this->assertEquals($position, strlen($content_array[0]));
+ $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[1], $position, $options);
+ $this->assertEquals($position, strlen($content_array[0]) + strlen($content_array[1]));
+ $position = $this->ossClient->appendObject($this->bucket, $object, $content_array[2], $position, $options);
+ $this->assertEquals($position, strlen($content_array[0]) + strlen($content_array[1]) + strlen($content_array[1]));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 检查内容的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, implode($content_array));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除测试object
+ */
+ try {
+ $this->ossClient->deleteObject($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 追加上传本地文件
+ */
+ try {
+ $position = $this->ossClient->appendFile($this->bucket, $object, __FILE__, 0, $options);
+ $this->assertEquals($position, filesize(__FILE__));
+ $position = $this->ossClient->appendFile($this->bucket, $object, __FILE__, $position, $options);
+ $this->assertEquals($position, filesize(__FILE__) * 2);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 检查复制的是否相同
+ */
+ try {
+ $content = $this->ossClient->getObject($this->bucket, $object);
+ $this->assertEquals($content, file_get_contents(__FILE__) . file_get_contents(__FILE__));
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ /**
+ * 删除测试object
+ */
+ try {
+ $this->ossClient->deleteObject($this->bucket, $object);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->ossClient->putObject($this->bucket, 'oss-php-sdk-test/upload-test-object-name.txt', file_get_contents(__FILE__));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientSignatureTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientSignatureTest.php
new file mode 100755
index 0000000..109121d
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientSignatureTest.php
@@ -0,0 +1,111 @@
+ossClient->putObject($this->bucket, $object, file_get_contents(__FILE__));
+ $timeout = 3600;
+ try {
+ $signedUrl = $this->ossClient->signUrl($this->bucket, $object, $timeout);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ $request = new RequestCore($signedUrl);
+ $request->set_method('GET');
+ $request->add_header('Content-Type', '');
+ $request->send_request();
+ $res = new ResponseCore($request->get_response_header(), $request->get_response_body(), $request->get_response_code());
+ $this->assertEquals(file_get_contents(__FILE__), $res->body);
+ }
+
+ public function testGetSignedUrlForPuttingObject()
+ {
+ $object = "a.file";
+ $timeout = 3600;
+ try {
+ $signedUrl = $this->ossClient->signUrl($this->bucket, $object, $timeout, "PUT");
+ $content = file_get_contents(__FILE__);
+ $request = new RequestCore($signedUrl);
+ $request->set_method('PUT');
+ $request->add_header('Content-Type', '');
+ $request->add_header('Content-Length', strlen($content));
+ $request->set_body($content);
+ $request->send_request();
+ $res = new ResponseCore($request->get_response_header(),
+ $request->get_response_body(), $request->get_response_code());
+ $this->assertTrue($res->isOK());
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+ public function testGetSignedUrlForPuttingObjectFromFile()
+ {
+ $file = __FILE__;
+ $object = "a.file";
+ $timeout = 3600;
+ $options = array('Content-Type' => 'txt');
+ try {
+ $signedUrl = $this->ossClient->signUrl($this->bucket, $object, $timeout, "PUT", $options);
+ $request = new RequestCore($signedUrl);
+ $request->set_method('PUT');
+ $request->add_header('Content-Type', 'txt');
+ $request->set_read_file($file);
+ $request->set_read_stream_size(filesize($file));
+ $request->send_request();
+ $res = new ResponseCore($request->get_response_header(),
+ $request->get_response_body(), $request->get_response_code());
+ $this->assertTrue($res->isOK());
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ }
+
+ public function tearDown()
+ {
+ $this->ossClient->deleteObject($this->bucket, "a.file");
+ parent::tearDown();
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+ /**
+ * 上传本地变量到bucket
+ */
+ $object = "a.file";
+ $content = file_get_contents(__FILE__);
+ $options = array(
+ OssClient::OSS_LENGTH => strlen($content),
+ OssClient::OSS_HEADERS => array(
+ 'Expires' => 'Fri, 28 Feb 2020 05:38:42 GMT',
+ 'Cache-Control' => 'no-cache',
+ 'Content-Disposition' => 'attachment;filename=oss_download.log',
+ 'Content-Encoding' => 'utf-8',
+ 'Content-Language' => 'zh-CN',
+ 'x-oss-server-side-encryption' => 'AES256',
+ 'x-oss-meta-self-define-title' => 'user define meta info',
+ ),
+ );
+
+ try {
+ $this->ossClient->putObject($this->bucket, $object, $content, $options);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientTest.php
new file mode 100755
index 0000000..72bf5cc
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientTest.php
@@ -0,0 +1,111 @@
+assertFalse($ossClient->isUseSSL());
+ $ossClient->setUseSSL(true);
+ $this->assertTrue($ossClient->isUseSSL());
+ $this->assertTrue(true);
+ $this->assertEquals(3, $ossClient->getMaxRetries());
+ $ossClient->setMaxTries(4);
+ $this->assertEquals(4, $ossClient->getMaxRetries());
+ $ossClient->setTimeout(10);
+ $ossClient->setConnectTimeout(20);
+ } catch (OssException $e) {
+ assertFalse(true);
+ }
+ }
+
+ public function testConstrunct2()
+ {
+ try {
+ $ossClient = new OssClient('id', "", 'http://oss-cn-hangzhou.aliyuncs.com');
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals("access key secret is empty", $e->getMessage());
+ }
+ }
+
+ public function testConstrunct3()
+ {
+ try {
+ $ossClient = new OssClient("", 'key', 'http://oss-cn-hangzhou.aliyuncs.com');
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals("access key id is empty", $e->getMessage());
+ }
+ }
+
+ public function testConstrunct4()
+ {
+ try {
+ $ossClient = new OssClient('id', 'key', "");
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('endpoint is empty', $e->getMessage());
+ }
+ }
+
+ public function testConstrunct5()
+ {
+ try {
+ $ossClient = new OssClient('id', 'key', "123.123.123.1");
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ public function testConstrunct6()
+ {
+ try {
+ $ossClient = new OssClient('id', 'key', "https://123.123.123.1");
+ $this->assertTrue($ossClient->isUseSSL());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ public function testConstrunct7()
+ {
+ try {
+ $ossClient = new OssClient('id', 'key', "http://123.123.123.1");
+ $this->assertFalse($ossClient->isUseSSL());
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ public function testConstrunct8()
+ {
+ try {
+ $ossClient = new OssClient('id', 'key', "http://123.123.123.1", true);
+ $ossClient->listBuckets();
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+
+ }
+ }
+
+ public function testConstrunct9()
+ {
+ try {
+ $accessKeyId = ' ' . getenv('OSS_ACCESS_KEY_ID') . ' ';
+ $accessKeySecret = ' ' . getenv('OSS_ACCESS_KEY_SECRET') . ' ';
+ $endpoint = ' ' . getenv('OSS_ENDPOINT') . '/ ';
+ $ossClient = new OssClient($accessKeyId, $accessKeySecret , $endpoint, false);
+ $ossClient->listBuckets();
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+ }
+
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssExceptionTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssExceptionTest.php
new file mode 100755
index 0000000..4a418d5
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssExceptionTest.php
@@ -0,0 +1,19 @@
+assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertNotNull($e);
+ $this->assertEquals($e->getMessage(), "ERR");
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssUtilTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssUtilTest.php
new file mode 100755
index 0000000..3279417
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssUtilTest.php
@@ -0,0 +1,214 @@
+assertEquals(OssUtil::chkChinese("hello,world"), 0);
+ $str = '你好,这里是卖咖啡!';
+ $strGBK = OssUtil::encodePath($str);
+ $this->assertEquals(OssUtil::chkChinese($str), 1);
+ $this->assertEquals(OssUtil::chkChinese($strGBK), 1);
+ }
+
+ public function testIsGB2312()
+ {
+ $str = '你好,这里是卖咖啡!';
+ $this->assertFalse(OssUtil::isGb2312($str));
+ }
+
+ public function testCheckChar()
+ {
+ $str = '你好,这里是卖咖啡!';
+ $this->assertFalse(OssUtil::checkChar($str));
+ $this->assertTrue(OssUtil::checkChar(iconv("UTF-8", "GB2312//IGNORE", $str)));
+ }
+
+ public function testIsIpFormat()
+ {
+ $this->assertTrue(OssUtil::isIPFormat("10.101.160.147"));
+ $this->assertTrue(OssUtil::isIPFormat("12.12.12.34"));
+ $this->assertTrue(OssUtil::isIPFormat("12.12.12.12"));
+ $this->assertTrue(OssUtil::isIPFormat("255.255.255.255"));
+ $this->assertTrue(OssUtil::isIPFormat("0.1.1.1"));
+ $this->assertFalse(OssUtil::isIPFormat("0.1.1.x"));
+ $this->assertFalse(OssUtil::isIPFormat("0.1.1.256"));
+ $this->assertFalse(OssUtil::isIPFormat("256.1.1.1"));
+ $this->assertFalse(OssUtil::isIPFormat("0.1.1.0.1"));
+ $this->assertTrue(OssUtil::isIPFormat("10.10.10.10:123"));
+ }
+
+ public function testToQueryString()
+ {
+ $option = array("a" => "b");
+ $this->assertEquals('a=b', OssUtil::toQueryString($option));
+ }
+
+ public function testSReplace()
+ {
+ $str = "<>&'\"";
+ $this->assertEquals("<>&'"", OssUtil::sReplace($str));
+ }
+
+ public function testCheckChinese()
+ {
+ $str = '你好,这里是卖咖啡!';
+ $this->assertEquals(OssUtil::chkChinese($str), 1);
+ if (OssUtil::isWin()) {
+ $strGB = OssUtil::encodePath($str);
+ $this->assertEquals($str, iconv("GB2312", "UTF-8", $strGB));
+ }
+ }
+
+ public function testValidateOption()
+ {
+ $option = 'string';
+
+ try {
+ OssUtil::validateOptions($option);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals("string:option must be array", $e->getMessage());
+ }
+
+ $option = null;
+
+ try {
+ OssUtil::validateOptions($option);
+ $this->assertTrue(true);
+ } catch (OssException $e) {
+ $this->assertFalse(true);
+ }
+
+ }
+
+ public function testCreateDeleteObjectsXmlBody()
+ {
+ $xml = <<true obj1
+BBBB;
+ $a = array('obj1');
+ $this->assertEquals($xml, $this->cleanXml(OssUtil::createDeleteObjectsXmlBody($a, 'true')));
+ }
+
+ public function testCreateCompleteMultipartUploadXmlBody()
+ {
+ $xml = <<2 xx
+BBBB;
+ $a = array(array("PartNumber" => 2, "ETag" => "xx"));
+ $this->assertEquals($this->cleanXml(OssUtil::createCompleteMultipartUploadXmlBody($a)), $xml);
+ }
+
+ public function testValidateBucket()
+ {
+ $this->assertTrue(OssUtil::validateBucket("xxx"));
+ $this->assertFalse(OssUtil::validateBucket("XXXqwe123"));
+ $this->assertFalse(OssUtil::validateBucket("XX"));
+ $this->assertFalse(OssUtil::validateBucket("/X"));
+ $this->assertFalse(OssUtil::validateBucket(""));
+ }
+
+ public function testValidateObject()
+ {
+ $this->assertTrue(OssUtil::validateObject("xxx"));
+ $this->assertTrue(OssUtil::validateObject("xxx23"));
+ $this->assertTrue(OssUtil::validateObject("12321-xxx"));
+ $this->assertTrue(OssUtil::validateObject("x"));
+ $this->assertFalse(OssUtil::validateObject("/aa"));
+ $this->assertFalse(OssUtil::validateObject("\\aa"));
+ $this->assertFalse(OssUtil::validateObject(""));
+ }
+
+ public function testStartWith()
+ {
+ $this->assertTrue(OssUtil::startsWith("xxab", "xx"), true);
+ }
+
+ public function testReadDir()
+ {
+ $list = OssUtil::readDir("./src", ".|..|.svn|.git", true);
+ $this->assertNotNull($list);
+ }
+
+ public function testIsWin()
+ {
+ //$this->assertTrue(OssUtil::isWin());
+ }
+
+ public function testGetMd5SumForFile()
+ {
+ $this->assertEquals(OssUtil::getMd5SumForFile(__FILE__, 0, filesize(__FILE__) - 1), base64_encode(md5(file_get_contents(__FILE__), true)));
+ }
+
+ public function testGenerateFile()
+ {
+ $path = __DIR__ . DIRECTORY_SEPARATOR . "generatedFile.txt";
+ OssUtil::generateFile($path, 1024 * 1024);
+ $this->assertEquals(filesize($path), 1024 * 1024);
+ unlink($path);
+ }
+
+ public function testThrowOssExceptionWithMessageIfEmpty()
+ {
+ $null = null;
+ try {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($null, "xx");
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertEquals('xx', $e->getMessage());
+ }
+ }
+
+ public function testThrowOssExceptionWithMessageIfEmpty2()
+ {
+ $null = "";
+ try {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($null, "xx");
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertEquals('xx', $e->getMessage());
+ }
+ }
+
+ public function testValidContent()
+ {
+ $null = "";
+ try {
+ OssUtil::validateContent($null);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertEquals('http body content is invalid', $e->getMessage());
+ }
+
+ $notnull = "x";
+ try {
+ OssUtil::validateContent($notnull);
+ $this->assertTrue(true);
+ } catch (OssException $e) {
+ $this->assertEquals('http body content is invalid', $e->getMessage());
+ }
+ }
+
+ public function testThrowOssExceptionWithMessageIfEmpty3()
+ {
+ $null = "xx";
+ try {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($null, "xx");
+ $this->assertTrue(True);
+ } catch (OssException $e) {
+ $this->assertTrue(false);
+ }
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/PutSetDeleteResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/PutSetDeleteResultTest.php
new file mode 100755
index 0000000..b298e44
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/PutSetDeleteResultTest.php
@@ -0,0 +1,66 @@
+assertFalse(true);
+ } catch (OssException $e) {
+ $this->assertEquals('raw response is null', $e->getMessage());
+ }
+ }
+
+ public function testOkResponse()
+ {
+ $header= array(
+ 'x-oss-request-id' => '582AA51E004C4550BD27E0E4',
+ 'etag' => '595FA1EA77945233921DF12427F9C7CE',
+ 'content-md5' => 'WV+h6neUUjOSHfEkJ/nHzg==',
+ 'info' => array(
+ 'http_code' => '200',
+ 'method' => 'PUT'
+ ),
+ );
+ $response = new ResponseCore($header, "this is a mock body, just for test", 200);
+ $result = new PutSetDeleteResult($response);
+ $data = $result->getData();
+ $this->assertTrue($result->isOK());
+ $this->assertEquals("this is a mock body, just for test", $data['body']);
+ $this->assertEquals('582AA51E004C4550BD27E0E4', $data['x-oss-request-id']);
+ $this->assertEquals('595FA1EA77945233921DF12427F9C7CE', $data['etag']);
+ $this->assertEquals('WV+h6neUUjOSHfEkJ/nHzg==', $data['content-md5']);
+ $this->assertEquals('200', $data['info']['http_code']);
+ $this->assertEquals('PUT', $data['info']['method']);
+ }
+
+ public function testFailResponse()
+ {
+ $response = new ResponseCore(array(), "", 301);
+ try {
+ new PutSetDeleteResult($response);
+ $this->assertFalse(true);
+ } catch (OssException $e) {
+
+ }
+ }
+
+ public function setUp()
+ {
+
+ }
+
+ public function tearDown()
+ {
+
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/RefererConfigTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/RefererConfigTest.php
new file mode 100755
index 0000000..8360a24
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/RefererConfigTest.php
@@ -0,0 +1,54 @@
+
+
+true
+
+http://www.aliyun.com
+https://www.aliyun.com
+http://www.*.com
+https://www.?.aliyuncs.com
+
+
+BBBB;
+
+ private $validXml2 = <<
+
+true
+
+http://www.aliyun.com
+
+
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $refererConfig = new RefererConfig();
+ $refererConfig->parseFromXml($this->validXml);
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($refererConfig->serializeToXml()));
+ }
+
+ public function testParseValidXml2()
+ {
+ $refererConfig = new RefererConfig();
+ $refererConfig->parseFromXml($this->validXml2);
+ $this->assertEquals(true, $refererConfig->isAllowEmptyReferer());
+ $this->assertEquals(1, count($refererConfig->getRefererList()));
+ $this->assertEquals($this->cleanXml($this->validXml2), $this->cleanXml(strval($refererConfig)));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/TestOssClientBase.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/TestOssClientBase.php
new file mode 100755
index 0000000..4abd31f
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/TestOssClientBase.php
@@ -0,0 +1,51 @@
+bucket = Common::getBucketName() . rand(100000, 999999);
+ $this->ossClient = Common::getOssClient();
+ $this->ossClient->createBucket($this->bucket);
+ Common::waitMetaSync();
+ }
+
+ public function tearDown()
+ {
+ if (!$this->ossClient->doesBucketExist($this->bucket)) {
+ return;
+ }
+
+ $objects = $this->ossClient->listObjects(
+ $this->bucket, array('max-keys' => 1000, 'delimiter' => ''))->getObjectList();
+ $keys = array();
+ foreach ($objects as $obj) {
+ $keys[] = $obj->getKey();
+ }
+ if (count($keys) > 0) {
+ $this->ossClient->deleteObjects($this->bucket, $keys);
+ }
+ $uploads = $this->ossClient->listMultipartUploads($this->bucket)->getUploads();
+ foreach ($uploads as $up) {
+ $this->ossClient->abortMultipartUpload($this->bucket, $up->getKey(), $up->getUploadId());
+ }
+
+ $this->ossClient->deleteBucket($this->bucket);
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/UploadPartResultTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/UploadPartResultTest.php
new file mode 100755
index 0000000..e4789ef
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/UploadPartResultTest.php
@@ -0,0 +1,33 @@
+ '7265F4D211B56873A381D321F586E4A9');
+ private $invalidHeader = array();
+
+ public function testParseValidHeader()
+ {
+ $response = new ResponseCore($this->validHeader, "", 200);
+ $result = new UploadPartResult($response);
+ $eTag = $result->getData();
+ $this->assertEquals('7265F4D211B56873A381D321F586E4A9', $eTag);
+ }
+
+ public function testParseInvalidHeader()
+ {
+ $response = new ResponseCore($this->invalidHeader, "", 200);
+ try {
+ new UploadPartResult($response);
+ $this->assertTrue(false);
+ } catch (OssException $e) {
+ $this->assertEquals('cannot get ETag', $e->getMessage());
+ }
+ }
+}
diff --git a/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/WebsiteConfigTest.php b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/WebsiteConfigTest.php
new file mode 100755
index 0000000..2ec0fcb
--- /dev/null
+++ b/app/Common/extend/aliyuncs/oss-sdk-php/tests/OSS/Tests/WebsiteConfigTest.php
@@ -0,0 +1,56 @@
+
+
+
+index.html
+
+
+errorDocument.html
+
+
+BBBB;
+
+ private $nullXml = <<
+BBBB;
+ private $nullXml2 = <<
+BBBB;
+
+ public function testParseValidXml()
+ {
+ $websiteConfig = new WebsiteConfig("index");
+ $websiteConfig->parseFromXml($this->validXml);
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($websiteConfig->serializeToXml()));
+ }
+
+ public function testParsenullXml()
+ {
+ $websiteConfig = new WebsiteConfig();
+ $websiteConfig->parseFromXml($this->nullXml);
+ $this->assertTrue($this->cleanXml($this->nullXml) === $this->cleanXml($websiteConfig->serializeToXml()) ||
+ $this->cleanXml($this->nullXml2) === $this->cleanXml($websiteConfig->serializeToXml()));
+ }
+
+ public function testWebsiteConstruct()
+ {
+ $websiteConfig = new WebsiteConfig("index.html", "errorDocument.html");
+ $this->assertEquals('index.html', $websiteConfig->getIndexDocument());
+ $this->assertEquals('errorDocument.html', $websiteConfig->getErrorDocument());
+ $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml($websiteConfig->serializeToXml()));
+ }
+
+ private function cleanXml($xml)
+ {
+ return str_replace("\n", "", str_replace("\r", "", $xml));
+ }
+}
diff --git a/app/Common/extend/diy/allComponents.php b/app/Common/extend/diy/allComponents.php
new file mode 100755
index 0000000..0015704
--- /dev/null
+++ b/app/Common/extend/diy/allComponents.php
@@ -0,0 +1,51 @@
+ "基本组件",
+ "type" => "base",
+ "data" => [
+ [
+ 'title' => "轮播图",
+ 'type' => "banner",
+ 'iconPath' => 'icontupian1'
+ ],
+ [
+ 'title' => "导航",
+ 'type' => "column",
+ 'iconPath' => 'icondaohang'
+ ],
+ [
+ 'title' => "广告",
+ 'type' => "imagewindow",
+ 'iconPath' => 'iconguanggaogongguan'
+ ],
+ ]
+];
+
+$decoration = [
+ "title" => "装修组件",
+ 'type' => 'decoration',
+ "data" => [
+ [
+ 'title' => "工地列表",
+ 'type' => "site",
+ 'iconPath' => 'icongongdiweixuanzhong'
+ ],
+ [
+ 'title' => "案例列表",
+ 'type' => "case",
+ 'iconPath' => 'iconanli'
+ ],
+ [
+ 'title' => "攻略列表",
+ 'type' => "strategy",
+ 'iconPath' => 'icongonglve'
+ ],
+ ]
+];
+
+
+return [
+ 20 => [$base, $decoration],
+// 21 => [$base, $decoration],
+];
\ No newline at end of file
diff --git a/app/Common/extend/menu/allAdminMenus.php b/app/Common/extend/menu/allAdminMenus.php
new file mode 100755
index 0000000..6c2b594
--- /dev/null
+++ b/app/Common/extend/menu/allAdminMenus.php
@@ -0,0 +1,5101 @@
+ $survey,
+ 'BusinessCard' => $businessCard,
+// 'Malls' => $malls,
+// 'Dynamic' => $dynamic,
+// 'Website' => $website,
+ 'Customer' => $customer,
+ 'Company' => $company,
+ 'System' => $sys,
+ 'Renovation' => $renovation,
+ 'Diy' => $diy,
+ 'App' => $app,
+];
diff --git a/app/Common/extend/qiniu/.gitignore b/app/Common/extend/qiniu/.gitignore
new file mode 100755
index 0000000..4c842c8
--- /dev/null
+++ b/app/Common/extend/qiniu/.gitignore
@@ -0,0 +1,12 @@
+*.phar
+*.zip
+build/artifacts
+phpunit.xml
+phpunit.functional.xml
+.DS_Store
+.swp
+.build
+composer.lock
+vendor
+src/package.xml
+.idea/
diff --git a/app/Common/extend/qiniu/.scrutinizer.yml b/app/Common/extend/qiniu/.scrutinizer.yml
new file mode 100755
index 0000000..8d9304c
--- /dev/null
+++ b/app/Common/extend/qiniu/.scrutinizer.yml
@@ -0,0 +1,35 @@
+filter:
+ excluded_paths: [tests/*]
+checks:
+ php:
+ code_rating: true
+ remove_extra_empty_lines: true
+ remove_php_closing_tag: true
+ remove_trailing_whitespace: true
+ fix_use_statements:
+ remove_unused: true
+ preserve_multiple: false
+ preserve_blanklines: true
+ order_alphabetically: true
+ fix_php_opening_tag: true
+ fix_linefeed: true
+ fix_line_ending: true
+ fix_identation_4spaces: true
+ fix_doc_comments: true
+tools:
+ external_code_coverage:
+ timeout: 1200
+ runs: 3
+ php_analyzer: true
+ php_code_coverage: false
+ php_code_sniffer:
+ config:
+ standard: PSR2
+ filter:
+ paths: ['src']
+ php_loc:
+ enabled: true
+ excluded_dirs: [vendor, tests]
+ php_cpd:
+ enabled: true
+ excluded_dirs: [vendor, tests]
diff --git a/app/Common/extend/qiniu/.travis.yml b/app/Common/extend/qiniu/.travis.yml
new file mode 100755
index 0000000..60951b1
--- /dev/null
+++ b/app/Common/extend/qiniu/.travis.yml
@@ -0,0 +1,23 @@
+sudo: false
+language: php
+
+php:
+ - 5.4
+ - 5.5
+ - 5.6
+ - 7.0
+
+before_script:
+ - export QINIU_TEST_ENV="travis"
+ - travis_retry composer self-update
+ - travis_retry composer install --no-interaction --prefer-source --dev
+
+script:
+ - ./vendor/bin/phpcs --standard=PSR2 src
+ - ./vendor/bin/phpcs --standard=PSR2 examples
+ - ./vendor/bin/phpcs --standard=PSR2 tests
+ - ./vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover tests/Qiniu/Tests/
+
+after_script:
+ - wget https://scrutinizer-ci.com/ocular.phar
+ - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
diff --git a/app/Common/extend/qiniu/CHANGELOG.md b/app/Common/extend/qiniu/CHANGELOG.md
new file mode 100755
index 0000000..8a284bd
--- /dev/null
+++ b/app/Common/extend/qiniu/CHANGELOG.md
@@ -0,0 +1,105 @@
+# Changelog
+
+## 7.2.7 (2018-11-06)
+* 添加 QVM 内网上传到 KODO 的 zone 设置
+
+## 7.2.6 (2018-05-18)
+* 修复rs,rsf在不同机房默认的https域名
+
+## 7.2.5 (2018-05-10)
+* 修复表单上传中多余的参数checkCrc导致的fname错位问题
+
+## 7.2.4 (2018-05-09)
+### 增加
+* 连麦功能
+
+## 7.2.3 (2018-01-20)
+### 增加
+* 新加坡机房
+### 修正
+* 获取域名的入口域名
+* http回复头部兼容大小写
+
+## 7.2.2 (2017-11-06)
+### 增加
+* Qiniu算法的鉴权方法
+
+## 7.1.4 (2017-06-21)
+### 增加
+* cdn 文件/目录 刷新
+* cdn 获取 流量/带宽
+* cdn 获取域名的访问日志列表
+* cdn 对资源链接进行时间戳防盗链签名
+
+## 7.1.3 (2016-11-18)
+### 增加
+* move, copy操作增加force参数
+
+## 7.1.2 (2016-11-12)
+### 修正
+* 明确抛出获取各区域域名失败时的报错
+
+## 7.1.1 (2016-11-02)
+### 修正
+* 多区域配置文件存储目录从home修改到tmp目录
+
+
+## 7.1.0 (2016-10-22)
+### 增加
+* 多存储区域的支持
+
+## 7.0.8 (2016-07-19)
+### 增加
+* demo
+* https url 支持
+* deleteAfterDays 策略
+* 添加图片处理链接统一拼接方法 by @SherlockRen
+
+## 7.0.7 (2016-01-12)
+### 修正
+* PersistentFop参数pipeline和notify_url失效
+* resume 模式 close file inputstream
+
+## 7.0.6 (2015-12-05)
+### 修正
+* php7.0 Json 对空字符串解析单元测试报错
+* 开启安全模式或者设置可操作目录树时,设置CURLOPT_FOLLOWLOCATION报错, by @twocabbages
+* fetch 支持不指定key, by @sinkcup
+
+## 7.0.5 (2015-10-29)
+### 增加
+* 增加上传策略最小文件大小限制 fsizeMin
+* 增加常见examples
+
+## 7.0.4 (2015-07-23)
+### 修正
+* 一些地方的严格比较检查
+* resumeupload 备用地址失效
+
+## 7.0.3 (2015-07-10)
+### 修改
+* 多zone 支持
+
+## 7.0.2 (2015-04-18)
+### 修改
+* fetch 接口返回内容调整
+* pfop 接口调整
+
+###修正
+* exception 类调用
+
+## 7.0.1 (2015-03-27)
+### 增加
+* 增加代码注释
+
+## 7.0.0 (2015-02-03)
+
+### 增加
+* 简化上传接口
+* 自动选择断点续上传还是直传
+* 重构代码,接口和内部结构更清晰
+* 改变mime
+* 代码覆盖度报告
+* policy改为array, 便于灵活增加,并加入过期字段检查
+* 文件列表支持目录形式
+* 利用元编程方式支持 fop 和 pfop
diff --git a/app/Common/extend/qiniu/CONTRIBUTING.md b/app/Common/extend/qiniu/CONTRIBUTING.md
new file mode 100755
index 0000000..0466bf9
--- /dev/null
+++ b/app/Common/extend/qiniu/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+# 贡献代码指南
+
+我们非常欢迎大家来贡献代码,我们会向贡献者致以最诚挚的敬意。
+
+一般可以通过在Github上提交[Pull Request](https://github.com/qiniu/php-sdk)来贡献代码。
+
+## Pull Request要求
+
+- **[PSR-2 编码风格标准](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** 。要通过项目中的code sniffer检查。
+
+- **代码格式** 提交前 请按 ./vendor/bin/phpcbf --standard=PSR2 进行格式化。
+
+- **必须添加测试!** - 如果没有测试(单元测试、集成测试都可以),那么提交的补丁是不会通过的。
+
+- **记得更新文档** - 保证`README.md`以及其他相关文档及时更新,和代码的变更保持一致性。
+
+- **考虑我们的发布周期** - 我们的版本号会服从[SemVer v2.0.0](http://semver.org/),我们绝对不会随意变更对外的API。
+
+- **创建feature分支** - 最好不要从你的master分支提交 pull request。
+
+- **一个feature提交一个pull请求** - 如果你的代码变更了多个操作,那就提交多个pull请求吧。
+
+- **清晰的commit历史** - 保证你的pull请求的每次commit操作都是有意义的。如果你开发中需要执行多次的即时commit操作,那么请把它们放到一起再提交pull请求。
+
+## 运行测试
+
+``` bash
+./vendor/bin/phpunit tests/Qiniu/Tests/
+
+```
diff --git a/app/Common/extend/qiniu/LICENSE b/app/Common/extend/qiniu/LICENSE
new file mode 100755
index 0000000..ba646be
--- /dev/null
+++ b/app/Common/extend/qiniu/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Qiniu, Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/app/Common/extend/qiniu/README.md b/app/Common/extend/qiniu/README.md
new file mode 100755
index 0000000..16c8b49
--- /dev/null
+++ b/app/Common/extend/qiniu/README.md
@@ -0,0 +1,75 @@
+# Qiniu Cloud SDK for PHP
+[](http://doxygen.io/github.com/qiniu/php-sdk/)
+[](LICENSE)
+[](https://travis-ci.org/qiniu/php-sdk)
+[](https://packagist.org/packages/qiniu/php-sdk)
+[](https://packagist.org/packages/qiniu/php-sdk)
+[](https://scrutinizer-ci.com/g/qiniu/php-sdk/?branch=master)
+[](https://scrutinizer-ci.com/g/qiniu/php-sdk/?branch=master)
+[](https://gitter.im/qiniu/php-sdk?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](http://weibo.com/qiniutek)
+
+## 安装
+
+* 通过composer,这是推荐的方式,可以使用composer.json 声明依赖,或者运行下面的命令。SDK 包已经放到这里 [`qiniu/php-sdk`][install-packagist] 。
+```bash
+$ composer require qiniu/php-sdk
+```
+* 直接下载安装,SDK 没有依赖其他第三方库,但需要参照 composer的autoloader,增加一个自己的autoloader程序。
+
+## 运行环境
+
+| Qiniu SDK版本 | PHP 版本 |
+|:--------------------:|:---------------------------:|
+| 7.x | cURL extension, 5.3 - 5.6,7.0 |
+| 6.x | cURL extension, 5.2 - 5.6 |
+
+## 使用方法
+
+### 上传
+```php
+use Qiniu\Storage\UploadManager;
+use Qiniu\Auth;
+...
+ $upManager = new UploadManager();
+ $auth = new Auth($accessKey, $secretKey);
+ $token = $auth->uploadToken($bucketName);
+ list($ret, $error) = $upManager->put($token, 'formput', 'hello world');
+...
+```
+
+## 测试
+
+``` bash
+$ ./vendor/bin/phpunit tests/Qiniu/Tests/
+```
+
+## 常见问题
+
+- $error保留了请求响应的信息,失败情况下ret 为none, 将$error可以打印出来,提交给我们。
+- API 的使用 demo 可以参考 [单元测试](https://github.com/qiniu/php-sdk/blob/master/tests)。
+
+## 代码贡献
+
+详情参考[代码提交指南](https://github.com/qiniu/php-sdk/blob/master/CONTRIBUTING.md)。
+
+## 贡献记录
+
+- [所有贡献者](https://github.com/qiniu/php-sdk/contributors)
+
+## 联系我们
+
+- 如果需要帮助,请提交工单(在portal右侧点击咨询和建议提交工单,或者直接向 support@qiniu.com 发送邮件)
+- 如果有什么问题,可以到问答社区提问,[问答社区](http://qiniu.segmentfault.com/)
+- 更详细的文档,见[官方文档站](http://developer.qiniu.com/)
+- 如果发现了bug, 欢迎提交 [issue](https://github.com/qiniu/php-sdk/issues)
+- 如果有功能需求,欢迎提交 [issue](https://github.com/qiniu/php-sdk/issues)
+- 如果要提交代码,欢迎提交 pull request
+- 欢迎关注我们的[微信](http://www.qiniu.com/#weixin) [微博](http://weibo.com/qiniutek),及时获取动态信息。
+
+## 代码许可
+
+The MIT License (MIT).详情见 [License文件](https://github.com/qiniu/php-sdk/blob/master/LICENSE).
+
+[packagist]: http://packagist.org
+[install-packagist]: https://packagist.org/packages/qiniu/php-sdk
diff --git a/app/Common/extend/qiniu/autoload.php b/app/Common/extend/qiniu/autoload.php
new file mode 100755
index 0000000..4379b91
--- /dev/null
+++ b/app/Common/extend/qiniu/autoload.php
@@ -0,0 +1,14 @@
+=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "~2.3"
+ },
+ "autoload": {
+ "psr-4": {"Qiniu\\": "src/Qiniu"},
+ "files": ["src/Qiniu/functions.php"]
+ }
+}
diff --git a/app/Common/extend/qiniu/docs/rtc/README.md b/app/Common/extend/qiniu/docs/rtc/README.md
new file mode 100755
index 0000000..7b98ca0
--- /dev/null
+++ b/app/Common/extend/qiniu/docs/rtc/README.md
@@ -0,0 +1,71 @@
+# Rtc Streaming Cloud Server-Side Library For PHP
+
+## Features
+
+- Appclient
+ - [x] 创建房间: client->createApp()
+ - [x] 查看房间: client->getApp()
+ - [x] 删除房间: client->deleteApp()
+ - [x] 生成房间token: client->appToken()
+
+
+
+## Contents
+
+- [Installation](#installation)
+- [Usage](#usage)
+ - [Configuration](#configuration)
+ - [App](#app)
+ - [Create a app](#create-a-app)
+ - [Get a app](#get-a-app)
+ - [Delete a app](#delete-a-app)
+ - [Generate a app token](#generate-a-app-token)
+
+
+## Usage
+
+### App
+
+#### Create a app
+
+```php
+$ak = "gwd_gV4gPKZZsmEOvAuNU1AcumicmuHooTfu64q5";
+$sk = "xxxx";
+$auth = new Auth($ak, $sk);
+$client = new Qiniu\Rtc\AppClient($auth);
+$resp=$client->createApp("901","testApp");
+print_r($resp);
+```
+
+#### Get an app
+
+```php
+$ak = "gwd_gV4gPKZZsmEOvAuNU1AcumicmuHooTfu64q5";
+$sk = "xxxx";
+$auth = new Auth($ak, $sk);
+$client = new Qiniu\Rtc\AppClient($auth);
+$resp=$client->getApp("deq02uhb6");
+print_r($resp);
+```
+
+#### Delete an app
+
+```php
+$ak = "gwd_gV4gPKZZsmEOvAuNU1AcumicmuHooTfu64q5";
+$sk = "xxxx";
+$auth = new Auth($ak, $sk);
+$client = new Qiniu\Rtc\AppClient($auth);
+$resp=$client->deleteApp("deq02uhb6");
+print_r($resp);
+```
+
+#### Generate an app token
+
+```php
+$ak = "gwd_gV4gPKZZsmEOvAuNU1AcumicmuHooTfu64q5";
+$sk = "xxxx";
+$auth = new Auth($ak, $sk);
+$client = new Qiniu\Rtc\AppClient($auth);
+$resp=$client->appToken("deq02uhb6", "lfx", '1111', (time()+3600), 'user');
+print_r($resp);
+```
\ No newline at end of file
diff --git a/app/Common/extend/qiniu/docs/rtc/example.php b/app/Common/extend/qiniu/docs/rtc/example.php
new file mode 100755
index 0000000..f30b9b4
--- /dev/null
+++ b/app/Common/extend/qiniu/docs/rtc/example.php
@@ -0,0 +1,42 @@
+createApp($hub, $title, $maxUsers);
+ print_r($resp);
+ // 获取app状态
+ $resp = $client->getApp('dgdl5ge8y');
+ print_r($resp);
+ //修改app状态
+ $mergePublishRtmp = null;
+ $mergePublishRtmp['enable'] = true;
+ $resp = $client->updateApp('dgdl5ge8y', $hub, $title, $maxUsers, $mergePublishRtmp);
+ print_r($resp);
+ //删除app
+ $resp = $client->deleteApp('dgdl5ge8y');
+ print_r($resp);
+ //获取房间连麦的成员
+ $resp=$client->listUser("dgbfvvzid", 'lfxl');
+ print_r($resp);
+ //剔除房间的连麦成员
+ $resp=$client->kickUser("dgbfvvzid", 'lfx', "qiniu-f6e07b78-4dc8-45fb-a701-a9e158abb8e6");
+ print_r($resp);
+ // 列举房间
+ $resp=$client->listActiveRooms("dgbfvvzid", 'lfx', null, null);
+ print_r($resp);
+ //鉴权的有效时间: 1个小时.
+ $resp = $client->appToken("dgd4vecde", "lfxl", '1111', (time()+3600), 'user');
+ print_r($resp);
+} catch (\Exception $e) {
+ echo "Error:", $e, "\n";
+}
diff --git a/app/Common/extend/qiniu/examples/README.md b/app/Common/extend/qiniu/examples/README.md
new file mode 100755
index 0000000..6cf8e30
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/README.md
@@ -0,0 +1,10 @@
+# examples
+
+这些 examples 旨在帮助你快速了解使用七牛的sdk。这些demo都是可以直接运行的, 但是在运行之前需要填上您自己的参数。
+
+比如:
+
+* `$bucket` 需要填上您想操作的 [bucket名字](http://developer.qiniu.com/docs/v6/api/overview/concepts.html#bucket)。
+* `$accessKey` 和 `$secretKey` 可以在我们的[管理后台](https://portal.qiniu.com/setting/key)找到。
+* 在进行`视频转码`, `压缩文件`等异步操作时 需要使用到的队列名称也可以在我们[管理后台](https://portal.qiniu.com/mps/pipeline)新建。
+
diff --git a/app/Common/extend/qiniu/examples/cdn_get_bandwidth.php b/app/Common/extend/qiniu/examples/cdn_get_bandwidth.php
new file mode 100755
index 0000000..4d2ccf6
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/cdn_get_bandwidth.php
@@ -0,0 +1,40 @@
+getBandwidthData(
+ $domains,
+ $startDate,
+ $endDate,
+ $granularity
+);
+
+if ($getBandwidthErr != null) {
+ var_dump($getBandwidthErr);
+} else {
+ echo "get bandwidth data success\n";
+ print_r($bandwidthData);
+}
diff --git a/app/Common/extend/qiniu/examples/cdn_get_flux.php b/app/Common/extend/qiniu/examples/cdn_get_flux.php
new file mode 100755
index 0000000..56da550
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/cdn_get_flux.php
@@ -0,0 +1,34 @@
+getFluxData($domains, $startDate, $endDate, $granularity);
+if ($getFluxErr != null) {
+ var_dump($getFluxErr);
+} else {
+ echo "get flux data success\n";
+ print_r($fluxData);
+}
diff --git a/app/Common/extend/qiniu/examples/cdn_get_log_list.php b/app/Common/extend/qiniu/examples/cdn_get_log_list.php
new file mode 100755
index 0000000..4e5c942
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/cdn_get_log_list.php
@@ -0,0 +1,29 @@
+getCdnLogList($domains, $logDate);
+if ($getLogErr != null) {
+ var_dump($getLogErr);
+} else {
+ echo "get cdn log list success\n";
+ print_r($logListData);
+}
diff --git a/app/Common/extend/qiniu/examples/cdn_refresh_urls_dirs.php b/app/Common/extend/qiniu/examples/cdn_refresh_urls_dirs.php
new file mode 100755
index 0000000..c05e75f
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/cdn_refresh_urls_dirs.php
@@ -0,0 +1,52 @@
+refreshUrlsAndDirs($urls, $dirs);
+if ($refreshErr != null) {
+ var_dump($refreshErr);
+} else {
+ echo "refresh request sent\n";
+ print_r($refreshResult);
+}
+
+//如果只有刷新链接或者目录的需求,可以分布使用
+
+list($refreshResult, $refreshErr) = $cdnManager->refreshUrls($urls);
+if ($refreshErr != null) {
+ var_dump($refreshErr);
+} else {
+ echo "refresh request sent\n";
+ print_r($refreshResult);
+}
+
+list($refreshResult, $refreshErr) = $cdnManager->refreshDirs($dirs);
+if ($refreshErr != null) {
+ var_dump($refreshErr);
+} else {
+ echo "refresh request sent\n";
+ print_r($refreshResult);
+}
diff --git a/app/Common/extend/qiniu/examples/cdn_timestamp_antileech.php b/app/Common/extend/qiniu/examples/cdn_timestamp_antileech.php
new file mode 100755
index 0000000..d9fd023
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/cdn_timestamp_antileech.php
@@ -0,0 +1,19 @@
+
+ */
+$thumbLink = $imageUrlBuilder->thumbnail($url, 1, 100, 100);
+
+// 函数方式调用 也可拼接多个操作参数 图片+水印
+$thumbLink2 = \Qiniu\thumbnail($url2, 1, 100, 100);
+var_dump($thumbLink, $thumbLink2);
+
+/**
+ * 图片水印
+ *
+ * @param string $url 图片链接
+ * @param string $image 水印图片链接
+ * @param numeric $dissolve 透明度 [可选]
+ * @param string $gravity 水印位置 [可选]
+ * @param numeric $dx 横轴边距 [可选]
+ * @param numeric $dy 纵轴边距 [可选]
+ * @param numeric $watermarkScale 自适应原图的短边比例 [可选]
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html
+ * @return string
+ * @author Sherlock Ren
+ */
+$waterLink = $imageUrlBuilder->waterImg($url, $waterImage);
+// 函数调用方法
+//$waterLink = \Qiniu\waterImg($url, $waterImage);
+var_dump($waterLink);
+
+/**
+ * 文字水印
+ *
+ * @param string $url 图片链接
+ * @param string $text 文字
+ * @param string $font 文字字体
+ * @param string $fontSize 文字字号
+ * @param string $fontColor 文字颜色 [可选]
+ * @param numeric $dissolve 透明度 [可选]
+ * @param string $gravity 水印位置 [可选]
+ * @param numeric $dx 横轴边距 [可选]
+ * @param numeric $dy 纵轴边距 [可选]
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark
+ * @return string
+ * @author Sherlock Ren
+ */
+$textLink = $imageUrlBuilder->waterText($url, '你瞅啥', '微软雅黑', 300);
+// 函数调用方法
+// $textLink = \Qiniu\waterText($url, '你瞅啥', '微软雅黑', 300);
+var_dump($textLink);
diff --git a/app/Common/extend/qiniu/examples/persistent_fop_init.php b/app/Common/extend/qiniu/examples/persistent_fop_init.php
new file mode 100755
index 0000000..2df01e9
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/persistent_fop_init.php
@@ -0,0 +1,19 @@
+status($persistentId);
+
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/pfop_mkzip.php b/app/Common/extend/qiniu/examples/pfop_mkzip.php
new file mode 100755
index 0000000..746b356
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/pfop_mkzip.php
@@ -0,0 +1,43 @@
+execute($bucket, $key, $fops, $pipeline, $notify_url, $force);
+
+echo "\n====> pfop mkzip result: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ echo "PersistentFop Id: $id\n";
+
+ $res = "http://api.qiniu.com/status/get/prefop?id=$id";
+ echo "Processing result: $res";
+}
diff --git a/app/Common/extend/qiniu/examples/pfop_vframe.php b/app/Common/extend/qiniu/examples/pfop_vframe.php
new file mode 100755
index 0000000..e1df2d5
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/pfop_vframe.php
@@ -0,0 +1,46 @@
+useHTTPS = true;
+$pfop = new PersistentFop($auth, $config);
+
+//要进行视频截图操作
+$fops = "vframe/jpg/offset/1/w/480/h/360/rotate/90|saveas/" .
+ \Qiniu\base64_urlSafeEncode($bucket . ":qiniu_480x360.jpg");
+
+list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force);
+echo "\n====> pfop avthumb result: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ echo "PersistentFop Id: $id\n";
+}
+
+//查询转码的进度和状态
+list($ret, $err) = $pfop->status($id);
+echo "\n====> pfop avthumb status: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/pfop_video_avthumb.php b/app/Common/extend/qiniu/examples/pfop_video_avthumb.php
new file mode 100755
index 0000000..aebe815
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/pfop_video_avthumb.php
@@ -0,0 +1,47 @@
+useHTTPS=true;
+
+$pfop = new PersistentFop($auth, $config);
+
+//要进行转码的转码操作。 http://developer.qiniu.com/docs/v6/api/reference/fop/av/avthumb.html
+$fops = "avthumb/mp4/s/640x360/vb/1.4m|saveas/" . \Qiniu\base64_urlSafeEncode($bucket . ":qiniu_640x360.mp4");
+
+list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force);
+echo "\n====> pfop avthumb result: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ echo "PersistentFop Id: $id\n";
+}
+
+//查询转码的进度和状态
+list($ret, $err) = $pfop->status($id);
+echo "\n====> pfop avthumb status: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/pfop_watermark.php b/app/Common/extend/qiniu/examples/pfop_watermark.php
new file mode 100755
index 0000000..72aa6c4
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/pfop_watermark.php
@@ -0,0 +1,52 @@
+useHTTPS=true;
+$pfop = new PersistentFop($auth, $config);
+
+//需要添加水印的图片UrlSafeBase64
+//可以参考http://developer.qiniu.com/code/v6/api/dora-api/av/video-watermark.html
+$base64URL = Qiniu\base64_urlSafeEncode('http://devtools.qiniu.com/qiniu.png');
+
+//水印参数
+$fops = "avthumb/mp4/s/640x360/vb/1.4m/image/" . $base64URL . "|saveas/"
+ . \Qiniu\base64_urlSafeEncode($bucket . ":qiniu_wm.mp4");
+
+list($id, $err) = $pfop->execute($bucket, $key, $fops, $pipeline, $notifyUrl, $force);
+echo "\n====> pfop avthumb result: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ echo "PersistentFop Id: $id\n";
+}
+
+//查询转码的进度和状态
+list($ret, $err) = $pfop->status($id);
+echo "\n====> pfop avthumb status: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/php-logo.png b/app/Common/extend/qiniu/examples/php-logo.png
new file mode 100755
index 0000000..77e051f
Binary files /dev/null and b/app/Common/extend/qiniu/examples/php-logo.png differ
diff --git a/app/Common/extend/qiniu/examples/prefop.php b/app/Common/extend/qiniu/examples/prefop.php
new file mode 100755
index 0000000..ae61a5f
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/prefop.php
@@ -0,0 +1,29 @@
+status($id);
+echo "\n====> pfop avthumb status: \n";
+if ($err != null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/pulpvideo.php b/app/Common/extend/qiniu/examples/pulpvideo.php
new file mode 100755
index 0000000..bad8821
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/pulpvideo.php
@@ -0,0 +1,55 @@
+ 'pulp',
+ 'params' => array(
+ 'labels' => array(
+ array(
+ 'label' => "1",
+ 'select' => 1,
+ 'score' => 2,
+ ),
+ )
+ )
+ ),
+);
+
+$params = array();
+$params = array(
+ 'async' => false,
+ 'vframe' => array(
+ 'mode' => 1,
+ 'interval' => 8,
+ )
+);
+
+$req = array();
+$req['data'] = $reqBody;
+$req['ops'] = $ops;
+$req['params'] = $params;
+$body = json_encode($req);
+
+$vid = "xxxx";
+list($ret, $err) = $argusManager->pulpVideo($body, $vid);
+
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/qetag.php b/app/Common/extend/qiniu/examples/qetag.php
new file mode 100755
index 0000000..f6aff8a
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/qetag.php
@@ -0,0 +1,11 @@
+ 'video/x-mp4',
+ 'qiniu.png' => 'image/x-png',
+ 'qiniu.jpg' => 'image/x-jpg'
+);
+
+$ops = $bucketManager->buildBatchChangeMime($bucket, $keyMimePairs);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_batch_change_type.php b/app/Common/extend/qiniu/examples/rs_batch_change_type.php
new file mode 100755
index 0000000..5f3f1cd
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_batch_change_type.php
@@ -0,0 +1,34 @@
+buildBatchChangeType($bucket, $keyTypePairs);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_batch_copy.php b/app/Common/extend/qiniu/examples/rs_batch_copy.php
new file mode 100755
index 0000000..988c642
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_batch_copy.php
@@ -0,0 +1,36 @@
+buildBatchCopy($srcBucket, $keyPairs, $destBucket, true);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_batch_delete.php b/app/Common/extend/qiniu/examples/rs_batch_delete.php
new file mode 100755
index 0000000..4f15586
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_batch_delete.php
@@ -0,0 +1,28 @@
+buildBatchDelete($bucket, $keys);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_batch_delete_after_days.php b/app/Common/extend/qiniu/examples/rs_batch_delete_after_days.php
new file mode 100755
index 0000000..dabfe84
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_batch_delete_after_days.php
@@ -0,0 +1,34 @@
+buildBatchDeleteAfterDays($bucket, $keyDayPairs);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_batch_move.php b/app/Common/extend/qiniu/examples/rs_batch_move.php
new file mode 100755
index 0000000..8922522
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_batch_move.php
@@ -0,0 +1,36 @@
+buildBatchMove($srcBucket, $keyPairs, $destBucket, true);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_batch_stat.php b/app/Common/extend/qiniu/examples/rs_batch_stat.php
new file mode 100755
index 0000000..a95fee7
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_batch_stat.php
@@ -0,0 +1,28 @@
+buildBatchStat($bucket, $keys);
+list($ret, $err) = $bucketManager->batch($ops);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_bucket_domains.php b/app/Common/extend/qiniu/examples/rs_bucket_domains.php
new file mode 100755
index 0000000..ea27cdc
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_bucket_domains.php
@@ -0,0 +1,19 @@
+domains($bucket);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($domains);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_buckets.php b/app/Common/extend/qiniu/examples/rs_buckets.php
new file mode 100755
index 0000000..5fe1304
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_buckets.php
@@ -0,0 +1,19 @@
+buckets(true);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($buckets);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_change_mime.php b/app/Common/extend/qiniu/examples/rs_change_mime.php
new file mode 100755
index 0000000..0d3f3ad
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_change_mime.php
@@ -0,0 +1,20 @@
+changeMime($bucket, $key, $newMime);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_change_status.php b/app/Common/extend/qiniu/examples/rs_change_status.php
new file mode 100755
index 0000000..cbcea5c
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_change_status.php
@@ -0,0 +1,20 @@
+changeStatus($bucket, $key, $status);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_change_type.php b/app/Common/extend/qiniu/examples/rs_change_type.php
new file mode 100755
index 0000000..acb8963
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_change_type.php
@@ -0,0 +1,20 @@
+changeType($bucket, $key, $fileType);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_copy.php b/app/Common/extend/qiniu/examples/rs_copy.php
new file mode 100755
index 0000000..10e7de8
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_copy.php
@@ -0,0 +1,22 @@
+copy($srcBucket, $srcKey, $destBucket, $destKey, true);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_delete.php b/app/Common/extend/qiniu/examples/rs_delete.php
new file mode 100755
index 0000000..365d3be
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_delete.php
@@ -0,0 +1,17 @@
+delete($bucket, $key);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_delete_after_days.php b/app/Common/extend/qiniu/examples/rs_delete_after_days.php
new file mode 100755
index 0000000..ba0b586
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_delete_after_days.php
@@ -0,0 +1,20 @@
+deleteAfterDays($bucket, $key, $days);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_download_urls.php b/app/Common/extend/qiniu/examples/rs_download_urls.php
new file mode 100755
index 0000000..522b9f2
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_download_urls.php
@@ -0,0 +1,17 @@
+/
+$baseUrl = 'http://if-pri.qiniudn.com/qiniu.png?imageView2/1/h/500';
+// 对链接进行签名
+$signedUrl = $auth->privateDownloadUrl($baseUrl);
+
+echo $signedUrl;
diff --git a/app/Common/extend/qiniu/examples/rs_fetch.php b/app/Common/extend/qiniu/examples/rs_fetch.php
new file mode 100755
index 0000000..6792410
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_fetch.php
@@ -0,0 +1,34 @@
+fetch($url, $bucket, $key);
+echo "=====> fetch $url to bucket: $bucket key: $key\n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ print_r($ret);
+}
+
+// 不指定key时,以文件内容的hash作为文件名
+$key = null;
+list($ret, $err) = $bucketManager->fetch($url, $bucket, $key);
+echo "=====> fetch $url to bucket: $bucket key: $(etag)\n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ print_r($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_move.php b/app/Common/extend/qiniu/examples/rs_move.php
new file mode 100755
index 0000000..5610585
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_move.php
@@ -0,0 +1,22 @@
+move($srcBucket, $srcKey, $destBucket, $destKey, true);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_prefetch.php b/app/Common/extend/qiniu/examples/rs_prefetch.php
new file mode 100755
index 0000000..de947a7
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_prefetch.php
@@ -0,0 +1,17 @@
+prefetch($bucket, $key);
+if ($err) {
+ print_r($err);
+}
diff --git a/app/Common/extend/qiniu/examples/rs_stat.php b/app/Common/extend/qiniu/examples/rs_stat.php
new file mode 100755
index 0000000..891e4e0
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rs_stat.php
@@ -0,0 +1,19 @@
+stat($bucket, $key);
+if ($err) {
+ print_r($err);
+} else {
+ print_r($fileInfo);
+}
diff --git a/app/Common/extend/qiniu/examples/rsf_list_bucket.php b/app/Common/extend/qiniu/examples/rsf_list_bucket.php
new file mode 100755
index 0000000..5ce9a62
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rsf_list_bucket.php
@@ -0,0 +1,46 @@
+listFiles($bucket, $prefix, $marker, $limit, $delimiter);
+ if ($err !== null) {
+ echo "\n====> list file err: \n";
+ var_dump($err);
+ } else {
+ $marker = null;
+ if (array_key_exists('marker', $ret)) {
+ $marker = $ret['marker'];
+ }
+ echo "Marker: $marker\n";
+ echo "\nList Items====>\n";
+ //var_dump($ret['items']);
+ print('items count:' . count($ret['items']) . "\n");
+ if (array_key_exists('commonPrefixes', $ret)) {
+ print_r($ret['commonPrefixes']);
+ }
+ }
+} while (!empty($marker));
diff --git a/app/Common/extend/qiniu/examples/rsf_list_files.php b/app/Common/extend/qiniu/examples/rsf_list_files.php
new file mode 100755
index 0000000..a3981c5
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/rsf_list_files.php
@@ -0,0 +1,38 @@
+listFiles($bucket, $prefix, $marker, $limit, $delimiter);
+if ($err !== null) {
+ echo "\n====> list file err: \n";
+ var_dump($err);
+} else {
+ if (array_key_exists('marker', $ret)) {
+ echo "Marker:" . $ret["marker"] . "\n";
+ }
+ echo "\nList Iterms====>\n";
+ //var_dump($ret['items']);
+}
diff --git a/app/Common/extend/qiniu/examples/saveas.php b/app/Common/extend/qiniu/examples/saveas.php
new file mode 100755
index 0000000..d896f3b
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/saveas.php
@@ -0,0 +1,28 @@
+:';//为生成缩略图的文件名
+//生成的值
+$encodedEntryURI = \Qiniu\base64_urlSafeEncode($entry);
+
+//使用SecretKey对新的下载URL进行HMAC1-SHA1签名
+$newurl = "78re52.com1.z0.glb.clouddn.com/resource/Ship.jpg?imageView2/2/w/200/h/200|saveas/" . $encodedEntryURI;
+
+$sign = hash_hmac("sha1", $newurl, $secretKey, true);
+
+//对签名进行URL安全的Base64编码
+$encodedSign = \Qiniu\base64_urlSafeEncode($sign);
+//最终得到的完整下载URL
+$finalURL = "http://" . $newurl . "/sign/" . $accessKey . ":" . $encodedSign;
+
+$callbackBody = file_get_contents("$finalURL");
+
+echo $callbackBody;
diff --git a/app/Common/extend/qiniu/examples/upload_and_callback.php b/app/Common/extend/qiniu/examples/upload_and_callback.php
new file mode 100755
index 0000000..4762bd3
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_and_callback.php
@@ -0,0 +1,40 @@
+ 'http://your.domain.com/upload_verify_callback.php',
+ 'callbackBody' => 'filename=$(fname)&filesize=$(fsize)'
+);
+$uptoken = $auth->uploadToken($bucket, null, 3600, $policy);
+
+//上传文件的本地路径
+$filePath = './php-logo.png';
+
+//指定 config
+// $uploadMgr = new UploadManager($config);
+$uploadMgr = new UploadManager();
+
+list($ret, $err) = $uploadMgr->putFile($uptoken, null, $filePath);
+echo "\n====> putFile result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/upload_and_pfop.php b/app/Common/extend/qiniu/examples/upload_and_pfop.php
new file mode 100755
index 0000000..898c09c
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_and_pfop.php
@@ -0,0 +1,38 @@
+ $pfop,
+ 'persistentNotifyUrl' => $notifyUrl,
+ 'persistentPipeline' => $pipeline
+);
+$token = $auth->uploadToken($bucket, null, 3600, $policy);
+
+list($ret, $err) = $uploadMgr->putFile($token, null, $key);
+echo "\n====> putFile result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/upload_mgr_init.php b/app/Common/extend/qiniu/examples/upload_mgr_init.php
new file mode 100755
index 0000000..3459ef1
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_mgr_init.php
@@ -0,0 +1,18 @@
+uploadToken($bucket);
+
+// 构建 UploadManager 对象
+$uploadMgr = new UploadManager();
diff --git a/app/Common/extend/qiniu/examples/upload_multi_demos.php b/app/Common/extend/qiniu/examples/upload_multi_demos.php
new file mode 100755
index 0000000..3bbcd60
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_multi_demos.php
@@ -0,0 +1,85 @@
+uploadToken($bucket);
+$uploadMgr = new UploadManager();
+
+//----------------------------------------upload demo1 ----------------------------------------
+// 上传字符串到七牛
+list($ret, $err) = $uploadMgr->put($token, null, 'content string');
+echo "\n====> put result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
+
+
+//----------------------------------------upload demo2 ----------------------------------------
+// 上传文件到七牛
+$filePath = './php-logo.png';
+$key = 'php-logo.png';
+list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath);
+echo "\n====> putFile result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
+
+
+//----------------------------------------upload demo3 ----------------------------------------
+// 上传文件到七牛后, 七牛将文件名和文件大小回调给业务服务器.
+// 可参考文档: http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html
+$policy = array(
+ 'callbackUrl' => 'http://172.30.251.210/upload_verify_callback.php',
+ 'callbackBody' => 'filename=$(fname)&filesize=$(fsize)'
+// 'callbackBodyType' => 'application/json',
+// 'callbackBody' => '{"filename":$(fname), "filesize": $(fsize)}' //设置application/json格式回调
+);
+$token = $auth->uploadToken($bucket, null, 3600, $policy);
+
+
+list($ret, $err) = $uploadMgr->putFile($token, null, $key);
+echo "\n====> putFile result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
+
+
+//----------------------------------------upload demo4 ----------------------------------------
+//上传视频,上传完成后进行m3u8的转码, 并给视频打水印
+$wmImg = Qiniu\base64_urlSafeEncode('http://devtools.qiniudn.com/qiniu.png');
+$pfop = "avthumb/m3u8/wmImage/$wmImg";
+
+//转码完成后回调到业务服务器。(公网可以访问,并相应200 OK)
+$notifyUrl = 'http://notify.fake.com';
+
+//独立的转码队列:https://portal.qiniu.com/mps/pipeline
+
+
+$policy = array(
+ 'persistentOps' => $pfop,
+ 'persistentNotifyUrl' => $notifyUrl,
+ 'persistentPipeline' => $pipeline
+);
+$token = $auth->uploadToken($bucket, null, 3600, $policy);
+print($token);
+list($ret, $err) = $uploadMgr->putFile($token, null, $key);
+echo "\n====> putFile result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/upload_simple_file.php b/app/Common/extend/qiniu/examples/upload_simple_file.php
new file mode 100755
index 0000000..9d003f0
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_simple_file.php
@@ -0,0 +1,37 @@
+uploadToken($bucket);
+
+// 要上传文件的本地路径
+$filePath = './php-logo.png';
+
+// 上传到七牛后保存的文件名
+$key = 'my-php-logo.png';
+
+// 初始化 UploadManager 对象并进行文件的上传。
+$uploadMgr = new UploadManager();
+
+// 调用 UploadManager 的 putFile 方法进行文件的上传。
+list($ret, $err) = $uploadMgr->putFile($token, $key, $filePath);
+echo "\n====> putFile result: \n";
+if ($err !== null) {
+ var_dump($err);
+} else {
+ var_dump($ret);
+}
diff --git a/app/Common/extend/qiniu/examples/upload_tokens.php b/app/Common/extend/qiniu/examples/upload_tokens.php
new file mode 100755
index 0000000..90f2423
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_tokens.php
@@ -0,0 +1,68 @@
+uploadToken($bucket, null, $expires, $policy, true);
+print($upToken . "\n");
+
+// 自定义凭证有效期(示例2小时)
+$expires = 7200;
+$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true);
+print($upToken . "\n");
+
+// 覆盖上传凭证
+$expires = 3600;
+$keyToOverwrite = 'qiniu.mp4';
+$upToken = $auth->uploadToken($bucket, $keyToOverwrite, $expires, $policy, true);
+print($upToken . "\n");
+
+//自定义上传回复(非callback模式)凭证
+$returnBody = '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}';
+$policy = array(
+ 'returnBody' => $returnBody
+);
+$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true);
+print($upToken . "\n");
+
+//带回调业务服务器的凭证(application/json)
+$policy = array(
+ 'callbackUrl' => 'http://api.example.com/qiniu/upload/callback',
+ 'callbackBody' => '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}',
+ 'callbackBodyType' => 'application/json'
+);
+$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true);
+print($upToken . "\n");
+
+
+//带回调业务服务器的凭证(application/x-www-form-urlencoded)
+$policy = array(
+ 'callbackUrl' => 'http://api.example.com/qiniu/upload/callback',
+ 'callbackBody' => 'key=$(key)&hash=$(etag)&bucket=$(bucket)&fsize=$(fsize)&name=$(x:name)'
+);
+$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true);
+print($upToken . "\n");
+
+//带数据处理的凭证
+$saveMp4Entry = \Qiniu\base64_urlSafeEncode($bucket . ":avthumb_test_target.mp4");
+$saveJpgEntry = \Qiniu\base64_urlSafeEncode($bucket . ":vframe_test_target.jpg");
+$avthumbMp4Fop = "avthumb/mp4|saveas/" . $saveMp4Entry;
+$vframeJpgFop = "vframe/jpg/offset/1|saveas/" . $saveJpgEntry;
+$policy = array(
+ 'persistentOps' => $avthumbMp4Fop . ";" . $vframeJpgFop,
+ 'persistentPipeline' => "video-pipe",
+ 'persistentNotifyUrl' => "http://api.example.com/qiniu/pfop/notify",
+);
+$upToken = $auth->uploadToken($bucket, null, $expires, $policy, true);
+print($upToken . "\n");
diff --git a/app/Common/extend/qiniu/examples/upload_verify_callback.php b/app/Common/extend/qiniu/examples/upload_verify_callback.php
new file mode 100755
index 0000000..ffbbc80
--- /dev/null
+++ b/app/Common/extend/qiniu/examples/upload_verify_callback.php
@@ -0,0 +1,32 @@
+verifyCallback($contentType, $authorization, $url, $callbackBody);
+
+if ($isQiniuCallback) {
+ $resp = array('ret' => 'success');
+} else {
+ $resp = array('ret' => 'failed');
+}
+
+echo json_encode($resp);
diff --git a/app/Common/extend/qiniu/phpunit.xml.dist b/app/Common/extend/qiniu/phpunit.xml.dist
new file mode 100755
index 0000000..72ff67f
--- /dev/null
+++ b/app/Common/extend/qiniu/phpunit.xml.dist
@@ -0,0 +1,19 @@
+
+
+
+
+ tests
+
+
+
+
diff --git a/app/Common/extend/qiniu/src/Qiniu/Auth.php b/app/Common/extend/qiniu/src/Qiniu/Auth.php
new file mode 100755
index 0000000..b5e4a6b
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Auth.php
@@ -0,0 +1,187 @@
+accessKey = $accessKey;
+ $this->secretKey = $secretKey;
+ }
+
+ public function getAccessKey()
+ {
+ return $this->accessKey;
+ }
+
+ public function sign($data)
+ {
+ $hmac = hash_hmac('sha1', $data, $this->secretKey, true);
+ return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac);
+ }
+
+ public function signWithData($data)
+ {
+ $encodedData = \Qiniu\base64_urlSafeEncode($data);
+ return $this->sign($encodedData) . ':' . $encodedData;
+ }
+
+ public function signRequest($urlString, $body, $contentType = null)
+ {
+ $url = parse_url($urlString);
+ $data = '';
+ if (array_key_exists('path', $url)) {
+ $data = $url['path'];
+ }
+ if (array_key_exists('query', $url)) {
+ $data .= '?' . $url['query'];
+ }
+ $data .= "\n";
+
+ if ($body !== null && $contentType === 'application/x-www-form-urlencoded') {
+ $data .= $body;
+ }
+ return $this->sign($data);
+ }
+
+ public function verifyCallback($contentType, $originAuthorization, $url, $body)
+ {
+ $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
+ return $originAuthorization === $authorization;
+ }
+
+ public function privateDownloadUrl($baseUrl, $expires = 3600)
+ {
+ $deadline = time() + $expires;
+
+ $pos = strpos($baseUrl, '?');
+ if ($pos !== false) {
+ $baseUrl .= '&e=';
+ } else {
+ $baseUrl .= '?e=';
+ }
+ $baseUrl .= $deadline;
+
+ $token = $this->sign($baseUrl);
+ return "$baseUrl&token=$token";
+ }
+
+ public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true)
+ {
+ $deadline = time() + $expires;
+ $scope = $bucket;
+ if ($key !== null) {
+ $scope .= ':' . $key;
+ }
+
+ $args = self::copyPolicy($args, $policy, $strictPolicy);
+ $args['scope'] = $scope;
+ $args['deadline'] = $deadline;
+
+ $b = json_encode($args);
+ return $this->signWithData($b);
+ }
+
+ /**
+ *上传策略,参数规格详见
+ *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html
+ */
+ private static $policyFields = array(
+ 'callbackUrl',
+ 'callbackBody',
+ 'callbackHost',
+ 'callbackBodyType',
+ 'callbackFetchKey',
+
+ 'returnUrl',
+ 'returnBody',
+
+ 'endUser',
+ 'saveKey',
+ 'insertOnly',
+
+ 'detectMime',
+ 'mimeLimit',
+ 'fsizeMin',
+ 'fsizeLimit',
+
+ 'persistentOps',
+ 'persistentNotifyUrl',
+ 'persistentPipeline',
+
+ 'deleteAfterDays',
+ 'fileType',
+ 'isPrefixalScope',
+ );
+
+ private static function copyPolicy(&$policy, $originPolicy, $strictPolicy)
+ {
+ if ($originPolicy === null) {
+ return array();
+ }
+ foreach ($originPolicy as $key => $value) {
+ if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) {
+ $policy[$key] = $value;
+ }
+ }
+ return $policy;
+ }
+
+ public function authorization($url, $body = null, $contentType = null)
+ {
+ $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
+ return array('Authorization' => $authorization);
+ }
+
+ public function authorizationV2($url, $method, $body = null, $contentType = null)
+ {
+ $urlItems = parse_url($url);
+ $host = $urlItems['host'];
+
+ if (isset($urlItems['port'])) {
+ $port = $urlItems['port'];
+ } else {
+ $port = '';
+ }
+
+ $path = $urlItems['path'];
+ if (isset($urlItems['query'])) {
+ $query = $urlItems['query'];
+ } else {
+ $query = '';
+ }
+
+ //write request uri
+ $toSignStr = $method . ' ' . $path;
+ if (!empty($query)) {
+ $toSignStr .= '?' . $query;
+ }
+
+ //write host and port
+ $toSignStr .= "\nHost: " . $host;
+ if (!empty($port)) {
+ $toSignStr .= ":" . $port;
+ }
+
+ //write content type
+ if (!empty($contentType)) {
+ $toSignStr .= "\nContent-Type: " . $contentType;
+ }
+
+ $toSignStr .= "\n\n";
+
+ //write body
+ if (!empty($body)) {
+ $toSignStr .= $body;
+ }
+
+ $sign = $this->sign($toSignStr);
+ $auth = 'Qiniu ' . $sign;
+ return array('Authorization' => $auth);
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Cdn/CdnManager.php b/app/Common/extend/qiniu/src/Qiniu/Cdn/CdnManager.php
new file mode 100755
index 0000000..0e6abac
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Cdn/CdnManager.php
@@ -0,0 +1,191 @@
+auth = $auth;
+ $this->server = 'http://fusion.qiniuapi.com';
+ }
+
+ /**
+ * @param array $urls 待刷新的文件链接数组
+ * @return array
+ */
+ public function refreshUrls(array $urls)
+ {
+ return $this->refreshUrlsAndDirs($urls, array());
+ }
+
+ /**
+ * @param array $dirs 待刷新的文件链接数组
+ * @return array
+ * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh
+ * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category
+ */
+ public function refreshDirs(array $dirs)
+ {
+ return $this->refreshUrlsAndDirs(array(), $dirs);
+ }
+
+ /**
+ * @param array $urls 待刷新的文件链接数组
+ * @param array $dirs 待刷新的目录链接数组
+ *
+ * @return array 刷新的请求回复和错误,参考 examples/cdn_manager.php 代码
+ * @link http://developer.qiniu.com/article/fusion/api/refresh.html
+ *
+ * 目前客户默认没有目录刷新权限,刷新会有400038报错,参考:https://developer.qiniu.com/fusion/api/1229/cache-refresh
+ * 需要刷新目录请工单联系技术支持 https://support.qiniu.com/tickets/category
+ */
+ public function refreshUrlsAndDirs(array $urls, array $dirs)
+ {
+ $req = array();
+ if (!empty($urls)) {
+ $req['urls'] = $urls;
+ }
+ if (!empty($dirs)) {
+ $req['dirs'] = $dirs;
+ }
+
+ $url = $this->server . '/v2/tune/refresh';
+ $body = json_encode($req);
+ return $this->post($url, $body);
+ }
+
+ /**
+ * @param array $urls 待预取的文件链接数组
+ *
+ * @return array 预取的请求回复和错误,参考 examples/cdn_manager.php 代码
+ *
+ * @link http://developer.qiniu.com/article/fusion/api/refresh.html
+ */
+ public function prefetchUrls(array $urls)
+ {
+ $req = array(
+ 'urls' => $urls,
+ );
+
+ $url = $this->server . '/v2/tune/prefetch';
+ $body = json_encode($req);
+ return $this->post($url, $body);
+ }
+
+ /**
+ * @param array $domains 待获取带宽数据的域名数组
+ * @param string $startDate 开始的日期,格式类似 2017-01-01
+ * @param string $endDate 结束的日期,格式类似 2017-01-01
+ * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day
+ *
+ * @return array 带宽数据和错误信息,参考 examples/cdn_manager.php 代码
+ *
+ * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html
+ */
+ public function getBandwidthData(array $domains, $startDate, $endDate, $granularity)
+ {
+ $req = array();
+ $req['domains'] = implode(';', $domains);
+ $req['startDate'] = $startDate;
+ $req['endDate'] = $endDate;
+ $req['granularity'] = $granularity;
+
+ $url = $this->server . '/v2/tune/bandwidth';
+ $body = json_encode($req);
+ return $this->post($url, $body);
+ }
+
+ /**
+ * @param array $domains 待获取流量数据的域名数组
+ * @param string $startDate 开始的日期,格式类似 2017-01-01
+ * @param string $endDate 结束的日期,格式类似 2017-01-01
+ * @param string $granularity 获取数据的时间间隔,可以是 5min, hour 或者 day
+ *
+ * @return array 流量数据和错误信息,参考 examples/cdn_manager.php 代码
+ *
+ * @link http://developer.qiniu.com/article/fusion/api/traffic-bandwidth.html
+ */
+ public function getFluxData(array $domains, $startDate, $endDate, $granularity)
+ {
+ $req = array();
+ $req['domains'] = implode(';', $domains);
+ $req['startDate'] = $startDate;
+ $req['endDate'] = $endDate;
+ $req['granularity'] = $granularity;
+
+ $url = $this->server . '/v2/tune/flux';
+ $body = json_encode($req);
+ return $this->post($url, $body);
+ }
+
+ /**
+ * @param array $domains 待获取日志下载链接的域名数组
+ * @param string $logDate 获取指定日期的日志下载链接,格式类似 2017-01-01
+ *
+ * @return array 日志下载链接数据和错误信息,参考 examples/cdn_manager.php 代码
+ *
+ * @link http://developer.qiniu.com/article/fusion/api/log.html
+ */
+ public function getCdnLogList(array $domains, $logDate)
+ {
+ $req = array();
+ $req['domains'] = implode(';', $domains);
+ $req['day'] = $logDate;
+
+ $url = $this->server . '/v2/tune/log/list';
+ $body = json_encode($req);
+ return $this->post($url, $body);
+ }
+
+ private function post($url, $body)
+ {
+ $headers = $this->auth->authorization($url, $body, 'application/json');
+ $headers['Content-Type'] = 'application/json';
+ $ret = Client::post($url, $body, $headers);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ $r = ($ret->body === null) ? array() : $ret->json();
+ return array($r, null);
+ }
+
+ /**
+ * 构建时间戳防盗链鉴权的访问外链
+ *
+ * @param string $rawUrl 需要签名的资源url
+ * @param string $encryptKey 时间戳防盗链密钥
+ * @param string $durationInSeconds 链接的有效期(以秒为单位)
+ *
+ * @return string 带鉴权信息的资源外链,参考 examples/cdn_timestamp_antileech.php 代码
+ */
+ public static function createTimestampAntiLeechUrl($rawUrl, $encryptKey, $durationInSeconds)
+ {
+
+ $parsedUrl = parse_url($rawUrl);
+
+ $deadline = time() + $durationInSeconds;
+ $expireHex = dechex($deadline);
+ $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
+ $path = implode('/', array_map('rawurlencode', explode('/', $path)));
+
+ $strToSign = $encryptKey . $path . $expireHex;
+ $signStr = md5($strToSign);
+
+ if (isset($parsedUrl['query'])) {
+ $signedUrl = $rawUrl . '&sign=' . $signStr . '&t=' . $expireHex;
+ } else {
+ $signedUrl = $rawUrl . '?sign=' . $signStr . '&t=' . $expireHex;
+ }
+
+ return $signedUrl;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Config.php b/app/Common/extend/qiniu/src/Qiniu/Config.php
new file mode 100755
index 0000000..b1f6367
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Config.php
@@ -0,0 +1,137 @@
+zone = $z;
+ $this->useHTTPS = false;
+ $this->useCdnDomains = false;
+ $this->zoneCache = array();
+ }
+
+ public function getUpHost($accessKey, $bucket)
+ {
+ $zone = $this->getZone($accessKey, $bucket);
+ if ($this->useHTTPS === true) {
+ $scheme = "https://";
+ } else {
+ $scheme = "http://";
+ }
+
+ $host = $zone->srcUpHosts[0];
+ if ($this->useCdnDomains === true) {
+ $host = $zone->cdnUpHosts[0];
+ }
+
+ return $scheme . $host;
+ }
+
+ public function getUpBackupHost($accessKey, $bucket)
+ {
+ $zone = $this->getZone($accessKey, $bucket);
+ if ($this->useHTTPS === true) {
+ $scheme = "https://";
+ } else {
+ $scheme = "http://";
+ }
+
+ $host = $zone->cdnUpHosts[0];
+ if ($this->useCdnDomains === true) {
+ $host = $zone->srcUpHosts[0];
+ }
+
+ return $scheme . $host;
+ }
+
+ public function getRsHost($accessKey, $bucket)
+ {
+ $zone = $this->getZone($accessKey, $bucket);
+
+ if ($this->useHTTPS === true) {
+ $scheme = "https://";
+ } else {
+ $scheme = "http://";
+ }
+
+ return $scheme . $zone->rsHost;
+ }
+
+ public function getRsfHost($accessKey, $bucket)
+ {
+ $zone = $this->getZone($accessKey, $bucket);
+
+ if ($this->useHTTPS === true) {
+ $scheme = "https://";
+ } else {
+ $scheme = "http://";
+ }
+
+ return $scheme . $zone->rsfHost;
+ }
+
+ public function getIovipHost($accessKey, $bucket)
+ {
+ $zone = $this->getZone($accessKey, $bucket);
+
+ if ($this->useHTTPS === true) {
+ $scheme = "https://";
+ } else {
+ $scheme = "http://";
+ }
+
+ return $scheme . $zone->iovipHost;
+ }
+
+ public function getApiHost($accessKey, $bucket)
+ {
+ $zone = $this->getZone($accessKey, $bucket);
+
+ if ($this->useHTTPS === true) {
+ $scheme = "https://";
+ } else {
+ $scheme = "http://";
+ }
+
+ return $scheme . $zone->apiHost;
+ }
+
+ private function getZone($accessKey, $bucket)
+ {
+ $cacheId = "$accessKey:$bucket";
+
+ if (isset($this->zoneCache[$cacheId])) {
+ $zone = $this->zoneCache[$cacheId];
+ } elseif (isset($this->zone)) {
+ $zone = $this->zone;
+ $this->zoneCache[$cacheId] = $zone;
+ } else {
+ $zone = Zone::queryZone($accessKey, $bucket);
+ $this->zoneCache[$cacheId] = $zone;
+ }
+ return $zone;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Etag.php b/app/Common/extend/qiniu/src/Qiniu/Etag.php
new file mode 100755
index 0000000..d7be064
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Etag.php
@@ -0,0 +1,76 @@
+ $val) {
+ array_push($data, '--' . $mimeBoundary);
+ array_push($data, "Content-Disposition: form-data; name=\"$key\"");
+ array_push($data, '');
+ array_push($data, $val);
+ }
+
+ array_push($data, '--' . $mimeBoundary);
+ $finalMimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType;
+ $finalFileName = self::escapeQuotes($fileName);
+ array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$finalFileName\"");
+ array_push($data, "Content-Type: $finalMimeType");
+ array_push($data, '');
+ array_push($data, $fileBody);
+
+ array_push($data, '--' . $mimeBoundary . '--');
+ array_push($data, '');
+
+ $body = implode("\r\n", $data);
+ $contentType = 'multipart/form-data; boundary=' . $mimeBoundary;
+ $headers['Content-Type'] = $contentType;
+ $request = new Request('POST', $url, $headers, $body);
+ return self::sendRequest($request);
+ }
+
+ private static function userAgent()
+ {
+ $sdkInfo = "QiniuPHP/" . Config::SDK_VER;
+
+ $systemInfo = php_uname("s");
+ $machineInfo = php_uname("m");
+
+ $envInfo = "($systemInfo/$machineInfo)";
+
+ $phpVer = phpversion();
+
+ $ua = "$sdkInfo $envInfo PHP/$phpVer";
+ return $ua;
+ }
+
+ public static function sendRequest($request)
+ {
+ $t1 = microtime(true);
+ $ch = curl_init();
+ $options = array(
+ CURLOPT_USERAGENT => self::userAgent(),
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_SSL_VERIFYHOST => false,
+ CURLOPT_HEADER => true,
+ CURLOPT_NOBODY => false,
+ CURLOPT_CUSTOMREQUEST => $request->method,
+ CURLOPT_URL => $request->url,
+ );
+
+ // Handle open_basedir & safe mode
+ if (!ini_get('safe_mode') && !ini_get('open_basedir')) {
+ $options[CURLOPT_FOLLOWLOCATION] = true;
+ }
+
+ if (!empty($request->headers)) {
+ $headers = array();
+ foreach ($request->headers as $key => $val) {
+ array_push($headers, "$key: $val");
+ }
+ $options[CURLOPT_HTTPHEADER] = $headers;
+ }
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
+
+ if (!empty($request->body)) {
+ $options[CURLOPT_POSTFIELDS] = $request->body;
+ }
+ curl_setopt_array($ch, $options);
+ $result = curl_exec($ch);
+ $t2 = microtime(true);
+ $duration = round($t2 - $t1, 3);
+ $ret = curl_errno($ch);
+ if ($ret !== 0) {
+ $r = new Response(-1, $duration, array(), null, curl_error($ch));
+ curl_close($ch);
+ return $r;
+ }
+ $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
+ $headers = self::parseHeaders(substr($result, 0, $header_size));
+ $body = substr($result, $header_size);
+ curl_close($ch);
+ return new Response($code, $duration, $headers, $body, null);
+ }
+
+ private static function parseHeaders($raw)
+ {
+ $headers = array();
+ $headerLines = explode("\r\n", $raw);
+ foreach ($headerLines as $line) {
+ $headerLine = trim($line);
+ $kv = explode(':', $headerLine);
+ if (count($kv) > 1) {
+ $kv[0] =self::ucwordsHyphen($kv[0]);
+ $headers[$kv[0]] = trim($kv[1]);
+ }
+ }
+ return $headers;
+ }
+
+ private static function escapeQuotes($str)
+ {
+ $find = array("\\", "\"");
+ $replace = array("\\\\", "\\\"");
+ return str_replace($find, $replace, $str);
+ }
+
+ private static function ucwordsHyphen($str)
+ {
+ return str_replace('- ', '-', ucwords(str_replace('-', '- ', $str)));
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Http/Error.php b/app/Common/extend/qiniu/src/Qiniu/Http/Error.php
new file mode 100755
index 0000000..73477cf
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Http/Error.php
@@ -0,0 +1,35 @@
+
+ * {"error" : "detailed error message"}
+ *
+ */
+final class Error
+{
+ private $url;
+ private $response;
+
+ public function __construct($url, $response)
+ {
+ $this->url = $url;
+ $this->response = $response;
+ }
+
+ public function code()
+ {
+ return $this->response->statusCode;
+ }
+
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ public function message()
+ {
+ return $this->response->error;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Http/Request.php b/app/Common/extend/qiniu/src/Qiniu/Http/Request.php
new file mode 100755
index 0000000..43b0bfd
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Http/Request.php
@@ -0,0 +1,18 @@
+method = strtoupper($method);
+ $this->url = $url;
+ $this->headers = $headers;
+ $this->body = $body;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Http/Response.php b/app/Common/extend/qiniu/src/Qiniu/Http/Response.php
new file mode 100755
index 0000000..f22ab37
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Http/Response.php
@@ -0,0 +1,176 @@
+ 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status',
+ 208 => 'Already Reported',
+ 226 => 'IM Used',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+ 308 => 'Permanent Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Reserved for WebDAV advanced collections expired proposal',
+ 426 => 'Upgrade required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 506 => 'Variant Also Negotiates (Experimental)',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 510 => 'Not Extended',
+ 511 => 'Network Authentication Required',
+ );
+
+ /**
+ * @param int $code 状态码
+ * @param double $duration 请求时长
+ * @param array $headers 响应头部
+ * @param string $body 响应内容
+ * @param string $error 错误描述
+ */
+ public function __construct($code, $duration, array $headers = array(), $body = null, $error = null)
+ {
+ $this->statusCode = $code;
+ $this->duration = $duration;
+ $this->headers = $headers;
+ $this->body = $body;
+ $this->error = $error;
+ $this->jsonData = null;
+ if ($error !== null) {
+ return;
+ }
+
+ if ($body === null) {
+ if ($code >= 400) {
+ $this->error = self::$statusTexts[$code];
+ }
+ return;
+ }
+ if (self::isJson($headers)) {
+ try {
+ $jsonData = self::bodyJson($body);
+ if ($code >= 400) {
+ $this->error = $body;
+ if ($jsonData['error'] !== null) {
+ $this->error = $jsonData['error'];
+ }
+ }
+ $this->jsonData = $jsonData;
+ } catch (\InvalidArgumentException $e) {
+ $this->error = $body;
+ if ($code >= 200 && $code < 300) {
+ $this->error = $e->getMessage();
+ }
+ }
+ } elseif ($code >= 400) {
+ $this->error = $body;
+ }
+ return;
+ }
+
+ public function json()
+ {
+ return $this->jsonData;
+ }
+
+ private static function bodyJson($body)
+ {
+ return \Qiniu\json_decode((string) $body, true, 512);
+ }
+
+ public function xVia()
+ {
+ $via = $this->headers['X-Via'];
+ if ($via === null) {
+ $via = $this->headers['X-Px'];
+ }
+ if ($via === null) {
+ $via = $this->headers['Fw-Via'];
+ }
+ return $via;
+ }
+
+ public function xLog()
+ {
+ return $this->headers['X-Log'];
+ }
+
+ public function xReqId()
+ {
+ return $this->headers['X-Reqid'];
+ }
+
+ public function ok()
+ {
+ return $this->statusCode >= 200 && $this->statusCode < 300 && $this->error === null;
+ }
+
+ public function needRetry()
+ {
+ $code = $this->statusCode;
+ if ($code < 0 || ($code / 100 === 5 and $code !== 579) || $code === 996) {
+ return true;
+ }
+ }
+
+ private static function isJson($headers)
+ {
+ return array_key_exists('Content-Type', $headers) &&
+ strpos($headers['Content-Type'], 'application/json') === 0;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Processing/ImageUrlBuilder.php b/app/Common/extend/qiniu/src/Qiniu/Processing/ImageUrlBuilder.php
new file mode 100755
index 0000000..1ac5bf7
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Processing/ImageUrlBuilder.php
@@ -0,0 +1,282 @@
+
+ */
+ public function thumbnail(
+ $url,
+ $mode,
+ $width,
+ $height,
+ $format = null,
+ $interlace = null,
+ $quality = null,
+ $ignoreError = 1
+ ) {
+
+ // url合法效验
+ if (!$this->isUrl($url)) {
+ return $url;
+ }
+
+ // 参数合法性效验
+ if (!in_array(intval($mode), $this->modeArr, true)) {
+ return $url;
+ }
+
+ if (!$width || !$height) {
+ return $url;
+ }
+
+ $thumbStr = 'imageView2/' . $mode . '/w/' . $width . '/h/' . $height . '/';
+
+ // 拼接输出格式
+ if (!is_null($format)
+ && in_array($format, $this->formatArr)
+ ) {
+ $thumbStr .= 'format/' . $format . '/';
+ }
+
+ // 拼接渐进显示
+ if (!is_null($interlace)
+ && in_array(intval($interlace), array(0, 1), true)
+ ) {
+ $thumbStr .= 'interlace/' . $interlace . '/';
+ }
+
+ // 拼接图片质量
+ if (!is_null($quality)
+ && intval($quality) >= 0
+ && intval($quality) <= 100
+ ) {
+ $thumbStr .= 'q/' . $quality . '/';
+ }
+
+ $thumbStr .= 'ignore-error/' . $ignoreError . '/';
+
+ // 如果有query_string用|线分割实现多参数
+ return $url . ($this->hasQuery($url) ? '|' : '?') . $thumbStr;
+ }
+
+ /**
+ * 图片水印
+ *
+ * @param string $url 图片链接
+ * @param string $image 水印图片链接
+ * @param numeric $dissolve 透明度
+ * @param string $gravity 水印位置
+ * @param numeric $dx 横轴边距
+ * @param numeric $dy 纵轴边距
+ * @param numeric $watermarkScale 自适应原图的短边比例
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html
+ * @return string
+ * @author Sherlock Ren
+ */
+ public function waterImg(
+ $url,
+ $image,
+ $dissolve = 100,
+ $gravity = 'SouthEast',
+ $dx = null,
+ $dy = null,
+ $watermarkScale = null
+ ) {
+ // url合法效验
+ if (!$this->isUrl($url)) {
+ return $url;
+ }
+
+ $waterStr = 'watermark/1/image/' . \Qiniu\base64_urlSafeEncode($image) . '/';
+
+ // 拼接水印透明度
+ if (is_numeric($dissolve)
+ && $dissolve <= 100
+ ) {
+ $waterStr .= 'dissolve/' . $dissolve . '/';
+ }
+
+ // 拼接水印位置
+ if (in_array($gravity, $this->gravityArr, true)) {
+ $waterStr .= 'gravity/' . $gravity . '/';
+ }
+
+ // 拼接横轴边距
+ if (!is_null($dx)
+ && is_numeric($dx)
+ ) {
+ $waterStr .= 'dx/' . $dx . '/';
+ }
+
+ // 拼接纵轴边距
+ if (!is_null($dy)
+ && is_numeric($dy)
+ ) {
+ $waterStr .= 'dy/' . $dy . '/';
+ }
+
+ // 拼接自适应原图的短边比例
+ if (!is_null($watermarkScale)
+ && is_numeric($watermarkScale)
+ && $watermarkScale > 0
+ && $watermarkScale < 1
+ ) {
+ $waterStr .= 'ws/' . $watermarkScale . '/';
+ }
+
+ // 如果有query_string用|线分割实现多参数
+ return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr;
+ }
+
+ /**
+ * 文字水印
+ *
+ * @param string $url 图片链接
+ * @param string $text 文字
+ * @param string $font 文字字体
+ * @param string $fontSize 文字字号
+ * @param string $fontColor 文字颜色
+ * @param numeric $dissolve 透明度
+ * @param string $gravity 水印位置
+ * @param numeric $dx 横轴边距
+ * @param numeric $dy 纵轴边距
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark
+ * @return string
+ * @author Sherlock Ren
+ */
+ public function waterText(
+ $url,
+ $text,
+ $font = '黑体',
+ $fontSize = 0,
+ $fontColor = null,
+ $dissolve = 100,
+ $gravity = 'SouthEast',
+ $dx = null,
+ $dy = null
+ ) {
+ // url合法效验
+ if (!$this->isUrl($url)) {
+ return $url;
+ }
+
+ $waterStr = 'watermark/2/text/'
+ . \Qiniu\base64_urlSafeEncode($text) . '/font/'
+ . \Qiniu\base64_urlSafeEncode($font) . '/';
+
+ // 拼接文字大小
+ if (is_int($fontSize)) {
+ $waterStr .= 'fontsize/' . $fontSize . '/';
+ }
+
+ // 拼接文字颜色
+ if (!is_null($fontColor)
+ && $fontColor
+ ) {
+ $waterStr .= 'fill/' . \Qiniu\base64_urlSafeEncode($fontColor) . '/';
+ }
+
+ // 拼接水印透明度
+ if (is_numeric($dissolve)
+ && $dissolve <= 100
+ ) {
+ $waterStr .= 'dissolve/' . $dissolve . '/';
+ }
+
+ // 拼接水印位置
+ if (in_array($gravity, $this->gravityArr, true)) {
+ $waterStr .= 'gravity/' . $gravity . '/';
+ }
+
+ // 拼接横轴边距
+ if (!is_null($dx)
+ && is_numeric($dx)
+ ) {
+ $waterStr .= 'dx/' . $dx . '/';
+ }
+
+ // 拼接纵轴边距
+ if (!is_null($dy)
+ && is_numeric($dy)
+ ) {
+ $waterStr .= 'dy/' . $dy . '/';
+ }
+
+ // 如果有query_string用|线分割实现多参数
+ return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr;
+ }
+
+ /**
+ * 效验url合法性
+ *
+ * @param string $url url链接
+ * @return string
+ * @author Sherlock Ren
+ */
+ protected function isUrl($url)
+ {
+ $urlArr = parse_url($url);
+
+ return $urlArr['scheme']
+ && in_array($urlArr['scheme'], array('http', 'https'))
+ && $urlArr['host']
+ && $urlArr['path'];
+ }
+
+ /**
+ * 检测是否有query
+ *
+ * @param string $url url链接
+ * @return string
+ * @author Sherlock Ren
+ */
+ protected function hasQuery($url)
+ {
+ $urlArr = parse_url($url);
+
+ return !empty($urlArr['query']);
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Processing/Operation.php b/app/Common/extend/qiniu/src/Qiniu/Processing/Operation.php
new file mode 100755
index 0000000..919136f
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Processing/Operation.php
@@ -0,0 +1,60 @@
+auth = $auth;
+ $this->domain = $domain;
+ $this->token_expire = $token_expire;
+ }
+
+
+ /**
+ * 对资源文件进行处理
+ *
+ * @param $key 待处理的资源文件名
+ * @param $fops string|array fop操作,多次fop操作以array的形式传入。
+ * eg. imageView2/1/w/200/h/200, imageMogr2/thumbnail/!75px
+ *
+ * @return array 文件处理后的结果及错误。
+ *
+ * @link http://developer.qiniu.com/docs/v6/api/reference/fop/
+ */
+ public function execute($key, $fops)
+ {
+ $url = $this->buildUrl($key, $fops);
+ $resp = Client::get($url);
+ if (!$resp->ok()) {
+ return array(null, new Error($url, $resp));
+ }
+ if ($resp->json() !== null) {
+ return array($resp->json(), null);
+ }
+ return array($resp->body, null);
+ }
+
+ public function buildUrl($key, $fops, $protocol = 'http')
+ {
+ if (is_array($fops)) {
+ $fops = implode('|', $fops);
+ }
+
+ $url = $protocol . "://$this->domain/$key?$fops";
+ if ($this->auth !== null) {
+ $url = $this->auth->privateDownloadUrl($url, $this->token_expire);
+ }
+
+ return $url;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Processing/PersistentFop.php b/app/Common/extend/qiniu/src/Qiniu/Processing/PersistentFop.php
new file mode 100755
index 0000000..24e7b73
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Processing/PersistentFop.php
@@ -0,0 +1,94 @@
+auth = $auth;
+ if ($config == null) {
+ $this->config = new Config();
+ } else {
+ $this->config = $config;
+ }
+ }
+
+ /**
+ * 对资源文件进行异步持久化处理
+ * @param $bucket 资源所在空间
+ * @param $key 待处理的源文件
+ * @param $fops string|array 待处理的pfop操作,多个pfop操作以array的形式传入。
+ * eg. avthumb/mp3/ab/192k, vframe/jpg/offset/7/w/480/h/360
+ * @param $pipeline 资源处理队列
+ * @param $notify_url 处理结果通知地址
+ * @param $force 是否强制执行一次新的指令
+ *
+ *
+ * @return array 返回持久化处理的persistentId, 和返回的错误。
+ *
+ * @link http://developer.qiniu.com/docs/v6/api/reference/fop/
+ */
+ public function execute($bucket, $key, $fops, $pipeline = null, $notify_url = null, $force = false)
+ {
+ if (is_array($fops)) {
+ $fops = implode(';', $fops);
+ }
+ $params = array('bucket' => $bucket, 'key' => $key, 'fops' => $fops);
+ \Qiniu\setWithoutEmpty($params, 'pipeline', $pipeline);
+ \Qiniu\setWithoutEmpty($params, 'notifyURL', $notify_url);
+ if ($force) {
+ $params['force'] = 1;
+ }
+ $data = http_build_query($params);
+ $scheme = "http://";
+ if ($this->config->useHTTPS === true) {
+ $scheme = "https://";
+ }
+ $url = $scheme . Config::API_HOST . '/pfop/';
+ $headers = $this->auth->authorization($url, $data, 'application/x-www-form-urlencoded');
+ $headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ $response = Client::post($url, $data, $headers);
+ if (!$response->ok()) {
+ return array(null, new Error($url, $response));
+ }
+ $r = $response->json();
+ $id = $r['persistentId'];
+ return array($id, null);
+ }
+
+ public function status($id)
+ {
+ $scheme = "http://";
+
+ if ($this->config->useHTTPS === true) {
+ $scheme = "https://";
+ }
+ $url = $scheme . Config::API_HOST . "/status/get/prefop?id=$id";
+ $response = Client::get($url);
+ if (!$response->ok()) {
+ return array(null, new Error($url, $response));
+ }
+ return array($response->json(), null);
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Rtc/AppClient.php b/app/Common/extend/qiniu/src/Qiniu/Rtc/AppClient.php
new file mode 100755
index 0000000..c07ee72
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Rtc/AppClient.php
@@ -0,0 +1,204 @@
+auth = $auth;
+
+ $this->baseURL = sprintf("%s/%s/apps", Config::RTCAPI_HOST, Config::RTCAPI_VERSION);
+ }
+
+ /*
+ * hub: 直播空间名
+ * title: app 的名称 注意,Title 不是唯一标识,重复 create 动作将生成多个 app
+ * maxUsers:人数限制
+ * NoAutoKickUser: bool 类型,可选,禁止自动踢人(抢流)。默认为 false ,
+ 即同一个身份的 client (app/room/user) ,新的连麦请求可以成功,旧连接被关闭。
+ */
+ public function createApp($hub, $title, $maxUsers = null, $noAutoKickUser = null)
+ {
+ $params['hub'] = $hub;
+ $params['title'] = $title;
+ if (!empty($maxUsers)) {
+ $params['maxUsers'] = $maxUsers;
+ }
+ if (!empty($noAutoKickUser)) {
+ $params['noAutoKickUser'] = $noAutoKickUser;
+ }
+ $body = json_encode($params);
+ $ret = $this->post($this->baseURL, $body);
+ return $ret;
+ }
+
+ /*
+ * appId: app 的唯一标识,创建的时候由系统生成。
+ * Title: app 的名称, 可选。
+ * Hub: 绑定的直播 hub,可选,用于合流后 rtmp 推流。
+ * MaxUsers: int 类型,可选,连麦房间支持的最大在线人数。
+ * NoAutoKickUser: bool 类型,可选,禁止自动踢人。
+ * MergePublishRtmp: 连麦合流转推 RTMP 的配置,可选择。其详细配置包括如下
+ Enable: 布尔类型,用于开启和关闭所有房间的合流功能。
+ AudioOnly: 布尔类型,可选,指定是否只合成音频。
+ Height, Width: int64,可选,指定合流输出的高和宽,默认为 640 x 480。
+ OutputFps: int64,可选,指定合流输出的帧率,默认为 25 fps 。
+ OutputKbps: int64,可选,指定合流输出的码率,默认为 1000 。
+ URL: 合流后转推旁路直播的地址,可选,支持魔法变量配置按照连麦房间号生成不同的推流地址。如果是转推到七牛直播云,不建议使用该配置。
+ StreamTitle: 转推七牛直播云的流名,可选,支持魔法变量配置按照连麦房间号生成不同的流名。例如,配置 Hub 为 qn-zhibo ,配置 StreamTitle 为 $(roomName) ,则房间 meeting-001 的合流将会被转推到 rtmp://pili-publish.qn-zhibo.***.com/qn-zhibo/meeting-001地址。详细配置细则,请咨询七牛技术支持。
+ */
+ public function updateApp($appId, $hub, $title, $maxUsers = null, $mergePublishRtmp = null, $noAutoKickUser = null)
+ {
+ $url = $this->baseURL . '/' . $appId;
+ $params['hub'] = $hub;
+ $params['title'] = $title;
+ if (!empty($maxUsers)) {
+ $params['maxUsers'] = $maxUsers;
+ }
+ if (!empty($noAutoKickUser)) {
+ $params['noAutoKickUser'] = $noAutoKickUser;
+ }
+ if (!empty($mergePublishRtmp)) {
+ $params['mergePublishRtmp'] = $mergePublishRtmp;
+ }
+ $body = json_encode($params);
+ $ret = $this->post($url, $body);
+ return $ret;
+ }
+
+ /*
+ * appId: app 的唯一标识,创建的时候由系统生成。
+ */
+ public function getApp($appId)
+ {
+ $url = $this->baseURL . '/' . $appId;
+ $ret = $this->get($url);
+ return $ret;
+ }
+
+ /*
+ * appId: app 的唯一标识,创建的时候由系统生成
+ */
+ public function deleteApp($appId)
+ {
+ $url = $this->baseURL . '/' . $appId;
+ list(, $err) = $this->delete($url);
+ return $err;
+ }
+
+ /*
+ * 获取房间的人数
+ * appId: app 的唯一标识,创建的时候由系统生成。
+ * roomName: 操作所查询的连麦房间。
+ */
+ public function listUser($appId, $roomName)
+ {
+ $url = sprintf("%s/%s/rooms/%s/users", $this->baseURL, $appId, $roomName);
+ $ret = $this->get($url);
+ return $ret;
+ }
+
+ /*
+ * 踢出玩家
+ * appId: app 的唯一标识,创建的时候由系统生成。
+ * roomName: 连麦房间
+ * userId: 请求加入房间的用户ID
+ */
+ public function kickUser($appId, $roomName, $userId)
+ {
+ $url = sprintf("%s/%s/rooms/%s/users/%s", $this->baseURL, $appId, $roomName, $userId);
+ list(, $err) = $this->delete($url);
+ return $err;
+ }
+
+ /*
+ * 获取房间的人数
+ * appId: app 的唯一标识,创建的时候由系统生成。
+ * prefix: 所查询房间名的前缀索引,可以为空。
+ * offset: int 类型,分页查询的位移标记。
+ * limit: int 类型,此次查询的最大长度。
+ * GET /v3/apps//rooms?prefix=&offset=&limit=
+ */
+ public function listActiveRooms($appId, $prefix = null, $offset = null, $limit = null)
+ {
+ if (isset($prefix)) {
+ $query['prefix'] = $prefix;
+ }
+ if (isset($offset)) {
+ $query['offset'] = $offset;
+ }
+ if (isset($limit)) {
+ $query['limit'] = $limit;
+ }
+ if (isset($query) && !empty($query)) {
+ $query = '?' . http_build_query($query);
+ $url = sprintf("%s/%s/rooms%s", $this->baseURL, $appId, $query);
+ } else {
+ $url = sprintf("%s/%s/rooms", $this->baseURL, $appId);
+ }
+ $ret = $this->get($url);
+ return $ret;
+ }
+
+ /*
+ * appId: app 的唯一标识,创建的时候由系统生成。
+ * roomName: 房间名称,需满足规格 ^[a-zA-Z0-9_-]{3,64}$
+ * userId: 请求加入房间的用户 ID,需满足规格 ^[a-zA-Z0-9_-]{3,50}$
+ * expireAt: int64 类型,鉴权的有效时间,传入以秒为单位的64位Unix
+ 绝对时间,token 将在该时间后失效。
+ * permission: 该用户的房间管理权限,"admin" 或 "user",默认为 "user" 。
+ 当权限角色为 "admin" 时,拥有将其他用户移除出房间等特权.
+ */
+ public function appToken($appId, $roomName, $userId, $expireAt, $permission)
+ {
+ $params['appId'] = $appId;
+ $params['userId'] = $userId;
+ $params['roomName'] = $roomName;
+ $params['permission'] = $permission;
+ $params['expireAt'] = $expireAt;
+ $appAccessString = json_encode($params);
+ return $this->auth->signWithData($appAccessString);
+ }
+
+ private function get($url, $cType = null)
+ {
+ $rtcToken = $this->auth->authorizationV2($url, "GET", null, $cType);
+ $rtcToken['Content-Type'] = $cType;
+ $ret = Client::get($url, $rtcToken);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ return array($ret->json(), null);
+ }
+
+ private function delete($url, $contentType = 'application/json')
+ {
+ $rtcToken = $this->auth->authorizationV2($url, "DELETE", null, $contentType);
+ $rtcToken['Content-Type'] = $contentType;
+ $ret = Client::delete($url, $rtcToken);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ return array($ret->json(), null);
+ }
+
+ private function post($url, $body, $contentType = 'application/json')
+ {
+ $rtcToken = $this->auth->authorizationV2($url, "POST", $body, $contentType);
+ $rtcToken['Content-Type'] = $contentType;
+ $ret = Client::post($url, $body, $rtcToken);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ $r = ($ret->body === null) ? array() : $ret->json();
+ return array($r, null);
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Storage/ArgusManager.php b/app/Common/extend/qiniu/src/Qiniu/Storage/ArgusManager.php
new file mode 100755
index 0000000..0889370
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Storage/ArgusManager.php
@@ -0,0 +1,73 @@
+auth = $auth;
+ if ($config == null) {
+ $this->config = new Config();
+ } else {
+ $this->config = $config;
+ }
+ }
+
+ /**
+ * 视频鉴黄
+ *
+ * @param $body body信息
+ * @param $vid videoID
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link https://developer.qiniu.com/dora/manual/4258/video-pulp
+ */
+ public function pulpVideo($body, $vid)
+ {
+ $path = '/v1/video/' . $vid;
+
+ return $this->arPost($path, $body);
+ }
+
+ private function getArHost()
+ {
+ $scheme = "http://";
+ if ($this->config->useHTTPS == true) {
+ $scheme = "https://";
+ }
+ return $scheme . Config::ARGUS_HOST;
+ }
+
+ private function arPost($path, $body = null)
+ {
+ $url = $this->getArHost() . $path;
+ return $this->post($url, $body);
+ }
+
+ private function post($url, $body)
+ {
+ $headers = $this->auth->authorizationV2($url, 'POST', $body, 'application/json');
+ $headers['Content-Type']='application/json';
+ $ret = Client::post($url, $body, $headers);
+ if (!$ret->ok()) {
+ print($ret->statusCode);
+ return array(null, new Error($url, $ret));
+ }
+ $r = ($ret->body === null) ? array() : $ret->json();
+ return array($r, null);
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Storage/BucketManager.php b/app/Common/extend/qiniu/src/Qiniu/Storage/BucketManager.php
new file mode 100755
index 0000000..2e82a14
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Storage/BucketManager.php
@@ -0,0 +1,492 @@
+auth = $auth;
+ if ($config == null) {
+ $this->config = new Config();
+ } else {
+ $this->config = $config;
+ }
+ }
+
+ /**
+ * 获取指定账号下所有的空间名。
+ *
+ * @return string[] 包含所有空间名
+ */
+ public function buckets($shared = true)
+ {
+ $includeShared = "false";
+ if ($shared === true) {
+ $includeShared = "true";
+ }
+ return $this->rsGet('/buckets?shared=' . $includeShared);
+ }
+
+ /**
+ * 获取指定空间绑定的所有的域名
+ *
+ * @return string[] 包含所有空间域名
+ */
+ public function domains($bucket)
+ {
+ return $this->apiGet('/v6/domain/list?tbl=' . $bucket);
+ }
+
+ /**
+ * 获取空间绑定的域名列表
+ * @return string[] 包含空间绑定的所有域名
+ */
+
+ /**
+ * 列取空间的文件列表
+ *
+ * @param $bucket 空间名
+ * @param $prefix 列举前缀
+ * @param $marker 列举标识符
+ * @param $limit 单次列举个数限制
+ * @param $delimiter 指定目录分隔符
+ *
+ * @return array 包含文件信息的数组,类似:[
+ * {
+ * "hash" => "",
+ * "key" => "",
+ * "fsize" => "",
+ * "putTime" => ""
+ * },
+ * ...
+ * ]
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/list.html
+ */
+ public function listFiles($bucket, $prefix = null, $marker = null, $limit = 1000, $delimiter = null)
+ {
+ $query = array('bucket' => $bucket);
+ \Qiniu\setWithoutEmpty($query, 'prefix', $prefix);
+ \Qiniu\setWithoutEmpty($query, 'marker', $marker);
+ \Qiniu\setWithoutEmpty($query, 'limit', $limit);
+ \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter);
+ $url = $this->getRsfHost() . '/list?' . http_build_query($query);
+ return $this->get($url);
+ }
+
+ /**
+ * 获取资源的元信息,但不返回文件内容
+ *
+ * @param $bucket 待获取信息资源所在的空间
+ * @param $key 待获取资源的文件名
+ *
+ * @return array 包含文件信息的数组,类似:
+ * [
+ * "hash" => "",
+ * "key" => "",
+ * "fsize" => ,
+ * "putTime" => ""
+ * "fileType" =>
+ * ]
+ *
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/stat.html
+ */
+ public function stat($bucket, $key)
+ {
+ $path = '/stat/' . \Qiniu\entry($bucket, $key);
+ return $this->rsGet($path);
+ }
+
+ /**
+ * 删除指定资源
+ *
+ * @param $bucket 待删除资源所在的空间
+ * @param $key 待删除资源的文件名
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/delete.html
+ */
+ public function delete($bucket, $key)
+ {
+ $path = '/delete/' . \Qiniu\entry($bucket, $key);
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+
+ /**
+ * 给资源进行重命名,本质为move操作。
+ *
+ * @param $bucket 待操作资源所在空间
+ * @param $oldname 待操作资源文件名
+ * @param $newname 目标资源文件名
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ */
+ public function rename($bucket, $oldname, $newname)
+ {
+ return $this->move($bucket, $oldname, $bucket, $newname);
+ }
+
+ /**
+ * 给资源进行重命名,本质为move操作。
+ *
+ * @param $from_bucket 待操作资源所在空间
+ * @param $from_key 待操作资源文件名
+ * @param $to_bucket 目标资源空间名
+ * @param $to_key 目标资源文件名
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/copy.html
+ */
+ public function copy($from_bucket, $from_key, $to_bucket, $to_key, $force = false)
+ {
+ $from = \Qiniu\entry($from_bucket, $from_key);
+ $to = \Qiniu\entry($to_bucket, $to_key);
+ $path = '/copy/' . $from . '/' . $to;
+ if ($force === true) {
+ $path .= '/force/true';
+ }
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+ /**
+ * 将资源从一个空间到另一个空间
+ *
+ * @param $from_bucket 待操作资源所在空间
+ * @param $from_key 待操作资源文件名
+ * @param $to_bucket 目标资源空间名
+ * @param $to_key 目标资源文件名
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/move.html
+ */
+ public function move($from_bucket, $from_key, $to_bucket, $to_key, $force = false)
+ {
+ $from = \Qiniu\entry($from_bucket, $from_key);
+ $to = \Qiniu\entry($to_bucket, $to_key);
+ $path = '/move/' . $from . '/' . $to;
+ if ($force) {
+ $path .= '/force/true';
+ }
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+ /**
+ * 主动修改指定资源的文件类型
+ *
+ * @param $bucket 待操作资源所在空间
+ * @param $key 待操作资源文件名
+ * @param $mime 待操作文件目标mimeType
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/chgm.html
+ */
+ public function changeMime($bucket, $key, $mime)
+ {
+ $resource = \Qiniu\entry($bucket, $key);
+ $encode_mime = \Qiniu\base64_urlSafeEncode($mime);
+ $path = '/chgm/' . $resource . '/mime/' . $encode_mime;
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+
+ /**
+ * 修改指定资源的存储类型
+ *
+ * @param $bucket 待操作资源所在空间
+ * @param $key 待操作资源文件名
+ * @param $fileType 待操作文件目标文件类型
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link https://developer.qiniu.com/kodo/api/3710/modify-the-file-type
+ */
+ public function changeType($bucket, $key, $fileType)
+ {
+ $resource = \Qiniu\entry($bucket, $key);
+ $path = '/chtype/' . $resource . '/type/' . $fileType;
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+ /**
+ * 修改文件的存储状态,即禁用状态和启用状态间的的互相转换
+ *
+ * @param $bucket 待操作资源所在空间
+ * @param $key 待操作资源文件名
+ * @param $status 待操作文件目标文件类型
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link https://developer.qiniu.com/kodo/api/4173/modify-the-file-status
+ */
+ public function changeStatus($bucket, $key, $status)
+ {
+ $resource = \Qiniu\entry($bucket, $key);
+ $path = '/chstatus/' . $resource . '/status/' . $status;
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+ /**
+ * 从指定URL抓取资源,并将该资源存储到指定空间中
+ *
+ * @param $url 指定的URL
+ * @param $bucket 目标资源空间
+ * @param $key 目标资源文件名
+ *
+ * @return array 包含已拉取的文件信息。
+ * 成功时: [
+ * [
+ * "hash" => "",
+ * "key" => ""
+ * ],
+ * null
+ * ]
+ *
+ * 失败时: [
+ * null,
+ * Qiniu/Http/Error
+ * ]
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/fetch.html
+ */
+ public function fetch($url, $bucket, $key = null)
+ {
+
+ $resource = \Qiniu\base64_urlSafeEncode($url);
+ $to = \Qiniu\entry($bucket, $key);
+ $path = '/fetch/' . $resource . '/to/' . $to;
+
+ $ak = $this->auth->getAccessKey();
+ $ioHost = $this->config->getIovipHost($ak, $bucket);
+
+ $url = $ioHost . $path;
+ return $this->post($url, null);
+ }
+
+ /**
+ * 从镜像源站抓取资源到空间中,如果空间中已经存在,则覆盖该资源
+ *
+ * @param $bucket 待获取资源所在的空间
+ * @param $key 代获取资源文件名
+ *
+ * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/prefetch.html
+ */
+ public function prefetch($bucket, $key)
+ {
+ $resource = \Qiniu\entry($bucket, $key);
+ $path = '/prefetch/' . $resource;
+
+ $ak = $this->auth->getAccessKey();
+ $ioHost = $this->config->getIovipHost($ak, $bucket);
+
+ $url = $ioHost . $path;
+ list(, $error) = $this->post($url, null);
+ return $error;
+ }
+
+ /**
+ * 在单次请求中进行多个资源管理操作
+ *
+ * @param $operations 资源管理操作数组
+ *
+ * @return array 每个资源的处理情况,结果类似:
+ * [
+ * { "code" => , "data" => },
+ * { "code" => },
+ * { "code" => },
+ * { "code" => },
+ * { "code" => , "data" => { "error": "" } },
+ * ...
+ * ]
+ * @link http://developer.qiniu.com/docs/v6/api/reference/rs/batch.html
+ */
+ public function batch($operations)
+ {
+ $params = 'op=' . implode('&op=', $operations);
+ return $this->rsPost('/batch', $params);
+ }
+
+ /**
+ * 设置文件的生命周期
+ *
+ * @param $bucket 设置文件生命周期文件所在的空间
+ * @param $key 设置文件生命周期文件的文件名
+ * @param $days 设置该文件多少天后删除,当$days设置为0时表示取消该文件的生命周期
+ *
+ * @return Mixed
+ * @link https://developer.qiniu.com/kodo/api/update-file-lifecycle
+ */
+ public function deleteAfterDays($bucket, $key, $days)
+ {
+ $entry = \Qiniu\entry($bucket, $key);
+ $path = "/deleteAfterDays/$entry/$days";
+ list(, $error) = $this->rsPost($path);
+ return $error;
+ }
+
+ private function getRsfHost()
+ {
+ $scheme = "http://";
+ if ($this->config->useHTTPS == true) {
+ $scheme = "https://";
+ }
+ return $scheme . Config::RSF_HOST;
+ }
+
+ private function getRsHost()
+ {
+ $scheme = "http://";
+ if ($this->config->useHTTPS == true) {
+ $scheme = "https://";
+ }
+ return $scheme . Config::RS_HOST;
+ }
+
+ private function getApiHost()
+ {
+ $scheme = "http://";
+ if ($this->config->useHTTPS == true) {
+ $scheme = "https://";
+ }
+ return $scheme . Config::API_HOST;
+ }
+
+ private function rsPost($path, $body = null)
+ {
+ $url = $this->getRsHost() . $path;
+ return $this->post($url, $body);
+ }
+
+ private function apiGet($path)
+ {
+ $url = $this->getApiHost() . $path;
+ return $this->get($url);
+ }
+
+ private function rsGet($path)
+ {
+ $url = $this->getRsHost() . $path;
+ return $this->get($url);
+ }
+
+ private function get($url)
+ {
+ $headers = $this->auth->authorization($url);
+ $ret = Client::get($url, $headers);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ return array($ret->json(), null);
+ }
+
+ private function post($url, $body)
+ {
+ $headers = $this->auth->authorization($url, $body, 'application/x-www-form-urlencoded');
+ $ret = Client::post($url, $body, $headers);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ $r = ($ret->body === null) ? array() : $ret->json();
+ return array($r, null);
+ }
+
+ public static function buildBatchCopy($source_bucket, $key_pairs, $target_bucket, $force)
+ {
+ return self::twoKeyBatch('/copy', $source_bucket, $key_pairs, $target_bucket, $force);
+ }
+
+
+ public static function buildBatchRename($bucket, $key_pairs, $force)
+ {
+ return self::buildBatchMove($bucket, $key_pairs, $bucket, $force);
+ }
+
+
+ public static function buildBatchMove($source_bucket, $key_pairs, $target_bucket, $force)
+ {
+ return self::twoKeyBatch('/move', $source_bucket, $key_pairs, $target_bucket, $force);
+ }
+
+
+ public static function buildBatchDelete($bucket, $keys)
+ {
+ return self::oneKeyBatch('/delete', $bucket, $keys);
+ }
+
+
+ public static function buildBatchStat($bucket, $keys)
+ {
+ return self::oneKeyBatch('/stat', $bucket, $keys);
+ }
+
+ public static function buildBatchDeleteAfterDays($bucket, $key_day_pairs)
+ {
+ $data = array();
+ foreach ($key_day_pairs as $key => $day) {
+ array_push($data, '/deleteAfterDays/' . \Qiniu\entry($bucket, $key) . '/' . $day);
+ }
+ return $data;
+ }
+
+ public static function buildBatchChangeMime($bucket, $key_mime_pairs)
+ {
+ $data = array();
+ foreach ($key_mime_pairs as $key => $mime) {
+ array_push($data, '/chgm/' . \Qiniu\entry($bucket, $key) . '/mime/' . base64_encode($mime));
+ }
+ return $data;
+ }
+
+ public static function buildBatchChangeType($bucket, $key_type_pairs)
+ {
+ $data = array();
+ foreach ($key_type_pairs as $key => $type) {
+ array_push($data, '/chtype/' . \Qiniu\entry($bucket, $key) . '/type/' . $type);
+ }
+ return $data;
+ }
+
+ private static function oneKeyBatch($operation, $bucket, $keys)
+ {
+ $data = array();
+ foreach ($keys as $key) {
+ array_push($data, $operation . '/' . \Qiniu\entry($bucket, $key));
+ }
+ return $data;
+ }
+
+ private static function twoKeyBatch($operation, $source_bucket, $key_pairs, $target_bucket, $force)
+ {
+ if ($target_bucket === null) {
+ $target_bucket = $source_bucket;
+ }
+ $data = array();
+ $forceOp = "false";
+ if ($force) {
+ $forceOp = "true";
+ }
+ foreach ($key_pairs as $from_key => $to_key) {
+ $from = \Qiniu\entry($source_bucket, $from_key);
+ $to = \Qiniu\entry($target_bucket, $to_key);
+ array_push($data, $operation . '/' . $from . '/' . $to . "/force/" . $forceOp);
+ }
+ return $data;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Storage/FormUploader.php b/app/Common/extend/qiniu/src/Qiniu/Storage/FormUploader.php
new file mode 100755
index 0000000..5c3361f
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Storage/FormUploader.php
@@ -0,0 +1,139 @@
+ "",
+ * "key" => ""
+ * ]
+ */
+ public static function put(
+ $upToken,
+ $key,
+ $data,
+ $config,
+ $params,
+ $mime,
+ $fname
+ ) {
+
+ $fields = array('token' => $upToken);
+ if ($key === null) {
+ $fname='nullkey';
+ } else {
+ $fields['key'] = $key;
+ }
+
+ //enable crc32 check by default
+ $fields['crc32'] = \Qiniu\crc32_data($data);
+
+ if ($params) {
+ foreach ($params as $k => $v) {
+ $fields[$k] = $v;
+ }
+ }
+
+ list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
+ if ($err != null) {
+ return array(null, $err);
+ }
+
+ $upHost = $config->getUpHost($accessKey, $bucket);
+
+ $response = Client::multipartPost($upHost, $fields, 'file', $fname, $data, $mime);
+ if (!$response->ok()) {
+ return array(null, new Error($upHost, $response));
+ }
+ return array($response->json(), null);
+ }
+
+ /**
+ * 上传文件到七牛,内部使用
+ *
+ * @param $upToken 上传凭证
+ * @param $key 上传文件名
+ * @param $filePath 上传文件的路径
+ * @param $config 上传配置
+ * @param $params 自定义变量,规格参考
+ * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
+ * @param $mime 上传数据的mimeType
+ *
+ * @return array 包含已上传文件的信息,类似:
+ * [
+ * "hash" => "",
+ * "key" => ""
+ * ]
+ */
+ public static function putFile(
+ $upToken,
+ $key,
+ $filePath,
+ $config,
+ $params,
+ $mime
+ ) {
+
+
+ $fields = array('token' => $upToken, 'file' => self::createFile($filePath, $mime));
+ if ($key !== null) {
+ $fields['key'] = $key;
+ }
+
+ $fields['crc32'] = \Qiniu\crc32_file($filePath);
+
+ if ($params) {
+ foreach ($params as $k => $v) {
+ $fields[$k] = $v;
+ }
+ }
+ $fields['key'] = $key;
+ $headers = array('Content-Type' => 'multipart/form-data');
+
+ list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
+ if ($err != null) {
+ return array(null, $err);
+ }
+
+ $upHost = $config->getUpHost($accessKey, $bucket);
+
+ $response = Client::post($upHost, $fields, $headers);
+ if (!$response->ok()) {
+ return array(null, new Error($upHost, $response));
+ }
+ return array($response->json(), null);
+ }
+
+ private static function createFile($filename, $mime)
+ {
+ // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax
+ // See: https://wiki.php.net/rfc/curl-file-upload
+ if (function_exists('curl_file_create')) {
+ return curl_file_create($filename, $mime);
+ }
+
+ // Use the old style if using an older version of PHP
+ $value = "@{$filename}";
+ if (!empty($mime)) {
+ $value .= ';type=' . $mime;
+ }
+
+ return $value;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Storage/ResumeUploader.php b/app/Common/extend/qiniu/src/Qiniu/Storage/ResumeUploader.php
new file mode 100755
index 0000000..5d8bf87
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Storage/ResumeUploader.php
@@ -0,0 +1,169 @@
+upToken = $upToken;
+ $this->key = $key;
+ $this->inputStream = $inputStream;
+ $this->size = $size;
+ $this->params = $params;
+ $this->mime = $mime;
+ $this->contexts = array();
+ $this->config = $config;
+
+ list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken);
+ if ($err != null) {
+ return array(null, $err);
+ }
+
+ $upHost = $config->getUpHost($accessKey, $bucket);
+ if ($err != null) {
+ throw new \Exception($err->message(), 1);
+ }
+ $this->host = $upHost;
+ }
+
+ /**
+ * 上传操作
+ */
+ public function upload($fname)
+ {
+ $uploaded = 0;
+ while ($uploaded < $this->size) {
+ $blockSize = $this->blockSize($uploaded);
+ $data = fread($this->inputStream, $blockSize);
+ if ($data === false) {
+ throw new \Exception("file read failed", 1);
+ }
+ $crc = \Qiniu\crc32_data($data);
+ $response = $this->makeBlock($data, $blockSize);
+ $ret = null;
+ if ($response->ok() && $response->json() != null) {
+ $ret = $response->json();
+ }
+ if ($response->statusCode < 0) {
+ list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($this->upToken);
+ if ($err != null) {
+ return array(null, $err);
+ }
+
+ $upHostBackup = $this->config->getUpBackupHost($accessKey, $bucket);
+ $this->host = $upHostBackup;
+ }
+ if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) {
+ $response = $this->makeBlock($data, $blockSize);
+ $ret = $response->json();
+ }
+
+ if (!$response->ok() || !isset($ret['crc32']) || $crc != $ret['crc32']) {
+ return array(null, new Error($this->currentUrl, $response));
+ }
+ array_push($this->contexts, $ret['ctx']);
+ $uploaded += $blockSize;
+ }
+ return $this->makeFile($fname);
+ }
+
+ /**
+ * 创建块
+ */
+ private function makeBlock($block, $blockSize)
+ {
+ $url = $this->host . '/mkblk/' . $blockSize;
+ return $this->post($url, $block);
+ }
+
+ private function fileUrl($fname)
+ {
+ $url = $this->host . '/mkfile/' . $this->size;
+ $url .= '/mimeType/' . \Qiniu\base64_urlSafeEncode($this->mime);
+ if ($this->key != null) {
+ $url .= '/key/' . \Qiniu\base64_urlSafeEncode($this->key);
+ }
+ $url .= '/fname/' . \Qiniu\base64_urlSafeEncode($fname);
+ if (!empty($this->params)) {
+ foreach ($this->params as $key => $value) {
+ $val = \Qiniu\base64_urlSafeEncode($value);
+ $url .= "/$key/$val";
+ }
+ }
+ return $url;
+ }
+
+ /**
+ * 创建文件
+ */
+ private function makeFile($fname)
+ {
+ $url = $this->fileUrl($fname);
+ $body = implode(',', $this->contexts);
+ $response = $this->post($url, $body);
+ if ($response->needRetry()) {
+ $response = $this->post($url, $body);
+ }
+ if (!$response->ok()) {
+ return array(null, new Error($this->currentUrl, $response));
+ }
+ return array($response->json(), null);
+ }
+
+ private function post($url, $data)
+ {
+ $this->currentUrl = $url;
+ $headers = array('Authorization' => 'UpToken ' . $this->upToken);
+ return Client::post($url, $data, $headers);
+ }
+
+ private function blockSize($uploaded)
+ {
+ if ($this->size < $uploaded + Config::BLOCK_SIZE) {
+ return $this->size - $uploaded;
+ }
+ return Config::BLOCK_SIZE;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Storage/UploadManager.php b/app/Common/extend/qiniu/src/Qiniu/Storage/UploadManager.php
new file mode 100755
index 0000000..209df11
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Storage/UploadManager.php
@@ -0,0 +1,144 @@
+config = $config;
+ }
+
+ /**
+ * 上传二进制流到七牛
+ *
+ * @param $upToken 上传凭证
+ * @param $key 上传文件名
+ * @param $data 上传二进制流
+ * @param $params 自定义变量,规格参考
+ * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
+ * @param $mime 上传数据的mimeType
+ * @param $checkCrc 是否校验crc32
+ *
+ * @return array 包含已上传文件的信息,类似:
+ * [
+ * "hash" => "",
+ * "key" => ""
+ * ]
+ */
+ public function put(
+ $upToken,
+ $key,
+ $data,
+ $params = null,
+ $mime = 'application/octet-stream',
+ $fname = null
+ ) {
+
+ $params = self::trimParams($params);
+ return FormUploader::put(
+ $upToken,
+ $key,
+ $data,
+ $this->config,
+ $params,
+ $mime,
+ $fname
+ );
+ }
+
+
+ /**
+ * 上传文件到七牛
+ *
+ * @param $upToken 上传凭证
+ * @param $key 上传文件名
+ * @param $filePath 上传文件的路径
+ * @param $params 自定义变量,规格参考
+ * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
+ * @param $mime 上传数据的mimeType
+ * @param $checkCrc 是否校验crc32
+ *
+ * @return array 包含已上传文件的信息,类似:
+ * [
+ * "hash" => "",
+ * "key" => ""
+ * ]
+ */
+ public function putFile(
+ $upToken,
+ $key,
+ $filePath,
+ $params = null,
+ $mime = 'application/octet-stream',
+ $checkCrc = false
+ ) {
+
+ $file = fopen($filePath, 'rb');
+ if ($file === false) {
+ throw new \Exception("file can not open", 1);
+ }
+ $params = self::trimParams($params);
+ $stat = fstat($file);
+ $size = $stat['size'];
+ if ($size <= Config::BLOCK_SIZE) {
+ $data = fread($file, $size);
+ fclose($file);
+ if ($data === false) {
+ throw new \Exception("file can not read", 1);
+ }
+ return FormUploader::put(
+ $upToken,
+ $key,
+ $data,
+ $this->config,
+ $params,
+ $mime,
+ basename($filePath)
+ );
+ }
+
+ $up = new ResumeUploader(
+ $upToken,
+ $key,
+ $file,
+ $size,
+ $params,
+ $mime,
+ $this->config
+ );
+ $ret = $up->upload(basename($filePath));
+ fclose($file);
+ return $ret;
+ }
+
+ public static function trimParams($params)
+ {
+ if ($params === null) {
+ return null;
+ }
+ $ret = array();
+ foreach ($params as $k => $v) {
+ $pos1 = strpos($k, 'x:');
+ $pos2 = strpos($k, 'x-qn-meta-');
+ if (($pos1 === 0 || $pos2 === 0) && !empty($v)) {
+ $ret[$k] = $v;
+ }
+ }
+ return $ret;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/Zone.php b/app/Common/extend/qiniu/src/Qiniu/Zone.php
new file mode 100755
index 0000000..9b142dc
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/Zone.php
@@ -0,0 +1,197 @@
+srcUpHosts = $srcUpHosts;
+ $this->cdnUpHosts = $cdnUpHosts;
+ $this->rsHost = $rsHost;
+ $this->rsfHost = $rsfHost;
+ $this->apiHost = $apiHost;
+ $this->iovipHost = $iovipHost;
+ }
+
+ //华东机房
+ public static function zone0()
+ {
+ $Zone_z0 = new Zone(
+ array("up.qiniup.com", 'up-jjh.qiniup.com', 'up-xs.qiniup.com'),
+ array('upload.qiniup.com', 'upload-jjh.qiniup.com', 'upload-xs.qiniup.com'),
+ 'rs.qbox.me',
+ 'rsf.qbox.me',
+ 'api.qiniu.com',
+ 'iovip.qbox.me'
+ );
+ return $Zone_z0;
+ }
+
+ //华东机房内网上传
+ public static function zoneZ0()
+ {
+ $Zone_z01 = new Zone(
+ array("free-qvm-z0-xs.qiniup.com"),
+ 'rs.qbox.me',
+ 'rsf.qbox.me',
+ 'api.qiniu.com',
+ 'iovip.qbox.me'
+ );
+ return $Zone_z01;
+ }
+
+ //华北机房内网上传
+ public static function zoneZ1()
+ {
+ $Zone_z12 = new Zone(
+ array("free-qvm-z1-zz.qiniup.com"),
+ "rs-z1.qbox.me",
+ "rsf-z1.qbox.me",
+ "api-z1.qiniu.com",
+ "iovip-z1.qbox.me"
+ );
+ return $Zone_z12;
+ }
+
+ //华北机房
+ public static function zone1()
+ {
+ $Zone_z1 = new Zone(
+ array('up-z1.qiniup.com'),
+ array('upload-z1.qiniup.com'),
+ "rs-z1.qbox.me",
+ "rsf-z1.qbox.me",
+ "api-z1.qiniu.com",
+ "iovip-z1.qbox.me"
+ );
+
+ return $Zone_z1;
+ }
+
+ //华南机房
+ public static function zone2()
+ {
+ $Zone_z2 = new Zone(
+ array('up-z2.qiniup.com', 'up-dg.qiniup.com', 'up-fs.qiniup.com'),
+ array('upload-z2.qiniup.com', 'upload-dg.qiniup.com', 'upload-fs.qiniup.com'),
+ "rs-z2.qbox.me",
+ "rsf-z2.qbox.me",
+ "api-z2.qiniu.com",
+ "iovip-z2.qbox.me"
+ );
+ return $Zone_z2;
+ }
+
+ //北美机房
+ public static function zoneNa0()
+ {
+ //北美机房
+ $Zone_na0 = new Zone(
+ array('up-na0.qiniup.com'),
+ array('upload-na0.qiniup.com'),
+ "rs-na0.qbox.me",
+ "rsf-na0.qbox.me",
+ "api-na0.qiniu.com",
+ "iovip-na0.qbox.me"
+ );
+ return $Zone_na0;
+ }
+
+ //新加坡机房
+ public static function zoneAs0()
+ {
+ //新加坡机房
+ $Zone_as0 = new Zone(
+ array('up-as0.qiniup.com'),
+ array('upload-as0.qiniup.com'),
+ "rs-as0.qbox.me",
+ "rsf-as0.qbox.me",
+ "api-as0.qiniu.com",
+ "iovip-as0.qbox.me"
+ );
+ return $Zone_as0;
+ }
+
+ /*
+ * GET /v2/query?ak=&&bucket=
+ **/
+ public static function queryZone($ak, $bucket)
+ {
+ $zone = new Zone();
+ $url = Config::UC_HOST . '/v2/query' . "?ak=$ak&bucket=$bucket";
+ $ret = Client::Get($url);
+ if (!$ret->ok()) {
+ return array(null, new Error($url, $ret));
+ }
+ $r = ($ret->body === null) ? array() : $ret->json();
+ //print_r($ret);
+ //parse zone;
+
+ $iovipHost = $r['io']['src']['main'][0];
+ $zone->iovipHost = $iovipHost;
+ $accMain = $r['up']['acc']['main'][0];
+ array_push($zone->cdnUpHosts, $accMain);
+ if (isset($r['up']['acc']['backup'])) {
+ foreach ($r['up']['acc']['backup'] as $key => $value) {
+ array_push($zone->cdnUpHosts, $value);
+ }
+ }
+ $srcMain = $r['up']['src']['main'][0];
+ array_push($zone->srcUpHosts, $srcMain);
+ if (isset($r['up']['src']['backup'])) {
+ foreach ($r['up']['src']['backup'] as $key => $value) {
+ array_push($zone->srcUpHosts, $value);
+ }
+ }
+
+ //set specific hosts
+ if (strstr($zone->iovipHost, "z1") !== false) {
+ $zone->rsHost = "rs-z1.qbox.me";
+ $zone->rsfHost = "rsf-z1.qbox.me";
+ $zone->apiHost = "api-z1.qiniu.com";
+ } elseif (strstr($zone->iovipHost, "z2") !== false) {
+ $zone->rsHost = "rs-z2.qbox.me";
+ $zone->rsfHost = "rsf-z2.qbox.me";
+ $zone->apiHost = "api-z2.qiniu.com";
+ } elseif (strstr($zone->iovipHost, "na0") !== false) {
+ $zone->rsHost = "rs-na0.qbox.me";
+ $zone->rsfHost = "rsf-na0.qbox.me";
+ $zone->apiHost = "api-na0.qiniu.com";
+ } elseif (strstr($zone->iovipHost, "as0") !== false) {
+ $zone->rsHost = "rs-as0.qbox.me";
+ $zone->rsfHost = "rsf-as0.qbox.me";
+ $zone->apiHost = "api-as0.qiniu.com";
+ } else {
+ $zone->rsHost = "rs.qbox.me";
+ $zone->rsfHost = "rsf.qbox.me";
+ $zone->apiHost = "api.qiniu.com";
+ }
+
+ return $zone;
+ }
+}
diff --git a/app/Common/extend/qiniu/src/Qiniu/functions.php b/app/Common/extend/qiniu/src/Qiniu/functions.php
new file mode 100755
index 0000000..5831a51
--- /dev/null
+++ b/app/Common/extend/qiniu/src/Qiniu/functions.php
@@ -0,0 +1,264 @@
+ 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
+ JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
+ JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
+ JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
+ JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
+ );
+
+ if (empty($json)) {
+ return null;
+ }
+ $data = \json_decode($json, $assoc, $depth);
+
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ $last = json_last_error();
+ throw new \InvalidArgumentException(
+ 'Unable to parse JSON data: '
+ . (isset($jsonErrors[$last])
+ ? $jsonErrors[$last]
+ : 'Unknown error')
+ );
+ }
+
+ return $data;
+ }
+
+ /**
+ * 计算七牛API中的数据格式
+ *
+ * @param $bucket 待操作的空间名
+ * @param $key 待操作的文件名
+ *
+ * @return string 符合七牛API规格的数据格式
+ * @link http://developer.qiniu.com/docs/v6/api/reference/data-formats.html
+ */
+ function entry($bucket, $key)
+ {
+ $en = $bucket;
+ if (!empty($key)) {
+ $en = $bucket . ':' . $key;
+ }
+ return base64_urlSafeEncode($en);
+ }
+
+ /**
+ * array 辅助方法,无值时不set
+ *
+ * @param $array 待操作array
+ * @param $key key
+ * @param $value value 为null时 不设置
+ *
+ * @return array 原来的array,便于连续操作
+ */
+ function setWithoutEmpty(&$array, $key, $value)
+ {
+ if (!empty($value)) {
+ $array[$key] = $value;
+ }
+ return $array;
+ }
+
+ /**
+ * 缩略图链接拼接
+ *
+ * @param string $url 图片链接
+ * @param int $mode 缩略模式
+ * @param int $width 宽度
+ * @param int $height 长度
+ * @param string $format 输出类型
+ * @param int $quality 图片质量
+ * @param int $interlace 是否支持渐进显示
+ * @param int $ignoreError 忽略结果
+ * @return string
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html
+ * @author Sherlock Ren
+ */
+ function thumbnail(
+ $url,
+ $mode,
+ $width,
+ $height,
+ $format = null,
+ $quality = null,
+ $interlace = null,
+ $ignoreError = 1
+ ) {
+
+ static $imageUrlBuilder = null;
+ if (is_null($imageUrlBuilder)) {
+ $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder;
+ }
+
+ return call_user_func_array(array($imageUrlBuilder, 'thumbnail'), func_get_args());
+ }
+
+ /**
+ * 图片水印
+ *
+ * @param string $url 图片链接
+ * @param string $image 水印图片链接
+ * @param numeric $dissolve 透明度
+ * @param string $gravity 水印位置
+ * @param numeric $dx 横轴边距
+ * @param numeric $dy 纵轴边距
+ * @param numeric $watermarkScale 自适应原图的短边比例
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html
+ * @return string
+ * @author Sherlock Ren
+ */
+ function waterImg(
+ $url,
+ $image,
+ $dissolve = 100,
+ $gravity = 'SouthEast',
+ $dx = null,
+ $dy = null,
+ $watermarkScale = null
+ ) {
+
+ static $imageUrlBuilder = null;
+ if (is_null($imageUrlBuilder)) {
+ $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder;
+ }
+
+ return call_user_func_array(array($imageUrlBuilder, 'waterImg'), func_get_args());
+ }
+
+ /**
+ * 文字水印
+ *
+ * @param string $url 图片链接
+ * @param string $text 文字
+ * @param string $font 文字字体
+ * @param string $fontSize 文字字号
+ * @param string $fontColor 文字颜色
+ * @param numeric $dissolve 透明度
+ * @param string $gravity 水印位置
+ * @param numeric $dx 横轴边距
+ * @param numeric $dy 纵轴边距
+ * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark
+ * @return string
+ * @author Sherlock Ren
+ */
+ function waterText(
+ $url,
+ $text,
+ $font = '黑体',
+ $fontSize = 0,
+ $fontColor = null,
+ $dissolve = 100,
+ $gravity = 'SouthEast',
+ $dx = null,
+ $dy = null
+ ) {
+
+ static $imageUrlBuilder = null;
+ if (is_null($imageUrlBuilder)) {
+ $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder;
+ }
+
+ return call_user_func_array(array($imageUrlBuilder, 'waterText'), func_get_args());
+ }
+
+ /**
+ * 从uptoken解析accessKey和bucket
+ *
+ * @param $upToken
+ * @return array(ak,bucket,err=null)
+ */
+ function explodeUpToken($upToken)
+ {
+ $items = explode(':', $upToken);
+ if (count($items) != 3) {
+ return array(null, null, "invalid uptoken");
+ }
+ $accessKey = $items[0];
+ $putPolicy = json_decode(base64_urlSafeDecode($items[2]));
+ $scope = $putPolicy->scope;
+ $scopeItems = explode(':', $scope);
+ $bucket = $scopeItems[0];
+ return array($accessKey, $bucket, null);
+ }
+}
diff --git a/app/Common/extend/qiniu/test-env.sh b/app/Common/extend/qiniu/test-env.sh
new file mode 100755
index 0000000..eedf6b5
--- /dev/null
+++ b/app/Common/extend/qiniu/test-env.sh
@@ -0,0 +1,4 @@
+export QINIU_ACCESS_KEY=xxx
+export QINIU_SECRET_KEY=xxx
+export QINIU_TEST_BUCKET=phpsdk
+export QINIU_TEST_DOMAIN=phpsdk.qiniudn.com
\ No newline at end of file
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/AuthTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/AuthTest.php
new file mode 100755
index 0000000..712cbd5
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/AuthTest.php
@@ -0,0 +1,71 @@
+sign('test');
+ $this->assertEquals('abcdefghklmnopq:mSNBTR7uS2crJsyFr2Amwv1LaYg=', $token);
+ }
+
+ public function testSignWithData()
+ {
+ global $dummyAuth;
+ $token = $dummyAuth->signWithData('test');
+ $this->assertEquals('abcdefghklmnopq:-jP8eEV9v48MkYiBGs81aDxl60E=:dGVzdA==', $token);
+ }
+
+ public function testSignRequest()
+ {
+ global $dummyAuth;
+ $token = $dummyAuth->signRequest('http://www.qiniu.com?go=1', 'test', '');
+ $this->assertEquals('abcdefghklmnopq:cFyRVoWrE3IugPIMP5YJFTO-O-Y=', $token);
+ $ctype = 'application/x-www-form-urlencoded';
+ $token = $dummyAuth->signRequest('http://www.qiniu.com?go=1', 'test', $ctype);
+ $this->assertEquals($token, 'abcdefghklmnopq:svWRNcacOE-YMsc70nuIYdaa1e4=');
+ }
+
+ public function testPrivateDownloadUrl()
+ {
+ global $dummyAuth;
+ $_SERVER['override_qiniu_auth_time'] = true;
+ $url = $dummyAuth->privateDownloadUrl('http://www.qiniu.com?go=1');
+ $expect = 'http://www.qiniu.com?go=1&e=1234571490&token=abcdefghklmnopq:8vzBeLZ9W3E4kbBLFLW0Xe0u7v4=';
+ $this->assertEquals($expect, $url);
+ unset($_SERVER['override_qiniu_auth_time']);
+ }
+
+ public function testUploadToken()
+ {
+ global $dummyAuth;
+ $_SERVER['override_qiniu_auth_time'] = true;
+ $token = $dummyAuth->uploadToken('1', '2', 3600, array('endUser' => 'y'));
+ // @codingStandardsIgnoreStart
+ $exp = 'abcdefghklmnopq:yyeexeUkPOROoTGvwBjJ0F0VLEo=:eyJlbmRVc2VyIjoieSIsInNjb3BlIjoiMToyIiwiZGVhZGxpbmUiOjEyMzQ1NzE0OTB9';
+ // @codingStandardsIgnoreEnd
+ $this->assertEquals($exp, $token);
+ unset($_SERVER['override_qiniu_auth_time']);
+ }
+
+ public function testVerifyCallback()
+ {
+ }
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/Base64Test.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/Base64Test.php
new file mode 100755
index 0000000..6d63353
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/Base64Test.php
@@ -0,0 +1,14 @@
+assertEquals($a, \Qiniu\base64_urlSafeDecode($b));
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/BucketTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/BucketTest.php
new file mode 100755
index 0000000..534d8c2
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/BucketTest.php
@@ -0,0 +1,227 @@
+bucketName = $bucketName;
+ $this->key = $key;
+ $this->key2 = $key2;
+
+ global $testAuth;
+ $this->bucketManager = new BucketManager($testAuth);
+
+ global $dummyAuth;
+ $this->dummyBucketManager = new BucketManager($dummyAuth);
+ }
+
+ public function testBuckets()
+ {
+
+ list($list, $error) = $this->bucketManager->buckets();
+ $this->assertTrue(in_array($this->bucketName, $list));
+ $this->assertNull($error);
+
+ list($list2, $error) = $this->dummyBucketManager->buckets();
+ $this->assertEquals(401, $error->code());
+ $this->assertNull($list2);
+ $this->assertNotNull($error->message());
+ }
+
+ public function testList()
+ {
+ list($ret, $error) = $this->bucketManager->listFiles($this->bucketName, null, null, 10);
+ $this->assertNotNull($ret['items'][0]);
+ $this->assertNotNull($ret['marker']);
+ }
+
+ public function testStat()
+ {
+ list($stat, $error) = $this->bucketManager->stat($this->bucketName, $this->key);
+ $this->assertNotNull($stat);
+ $this->assertNull($error);
+ $this->assertNotNull($stat['hash']);
+
+ list($stat, $error) = $this->bucketManager->stat($this->bucketName, 'nofile');
+ $this->assertNull($stat);
+ $this->assertEquals(612, $error->code());
+ $this->assertNotNull($error->message());
+
+ list($stat, $error) = $this->bucketManager->stat('nobucket', 'nofile');
+ $this->assertNull($stat);
+ $this->assertEquals(631, $error->code());
+ $this->assertNotNull($error->message());
+ }
+
+ public function testDelete()
+ {
+ $error = $this->bucketManager->delete($this->bucketName, 'del');
+ $this->assertEquals(612, $error->code());
+ }
+
+
+ public function testRename()
+ {
+ $key = 'renamefrom' . rand();
+ $this->bucketManager->copy($this->bucketName, $this->key, $this->bucketName, $key);
+ $key2 = 'renameto' . $key;
+ $error = $this->bucketManager->rename($this->bucketName, $key, $key2);
+ $this->assertNull($error);
+ $error = $this->bucketManager->delete($this->bucketName, $key2);
+ $this->assertNull($error);
+ }
+
+
+ public function testCopy()
+ {
+ $key = 'copyto' . rand();
+ $this->bucketManager->delete($this->bucketName, $key);
+
+ $error = $this->bucketManager->copy(
+ $this->bucketName,
+ $this->key,
+ $this->bucketName,
+ $key
+ );
+ $this->assertNull($error);
+
+ //test force copy
+ $error = $this->bucketManager->copy(
+ $this->bucketName,
+ $this->key2,
+ $this->bucketName,
+ $key,
+ true
+ );
+ $this->assertNull($error);
+
+ list($key2Stat,) = $this->bucketManager->stat($this->bucketName, $this->key2);
+ list($key2CopiedStat,) = $this->bucketManager->stat($this->bucketName, $key);
+
+ $this->assertEquals($key2Stat['hash'], $key2CopiedStat['hash']);
+
+ $error = $this->bucketManager->delete($this->bucketName, $key);
+ $this->assertNull($error);
+ }
+
+
+ public function testChangeMime()
+ {
+ $error = $this->bucketManager->changeMime(
+ $this->bucketName,
+ 'php-sdk.html',
+ 'text/html'
+ );
+ $this->assertNull($error);
+ }
+
+ public function testPrefetch()
+ {
+ $error = $this->bucketManager->prefetch(
+ $this->bucketName,
+ 'php-sdk.html'
+ );
+ $this->assertNull($error);
+ }
+
+ public function testFetch()
+ {
+ list($ret, $error) = $this->bucketManager->fetch(
+ 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html',
+ $this->bucketName,
+ 'fetch.html'
+ );
+ $this->assertArrayHasKey('hash', $ret);
+ $this->assertNull($error);
+
+ list($ret, $error) = $this->bucketManager->fetch(
+ 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html',
+ $this->bucketName,
+ ''
+ );
+ $this->assertArrayHasKey('key', $ret);
+ $this->assertNull($error);
+
+ list($ret, $error) = $this->bucketManager->fetch(
+ 'http://developer.qiniu.com/docs/v6/sdk/php-sdk.html',
+ $this->bucketName
+ );
+ $this->assertArrayHasKey('key', $ret);
+ $this->assertNull($error);
+ }
+
+ public function testBatchCopy()
+ {
+ $key = 'copyto' . rand();
+ $ops = BucketManager::buildBatchCopy(
+ $this->bucketName,
+ array($this->key => $key),
+ $this->bucketName,
+ true
+ );
+ list($ret, $error) = $this->bucketManager->batch($ops);
+ $this->assertEquals(200, $ret[0]['code']);
+ $ops = BucketManager::buildBatchDelete($this->bucketName, array($key));
+ list($ret, $error) = $this->bucketManager->batch($ops);
+ $this->assertEquals(200, $ret[0]['code']);
+ }
+
+ public function testBatchMove()
+ {
+ $key = 'movefrom' . rand();
+ $this->bucketManager->copy($this->bucketName, $this->key, $this->bucketName, $key);
+ $key2 = $key . 'to';
+ $ops = BucketManager::buildBatchMove(
+ $this->bucketName,
+ array($key => $key2),
+ $this->bucketName,
+ true
+ );
+ list($ret, $error) = $this->bucketManager->batch($ops);
+ $this->assertEquals(200, $ret[0]['code']);
+ $error = $this->bucketManager->delete($this->bucketName, $key2);
+ $this->assertNull($error);
+ }
+
+ public function testBatchRename()
+ {
+ $key = 'rename' . rand();
+ $this->bucketManager->copy($this->bucketName, $this->key, $this->bucketName, $key);
+ $key2 = $key . 'to';
+ $ops = BucketManager::buildBatchRename($this->bucketName, array($key => $key2), true);
+ list($ret, $error) = $this->bucketManager->batch($ops);
+ $this->assertEquals(200, $ret[0]['code']);
+ $error = $this->bucketManager->delete($this->bucketName, $key2);
+ $this->assertNull($error);
+ }
+
+ public function testBatchStat()
+ {
+ $ops = BucketManager::buildBatchStat($this->bucketName, array('php-sdk.html'));
+ list($ret, $error) = $this->bucketManager->batch($ops);
+ $this->assertEquals(200, $ret[0]['code']);
+ }
+
+ public function testDeleteAfterDays()
+ {
+ $key = rand();
+ $err = $this->bucketManager->deleteAfterDays($this->bucketName, $key, 1);
+ $this->assertEquals(612, $err->code());
+
+ $this->bucketManager->copy($this->bucketName, $this->key, $this->bucketName, $key);
+ $err = $this->bucketManager->deleteAfterDays($this->bucketName, $key, 1);
+ $this->assertEquals(null, $err);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/CdnManagerTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/CdnManagerTest.php
new file mode 100755
index 0000000..5a858df
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/CdnManagerTest.php
@@ -0,0 +1,50 @@
+cdnManager = new CdnManager($testAuth);
+ $this->encryptKey = $timestampAntiLeechEncryptKey;
+ $this->imgUrl = $customDomain . '/24.jpg';
+ }
+
+ public function testCreateTimestampAntiLeechUrl()
+ {
+
+ $signUrl = $this->cdnManager->createTimestampAntiLeechUrl($this->imgUrl, $this->encryptKey, 3600);
+
+ $response = Client::get($signUrl);
+ $this->assertEquals($response->statusCode, 200);
+ $this->assertNull($response->error);
+
+ $url2 = $this->imgUrl . '?imageInfo';
+ $signUrl2 = $this->cdnManager->createTimestampAntiLeechUrl($url2, $this->encryptKey, 3600);
+
+ $response = Client::get($signUrl2);
+ $imgInfo = $response->json();
+
+ $this->assertEquals($response->statusCode, 200);
+ $this->assertEquals($imgInfo['size'], 2196145);
+ $this->assertNull($response->error);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/Crc32Test.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/Crc32Test.php
new file mode 100755
index 0000000..bfb36da
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/Crc32Test.php
@@ -0,0 +1,21 @@
+assertEquals('1352841281', $b);
+ }
+
+ public function testFile()
+ {
+ $b = \Qiniu\crc32_file(__file__);
+ $c = \Qiniu\crc32_file(__file__);
+ $this->assertEquals($c, $b);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/DownloadTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/DownloadTest.php
new file mode 100755
index 0000000..82990f2
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/DownloadTest.php
@@ -0,0 +1,25 @@
+privateDownloadUrl($base_url);
+ $response = Client::get($private_url);
+ $this->assertEquals(200, $response->statusCode);
+ }
+
+ public function testFop()
+ {
+ global $testAuth;
+ $base_url = 'http://private-res.qiniudn.com/gogopher.jpg?exif';
+ $private_url = $testAuth->privateDownloadUrl($base_url);
+ $response = Client::get($private_url);
+ $this->assertEquals(200, $response->statusCode);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/EtagTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/EtagTest.php
new file mode 100755
index 0000000..42a1499
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/EtagTest.php
@@ -0,0 +1,52 @@
+assertEquals('Fto5o-5ea0sNMlW_75VgGJCv2AcJ', $r);
+ $this->assertNull($error);
+ }
+
+ public function testLess4M()
+ {
+ $file = qiniuTempFile(3 * 1024 * 1024);
+ list($r, $error) = Etag::sum($file);
+ unlink($file);
+ $this->assertEquals('Fs5BpnAjRykYTg6o5E09cjuXrDkG', $r);
+ $this->assertNull($error);
+ }
+
+ public function test4M()
+ {
+ $file = qiniuTempFile(4 * 1024 * 1024);
+ list($r, $error) = Etag::sum($file);
+ unlink($file);
+ $this->assertEquals('FiuKULnybewpEnrfTmxjsxc-3dWp', $r);
+ $this->assertNull($error);
+ }
+
+ public function testMore4M()
+ {
+ $file = qiniuTempFile(5 * 1024 * 1024);
+ list($r, $error) = Etag::sum($file);
+ unlink($file);
+ $this->assertEquals('lhvyfIWMYFTq4s4alzlhXoAkqfVL', $r);
+ $this->assertNull($error);
+ }
+
+ public function test8M()
+ {
+ $file = qiniuTempFile(8 * 1024 * 1024);
+ list($r, $error) = Etag::sum($file);
+ unlink($file);
+ $this->assertEquals('lmRm9ZfGZ86bnMys4wRTWtJj9ClG', $r);
+ $this->assertNull($error);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/FopTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/FopTest.php
new file mode 100755
index 0000000..e1ea730
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/FopTest.php
@@ -0,0 +1,37 @@
+execute('gogopher.jpg', 'exif');
+ $this->assertNull($error);
+ $this->assertNotNull($exif);
+ }
+
+ public function testExifPrivate()
+ {
+ global $testAuth;
+ $fop = new Operation('private-res.qiniudn.com', $testAuth);
+ list($exif, $error) = $fop->execute('noexif.jpg', 'exif');
+ $this->assertNotNull($error);
+ $this->assertNull($exif);
+ }
+
+ public function testbuildUrl()
+ {
+ $fops = 'imageView2/2/h/200';
+ $fop = new Operation('testres.qiniudn.com');
+ $url = $fop->buildUrl('gogopher.jpg', $fops);
+ $this->assertEquals($url, 'http://testres.qiniudn.com/gogopher.jpg?imageView2/2/h/200');
+
+ $fops = array('imageView2/2/h/200', 'imageInfo');
+ $url = $fop->buildUrl('gogopher.jpg', $fops);
+ $this->assertEquals($url, 'http://testres.qiniudn.com/gogopher.jpg?imageView2/2/h/200|imageInfo');
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/FormUpTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/FormUpTest.php
new file mode 100755
index 0000000..4813eed
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/FormUpTest.php
@@ -0,0 +1,59 @@
+bucketName = $bucketName;
+
+ global $testAuth;
+ $this->auth = $testAuth;
+ $this->cfg = new Config();
+ }
+
+ public function testData()
+ {
+ $token = $this->auth->uploadToken($this->bucketName);
+ list($ret, $error) = FormUploader::put($token, 'formput', 'hello world', $this->cfg, null, 'text/plain', null);
+ $this->assertNull($error);
+ $this->assertNotNull($ret['hash']);
+ }
+
+ public function testData2()
+ {
+ $upManager = new UploadManager();
+ $token = $this->auth->uploadToken($this->bucketName);
+ list($ret, $error) = $upManager->put($token, 'formput', 'hello world', null, 'text/plain', null);
+ $this->assertNull($error);
+ $this->assertNotNull($ret['hash']);
+ }
+
+ public function testFile()
+ {
+ $key = 'formPutFile';
+ $token = $this->auth->uploadToken($this->bucketName, $key);
+ list($ret, $error) = FormUploader::putFile($token, $key, __file__, $this->cfg, null, 'text/plain', null);
+ $this->assertNull($error);
+ $this->assertNotNull($ret['hash']);
+ }
+
+ public function testFile2()
+ {
+ $key = 'formPutFile';
+ $token = $this->auth->uploadToken($this->bucketName, $key);
+ $upManager = new UploadManager();
+ list($ret, $error) = $upManager->putFile($token, $key, __file__, null, 'text/plain', null);
+ $this->assertNull($error);
+ $this->assertNotNull($ret['hash']);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/HttpTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/HttpTest.php
new file mode 100755
index 0000000..e2ab5fc
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/HttpTest.php
@@ -0,0 +1,43 @@
+assertEquals($response->statusCode, 200);
+ $this->assertNotNull($response->body);
+ $this->assertNull($response->error);
+ }
+
+ public function testGetQiniu()
+ {
+ $response = Client::get('up.qiniu.com');
+ $this->assertEquals(405, $response->statusCode);
+ $this->assertNotNull($response->body);
+ $this->assertNotNull($response->xReqId());
+ $this->assertNotNull($response->xLog());
+ $this->assertNotNull($response->error);
+ }
+
+ public function testPost()
+ {
+ $response = Client::post('baidu.com', null);
+ $this->assertEquals($response->statusCode, 200);
+ $this->assertNotNull($response->body);
+ $this->assertNull($response->error);
+ }
+
+ public function testPostQiniu()
+ {
+ $response = Client::post('up.qiniu.com', null);
+ $this->assertEquals($response->statusCode, 400);
+ $this->assertNotNull($response->body);
+ $this->assertNotNull($response->xReqId());
+ $this->assertNotNull($response->xLog());
+ $this->assertNotNull($response->error);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/ImageUrlBuilderTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/ImageUrlBuilderTest.php
new file mode 100755
index 0000000..fca87b6
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/ImageUrlBuilderTest.php
@@ -0,0 +1,261 @@
+
+ */
+class ImageUrlBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * 缩略图测试
+ *
+ * @test
+ * @return void
+ * @author Sherlock Ren
+ */
+ public function testThumbutl()
+ {
+ $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder();
+ $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg';
+ $url2 = $url . '?watermark/1/gravity/SouthEast/dx/0/dy/0/image/'
+ . 'aHR0cDovL2Fkcy1jZG4uY2h1Y2h1amllLmNvbS9Ga1R6bnpIY2RLdmRBUFc5cHZZZ3pTc21UY0tB';
+ // 异常测试
+ $this->assertEquals($url, $imageUrlBuilder->thumbnail($url, 1, 0, 0));
+ $this->assertEquals($url, \Qiniu\thumbnail($url, 1, 0, 0));
+
+ // 简单缩略测试
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/ignore-error/1/',
+ $imageUrlBuilder->thumbnail($url, 1, 200, 200)
+ );
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/ignore-error/1/',
+ \Qiniu\thumbnail($url, 1, 200, 200)
+ );
+
+ // 输出格式测试
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/',
+ $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png')
+ );
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/',
+ \Qiniu\thumbnail($url, 1, 200, 200, 'png')
+ );
+
+ // 渐进显示测试
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/ignore-error/1/',
+ $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png', 1)
+ );
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/',
+ \Qiniu\thumbnail($url, 1, 200, 200, 'png', 2)
+ );
+
+ // 图片质量测试
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/q/80/ignore-error/1/',
+ $imageUrlBuilder->thumbnail($url, 1, 200, 200, 'png', 1, 80)
+ );
+ $this->assertEquals(
+ $url . '?imageView2/1/w/200/h/200/format/png/interlace/1/ignore-error/1/',
+ \Qiniu\thumbnail($url, 1, 200, 200, 'png', 1, 101)
+ );
+
+ // 多参数测试
+ $this->assertEquals(
+ $url2 . '|imageView2/1/w/200/h/200/ignore-error/1/',
+ $imageUrlBuilder->thumbnail($url2, 1, 200, 200)
+ );
+ $this->assertEquals(
+ $url2 . '|imageView2/1/w/200/h/200/ignore-error/1/',
+ \Qiniu\thumbnail($url2, 1, 200, 200)
+ );
+ }
+
+ /**
+ * 图片水印测试
+ *
+ * @test
+ * @param void
+ * @return void
+ * @author Sherlock Ren
+ */
+ public function waterImgTest()
+ {
+ $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder();
+ $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg';
+ $url2 = $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/';
+ $image = 'http://developer.qiniu.com/resource/logo-2.jpg';
+
+ // 水印简单测试
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ $imageUrlBuilder->waterImg($url, $image)
+ );
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/gravity/SouthEast/',
+ $imageUrlBuilder->waterImg($url, $image, 101)
+ );
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw==/',
+ $imageUrlBuilder->waterImg($url, $image, 101, 'sdfsd')
+ );
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterImg($url, $image)
+ );
+
+ // 横轴边距测试
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/dx/10/',
+ $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10)
+ );
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad')
+ );
+
+ // 纵轴边距测试
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/dx/10/dy/10/',
+ $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10, 10)
+ );
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad', 'asdf')
+ );
+
+ // 自适应原图的短边比例测试
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/dx/10/dy/10/ws/0.5/',
+ $imageUrlBuilder->waterImg($url, $image, 100, 'SouthEast', 10, 10, 0.5)
+ );
+ $this->assertEquals(
+ $url . '?watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterImg($url, $image, 100, 'SouthEast', 'sad', 'asdf', 2)
+ );
+
+ // 多参数测试
+ $this->assertEquals(
+ $url2 . '|watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ $imageUrlBuilder->waterImg($url2, $image)
+ );
+ $this->assertEquals(
+ $url2 . '|watermark/1/image/aHR0cDovL2RldmVsb3Blci5xaW5pdS5jb20vcmVzb3VyY2UvbG9nby0yLmpwZw=='
+ . '/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterImg($url2, $image)
+ );
+ }
+
+ /**
+ * 文字水印测试
+ *
+ * @test
+ * @param void
+ * @return void
+ * @author Sherlock Ren
+ */
+ public function waterTextTest()
+ {
+ $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder();
+ $url = 'http://78re52.com1.z0.glb.clouddn.com/resource/gogopher.jpg';
+ $url2 = $url . '?imageView2/1/w/200/h/200/format/png/ignore-error/1/';
+ $text = '测试一下';
+ $font = '微软雅黑';
+ $fontColor = '#FF0000';
+
+ // 水印简单测试
+ $this->assertEquals($url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/'
+ . 'fontsize/500/dissolve/100/gravity/SouthEast/', $imageUrlBuilder->waterText($url, $text, $font, 500));
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/'
+ . 'dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterText($url, $text, $font, 'sdf')
+ );
+
+ // 字体颜色测试
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/'
+ . 'I0ZGMDAwMA==/dissolve/100/gravity/SouthEast/',
+ $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor)
+ );
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA=='
+ . '/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor)
+ );
+
+ // 透明度测试
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA=='
+ . '/dissolve/80/gravity/SouthEast/',
+ $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80)
+ );
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA=='
+ . '/gravity/SouthEast/',
+ \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101)
+ );
+
+ // 水印位置测试
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA=='
+ . '/dissolve/80/gravity/East/',
+ $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East')
+ );
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/',
+ \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf')
+ );
+
+ // 横轴距离测试
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA=='
+ . '/dissolve/80/gravity/East/dx/10/',
+ $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East', 10)
+ );
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/',
+ \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf', 'sdfs')
+ );
+
+ // 纵轴距离测试
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fontsize/500/fill/I0ZGMDAwMA=='
+ . '/dissolve/80/gravity/East/dx/10/dy/10/',
+ $imageUrlBuilder->waterText($url, $text, $font, 500, $fontColor, 80, 'East', 10, 10)
+ );
+ $this->assertEquals(
+ $url . '?watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/fill/I0ZGMDAwMA==/',
+ \Qiniu\waterText($url, $text, $font, 'sdf', $fontColor, 101, 'sdfsdf', 'sdfs', 'ssdf')
+ );
+ // 多参数测试
+ $this->assertEquals(
+ $url2 . '|watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/'
+ . 'fontsize/500/dissolve/100/gravity/SouthEast/',
+ $imageUrlBuilder->waterText($url2, $text, $font, 500)
+ );
+ $this->assertEquals(
+ $url2 . '|watermark/2/text/5rWL6K-V5LiA5LiL/font/5b6u6L2v6ZuF6buR/'
+ . 'fontsize/500/dissolve/100/gravity/SouthEast/',
+ \Qiniu\waterText($url2, $text, $font, 500)
+ );
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/PfopTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/PfopTest.php
new file mode 100755
index 0000000..d03b3f6
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/PfopTest.php
@@ -0,0 +1,66 @@
+execute($bucket, $key, $fops);
+ $this->assertNull($error);
+ list($status, $error) = $pfop->status($id);
+ $this->assertNotNull($status);
+ $this->assertNull($error);
+ }
+
+
+ public function testPfops()
+ {
+ global $testAuth;
+ $bucket = 'testres';
+ $key = 'sintel_trailer.mp4';
+ $fops = array(
+ 'avthumb/m3u8/segtime/10/vcodec/libx264/s/320x240',
+ 'vframe/jpg/offset/7/w/480/h/360',
+ );
+ $pfop = new PersistentFop($testAuth, null);
+
+ list($id, $error) = $pfop->execute($bucket, $key, $fops);
+ $this->assertNull($error);
+
+ list($status, $error) = $pfop->status($id);
+ $this->assertNotNull($status);
+ $this->assertNull($error);
+ }
+
+ public function testMkzip()
+ {
+ global $testAuth;
+ $bucket = 'phpsdk';
+ $key = 'php-logo.png';
+ $pfop = new PersistentFop($testAuth, null);
+
+ $url1 = 'http://phpsdk.qiniudn.com/php-logo.png';
+ $url2 = 'http://phpsdk.qiniudn.com/php-sdk.html';
+ $zipKey = 'test.zip';
+
+ $fops = 'mkzip/2/url/' . \Qiniu\base64_urlSafeEncode($url1);
+ $fops .= '/url/' . \Qiniu\base64_urlSafeEncode($url2);
+ $fops .= '|saveas/' . \Qiniu\base64_urlSafeEncode("$bucket:$zipKey");
+
+ list($id, $error) = $pfop->execute($bucket, $key, $fops);
+ $this->assertNull($error);
+
+ list($status, $error) = $pfop->status($id);
+ $this->assertNotNull($status);
+ $this->assertNull($error);
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/ResumeUpTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/ResumeUpTest.php
new file mode 100755
index 0000000..00008d4
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/ResumeUpTest.php
@@ -0,0 +1,60 @@
+bucketName = $bucketName;
+
+ global $testAuth;
+ $this->auth = $testAuth;
+ }
+
+ public function test4ML()
+ {
+ $key = 'resumePutFile4ML';
+ $upManager = new UploadManager();
+ $token = $this->auth->uploadToken($this->bucketName, $key);
+ $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10);
+ list($ret, $error) = $upManager->putFile($token, $key, $tempFile);
+ $this->assertNull($error);
+ $this->assertNotNull($ret['hash']);
+ unlink($tempFile);
+ }
+
+ public function test4ML2()
+ {
+ $key = 'resumePutFile4ML';
+ $zone = new Zone(array('up.qiniup.com'));
+ $cfg = new Config($zone);
+ $upManager = new UploadManager($cfg);
+ $token = $this->auth->uploadToken($this->bucketName, $key);
+ $tempFile = qiniuTempFile(4 * 1024 * 1024 + 10);
+ list($ret, $error) = $upManager->putFile($token, $key, $tempFile);
+ $this->assertNull($error);
+ $this->assertNotNull($ret['hash']);
+ unlink($tempFile);
+ }
+
+ // public function test8M()
+ // {
+ // $key = 'resumePutFile8M';
+ // $upManager = new UploadManager();
+ // $token = $this->auth->uploadToken($this->bucketName, $key);
+ // $tempFile = qiniuTempFile(8*1024*1024+10);
+ // list($ret, $error) = $upManager->putFile($token, $key, $tempFile);
+ // $this->assertNull($error);
+ // $this->assertNotNull($ret['hash']);
+ // unlink($tempFile);
+ // }
+}
diff --git a/app/Common/extend/qiniu/tests/Qiniu/Tests/ZoneTest.php b/app/Common/extend/qiniu/tests/Qiniu/Tests/ZoneTest.php
new file mode 100755
index 0000000..d32875b
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/Qiniu/Tests/ZoneTest.php
@@ -0,0 +1,59 @@
+bucketName = $bucketName;
+
+ global $bucketNameBC;
+ $this->bucketNameBC = $bucketNameBC;
+
+ global $bucketNameNA;
+ $this->bucketNameNA = $bucketNameNA;
+
+ global $accessKey;
+ $this->ak = $accessKey;
+
+ $this->zone = new Zone();
+ $this->zoneHttps = new Zone('https');
+ }
+
+ public function testUpHosts()
+ {
+ $zone = Zone::queryZone($this->ak, $this->bucketName);
+ $this->assertContains('upload.qiniup.com', $zone->cdnUpHosts);
+
+ $zone = Zone::queryZone($this->ak, $this->bucketNameBC);
+ $this->assertContains('upload-z1.qiniup.com', $zone->cdnUpHosts);
+
+ $zone = Zone::queryZone($this->ak, $this->bucketNameNA);
+ $this->assertContains('upload-na0.qiniup.com', $zone->cdnUpHosts);
+ }
+
+ public function testIoHosts()
+ {
+ $zone = Zone::queryZone($this->ak, $this->bucketName);
+ $this->assertEquals($zone->iovipHost, 'iovip.qbox.me');
+
+ $zone = Zone::queryZone($this->ak, $this->bucketNameBC);
+ $this->assertEquals($zone->iovipHost, 'iovip-z1.qbox.me');
+
+ $zone = Zone::queryZone($this->ak, $this->bucketNameNA);
+ $this->assertEquals($zone->iovipHost, 'iovip-na0.qbox.me');
+ }
+}
diff --git a/app/Common/extend/qiniu/tests/bootstrap.php b/app/Common/extend/qiniu/tests/bootstrap.php
new file mode 100755
index 0000000..5bd8b05
--- /dev/null
+++ b/app/Common/extend/qiniu/tests/bootstrap.php
@@ -0,0 +1,43 @@
+ 0) {
+ fseek($file, $size - 1);
+ fwrite($file, ' ');
+ }
+ fclose($file);
+ return $fileName;
+}
diff --git a/app/Common/extend/radarMsg.php b/app/Common/extend/radarMsg.php
new file mode 100755
index 0000000..1e93271
--- /dev/null
+++ b/app/Common/extend/radarMsg.php
@@ -0,0 +1,814 @@
+ "praises",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看",
+ "item"=> "名片",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "对你已建立信任,保持联系持续跟进",
+ "operation"=> "将",
+ "item"=> "手机号码存入了手机通讯录",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "咨询意向强烈,及时联系确保沟通顺畅",
+ "operation"=> "拨打",
+ "item"=> "手机号",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_user_info",
+ "field"=> "phone",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请随时保持电话畅通",
+ "operation"=> "拨打",
+ "item"=> "公司电话",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "客户请随时可能加你微信",
+ "operation"=> "复制了",
+ "item"=> "微信",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 5,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "可能随时邮寄文件给你,请注意查收",
+ "operation"=> "复制了",
+ "item"=> "邮箱",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 6,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "复制",
+ "item"=> "公司名称",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 7,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "对你的公司非常感兴趣",
+ "operation"=> "查看了",
+ "item"=> "公司地址",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "咨询",
+ "item"=> "产品",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 9,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "播放",
+ "item"=> "语音",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 10,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "保存了",
+ "item"=> "名片海报",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请随时保持电话畅通",
+ "operation"=> "拨打",
+ "item"=> "400热线",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商城列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机,主动提供细致的商品讲解将大大有利于成交",
+ "operation"=> "正在查看你的",
+ "item"=> "商品",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_goods",
+ "field"=> "name",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "看来TA对公司动态感兴趣",
+ "operation"=> "浏览",
+ "item"=> "动态列表",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "点赞",
+ "item"=> "动态",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 5,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "评论了",
+ "item"=> "动态",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 6,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "查看了",
+ "item"=> "企业官网",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 7,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "动态",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "动态视频",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 9,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "动态外链",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 10,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "通过动态列表跳转小程序",
+ "item"=> "",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商品分类列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 12,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快展开跟进",
+ "operation"=> "正在阅读",
+ "item"=> "文章",
+ "show_count"=> 0,
+ "table_name"=> "lb_marketing_article_v2",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 13,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "分享了",
+ "item"=> "文章",
+ "show_count"=> 0,
+ "table_name"=> "lb_marketing_article_v2",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 14,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "保存",
+ "item"=> "文章海报",
+ "show_count"=> 0,
+ "table_name"=> "lb_marketing_article_v2",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 15,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "查看了",
+ "item"=> "预约",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 16,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "预约栏目",
+ "show_count"=> 1,
+ "table_name"=> "lb_appoint_classify",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 17,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "预约活动",
+ "operation"=> "正在查看",
+ "item"=> "预约",
+ "show_count"=> 0,
+ "table_name"=> "lb_appoint_project",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 18,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快处理",
+ "operation"=> "在官网留言",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_form",
+ "field"=> "name,phone,content",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 19,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "订单商品已发货,系统订单号为:",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 20,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "自提商品已提货",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 21,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请等待管理员审核并注意查收",
+ "operation"=> "已申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 22,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "已取消申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 23,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "管理员拒绝退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 24,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请注意查收",
+ "operation"=> "退款成功",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 25,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "查看了",
+ "item"=> "活动",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 26,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "活动报名分类列表",
+ "show_count"=> 1,
+ "table_name"=> "lb_activity_classify",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 27,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "正在查看",
+ "item"=> "活动",
+ "show_count"=> 0,
+ "table_name"=> "lb_activity_activity",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 28,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在活动开始前提醒客户",
+ "operation"=> "已参加了活动",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "lb_activity_activity",
+ "field"=> "title",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 29,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "房源信息",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 30,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看了",
+ "item"=> "房源",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_house",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "语音点赞",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看",
+ "item"=> "名片",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "Ta给你点赞了",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "分享了",
+ "item"=> "名片",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 5,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "咨询",
+ "item"=> "房源信息",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 6,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "收藏了",
+ "item"=> "房源",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_house",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 7,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "电话咨询了",
+ "item"=> "房源",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_house",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请提前联系客户",
+ "operation"=> "预约查看",
+ "item"=> "房源",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_house",
+ "field"=> "title",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已购买商品",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已参与拼团",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在预约订单中心查看详情",
+ "operation"=> "预约了",
+ "item"=> "服务",
+ "show_count"=> 0,
+ "table_name"=> "lb_appoint_record",
+ "field"=> "name,phone,project_id,start_time,remark",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "qr",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在使用扫码支付",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "lb_pay_qr_record",
+ "field"=> "money",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+];
\ No newline at end of file
diff --git a/app/Common/extend/tencentcloud/.gitignore b/app/Common/extend/tencentcloud/.gitignore
new file mode 100755
index 0000000..1c0b8d4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/.gitignore
@@ -0,0 +1,2 @@
+.vscode/
+.idea/
\ No newline at end of file
diff --git a/app/Common/extend/tencentcloud/.travis.yml b/app/Common/extend/tencentcloud/.travis.yml
new file mode 100755
index 0000000..0392843
--- /dev/null
+++ b/app/Common/extend/tencentcloud/.travis.yml
@@ -0,0 +1,6 @@
+language: php
+php:
+ - 5.4
+script:
+ - composer install
+ - phpunit -v
diff --git a/app/Common/extend/tencentcloud/LICENSE b/app/Common/extend/tencentcloud/LICENSE
new file mode 100755
index 0000000..2c948c8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 腾讯云
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/app/Common/extend/tencentcloud/README.md b/app/Common/extend/tencentcloud/README.md
new file mode 100755
index 0000000..2a404c5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/README.md
@@ -0,0 +1,257 @@
+# COS-PHP-SDK-V5
+腾讯云COS-PHP-SDK-V5([XML API](https://cloud.tencent.com/document/product/436/7751))
+
+[](https://packagist.org/packages/qcloud/cos-sdk-v5)
+[](https://travis-ci.org/tencentyun/cos-php-sdk-v5)
+
+## 环境准备
+* PHP 5.3+
+ 您可以通过`php -v`命令查看当前的PHP版本。
+
+* cURL 扩展
+ 您可以通过`php -m`命令查看cURL扩展是否已经安装好。
+
+> **说明:**
+>
+> * Ubuntu系统中,您可以使用apt-get包管理器安装PHP的cURL扩展 `sudo apt-get install php-curl`。
+> * CentOS系统中,您可以使用yum包管理器安装PHP的cURL扩展 `sudo yum install php-curl`。
+
+### SDK 安装
+有三种方式安装SDK:
+* Composer方式
+* Phar方式
+* 源码方式
+#### 1、Composer方式
+推荐用户使用 Composer 安装 cos-php-sdk-v5,Composer是PHP的依赖管理工具,允许您声明项目所需的依赖,然后自动将它们安装到您的项目中。
+
+> **提示**:您可以在 [getcomposer.org](getcomposer.org) 上找到更多关于如何安装Composer,配置自动加载以及用于定义依赖项的其他最佳实践。
+
+**使用 Composer 安装 COS-PHP-SDK-V5**
+1. 打开终端
+2. 下载 Composer
+```
+curl -sS https://getcomposer.org/installer | php
+```
+3. 创建一个名为`composer.json`的文件,内容为
+```
+{
+ "require": {
+ "qcloud/cos-sdk-v5": "1.*"
+ }
+}
+```
+4. 使用 Composer 安装
+```
+php composer.phar install
+```
+使用该命令后会在当前目录中创建一个vendor文件夹,里面包含 sdk 的依赖库和一个 autoload.php 脚本,方便用户在自己的项目中调用。
+5. 通过 autoloader 脚本调用cos-php-sdk-v5
+```
+require '/path/to/sdk/vendor/autoload.php';
+```
+现在您的项目已经可以使用COS的V5 SDK了。
+
+
+#### 2、Phar方式
+phar方式安装SDK的步骤如下:
+
+1. 在[github发布页面](https://github.com/tencentyun/cos-php-sdk-v5/releases)下载相应的phar文件
+
+2. 在代码中引入phar文件:
+```
+require '/path/to/cos-sdk-v5.phar';
+```
+
+#### 3、源码方式
+源码方式安装SDK的步骤如下:
+
+1. 在[github发布页面](https://github.com/tencentyun/cos-php-sdk-v5/releases)下载相应的zip文件
+
+2. 解压通过 autoload.php 脚本加载sdk
+```
+require '/path/to/sdk/vendor/autoload.php';
+```
+
+
+## 快速入门
+可参照Demo程序,详见 [sample.php](https://github.com/tencentyun/cos-php-sdk-v5/blob/master/sample.php)
+## 接口文档
+php sdk 接口文档,详见https://cloud.tencent.com/document/product/436/12267
+### 配置文件
+```php
+$cosClient = new Qcloud\Cos\Client(array('region' => 'COS_REGION',
+ 'credentials'=> array(
+ 'secretId' => 'COS_KEY',
+ 'secretKey' => 'COS_SECRET')));
+```
+### 上传文件
+* 使用putObject接口上传文件(最大5G)
+* 使用Upload接口分块上传文件
+```php
+# 上传文件
+## putObject(上传接口,最大支持上传5G文件)
+### 上传内存中的字符串
+//bucket 的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
+try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => 'Hello World!'));
+ print_r($result);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 上传文件流
+try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => fopen($local_path, 'rb')));
+ print_r($result);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 设置header和meta
+try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => fopen($local_path, 'rb'),
+ 'ACL' => 'string',
+ 'CacheControl' => 'string',
+ 'ContentDisposition' => 'string',
+ 'ContentEncoding' => 'string',
+ 'ContentLanguage' => 'string',
+ 'ContentLength' => integer,
+ 'ContentType' => 'string',
+ 'Expires' => 'mixed type: string (date format)|int (unix timestamp)|\DateTime',
+ 'GrantFullControl' => 'string',
+ 'GrantRead' => 'string',
+ 'GrantWrite' => 'string',
+ 'Metadata' => array(
+ 'string' => 'string',
+ ),
+ 'StorageClass' => 'string'));
+ print_r($result);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+## Upload(高级上传接口,默认使用分块上传最大支持50T)
+### 上传内存中的字符串
+try {
+ $result = $cosClient->Upload(
+ $bucket = $bucket,
+ $key = $key,
+ $body = 'Hello World!');
+ print_r($result);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 上传文件流
+try {
+ $result = $cosClient->Upload(
+ $bucket = $bucket,
+ $key = $key,
+ $body = fopen($local_path, 'rb'));
+ print_r($result);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 设置header和meta
+try {
+ $result = $cosClient->Upload(
+ $bucket= $bucket,
+ $key = $key,
+ $body = fopen($local_path, 'rb'),
+ $options = array(
+ 'ACL' => 'string',
+ 'CacheControl' => 'string',
+ 'ContentDisposition' => 'string',
+ 'ContentEncoding' => 'string',
+ 'ContentLanguage' => 'string',
+ 'ContentLength' => integer,
+ 'ContentType' => 'string',
+ 'Expires' => 'mixed type: string (date format)|int (unix timestamp)|\DateTime',
+ 'GrantFullControl' => 'string',
+ 'GrantRead' => 'string',
+ 'GrantWrite' => 'string',
+ 'Metadata' => array(
+ 'string' => 'string',
+ ),
+ 'StorageClass' => 'string'));
+ print_r($result);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+```
+
+### 下载文件
+* 使用getObject接口下载文件
+* 使用getObjectUrl接口获取文件下载URL
+```php
+# 下载文件
+## getObject(下载文件)
+### 下载到内存
+//bucket 的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key));
+ echo($result['Body']);
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 下载到本地
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'SaveAs' => $local_path));
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 指定下载范围
+/*
+ * Range 字段格式为 'bytes=a-b'
+ */
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Range' => 'bytes=0-10',
+ 'SaveAs' => $local_path));
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+### 设置返回header
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'ResponseCacheControl' => 'string',
+ 'ResponseContentDisposition' => 'string',
+ 'ResponseContentEncoding' => 'string',
+ 'ResponseContentLanguage' => 'string',
+ 'ResponseContentType' => 'string',
+ 'ResponseExpires' => 'mixed type: string (date format)|int (unix timestamp)|\DateTime',
+ 'SaveAs' => $local_path));
+} catch (\Exception $e) {
+ echo "$e\n";
+}
+
+## getObjectUrl(获取文件UrL)
+try {
+ $signedUrl = $cosClient->getObjectUrl($bucket, $key, '+10 minutes');
+ echo $signedUrl;
+} catch (\Exception $e) {
+ print_r($e);
+}
+```
diff --git a/app/Common/extend/tencentcloud/composer.json b/app/Common/extend/tencentcloud/composer.json
new file mode 100755
index 0000000..bdeff53
--- /dev/null
+++ b/app/Common/extend/tencentcloud/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "qcloud/cos-sdk-v5",
+ "description": "PHP SDK for QCloud COS",
+ "keywords": [
+ "qcloud", "cos", "php"
+ ],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "yaozongyou",
+ "email": "yaozongyou@vip.qq.com"
+ },
+ {
+ "name": "lewzylu",
+ "email": "327874225@qq.com"
+ }
+ ],
+ "autoload": {
+ "psr-0": {
+ "Qcloud\\Cos\\": "src/"
+ }
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "guzzle/guzzle": "~3.7"
+ }
+}
diff --git a/app/Common/extend/tencentcloud/phpunit.xml b/app/Common/extend/tencentcloud/phpunit.xml
new file mode 100755
index 0000000..3c7a4c1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/phpunit.xml
@@ -0,0 +1,7 @@
+
+
+
+ src/Qcloud/Cos/Tests
+
+
+
diff --git a/app/Common/extend/tencentcloud/sample.php b/app/Common/extend/tencentcloud/sample.php
new file mode 100755
index 0000000..4c98c86
--- /dev/null
+++ b/app/Common/extend/tencentcloud/sample.php
@@ -0,0 +1,824 @@
+ 'COS_REGION', #地域,如ap-guangzhou,ap-beijing-1
+ 'credentials' => array(
+ 'secretId' => 'COS_KEY',
+ 'secretKey' => 'COS_SECRET',
+ ),
+));
+
+// 若初始化 Client 时未填写 appId,则 bucket 的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
+$bucket = 'test2-1252448703';
+$key = 'a.txt';
+$local_path = "E:/a.txt";
+
+# 上传文件
+## putObject(上传接口,最大支持上传5G文件)
+### 上传内存中的字符串
+try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => 'Hello World!'
+ ));
+ print_r($result);
+ # 可以直接通过$result读出返回结果
+ echo ($result['ETag']);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 上传文件流
+try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => fopen($local_path, 'rb')
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 设置header和meta
+try {
+ $result = $cosClient->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => fopen($local_path, 'rb'),
+ 'ACL' => 'string',
+ 'CacheControl' => 'string',
+ 'ContentDisposition' => 'string',
+ 'ContentEncoding' => 'string',
+ 'ContentLanguage' => 'string',
+ 'ContentLength' => integer,
+ 'cONTENTType' => 'string',
+ 'Expires' => 'mixed type: string (date format)|int (unix timestamp)|\DateTime',
+ 'GrantFullControl' => 'string',
+ 'GrantRead' => 'string',
+ 'GrantWrite' => 'string',
+ 'Metadata' => array(
+ 'string' => 'string',
+ ),
+ 'StorageClass' => 'string'
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## Upload(高级上传接口,默认使用分块上传最大支持50T)
+### 上传内存中的字符串
+try {
+ $result = $cosClient->upload(
+ $bucket = $bucket,
+ $key = $key,
+ $body = 'Hello World!'
+ );
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 上传文件流
+try {
+ $result = $cosClient->upload(
+ $bucket = $bucket,
+ $key = $key,
+ $body = fopen($local_path, 'rb')
+ );
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 设置header和meta
+try {
+ $result = $cosClient->upload(
+ $bucket = $bucket,
+ $key = $key,
+ $body = fopen($local_path, 'rb'),
+ $options = array(
+ 'ACL' => 'string',
+ 'CacheControl' => 'string',
+ 'ContentDisposition' => 'string',
+ 'ContentEncoding' => 'string',
+ 'ContentLanguage' => 'string',
+ 'ContentLength' => integer,
+ 'ContentType' => 'string',
+ 'Expires' => 'mixed type: string (date format)|int (unix timestamp)|\DateTime',
+ 'GrantFullControl' => 'string',
+ 'GrantRead' => 'string',
+ 'GrantWrite' => 'string',
+ 'Metadata' => array(
+ 'string' => 'string',
+ ),
+ 'StorageClass' => 'string'
+ )
+ );
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## 预签名上传createPresignedUrl
+## 获取带有签名的url
+### 简单上传预签名
+try {
+ #此处可以替换为其他上传接口
+ $command = $cosClient->getCommand('putObject', array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => '', //Body可以任意
+ ));
+ $signedUrl = $command->createPresignedUrl('+10 minutes');
+ echo ($signedUrl);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 分块上传预签名
+try {
+ #此处可以替换为其他上传接口
+ $command = $cosClient->getCommand('uploadPart', array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'UploadId' => '',
+ 'PartNumber' => '1',
+ 'Body' => '', //Body可以任意
+ ));
+ $signedUrl = $command->createPresignedUrl('+10 minutes');
+ echo ($signedUrl);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 获取签名
+try {
+ #此处可以替换为其他上传接口
+ $command = $cosClient->getCommand('putObject', array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => '', //Body可以任意
+ ));
+ $signedUrl = $command->createAuthorization('+10 minutes');
+ echo ($signedUrl);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+
+# 下载文件
+## getObject(下载文件)
+### 下载到内存
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key
+ ));
+ echo $result['Body'];
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 下载到本地
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'SaveAs' => $local_path
+ ));
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 指定下载范围
+/*
+ * Range 字段格式为 'bytes=a-b'
+ */
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Range' => 'bytes=0-10',
+ 'SaveAs' => $local_path
+ ));
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 设置返回header
+try {
+ $result = $cosClient->getObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'ResponseCacheControl' => 'string',
+ 'ResponseContentDisposition' => 'string',
+ 'ResponseContentEncoding' => 'string',
+ 'ResponseContentLanguage' => 'string',
+ 'ResponseContentType' => 'string',
+ 'ResponseExpires' => 'mixed type: string (date format)|int (unix timestamp)|\DateTime',
+ 'SaveAs' => $local_path
+ ));
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## getObjectUrl(获取文件UrL)
+try {
+ $signedUrl = $cosClient->getObjectUrl($bucket, $key, '+10 minutes');
+ echo $signedUrl;
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 删除object
+## deleteObject
+try {
+ $result = $cosClient->deleteObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'VersionId' => 'string'
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 删除多个object
+## deleteObjects
+try {
+ $result = $cosClient->deleteObjects(array(
+ 'Bucket' => 'string',
+ 'Objects' => array(
+ array(
+ 'Key' => $key,
+ 'VersionId' => 'string',
+ ),
+ // ... repeated
+ ),
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 获取object信息
+## headObject
+/*
+ * 可代替isObjectExist接口,查询object是否存在
+ */
+try {
+ $result = $cosClient->headObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => '11',
+ 'VersionId' => '111',
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 获取bucket列表
+## listBuckets
+try {
+ $result = $cosClient->listBuckets();
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 创建bucket
+## createBucket
+try {
+ $result = $cosClient->createBucket(array('Bucket' => $bucket));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 删除bucket
+## deleteBucket
+try {
+ $result = $cosClient->deleteBucket(array(
+ 'Bucket' => $bucket
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 获取bucket信息
+## headBucket
+/*
+ * 可代替isBucketExist接口,查询bucket是否存在
+ */
+try {
+ $result = $cosClient->headBucket(array(
+ 'Bucket' => $bucket
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 列出bucket下的object
+## listObjects
+### 列出所有object
+/*
+ * 该接口一次最多列出1000个,需要列出所有请参考其他服务中的清空并删除bucket接口
+ */
+try {
+ $result = $cosClient->listObjects(array(
+ 'Bucket' => $bucket
+ ));
+ foreach ($result['Contents'] as $rt) {
+ print_r($rt);
+ }
+} catch (\Exception $e) {
+ echo($e);
+}
+
+### 列出带有前缀的object
+try {
+ $result = $cosClient->listObjects(array(
+ 'Bucket' => $bucket,
+ 'Prefix' => 'string'
+ ));
+ foreach ($result['Contents'] as $rt) {
+ print_r($rt);
+ }
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 获取bucket地域
+## getBucketLocation
+try {
+ $result = $cosClient->getBucketLocation(array(
+ 'Bucket' => 'lewzylu02',
+ ));
+} catch (\Exception $e) {
+ echo($e);
+};
+
+# 多版本相关
+## putBucketVersioning(开启关闭某个bucket的多版本)
+try {
+ $result = $cosClient->putBucketVersioning(array(
+ 'Bucket' => $bucket,
+ 'Status' => 'Enabled'
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## ListObjectVersions(列出多版本object)
+/*
+ * 同名文件会出现多个版本
+ */
+try {
+ $result = $cosClient->listObjectVersions(array(
+ 'Bucket' => $bucket,
+ 'Prefix' => 'string'
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## getBucketVersioning(获取某个bucket多版本属性)
+try {
+ $result = $cosClient->getBucketVersioning(
+ array('Bucket' => $bucket));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# ACL相关
+## PutBucketAcl(设置bucketACL)
+try {
+ $result = $cosClient->putBucketAcl(array(
+ 'Bucket' => $bucket,
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'ID' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/3210232098:uin/3210232098',
+ 'ID' => 'qcs::cam::uin/3210232098:uin/3210232098',
+ )));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## getBucketAcl(获取bucketACL)
+try {
+ $result = $cosClient->getBucketAcl(array(
+ 'Bucket' => $bucket));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## putObjectAcl(设置objectACL)
+try {
+ $result = $cosClient->putObjectAcl(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'ID' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/3210232098:uin/3210232098',
+ 'ID' => 'qcs::cam::uin/3210232098:uin/3210232098',
+ )));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## GetObjectAcl(获取objectACL)
+try {
+ $result = $cosClient->getObjectAcl(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 生命周期相关
+## putBucketLifecycle(设置bucket生命周期)
+try {
+ $result = $cosClient->putBucketLifecycle(array(
+ 'Bucket' => $bucket,
+ 'Rules' => array(
+ array(
+ 'Expiration' => array(
+ 'Days' => 1000,
+ ),
+ 'ID' => 'id1',
+ 'Filter' => array(
+ 'Prefix' => 'documents/',
+ ),
+ 'Status' => 'Enabled',
+ 'Transitions' => array(
+ array(
+ 'Days' => 200,
+ 'StorageClass' => 'NEARLINE'),
+ ),
+ ),
+ )));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## getBucketLifecycle(获取bucket生命周期)
+try {
+ $result = $cosClient->getBucketLifecycle(array(
+ 'Bucket' => $bucket,
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## deleteBucketLifecycle(删除bucket生命周期)
+try {
+ $result = $cosClient->deleteBucketLifecycle(array(
+ 'Bucket' => $bucket,
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 跨域相关
+## putBucketCors(设置bucket跨域)
+try {
+ $result = $cosClient->putBucketCors(array(
+ 'Bucket' => $bucket,
+ 'CORSRules' => array(
+ array(
+ 'ID' => '1234',
+ 'AllowedHeaders' => array('*'),
+ 'AllowedMethods' => array('PUT'),
+ 'AllowedOrigins' => array('http://www.qq.com'),
+ ),
+ ),
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## getBucketCors(获取bucket跨域信息)
+try {
+ $result = $cosClient->getBucketCors(array());
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## deleteBucketCors(删除bucket跨域)
+try {
+ $result = $cosClient->deleteBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $bucket,
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 跨区域复制相关
+## PutBucketReplication(设置bucket跨区域复制)
+### 注意:目标bucket和源bucket都需要开启多版本
+try {
+ $result = $cosClient->putBucketReplication(array(
+ 'Bucket' => $bucket,
+ 'Role' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'Rules'=>array(
+ array(
+ 'Status' => 'Enabled',
+ 'ID' => 'string',
+ 'Prefix' => 'string',
+ 'Destination' => array(
+ 'Bucket' => 'qcs::cos:ap-guangzhou::lewzylu01-1252448703',
+ 'StorageClass' => 'standard',
+ ),
+ // ...repeated
+ ),
+ ),
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## GetBucketReplication(获取bucket跨区域复制信息)
+try {
+ $result = $cosClient->getBucketReplication(array(
+ 'Bucket' => $bucket
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## DeleteBucketReplication(删除bucket跨区域复制信息)
+try {
+ $result = $cosClient->deleteBucketReplication(array(
+ 'Bucket' => $bucket
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 回调相关
+## PutBucketNotification
+try {
+ $result = $cosClient->putBucketNotification(array(
+ "Bucket" => $bucket,
+ "CloudFunctionConfigurations"=> array(
+ array(
+ "Id" => "test-1",
+ "Filter" => array(
+ "Key" => array(
+ "FilterRules" => array(
+ array(
+ "Name" => "Prefix",
+ "Value" => "111"
+ ),
+ array(
+ "Name" => "Suffix",
+ "Value" => "111"
+ ),
+ ),
+ )
+ ),
+ "CloudFunction" => "qcs:0:video:sh:appid/1253125191:video/10010",
+ "Events" => array(
+ 'Event' => "cos:ObjectCreated:*"
+ )
+ ),
+ array(
+ "Id" => "test-2",
+ "Filter" => array(
+ "Key" => array(
+ "FilterRules" => array(
+ array(
+ "Name" => "Prefix",
+ "Value" => "111"
+ ),
+ array(
+ "Name" => "Suffix",
+ "Value" => "111"
+ ),
+ ),
+ )
+ ),
+ "CloudFunction" => "qcs:0:video:sh:appid/1253125191:video/10010",
+ "Events" => array(
+ 'Event' => "cos:ObjectRemove:*"
+ )
+ ),
+ ))
+ );
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## GetBucketNotification
+try {
+ $result = $cosClient->getBucketNotification(array(
+ 'Bucket' => $bucket
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 复制
+## copyobject(简单复制)
+/*
+ * 将{bucket},{region},{cos_path},{versionId}替换成复制源的真实信息
+ */
+try {
+ $result = $cosClient->copyObject(array(
+ 'Bucket' => $bucket,
+ 'CopySource' => '{bucket}.cos.{region}.myqcloud.com/{cos_path}?versionId={versionId}',
+ 'Key' => 'string',
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## Copy(分块并发复制)
+/*
+ * 将{bucket},{region},{cos_path},{versionId}替换成复制源的真实信息
+ */
+try {
+ $result = $cosClient->copy(
+ $bucket = $bucket,
+ $key = $key,
+ $copysource = '{bucket}.cos.{region}.myqcloud.com/{cos_path}',
+ $options = array('VersionId' => '{versionId}'
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 恢复归档文件
+## restoreObject
+try {
+ $result = $cosClient->restoreObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Days' => 7,
+ 'CASJobParameters' => array(
+ 'Tier' => 'Bulk',
+ ),
+ ));
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+# 其他服务
+## 列出某bucket下所有的object
+try {
+ $prefix = '';
+ $marker = '';
+ while (true) {
+ $result = $cosClient->listObjects(array(
+ 'Bucket' => $bucket,
+ 'Marker' => $marker,
+ 'MaxKeys' => 1000
+ ));
+ foreach ($result['Contents'] as $rt) {
+ print_r($rt['Key'] . " ");
+ /*
+ * 使用下面的代码可以删除全部object
+ */
+ // try {
+ // $result = $cosClient->deleteobjects(array(
+ // 'Bucket' => $bucket,
+ // 'Key' => $rt['Key']));
+ // print_r($result);
+ // } catch (\Exception $e) {
+ // echo($e);
+ // }
+ }
+ $marker = $result['NextMarker'];
+ if (!$result['IsTruncated']) {
+ break;
+ }
+ }
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## 删除所有因上传失败而产生的分块
+/*
+ * 可以清理掉因分块上传失败
+ */
+try {
+ while (true) {
+ $result = $cosClient->listMultipartUploads(
+ array('Bucket' => $bucket,
+ 'Prefix' => ''));
+ if (count($result['Uploads']) == 0) {
+ break;
+ }
+ foreach ($result['Uploads'] as $upload) {
+ try {
+ $rt = $cosClient->abortMultipartUpload(array(
+ 'Bucket' => $bucket,
+ 'Key' => $upload['Key'],
+ 'UploadId' => $upload['UploadId']
+ ));
+ print_r($rt);
+ } catch (\Exception $e) {
+ echo($e);
+ }
+ }
+ }
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## 分块上传断点重传
+/*
+ * 仅适用于分块上传失败的情况
+ * 需要填写上传失败的uploadId
+ */
+try {
+ $result = $cosClient->resumeUpload(
+ $bucket = $bucket,
+ $key = $key,
+ $body = fopen("E:/test.txt", 'rb'),
+ $uploadId = '152448808231afdf221eb558ab15d1e455d2afd025c5663936142fdf5614ebf6d1668e2eda'
+ );
+ print_r($result);
+} catch (\Exception $e) {
+ echo($e);
+}
+
+## 删除某些前缀的空bucket
+function startsWith($haystack, $needle)
+{
+ $length = strlen($needle);
+ return (substr($haystack, 0, $length) === $needle);
+}
+
+try {
+ $result = $cosClient->listBuckets();
+ foreach ($result['Buckets'] as $bucket) {
+ $region = $bucket['Location'];
+ $name = $bucket['Name'];
+ if (startsWith($name, 'lewzylu')) {
+ try {
+ $cosClient2 = new Qcloud\Cos\Client(array(
+ 'region' => $region,
+ 'credentials' => array(
+ //getenv为获取本地环境变量,请替换为真实密钥
+ 'secretId' => getenv('COS_KEY'),
+ 'secretKey' => getenv('COS_SECRET'))
+ ));
+ $rt = $cosClient2->deleteBucket(array('Bucket' => $name));
+ print_r($rt);
+ } catch (\Exception $e) {
+ }
+ }
+ }
+} catch (\Exception $e) {
+ echo($e);
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/BucketStyleListener.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/BucketStyleListener.php
new file mode 100755
index 0000000..a035d05
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/BucketStyleListener.php
@@ -0,0 +1,74 @@
+appId = $appId;
+ }
+
+ public static function getSubscribedEvents() {
+ return array('command.after_prepare' => array('onCommandAfterPrepare', -230));
+ }
+
+ /**
+ * Change from path style to host style.
+ * @param Event $event Event emitted.
+ */
+ public function onCommandAfterPrepare(Event $event) {
+ $command = $event['command'];
+ $bucket = $command['Bucket'];
+ $request = $command->getRequest();
+
+ if ($command->getName() == 'ListBuckets')
+ {
+ $request->setHost('service.cos.myqcloud.com');
+ return ;
+ }
+ if ($key = $command['Key']) {
+ // Modify the command Key to account for the {/Key*} explosion into an array
+ if (is_array($key)) {
+ $command['Key'] = $key = implode('/', $key);
+ }
+ }
+ $request->setHeader('Date', gmdate('D, d M Y H:i:s T'));
+ $request->setPath(preg_replace("#^/{$bucket}#", '', $request->getPath()));
+
+ if ($this->appId != null && endWith($bucket,'-'.$this->appId) == False)
+ {
+ $bucket = $bucket.'-'.$this->appId;
+ }
+ // Set the key and bucket on the request
+ $request->getParams()->set('bucket', $bucket)->set('key', $key);
+
+ //$request->setPath(urldecode($request->getPath()));
+ // Switch to virtual hosted bucket
+ $request->setHost($bucket. '.' . $request->getHost());
+ if (!$bucket) {
+ $request->getParams()->set('cos.resource', '/');
+ } else {
+ // Bucket style needs a trailing slash
+ $request->getParams()->set(
+ 'cos.resource',
+ '/' . rawurlencode($bucket) . ($key ? ('/' . Client::encodeKey($key)) : '/')
+ );
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Client.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Client.php
new file mode 100755
index 0000000..e6dd11f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Client.php
@@ -0,0 +1,270 @@
+region = $config['region'];
+ $regionmap = array('cn-east'=>'ap-shanghai',
+ 'cn-sorth'=>'ap-guangzhou',
+ 'cn-north'=>'ap-beijing-1',
+ 'cn-south-2'=>'ap-guangzhou-2',
+ 'cn-southwest'=>'ap-chengdu',
+ 'sg'=>'ap-singapore',
+ 'tj'=>'ap-beijing-1',
+ 'bj'=>'ap-beijing',
+ 'sh'=>'ap-shanghai',
+ 'gz'=>'ap-guangzhou',
+ 'cd'=>'ap-chengdu',
+ 'sgp'=>'ap-singapore',);
+ $this->region = isset($regionmap[$this->region]) ? $regionmap[$this->region] : $this->region;
+ $this->credentials = $config['credentials'];
+ $this->appId = isset($config['credentials']['appId']) ? $config['credentials']['appId'] : null;
+ $this->secretId = $config['credentials']['secretId'];
+ $this->secretKey = $config['credentials']['secretKey'];
+ $this->token = isset($config['credentials']['token']) ? $config['credentials']['token'] : null;
+ $this->timeout = isset($config['timeout']) ? $config['timeout'] : 3600;
+ $this->connect_timeout = isset($config['connect_timeout']) ? $config['connect_timeout'] : 3600;
+ $this->signature = new signature($this->secretId, $this->secretKey);
+ parent::__construct(
+ 'http://cos.' . $this->region . '.myqcloud.com/', // base url
+ array('request.options' => array('timeout' => $this->timeout, 'connect_timeout' => $this->connect_timeout),
+ )); // show curl verbose or not
+
+ $desc = ServiceDescription::factory(Service::getService());
+ $this->setDescription($desc);
+ $this->setUserAgent('cos-php-sdk-v5.' . Client::VERSION, true);
+
+ $this->addSubscriber(new ExceptionListener());
+ $this->addSubscriber(new Md5Listener($this->signature));
+ $this->addSubscriber(new TokenListener($this->token));
+ $this->addSubscriber(new SignatureListener($this->secretId, $this->secretKey));
+ $this->addSubscriber(new BucketStyleListener($this->appId));
+
+ // Allow for specifying bodies with file paths and file handles
+ $this->addSubscriber(new UploadBodyListener(array('PutObject', 'UploadPart')));
+ }
+ public function set_config($config) {
+ $this->region = $config['region'];
+ $regionmap = array('cn-east'=>'ap-shanghai',
+ 'cn-sorth'=>'ap-guangzhou',
+ 'cn-north'=>'ap-beijing-1',
+ 'cn-south-2'=>'ap-guangzhou-2',
+ 'cn-southwest'=>'ap-chengdu',
+ 'sg'=>'ap-singapore',
+ 'tj'=>'ap-beijing-1',
+ 'bj'=>'ap-beijing',
+ 'sh'=>'ap-shanghai',
+ 'gz'=>'ap-guangzhou',
+ 'cd'=>'ap-chengdu',
+ 'sgp'=>'ap-singapore',);
+ $this->region = isset($regionmap[$this->region]) ? $regionmap[$this->region] : $this->region;
+ $this->credentials = $config['credentials'];
+ $this->appId = isset($config['credentials']['appId']) ? $config['credentials']['appId'] : null;
+ $this->secretId = $config['credentials']['secretId'];
+ $this->secretKey = $config['credentials']['secretKey'];
+ $this->token = isset($config['credentials']['token']) ? $config['credentials']['token'] : null;
+ $this->timeout = isset($config['timeout']) ? $config['timeout'] : 3600;
+ $this->connect_timeout = isset($config['connect_timeout']) ? $config['connect_timeout'] : 3600;
+ $this->signature = new signature($this->secretId, $this->secretKey);
+ parent::__construct(
+ 'http://cos.' . $this->region . '.myqcloud.com/', // base url
+ array('request.options' => array('timeout' => $this->timeout, 'connect_timeout' => $this->connect_timeout),
+ )); // show curl verbose or not
+ }
+ public function __destruct() {
+ }
+
+ public function __call($method, $args) {
+ return parent::__call(ucfirst($method), $args);
+ }
+ public function createAuthorization(RequestInterface $request, $expires)
+ {
+ if ($request->getClient() !== $this) {
+ throw new InvalidArgumentException('The request object must be associated with the client. Use the '
+ . '$client->get(), $client->head(), $client->post(), $client->put(), etc. methods when passing in a '
+ . 'request object');
+ }
+ return $this->signature->createAuthorization($request, $expires);
+ }
+ public function createPresignedUrl(RequestInterface $request, $expires)
+ {
+ if ($request->getClient() !== $this) {
+ throw new InvalidArgumentException('The request object must be associated with the client. Use the '
+ . '$client->get(), $client->head(), $client->post(), $client->put(), etc. methods when passing in a '
+ . 'request object');
+ }
+ return $this->signature->createPresignedUrl($request, $expires);
+ }
+ public function getObjectUrl($bucket, $key, $expires = null, array $args = array())
+ {
+ $command = $this->getCommand('GetObject', $args + array('Bucket' => $bucket, 'Key' => $key));
+
+ if ($command->hasKey('Scheme')) {
+ $scheme = $command['Scheme'];
+ $request = $command->remove('Scheme')->prepare()->setScheme($scheme)->setPort(null);
+ } else {
+ $request = $command->prepare();
+ }
+
+ return $expires ? $this->createPresignedUrl($request, $expires) : $request->getUrl();
+ }
+ public function Upload($bucket, $key, $body, $options = array()) {
+ $body = EntityBody::factory($body);
+ $options = Collection::fromConfig(array_change_key_case($options), array(
+ 'min_part_size' => MultipartUpload::MIN_PART_SIZE,
+ 'params' => $options));
+ if ($body->getSize() < $options['min_part_size']) {
+ // Perform a simple PutObject operation
+ $rt = $this->putObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => $body,
+ ) + $options['params']);
+
+ $rt['Location'] = $rt['ObjectURL'];
+ unset($rt['ObjectURL']);
+ }
+ else {
+ $multipartUpload = new MultipartUpload($this, $body, $options['min_part_size'], array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => $body,
+ ) + $options['params']);
+
+ $rt = $multipartUpload->performUploading();
+ }
+ return $rt;
+ }
+
+ public function resumeUpload($bucket, $key, $body, $uploadId, $options = array()) {
+ $body = EntityBody::factory($body);
+ $options = Collection::fromConfig(array_change_key_case($options), array(
+ 'min_part_size' => MultipartUpload::MIN_PART_SIZE,
+ 'params' => $options));
+ $multipartUpload = new MultipartUpload($this, $body, $options['min_part_size'], array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'Body' => $body,
+ 'UploadId' => $uploadId,
+ ) + $options['params']);
+
+ $rt = $multipartUpload->resumeUploading();
+ return $rt;
+ }
+
+ public function Copy($bucket, $key, $copysource, $options = array()) {
+
+ $options = Collection::fromConfig(array_change_key_case($options), array(
+ 'min_part_size' => Copy::MIN_PART_SIZE,
+ 'params' => $options));
+ $sourcelistdot = explode('.',$copysource);
+ $sourcelistline = explode('-',$sourcelistdot[0]);
+ $sourceappid = array_pop($sourcelistline);
+ $sourcebucket = implode('-', $sourcelistline);
+ $sourceregion = $sourcelistdot[2];
+ $sourcekey = substr(strstr($copysource,'/'),1);
+ $sourceversion = "";
+ $cosClient = new Client(array('region' => $sourceregion,
+ 'credentials'=> array(
+ 'appId' => $sourceappid,
+ 'secretId' => $this->secretId,
+ 'secretKey' => $this->secretKey)));
+ if (!key_exists('VersionId',$options['params'])) {
+ $sourceversion = "";
+ }
+ else{
+ $sourceversion = $options['params']['VersionId'];
+ }
+ $rt = $cosClient->headObject(array('Bucket'=>$sourcebucket,
+ 'Key'=>$sourcekey,
+ 'VersionId'=>$sourceversion));
+ $contentlength =$rt['ContentLength'];
+
+ if ($contentlength < $options['min_part_size']) {
+ return $this->copyObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key,
+ 'CopySource' => $copysource."?versionId=".$sourceversion,
+ ) + $options['params']);
+ }
+ $copy = new Copy($this, $contentlength, $copysource."?versionId=".$sourceversion, $options['min_part_size'], array(
+ 'Bucket' => $bucket,
+ 'Key' => $key
+ ) + $options['params']);
+
+ return $copy->copy();
+ }
+
+ /**
+ * Determines whether or not a bucket exists by name
+ *
+ * @param string $bucket The name of the bucket
+ * @param bool $accept403 Set to true if 403s are acceptable
+ * @param array $options Additional options to add to the executed command
+ *
+ * @return bool
+ */
+ public function doesBucketExist($bucket, $accept403 = true, array $options = array())
+ {
+ try {
+ $this->HeadBucket(array(
+ 'Bucket' => $bucket));
+ return True;
+ }catch (\Exception $e){
+ return False;
+ }
+ }
+
+ /**
+ * Determines whether or not an object exists by name
+ *
+ * @param string $bucket The name of the bucket
+ * @param string $key The key of the object
+ * @param array $options Additional options to add to the executed command
+ *
+ * @return bool
+ */
+ public function doesObjectExist($bucket, $key, array $options = array())
+ {
+ try {
+ $this->HeadObject(array(
+ 'Bucket' => $bucket,
+ 'Key' => $key));
+ return True;
+ }catch (\Exception $e){
+ return False;
+ }
+ }
+ public static function encodeKey($key) {
+ return $key;
+ return str_replace('%2F', '/', rawurlencode($key));
+ }
+
+ public static function explodeKey($key) {
+ // Remove a leading slash if one is found
+ //return explode('/', $key && $key[0] == '/' ? substr($key, 1) : $key);
+ return $key;
+ return ltrim($key, "/");
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Command.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Command.php
new file mode 100755
index 0000000..647bb52
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Command.php
@@ -0,0 +1,39 @@
+client->createPresignedUrl($this->prepare(), $expires);
+ }
+ public function createAuthorization($expires)
+ {
+ return $this->client->createAuthorization($this->prepare(), $expires);
+ }
+
+ protected function process() {
+ parent::process();
+ // Set the GetObject URL if using the PutObject operation
+ if ($this->result instanceof Model && $this->getName() == 'PutObject') {
+ $request = $this->getRequest();;
+ $this->result->set('ObjectURL', $request->getUrl());
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Copy.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Copy.php
new file mode 100755
index 0000000..06d464a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Copy.php
@@ -0,0 +1,140 @@
+client = $client;
+ $this->source = $source;
+ $this->options = $options;
+ $this->size = $contentlength;
+ $this->partSize = $this->calculatePartSize($minPartSize);
+ $this->concurrency = isset($options['concurrency']) ? $options['concurrency'] : 10;
+ $this->retry = isset($options['retry']) ? $options['retry'] : 5;
+ }
+ public function copy() {
+ $uploadId= $this->initiateMultipartUpload();
+ for ($i = 0; $i < 5; $i += 1) {
+ $rt = $this->uploadParts($uploadId);
+ if ($rt == 0) {
+ break;
+ }
+ sleep(1 << $i);
+ }
+ return $this->client->completeMultipartUpload(array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'UploadId' => $uploadId,
+ 'Parts' => $this->parts));
+
+ }
+ public function uploadParts($uploadId) {
+ $commands = array();
+ $offset = 0;
+ $partNumber = 1;
+ $partSize = $this->partSize;
+ $finishedNum = 0;
+ $this->parts = array();
+ for (;;) {
+
+ if ($offset + $partSize >= $this->size)
+ {
+ $partSize = $this->size - $offset;
+ }
+ $params = array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'UploadId' => $uploadId,
+ 'PartNumber' => $partNumber,
+ 'CopySource'=> $this->source,
+ 'CopySourceRange' => 'bytes='.((string)$offset).'-'.(string)($offset+$partSize - 1),
+ );
+ if(!isset($parts[$partNumber])) {
+ $commands[] = $this->client->getCommand('UploadPartCopy', $params);
+ }
+ if ($partNumber % $this->concurrency == 0) {
+ $this->client->execute($commands);
+ $commands = array();
+ }
+ ++$partNumber;
+ $offset += $partSize;
+ if ($this->size == $offset)
+ {
+ break;
+ }
+ }
+ if (!empty($commands)) {
+ $this->client->execute($commands);
+ }
+ try {
+ $marker = 0;
+ $finishedNum = 1;
+ while (true) {
+ $rt = $this->client->listParts(array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'PartNumberMarker' => $marker,
+ 'MaxParts' => 1000,
+ 'UploadId' => $uploadId));
+ if (!empty($rt['Parts'])) {
+ foreach ($rt['Parts'] as $part) {
+ $part = array('PartNumber' => $finishedNum, 'ETag' => $part['ETag']);
+ $this->parts[$finishedNum] = $part;
+ $finishedNum++;
+ }
+ }
+ $marker = $rt['NextPartNumberMarker'];
+ if (!$rt['IsTruncated']) {
+ break;
+ }
+ }
+ } catch (\Exception $e) {
+ echo($e);
+ }
+ if ($finishedNum == $partNumber) {
+ return 0;
+ } else {
+ return -1;
+ }
+
+ }
+
+
+ private function calculatePartSize($minPartSize)
+ {
+ $partSize = intval(ceil(($this->size / self::MAX_PARTS)));
+ $partSize = max($minPartSize, $partSize);
+ $partSize = min($partSize, self::MAX_PART_SIZE);
+ $partSize = max($partSize, self::MIN_PART_SIZE);
+
+ return $partSize;
+ }
+
+ private function initiateMultipartUpload() {
+ $result = $this->client->createMultipartUpload($this->options);
+ return $result['UploadId'];
+ }
+
+}
+function partUploadCopy($client, $params) {
+ $rt = $client->uploadPartCopy($params);
+// $part = array('PartNumber' => $params['PartNumber'], 'ETag' => $rt['ETag']);
+ $rt['PartNumber'] = $params['PartNumber'];
+ return $rt;
+}
\ No newline at end of file
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Exception/BucketAlreadyExistsException.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Exception/BucketAlreadyExistsException.php
new file mode 100755
index 0000000..08de5ac
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Exception/BucketAlreadyExistsException.php
@@ -0,0 +1,5 @@
+exceptionCode = $code;
+ }
+
+ /**
+ * Get the exception code
+ *
+ * @return string|null
+ */
+ public function getExceptionCode() {
+ return $this->exceptionCode;
+ }
+
+ /**
+ * Set the exception type
+ *
+ * @param string $type Exception type
+ */
+ public function setExceptionType($type) {
+ $this->exceptionType = $type;
+ }
+
+ /**
+ * Get the exception type (one of client or server)
+ *
+ * @return string|null
+ */
+ public function getExceptionType() {
+ return $this->exceptionType;
+ }
+
+ /**
+ * Set the request ID
+ *
+ * @param string $id Request ID
+ */
+ public function setRequestId($id) {
+ $this->requestId = $id;
+ }
+
+ /**
+ * Get the Request ID
+ *
+ * @return string|null
+ */
+ public function getRequestId() {
+ return $this->requestId;
+ }
+
+ /**
+ * Set the associated response
+ *
+ * @param Response $response Response
+ */
+ public function setResponse(Response $response) {
+ $this->response = $response;
+ }
+
+ /**
+ * Get the associated response object
+ *
+ * @return Response|null
+ */
+ public function getResponse() {
+ return $this->response;
+ }
+
+ /**
+ * Set the associated request
+ *
+ * @param RequestInterface $request
+ */
+ public function setRequest(RequestInterface $request) {
+ $this->request = $request;
+ }
+
+ /**
+ * Get the associated request object
+ *
+ * @return RequestInterface|null
+ */
+ public function getRequest() {
+ return $this->request;
+ }
+
+ /**
+ * Get the status code of the response
+ *
+ * @return int|null
+ */
+ public function getStatusCode() {
+ return $this->response ? $this->response->getStatusCode() : null;
+ }
+
+ /**
+ * Cast to a string
+ *
+ * @return string
+ */
+ public function __toString() {
+ $message = get_class($this) . ': '
+ . 'Cos Error Code: ' . $this->getExceptionCode() . ', '
+ . 'Status Code: ' . $this->getStatusCode() . ', '
+ . 'Cos Request ID: ' . $this->getRequestId() . ', '
+ . 'Cos Error Type: ' . $this->getExceptionType() . ', '
+ . 'Cos Error Message: ' . $this->getMessage();
+
+ // Add the User-Agent if available
+ if ($this->request) {
+ $message .= ', ' . 'User-Agent: ' . $this->request->getHeader('User-Agent');
+ }
+
+ return $message;
+ }
+
+ /**
+ * Get the request ID of the error. This value is only present if a
+ * response was received, and is not present in the event of a networking
+ * error.
+ *
+ * Same as `getRequestId()` method, but matches the interface for SDKv3.
+ *
+ * @return string|null Returns null if no response was received
+ */
+ public function getCosRequestId() {
+ return $this->requestId;
+ }
+
+ /**
+ * Get the Cos error type.
+ *
+ * Same as `getExceptionType()` method, but matches the interface for SDKv3.
+ *
+ * @return string|null Returns null if no response was received
+ */
+ public function getCosErrorType() {
+ return $this->exceptionType;
+ }
+
+ /**
+ * Get the Cos error code.
+ *
+ * Same as `getExceptionCode()` method, but matches the interface for SDKv3.
+ *
+ * @return string|null Returns null if no response was received
+ */
+ public function getCosErrorCode() {
+ return $this->exceptionCode;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/ExceptionListener.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/ExceptionListener.php
new file mode 100755
index 0000000..a7c0b69
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/ExceptionListener.php
@@ -0,0 +1,69 @@
+parser = new ExceptionParser();
+ $this->defaultException = 'Qcloud\Cos\Exception\ServiceResponseException';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getSubscribedEvents() {
+ return array('request.error' => array('onRequestError', -1));
+ }
+
+ /**
+ * Throws a more meaningful request exception if available
+ *
+ * @param Event $event Event emitted
+ */
+ public function onRequestError(Event $event) {
+ $e = $this->fromResponse($event['request'], $event['response']);
+ $event->stopPropagation();
+ throw $e;
+ }
+
+ public function fromResponse(RequestInterface $request, Response $response) {
+ $parts = $this->parser->parse($request, $response);
+
+ $className = 'Qcloud\\Cos\\Exception\\' . $parts['code'];
+ if (substr($className, -9) !== 'Exception') {
+ $className .= 'Exception';
+ }
+
+ $className = class_exists($className) ? $className : $this->defaultException;
+
+ return $this->createException($className, $request, $response, $parts);
+ }
+
+ protected function createException($className, RequestInterface $request, Response $response, array $parts) {
+ $class = new $className($parts['message']);
+
+ if ($class instanceof ServiceResponseException) {
+ $class->setExceptionCode($parts['code']);
+ $class->setExceptionType($parts['type']);
+ $class->setResponse($response);
+ $class->setRequest($request);
+ $class->setRequestId($parts['request_id']);
+ }
+
+ return $class;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/ExceptionParser.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/ExceptionParser.php
new file mode 100755
index 0000000..ab1cd9b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/ExceptionParser.php
@@ -0,0 +1,112 @@
+ null,
+ 'message' => null,
+ 'type' => $response->isClientError() ? 'client' : 'server',
+ 'request_id' => null,
+ 'parsed' => null
+ );
+
+ $body = $response->getBody(true);
+
+ if (!$body) {
+ $this->parseHeaders($request, $response, $data);
+ return $data;
+ }
+
+ try {
+ $xml = new \SimpleXMLElement($body);
+ $this->parseBody($xml, $data);
+ return $data;
+ } catch (\Exception $e) {
+ // Gracefully handle parse errors. This could happen when the
+ // server responds with a non-XML response (e.g., private beta
+ // services).
+ $data['code'] = 'PhpInternalXmlParseError';
+ $data['message'] = 'A non-XML response was received';
+ return $data;
+ }
+ }
+
+ /**
+ * Parses additional exception information from the response headers
+ *
+ * @param RequestInterface $request Request that was issued
+ * @param Response $response The response from the request
+ * @param array $data The current set of exception data
+ */
+ protected function parseHeaders(RequestInterface $request, Response $response, array &$data) {
+ $data['message'] = $response->getStatusCode() . ' ' . $response->getReasonPhrase();
+ if ($requestId = $response->getHeader('x-cos-request-id')) {
+ $data['request_id'] = $requestId;
+ $data['message'] .= " (Request-ID: $requestId)";
+ }
+
+ // Get the request
+ $status = $response->getStatusCode();
+ $method = $request->getMethod();
+
+ // Attempt to determine code for 403s and 404s
+ if ($status === 403) {
+ $data['code'] = 'AccessDenied';
+ } elseif ($method === 'HEAD' && $status === 404) {
+ $path = explode('/', trim($request->getPath(), '/'));
+ $host = explode('.', $request->getHost());
+ $bucket = (count($host) >= 4) ? $host[0] : array_shift($path);
+ $object = array_shift($path);
+
+ if ($bucket && $object) {
+ $data['code'] = 'NoSuchKey';
+ } elseif ($bucket) {
+ $data['code'] = 'NoSuchBucket';
+ }
+ }
+ }
+
+ /**
+ * Parses additional exception information from the response body
+ *
+ * @param \SimpleXMLElement $body The response body as XML
+ * @param array $data The current set of exception data
+ */
+ protected function parseBody(\SimpleXMLElement $body, array &$data) {
+ $data['parsed'] = $body;
+
+ $namespaces = $body->getDocNamespaces();
+ if (isset($namespaces[''])) {
+ // Account for the default namespace being defined and PHP not being able to handle it :(
+ $body->registerXPathNamespace('ns', $namespaces['']);
+ $prefix = 'ns:';
+ } else {
+ $prefix = '';
+ }
+
+ if ($tempXml = $body->xpath("//{$prefix}Code[1]")) {
+ $data['code'] = (string) $tempXml[0];
+ }
+
+ if ($tempXml = $body->xpath("//{$prefix}Message[1]")) {
+ $data['message'] = (string) $tempXml[0];
+ }
+
+ $tempXml = $body->xpath("//{$prefix}RequestId[1]");
+ if (empty($tempXml)) {
+ $tempXml = $body->xpath("//{$prefix}RequestID[1]");
+ }
+ if (isset($tempXml[0])) {
+ $data['request_id'] = (string) $tempXml[0];
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Md5Listener.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Md5Listener.php
new file mode 100755
index 0000000..9595600
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Md5Listener.php
@@ -0,0 +1,57 @@
+ 'onCommandAfterPrepare');
+ }
+
+ public function __construct(Signature $signature)
+ {
+ $this->signature = $signature;
+ }
+
+ public function onCommandAfterPrepare(Event $event)
+ {
+ $command = $event['command'];
+ $operation = $command->getOperation();
+
+ if ($operation->getData('contentMd5')) {
+ // Add the MD5 if it is required for all signers
+ $this->addMd5($command);
+ } elseif ($operation->hasParam('ContentMD5')) {
+ $value = $command['ContentMD5'];
+ // Add a computed MD5 if the parameter is set to true or if
+ // not using Signature V4 and the value is not set (null).
+ if ($value === true ||
+ ($value === null && !($this->signature instanceof SignatureV4))
+ ) {
+ $this->addMd5($command);
+ }
+ }
+ }
+
+ private function addMd5(CommandInterface $command)
+ {
+ $request = $command->getRequest();
+ $body = $request->getBody();
+ if ($body && $body->getSize() > 0) {
+ if (false !== ($md5 = $body->getContentMd5(true, true))) {
+ $request->setHeader('Content-MD5', $md5);
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/MultipartUpload.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/MultipartUpload.php
new file mode 100755
index 0000000..30a942d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/MultipartUpload.php
@@ -0,0 +1,132 @@
+client = $client;
+ $this->source = $source;
+ $this->options = $options;
+ $this->partSize = $this->calculatePartSize($minPartSize);
+ }
+
+ public function performUploading() {
+ $uploadId = $this->initiateMultipartUpload();
+
+ $partNumber = 1;
+ $parts = array();
+ for (;;) {
+ if ($this->source->isConsumed()) {
+ break;
+ }
+
+ $body = new ReadLimitEntityBody($this->source, $this->partSize, $this->source->ftell());
+ if ($body->getContentLength() == 0) {
+ break;
+ }
+ $result = $this->client->uploadPart(array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'Body' => $body,
+ 'UploadId' => $uploadId,
+ 'PartNumber' => $partNumber));
+ if (md5($body) != substr($result['ETag'], 1, -1)){
+ throw new CosException("ETag check inconsistency");
+ }
+ $part = array('PartNumber' => $partNumber, 'ETag' => $result['ETag']);
+ array_push($parts, $part);
+ ++$partNumber;
+ }
+ try {
+ $rt = $this->client->completeMultipartUpload(array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'UploadId' => $uploadId,
+ 'Parts' => $parts));
+ } catch(\Exception $e){
+ throw $e;
+ }
+ return $rt;
+ }
+
+ public function resumeUploading() {
+ $uploadId = $this->options['UploadId'];
+ $rt = $this->client->ListParts(
+ array('UploadId' => $uploadId,
+ 'Bucket'=>$this->options['Bucket'],
+ 'Key'=>$this->options['Key']));
+ $parts = array();
+ $offset = $this->partSize;
+ if (count($rt['Parts']) > 0) {
+ foreach ($rt['Parts'] as $part) {
+ $parts[$part['PartNumber'] - 1] = array('PartNumber' => $part['PartNumber'], 'ETag' => $part['ETag']);
+ }
+ }
+ for ($partNumber = 1;;++$partNumber,$offset+=$body->getContentLength()) {
+ if ($this->source->isConsumed()) {
+ break;
+ }
+
+ $body = new ReadLimitEntityBody($this->source, $this->partSize, $this->source->ftell());
+ if ($body->getContentLength() == 0) {
+ break;
+ }
+
+
+ if (array_key_exists($partNumber-1,$parts)){
+
+ if (md5($body) != substr($parts[$partNumber-1]['ETag'], 1, -1)){
+ throw new CosException("ETag check inconsistency");
+ }
+ $body->setOffset($offset);
+ continue;
+ }
+
+ $result = $this->client->uploadPart(array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'Body' => $body,
+ 'UploadId' => $uploadId,
+ 'PartNumber' => $partNumber));
+ if (md5($body) != substr($result['ETag'], 1, -1)){
+ throw new CosException("ETag check inconsistency");
+ }
+ $parts[$partNumber-1] = array('PartNumber' => $partNumber, 'ETag' => $result['ETag']);
+
+ }
+ $rt = $this->client->completeMultipartUpload(array(
+ 'Bucket' => $this->options['Bucket'],
+ 'Key' => $this->options['Key'],
+ 'UploadId' => $uploadId,
+ 'Parts' => $parts));
+ return $rt;
+ }
+
+ private function calculatePartSize($minPartSize) {
+ $partSize = intval(ceil(($this->source->getContentLength() / self::MAX_PARTS)));
+ $partSize = max($minPartSize, $partSize);
+ $partSize = min($partSize, self::MAX_PART_SIZE);
+ $partSize = max($partSize, self::MIN_PART_SIZE);
+
+ return $partSize;
+ }
+
+ private function initiateMultipartUpload() {
+ $result = $this->client->createMultipartUpload($this->options);
+ return $result['UploadId'];
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Service.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Service.php
new file mode 100755
index 0000000..a2d0abb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Service.php
@@ -0,0 +1,4328 @@
+ 'Cos Service',
+ 'apiVersion' => 'V5',
+ 'description' => 'Cos V5 API Service',
+
+ 'operations' => array(
+ /**
+ 舍弃一个分块上传且删除已上传的分片块的方法.
+
+ COS 支持舍弃一个分块上传且删除已上传的分片块. 注意,已上传但是未终止的分片块会占用存储空间进 而产生存储费用.因此,建议及时完成分块上传 或者舍弃分块上传.
+
+ 关于分块上传的具体描述,请查看 https://cloud.tencent.com/document/product/436/14112.
+
+ 关于舍弃一个分块上传且删除已上传的分片块接口的描述,请查看 https://cloud.tencent.com/document/product/436/7740.
+
+ cos php SDK 中舍弃一个分块上传且删除已上传的分片块请求的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 AbortMultipfartUpload 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则操作成功。
+ */
+ 'AbortMultipartUpload' => array(
+ 'httpMethod' => 'DELETE',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'AbortMultipartUploadOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'UploadId' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'uploadId')),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified multipart upload does not exist.',
+ 'class' => 'NoSuchUploadException'))),
+ /**
+ 创建存储桶(Bucket)的方法.
+
+ 在开始使用 COS 时,需要在指定的账号下先创建一个 Bucket 以便于对象的使用和管理. 并指定 Bucket 所属的地域.创建 Bucket 的用户默认成为 Bucket 的持有者.若创建 Bucket 时没有指定访问权限,则默认 为私有读写(private)权限.
+
+ 可用地域,可以查看https://cloud.tencent.com/document/product/436/6224.
+
+ 关于创建 Bucket 描述,请查看 https://cloud.tencent.com/document/product/436/14106.
+
+ 关于创建存储桶(Bucket)接口的具体 描述,请查看 https://cloud.tencent.com/document/product/436/7738.
+
+ cos php SDK 中创建 Bucket的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 CreateBucket 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则创建成功。
+
+ 示例:
+ $result = $cosClient->createBucket(array('Bucket' => 'testbucket-1252448703'));
+ */
+ 'CreateBucket' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'CreateBucketOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'CreateBucketConfiguration')),
+ 'parameters' => array(
+ 'ACL' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-acl'),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri')),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.',
+ 'class' => 'BucketAlreadyExistsException'))),
+ /**
+ 完成整个分块上传的方法.
+
+ 当使用分块上传(uploadPart(UploadPartRequest))完对象的所有块以后,必须调用该 completeMultiUpload(CompleteMultiUploadRequest) 或者 completeMultiUploadAsync(CompleteMultiUploadRequest, CosXmlResultListener) 来完成整个文件的分块上传.且在该请求的 Body 中需要给出每一个块的 PartNumber 和 ETag,用来校验块的准 确性.
+
+ 分块上传适合于在弱网络或高带宽环境下上传较大的对象.SDK 支持自行切分对象并分别调用uploadPart(UploadPartRequest)上传各 个分块.
+
+ 关于分块上传的描述,请查看 https://cloud.tencent.com/document/product/436/14112.
+
+ 关于完成整个分片上传接口的描述,请查看 https://cloud.tencent.com/document/product/436/7742.
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 CompleteMultipartUpload 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则操作成功。
+
+ */
+ 'CompleteMultipartUpload' => array(
+ 'httpMethod' => 'POST',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'CompleteMultipartUploadOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'CompleteMultipartUpload')),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'Parts' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true),
+ 'items' => array(
+ 'name' => 'CompletedPart',
+ 'type' => 'object',
+ 'sentAs' => 'Part',
+ 'properties' => array(
+ 'ETag' => array(
+ 'type' => 'string'),
+ 'PartNumber' => array(
+ 'type' => 'numeric')))),
+ 'UploadId' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'uploadId'),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml'))),
+ 'CreateMultipartUpload' => array(
+ 'httpMethod' => 'POST',
+ 'uri' => '/{Bucket}{/Key*}?uploads',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'CreateMultipartUploadOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'CreateMultipartUploadRequest')),
+ 'parameters' => array(
+ 'ACL' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-acl',
+ ),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'CacheControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Cache-Control',
+ ),
+ 'ContentDisposition' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Disposition',
+ ),
+ 'ContentEncoding' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Encoding',
+ ),
+ 'ContentLanguage' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Language',
+ ),
+ 'ContentType' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Type',
+ ),
+ 'Expires' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ ),
+ 'GrantFullControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-full-control',
+ ),
+ 'GrantRead' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read',
+ ),
+ 'GrantReadACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read-acp',
+ ),
+ 'GrantWriteACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-write-acp',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'Metadata' => array(
+ 'type' => 'object',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-meta-',
+ 'additionalProperties' => array(
+ 'type' => 'string',
+ ),
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-storage-class',
+ ),
+ 'WebsiteRedirectLocation' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-website-redirect-location',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'ACP' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ))),
+ 'CopyObject' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'CopyObjectOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'CopyObjectRequest',
+ ),
+ ),
+ 'parameters' => array(
+ 'ACL' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-acl',
+ ),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'CacheControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Cache-Control',
+ ),
+ 'ContentDisposition' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Disposition',
+ ),
+ 'ContentEncoding' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Encoding',
+ ),
+ 'ContentLanguage' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Language',
+ ),
+ 'ContentType' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Type',
+ ),
+ 'CopySource' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source',
+ ),
+ 'CopySourceIfMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-match',
+ ),
+ 'CopySourceIfModifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-modified-since',
+ ),
+ 'CopySourceIfNoneMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-none-match',
+ ),
+ 'CopySourceIfUnmodifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-unmodified-since',
+ ),
+ 'Expires' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ ),
+ 'GrantFullControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-full-control',
+ ),
+ 'GrantRead' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read',
+ ),
+ 'GrantReadACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read-acp',
+ ),
+ 'GrantWriteACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-write-acp',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'Metadata' => array(
+ 'type' => 'object',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-meta-',
+ 'additionalProperties' => array(
+ 'type' => 'string',
+ ),
+ ),
+ 'MetadataDirective' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-metadata-directive',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-storage-class',
+ ),
+ 'WebsiteRedirectLocation' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-website-redirect-location',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key',
+ ),
+ 'CopySourceSSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-algorithm',
+ ),
+ 'CopySourceSSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key',
+ ),
+ 'CopySourceSSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key-MD5',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'ACP' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The source object of the COPY operation is not in the active tier.',
+ 'class' => 'ObjectNotInActiveTierErrorException',
+ ),
+ ),
+ ),
+ /**
+ 删除存储桶 (Bucket)的方法.
+
+ COS 目前仅支持删除已经清空的 Bucket,如果 Bucket 中仍有对象,将会删除失败. 因此,在执行删除 Bucket 前,需确保 Bucket 内已经没有对象. 删除 Bucket 时,还需要确保操作的身份已被授权该操作,并确认 传入了正确的存储桶名称和地域参数, 请参阅 putBucket(PutBucketRequest).
+
+ 关于删除 Bucket 的描述,请查看 https://cloud.tencent.com/document/product/436/14105.
+
+ 关于删除 Bucket 接口的具体描述,请查看https://cloud.tencent.com/document/product/436/7732.
+
+ cos php SDK 中删除 Bucket 的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 DeleteBucket 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,删除成功。
+
+ 示例:
+ $result = $cosClient->deleteBucket(array(
+ 'Bucket' => 'testbucket-1252448703'));
+ print_r($result);
+ */
+ 'DeleteBucket' => array(
+ 'httpMethod' => 'DELETE',
+ 'uri' => '/{Bucket}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'DeleteBucketOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'))),
+ /**
+ 删除跨域访问配置信息的方法.
+
+ 若是 Bucket 不需要支持跨域访问配置,可以调用此接口删除已配置的跨域访问信息. 跨域访问配置可以通过 putBucketCORS(PutBucketCORSRequest) 或者 putBucketCORSAsync(PutBucketCORSRequest, CosXmlResultListener) 方法来开启 Bucket 的跨域访问 支持.
+
+ 关于删除跨域访问配置信息接口的具体描述,请查看https://cloud.tencent.com/document/product/436/8283.
+
+ cos php SDK 中删除跨域访问配置信息的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 DeleteBucketCORS 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,删除成功。
+
+ 示例:
+ $result = $cosClient->deleteBucketCors(array(
+ // Bucket is required
+ 'Bucket' => 'testbucket-1252448703',
+ ));
+ */
+ 'DeleteBucketCors' => array(
+ 'httpMethod' => 'DELETE',
+ 'uri' => '/{Bucket}?cors',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'DeleteBucketCorsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ ),
+ ),
+ /**
+ 删除 COS 上单个对象的方法.
+
+ COS 支持直接删除一个或多个对象,当仅需要删除一个对象时,只需要提供对象的名称(即对象键)即可.
+
+ 关于删除 COS 上单个对象的具体描述,请查看 https://cloud.tencent.com/document/product/436/14119.
+
+ 关于删除 COS 上单个对象接口的具体描述,请查看 https://cloud.tencent.com/document/product/436/7743.
+
+ cos php SDK 中删除 COS 上单个对象请求的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 DeleteObject 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则删除成功。
+
+ 示例:
+ $result = $cosClient->deleteObject(array(
+ 'Bucket' => 'testbucket-1252448703',
+ 'Key' => '111.txt',
+ 'VersionId' => 'string'));
+ */
+ 'DeleteObject' => array(
+ 'httpMethod' => 'DELETE',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'DeleteObjectOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'MFA' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-mfa',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'versionId',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),)),
+ /**
+ 批量删除 COS 对象的方法.
+
+ COS 支持批量删除指定 Bucket 中 对象,单次请求最大支持批量删除 1000 个 对象. 请求中删除一个不存在的对象,仍然认为是成功的. 对于响应结果,COS提供 Verbose 和 Quiet 两种模式:Verbose 模式将返回每个对象的删除结果;Quiet 模式只返回删除报错的对象信息. 请求必须携带 Content-MD5 用来校验请求Body 的完整性.
+
+ 关于批量删除 COS 对象接口的描述,请查看https://cloud.tencent.com/document/product/436/8289.
+
+ cos php SDK 中批量删除 COS 对象的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 DeleteObjects 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则删除成功。
+
+ 示例:
+ $result = $cosClient->deleteObjects(array(
+ // Bucket is required
+ 'Bucket' => 'testbucket-1252448703',
+ // Objects is required
+ 'Objects' => array(
+ array(
+ // Key is required
+ 'Key' => 'string',
+ 'VersionId' => 'string',
+ ),
+ // ... repeated
+ ),
+ ));
+ */
+ 'DeleteObjects' => array(
+ 'httpMethod' => 'POST',
+ 'uri' => '/{Bucket}?delete',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'DeleteObjectsOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'Delete',
+ ),
+ 'contentMd5' => true,
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Objects' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'ObjectIdentifier',
+ 'type' => 'object',
+ 'sentAs' => 'Object',
+ 'properties' => array(
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'minLength' => 1,
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'Quiet' => array(
+ 'type' => 'boolean',
+ 'format' => 'boolean-string',
+ 'location' => 'xml',
+ ),
+ 'MFA' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-mfa',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ /**
+ 删除存储桶(Bucket) 的生命周期配置的方法.
+
+ COS 支持删除已配置的 Bucket 的生命周期列表. COS 支持以生命周期配置的方式来管理 Bucket 中 对象的生命周期,生命周期配置包含一个或多个将 应用于一组对象规则的规则集 (其中每个规则为 COS 定义一个操作),请参阅 putBucketLifecycle(PutBucketLifecycleRequest).
+
+ 关于删除 Bucket 的生命周期配置接口的具体描述,请查看https://cloud.tencent.com/document/product/436/8284.
+
+ cos php SDK 中删除 Bucket 的生命周期配置的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 DeleteBucketLifeCycle 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,删除成功。
+
+ 示例:
+ $result = $cosClient->deleteBucketLifecycle(array(
+ // Bucket is required
+ 'Bucket' =>'testbucket-1252448703',
+ ));
+ */
+ 'DeleteBucketLifecycle' => array(
+ 'httpMethod' => 'DELETE',
+ 'uri' => '/{Bucket}?lifecycle',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'DeleteBucketLifecycleOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ ),
+ ),
+ /**
+ 删除跨区域复制配置的方法.
+
+ 当不需要进行跨区域复制时,可以删除 Bucket 的跨区域复制配置. 跨区域复制,可以查阅putBucketReplication(PutBucketReplicationRequest)
+
+ cos php SDK 中删除跨区域复制配置的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 DeleteBucketReplication 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,获取成功。
+
+ */
+ 'DeleteBucketReplication' => array(
+ 'httpMethod' => 'DELETE',
+ 'uri' => '/{Bucket}?replication',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'DeleteBucketReplicationOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ ),
+ ),
+ 'GetObject' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetObjectOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'IfMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'If-Match'),
+ 'IfModifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer'),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'If-Modified-Since'),
+ 'IfNoneMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'If-None-Match'),
+ 'IfUnmodifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer'),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'If-Unmodified-Since'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'Range' => array(
+ 'type' => 'string',
+ 'location' => 'header'),
+ 'ResponseCacheControl' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'response-cache-control'),
+ 'ResponseContentDisposition' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'response-content-disposition'),
+ 'ResponseContentEncoding' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'response-content-encoding'),
+ 'ResponseContentLanguage' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'response-content-language'),
+ 'ResponseContentType' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'response-content-type'),
+ 'ResponseExpires' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer'),
+ 'format' => 'date-time-http',
+ 'location' => 'query',
+ 'sentAs' => 'response-expires'),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'versionId',
+ ),
+ 'SaveAs' => array(
+ 'location' => 'response_body')),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified key does not exist.',
+ 'class' => 'NoSuchKeyException'))),
+ /**
+ 获取 COS 对象的访问权限信息(Access Control List, ACL)的方法.
+
+ Bucket 的持有者可获取该 Bucket 下的某个对象的 ACL 信息,如被授权者以及被授权的信息. ACL 权限包括读、写、读写权限.
+
+ 关于获取 COS 对象的 ACL 接口的具体描述,请查看https://cloud.tencent.com/document/product/436/7744.
+
+ cos php SDK 中获取 COS 对象的 ACL 的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetObjectAcl 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则获取成功。
+
+ 示例:
+ $result = $cosClient->getObjectAcl(array(
+ 'Bucket' => 'testbucket-1252448703',
+ 'Key' => '11'));
+ */
+ 'GetObjectAcl' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}{/Key*}?acl',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetObjectAclOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'versionId',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified key does not exist.',
+ 'class' => 'NoSuchKeyException',
+ ),
+ ),
+ ),
+ /**
+ 获取存储桶(Bucket) 的访问权限信息(Access Control List, ACL)的方法.
+
+ ACL 权限包括读、写、读写权限. COS 中 Bucket 是有访问权限控制的.可以通过获取 Bucket 的 ACL 表(putBucketACL(PutBucketACLRequest)),来查看那些用户拥有 Bucket 访 问权限.
+
+ 关于获取 Bucket 的 ACL 接口的具体描述,请查看 https://cloud.tencent.com/document/product/436/7733.
+
+ cos php SDK 中获取 Bucket 的 ACL 的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetBucketACL 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则获取成功。
+
+
+ 示例:
+ $result = $cosClient->GetBucketAcl(array(
+ 'Bucket' => 'testbucket-1252448703',));
+ */
+ 'GetBucketAcl' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?acl',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketAclOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml'))),
+ /**
+ 查询存储桶(Bucket) 跨域访问配置信息的方法.
+
+ COS 支持查询当前 Bucket 跨域访问配置信息,以确定是否配置跨域信息.当跨域访问配置不存在时,请求 返回403 Forbidden. 跨域访问配置可以通过 putBucketCORS(PutBucketCORSRequest) 或者 putBucketCORSAsync(PutBucketCORSRequest, CosXmlResultListener) 方法来开启 Bucket 的跨域访问 支持.
+
+ 关于查询 Bucket 跨域访问配置信息接口的具体描述, 请查看 https://cloud.tencent.com/document/product/436/8274.
+
+ cos php SDK 中查询 Bucket 跨域访问配置信息的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetBucketCORS 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则获取成功。
+
+
+ 示例:
+ $result = $cosClient->getBucketCors(array(
+ // Bucket is required
+ 'Bucket' => 'testbucket-1252448703',
+ ));
+ */
+ 'GetBucketCors' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?cors',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketCorsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ /**
+ 查询存储桶(Bucket) 的生命周期配置的方法.
+
+ COS 支持以生命周期配置的方式来管理 Bucket 中对象的生命周期,生命周期配置包含一个或多个将 应用于一组对象规则的规则集 (其中每个规则为 COS 定义一个操作),请参阅 putBucketLifecycle(PutBucketLifecycleRequest).
+
+ 关于查询 Bucket 的生命周期配置接口的具体描述,请查看https://cloud.tencent.com/document/product/436/8278.
+
+ cos php SDK 中查询 Bucket 的生命周期配置的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetBucketLifecycle 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则获取成功。
+
+
+ 示例:
+ $result = $cosClient->getBucketLifecycle(array(
+ 'Bucket' => 'testbucket-1252448703',
+ ));
+ */
+ 'GetBucketLifecycle' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?lifecycle',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketLifecycleOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ /**
+ 获取存储桶(Bucket)版本控制信息的方法.
+
+ 通过查询版本控制信息,可以得知该 Bucket 的版本控制功能是处于禁用状态还是启用状态(Enabled 或者 Suspended), 开启版本控制功能,可参考putBucketVersioning(PutBucketVersioningRequest).
+
+ cos php SDK 中获取 Bucket 版本控制信息的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetBucketVersioning 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,获取成功。
+
+ 示例:
+ $result = $cosClient->getBucketVersioning(
+ array('Bucket' => 'lewzylu02-1252448703'));
+ */
+ 'GetBucketVersioning' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?versioning',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketVersioningOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ /**
+ 获取跨区域复制配置信息的方法.
+
+ 跨区域复制是支持不同区域 Bucket 自动复制对象, 请查阅putBucketReplication(PutBucketReplicationRequest).
+
+ cos php SDK 中获取跨区域复制配置信息的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetBucketReplication 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,设置成功。
+
+ */
+ 'GetBucketReplication' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?replication',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketReplicationOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ /**
+ 获取存储桶(Bucket) 所在的地域信息的方法.
+
+ 在创建 Bucket 时,需要指定所属该 Bucket 所属地域信息.
+
+ COS 支持的地域信息,可查看https://cloud.tencent.com/document/product/436/6224.
+
+ 关于获取 Bucket 所在的地域信息接口的具体描述,请查看https://cloud.tencent.com/document/product/436/8275.
+
+ cos php SDK 中获取 Bucket 所在的地域信息的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 GetBucketLocation 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则获取成功。
+
+
+ 示例:
+ $result = $cosClient->getBucketLocation(array(
+ 'Bucket' => 'testbucket-1252448703',
+ ));
+ */
+ 'GetBucketLocation' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?location',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketLocationOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ ),
+ ),
+ 'GetBucketNotification' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?notification',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'GetBucketNotificationOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ 'UploadPart' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'UploadPartOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'UploadPartRequest')),
+ 'parameters' => array(
+ 'Body' => array(
+ 'type' => array(
+ 'string',
+ 'object'),
+ 'location' => 'body'),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'ContentLength' => array(
+ 'type' => 'numeric',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Length'),
+ 'ContentMD5' => array(
+ 'type' => array(
+ 'string',
+ 'boolean'),
+ 'location' => 'header',
+ 'sentAs' => 'Content-MD5'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'PartNumber' => array(
+ 'required' => true,
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'partNumber'),
+ 'UploadId' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'uploadId'),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ))),
+ 'PutObject' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutObjectOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'PutObjectRequest')),
+ 'parameters' => array(
+ 'ACL' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-acl'),
+ 'Body' => array(
+ 'type' => array(
+ 'string',
+ 'object'),
+ 'location' => 'body'),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'CacheControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Cache-Control'),
+ 'ContentDisposition' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Disposition'),
+ 'ContentEncoding' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Encoding'),
+ 'ContentLanguage' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Language'),
+ 'ContentLength' => array(
+ 'type' => 'numeric',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Length'),
+ 'ContentMD5' => array(
+ 'type' => array(
+ 'string',
+ 'boolean'),
+ 'location' => 'header',
+ 'sentAs' => 'Content-MD5'),
+ 'ContentType' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Type'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'Metadata' => array(
+ 'type' => 'object',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-meta-',
+ 'additionalProperties' => array(
+ 'type' => 'string')
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-storage-class',
+ ),
+ 'WebsiteRedirectLocation' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-website-redirect-location',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'ACP' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ ))),
+ /**
+ 设置 COS 对象的访问权限信息(Access Control List, ACL)的方法.
+
+ ACL权限包括读、写、读写权限. COS 对象的 ACL 可以通过 header头部:"x-cos-acl","x-cos-grant-read","x-cos-grant-write", "x-cos-grant-full-control" 传入 ACL 信息,或者通过 Body 以 XML 格式传入 ACL 信息.这两种方式只 能选择其中一种,否则引起冲突. 传入新的 ACL 将覆盖原有 ACL信息.ACL策略数上限1000,建议用户不要每个上传文件都设置 ACL.
+
+ 关于设置 COS 对象的ACL接口的具体描述,请查看https://cloud.tencent.com/document/product/436/7748.
+
+ cos PHP SDK 中设置 COS 对象的 ACL 的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 PutObjectAcl 对象中的方法发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则设置成功。
+
+ 示例:
+ $cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '11',
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'ID' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+ */
+ 'PutObjectAcl' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}{/Key*}?acl',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutObjectAclOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'AccessControlPolicy',
+ ),
+ ),
+ 'parameters' => array(
+ 'ACL' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-acl',
+ ),
+ 'Grants' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'AccessControlList',
+ 'items' => array(
+ 'name' => 'Grant',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Grantee' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string'),
+ 'ID' => array(
+ 'type' => 'string'),
+ 'Type' => array(
+ 'type' => 'string',
+ 'sentAs' => 'xsi:type',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ 'xmlNamespace' => 'http://www.w3.org/2001/XMLSchema-instance')),
+ 'URI' => array(
+ 'type' => 'string') )),
+ 'Permission' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'GrantFullControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-full-control',
+ ),
+ 'GrantRead' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read',
+ ),
+ 'GrantReadACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read-acp',
+ ),
+ 'GrantWrite' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-write',
+ ),
+ 'GrantWriteACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-write-acp',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'ACP' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ ),
+ ),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified key does not exist.',
+ 'class' => 'NoSuchKeyException',
+ ),
+ ),
+ ),
+ /**
+ 设置存储桶(Bucket) 的访问权限(Access Control List, ACL)的方法.
+
+ ACL 权限包括读、写、读写权限. 写入 Bucket 的 ACL 可以通过 header头部:"x-cos-acl","x-cos-grant-read","x-cos-grant-write", "x-cos-grant-full-control" 传入 ACL 信息,或者通过 Body 以 XML 格式传入 ACL 信息.这两种方式只 能选择其中一种,否则引起冲突. 传入新的 ACL 将覆盖原有 ACL信息. 私有 Bucket 可以下可以给某个文件夹设置成公有,那么该文件夹下的文件都是公有;但是把文件夹设置成私有后,在该文件夹下的文件设置 的公有属性,不会生效.
+
+ 关于设置 Bucket 的ACL接口的具体描述,请查看 https://cloud.tencent.com/document/product/436/7737.
+
+ cos php SDK 中设置 Bucket 的ACL的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 PutObjectAcl 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,设置成功。
+
+
+ 示例:
+ $result = $cosClient->PutObjectAcl(array(
+ 'Bucket' => 'testbucket-1252448703',
+ 'Key' => '111',
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'ID' => 'qcs::cam::uin/327874225:uin/327874225',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/3210232098:uin/3210232098',
+ 'ID' => 'qcs::cam::uin/3210232098:uin/3210232098',
+ ),));
+ */
+ 'PutBucketAcl' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}?acl',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutBucketAclOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'AccessControlPolicy',
+ ),
+ ),
+ 'parameters' => array(
+ 'ACL' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-acl',
+ ),
+ 'Grants' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'AccessControlList',
+ 'items' => array(
+ 'name' => 'Grant',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Grantee' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'EmailAddress' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'Type' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'sentAs' => 'xsi:type',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ 'xmlNamespace' => 'http://www.w3.org/2001/XMLSchema-instance',
+ ),
+ ),
+ 'URI' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'Permission' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'GrantFullControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-full-control',
+ ),
+ 'GrantRead' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read',
+ ),
+ 'GrantReadACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-read-acp',
+ ),
+ 'GrantWrite' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-write',
+ ),
+ 'GrantWriteACP' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-grant-write-acp',
+ ),
+ 'ACP' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ ),
+ ),
+ ),
+ /**
+ 设置存储桶(Bucket) 的跨域配置信息的方法.
+
+ 跨域访问配置的预请求是指在发送跨域请求之前会发送一个 OPTIONS 请求并带上特定的来源域,HTTP 方 法和 header 信息等给 COS,以决定是否可以发送真正的跨域请求. 当跨域访问配置不存在时,请求返回403 Forbidden.
+
+ 默认情况下,Bucket的持有者可以直接配置 Bucket的跨域信息 ,Bucket 持有者也可以将配置权限授予其他用户.新的配置是覆盖当前的所有配置信 息,而不是新增一条配置.可以通过传入 XML 格式的配置文件来实现配置,文件大小限制为64 KB.
+
+ 关于设置 Bucket 的跨域配置信息接口的具体描述,请查看 https://cloud.tencent.com/document/product/436/8279.
+
+ cos php SDK 中设置 Bucket 的跨域配置信息的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 PutBucketCORS 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,设置成功。
+
+ 示例:
+ $result = $cosClient->putBucketCors(array(
+ // Bucket is required
+ 'Bucket' => 'testbucket-1252448703',
+ // CORSRules is required
+ 'CORSRules' => array(
+ array(
+ 'ID' => '1234',
+ 'AllowedHeaders' => array('*'),
+ // AllowedMethods is required
+ 'AllowedMethods' => array('PUT'),
+ // AllowedOrigins is required
+ 'AllowedOrigins' => array('http://www.qq.com', ),
+ ),
+ // ... repeated
+ ),
+ ));
+ */
+ 'PutBucketCors' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}?cors',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutBucketCorsOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'CORSConfiguration',
+ ),
+ 'contentMd5' => true,
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'CORSRules' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'CORSRule',
+ 'type' => 'object',
+ 'sentAs' => 'CORSRule',
+ 'properties' => array(
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'AllowedHeaders' => array(
+ 'type' => 'array',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'AllowedHeader',
+ 'type' => 'string',
+ 'sentAs' => 'AllowedHeader',
+ ),
+ ),
+ 'AllowedMethods' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'AllowedMethod',
+ 'type' => 'string',
+ 'sentAs' => 'AllowedMethod',
+ ),
+ ),
+ 'AllowedOrigins' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'AllowedOrigin',
+ 'type' => 'string',
+ 'sentAs' => 'AllowedOrigin',
+ ),
+ ),
+ 'ExposeHeaders' => array(
+ 'type' => 'array',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'ExposeHeader',
+ 'type' => 'string',
+ 'sentAs' => 'ExposeHeader',
+ ),
+ ),
+ 'MaxAgeSeconds' => array(
+ 'type' => 'numeric',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ /**
+ 设置存储桶(Bucket) 生命周期配置的方法.
+
+ COS 支持以生命周期配置的方式来管理 Bucket 中对象的生命周期. 如果该 Bucket 已配置生命周期,新的配置的同时则会覆盖原有的配置. 生命周期配置包含一个或多个将应用于一组对象规则的规则集 (其中每个规则为 COS 定义一个操作)。这些操作分为以下两种:转换操作,过期操作.
+
+ 转换操作,定义对象转换为另一个存储类的时间(例如,您可以选择在对象创建 30 天后将其转换为低频存储类别,同 时也支持将数据沉降到归档存储类别.
+
+ 过期操作,指定 Object 的过期时间,COS 将会自动为用户删除过期的 Object.
+
+ 关于Bucket 生命周期配置接口的具体描述,请查看 https://cloud.tencent.com/document/product/436/8280
+
+ cos php SDK 中Bucket 生命周期配置的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 PutBucketLifecycle 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,设置成功。
+
+ 示例:
+ $result = $cosClient->putBucketLifecycle(array(
+ // Bucket is required
+ 'Bucket' => 'lewzylu06-1252448703',
+ // Rules is required
+ 'Rules' => array(
+ array(
+ 'Expiration' => array(
+ 'Days' => 1000,
+ ),
+ 'ID' => 'id1',
+ 'Filter' => array(
+ 'Prefix' => 'documents/'
+ ),
+ // Status is required
+ 'Status' => 'Enabled',
+ 'Transitions' => array(
+ array(
+ 'Days' => 200,
+ 'StorageClass' => 'NEARLINE'),
+ ),
+ // ... repeated
+ ),
+ )));
+ */
+ 'PutBucketLifecycle' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}?lifecycle',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutBucketLifecycleOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'LifecycleConfiguration',
+ ),
+ 'contentMd5' => true,
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Rules' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'Rule',
+ 'type' => 'object',
+ 'sentAs' => 'Rule',
+ 'properties' => array(
+ 'Expiration' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Date' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time',
+ ),
+ 'Days' => array(
+ 'type' => 'numeric',
+ ),
+ ),
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'Filter' => array(
+ 'type' => 'object',
+ 'require' => true,
+ 'properties' => array(
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'require' => true,
+ ),
+ 'Tag' => array(
+ 'type' => 'object',
+ 'require' => true,
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'string'
+ ),
+ 'Value' => array(
+ 'type' => 'string'
+ ),
+ )
+ )
+ ),
+ ),
+ 'Status' => array(
+ 'required' => true,
+ 'type' => 'string',
+ ),
+ 'Transitions' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'Transition',
+ 'type' => 'object',
+ 'sentAs' => 'Transition',
+ 'properties' => array(
+ 'Date' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time',
+ ),
+ 'Days' => array(
+ 'type' => 'numeric',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ )))),
+ 'NoncurrentVersionTransition' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'NoncurrentDays' => array(
+ 'type' => 'numeric',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'NoncurrentVersionExpiration' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'NoncurrentDays' => array(
+ 'type' => 'numeric',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ /**
+ 存储桶(Bucket)版本控制的方法.
+
+ 版本管理功能一经打开,只能暂停,不能关闭. 通过版本控制,可以在一个 Bucket 中保留一个对象的多个版本. 版本控制可以防止意外覆盖和删除对象,以便检索早期版本的对象. 默认情况下,版本控制功能处于禁用状态,需要主动去启用或者暂停(Enabled 或者 Suspended).
+
+ cos php SDK 中 Bucket 版本控制启用或者暂停的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 PutBucketVersioning 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,设置成功。
+
+ 示例:
+ $result = $cosClient->putBucketVersioning(
+ array('Bucket' => 'testbucket-1252448703',
+ 'Status' => 'Enabled'));
+ */
+ 'PutBucketVersioning' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}?versioning',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutBucketVersioningOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'VersioningConfiguration',
+ ),
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'MFA' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-mfa',
+ ),
+ 'MFADelete' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ 'sentAs' => 'MfaDelete',
+ ),
+ 'Status' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ ),
+ ),
+ /**
+ 配置跨区域复制的方法.
+
+ 跨区域复制是支持不同区域 Bucket 自动异步复制对象.注意,不能是同区域的 Bucket, 且源 Bucket 和目 标 Bucket 必须已启用版本控制putBucketVersioning(PutBucketVersioningRequest).
+
+ cos php SDK 中配置跨区域复制的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 PutBucketRelication 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,设置成功。
+
+ 示例:
+
+ */
+ 'PutBucketReplication' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}?replication',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutBucketReplicationOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'ReplicationConfiguration',
+ ),
+ 'contentMd5' => true,
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Role' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Rules' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'ReplicationRule',
+ 'type' => 'object',
+ 'sentAs' => 'Rule',
+ 'properties' => array(
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'Prefix' => array(
+ 'required' => true,
+ 'type' => 'string',
+ ),
+ 'Status' => array(
+ 'required' => true,
+ 'type' => 'string',
+ ),
+ 'Destination' => array(
+ 'required' => true,
+ 'type' => 'object',
+ 'properties' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ /**
+ 设置存储桶(Bucket) 的回调设置的方法.
+ */
+ 'PutBucketNotification' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}?notification',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'PutBucketNotificationOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'NotificationConfiguration',
+ ),
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'CloudFunctionConfigurations' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'CloudFunctionConfiguration',
+ 'type' => 'object',
+ 'sentAs' => 'CloudFunctionConfiguration',
+ 'properties' => array(
+ 'Id' => array(
+ 'type' => 'string',
+ ),
+ 'CloudFunction' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'sentAs' => 'CloudFunction',
+ ),
+ 'Events' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'Event',
+ 'type' => 'string',
+ 'sentAs' => 'Event',
+ ),
+ ),
+ 'Filter' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'object',
+ 'sentAs' => 'Key',
+ 'properties' => array(
+ 'FilterRules' => array(
+ 'type' => 'array',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'FilterRule',
+ 'type' => 'object',
+ 'sentAs' => 'FilterRule',
+ 'properties' => array(
+ 'Name' => array(
+ 'type' => 'string',
+ ),
+ 'Value' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'RestoreObject' => array(
+ 'httpMethod' => 'POST',
+ 'uri' => '/{Bucket}{/Key*}?restore',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'RestoreObjectOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'RestoreRequest',
+ ),
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'versionId',
+ ),
+ 'Days' => array(
+ 'required' => true,
+ 'type' => 'numeric',
+ 'location' => 'xml',
+ ),
+ 'CASJobParameters' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Tier' => array(
+ 'type' => 'string',
+ 'required' => true,
+ ),
+ ),
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ ),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'This operation is not allowed against this storage tier',
+ 'class' => 'ObjectAlreadyInActiveTierErrorException',
+ ),
+ ),
+ ),
+ /**
+ 查询存储桶(Bucket)中正在进行中的分块上传对象的方法.
+
+ COS 支持查询 Bucket 中有哪些正在进行中的分块上传对象,单次请求操作最多列出 1000 个正在进行中的 分块上传对象.
+
+ 关于查询 Bucket 中正在进行中的分块上传对象接口的具体描述,请查看 https://cloud.tencent.com/document/product/436/7736.
+
+ cos php SDK 中查询 Bucket 中正在进行中的分块上传对象的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 ListParts 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,获取成功。
+
+ */
+ 'ListParts' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'ListPartsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1),
+ 'MaxParts' => array(
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'max-parts'),
+ 'PartNumberMarker' => array(
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'part-number-marker'),
+ 'UploadId' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'uploadId'),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml'))),
+ /**
+ 查询存储桶(Bucket) 下的部分或者全部对象的方法.
+
+ COS 支持列出指定 Bucket 下的部分或者全部对象.
+
+ 每次默认返回的最大条目数为 1000 条.
+
+ 如果无法一次返回所有的对象,则返回结果中的 IsTruncated 为 true,同时会附加一个 NextMarker 字段,提示下 一个条目的起点.
+
+ 若一次请求,已经返回了全部对象,则不会有 NextMarker 这个字段,同时 IsTruncated 为 false.
+
+ 若把 prefix 设置为某个文件夹的全路径名,则可以列出以此 prefix 为开头的文件,即该文件 夹下递归的所有文件和子文件夹.
+
+ 如果再设置 delimiter 定界符为 “/”,则只列出该文件夹下的文件,子文件夹下递归的文件和文件夹名 将不被列出.而子文件夹名将会以 CommonPrefix 的形式给出.
+
+ 关于查询Bucket 下的部分或者全部对象接口的具体描述,请查看https://cloud.tencent.com/document/product/436/7734.
+
+ cos php SDK 中查询 Bucket 下的部分或者全部对象的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 ListObjects 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,则list成功。
+
+ 示例:
+ $result = $cosClient->ListObjects(array(
+ 'Bucket' => 'testbucket-1252448703'));
+ */
+ 'ListObjects' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'ListObjectsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri'),
+ 'Delimiter' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'delimiter'),
+ 'EncodingType' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'encoding-type'),
+ 'Marker' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'marker'),
+ 'MaxKeys' => array(
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'max-keys'),
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'prefix'),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml')),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified bucket does not exist.',
+ 'class' => 'NoSuchBucketException'))),
+ /**
+ 获取所属账户的所有存储空间列表的方法.
+
+ 通过使用帯 Authorization 签名认证的请求,可以获取签名中 APPID 所属账户的所有存储空间列表 (Bucket list).
+
+ 关于获取所有存储空间列表接口的具体描述,请查看https://cloud.tencent.com/document/product/436/8291.
+
+ cos php SDK 中获取所属账户的所有存储空间列表的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 ListBuckets 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,获取成功。
+
+ 示例:
+ $result = $cosClient->listBuckets();
+ print_r($result);
+ */
+ 'ListBuckets' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'ListBucketsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ 'ListObjectVersions' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?versions',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'ListObjectVersionsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Delimiter' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'delimiter',
+ ),
+ 'EncodingType' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'encoding-type',
+ ),
+ 'KeyMarker' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'key-marker',
+ ),
+ 'MaxKeys' => array(
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'max-keys',
+ ),
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'prefix',
+ ),
+ 'VersionIdMarker' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'version-id-marker',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ 'ListMultipartUploads' => array(
+ 'httpMethod' => 'GET',
+ 'uri' => '/{Bucket}?uploads',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'ListMultipartUploadsOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'Delimiter' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'delimiter',
+ ),
+ 'EncodingType' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'encoding-type',
+ ),
+ 'KeyMarker' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'key-marker',
+ ),
+ 'MaxUploads' => array(
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'max-uploads',
+ ),
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'prefix',
+ ),
+ 'UploadIdMarker' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'upload-id-marker',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),
+ 'HeadObject' => array(
+ 'httpMethod' => 'HEAD',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'HeadObjectOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'IfMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'If-Match',
+ ),
+ 'IfModifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'If-Modified-Since',
+ ),
+ 'IfNoneMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'If-None-Match',
+ ),
+ 'IfUnmodifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'If-Unmodified-Since',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'Range' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'versionId',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ ),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified key does not exist.',
+ 'class' => 'NoSuchKeyException',
+ ),
+ ),
+ ),
+ /**
+ 存储桶(Bucket) 是否存在的方法.
+
+ 在开始使用 COS 时,需要确认该 Bucket 是否存在,是否有权限访问.若不存在,则可以调用putBucket(PutBucketRequest) 创建.
+
+ 关于确认该 Bucket 是否存在,是否有权限访问接口的具体描述,请查看https://cloud.tencent.com/document/product/436/7735.
+
+ cos php SDK 中Bucket 是否存在的方法具体步骤如下:
+
+ 1. 初始化客户端cosClient,填入存储桶名,和一些额外需要的参数,如授权的具体信息等。
+
+ 2. 调用 HeadBucket 接口发出请求。
+
+ 3. 接收该接口的返回数据,若没有抛出异常,获取成功。
+
+ 示例:
+ $result = $cosClient->headObject(array(
+ 'Bucket' => 'testbucket-1252448703',
+ 'Key' => '11',
+ 'VersionId' =>'111',
+ 'ServerSideEncryption' => 'AES256'));
+ */
+ 'HeadBucket' => array(
+ 'httpMethod' => 'HEAD',
+ 'uri' => '/{Bucket}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'HeadBucketOutput',
+ 'responseType' => 'model',
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ ),
+ 'errorResponses' => array(
+ array(
+ 'reason' => 'The specified bucket does not exist.',
+ 'class' => 'NoSuchBucketException',
+ ),
+ ),
+ ),
+ 'UploadPartCopy' => array(
+ 'httpMethod' => 'PUT',
+ 'uri' => '/{Bucket}{/Key*}',
+ 'class' => 'Qcloud\\Cos\\Command',
+ 'responseClass' => 'UploadPartCopyOutput',
+ 'responseType' => 'model',
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'UploadPartCopyRequest',
+ ),
+ ),
+ 'parameters' => array(
+ 'Bucket' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ ),
+ 'CopySource' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source',
+ ),
+ 'CopySourceIfMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-match',
+ ),
+ 'CopySourceIfModifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-modified-since',
+ ),
+ 'CopySourceIfNoneMatch' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-none-match',
+ ),
+ 'CopySourceIfUnmodifiedSince' => array(
+ 'type' => array(
+ 'object',
+ 'string',
+ 'integer',
+ ),
+ 'format' => 'date-time-http',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-if-unmodified-since',
+ ),
+ 'CopySourceRange' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-range',
+ ),
+ 'Key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'uri',
+ 'minLength' => 1,
+ ),
+ 'PartNumber' => array(
+ 'required' => true,
+ 'type' => 'numeric',
+ 'location' => 'query',
+ 'sentAs' => 'partNumber',
+ ),
+ 'UploadId' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'uploadId',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'CopySourceSSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-algorithm',
+ ),
+ 'CopySourceSSECustomerKey' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key',
+ ),
+ 'CopySourceSSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-server-side-encryption-customer-key-MD5',
+ ),
+ 'RequestPayer' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-payer',
+ ),
+ 'command.expects' => array(
+ 'static' => true,
+ 'default' => 'application/xml',
+ ),
+ ),
+ ),),
+ 'models' => array(
+ 'AbortMultipartUploadOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'CreateBucketOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Location' => array(
+ 'type' => 'string',
+ 'location' => 'header'),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'CompleteMultipartUploadOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Location' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Bucket' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Key' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Expiration' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-expiration',
+ ),
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-version-id',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'CreateMultipartUploadOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Bucket' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ 'sentAs' => 'Bucket'),
+ 'Key' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'UploadId' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ))),
+ 'CopyObjectOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'LastModified' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Expiration' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-expiration',
+ ),
+ 'CopySourceVersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-version-id',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-version-id',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'DeleteBucketOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'DeleteBucketCorsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'DeleteObjectOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'DeleteMarker' => array(
+ 'type' => 'boolean',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-delete-marker',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-version-id',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'DeleteObjectsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Deleted' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'DeletedObject',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'string',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ ),
+ 'DeleteMarker' => array(
+ 'type' => 'boolean',
+ ),
+ 'DeleteMarkerVersionId' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'Errors' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'Error',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'Error',
+ 'type' => 'object',
+ 'sentAs' => 'Error',
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'string',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ ),
+ 'Code' => array(
+ 'type' => 'string',
+ ),
+ 'Message' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'DeleteBucketLifecycleOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'DeleteBucketReplicationOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetObjectOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Body' => array(
+ 'type' => 'string',
+ 'instanceOf' => 'Guzzle\\Http\\EntityBody',
+ 'location' => 'body',
+ ),
+ 'DeleteMarker' => array(
+ 'type' => 'boolean',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-delete-marker',
+ ),
+ 'AcceptRanges' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'accept-ranges',
+ ),
+ 'Expiration' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-expiration',
+ ),
+ 'Restore' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-restore',
+ ),
+ 'LastModified' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Last-Modified',
+ ),
+ 'ContentLength' => array(
+ 'type' => 'numeric',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Length',
+ ),
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'MissingMeta' => array(
+ 'type' => 'numeric',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-missing-meta',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-version-id',
+ ),
+ 'CacheControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Cache-Control',
+ ),
+ 'ContentDisposition' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Disposition',
+ ),
+ 'ContentEncoding' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Encoding',
+ ),
+ 'ContentLanguage' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Language',
+ ),
+ 'ContentRange' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Range',
+ ),
+ 'ContentType' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Type',
+ ),
+ 'Expires' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'WebsiteRedirectLocation' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-website-redirect-location',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'Metadata' => array(
+ 'type' => 'object',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-meta-',
+ 'additionalProperties' => array(
+ 'type' => 'string',
+ ),
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-storage-class',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'ReplicationStatus' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-replication-status',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetObjectAclOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Owner' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'Grants' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'AccessControlList',
+ 'items' => array(
+ 'name' => 'Grant',
+ 'type' => 'object',
+ 'sentAs' => 'Grant',
+ 'properties' => array(
+ 'Grantee' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string'),
+ /*
+ 'EmailAddress' => array(
+ 'type' => 'string'),
+ */
+ 'ID' => array(
+ 'type' => 'string'),
+ /*
+ 'Type' => array(
+ 'type' => 'string',
+ 'sentAs' => 'xsi:type',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ 'xmlNamespace' => 'http://www.w3.org/2001/XMLSchema-instance')),
+ */
+ /*'URI' => array(
+ 'type' => 'string') */)),
+ 'Permission' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetBucketAclOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Owner' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string'),
+ 'ID' => array(
+ 'type' => 'string'))),
+ 'Grants' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'AccessControlList',
+ 'items' => array(
+ 'name' => 'Grant',
+ 'type' => 'object',
+ 'sentAs' => 'Grant',
+ 'properties' => array(
+ 'Grantee' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string'),
+ /*
+ 'EmailAddress' => array(
+ 'type' => 'string'),
+ */
+ 'ID' => array(
+ 'type' => 'string'),
+ /*
+ 'Type' => array(
+ 'type' => 'string',
+ 'sentAs' => 'xsi:type',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ 'xmlNamespace' => 'http://www.w3.org/2001/XMLSchema-instance')),
+ */
+ /*'URI' => array(
+ 'type' => 'string') */)),
+ 'Permission' => array(
+ 'type' => 'string')))),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'GetBucketCorsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'CORSRules' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'CORSRule',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'CORSRule',
+ 'type' => 'object',
+ 'sentAs' => 'CORSRule',
+ 'properties' => array(
+ 'ID' => array(
+ 'type' => 'string'),
+ 'AllowedHeaders' => array(
+ 'type' => 'array',
+ 'sentAs' => 'AllowedHeader',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'AllowedHeader',
+ 'type' => 'string',
+ 'sentAs' => 'AllowedHeader',
+ ),
+ ),
+ 'AllowedMethods' => array(
+ 'type' => 'array',
+ 'sentAs' => 'AllowedMethod',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'AllowedMethod',
+ 'type' => 'string',
+ 'sentAs' => 'AllowedMethod',
+ ),
+ ),
+ 'AllowedOrigins' => array(
+ 'type' => 'array',
+ 'sentAs' => 'AllowedOrigin',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'AllowedOrigin',
+ 'type' => 'string',
+ 'sentAs' => 'AllowedOrigin',
+ ),
+ ),
+ 'ExposeHeaders' => array(
+ 'type' => 'array',
+ 'sentAs' => 'ExposeHeader',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'ExposeHeader',
+ 'type' => 'string',
+ 'sentAs' => 'ExposeHeader',
+ ),
+ ),
+ 'MaxAgeSeconds' => array(
+ 'type' => 'numeric',
+ ),
+ ),
+ ),
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetBucketLifecycleOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Rules' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'Rule',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'Rule',
+ 'type' => 'object',
+ 'sentAs' => 'Rule',
+ 'properties' => array(
+ 'Expiration' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Date' => array(
+ 'type' => 'string',
+ ),
+ 'Days' => array(
+ 'type' => 'numeric',
+ ),
+ ),
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'Filter' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Prefix' => array(
+ 'type' => 'string',
+ ),
+ 'Tag' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'string'
+ ),
+ 'Value' => array(
+ 'type' => 'string'
+ ),
+ )
+ )
+ ),
+ ),
+ 'Status' => array(
+ 'type' => 'string',
+ ),
+ 'Transition' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Date' => array(
+ 'type' => 'string',
+ ),
+ 'Days' => array(
+ 'type' => 'numeric',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'NoncurrentVersionTransition' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'NoncurrentDays' => array(
+ 'type' => 'numeric',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'NoncurrentVersionExpiration' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'NoncurrentDays' => array(
+ 'type' => 'numeric',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetBucketVersioningOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Status' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'MFADelete' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ 'sentAs' => 'MfaDelete',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetBucketReplicationOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Role' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Rules' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'Rule',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'ReplicationRule',
+ 'type' => 'object',
+ 'sentAs' => 'Rule',
+ 'properties' => array(
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'Prefix' => array(
+ 'type' => 'string',
+ ),
+ 'Status' => array(
+ 'type' => 'string',
+ ),
+ 'Destination' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Bucket' => array(
+ 'type' => 'string',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetBucketLocationOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Location' => array(
+ 'type' => 'string',
+ 'location' => 'body',
+ 'filters' => array(
+ 'strval',
+ 'strip_tags',
+ 'trim',
+ ),
+ ),
+ ),
+ ),
+ 'UploadPartOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'UploadPartCopyOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'CopySourceVersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-copy-source-version-id',
+ ),
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'LastModified' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutBucketAclOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'PutObjectOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Expiration' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-expiration',
+ ),
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-version-id',
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutObjectAclOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutBucketCorsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutBucketLifecycleOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutBucketVersioningOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutBucketReplicationOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'PutBucketNotificationOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'RestoreObjectOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'ListPartsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Bucket' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'Key' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'UploadId' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'PartNumberMarker' => array(
+ 'type' => 'numeric',
+ 'location' => 'xml'),
+ 'NextPartNumberMarker' => array(
+ 'type' => 'numeric',
+ 'location' => 'xml'),
+ 'MaxParts' => array(
+ 'type' => 'numeric',
+ 'location' => 'xml'),
+ 'IsTruncated' => array(
+ 'type' => 'boolean',
+ 'location' => 'xml'),
+ 'Parts' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'Part',
+ 'data' => array(
+ 'xmlFlattened' => true),
+ 'items' => array(
+ 'name' => 'Part',
+ 'type' => 'object',
+ 'sentAs' => 'Part',
+ 'properties' => array(
+ 'PartNumber' => array(
+ 'type' => 'numeric'),
+ 'LastModified' => array(
+ 'type' => 'string'),
+ 'ETag' => array(
+ 'type' => 'string'),
+ 'Size' => array(
+ 'type' => 'numeric')))),
+ 'Initiator' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'ID' => array(
+ 'type' => 'string'),
+ 'DisplayName' => array(
+ 'type' => 'string'))),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string'),
+ 'ID' => array(
+ 'type' => 'string'))),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'ListObjectsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'IsTruncated' => array(
+ 'type' => 'boolean',
+ 'location' => 'xml'),
+ 'Marker' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'NextMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'Contents' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true),
+ 'items' => array(
+ 'name' => 'Object',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'string'),
+ 'LastModified' => array(
+ 'type' => 'string'),
+ 'ETag' => array(
+ 'type' => 'string'),
+ 'Size' => array(
+ 'type' => 'numeric'),
+ 'StorageClass' => array(
+ 'type' => 'string'),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string'),
+ 'ID' => array(
+ 'type' => 'string')))))),
+ 'Name' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'Delimiter' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'MaxKeys' => array(
+ 'type' => 'numeric',
+ 'location' => 'xml'),
+ 'CommonPrefixes' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true),
+ 'items' => array(
+ 'name' => 'CommonPrefix',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Prefix' => array(
+ 'type' => 'string')))),
+ 'EncodingType' => array(
+ 'type' => 'string',
+ 'location' => 'xml'),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id'))),
+ 'ListBucketsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Buckets' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'items' => array(
+ 'name' => 'Bucket',
+ 'type' => 'object',
+ 'sentAs' => 'Bucket',
+ 'properties' => array(
+ 'Name' => array(
+ 'type' => 'string',
+ ),
+ 'CreationDate' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'ListObjectVersionsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'IsTruncated' => array(
+ 'type' => 'boolean',
+ 'location' => 'xml',
+ ),
+ 'KeyMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'VersionIdMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'NextKeyMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'NextVersionIdMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Versions' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'Version',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'ObjectVersion',
+ 'type' => 'object',
+ 'sentAs' => 'Version',
+ 'properties' => array(
+ 'ETag' => array(
+ 'type' => 'string',
+ ),
+ 'Size' => array(
+ 'type' => 'numeric',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ 'Key' => array(
+ 'type' => 'string',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ ),
+ 'IsLatest' => array(
+ 'type' => 'boolean',
+ ),
+ 'LastModified' => array(
+ 'type' => 'string',
+ ),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'DeleteMarkers' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'DeleteMarker',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'DeleteMarkerEntry',
+ 'type' => 'object',
+ 'sentAs' => 'DeleteMarker',
+ 'properties' => array(
+ 'Owner' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'Key' => array(
+ 'type' => 'string',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ ),
+ 'IsLatest' => array(
+ 'type' => 'boolean',
+ ),
+ 'LastModified' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'Name' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Delimiter' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'MaxKeys' => array(
+ 'type' => 'numeric',
+ 'location' => 'xml',
+ ),
+ 'CommonPrefixes' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'CommonPrefix',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Prefix' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'EncodingType' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'ListMultipartUploadsOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'Bucket' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'KeyMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'UploadIdMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'NextKeyMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Prefix' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'Delimiter' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'NextUploadIdMarker' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'MaxUploads' => array(
+ 'type' => 'numeric',
+ 'location' => 'xml',
+ ),
+ 'IsTruncated' => array(
+ 'type' => 'boolean',
+ 'location' => 'xml',
+ ),
+ 'Uploads' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'Upload',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'MultipartUpload',
+ 'type' => 'object',
+ 'sentAs' => 'Upload',
+ 'properties' => array(
+ 'UploadId' => array(
+ 'type' => 'string',
+ ),
+ 'Key' => array(
+ 'type' => 'string',
+ ),
+ 'Initiated' => array(
+ 'type' => 'string',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ ),
+ 'Owner' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'Initiator' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'ID' => array(
+ 'type' => 'string',
+ ),
+ 'DisplayName' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'CommonPrefixes' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'CommonPrefix',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Prefix' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ 'EncodingType' => array(
+ 'type' => 'string',
+ 'location' => 'xml',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'HeadObjectOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'DeleteMarker' => array(
+ 'type' => 'boolean',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-delete-marker',
+ ),
+ 'AcceptRanges' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'accept-ranges',
+ ),
+ 'Expiration' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-expiration',
+ ),
+ 'Restore' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-restore',
+ ),
+ 'LastModified' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Last-Modified',
+ ),
+ 'ContentLength' => array(
+ 'type' => 'numeric',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Length',
+ ),
+ 'ETag' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'MissingMeta' => array(
+ 'type' => 'numeric',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-missing-meta',
+ ),
+ 'VersionId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-version-id',
+ ),
+ 'CacheControl' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Cache-Control',
+ ),
+ 'ContentDisposition' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Disposition',
+ ),
+ 'ContentEncoding' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Encoding',
+ ),
+ 'ContentLanguage' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Language',
+ ),
+ 'ContentType' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'Content-Type',
+ ),
+ 'Expires' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ ),
+ 'WebsiteRedirectLocation' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-website-redirect-location',
+ ),
+ 'ServerSideEncryption' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption',
+ ),
+ 'Metadata' => array(
+ 'type' => 'object',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-meta-',
+ 'additionalProperties' => array(
+ 'type' => 'string',
+ ),
+ ),
+ 'SSECustomerAlgorithm' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-algorithm',
+ ),
+ 'SSECustomerKeyMD5' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-customer-key-MD5',
+ ),
+ 'SSEKMSKeyId' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-server-side-encryption-aws-kms-key-id',
+ ),
+ 'StorageClass' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-storage-class',
+ ),
+ 'RequestCharged' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-charged',
+ ),
+ 'ReplicationStatus' => array(
+ 'type' => 'string',
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-replication-status',
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ))),
+ 'HeadBucketOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ ),
+ 'GetBucketNotificationOutput' => array(
+ 'type' => 'object',
+ 'additionalProperties' => true,
+ 'properties' => array(
+ 'CloudFunctionConfigurations' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'CloudFunctionConfiguration',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'CloudFunctionConfiguration',
+ 'type' => 'object',
+ 'sentAs' => 'CloudFunctionConfiguration',
+ 'properties' => array(
+ 'Id' => array(
+ 'type' => 'string',
+ ),
+ 'CloudFunction' => array(
+ 'type' => 'string',
+ 'sentAs' => 'CloudFunction',
+ ),
+ 'Events' => array(
+ 'type' => 'array',
+ 'sentAs' => 'Event',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'Event',
+ 'type' => 'string',
+ 'sentAs' => 'Event',
+ ),
+ ),
+ 'Filter' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Key' => array(
+ 'type' => 'object',
+ 'sentAs' => 'Key',
+ 'properties' => array(
+ 'FilterRules' => array(
+ 'type' => 'array',
+ 'sentAs' => 'FilterRule',
+ 'data' => array(
+ 'xmlFlattened' => true,
+ ),
+ 'items' => array(
+ 'name' => 'FilterRule',
+ 'type' => 'object',
+ 'sentAs' => 'FilterRule',
+ 'properties' => array(
+ 'Name' => array(
+ 'type' => 'string',
+ ),
+ 'Value' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'RequestId' => array(
+ 'location' => 'header',
+ 'sentAs' => 'x-cos-request-id',
+ ),
+ ),
+ )));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Signature.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Signature.php
new file mode 100755
index 0000000..51c02e9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Signature.php
@@ -0,0 +1,50 @@
+accessKey = $accessKey;
+ $this->secretKey = $secretKey;
+ }
+ public function __destruct() {
+ }
+ public function signRequest(RequestInterface $request) {
+ $signTime = (string)(time() - 60) . ';' . (string)(time() + 3600);
+ $httpString = strtolower($request->getMethod()) . "\n" . urldecode($request->getPath()) .
+ "\n\nhost=" . $request->getHost() . "\n";
+ $sha1edHttpString = sha1($httpString);
+ $stringToSign = "sha1\n$signTime\n$sha1edHttpString\n";
+ $signKey = hash_hmac('sha1', $signTime, $this->secretKey);
+ $signature = hash_hmac('sha1', $stringToSign, $signKey);
+ $authorization = 'q-sign-algorithm=sha1&q-ak='. $this->accessKey .
+ "&q-sign-time=$signTime&q-key-time=$signTime&q-header-list=host&q-url-param-list=&" .
+ "q-signature=$signature";
+ $request->setHeader('Authorization', $authorization);
+ }
+ public function createAuthorization(
+ RequestInterface $request,
+ $expires = "10 minutes"
+ ) {
+ $signTime = (string)(time() - 60) . ';' . (string)(strtotime($expires));
+ $httpString = strtolower($request->getMethod()) . "\n" . urldecode($request->getPath()) .
+ "\n\nhost=" . $request->getHost() . "\n";
+ $sha1edHttpString = sha1($httpString);
+ $stringToSign = "sha1\n$signTime\n$sha1edHttpString\n";
+ $signKey = hash_hmac('sha1', $signTime, $this->secretKey);
+ $signature = hash_hmac('sha1', $stringToSign, $signKey);
+ $authorization = 'q-sign-algorithm=sha1&q-ak='. $this->accessKey .
+ "&q-sign-time=$signTime&q-key-time=$signTime&q-header-list=host&q-url-param-list=&" .
+ "q-signature=$signature";
+ return $authorization;
+ }
+ public function createPresignedUrl(
+ RequestInterface $request,
+ $expires = "10 minutes"
+ ) {
+ $authorization = $this->createAuthorization($request, $expires);
+ $request->getQuery()->add('sign', $authorization);
+ return $request->getUrl();
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/SignatureListener.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/SignatureListener.php
new file mode 100755
index 0000000..a979583
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/SignatureListener.php
@@ -0,0 +1,45 @@
+signature = new Signature($accessKey, $secretKey);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'request.before_send' => array('onRequestBeforeSend', -255));
+ }
+
+ /**
+ * Signs requests before they are sent
+ *
+ * @param Event $event Event emitted
+ */
+ public function onRequestBeforeSend(Event $event) {
+
+ $this->signature->signRequest($event['request']);
+/*
+ if(!$this->credentials instanceof NullCredentials) {
+ $this->signature->signRequest($event['request'], $this->credentials);
+ }
+*/
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Tests/Test.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Tests/Test.php
new file mode 100755
index 0000000..d32f6ac
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Tests/Test.php
@@ -0,0 +1,1367 @@
+bucket = getenv('COS_BUCKET');
+ TestHelper::nuke($this->bucket);
+ $this->cosClient = new Client(array('region' => getenv('COS_REGION'),
+ 'credentials' => array(
+ 'appId' => getenv('COS_APPID'),
+ 'secretId' => getenv('COS_KEY'),
+ 'secretKey' => getenv('COS_SECRET'))));
+ sleep(5);
+ }
+
+ protected function tearDown()
+ {
+ TestHelper::nuke($this->bucket);
+ }
+
+ /**********************************
+ * TestBucket
+ **********************************/
+
+ /*
+ * put bucket,bucket已经存在
+ * BucketAlreadyOwnedByYou
+ * 409
+ */
+ public function testCreateExistingBucket()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'BucketAlreadyOwnedByYou' && $e->getStatusCode() === 409);
+ }
+ }
+
+ /*
+ * put bucket,bucket名称非法
+ * InvalidBucketName
+ * 400
+ */
+ public function testCreateInvalidBucket()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => 'qwe_213'));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'InvalidBucketName' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * put bucket,设置bucket公公权限为private
+ * 200
+ */
+ public function testCreatePrivateBucket()
+ {
+ try {
+ $this->cosClient->createBucket(
+ array(
+ 'Bucket' => $this->bucket,
+ 'ACL'=>'private'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket,设置bucket公公权限为public-read
+ * 200
+ */
+ public function testCreatePublicReadBucket()
+ {
+ try {
+ $this->cosClient->createBucket(
+ array(
+ 'Bucket' => $this->bucket,
+ 'ACL'=>'public-read'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket,公共权限非法
+ * InvalidArgument
+ * 400
+ */
+ public function testCreateInvalidACLBucket()
+ {
+ try {
+ $this->cosClient->createBucket(
+ array(
+ 'Bucket' => $this->bucket,
+ 'ACL'=>'public'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket公共权限为private
+ * 200
+ */
+ public function testPutBucketAclPrivate()
+ {
+ try {
+
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(
+ array(
+ 'Bucket' => $this->bucket,
+ 'ACL'=>'private'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket公共权限为public-read
+ * 200
+ */
+ public function testPutBucketAclPublicRead()
+ {
+ try {
+
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(
+ array(
+ 'Bucket' => $this->bucket,
+ 'ACL'=>'public-read'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,公共权限非法
+ * InvalidArgument
+ * 400
+ */
+ public function testPutBucketAclInvalid()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(
+ array(
+ 'Bucket' => $this->bucket,
+ 'ACL'=>'public'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限为grant-read
+ * 200
+ */
+ public function testPutBucketAclReadToUser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantRead' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限为grant-write
+ * 200
+ */
+ public function testPutBucketAclWriteToUser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantWrite' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限为grant-full-control
+ * 200
+ */
+ public function testPutBucketAclFullToUser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限,同时授权给多个账户
+ * 200
+ */
+ public function testPutBucketAclToUsers()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970",id="qcs::cam::uin/2779643970:uin/2779643970",id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限,授权给子账号
+ * 200
+ */
+ public function testPutBucketAclToSubuser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限,同时指定read、write和fullcontrol
+ * 200
+ */
+ public function testPutBucketAclReadWriteFull()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantRead' => 'id="qcs::cam::uin/123:uin/123"',
+ 'GrantWrite' => 'id="qcs::cam::uin/2779643970:uin/2779643970"',
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"',));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限,grant值非法
+ * InvalidArgument
+ * 400
+ */
+ public function testPutBucketAclInvalidGrant()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantFullControl' => 'id="qcs::camuin/321023:uin/2779643970"',));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限,通过body方式授权
+ * 200
+ */
+ public function testPutBucketAclByBody()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,设置bucket账号权限,通过body方式授权给anyone
+ * 200
+ */
+ public function testPutBucketAclByBodyToAnyone()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::anyone:anyone',
+ 'ID' => 'qcs::cam::anyone:anyone',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket acl,bucket不存在
+ * NoSuchBucket
+ * 404
+ */
+ public function testPutBucketAclBucketNonexisted()
+ {
+ try {
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantFullControl' => 'id="qcs::cam::uin/321023:uin/2779643970"',));
+ } catch (ServiceResponseException $e) {
+// echo($e->getExceptionCode());
+// echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);
+ }
+ }
+
+ /*
+ * put bucket acl,覆盖设置
+ * x200
+ */
+ public function testPutBucketAclCover()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"',
+ 'GrantRead' => 'id="qcs::cam::uin/2779643970:uin/2779643970"',
+ 'GrantWrite' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ $this->cosClient->PutBucketAcl(array(
+ 'Bucket' => $this->bucket,
+ 'GrantWrite' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 正常head bucket
+ * 200
+ */
+ public function testHeadBucket()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->HeadBucket(array(
+ 'Bucket' => $this->bucket));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * head bucket,bucket不存在
+ * NoSuchBucket
+ * 404
+ */
+ public function testHeadBucketNonexisted()
+ {
+ try {
+ $this->cosClient->HeadBucket(array(
+ 'Bucket' => $this->bucket,));
+ } catch (ServiceResponseException $e) {
+// echo($e->getExceptionCode());
+// echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);
+ }
+ }
+
+ /*
+ * get bucket,bucket为空
+ * 200
+ */
+ public function testGetBucketEmpty()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->ListObjects(array(
+ 'Bucket' => $this->bucket));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * get bucket,bucket不存在
+ * NoSuchBucket
+ * 404
+ */
+ public function testGetBucketNonexisted()
+ {
+ try {
+ $this->cosClient->ListObjects(array(
+ 'Bucket' => $this->bucket,));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);
+ }
+ }
+
+
+ /*
+ * put bucket cors,cors规则包含多条
+ * 200
+ */
+ public function testPutBucketCors()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,
+ // CORSRules is required
+ 'CORSRules' => array(
+ array(
+ 'ID' => '1234',
+ 'AllowedHeaders' => array('*',),
+ // AllowedMethods is required
+ 'AllowedMethods' => array('PUT',),
+ // AllowedOrigins is required
+ 'AllowedOrigins' => array('*',),
+ 'ExposeHeaders' => array('*',),
+ 'MaxAgeSeconds' => 1,
+ ),
+ array(
+ 'ID' => '12345',
+ 'AllowedHeaders' => array('*',),
+ // AllowedMethods is required
+ 'AllowedMethods' => array('PUT',),
+ // AllowedOrigins is required
+ 'AllowedOrigins' => array('*',),
+ 'ExposeHeaders' => array('*',),
+ 'MaxAgeSeconds' => 1,
+ ),
+ // ... repeated
+ ),
+ ));
+ $this->cosClient->getBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+
+ /*
+ * 正常get bucket cors
+ * 200
+ */
+ public function testGetBucketCors()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,
+ // CORSRules is required
+ 'CORSRules' => array(
+ array(
+ 'ID' => '1234',
+ 'AllowedHeaders' => array('*',),
+ // AllowedMethods is required
+ 'AllowedMethods' => array('PUT',),
+ // AllowedOrigins is required
+ 'AllowedOrigins' => array('*',),
+ 'ExposeHeaders' => array('*',),
+ 'MaxAgeSeconds' => 1,
+ ),
+ array(
+ 'ID' => '12345',
+ 'AllowedHeaders' => array('*',),
+ // AllowedMethods is required
+ 'AllowedMethods' => array('PUT',),
+ // AllowedOrigins is required
+ 'AllowedOrigins' => array('*',),
+ 'ExposeHeaders' => array('*',),
+ 'MaxAgeSeconds' => 1,
+ ),
+ // ... repeated
+ ),
+ ));
+ $this->cosClient->getBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * bucket未设置cors规则,发送get bucket cors
+ * NoSuchCORSConfiguration
+ * 404
+ */
+ public function testGetBucketCorsNull()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->getBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,));
+ } catch (ServiceResponseException $e) {
+// echo($e->getExceptionCode());
+// echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchCORSConfiguration' && $e->getStatusCode() === 404);
+ }
+ }
+
+ /*
+ * bucket未设置cors规则,发送get bucket cors
+ * NoSuchCORSConfiguration
+ * 404
+ */
+ public function testGetBucketCorsNonExisted()
+ {
+ try {
+ $this->cosClient->getBucketCors(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,));
+ } catch (ServiceResponseException $e) {
+// echo($e->getExceptionCode());
+// echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);
+ }
+ }
+
+ /*
+ * 正常get bucket lifecycle
+ * 200
+ */
+ public function testGetBucketLifecycle()
+ {
+ try {
+ $result = $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $result = $this->cosClient->putBucketLifecycle(array(
+ 'Bucket' => $this->bucket,
+ 'Rules' => array(
+ array(
+ 'Status' => 'Enabled',
+ 'Filter' => array(
+ 'Tag' => array(
+ 'Key' => 'datalevel',
+ 'Value' => 'backup'
+ )
+ ),
+ 'Transitions' => array(
+ array(
+ # 30天后转换为Standard_IA
+ 'Days' => 30,
+ 'StorageClass' => 'Standard_IA'),
+ array(
+ # 365天后转换为Archive
+ 'Days' => 365,
+ 'StorageClass' => 'Archive')
+ ),
+ 'Expiration' => array(
+ # 3650天后过期删除
+ 'Days' => 3650,
+ )
+ )
+ )
+ ));
+ $result = $this->cosClient->getBucketLifecycle(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 正常delete bucket lifecycle
+ * 200
+ */
+ public function testDeleteBucketLifecycle()
+ {
+ try {
+ $result = $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $result = $this->cosClient->putBucketLifecycle(array(
+ 'Bucket' => $this->bucket,
+ 'Rules' => array(
+ array(
+ 'Status' => 'Enabled',
+ 'Filter' => array(
+ 'Tag' => array(
+ 'Key' => 'datalevel',
+ 'Value' => 'backup'
+ )
+ ),
+ 'Transitions' => array(
+ array(
+ # 30天后转换为Standard_IA
+ 'Days' => 30,
+ 'StorageClass' => 'Standard_IA'),
+ array(
+ # 365天后转换为Archive
+ 'Days' => 365,
+ 'StorageClass' => 'Archive')
+ ),
+ 'Expiration' => array(
+ # 3650天后过期删除
+ 'Days' => 3650,
+ )
+ )
+ )
+ ));
+ $result = $this->cosClient->deleteBucketLifecycle(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket lifecycle,请求body中不指定filter
+ * 200
+ */
+ public function testPutBucketLifecycleNonFilter()
+ {
+ try {
+ $result = $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $result = $this->cosClient->putBucketLifecycle(array(
+ // Bucket is required
+ 'Bucket' => $this->bucket,
+ // Rules is required
+ 'Rules' => array(
+ array(
+ 'Expiration' => array(
+ 'Days' => 1000,
+ ),
+ 'ID' => 'id1',
+ // Status is required
+ 'Status' => 'Enabled',
+ 'Transitions' => array(
+ array(
+ 'Days' => 100,
+ 'StorageClass' => 'Standard_IA'),
+ ),
+ // ... repeated
+ ),
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);
+
+ }
+ }
+
+ /*
+ * put bucket,bucket名称带有-
+ * 200
+ */
+ public function testPutBucket2()
+ {
+ try {
+ try{
+ $this->cosClient->deleteBucket(array('Bucket' => '12345-'.$this->bucket));
+ } catch (\Exception $e) {
+ }
+ $this->cosClient->createBucket(array('Bucket' => '12345-'.$this->bucket));
+ $this->cosClient->deleteBucket(array('Bucket' => '12345-'.$this->bucket));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put bucket,bucket名称带有两个-
+ * 200
+ */
+ public function testPutBucket3()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket.'-12333-4445'));
+ $this->cosClient->deleteBucket(array('Bucket' => $this->bucket.'-12333-4445'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 正常get bucket location
+ * 200
+ */
+ public function testGetBucketLocation()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->getBucketLocation(array('Bucket' => $this->bucket));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * bucket不存在,发送get bucket location请求
+ * NoSuchBucket
+ * 404
+ */
+ public function testGetBucketLocationNonExisted()
+ {
+ try {
+ $this->cosClient->getBucketLocation(array('Bucket' => $this->bucket));
+ } catch (ServiceResponseException $e) {
+ // echo($e->getExceptionCode());
+ // echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket' && $e->getStatusCode() === 404);
+ }
+ }
+
+ /**********************************
+ * TestObject
+ **********************************/
+
+ /*
+ * put object,请求头部携带服务端加密参数
+ * 200
+ */
+ public function testPutObjectEncryption()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '11//32//43',
+ 'Body' => 'Hello World!',
+ 'ServerSideEncryption' => 'AES256'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * Copy大文件
+ * 200
+ */
+ public function testCopyBigFile()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->Copy($bucket = $this->bucket,
+ $key = 'test10G',
+ $copysource = 'lewzylu01-1251668577.cos.ap-guangzhou.myqcloud.com/test10G');
+ $rt = $this->cosClient->headObject(array('Bucket' => $this->$bucket,
+ 'Key' => 'test10G'));
+ assertTrue(true, $rt['ContentLength'] == 10485760000);
+
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+
+ /*
+ * 上传文件Bucket不存在
+ * NoSuchBucket
+ * 404
+ */
+ public function testPutObjectIntoNonexistedBucket() {
+ try {
+ $this->cosClient->putObject(array(
+ 'Bucket' => $this->bucket, 'Key' => 'hello.txt', 'Body' => 'Hello World'));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'NoSuchBucket');
+ $this->assertTrue($e->getStatusCode() === 404);
+ }
+ }
+
+
+ /*
+ * 上传小文件
+ * 200
+ */
+ public function testUploadSmallObject() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 上传空文件
+ * 200
+ */
+ public function testPutObjectEmpty() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', '123');
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 上传已存在的文件
+ * 200
+ */
+ public function testPutObjectExisted() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', '1234124');
+ $this->cosClient->upload($this->bucket, '你好.txt', '请二位qwe');
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object,请求头部携带自定义头部x-cos-meta-
+ * 200
+ */
+ public function testPutObjectMeta() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'Body' => '1234124',
+ 'Metadata' => array(
+ 'lew' => str_repeat('a', 1 * 1024),
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object,请求头部携带自定义头部x-cos-meta-
+ * KeyTooLong
+ * 400
+ */
+ public function testPutObjectMeta2K() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'Body' => '1234124',
+ 'Metadata' => array(
+ 'lew' => str_repeat('a', 3 * 1024),
+ )));
+ } catch (ServiceResponseException $e) {
+// echo($e->getExceptionCode());
+// echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'KeyTooLong' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * 上传复杂文件名的文件
+ * 200
+ */
+ public function testUploadComplexObject() {
+ try {
+ $result = $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '→↓←→↖↗↙↘! \"#$%&\'()*+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', 'Hello World');
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 上传大文件
+ * 200
+ */
+ public function testUploadLargeObject() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, 'hello.txt', str_repeat('a', 9 * 1024 * 1024));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 下载文件
+ * 200
+ */
+ public function testGetObject() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');
+ $this->cosClient->getObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * get object,object名称包含特殊字符
+ * 200
+ */
+ public function testGetObjectSpecialName() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好<>!@#^%^&*&(&^!@#@!.txt', 'Hello World');
+ $this->cosClient->getObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好<>!@#^%^&*&(&^!@#@!.txt',));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * get object,请求头部带if-match,参数值为true
+ * 200
+ */
+ public function testGetObjectIfMatchTrue() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');
+ $this->cosClient->getObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'IfMatch' => '"b10a8db164e0754105b7a99be72e3fe5"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+
+ /*
+ * get object,请求头部带if-match,参数值为false
+ * PreconditionFailed
+ * 412
+ */
+ public function testGetObjectIfMatchFalse() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');
+ $this->cosClient->getObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'IfMatch' => '""'));
+ } catch (ServiceResponseException $e) {
+// echo($e->getExceptionCode());
+// echo($e->getStatusCode());
+ $this->assertTrue($e->getExceptionCode() === 'PreconditionFailed' && $e->getStatusCode() === 412);
+ }
+ }
+
+ /*
+ * get object,请求头部带if-none-match,参数值为true
+ * 200
+ */
+ public function testGetObjectIfNoneMatchTrue() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');
+ $this->cosClient->getObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'IfNoneMatch' => '"b10a8db164e0754105b7a99be72e3fe5"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'NotModified' && $e->getStatusCode() === 304);
+ }
+ }
+
+
+ /*
+ * get object,请求头部带if-none-match,参数值为false
+ * PreconditionFailed
+ * 412
+ */
+ public function testGetObjectIfNoneMatchFalse() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '你好.txt', 'Hello World');
+ $this->cosClient->getObject(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'IfNoneMatch' => '""'));
+
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 获取文件url
+ * 200
+ */
+ public function testGetObjectUrl() {
+ try{
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->getObjectUrl($this->bucket, 'hello.txt', '+10 minutes');
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * 设置objectacl
+ * 200
+ */
+ public function testPutObjectACL() {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '11', 'hello.txt');
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '11',
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+
+ }
+
+
+ /*
+ * 获取objectacl
+ * 200
+ */
+ public function testGetObjectACL()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->upload($this->bucket, '11', 'hello.txt');
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '11',
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object公共权限为private
+ * 200
+ */
+ public function testPutObjectAclPrivate()
+ {
+ try {
+
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(
+ array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'ACL'=>'private'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object公共权限为public-read
+ * 200
+ */
+ public function testPutObjectAclPublicRead()
+ {
+ try {
+
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(
+ array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'ACL'=>'public-read'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,公共权限非法
+ * InvalidArgument
+ * 400
+ */
+ public function testPutObjectAclInvalid()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(
+ array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'ACL'=>'public'
+ ));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限为grant-read
+ * 200
+ */
+ public function testPutObjectAclReadToUser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'GrantRead' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限为grant-write
+ * 200
+ */
+// public function testPutObjectAclWriteToUser()
+// {
+// try {
+// $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+// $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+// $this->cosClient->PutObjectAcl(array(
+// 'Bucket' => $this->bucket,
+// 'Key' => '你好.txt',
+// 'GrantWrite' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+// } catch (ServiceResponseException $e) {
+// $this->assertFalse(true, $e);
+// }
+// }
+
+ /*
+ * put object acl,设置object账号权限为grant-full-control
+ * 200
+ */
+ public function testPutObjectAclFullToUser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限,同时授权给多个账户
+ * 200
+ */
+ public function testPutObjectAclToUsers()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970",id="qcs::cam::uin/2779643970:uin/2779643970",id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限,授权给子账号
+ * 200
+ */
+ public function testPutObjectAclToSubuser()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"'));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限,同时指定read、write和fullcontrol
+ * 200
+ */
+// public function testPutObjectAclReadWriteFull()
+// {
+// try {
+// $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+// $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+// $this->cosClient->PutObjectAcl(array(
+// 'Bucket' => $this->bucket,
+// 'Key' => '你好.txt',
+// 'GrantRead' => 'id="qcs::cam::uin/123:uin/123"',
+// 'GrantWrite' => 'id="qcs::cam::uin/2779643970:uin/2779643970"',
+// 'GrantFullControl' => 'id="qcs::cam::uin/2779643970:uin/2779643970"',));
+// } catch (ServiceResponseException $e) {
+// $this->assertFalse(true, $e);
+// }
+// }
+
+ /*
+ * put object acl,设置object账号权限,grant值非法
+ * InvalidArgument
+ * 400
+ */
+ public function testPutObjectAclInvalidGrant()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'GrantFullControl' => 'id="qcs::camuin/321023:uin/2779643970"',));
+ } catch (ServiceResponseException $e) {
+ $this->assertTrue($e->getExceptionCode() === 'InvalidArgument' && $e->getStatusCode() === 400);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限,通过body方式授权
+ * 200
+ */
+ public function testPutObjectAclByBody()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->PutObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+ /*
+ * put object acl,设置object账号权限,通过body方式授权给anyone
+ * 200
+ */
+ public function testPutObjectAclByBodyToAnyone()
+ {
+ try {
+ $this->cosClient->createBucket(array('Bucket' => $this->bucket));
+ $this->cosClient->putObject(array('Bucket' => $this->bucket,'Key' => '你好.txt', 'Body' => '123'));
+ $this->cosClient->putObjectAcl(array(
+ 'Bucket' => $this->bucket,
+ 'Key' => '你好.txt',
+ 'Grants' => array(
+ array(
+ 'Grantee' => array(
+ 'DisplayName' => 'qcs::cam::anyone:anyone',
+ 'ID' => 'qcs::cam::anyone:anyone',
+ 'Type' => 'CanonicalUser',
+ ),
+ 'Permission' => 'FULL_CONTROL',
+ ),
+ // ... repeated
+ ),
+ 'Owner' => array(
+ 'DisplayName' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ 'ID' => 'qcs::cam::uin/2779643970:uin/2779643970',
+ )));
+ } catch (ServiceResponseException $e) {
+ $this->assertFalse(true, $e);
+ }
+ }
+
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/Tests/TestHelper.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Tests/TestHelper.php
new file mode 100755
index 0000000..367b887
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/Tests/TestHelper.php
@@ -0,0 +1,48 @@
+ getenv('COS_REGION'),
+ 'credentials'=> array(
+ 'appId' => getenv('COS_APPID'),
+ 'secretId' => getenv('COS_KEY'),
+ 'secretKey' => getenv('COS_SECRET'))));
+ $result = $cosClient->listObjects(array('Bucket' => $bucket));
+ if ($result->get('Contents')) {
+ foreach ($result ->get('Contents') as $content) {
+ $cosClient->deleteObject(array('Bucket' => $bucket, 'Key' => $content['Key']));
+ }
+ }
+ $cosClient->deleteBucket(array('Bucket' => $bucket));
+
+ while(True){
+ $result = $cosClient->ListMultipartUploads(
+ array('Bucket' => $bucket,
+ 'Prefix' => ''));
+ if (count($result['Uploads']) == 0){
+ break;
+ }
+ foreach ($result['Uploads'] as $upload) {
+ try {
+ $rt = $cosClient->AbortMultipartUpload(
+ array('Bucket' => $bucket,
+ 'Key' => $upload['Key'],
+ 'UploadId' => $upload['UploadId']));
+ print_r($rt);
+ } catch (\Exception $e) {
+ print_r($e);
+ }
+ }
+ }
+ } catch (\Exception $e) {
+ //echo "$e\n";
+ // Ignore
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/TokenListener.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/TokenListener.php
new file mode 100755
index 0000000..8bde999
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/TokenListener.php
@@ -0,0 +1,48 @@
+token = $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'request.before_send' => array('onRequestBeforeSend', -240));
+ }
+
+ /**
+ * Signs requests before they are sent
+ *
+ * @param Event $event Event emitted
+ */
+ public function onRequestBeforeSend(Event $event) {
+ if ($this->token != null) {
+ $event['request']->setHeader('x-cos-security-token', $this->token);
+ }
+/*
+ if(!$this->credentials instanceof NullCredentials) {
+ $this->signature->signRequest($event['request'], $this->credentials);
+ }
+*/
+ }
+}
diff --git a/app/Common/extend/tencentcloud/src/Qcloud/Cos/UploadBodyListener.php b/app/Common/extend/tencentcloud/src/Qcloud/Cos/UploadBodyListener.php
new file mode 100755
index 0000000..f318029
--- /dev/null
+++ b/app/Common/extend/tencentcloud/src/Qcloud/Cos/UploadBodyListener.php
@@ -0,0 +1,79 @@
+commands = $commands;
+ $this->bodyParameter = (string) $bodyParameter;
+ $this->sourceParameter = (string) $sourceParameter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getSubscribedEvents() {
+ return array('command.before_prepare' => array('onCommandBeforePrepare'));
+ }
+
+ /**
+ * Converts filenames and file handles into EntityBody objects before the command is validated
+ *
+ * @param Event $event Event emitted
+ * @throws InvalidArgumentException
+ */
+ public function onCommandBeforePrepare(Event $event) {
+ /** @var Command $command */
+ $command = $event['command'];
+ if (in_array($command->getName(), $this->commands)) {
+ // Get the interesting parameters
+ $source = $command->get($this->sourceParameter);
+ $body = $command->get($this->bodyParameter);
+
+ // If a file path is passed in then get the file handle
+ if (is_string($source) && file_exists($source)) {
+ $body = fopen($source, 'rb');
+ }
+
+ // Prepare the body parameter and remove the source file parameter
+ if (null !== $body) {
+ $command->remove($this->sourceParameter);
+ $command->set($this->bodyParameter, EntityBody::factory($body));
+ } else {
+ throw new InvalidArgumentException(
+ "You must specify a non-null value for the {$this->bodyParameter} or {$this->sourceParameter} parameters.");
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/autoload.php b/app/Common/extend/tencentcloud/vendor/autoload.php
new file mode 100755
index 0000000..9b271fd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/autoload.php
@@ -0,0 +1,7 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @see http://www.php-fig.org/psr/psr-0/
+ * @see http://www.php-fig.org/psr/psr-4/
+ */
+class ClassLoader
+{
+ // PSR-4
+ private $prefixLengthsPsr4 = array();
+ private $prefixDirsPsr4 = array();
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ private $prefixesPsr0 = array();
+ private $fallbackDirsPsr0 = array();
+
+ private $useIncludePath = false;
+ private $classMap = array();
+ private $classMapAuthoritative = false;
+ private $missingClasses = array();
+ private $apcuPrefix;
+
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
+ }
+
+ return array();
+ }
+
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 base directories
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
+ *
+ * @param string|null $apcuPrefix
+ */
+ public function setApcuPrefix($apcuPrefix)
+ {
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
+ }
+
+ /**
+ * The APCu prefix in use, or null if APCu caching is not enabled.
+ *
+ * @return string|null
+ */
+ public function getApcuPrefix()
+ {
+ return $this->apcuPrefix;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return bool|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
+ return false;
+ }
+ if (null !== $this->apcuPrefix) {
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
+ if ($hit) {
+ return $file;
+ }
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if (false === $file && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if (null !== $this->apcuPrefix) {
+ apcu_add($this->apcuPrefix.$class, $file);
+ }
+
+ if (false === $file) {
+ // Remember that this class does not exist.
+ $this->missingClasses[$class] = true;
+ }
+
+ return $file;
+ }
+
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ $subPath = $class;
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
+ $subPath = substr($subPath, 0, $lastPos);
+ $search = $subPath . '\\';
+ if (isset($this->prefixDirsPsr4[$search])) {
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
+ if (file_exists($file = $dir . $pathEnd)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+
+ return false;
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/app/Common/extend/tencentcloud/vendor/composer/LICENSE b/app/Common/extend/tencentcloud/vendor/composer/LICENSE
new file mode 100755
index 0000000..f27399a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/composer/LICENSE
@@ -0,0 +1,21 @@
+
+Copyright (c) Nils Adermann, Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/app/Common/extend/tencentcloud/vendor/composer/autoload_classmap.php b/app/Common/extend/tencentcloud/vendor/composer/autoload_classmap.php
new file mode 100755
index 0000000..7a91153
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/composer/autoload_classmap.php
@@ -0,0 +1,9 @@
+ array($baseDir . '/src'),
+ 'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
+ 'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
+);
diff --git a/app/Common/extend/tencentcloud/vendor/composer/autoload_psr4.php b/app/Common/extend/tencentcloud/vendor/composer/autoload_psr4.php
new file mode 100755
index 0000000..29f1523
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/composer/autoload_psr4.php
@@ -0,0 +1,10 @@
+ array($vendorDir . '/symfony/event-dispatcher'),
+);
diff --git a/app/Common/extend/tencentcloud/vendor/composer/autoload_real.php b/app/Common/extend/tencentcloud/vendor/composer/autoload_real.php
new file mode 100755
index 0000000..6913689
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/composer/autoload_real.php
@@ -0,0 +1,52 @@
+= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
+ if ($useStaticLoader) {
+ require_once __DIR__ . '/autoload_static.php';
+
+ call_user_func(\Composer\Autoload\ComposerStaticInita3c18f6f45b4cf998e466d2367db0e41::getInitializer($loader));
+ } else {
+ $map = require __DIR__ . '/autoload_namespaces.php';
+ foreach ($map as $namespace => $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+ }
+
+ $loader->register(true);
+
+ return $loader;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/composer/autoload_static.php b/app/Common/extend/tencentcloud/vendor/composer/autoload_static.php
new file mode 100755
index 0000000..71c0d16
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/composer/autoload_static.php
@@ -0,0 +1,53 @@
+
+ array (
+ 'Symfony\\Component\\EventDispatcher\\' => 34,
+ ),
+ );
+
+ public static $prefixDirsPsr4 = array (
+ 'Symfony\\Component\\EventDispatcher\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/symfony/event-dispatcher',
+ ),
+ );
+
+ public static $prefixesPsr0 = array (
+ 'Q' =>
+ array (
+ 'Qcloud\\Cos\\' =>
+ array (
+ 0 => __DIR__ . '/../..' . '/src',
+ ),
+ ),
+ 'G' =>
+ array (
+ 'Guzzle\\Tests' =>
+ array (
+ 0 => __DIR__ . '/..' . '/guzzle/guzzle/tests',
+ ),
+ 'Guzzle' =>
+ array (
+ 0 => __DIR__ . '/..' . '/guzzle/guzzle/src',
+ ),
+ ),
+ );
+
+ public static function getInitializer(ClassLoader $loader)
+ {
+ return \Closure::bind(function () use ($loader) {
+ $loader->prefixLengthsPsr4 = ComposerStaticInita3c18f6f45b4cf998e466d2367db0e41::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInita3c18f6f45b4cf998e466d2367db0e41::$prefixDirsPsr4;
+ $loader->prefixesPsr0 = ComposerStaticInita3c18f6f45b4cf998e466d2367db0e41::$prefixesPsr0;
+
+ }, null, ClassLoader::class);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/composer/installed.json b/app/Common/extend/tencentcloud/vendor/composer/installed.json
new file mode 100755
index 0000000..9180abd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/composer/installed.json
@@ -0,0 +1,162 @@
+[
+ {
+ "name": "guzzle/guzzle",
+ "version": "v3.9.3",
+ "version_normalized": "3.9.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle3.git",
+ "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
+ "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "php": ">=5.3.3",
+ "symfony/event-dispatcher": "~2.1"
+ },
+ "replace": {
+ "guzzle/batch": "self.version",
+ "guzzle/cache": "self.version",
+ "guzzle/common": "self.version",
+ "guzzle/http": "self.version",
+ "guzzle/inflection": "self.version",
+ "guzzle/iterator": "self.version",
+ "guzzle/log": "self.version",
+ "guzzle/parser": "self.version",
+ "guzzle/plugin": "self.version",
+ "guzzle/plugin-async": "self.version",
+ "guzzle/plugin-backoff": "self.version",
+ "guzzle/plugin-cache": "self.version",
+ "guzzle/plugin-cookie": "self.version",
+ "guzzle/plugin-curlauth": "self.version",
+ "guzzle/plugin-error-response": "self.version",
+ "guzzle/plugin-history": "self.version",
+ "guzzle/plugin-log": "self.version",
+ "guzzle/plugin-md5": "self.version",
+ "guzzle/plugin-mock": "self.version",
+ "guzzle/plugin-oauth": "self.version",
+ "guzzle/service": "self.version",
+ "guzzle/stream": "self.version"
+ },
+ "require-dev": {
+ "doctrine/cache": "~1.3",
+ "monolog/monolog": "~1.0",
+ "phpunit/phpunit": "3.7.*",
+ "psr/log": "~1.0",
+ "symfony/class-loader": "~2.1",
+ "zendframework/zend-cache": "2.*,<2.3",
+ "zendframework/zend-log": "2.*,<2.3"
+ },
+ "suggest": {
+ "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
+ },
+ "time": "2015-03-18T18:23:50+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.9-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-0": {
+ "Guzzle": "src/",
+ "Guzzle\\Tests": "tests/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Guzzle Community",
+ "homepage": "https://github.com/guzzle/guzzle/contributors"
+ }
+ ],
+ "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "abandoned": "guzzlehttp/guzzle"
+ },
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v2.8.49",
+ "version_normalized": "2.8.49.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/event-dispatcher.git",
+ "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0",
+ "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "^2.0.5|~3.0.0",
+ "symfony/dependency-injection": "~2.6|~3.0.0",
+ "symfony/expression-language": "~2.6|~3.0.0",
+ "symfony/stopwatch": "~2.3|~3.0.0"
+ },
+ "suggest": {
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
+ },
+ "time": "2018-11-21T14:20:20+00:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony EventDispatcher Component",
+ "homepage": "https://symfony.com"
+ }
+]
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/.gitignore b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/.gitignore
new file mode 100755
index 0000000..893035d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/.gitignore
@@ -0,0 +1,27 @@
+# Ingore common cruft
+.DS_STORE
+coverage
+.idea
+
+# Ignore binary files
+guzzle.phar
+guzzle-min.phar
+
+# Ignore potentially sensitive phpunit file
+phpunit.xml
+
+# Ignore composer generated files
+composer.phar
+composer.lock
+composer-test.lock
+vendor/
+
+# Ignore build files
+build/
+phing/build.properties
+
+# Ignore subsplit working directory
+.subsplit
+
+docs/_build
+docs/*.pyc
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/.travis.yml b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/.travis.yml
new file mode 100755
index 0000000..209e05c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/.travis.yml
@@ -0,0 +1,17 @@
+language: php
+
+php:
+ - 5.3
+ - 5.4
+ - 5.5
+ - 5.6
+ - hhvm
+
+before_script:
+ - curl --version
+ - pecl install uri_template-beta || echo "pecl uri_template not available"
+ - composer self-update
+ - composer install --no-interaction --prefer-source --dev
+ - ~/.nvm/nvm.sh install v0.6.14
+
+script: composer test
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/CHANGELOG.md b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/CHANGELOG.md
new file mode 100755
index 0000000..f0dc544
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/CHANGELOG.md
@@ -0,0 +1,751 @@
+# CHANGELOG
+
+## 3.9.3 - 2015-03-18
+
+* Ensuring Content-Length is not stripped from a request when it is `0`.
+* Added more information to stream wrapper exceptions.
+* Message parser will no longer throw warnings for malformed messages.
+* Giving a valid cache TTL when max-age is 0.
+
+## 3.9.2 - 2014-09-10
+
+* Retrying "Connection died, retrying a fresh connect" curl errors.
+* Automatically extracting the cacert from the phar in client constructor.
+* Added EntityBody support for OPTIONS requests.
+
+## 3.9.1 - 2014-05-07
+
+* Added a fix to ReadLimitEntityBody to ensure it doesn't infinitely loop.
+* Added a fix to the stream checksum function so that when the first read
+ returns a falsey value, it still continues to consume the stream until EOF.
+
+## 3.9.0 - 2014-04-23
+
+* `null`, `false`, and `"_guzzle_blank_"` all now serialize as an empty value
+ with no trailing "=". See dc1d824277.
+* No longer performing an MD5 check on the cacert each time the phar is used,
+ but rather copying the cacert to the temp directory.
+* `"0"` can now be added as a URL path
+* Deleting cookies that are set to empty
+* If-Modified-Since is no longer unnecessarily added to the CachePlugin
+* Cookie path matching now follows RFC 6265 s5.1.4
+* Updated service descriptions are now added to a service client's composite
+ factory.
+* MockPlugin now throws an exception if the queue is empty.
+* Properly parsing URLs that start with "http" but are not absolute
+* Added the ability to configure the curl_multi_select timeout setting
+* OAuth parameters are now sorted using lexicographical byte value ordering
+* Fixing invalid usage of an out of range PHP feature in the ErrorResponsePlugin
+
+## 3.8.1 -2014-01-28
+
+* Bug: Always using GET requests when redirecting from a 303 response
+* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in
+ `Guzzle\Http\ClientInterface::setSslVerification()`
+* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL
+* Bug: The body of a request can now be set to `"0"`
+* Sending PHP stream requests no longer forces `HTTP/1.0`
+* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of
+ each sub-exception
+* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than
+ clobbering everything).
+* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)
+* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.
+ For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.
+* Now properly escaping the regular expression delimiter when matching Cookie domains.
+* Network access is now disabled when loading XML documents
+
+## 3.8.0 - 2013-12-05
+
+* Added the ability to define a POST name for a file
+* JSON response parsing now properly walks additionalProperties
+* cURL error code 18 is now retried automatically in the BackoffPlugin
+* Fixed a cURL error when URLs contain fragments
+* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were
+ CurlExceptions
+* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)
+* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`
+* Fixed a bug that was encountered when parsing empty header parameters
+* UriTemplate now has a `setRegex()` method to match the docs
+* The `debug` request parameter now checks if it is truthy rather than if it exists
+* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin
+* Added the ability to combine URLs using strict RFC 3986 compliance
+* Command objects can now return the validation errors encountered by the command
+* Various fixes to cache revalidation (#437 and 29797e5)
+* Various fixes to the AsyncPlugin
+* Cleaned up build scripts
+
+## 3.7.4 - 2013-10-02
+
+* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)
+* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp
+ (see https://github.com/aws/aws-sdk-php/issues/147)
+* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots
+* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)
+* Updated the bundled cacert.pem (#419)
+* OauthPlugin now supports adding authentication to headers or query string (#425)
+
+## 3.7.3 - 2013-09-08
+
+* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and
+ `CommandTransferException`.
+* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description
+* Schemas are only injected into response models when explicitly configured.
+* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of
+ an EntityBody.
+* Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator.
+* Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`.
+* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()
+* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin
+* Bug fix: Visiting XML attributes first before visting XML children when serializing requests
+* Bug fix: Properly parsing headers that contain commas contained in quotes
+* Bug fix: mimetype guessing based on a filename is now case-insensitive
+
+## 3.7.2 - 2013-08-02
+
+* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander
+ See https://github.com/guzzle/guzzle/issues/371
+* Bug fix: Cookie domains are now matched correctly according to RFC 6265
+ See https://github.com/guzzle/guzzle/issues/377
+* Bug fix: GET parameters are now used when calculating an OAuth signature
+* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted
+* `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched
+* `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.
+ See https://github.com/guzzle/guzzle/issues/379
+* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See
+ https://github.com/guzzle/guzzle/pull/380
+* cURL multi cleanup and optimizations
+
+## 3.7.1 - 2013-07-05
+
+* Bug fix: Setting default options on a client now works
+* Bug fix: Setting options on HEAD requests now works. See #352
+* Bug fix: Moving stream factory before send event to before building the stream. See #353
+* Bug fix: Cookies no longer match on IP addresses per RFC 6265
+* Bug fix: Correctly parsing header parameters that are in `<>` and quotes
+* Added `cert` and `ssl_key` as request options
+* `Host` header can now diverge from the host part of a URL if the header is set manually
+* `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter
+* OAuth parameters are only added via the plugin if they aren't already set
+* Exceptions are now thrown when a URL cannot be parsed
+* Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails
+* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin
+
+## 3.7.0 - 2013-06-10
+
+* See UPGRADING.md for more information on how to upgrade.
+* Requests now support the ability to specify an array of $options when creating a request to more easily modify a
+ request. You can pass a 'request.options' configuration setting to a client to apply default request options to
+ every request created by a client (e.g. default query string variables, headers, curl options, etc).
+* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`.
+ See `Guzzle\Http\StaticClient::mount`.
+* Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests
+ created by a command (e.g. custom headers, query string variables, timeout settings, etc).
+* Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the
+ headers of a response
+* Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key
+ (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)
+* ServiceBuilders now support storing and retrieving arbitrary data
+* CachePlugin can now purge all resources for a given URI
+* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource
+* CachePlugin now uses the Vary header to determine if a resource is a cache hit
+* `Guzzle\Http\Message\Response` now implements `\Serializable`
+* Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters
+* `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable
+* Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()`
+* Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size
+* `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message
+* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older
+ Symfony users can still use the old version of Monolog.
+* Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`.
+ Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.
+* Several performance improvements to `Guzzle\Common\Collection`
+* Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
+ createRequest, head, delete, put, patch, post, options, prepareRequest
+* Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
+* Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
+* Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
+* Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
+ default `array()`
+* Added `Guzzle\Stream\StreamInterface::isRepeatable`
+* Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
+ $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
+ $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.
+* Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.
+* Removed `Guzzle\Http\ClientInterface::expandTemplate()`
+* Removed `Guzzle\Http\ClientInterface::setRequestFactory()`
+* Removed `Guzzle\Http\ClientInterface::getCurlMulti()`
+* Removed `Guzzle\Http\Message\RequestInterface::canCache`
+* Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`
+* Removed `Guzzle\Http\Message\RequestInterface::isRedirect`
+* Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
+* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting
+ `Guzzle\Common\Version::$emitWarnings` to true.
+* Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use
+ `$request->getResponseBody()->isRepeatable()` instead.
+* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+* Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
+* Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
+* Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
+* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.
+ These will work through Guzzle 4.0
+* Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params].
+* Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
+* Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.
+* Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.
+* Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
+* Marked `Guzzle\Common\Collection::inject()` as deprecated.
+* Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`
+* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
+* Always setting X-cache headers on cached responses
+* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
+* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
+ $request, Response $response);`
+* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
+* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
+* Added `CacheStorageInterface::purge($url)`
+* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
+ CanCacheStrategyInterface $canCache = null)`
+* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
+
+## 3.6.0 - 2013-05-29
+
+* ServiceDescription now implements ToArrayInterface
+* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters
+* Guzzle can now correctly parse incomplete URLs
+* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
+* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
+* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
+* Specific header implementations can be created for complex headers. When a message creates a header, it uses a
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
+ CacheControl header implementation.
+* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
+* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
+* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
+ Guzzle\Http\Curl\RequestMediator
+* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
+* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
+* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
+* Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
+* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
+* All response header helper functions return a string rather than mixing Header objects and strings inconsistently
+* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle
+ directly via interfaces
+* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
+ but are a no-op until removed.
+* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a
+ `Guzzle\Service\Command\ArrayCommandInterface`.
+* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
+ on a request while the request is still being transferred
+* The ability to case-insensitively search for header values
+* Guzzle\Http\Message\Header::hasExactHeader
+* Guzzle\Http\Message\Header::raw. Use getAll()
+* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
+ instead.
+* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
+* Added the ability to cast Model objects to a string to view debug information.
+
+## 3.5.0 - 2013-05-13
+
+* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times
+* Bug: Better cleanup of one-time events accross the board (when an event is meant to fire once, it will now remove
+ itself from the EventDispatcher)
+* Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values
+* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too
+* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a
+ non-existent key
+* Bug: All __call() method arguments are now required (helps with mocking frameworks)
+* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference
+ to help with refcount based garbage collection of resources created by sending a request
+* Deprecating ZF1 cache and log adapters. These will be removed in the next major version.
+* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it'sdeprecated). Use the
+ HistoryPlugin for a history.
+* Added a `responseBody` alias for the `response_body` location
+* Refactored internals to no longer rely on Response::getRequest()
+* HistoryPlugin can now be cast to a string
+* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests
+ and responses that are sent over the wire
+* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects
+
+## 3.4.3 - 2013-04-30
+
+* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response
+* Added a check to re-extract the temp cacert bundle from the phar before sending each request
+
+## 3.4.2 - 2013-04-29
+
+* Bug fix: Stream objects now work correctly with "a" and "a+" modes
+* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present
+* Bug fix: AsyncPlugin no longer forces HEAD requests
+* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter
+* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails
+* Setting a response on a request will write to the custom request body from the response body if one is specified
+* LogPlugin now writes to php://output when STDERR is undefined
+* Added the ability to set multiple POST files for the same key in a single call
+* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default
+* Added the ability to queue CurlExceptions to the MockPlugin
+* Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send)
+* Configuration loading now allows remote files
+
+## 3.4.1 - 2013-04-16
+
+* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti
+ handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.
+* Exceptions are now properly grouped when sending requests in parallel
+* Redirects are now properly aggregated when a multi transaction fails
+* Redirects now set the response on the original object even in the event of a failure
+* Bug fix: Model names are now properly set even when using $refs
+* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax
+* Added support for oauth_callback in OAuth signatures
+* Added support for oauth_verifier in OAuth signatures
+* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection
+
+## 3.4.0 - 2013-04-11
+
+* Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289
+* Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
+* Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
+* Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.
+* Bug fix: Added `number` type to service descriptions.
+* Bug fix: empty parameters are removed from an OAuth signature
+* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header
+* Bug fix: Fixed "array to string" error when validating a union of types in a service description
+* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream
+* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.
+* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.
+* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.
+* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if
+ the Content-Type can be determined based on the entity body or the path of the request.
+* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.
+* Added support for a PSR-3 LogAdapter.
+* Added a `command.after_prepare` event
+* Added `oauth_callback` parameter to the OauthPlugin
+* Added the ability to create a custom stream class when using a stream factory
+* Added a CachingEntityBody decorator
+* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.
+* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.
+* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies
+* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This
+ means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use
+ POST fields or files (the latter is only used when emulating a form POST in the browser).
+* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest
+
+## 3.3.1 - 2013-03-10
+
+* Added the ability to create PHP streaming responses from HTTP requests
+* Bug fix: Running any filters when parsing response headers with service descriptions
+* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing
+* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across
+ response location visitors.
+* Bug fix: Removed the possibility of creating configuration files with circular dependencies
+* RequestFactory::create() now uses the key of a POST file when setting the POST file name
+* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set
+
+## 3.3.0 - 2013-03-03
+
+* A large number of performance optimizations have been made
+* Bug fix: Added 'wb' as a valid write mode for streams
+* Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned
+* Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()`
+* BC: Removed `Guzzle\Http\Utils` class
+* BC: Setting a service description on a client will no longer modify the client's command factories.
+* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using
+ the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
+* BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to
+ lowercase
+* Operation parameter objects are now lazy loaded internally
+* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses
+* Added support for instantiating responseType=class responseClass classes. Classes must implement
+ `Guzzle\Service\Command\ResponseClassInterface`
+* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These
+ additional properties also support locations and can be used to parse JSON responses where the outermost part of the
+ JSON is an array
+* Added support for nested renaming of JSON models (rename sentAs to name)
+* CachePlugin
+ * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error
+ * Debug headers can now added to cached response in the CachePlugin
+
+## 3.2.0 - 2013-02-14
+
+* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.
+* URLs with no path no longer contain a "/" by default
+* Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url.
+* BadResponseException no longer includes the full request and response message
+* Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface
+* Adding getResponseBody() to Guzzle\Http\Message\RequestInterface
+* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription
+* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list
+* xmlEncoding can now be customized for the XML declaration of a XML service description operation
+* Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value
+ aggregation and no longer uses callbacks
+* The URL encoding implementation of Guzzle\Http\QueryString can now be customized
+* Bug fix: Filters were not always invoked for array service description parameters
+* Bug fix: Redirects now use a target response body rather than a temporary response body
+* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded
+* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives
+
+## 3.1.2 - 2013-01-27
+
+* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the
+ response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.
+* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent
+* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)
+* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()
+* Setting default headers on a client after setting the user-agent will not erase the user-agent setting
+
+## 3.1.1 - 2013-01-20
+
+* Adding wildcard support to Guzzle\Common\Collection::getPath()
+* Adding alias support to ServiceBuilder configs
+* Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface
+
+## 3.1.0 - 2013-01-12
+
+* BC: CurlException now extends from RequestException rather than BadResponseException
+* BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()
+* Added getData to ServiceDescriptionInterface
+* Added context array to RequestInterface::setState()
+* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http
+* Bug: Adding required content-type when JSON request visitor adds JSON to a command
+* Bug: Fixing the serialization of a service description with custom data
+* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing
+ an array of successful and failed responses
+* Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection
+* Added Guzzle\Http\IoEmittingEntityBody
+* Moved command filtration from validators to location visitors
+* Added `extends` attributes to service description parameters
+* Added getModels to ServiceDescriptionInterface
+
+## 3.0.7 - 2012-12-19
+
+* Fixing phar detection when forcing a cacert to system if null or true
+* Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()`
+* Cleaning up `Guzzle\Common\Collection::inject` method
+* Adding a response_body location to service descriptions
+
+## 3.0.6 - 2012-12-09
+
+* CurlMulti performance improvements
+* Adding setErrorResponses() to Operation
+* composer.json tweaks
+
+## 3.0.5 - 2012-11-18
+
+* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin
+* Bug: Response body can now be a string containing "0"
+* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert
+* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs
+* Added support for XML attributes in service description responses
+* DefaultRequestSerializer now supports array URI parameter values for URI template expansion
+* Added better mimetype guessing to requests and post files
+
+## 3.0.4 - 2012-11-11
+
+* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value
+* Bug: Cookies can now be added that have a name, domain, or value set to "0"
+* Bug: Using the system cacert bundle when using the Phar
+* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures
+* Enhanced cookie jar de-duplication
+* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added
+* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies
+* Added the ability to create any sort of hash for a stream rather than just an MD5 hash
+
+## 3.0.3 - 2012-11-04
+
+* Implementing redirects in PHP rather than cURL
+* Added PECL URI template extension and using as default parser if available
+* Bug: Fixed Content-Length parsing of Response factory
+* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.
+* Adding ToArrayInterface throughout library
+* Fixing OauthPlugin to create unique nonce values per request
+
+## 3.0.2 - 2012-10-25
+
+* Magic methods are enabled by default on clients
+* Magic methods return the result of a command
+* Service clients no longer require a base_url option in the factory
+* Bug: Fixed an issue with URI templates where null template variables were being expanded
+
+## 3.0.1 - 2012-10-22
+
+* Models can now be used like regular collection objects by calling filter, map, etc
+* Models no longer require a Parameter structure or initial data in the constructor
+* Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator`
+
+## 3.0.0 - 2012-10-15
+
+* Rewrote service description format to be based on Swagger
+ * Now based on JSON schema
+ * Added nested input structures and nested response models
+ * Support for JSON and XML input and output models
+ * Renamed `commands` to `operations`
+ * Removed dot class notation
+ * Removed custom types
+* Broke the project into smaller top-level namespaces to be more component friendly
+* Removed support for XML configs and descriptions. Use arrays or JSON files.
+* Removed the Validation component and Inspector
+* Moved all cookie code to Guzzle\Plugin\Cookie
+* Magic methods on a Guzzle\Service\Client now return the command un-executed.
+* Calling getResult() or getResponse() on a command will lazily execute the command if needed.
+* Now shipping with cURL's CA certs and using it by default
+* Added previousResponse() method to response objects
+* No longer sending Accept and Accept-Encoding headers on every request
+* Only sending an Expect header by default when a payload is greater than 1MB
+* Added/moved client options:
+ * curl.blacklist to curl.option.blacklist
+ * Added ssl.certificate_authority
+* Added a Guzzle\Iterator component
+* Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin
+* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)
+* Added a more robust caching plugin
+* Added setBody to response objects
+* Updating LogPlugin to use a more flexible MessageFormatter
+* Added a completely revamped build process
+* Cleaning up Collection class and removing default values from the get method
+* Fixed ZF2 cache adapters
+
+## 2.8.8 - 2012-10-15
+
+* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did
+
+## 2.8.7 - 2012-09-30
+
+* Bug: Fixed config file aliases for JSON includes
+* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests
+* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload
+* Bug: Hardening request and response parsing to account for missing parts
+* Bug: Fixed PEAR packaging
+* Bug: Fixed Request::getInfo
+* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail
+* Adding the ability for the namespace Iterator factory to look in multiple directories
+* Added more getters/setters/removers from service descriptions
+* Added the ability to remove POST fields from OAuth signatures
+* OAuth plugin now supports 2-legged OAuth
+
+## 2.8.6 - 2012-09-05
+
+* Added the ability to modify and build service descriptions
+* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command
+* Added a `json` parameter location
+* Now allowing dot notation for classes in the CacheAdapterFactory
+* Using the union of two arrays rather than an array_merge when extending service builder services and service params
+* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references
+ in service builder config files.
+* Services defined in two different config files that include one another will by default replace the previously
+ defined service, but you can now create services that extend themselves and merge their settings over the previous
+* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like
+ '_default' with a default JSON configuration file.
+
+## 2.8.5 - 2012-08-29
+
+* Bug: Suppressed empty arrays from URI templates
+* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching
+* Added support for HTTP responses that do not contain a reason phrase in the start-line
+* AbstractCommand commands are now invokable
+* Added a way to get the data used when signing an Oauth request before a request is sent
+
+## 2.8.4 - 2012-08-15
+
+* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin
+* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable.
+* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream
+* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream
+* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())
+* Added additional response status codes
+* Removed SSL information from the default User-Agent header
+* DELETE requests can now send an entity body
+* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries
+* Added the ability of the MockPlugin to consume mocked request bodies
+* LogPlugin now exposes request and response objects in the extras array
+
+## 2.8.3 - 2012-07-30
+
+* Bug: Fixed a case where empty POST requests were sent as GET requests
+* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body
+* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new
+* Added multiple inheritance to service description commands
+* Added an ApiCommandInterface and added ``getParamNames()`` and ``hasParam()``
+* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything
+* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles
+
+## 2.8.2 - 2012-07-24
+
+* Bug: Query string values set to 0 are no longer dropped from the query string
+* Bug: A Collection object is no longer created each time a call is made to ``Guzzle\Service\Command\AbstractCommand::getRequestHeaders()``
+* Bug: ``+`` is now treated as an encoded space when parsing query strings
+* QueryString and Collection performance improvements
+* Allowing dot notation for class paths in filters attribute of a service descriptions
+
+## 2.8.1 - 2012-07-16
+
+* Loosening Event Dispatcher dependency
+* POST redirects can now be customized using CURLOPT_POSTREDIR
+
+## 2.8.0 - 2012-07-15
+
+* BC: Guzzle\Http\Query
+ * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)
+ * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()
+ * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)
+ * Changed the aggregation functions of QueryString to be static methods
+ * Can now use fromString() with querystrings that have a leading ?
+* cURL configuration values can be specified in service descriptions using ``curl.`` prefixed parameters
+* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body
+* Cookies are no longer URL decoded by default
+* Bug: URI template variables set to null are no longer expanded
+
+## 2.7.2 - 2012-07-02
+
+* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser.
+* BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty()
+* CachePlugin now allows for a custom request parameter function to check if a request can be cached
+* Bug fix: CachePlugin now only caches GET and HEAD requests by default
+* Bug fix: Using header glue when transferring headers over the wire
+* Allowing deeply nested arrays for composite variables in URI templates
+* Batch divisors can now return iterators or arrays
+
+## 2.7.1 - 2012-06-26
+
+* Minor patch to update version number in UA string
+* Updating build process
+
+## 2.7.0 - 2012-06-25
+
+* BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes.
+* BC: Removed magic setX methods from commands
+* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method
+* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.
+* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)
+* Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace
+* Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin
+* Added the ability to set POST fields and files in a service description
+* Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method
+* Adding a command.before_prepare event to clients
+* Added BatchClosureTransfer and BatchClosureDivisor
+* BatchTransferException now includes references to the batch divisor and transfer strategies
+* Fixed some tests so that they pass more reliably
+* Added Guzzle\Common\Log\ArrayLogAdapter
+
+## 2.6.6 - 2012-06-10
+
+* BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin
+* BC: Removing Guzzle\Service\Command\CommandSet
+* Adding generic batching system (replaces the batch queue plugin and command set)
+* Updating ZF cache and log adapters and now using ZF's composer repository
+* Bug: Setting the name of each ApiParam when creating through an ApiCommand
+* Adding result_type, result_doc, deprecated, and doc_url to service descriptions
+* Bug: Changed the default cookie header casing back to 'Cookie'
+
+## 2.6.5 - 2012-06-03
+
+* BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource()
+* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from
+* BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data
+* BC: Renaming methods in the CookieJarInterface
+* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations
+* Making the default glue for HTTP headers ';' instead of ','
+* Adding a removeValue to Guzzle\Http\Message\Header
+* Adding getCookies() to request interface.
+* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()
+
+## 2.6.4 - 2012-05-30
+
+* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.
+* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand
+* Bug: Fixing magic method command calls on clients
+* Bug: Email constraint only validates strings
+* Bug: Aggregate POST fields when POST files are present in curl handle
+* Bug: Fixing default User-Agent header
+* Bug: Only appending or prepending parameters in commands if they are specified
+* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes
+* Allowing the use of dot notation for class namespaces when using instance_of constraint
+* Added any_match validation constraint
+* Added an AsyncPlugin
+* Passing request object to the calculateWait method of the ExponentialBackoffPlugin
+* Allowing the result of a command object to be changed
+* Parsing location and type sub values when instantiating a service description rather than over and over at runtime
+
+## 2.6.3 - 2012-05-23
+
+* [BC] Guzzle\Common\FromConfigInterface no longer requires any config options.
+* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.
+* You can now use an array of data when creating PUT request bodies in the request factory.
+* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.
+* [Http] Adding support for Content-Type in multipart POST uploads per upload
+* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])
+* Adding more POST data operations for easier manipulation of POST data.
+* You can now set empty POST fields.
+* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.
+* Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.
+* CS updates
+
+## 2.6.2 - 2012-05-19
+
+* [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method.
+
+## 2.6.1 - 2012-05-19
+
+* [BC] Removing 'path' support in service descriptions. Use 'uri'.
+* [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.
+* [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it.
+* [BC] Removing Guzzle\Common\XmlElement.
+* All commands, both dynamic and concrete, have ApiCommand objects.
+* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.
+* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.
+* Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible.
+
+## 2.6.0 - 2012-05-15
+
+* [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder
+* [BC] Executing a Command returns the result of the command rather than the command
+* [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed.
+* [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args.
+* [BC] Moving ResourceIterator* to Guzzle\Service\Resource
+* [BC] Completely refactored ResourceIterators to iterate over a cloned command object
+* [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate
+* [BC] Guzzle\Guzzle is now deprecated
+* Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject
+* Adding Guzzle\Version class to give version information about Guzzle
+* Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate()
+* Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data
+* ServiceDescription and ServiceBuilder are now cacheable using similar configs
+* Changing the format of XML and JSON service builder configs. Backwards compatible.
+* Cleaned up Cookie parsing
+* Trimming the default Guzzle User-Agent header
+* Adding a setOnComplete() method to Commands that is called when a command completes
+* Keeping track of requests that were mocked in the MockPlugin
+* Fixed a caching bug in the CacheAdapterFactory
+* Inspector objects can be injected into a Command object
+* Refactoring a lot of code and tests to be case insensitive when dealing with headers
+* Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL
+* Adding the ability to set global option overrides to service builder configs
+* Adding the ability to include other service builder config files from within XML and JSON files
+* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.
+
+## 2.5.0 - 2012-05-08
+
+* Major performance improvements
+* [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated.
+* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.
+* [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}"
+* Added the ability to passed parameters to all requests created by a client
+* Added callback functionality to the ExponentialBackoffPlugin
+* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.
+* Rewinding request stream bodies when retrying requests
+* Exception is thrown when JSON response body cannot be decoded
+* Added configurable magic method calls to clients and commands. This is off by default.
+* Fixed a defect that added a hash to every parsed URL part
+* Fixed duplicate none generation for OauthPlugin.
+* Emitting an event each time a client is generated by a ServiceBuilder
+* Using an ApiParams object instead of a Collection for parameters of an ApiCommand
+* cache.* request parameters should be renamed to params.cache.*
+* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc). See CurlHandle.
+* Added the ability to disable type validation of service descriptions
+* ServiceDescriptions and ServiceBuilders are now Serializable
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/LICENSE b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/LICENSE
new file mode 100755
index 0000000..d51aa69
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Michael Dowling, https://github.com/mtdowling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/README.md b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/README.md
new file mode 100755
index 0000000..6be06bf
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/README.md
@@ -0,0 +1,57 @@
+Guzzle, PHP HTTP client and webservice framework
+================================================
+
+# This is an old version of Guzzle
+
+This repository is for Guzzle 3.x. Guzzle 5.x, the new version of Guzzle, has
+been released and is available at
+[https://github.com/guzzle/guzzle](https://github.com/guzzle/guzzle). The
+documentation for Guzzle version 5+ can be found at
+[http://guzzlephp.org](http://guzzlephp.org).
+
+Guzzle 3 is only maintained for bug and security fixes. Guzzle 3 will be EOL
+at some point in late 2015.
+
+### About Guzzle 3
+
+[](https://packagist.org/packages/guzzle/guzzle)
+ [](http://travis-ci.org/guzzle/guzzle3)
+
+- Extremely powerful API provides all the power of cURL with a simple interface.
+- Truly take advantage of HTTP/1.1 with persistent connections, connection pooling, and parallel requests.
+- Service description DSL allows you build awesome web service clients faster.
+- Symfony2 event-based plugin system allows you to completely modify the behavior of a request.
+
+Get answers with: [Documentation](http://guzzle3.readthedocs.org/en/latest/), [Forums](https://groups.google.com/forum/?hl=en#!forum/guzzle), IRC ([#guzzlephp](irc://irc.freenode.net/#guzzlephp) @ irc.freenode.net)
+
+### Installing via Composer
+
+The recommended way to install Guzzle is through [Composer](http://getcomposer.org).
+
+```bash
+# Install Composer
+curl -sS https://getcomposer.org/installer | php
+
+# Add Guzzle as a dependency
+php composer.phar require guzzle/guzzle:~3.9
+```
+
+After installing, you need to require Composer's autoloader:
+
+```php
+require 'vendor/autoload.php';
+```
+## Known Issues
+
+1. Problem following a specific redirect: https://github.com/guzzle/guzzle/issues/385.
+ This has been fixed in Guzzle 4/5.
+2. Root XML attributes not serialized in a service description: https://github.com/guzzle/guzzle3/issues/5.
+ This has been fixed in Guzzle 4/5.
+3. Accept-Encoding not preserved when following redirect: https://github.com/guzzle/guzzle3/issues/9
+ Fixed in Guzzle 4/5.
+4. String "Array" Transmitted w/ PostFiles and Duplicate Aggregator: https://github.com/guzzle/guzzle3/issues/10
+ Fixed in Guzzle 4/5.
+5. Recursive model references with array items: https://github.com/guzzle/guzzle3/issues/13
+ Fixed in Guzzle 4/5
+6. String "Array" Transmitted w/ PostFiles and Duplicate Aggregator: https://github.com/guzzle/guzzle3/issues/10
+ Fixed in Guzzle 4/5.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/UPGRADING.md b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/UPGRADING.md
new file mode 100755
index 0000000..f58bf11
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/UPGRADING.md
@@ -0,0 +1,537 @@
+Guzzle Upgrade Guide
+====================
+
+3.6 to 3.7
+----------
+
+### Deprecations
+
+- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:
+
+```php
+\Guzzle\Common\Version::$emitWarnings = true;
+```
+
+The following APIs and options have been marked as deprecated:
+
+- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.
+- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
+- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
+- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
+- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
+- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
+- Marked `Guzzle\Common\Collection::inject()` as deprecated.
+- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use
+ `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or
+ `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`
+
+3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational
+request methods. When paired with a client's configuration settings, these options allow you to specify default settings
+for various aspects of a request. Because these options make other previous configuration options redundant, several
+configuration options and methods of a client and AbstractCommand have been deprecated.
+
+- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.
+- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.
+- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`
+- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0
+
+ $command = $client->getCommand('foo', array(
+ 'command.headers' => array('Test' => '123'),
+ 'command.response_body' => '/path/to/file'
+ ));
+
+ // Should be changed to:
+
+ $command = $client->getCommand('foo', array(
+ 'command.request_options' => array(
+ 'headers' => array('Test' => '123'),
+ 'save_as' => '/path/to/file'
+ )
+ ));
+
+### Interface changes
+
+Additions and changes (you will need to update any implementations or subclasses you may have created):
+
+- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
+ createRequest, head, delete, put, patch, post, options, prepareRequest
+- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
+- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
+- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
+- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
+ default `array()`
+- Added `Guzzle\Stream\StreamInterface::isRepeatable`
+- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
+
+The following methods were removed from interfaces. All of these methods are still available in the concrete classes
+that implement them, but you should update your code to use alternative methods:
+
+- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
+ `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
+ `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or
+ `$client->setDefaultOption('headers/{header_name}', 'value')`. or
+ `$client->setDefaultOption('headers', array('header_name' => 'value'))`.
+- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.
+- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail.
+- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail.
+- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.
+- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin.
+- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin.
+- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin.
+
+### Cache plugin breaking changes
+
+- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
+- Always setting X-cache headers on cached responses
+- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
+- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
+ $request, Response $response);`
+- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
+- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
+- Added `CacheStorageInterface::purge($url)`
+- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
+ CanCacheStrategyInterface $canCache = null)`
+- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
+
+3.5 to 3.6
+----------
+
+* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
+* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
+* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
+ For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().
+ Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.
+* Specific header implementations can be created for complex headers. When a message creates a header, it uses a
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
+ CacheControl header implementation.
+* Moved getLinks() from Response to just be used on a Link header object.
+
+If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the
+HeaderInterface (e.g. toArray(), getAll(), etc).
+
+### Interface changes
+
+* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
+* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
+* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
+ Guzzle\Http\Curl\RequestMediator
+* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
+* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
+* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
+
+### Removed deprecated functions
+
+* Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
+* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
+
+### Deprecations
+
+* The ability to case-insensitively search for header values
+* Guzzle\Http\Message\Header::hasExactHeader
+* Guzzle\Http\Message\Header::raw. Use getAll()
+* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
+ instead.
+
+### Other changes
+
+* All response header helper functions return a string rather than mixing Header objects and strings inconsistently
+* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle
+ directly via interfaces
+* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
+ but are a no-op until removed.
+* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a
+ `Guzzle\Service\Command\ArrayCommandInterface`.
+* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
+ on a request while the request is still being transferred
+* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
+
+3.3 to 3.4
+----------
+
+Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
+
+3.2 to 3.3
+----------
+
+### Response::getEtag() quote stripping removed
+
+`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
+
+### Removed `Guzzle\Http\Utils`
+
+The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
+
+### Stream wrapper and type
+
+`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to lowercase.
+
+### curl.emit_io became emit_io
+
+Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
+'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
+
+3.1 to 3.2
+----------
+
+### CurlMulti is no longer reused globally
+
+Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
+to a single client can pollute requests dispatched from other clients.
+
+If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
+ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
+created.
+
+```php
+$multi = new Guzzle\Http\Curl\CurlMulti();
+$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
+$builder->addListener('service_builder.create_client', function ($event) use ($multi) {
+ $event['client']->setCurlMulti($multi);
+}
+});
+```
+
+### No default path
+
+URLs no longer have a default path value of '/' if no path was specified.
+
+Before:
+
+```php
+$request = $client->get('http://www.foo.com');
+echo $request->getUrl();
+// >> http://www.foo.com/
+```
+
+After:
+
+```php
+$request = $client->get('http://www.foo.com');
+echo $request->getUrl();
+// >> http://www.foo.com
+```
+
+### Less verbose BadResponseException
+
+The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
+response information. You can, however, get access to the request and response object by calling `getRequest()` or
+`getResponse()` on the exception object.
+
+### Query parameter aggregation
+
+Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
+setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
+responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
+
+2.8 to 3.x
+----------
+
+### Guzzle\Service\Inspector
+
+Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
+
+**Before**
+
+```php
+use Guzzle\Service\Inspector;
+
+class YourClient extends \Guzzle\Service\Client
+{
+ public static function factory($config = array())
+ {
+ $default = array();
+ $required = array('base_url', 'username', 'api_key');
+ $config = Inspector::fromConfig($config, $default, $required);
+
+ $client = new self(
+ $config->get('base_url'),
+ $config->get('username'),
+ $config->get('api_key')
+ );
+ $client->setConfig($config);
+
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
+
+ return $client;
+ }
+```
+
+**After**
+
+```php
+use Guzzle\Common\Collection;
+
+class YourClient extends \Guzzle\Service\Client
+{
+ public static function factory($config = array())
+ {
+ $default = array();
+ $required = array('base_url', 'username', 'api_key');
+ $config = Collection::fromConfig($config, $default, $required);
+
+ $client = new self(
+ $config->get('base_url'),
+ $config->get('username'),
+ $config->get('api_key')
+ );
+ $client->setConfig($config);
+
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
+
+ return $client;
+ }
+```
+
+### Convert XML Service Descriptions to JSON
+
+**Before**
+
+```xml
+
+
+
+
+
+ Get a list of groups
+
+
+ Uses a search query to get a list of groups
+
+
+
+ Create a group
+
+
+
+
+ Delete a group by ID
+
+
+
+
+
+
+ Update a group
+
+
+
+
+
+
+```
+
+**After**
+
+```json
+{
+ "name": "Zendesk REST API v2",
+ "apiVersion": "2012-12-31",
+ "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
+ "operations": {
+ "list_groups": {
+ "httpMethod":"GET",
+ "uri": "groups.json",
+ "summary": "Get a list of groups"
+ },
+ "search_groups":{
+ "httpMethod":"GET",
+ "uri": "search.json?query=\"{query} type:group\"",
+ "summary": "Uses a search query to get a list of groups",
+ "parameters":{
+ "query":{
+ "location": "uri",
+ "description":"Zendesk Search Query",
+ "type": "string",
+ "required": true
+ }
+ }
+ },
+ "create_group": {
+ "httpMethod":"POST",
+ "uri": "groups.json",
+ "summary": "Create a group",
+ "parameters":{
+ "data": {
+ "type": "array",
+ "location": "body",
+ "description":"Group JSON",
+ "filters": "json_encode",
+ "required": true
+ },
+ "Content-Type":{
+ "type": "string",
+ "location":"header",
+ "static": "application/json"
+ }
+ }
+ },
+ "delete_group": {
+ "httpMethod":"DELETE",
+ "uri": "groups/{id}.json",
+ "summary": "Delete a group",
+ "parameters":{
+ "id":{
+ "location": "uri",
+ "description":"Group to delete by ID",
+ "type": "integer",
+ "required": true
+ }
+ }
+ },
+ "get_group": {
+ "httpMethod":"GET",
+ "uri": "groups/{id}.json",
+ "summary": "Get a ticket",
+ "parameters":{
+ "id":{
+ "location": "uri",
+ "description":"Group to get by ID",
+ "type": "integer",
+ "required": true
+ }
+ }
+ },
+ "update_group": {
+ "httpMethod":"PUT",
+ "uri": "groups/{id}.json",
+ "summary": "Update a group",
+ "parameters":{
+ "id": {
+ "location": "uri",
+ "description":"Group to update by ID",
+ "type": "integer",
+ "required": true
+ },
+ "data": {
+ "type": "array",
+ "location": "body",
+ "description":"Group JSON",
+ "filters": "json_encode",
+ "required": true
+ },
+ "Content-Type":{
+ "type": "string",
+ "location":"header",
+ "static": "application/json"
+ }
+ }
+ }
+}
+```
+
+### Guzzle\Service\Description\ServiceDescription
+
+Commands are now called Operations
+
+**Before**
+
+```php
+use Guzzle\Service\Description\ServiceDescription;
+
+$sd = new ServiceDescription();
+$sd->getCommands(); // @returns ApiCommandInterface[]
+$sd->hasCommand($name);
+$sd->getCommand($name); // @returns ApiCommandInterface|null
+$sd->addCommand($command); // @param ApiCommandInterface $command
+```
+
+**After**
+
+```php
+use Guzzle\Service\Description\ServiceDescription;
+
+$sd = new ServiceDescription();
+$sd->getOperations(); // @returns OperationInterface[]
+$sd->hasOperation($name);
+$sd->getOperation($name); // @returns OperationInterface|null
+$sd->addOperation($operation); // @param OperationInterface $operation
+```
+
+### Guzzle\Common\Inflection\Inflector
+
+Namespace is now `Guzzle\Inflection\Inflector`
+
+### Guzzle\Http\Plugin
+
+Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
+
+### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
+
+Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
+
+**Before**
+
+```php
+use Guzzle\Common\Log\ClosureLogAdapter;
+use Guzzle\Http\Plugin\LogPlugin;
+
+/** @var \Guzzle\Http\Client */
+$client;
+
+// $verbosity is an integer indicating desired message verbosity level
+$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
+```
+
+**After**
+
+```php
+use Guzzle\Log\ClosureLogAdapter;
+use Guzzle\Log\MessageFormatter;
+use Guzzle\Plugin\Log\LogPlugin;
+
+/** @var \Guzzle\Http\Client */
+$client;
+
+// $format is a string indicating desired message format -- @see MessageFormatter
+$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
+```
+
+### Guzzle\Http\Plugin\CurlAuthPlugin
+
+Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
+
+### Guzzle\Http\Plugin\ExponentialBackoffPlugin
+
+Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
+
+**Before**
+
+```php
+use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
+
+$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
+ ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
+ ));
+
+$client->addSubscriber($backoffPlugin);
+```
+
+**After**
+
+```php
+use Guzzle\Plugin\Backoff\BackoffPlugin;
+use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
+
+// Use convenient factory method instead -- see implementation for ideas of what
+// you can do with chaining backoff strategies
+$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
+ HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
+ ));
+$client->addSubscriber($backoffPlugin);
+```
+
+### Known Issues
+
+#### [BUG] Accept-Encoding header behavior changed unintentionally.
+
+(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
+
+In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
+properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
+See issue #217 for a workaround, or use a version containing the fix.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/build.xml b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/build.xml
new file mode 100755
index 0000000..2aa62ba
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/build.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/composer.json
new file mode 100755
index 0000000..59424b3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/composer.json
@@ -0,0 +1,82 @@
+{
+ "name": "guzzle/guzzle",
+ "type": "library",
+ "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
+ "keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
+ "homepage": "http://guzzlephp.org/",
+ "license": "MIT",
+
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Guzzle Community",
+ "homepage": "https://github.com/guzzle/guzzle/contributors"
+ }
+ ],
+
+ "replace": {
+ "guzzle/batch": "self.version",
+ "guzzle/cache": "self.version",
+ "guzzle/common": "self.version",
+ "guzzle/http": "self.version",
+ "guzzle/inflection": "self.version",
+ "guzzle/iterator": "self.version",
+ "guzzle/log": "self.version",
+ "guzzle/parser": "self.version",
+ "guzzle/plugin": "self.version",
+ "guzzle/plugin-async": "self.version",
+ "guzzle/plugin-backoff": "self.version",
+ "guzzle/plugin-cache": "self.version",
+ "guzzle/plugin-cookie": "self.version",
+ "guzzle/plugin-curlauth": "self.version",
+ "guzzle/plugin-error-response": "self.version",
+ "guzzle/plugin-history": "self.version",
+ "guzzle/plugin-log": "self.version",
+ "guzzle/plugin-md5": "self.version",
+ "guzzle/plugin-mock": "self.version",
+ "guzzle/plugin-oauth": "self.version",
+ "guzzle/service": "self.version",
+ "guzzle/stream": "self.version"
+ },
+
+ "require": {
+ "php": ">=5.3.3",
+ "ext-curl": "*",
+ "symfony/event-dispatcher": "~2.1"
+ },
+
+ "autoload": {
+ "psr-0": {
+ "Guzzle": "src/",
+ "Guzzle\\Tests": "tests/"
+ }
+ },
+
+ "suggest": {
+ "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
+ },
+
+ "scripts": {
+ "test": "phpunit"
+ },
+
+ "require-dev": {
+ "doctrine/cache": "~1.3",
+ "symfony/class-loader": "~2.1",
+ "monolog/monolog": "~1.0",
+ "psr/log": "~1.0",
+ "zendframework/zend-cache": "2.*,<2.3",
+ "zendframework/zend-log": "2.*,<2.3",
+ "phpunit/phpunit": "3.7.*"
+ },
+
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.9-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/Makefile b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/Makefile
new file mode 100755
index 0000000..d92e03f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make ' where is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Guzzle.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Guzzle.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Guzzle"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Guzzle"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json
new file mode 100755
index 0000000..8168302
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_downloads/guzzle-schema-1.0.json
@@ -0,0 +1,176 @@
+{
+ "additionalProperties": true,
+ "name": {
+ "type": "string",
+ "description": "Name of the web service"
+ },
+ "apiVersion": {
+ "type": ["string", "number"],
+ "description": "Version identifier that the service description is compatible with"
+ },
+ "baseUrl": {
+ "type": "string",
+ "description": "Base URL of the web service. Any relative URI specified in an operation will be merged with the baseUrl using the process defined in RFC 2396"
+ },
+ "basePath": {
+ "type": "string",
+ "description": "Alias of baseUrl"
+ },
+ "_description": {
+ "type": "string",
+ "description": "Short summary of the web service. This is actually called 'description' but this JSON schema wont validate using just description."
+ },
+ "operations": {
+ "description": "Operations of the web service",
+ "type": "object",
+ "properties": {
+ "extends": {
+ "type": "string",
+ "description": "Extend from another operation by name. The parent operation must be defined before the child."
+ },
+ "httpMethod": {
+ "type": "string",
+ "description": "HTTP method used with the operation (e.g. GET, POST, PUT, DELETE, PATCH, etc)"
+ },
+ "uri": {
+ "type": "string",
+ "description": "URI of the operation. The uri attribute can contain URI templates. The variables of the URI template are parameters of the operation with a location value of uri"
+ },
+ "summary": {
+ "type": "string",
+ "description": "Short summary of what the operation does"
+ },
+ "class": {
+ "type": "string",
+ "description": "Custom class to instantiate instead of the default Guzzle\\Service\\Command\\OperationCommand"
+ },
+ "responseClass": {
+ "type": "string",
+ "description": "This is what is returned from the method. Can be a primitive, class name, or model name."
+ },
+ "responseNotes": {
+ "type": "string",
+ "description": "A description of the response returned by the operation"
+ },
+ "responseType": {
+ "type": "string",
+ "description": "The type of response that the operation creates. If not specified, this value will be automatically inferred based on whether or not there is a model matching the name, if a matching class name is found, or set to 'primitive' by default.",
+ "enum": [ "primitive", "class", "model", "documentation" ]
+ },
+ "deprecated": {
+ "type": "boolean",
+ "description": "Whether or not the operation is deprecated"
+ },
+ "errorResponses": {
+ "description": "Errors that could occur while executing the operation",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "number",
+ "description": "HTTP response status code of the error"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Response reason phrase or description of the error"
+ },
+ "class": {
+ "type": "string",
+ "description": "A custom exception class that would be thrown if the error is encountered"
+ }
+ }
+ }
+ },
+ "data": {
+ "type": "object",
+ "additionalProperties": "true"
+ },
+ "parameters": {
+ "$ref": "parameters",
+ "description": "Parameters of the operation. Parameters are used to define how input data is serialized into a HTTP request."
+ },
+ "additionalParameters": {
+ "$ref": "parameters",
+ "description": "Validation and serialization rules for any parameter supplied to the operation that was not explicitly defined."
+ }
+ }
+ },
+ "models": {
+ "description": "Schema models that can be referenced throughout the service description. Models can be used to define how an HTTP response is parsed into a Guzzle\\Service\\Resource\\Model object.",
+ "type": "object",
+ "properties": {
+ "$ref": "parameters",
+ "description": "Parameters of the model. When a model is referenced in a responseClass attribute of an operation, parameters define how a HTTP response message is parsed into a Guzzle\\Service\\Resource\\Model."
+ }
+ },
+ "includes": {
+ "description": "Service description files to include and extend from (can be a .json, .js, or .php file)",
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": ".+\\.(js|json|php)$"
+ }
+ },
+ "definitions": {
+ "parameters": {
+ "extends": "http://json-schema.org/schema",
+ "id": "parameters",
+ "name": {
+ "type": "string",
+ "description": "Unique name of the parameter"
+ },
+ "type": {
+ "type": ["string", "array"],
+ "description": "Type of variable (string, number, integer, boolean, object, array, numeric, null, any). Types are using for validation and determining the structure of a parameter. You can use a union type by providing an array of simple types. If one of the union types matches the provided value, then the value is valid."
+ },
+ "instanceOf": {
+ "type": "string",
+ "description": "When the type is an object, you can specify the class that the object must implement"
+ },
+ "required": {
+ "type": "boolean",
+ "description": "Whether or not the parameter is required"
+ },
+ "default": {
+ "description": "Default value to use if no value is supplied"
+ },
+ "static": {
+ "type": "bool",
+ "description": "Set to true to specify that the parameter value cannot be changed from the default setting"
+ },
+ "description": {
+ "type": "string",
+ "description": "Documentation of the parameter"
+ },
+ "location": {
+ "type": "string",
+ "description": "The location of a request used to apply a parameter. Custom locations can be registered with a command, but the defaults are uri, query, statusCode, reasonPhrase, header, body, json, xml, postField, postFile, responseBody"
+ },
+ "sentAs": {
+ "type": "string",
+ "description": "Specifies how the data being modeled is sent over the wire. For example, you may wish to include certain headers in a response model that have a normalized casing of FooBar, but the actual header is x-foo-bar. In this case, sentAs would be set to x-foo-bar."
+ },
+ "filters": {
+ "type": "array",
+ "description": "Array of static method names to to run a parameter value through. Each value in the array must be a string containing the full class path to a static method or an array of complex filter information. You can specify static methods of classes using the full namespace class name followed by ‘::’ (e.g. FooBar::baz()). Some filters require arguments in order to properly filter a value. For complex filters, use a hash containing a ‘method’ key pointing to a static method, and an ‘args’ key containing an array of positional arguments to pass to the method. Arguments can contain keywords that are replaced when filtering a value: '@value‘ is replaced with the value being validated, '@api‘ is replaced with the Parameter object.",
+ "items": {
+ "type": ["string", {
+ "object": {
+ "properties": {
+ "method": {
+ "type": "string",
+ "description": "PHP function to call",
+ "required": true
+ },
+ "args": {
+ "type": "array"
+ }
+ }
+ }
+ }]
+ }
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/guzzle-icon.png b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/guzzle-icon.png
new file mode 100755
index 0000000..f1017f7
Binary files /dev/null and b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/guzzle-icon.png differ
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/homepage.css b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/homepage.css
new file mode 100755
index 0000000..70c46d8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/homepage.css
@@ -0,0 +1,122 @@
+/* Hero unit on homepage */
+
+.hero-unit h1 {
+ font-size: 49px;
+ margin-bottom: 12px;
+}
+
+.hero-unit {
+ padding: 40px;
+}
+
+.hero-unit p {
+ font-size: 17px;
+}
+
+.masthead img {
+ float: left;
+ margin-right: 17px;
+}
+
+.hero-unit ul li {
+ margin-left: 220px;
+}
+
+.hero-unit .buttons {
+ text-align: center;
+}
+
+.jumbotron {
+ position: relative;
+ padding: 40px 0;
+ color: #fff;
+ text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075);
+ background: #00312F;
+ background: -moz-linear-gradient(45deg, #002F31 0%, #335A6D 100%);
+ background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#00312D), color-stop(100%,#33566D));
+ background: -webkit-linear-gradient(45deg, #020031 0%,#334F6D 100%);
+ background: -o-linear-gradient(45deg, #002D31 0%,#334D6D 100%);
+ background: -ms-linear-gradient(45deg, #002F31 0%,#33516D 100%);
+ background: linear-gradient(45deg, #020031 0%,#33516D 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#020031', endColorstr='#6d3353',GradientType=1 );
+ -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2);
+ -moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2);
+ box-shadow: inset 0 3px 7px rgba(0, 0, 0, .2), inset 0 -3px 7px rgba(0, 0, 0, .2);
+}
+
+.jumbotron h1 {
+ font-size: 80px;
+ font-weight: bold;
+ letter-spacing: -1px;
+ line-height: 1;
+}
+
+.jumbotron p {
+ font-size: 24px;
+ font-weight: 300;
+ line-height: 1.25;
+ margin-bottom: 30px;
+}
+
+.masthead {
+ padding: 40px 0 30px;
+ margin-bottom: 0;
+ color: #fff;
+ margin-top: -19px;
+}
+
+.masthead h1 {
+ display: none;
+}
+
+.masthead p {
+ font-size: 40px;
+ font-weight: 200;
+ line-height: 1.25;
+ margin: 12px 0 0 0;
+}
+
+.masthead .btn {
+ padding: 19px 24px;
+ font-size: 24px;
+ font-weight: 200;
+ border: 0;
+}
+
+/* Social bar on homepage */
+
+.social {
+ padding: 2px 0;
+ text-align: center;
+ background-color: #f5f5f5;
+ border-top: 1px solid #fff;
+ border-bottom: 1px solid #ddd;
+ margin: 0 0 20px 0;
+}
+
+.social ul {
+ margin-top: 0;
+}
+
+.social-buttons {
+ margin-left: 0;
+ margin-bottom: 0;
+ padding-left: 0;
+ list-style: none;
+}
+
+.social-buttons li {
+ display: inline-block;
+ padding: 5px 8px;
+ line-height: 1;
+ *display: inline;
+ *zoom: 1;
+}
+
+.center-announcement {
+ padding: 10px;
+ background-color: rgb(238, 243, 255);
+ border-radius: 8px;
+ text-align: center;
+ margin: 24px 0;
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/logo.png b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/logo.png
new file mode 100755
index 0000000..965a4ef
Binary files /dev/null and b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/logo.png differ
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/prettify.css b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/prettify.css
new file mode 100755
index 0000000..4d410b1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/prettify.css
@@ -0,0 +1,41 @@
+.com {
+ color: #93A1A1;
+}
+.lit {
+ color: #195F91;
+}
+.pun, .opn, .clo {
+ color: #93A1A1;
+}
+.fun {
+ color: #DC322F;
+}
+.str, .atv {
+ color: #DD1144;
+}
+.kwd, .linenums .tag {
+ color: #1E347B;
+}
+.typ, .atn, .dec, .var {
+ color: teal;
+}
+.pln {
+ color: #48484C;
+}
+.prettyprint {
+ background-color: #F7F7F9;
+ border: 1px solid #E1E1E8;
+ padding: 8px;
+}
+.prettyprint.linenums {
+ box-shadow: 40px 0 0 #FBFBFC inset, 41px 0 0 #ECECF0 inset;
+}
+ol.linenums {
+ margin: 0 0 0 33px;
+}
+ol.linenums li {
+ color: #BEBEC5;
+ line-height: 18px;
+ padding-left: 12px;
+ text-shadow: 0 1px 0 #FFFFFF;
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/prettify.js b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/prettify.js
new file mode 100755
index 0000000..eef5ad7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_static/prettify.js
@@ -0,0 +1,28 @@
+var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
+(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
+[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
+l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
+q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
+q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
+"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
+a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
+for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
+H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
+J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
+I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]+/],["dec",/^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^
+
+
+
+
+
+
+
+
+
+
Introducing Guzzle
+
+
Guzzle takes the pain out of sending HTTP requests and the redundancy out of creating web service clients. It's
+ a framework that includes the tools needed to create a robust web service client, including:
+ Service descriptions for defining the inputs and outputs of an API, resource iterators for traversing
+ paginated resources, batching for sending a large number of requests as efficiently as possible.
+
+
+ All the power of cURL with a simple interface.
+ Persistent connections and parallel requests.
+ Streams request and response bodies
+ Service descriptions for quickly building clients.
+ Powered by the Symfony2 EventDispatcher.
+ Use all of the code or only specific components .
+ Plugins for caching, logging, OAuth, mocks, and more
+ Includes a custom node.js webserver to test your clients .
+
+
+
+ Guzzle is now part of Drupal 8 core and powers the official
AWS SDK for PHP
+
+
+
GitHub Example
+
+
<?php
+require_once 'vendor/autoload.php';
+use Guzzle\Http\Client;
+
+// Create a client and provide a base URL
+$client = new Client('https://api.github.com');
+// Create a request with basic Auth
+$request = $client->get('/user')->setAuth('user', 'pass');
+// Send the request and get the response
+$response = $request->send();
+echo $response->getBody();
+// >>> {"type":"User", ...
+echo $response->getHeader('Content-Length');
+// >>> 792
+
+
+
Twitter Example
+
<?php
+// Create a client to work with the Twitter API
+$client = new Client('https://api.twitter.com/{version}', array(
+ 'version' => '1.1'
+));
+
+// Sign all requests with the OauthPlugin
+$client->addSubscriber(new Guzzle\Plugin\Oauth\OauthPlugin(array(
+ 'consumer_key' => '***',
+ 'consumer_secret' => '***',
+ 'token' => '***',
+ 'token_secret' => '***'
+)));
+
+echo $client->get('statuses/user_timeline.json')->send()->getBody();
+// >>> {"public_gists":6,"type":"User" ...
+
+// Create a tweet using POST
+$request = $client->post('statuses/update.json', null, array(
+ 'status' => 'Tweeted with Guzzle, http://guzzlephp.org'
+));
+
+// Send the request and parse the JSON response into an array
+$data = $request->send()->json();
+echo $data['text'];
+// >>> Tweeted with Guzzle, http://t.co/kngJMfRk
+
+
+
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_templates/leftbar.html b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_templates/leftbar.html
new file mode 100755
index 0000000..e69de29
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_templates/nav_links.html b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_templates/nav_links.html
new file mode 100755
index 0000000..d4f2165
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/_templates/nav_links.html
@@ -0,0 +1,5 @@
+ Docs
+API
+GitHub
+Forum
+IRC
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/batching/batching.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/batching/batching.rst
new file mode 100755
index 0000000..57f04d8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/batching/batching.rst
@@ -0,0 +1,183 @@
+========
+Batching
+========
+
+Guzzle provides a fairly generic and very customizable batching framework that allows developers to efficiently
+transfer requests in parallel.
+
+Sending requests and commands in parallel
+-----------------------------------------
+
+You can send HTTP requests in parallel by passing an array of ``Guzzle\Http\Message\RequestInterface`` objects to
+``Guzzle\Http\Client::send()``:
+
+.. code-block:: php
+
+ $responses = $client->send(array(
+ $client->get('http://www.example.com/foo'),
+ $client->get('http://www.example.com/baz')
+ $client->get('http://www.example.com/bar')
+ ));
+
+You can send commands in parallel by passing an array of ``Guzzle\Service\Command\CommandInterface`` objects
+``Guzzle\Service\Client::execute()``:
+
+.. code-block:: php
+
+ $commands = $client->execute(array(
+ $client->getCommand('foo'),
+ $client->getCommand('baz'),
+ $client->getCommand('bar')
+ ));
+
+These approaches work well for most use-cases. When you need more control over the requests that are sent in
+parallel or you need to send a large number of requests, you need to use the functionality provided in the
+``Guzzle\Batch`` namespace.
+
+Batching overview
+-----------------
+
+The batch object, ``Guzzle\Batch\Batch``, is a queue. You add requests to the queue until you are ready to transfer
+all of the requests. In order to efficiently transfer the items in the queue, the batch object delegates the
+responsibility of dividing the queue into manageable parts to a divisor (``Guzzle\Batch\BatchDivisorInterface``).
+The batch object then iterates over each array of items created by the divisor and sends them to the batch object's
+``Guzzle\Batch\BatchTransferInterface``.
+
+.. code-block:: php
+
+ use Guzzle\Batch\Batch;
+ use Guzzle\Http\BatchRequestTransfer;
+
+ // BatchRequestTransfer acts as both the divisor and transfer strategy
+ $transferStrategy = new BatchRequestTransfer(10);
+ $divisorStrategy = $transferStrategy;
+
+ $batch = new Batch($transferStrategy, $divisorStrategy);
+
+ // Add some requests to the batch queue
+ $batch->add($request1)
+ ->add($request2)
+ ->add($request3);
+
+ // Flush the queue and retrieve the flushed items
+ $arrayOfTransferredRequests = $batch->flush();
+
+.. note::
+
+ You might find that your transfer strategy will need to act as both the divisor and transfer strategy.
+
+Using the BatchBuilder
+----------------------
+
+The ``Guzzle\Batch\BatchBuilder`` makes it easier to create batch objects. The batch builder also provides an easier
+way to add additional behaviors to your batch object.
+
+Transferring requests
+~~~~~~~~~~~~~~~~~~~~~
+
+The ``Guzzle\Http\BatchRequestTransfer`` class efficiently transfers HTTP requests in parallel by grouping batches of
+requests by the curl_multi handle that is used to transfer the requests.
+
+.. code-block:: php
+
+ use Guzzle\Batch\BatchBuilder;
+
+ $batch = BatchBuilder::factory()
+ ->transferRequests(10)
+ ->build();
+
+Transferring commands
+~~~~~~~~~~~~~~~~~~~~~
+
+The ``Guzzle\Service\Command\BatchCommandTransfer`` class efficiently transfers service commands by grouping commands
+by the client that is used to transfer them. You can add commands to a batch object that are transferred by different
+clients, and the batch will handle the rest.
+
+.. code-block:: php
+
+ use Guzzle\Batch\BatchBuilder;
+
+ $batch = BatchBuilder::factory()
+ ->transferCommands(10)
+ ->build();
+
+ $batch->add($client->getCommand('foo'))
+ ->add($client->getCommand('baz'))
+ ->add($client->getCommand('bar'));
+
+ $commands = $batch->flush();
+
+Batch behaviors
+---------------
+
+You can add various behaviors to your batch that allow for more customizable transfers.
+
+Automatically flushing a queue
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use the ``Guzzle\Batch\FlushingBatch`` decorator when you want to pump a large number of items into a batch queue and
+have the queue automatically flush when the size of the queue reaches a certain threshold.
+
+.. code-block:: php
+
+ use Guzzle\Batch\BatchBuilder;
+
+ $batch = BatchBuilder::factory()
+ ->transferRequests(10)
+ ->autoFlushAt(10)
+ ->build();
+
+Batch builder method: ``autoFlushAt($threshold)``
+
+Notifying on flush
+~~~~~~~~~~~~~~~~~~
+
+Use the ``Guzzle\Batch\NotifyingBatch`` decorator if you want a function to be notified each time the batch queue is
+flushed. This is useful when paired with the flushing batch decorator. Pass a callable to the ``notify()`` method of
+a batch builder to use this decorator with the builder.
+
+.. code-block:: php
+
+ use Guzzle\Batch\BatchBuilder;
+
+ $batch = BatchBuilder::factory()
+ ->transferRequests(10)
+ ->autoFlushAt(10)
+ ->notify(function (array $transferredItems) {
+ echo 'Transferred ' . count($transferredItems) . "items\n";
+ })
+ ->build();
+
+Batch builder method:: ``notify(callable $callback)``
+
+Keeping a history
+~~~~~~~~~~~~~~~~~
+
+Use the ``Guzzle\Batch\HistoryBatch`` decorator if you want to maintain a history of all the items transferred with
+the batch queue.
+
+.. code-block:: php
+
+ use Guzzle\Batch\BatchBuilder;
+
+ $batch = BatchBuilder::factory()
+ ->transferRequests(10)
+ ->keepHistory()
+ ->build();
+
+After transferring items, you can use the ``getHistory()`` of a batch to retrieve an array of transferred items. Be
+sure to periodically clear the history using ``clearHistory()``.
+
+Batch builder method: ``keepHistory()``
+
+Exception buffering
+~~~~~~~~~~~~~~~~~~~
+
+Use the ``Guzzle\Batch\ExceptionBufferingBatch`` decorator to buffer exceptions during a transfer so that you can
+transfer as many items as possible then deal with the errored batches after the transfer completes. After transfer,
+use the ``getExceptions()`` method of a batch to retrieve an array of
+``Guzzle\Batch\Exception\BatchTransferException`` objects. You can use these exceptions to attempt to retry the
+failed batches. Be sure to clear the buffered exceptions when you are done with them by using the
+``clearExceptions()`` method.
+
+Batch builder method: ``bufferExceptions()``
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/conf.py b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/conf.py
new file mode 100755
index 0000000..92bc46b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/conf.py
@@ -0,0 +1,94 @@
+import sys, os
+from sphinx.highlighting import lexers
+from pygments.lexers.web import PhpLexer
+
+lexers['php'] = PhpLexer(startinline=True, linenos=1)
+lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1)
+primary_domain = 'php'
+
+# -- General configuration -----------------------------------------------------
+
+extensions = []
+templates_path = ['_templates']
+source_suffix = '.rst'
+master_doc = 'index'
+
+project = u'Guzzle'
+copyright = u'2012, Michael Dowling'
+version = '3.0.0'
+release = '3.0.0'
+
+exclude_patterns = ['_build']
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# " v documentation".
+html_title = "Guzzle documentation"
+html_short_title = "Guzzle"
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {
+ '**': ['localtoc.html', 'leftbar.html', 'searchbox.html']
+}
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Guzzledoc'
+
+# -- Guzzle Sphinx theme setup ------------------------------------------------
+
+sys.path.insert(0, '/Users/dowling/projects/guzzle_sphinx_theme')
+
+import guzzle_sphinx_theme
+html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator'
+html_theme_path = guzzle_sphinx_theme.html_theme_path()
+html_theme = 'guzzle_sphinx_theme'
+
+# Guzzle theme options (see theme.conf for more information)
+html_theme_options = {
+ "index_template": "index.html",
+ "project_nav_name": "Guzzle",
+ "github_user": "guzzle",
+ "github_repo": "guzzle",
+ "disqus_comments_shortname": "guzzle",
+ "google_analytics_account": "UA-22752917-1"
+}
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Guzzle.tex', u'Guzzle Documentation',
+ u'Michael Dowling', 'manual'),
+]
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'guzzle', u'Guzzle Documentation',
+ [u'Michael Dowling'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'Guzzle', u'Guzzle Documentation',
+ u'Michael Dowling', 'Guzzle', 'One line description of project.',
+ 'Miscellaneous'),
+]
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/docs.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/docs.rst
new file mode 100755
index 0000000..cf87908
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/docs.rst
@@ -0,0 +1,73 @@
+.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services
+
+====================
+Guzzle Documentation
+====================
+
+Getting started
+---------------
+
+.. toctree::
+ :maxdepth: 1
+
+ getting-started/overview
+ getting-started/installation
+ getting-started/faq
+
+The HTTP client
+---------------
+
+.. toctree::
+ :maxdepth: 2
+
+ http-client/client
+ http-client/request
+ http-client/response
+ http-client/entity-bodies
+ http-client/http-redirects
+ http-client/uri-templates
+
+Plugins
+-------
+
+.. toctree::
+ :maxdepth: 1
+
+ plugins/plugins-overview
+ plugins/creating-plugins
+ plugins/async-plugin
+ plugins/backoff-plugin
+ plugins/cache-plugin
+ plugins/cookie-plugin
+ plugins/curl-auth-plugin
+ plugins/history-plugin
+ plugins/log-plugin
+ plugins/md5-validator-plugin
+ plugins/mock-plugin
+ plugins/oauth-plugin
+
+The web service client
+----------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ webservice-client/webservice-client
+ webservice-client/using-the-service-builder
+ webservice-client/guzzle-service-descriptions
+ batching/batching
+ iterators/resource-iterators
+ iterators/guzzle-iterators
+
+Testing
+-------
+
+.. toctree::
+ :maxdepth: 2
+
+ testing/unit-testing
+
+API Docs
+--------
+
+`Read the API docs `_
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/faq.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/faq.rst
new file mode 100755
index 0000000..a0a3fdb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/faq.rst
@@ -0,0 +1,29 @@
+===
+FAQ
+===
+
+What should I do if I get this error: Fatal error: Maximum function nesting level of '100' reached, aborting!
+-------------------------------------------------------------------------------------------------------------
+
+You could run into this error if you have the XDebug extension installed and you execute a lot of requests in
+callbacks. This error message comes specifically from the XDebug extension. PHP itself does not have a function
+nesting limit. Change this setting in your php.ini to increase the limit::
+
+ xdebug.max_nesting_level = 1000
+
+[`source `_]
+
+How can I speed up my client?
+-----------------------------
+
+There are several things you can do to speed up your client:
+
+1. Utilize a C based HTTP message parser (e.g. ``Guzzle\Parser\Message\PeclHttpMessageParser``)
+2. Disable operation validation by setting the ``command.disable_validation`` option to true on a command
+
+Why am I getting a 417 error response?
+--------------------------------------
+
+This can occur for a number of reasons, but if you are sending PUT, POST, or PATCH requests with an
+``Expect: 100-Continue`` header, a server that does not support this header will return a 417 response. You can work
+around this by calling ``$request->removeHeader('Expect');`` after setting the entity body of a request.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/installation.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/installation.rst
new file mode 100755
index 0000000..77d4001
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/installation.rst
@@ -0,0 +1,154 @@
+============
+Installation
+============
+
+Requirements
+------------
+
+#. PHP 5.3.3+ compiled with the cURL extension
+#. A recent version of cURL 7.16.2+ compiled with OpenSSL and zlib
+
+Installing Guzzle
+-----------------
+
+Composer
+~~~~~~~~
+
+The recommended way to install Guzzle is with `Composer `_. Composer is a dependency
+management tool for PHP that allows you to declare the dependencies your project needs and installs them into your
+project.
+
+.. code-block:: bash
+
+ # Install Composer
+ curl -sS https://getcomposer.org/installer | php
+
+ # Add Guzzle as a dependency
+ php composer.phar require guzzle/guzzle:~3.9
+
+After installing, you need to require Composer's autoloader:
+
+.. code-block:: php
+
+ require 'vendor/autoload.php';
+
+You can find out more on how to install Composer, configure autoloading, and other best-practices for defining
+dependencies at `getcomposer.org `_.
+
+Using only specific parts of Guzzle
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+While you can always just rely on ``guzzle/guzzle``, Guzzle provides several smaller parts of Guzzle as individual
+packages available through Composer.
+
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| Package name | Description |
++===============================================================================================+==========================================+
+| `guzzle/common `_ | Provides ``Guzzle\Common`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/http `_ | Provides ``Guzzle\Http`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/parser `_ | Provides ``Guzzle\Parser`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/batch `_ | Provides ``Guzzle\Batch`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/cache `_ | Provides ``Guzzle\Cache`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/inflection `_ | Provides ``Guzzle\Inflection`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/iterator `_ | Provides ``Guzzle\Iterator`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/log `_ | Provides ``Guzzle\Log`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin `_ | Provides ``Guzzle\Plugin`` (all plugins) |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-async `_ | Provides ``Guzzle\Plugin\Async`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-backoff `_ | Provides ``Guzzle\Plugin\BackoffPlugin`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-cache `_ | Provides ``Guzzle\Plugin\Cache`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-cookie `_ | Provides ``Guzzle\Plugin\Cookie`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-error-response `_ | Provides ``Guzzle\Plugin\ErrorResponse`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-history `_ | Provides ``Guzzle\Plugin\History`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-log `_ | Provides ``Guzzle\Plugin\Log`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-md5 `_ | Provides ``Guzzle\Plugin\Md5`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-mock `_ | Provides ``Guzzle\Plugin\Mock`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/plugin-oauth `_ | Provides ``Guzzle\Plugin\Oauth`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/service `_ | Provides ``Guzzle\Service`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+| `guzzle/stream `_ | Provides ``Guzzle\Stream`` |
++-----------------------------------------------------------------------------------------------+------------------------------------------+
+
+Bleeding edge
+^^^^^^^^^^^^^
+
+During your development, you can keep up with the latest changes on the master branch by setting the version
+requirement for Guzzle to ``dev-master``.
+
+.. code-block:: js
+
+ {
+ "require": {
+ "guzzle/guzzle": "dev-master"
+ }
+ }
+
+PEAR
+~~~~
+
+Guzzle can be installed through PEAR:
+
+.. code-block:: bash
+
+ pear channel-discover guzzlephp.org/pear
+ pear install guzzle/guzzle
+
+You can install a specific version of Guzzle by providing a version number suffix:
+
+.. code-block:: bash
+
+ pear install guzzle/guzzle-3.9.0
+
+Contributing to Guzzle
+----------------------
+
+In order to contribute, you'll need to checkout the source from GitHub and install Guzzle's dependencies using
+Composer:
+
+.. code-block:: bash
+
+ git clone https://github.com/guzzle/guzzle.git
+ cd guzzle && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev
+
+Guzzle is unit tested with PHPUnit. You will need to create your own phpunit.xml file in order to run the unit tests
+(or just copy phpunit.xml.dist to phpunit.xml). Run the tests using the vendored PHPUnit binary:
+
+.. code-block:: bash
+
+ vendor/bin/phpunit
+
+You'll need to install node.js v0.5.0 or newer in order to test the cURL implementation.
+
+Framework integrations
+----------------------
+
+Using Guzzle with Symfony
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Bundles are available on GitHub:
+
+- `DdeboerGuzzleBundle `_ for Guzzle 2
+- `MisdGuzzleBundle `_ for Guzzle 3
+
+Using Guzzle with Silex
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A `Guzzle Silex service provider `_ is available on GitHub.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/overview.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/overview.rst
new file mode 100755
index 0000000..505b409
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/getting-started/overview.rst
@@ -0,0 +1,85 @@
+=================
+Welcome to Guzzle
+=================
+
+What is Guzzle?
+~~~~~~~~~~~~~~~
+
+Guzzle is a PHP HTTP client and framework for building web service clients. Guzzle takes the pain out of sending HTTP
+requests and the redundancy out of creating web service clients.
+
+Features at a glance
+--------------------
+
+- All the power of cURL with a simple interface.
+- Persistent connections and parallel requests.
+- Streams request and response bodies
+- Service descriptions for quickly building clients.
+- Powered by the Symfony2 EventDispatcher.
+- Use all of the code or only specific components.
+- Plugins for caching, logging, OAuth, mocks, and more
+- Includes a custom node.js webserver to test your clients.
+- Service descriptions for defining the inputs and outputs of an API
+- Resource iterators for traversing paginated resources
+- Batching for sending a large number of requests as efficiently as possible
+
+.. code-block:: php
+
+ // Really simple using a static facade
+ Guzzle\Http\StaticClient::mount();
+ $response = Guzzle::get('http://guzzlephp.org');
+
+ // More control using a client class
+ $client = new \Guzzle\Http\Client('http://guzzlephp.org');
+ $request = $client->get('/');
+ $response = $request->send();
+
+License
+-------
+
+Licensed using the `MIT license `_.
+
+ Copyright (c) 2013 Michael Dowling
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+Contributing
+------------
+
+Guidelines
+~~~~~~~~~~
+
+This is still a work in progress, but there are only a few rules:
+
+1. Guzzle follows PSR-0, PSR-1, and PSR-2
+2. All pull requests must include unit tests to ensure the change works as expected and to prevent future regressions
+
+Reporting a security vulnerability
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We want to ensure that Guzzle is a secure HTTP client library for everyone. If you've discovered a security
+vulnerability in Guzzle, we appreciate your help in disclosing it to us in a
+`responsible manner `_.
+
+Publicly disclosing a vulnerability can put the entire community at risk. If you've discovered a security concern,
+please email us at security@guzzlephp.org. We'll work with you to make sure that we understand the scope of the issue,
+and that we fully address your concern. We consider correspondence sent to security@guzzlephp.org our highest priority,
+and work to address any issues that arise as quickly as possible.
+
+After a security vulnerability has been corrected, a security hotfix release will be deployed as soon as possible.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/client.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/client.rst
new file mode 100755
index 0000000..723d729
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/client.rst
@@ -0,0 +1,569 @@
+======================
+The Guzzle HTTP client
+======================
+
+Guzzle gives PHP developers complete control over HTTP requests while utilizing HTTP/1.1 best practices. Guzzle's HTTP
+functionality is a robust framework built on top of the `PHP libcurl bindings `_.
+
+The three main parts of the Guzzle HTTP client are:
+
++--------------+-------------------------------------------------------------------------------------------------------+
+| Clients | ``Guzzle\Http\Client`` (creates and sends requests, associates a response with a request) |
++--------------+-------------------------------------------------------------------------------------------------------+
+| Requests | ``Guzzle\Http\Message\Request`` (requests with no body), |
+| | ``Guzzle\Http\Message\EntityEnclosingRequest`` (requests with a body) |
++--------------+-------------------------------------------------------------------------------------------------------+
+| Responses | ``Guzzle\Http\Message\Response`` |
++--------------+-------------------------------------------------------------------------------------------------------+
+
+Creating a Client
+-----------------
+
+Clients create requests, send requests, and set responses on a request object. When instantiating a client object,
+you can pass an optional "base URL" and optional array of configuration options. A base URL is a
+:doc:`URI template ` that contains the URL of a remote server. When creating requests with a relative
+URL, the base URL of a client will be merged into the request's URL.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+
+ // Create a client and provide a base URL
+ $client = new Client('https://api.github.com');
+
+ $request = $client->get('/user');
+ $request->setAuth('user', 'pass');
+ echo $request->getUrl();
+ // >>> https://api.github.com/user
+
+ // You must send a request in order for the transfer to occur
+ $response = $request->send();
+
+ echo $response->getBody();
+ // >>> {"type":"User", ...
+
+ echo $response->getHeader('Content-Length');
+ // >>> 792
+
+ $data = $response->json();
+ echo $data['type'];
+ // >>> User
+
+Base URLs
+~~~~~~~~~
+
+Notice that the URL provided to the client's ``get()`` method is relative. Relative URLs will always merge into the
+base URL of the client. There are a few rules that control how the URLs are merged.
+
+.. tip::
+
+ Guzzle follows `RFC 3986 `_ when merging base URLs and
+ relative URLs.
+
+In the above example, we passed ``/user`` to the ``get()`` method of the client. This is a relative URL, so it will
+merge into the base URL of the client-- resulting in the derived URL of ``https://api.github.com/users``.
+
+``/user`` is a relative URL but uses an absolute path because it contains the leading slash. Absolute paths will
+overwrite any existing path of the base URL. If an absolute path is provided (e.g. ``/path/to/something``), then the
+path specified in the base URL of the client will be replaced with the absolute path, and the query string provided
+by the relative URL will replace the query string of the base URL.
+
+Omitting the leading slash and using relative paths will add to the path of the base URL of the client. So using a
+client base URL of ``https://api.twitter.com/v1.1`` and creating a GET request with ``statuses/user_timeline.json``
+will result in a URL of ``https://api.twitter.com/v1.1/statuses/user_timeline.json``. If a relative path and a query
+string are provided, then the relative path will be appended to the base URL path, and the query string provided will
+be merged into the query string of the base URL.
+
+If an absolute URL is provided (e.g. ``http://httpbin.org/ip``), then the request will completely use the absolute URL
+as-is without merging in any of the URL parts specified in the base URL.
+
+Configuration options
+~~~~~~~~~~~~~~~~~~~~~
+
+The second argument of the client's constructor is an array of configuration data. This can include URI template data
+or special options that alter the client's behavior:
+
++-------------------------------+-------------------------------------------------------------------------------------+
+| ``request.options`` | Associative array of :ref:`Request options ` to apply to every |
+| | request created by the client. |
++-------------------------------+-------------------------------------------------------------------------------------+
+| ``redirect.disable`` | Disable HTTP redirects for every request created by the client. |
++-------------------------------+-------------------------------------------------------------------------------------+
+| ``curl.options`` | Associative array of cURL options to apply to every request created by the client. |
+| | if either the key or value of an entry in the array is a string, Guzzle will |
+| | attempt to find a matching defined cURL constant automatically (e.g. |
+| | "CURLOPT_PROXY" will be converted to the constant ``CURLOPT_PROXY``). |
++-------------------------------+-------------------------------------------------------------------------------------+
+| ``ssl.certificate_authority`` | Set to true to use the Guzzle bundled SSL certificate bundle (this is used by |
+| | default, 'system' to use the bundle on your system, a string pointing to a file to |
+| | use a specific certificate file, a string pointing to a directory to use multiple |
+| | certificates, or ``false`` to disable SSL validation (not recommended). |
+| | |
+| | When using Guzzle inside of a phar file, the bundled SSL certificate will be |
+| | extracted to your system's temp folder, and each time a client is created an MD5 |
+| | check will be performed to ensure the integrity of the certificate. |
++-------------------------------+-------------------------------------------------------------------------------------+
+| ``command.params`` | When using a ``Guzzle\Service\Client`` object, this is an associative array of |
+| | default options to set on each command created by the client. |
++-------------------------------+-------------------------------------------------------------------------------------+
+
+Here's an example showing how to set various configuration options, including default headers to send with each request,
+default query string parameters to add to each request, a default auth scheme for each request, and a proxy to use for
+each request. Values can be injected into the client's base URL using variables from the configuration array.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+
+ $client = new Client('https://api.twitter.com/{version}', array(
+ 'version' => 'v1.1',
+ 'request.options' => array(
+ 'headers' => array('Foo' => 'Bar'),
+ 'query' => array('testing' => '123'),
+ 'auth' => array('username', 'password', 'Basic|Digest|NTLM|Any'),
+ 'proxy' => 'tcp://localhost:80'
+ )
+ ));
+
+Setting a custom User-Agent
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default Guzzle User-Agent header is ``Guzzle/ curl/ PHP/``. You can
+customize the User-Agent header of a client by calling the ``setUserAgent()`` method of a Client object.
+
+.. code-block:: php
+
+ // Completely override the default User-Agent
+ $client->setUserAgent('Test/123');
+
+ // Prepend a string to the default User-Agent
+ $client->setUserAgent('Test/123', true);
+
+Creating requests with a client
+-------------------------------
+
+A Client object exposes several methods used to create Request objects:
+
+* Create a custom HTTP request: ``$client->createRequest($method, $uri, array $headers, $body, $options)``
+* Create a GET request: ``$client->get($uri, array $headers, $options)``
+* Create a HEAD request: ``$client->head($uri, array $headers, $options)``
+* Create a DELETE request: ``$client->delete($uri, array $headers, $body, $options)``
+* Create a POST request: ``$client->post($uri, array $headers, $postBody, $options)``
+* Create a PUT request: ``$client->put($uri, array $headers, $body, $options)``
+* Create a PATCH request: ``$client->patch($uri, array $headers, $body, $options)``
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+
+ $client = new Client('http://baseurl.com/api/v1');
+
+ // Create a GET request using Relative to base URL
+ // URL of the request: http://baseurl.com/api/v1/path?query=123&value=abc)
+ $request = $client->get('path?query=123&value=abc');
+ $response = $request->send();
+
+ // Create HEAD request using a relative URL with an absolute path
+ // URL of the request: http://baseurl.com/path?query=123&value=abc
+ $request = $client->head('/path?query=123&value=abc');
+ $response = $request->send();
+
+ // Create a DELETE request using an absolute URL
+ $request = $client->delete('http://www.example.com/path?query=123&value=abc');
+ $response = $request->send();
+
+ // Create a PUT request using the contents of a PHP stream as the body
+ // Specify custom HTTP headers
+ $request = $client->put('http://www.example.com/upload', array(
+ 'X-Header' => 'My Header'
+ ), fopen('http://www.test.com/', 'r'));
+ $response = $request->send();
+
+ // Create a POST request and add the POST files manually
+ $request = $client->post('http://localhost:8983/solr/update')
+ ->addPostFiles(array('file' => '/path/to/documents.xml'));
+ $response = $request->send();
+
+ // Check if a resource supports the DELETE method
+ $supportsDelete = $client->options('/path')->send()->isMethodAllowed('DELETE');
+ $response = $request->send();
+
+Client objects create Request objects using a request factory (``Guzzle\Http\Message\RequestFactoryInterface``).
+You can inject a custom request factory into the Client using ``$client->setRequestFactory()``, but you can typically
+rely on a Client's default request factory.
+
+Static clients
+--------------
+
+You can use Guzzle's static client facade to more easily send simple HTTP requests.
+
+.. code-block:: php
+
+ // Mount the client so that you can access it at \Guzzle
+ Guzzle\Http\StaticClient::mount();
+ $response = Guzzle::get('http://guzzlephp.org');
+
+Each request method of the static client (e.g. ``get()``, ``post()`, ``put()``, etc) accepts an associative array of request
+options to apply to the request.
+
+.. code-block:: php
+
+ $response = Guzzle::post('http://test.com', array(
+ 'headers' => array('X-Foo' => 'Bar'),
+ 'body' => array('Test' => '123'),
+ 'timeout' => 10
+ ));
+
+.. _request-options:
+
+Request options
+---------------
+
+Request options can be specified when creating a request or in the ``request.options`` parameter of a client. These
+options can control various aspects of a request including: headers to send, query string data, where the response
+should be downloaded, proxies, auth, etc.
+
+headers
+~~~~~~~
+
+Associative array of headers to apply to the request. When specified in the ``$options`` argument of a client creational
+method (e.g. ``get()``, ``post()``, etc), the headers in the ``$options`` array will overwrite headers specified in the
+``$headers`` array.
+
+.. code-block:: php
+
+ $request = $client->get($url, array(), array(
+ 'headers' => array('X-Foo' => 'Bar')
+ ));
+
+Headers can be specified on a client to add default headers to every request sent by a client.
+
+.. code-block:: php
+
+ $client = new Guzzle\Http\Client();
+
+ // Set a single header using path syntax
+ $client->setDefaultOption('headers/X-Foo', 'Bar');
+
+ // Set all headers
+ $client->setDefaultOption('headers', array('X-Foo' => 'Bar'));
+
+.. note::
+
+ In addition to setting request options when creating requests or using the ``setDefaultOption()`` method, any
+ default client request option can be set using a client's config object:
+
+ .. code-block:: php
+
+ $client->getConfig()->setPath('request.options/headers/X-Foo', 'Bar');
+
+query
+~~~~~
+
+Associative array of query string parameters to the request. When specified in the ``$options`` argument of a client
+creational method, the query string parameters in the ``$options`` array will overwrite query string parameters
+specified in the `$url`.
+
+.. code-block:: php
+
+ $request = $client->get($url, array(), array(
+ 'query' => array('abc' => '123')
+ ));
+
+Query string parameters can be specified on a client to add default query string parameters to every request sent by a
+client.
+
+.. code-block:: php
+
+ $client = new Guzzle\Http\Client();
+
+ // Set a single query string parameter using path syntax
+ $client->setDefaultOption('query/abc', '123');
+
+ // Set an array of default query string parameters
+ $client->setDefaultOption('query', array('abc' => '123'));
+
+body
+~~~~
+
+Sets the body of a request. The value supplied to the body option can be a ``Guzzle\Http\EntityBodyInterface``, string,
+fopen resource, or array when sending POST requests. When a ``body`` request option is supplied, the option value will
+overwrite the ``$body`` argument of a client creational method.
+
+auth
+~~~~
+
+Specifies and array of HTTP authorization parameters parameters to use with the request. The array must contain the
+username in index [0], the password in index [1], and can optionally contain the authentication type in index [2].
+The available authentication types are: "Basic" (default), "Digest", "NTLM", or "Any".
+
+.. code-block:: php
+
+ $request = $client->get($url, array(), array(
+ 'auth' => array('username', 'password', 'Digest')
+ ));
+
+ // You can add auth headers to every request of a client
+ $client->setDefaultOption('auth', array('username', 'password', 'Digest'));
+
+cookies
+~~~~~~~
+
+Specifies an associative array of cookies to add to the request.
+
+allow_redirects
+~~~~~~~~~~~~~~~
+
+Specifies whether or not the request should follow redirects. Requests will follow redirects by default. Set
+``allow_redirects`` to ``false`` to disable redirects.
+
+save_to
+~~~~~~~
+
+The ``save_to`` option specifies where the body of a response is downloaded. You can pass the path to a file, an fopen
+resource, or a ``Guzzle\Http\EntityBodyInterface`` object.
+
+See :ref:`Changing where a response is downloaded ` for more information on setting the
+`save_to` option.
+
+events
+~~~~~~
+
+The `events` option makes it easy to attach listeners to the various events emitted by a request object. The `events`
+options must be an associative array mapping an event name to a Closure or array the contains a Closure and the
+priority of the event.
+
+.. code-block:: php
+
+ $request = $client->get($url, array(), array(
+ 'events' => array(
+ 'request.before_send' => function (\Guzzle\Common\Event $e) {
+ echo 'About to send ' . $e['request'];
+ }
+ )
+ ));
+
+ // Using the static client:
+ Guzzle::get($url, array(
+ 'events' => array(
+ 'request.before_send' => function (\Guzzle\Common\Event $e) {
+ echo 'About to send ' . $e['request'];
+ }
+ )
+ ));
+
+plugins
+~~~~~~~
+
+The `plugins` options makes it easy to attach an array of plugins to a request.
+
+.. code-block:: php
+
+ // Using the static client:
+ Guzzle::get($url, array(
+ 'plugins' => array(
+ new Guzzle\Plugin\Cache\CachePlugin(),
+ new Guzzle\Plugin\Cookie\CookiePlugin()
+ )
+ ));
+
+exceptions
+~~~~~~~~~~
+
+The `exceptions` option can be used to disable throwing exceptions for unsuccessful HTTP response codes
+(e.g. 404, 500, etc). Set `exceptions` to false to not throw exceptions.
+
+params
+~~~~~~
+
+The `params` options can be used to specify an associative array of data parameters to add to a request. Note that
+these are not query string parameters.
+
+timeout / connect_timeout
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can specify the maximum number of seconds to allow for an entire transfer to take place before timing out using
+the `timeout` request option. You can specify the maximum number of seconds to wait while trying to connect using the
+`connect_timeout` request option. Set either of these options to 0 to wait indefinitely.
+
+.. code-block:: php
+
+ $request = $client->get('http://www.example.com', array(), array(
+ 'timeout' => 20,
+ 'connect_timeout' => 1.5
+ ));
+
+verify
+~~~~~~
+
+Set to true to enable SSL certificate validation (the default), false to disable SSL certificate validation, or supply
+the path to a CA bundle to enable verification using a custom certificate.
+
+cert
+~~~~
+
+The `cert` option lets you specify a PEM formatted SSL client certificate to use with servers that require one. If the
+certificate requires a password, provide an array with the password as the second item.
+
+This would typically be used in conjunction with the `ssl_key` option.
+
+.. code-block:: php
+
+ $request = $client->get('https://www.example.com', array(), array(
+ 'cert' => '/etc/pki/client_certificate.pem'
+ )
+
+ $request = $client->get('https://www.example.com', array(), array(
+ 'cert' => array('/etc/pki/client_certificate.pem', 's3cr3tp455w0rd')
+ )
+
+ssl_key
+~~~~~~~
+
+The `ssl_key` option lets you specify a file containing your PEM formatted private key, optionally protected by a password.
+Note: your password is sensitive, keep the PHP script containing it safe.
+
+This would typically be used in conjunction with the `cert` option.
+
+.. code-block:: php
+
+ $request = $client->get('https://www.example.com', array(), array(
+ 'ssl_key' => '/etc/pki/private_key.pem'
+ )
+
+ $request = $client->get('https://www.example.com', array(), array(
+ 'ssl_key' => array('/etc/pki/private_key.pem', 's3cr3tp455w0rd')
+ )
+
+proxy
+~~~~~
+
+The `proxy` option is used to specify an HTTP proxy (e.g. `http://username:password@192.168.16.1:10`).
+
+debug
+~~~~~
+
+The `debug` option is used to show verbose cURL output for a transfer.
+
+stream
+~~~~~~
+
+When using a static client, you can set the `stream` option to true to return a `Guzzle\Stream\Stream` object that can
+be used to pull data from a stream as needed (rather than have cURL download the entire contents of a response to a
+stream all at once).
+
+.. code-block:: php
+
+ $stream = Guzzle::get('http://guzzlephp.org', array('stream' => true));
+ while (!$stream->feof()) {
+ echo $stream->readLine();
+ }
+
+Sending requests
+----------------
+
+Requests can be sent by calling the ``send()`` method of a Request object, but you can also send requests using the
+``send()`` method of a Client.
+
+.. code-block:: php
+
+ $request = $client->get('http://www.amazon.com');
+ $response = $client->send($request);
+
+Sending requests in parallel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Client's ``send()`` method accept a single ``Guzzle\Http\Message\RequestInterface`` object or an array of
+RequestInterface objects. When an array is specified, the requests will be sent in parallel.
+
+Sending many HTTP requests serially (one at a time) can cause an unnecessary delay in a script's execution. Each
+request must complete before a subsequent request can be sent. By sending requests in parallel, a pool of HTTP
+requests can complete at the speed of the slowest request in the pool, significantly reducing the amount of time
+needed to execute multiple HTTP requests. Guzzle provides a wrapper for the curl_multi functions in PHP.
+
+Here's an example of sending three requests in parallel using a client object:
+
+.. code-block:: php
+
+ use Guzzle\Common\Exception\MultiTransferException;
+
+ try {
+ $responses = $client->send(array(
+ $client->get('http://www.google.com/'),
+ $client->head('http://www.google.com/'),
+ $client->get('https://www.github.com/')
+ ));
+ } catch (MultiTransferException $e) {
+
+ echo "The following exceptions were encountered:\n";
+ foreach ($e as $exception) {
+ echo $exception->getMessage() . "\n";
+ }
+
+ echo "The following requests failed:\n";
+ foreach ($e->getFailedRequests() as $request) {
+ echo $request . "\n\n";
+ }
+
+ echo "The following requests succeeded:\n";
+ foreach ($e->getSuccessfulRequests() as $request) {
+ echo $request . "\n\n";
+ }
+ }
+
+If the requests succeed, an array of ``Guzzle\Http\Message\Response`` objects are returned. A single request failure
+will not cause the entire pool of requests to fail. Any exceptions thrown while transferring a pool of requests will
+be aggregated into a ``Guzzle\Common\Exception\MultiTransferException`` exception.
+
+Plugins and events
+------------------
+
+Guzzle provides easy to use request plugins that add behavior to requests based on signal slot event notifications
+powered by the
+`Symfony2 Event Dispatcher component `_. Any
+event listener or subscriber attached to a Client object will automatically be attached to each request created by the
+client.
+
+Using the same cookie session for each request
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Attach a ``Guzzle\Plugin\Cookie\CookiePlugin`` to a client which will in turn add support for cookies to every request
+created by a client, and each request will use the same cookie session:
+
+.. code-block:: php
+
+ use Guzzle\Plugin\Cookie\CookiePlugin;
+ use Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar;
+
+ // Create a new cookie plugin
+ $cookiePlugin = new CookiePlugin(new ArrayCookieJar());
+
+ // Add the cookie plugin to the client
+ $client->addSubscriber($cookiePlugin);
+
+.. _client-events:
+
+Events emitted from a client
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A ``Guzzle\Http\Client`` object emits the following events:
+
++------------------------------+--------------------------------------------+------------------------------------------+
+| Event name | Description | Event data |
++==============================+============================================+==========================================+
+| client.create_request | Called when a client creates a request | * client: The client |
+| | | * request: The created request |
++------------------------------+--------------------------------------------+------------------------------------------+
+
+.. code-block:: php
+
+ use Guzzle\Common\Event;
+ use Guzzle\Http\Client;
+
+ $client = new Client();
+
+ // Add a listener that will echo out requests as they are created
+ $client->getEventDispatcher()->addListener('client.create_request', function (Event $e) {
+ echo 'Client object: ' . spl_object_hash($e['client']) . "\n";
+ echo "Request object: {$e['request']}\n";
+ });
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst
new file mode 100755
index 0000000..823b0c0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/entity-bodies.rst
@@ -0,0 +1,151 @@
+===========================
+Request and response bodies
+===========================
+
+`Entity body `_ is the term used for the body of an HTTP
+message. The entity body of requests and responses is inherently a
+`PHP stream `_ in Guzzle. The body of the request can be either a string or
+a PHP stream which are converted into a ``Guzzle\Http\EntityBody`` object using its factory method. When using a
+string, the entity body is stored in a `temp PHP stream `_. The use of
+temp PHP streams helps to protect your application from running out of memory when sending or receiving large entity
+bodies in your messages. When more than 2MB of data is stored in a temp stream, it automatically stores the data on
+disk rather than in memory.
+
+EntityBody objects provide a great deal of functionality: compression, decompression, calculate the Content-MD5,
+calculate the Content-Length (when the resource is repeatable), guessing the Content-Type, and more. Guzzle doesn't
+need to load an entire entity body into a string when sending or retrieving data; entity bodies are streamed when
+being uploaded and downloaded.
+
+Here's an example of gzip compressing a text file then sending the file to a URL:
+
+.. code-block:: php
+
+ use Guzzle\Http\EntityBody;
+
+ $body = EntityBody::factory(fopen('/path/to/file.txt', 'r+'));
+ echo $body->read(1024);
+ $body->seek(0, SEEK_END);
+ $body->write('foo');
+ echo $body->ftell();
+ $body->rewind();
+
+ // Send a request using the body
+ $response = $client->put('http://localhost:8080/uploads', null, $body)->send();
+
+The body of the request can be specified in the ``Client::put()`` or ``Client::post()`` method, or, you can specify
+the body of the request by calling the ``setBody()`` method of any
+``Guzzle\Http\Message\EntityEnclosingRequestInterface`` object.
+
+Compression
+-----------
+
+You can compress the contents of an EntityBody object using the ``compress()`` method. The compress method accepts a
+filter that must match to one of the supported
+`PHP stream filters `_ on your system (e.g. `zlib.deflate`,
+``bzip2.compress``, etc). Compressing an entity body will stream the entire entity body through a stream compression
+filter into a temporary PHP stream. You can uncompress an entity body using the ``uncompress()`` method and passing
+the PHP stream filter to use when decompressing the stream (e.g. ``zlib.inflate``).
+
+.. code-block:: php
+
+ use Guzzle\Http\EntityBody;
+
+ $body = EntityBody::factory(fopen('/tmp/test.txt', 'r+'));
+ echo $body->getSize();
+ // >>> 1048576
+
+ // Compress using the default zlib.deflate filter
+ $body->compress();
+ echo $body->getSize();
+ // >>> 314572
+
+ // Decompress the stream
+ $body->uncompress();
+ echo $body->getSize();
+ // >>> 1048576
+
+Decorators
+----------
+
+Guzzle provides several EntityBody decorators that can be used to add functionality to an EntityBody at runtime.
+
+IoEmittingEntityBody
+~~~~~~~~~~~~~~~~~~~~
+
+This decorator will emit events when data is read from a stream or written to a stream. Add an event subscriber to the
+entity body's ``body.read`` or ``body.write`` methods to receive notifications when data data is transferred.
+
+.. code-block:: php
+
+ use Guzzle\Common\Event;
+ use Guzzle\Http\EntityBody;
+ use Guzzle\Http\IoEmittingEntityBody;
+
+ $original = EntityBody::factory(fopen('/tmp/test.txt', 'r+'));
+ $body = new IoEmittingEntityBody($original);
+
+ // Listen for read events
+ $body->getEventDispatcher()->addListener('body.read', function (Event $e) {
+ // Grab data from the event
+ $entityBody = $e['body'];
+ // Amount of data retrieved from the body
+ $lengthOfData = $e['length'];
+ // The actual data that was read
+ $data = $e['read'];
+ });
+
+ // Listen for write events
+ $body->getEventDispatcher()->addListener('body.write', function (Event $e) {
+ // Grab data from the event
+ $entityBody = $e['body'];
+ // The data that was written
+ $data = $e['write'];
+ // The actual amount of data that was written
+ $data = $e['read'];
+ });
+
+ReadLimitEntityBody
+~~~~~~~~~~~~~~~~~~~
+
+The ReadLimitEntityBody decorator can be used to transfer a subset or slice of an existing EntityBody object. This can
+be useful for breaking a large file into smaller pieces to be sent in chunks (e.g. Amazon S3's multipart upload API).
+
+.. code-block:: php
+
+ use Guzzle\Http\EntityBody;
+ use Guzzle\Http\ReadLimitEntityBody;
+
+ $original = EntityBody::factory(fopen('/tmp/test.txt', 'r+'));
+ echo $original->getSize();
+ // >>> 1048576
+
+ // Limit the size of the body to 1024 bytes and start reading from byte 2048
+ $body = new ReadLimitEntityBody($original, 1024, 2048);
+ echo $body->getSize();
+ // >>> 1024
+ echo $body->ftell();
+ // >>> 0
+
+CachingEntityBody
+~~~~~~~~~~~~~~~~~
+
+The CachingEntityBody decorator is used to allow seeking over previously read bytes on non-seekable read streams. This
+can be useful when transferring a non-seekable entity body fails due to needing to rewind the stream (for example,
+resulting from a redirect). Data that is read from the remote stream will be buffered in a PHP temp stream so that
+previously read bytes are cached first in memory, then on disk.
+
+.. code-block:: php
+
+ use Guzzle\Http\EntityBody;
+ use Guzzle\Http\CachingEntityBody;
+
+ $original = EntityBody::factory(fopen('http://www.google.com', 'r'));
+ $body = new CachingEntityBody($original);
+
+ $body->read(1024);
+ echo $body->ftell();
+ // >>> 1024
+
+ $body->seek(0);
+ echo $body->ftell();
+ // >>> 0
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/http-redirects.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/http-redirects.rst
new file mode 100755
index 0000000..32ba268
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/http-redirects.rst
@@ -0,0 +1,99 @@
+==============
+HTTP redirects
+==============
+
+By default, Guzzle will automatically follow redirects using the non-RFC compliant implementation used by most web
+browsers. This means that redirects for POST requests are followed by a GET request. You can force RFC compliance by
+enabling the strict mode on a request's parameter object:
+
+.. code-block:: php
+
+ // Set per request
+ $request = $client->post();
+ $request->getParams()->set('redirect.strict', true);
+
+ // You can set globally on a client so all requests use strict redirects
+ $client->getConfig()->set('request.params', array(
+ 'redirect.strict' => true
+ ));
+
+By default, Guzzle will redirect up to 5 times before throwing a ``Guzzle\Http\Exception\TooManyRedirectsException``.
+You can raise or lower this value using the ``redirect.max`` parameter of a request object:
+
+.. code-block:: php
+
+ $request->getParams()->set('redirect.max', 2);
+
+Redirect history
+----------------
+
+You can get the number of redirects of a request using the resulting response object's ``getRedirectCount()`` method.
+Similar to cURL's ``effective_url`` property, Guzzle provides the effective URL, or the last redirect URL that returned
+the request, in a response's ``getEffectiveUrl()`` method.
+
+When testing or debugging, it is often useful to see a history of redirects for a particular request. This can be
+achieved using the HistoryPlugin.
+
+.. code-block:: php
+
+ $request = $client->get('/');
+ $history = new Guzzle\Plugin\History\HistoryPlugin();
+ $request->addSubscriber($history);
+ $response = $request->send();
+
+ // Get the last redirect URL or the URL of the request that received
+ // this response
+ echo $response->getEffectiveUrl();
+
+ // Get the number of redirects
+ echo $response->getRedirectCount();
+
+ // Iterate over each sent request and response
+ foreach ($history->getAll() as $transaction) {
+ // Request object
+ echo $transaction['request']->getUrl() . "\n";
+ // Response object
+ echo $transaction['response']->getEffectiveUrl() . "\n";
+ }
+
+ // Or, simply cast the HistoryPlugin to a string to view each request and response
+ echo $history;
+
+Disabling redirects
+-------------------
+
+You can disable redirects on a client by passing a configuration option in the client's constructor:
+
+.. code-block:: php
+
+ $client = new Client(null, array('redirect.disable' => true));
+
+You can also disable redirects per request:
+
+.. code-block:: php
+
+ $request = $client->get($url, array(), array('allow_redirects' => false));
+
+Redirects and non-repeatable streams
+------------------------------------
+
+If you are redirected when sending data from a non-repeatable stream and some of the data has been read off of the
+stream, then you will get a ``Guzzle\Http\Exception\CouldNotRewindStreamException``. You can get around this error by
+adding a custom rewind method to the entity body object being sent in the request.
+
+.. code-block:: php
+
+ $request = $client->post(
+ 'http://httpbin.com/redirect/2',
+ null,
+ fopen('http://httpbin.com/get', 'r')
+ );
+
+ // Add a custom function that can be used to rewind the stream
+ // (reopen in this example)
+ $request->getBody()->setRewindFunction(function ($body) {
+ $body->setStream(fopen('http://httpbin.com/get', 'r'));
+ return true;
+ );
+
+ $response = $client->send();
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/request.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/request.rst
new file mode 100755
index 0000000..a8387a9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/request.rst
@@ -0,0 +1,667 @@
+=====================
+Using Request objects
+=====================
+
+HTTP request messages
+---------------------
+
+Request objects are all about building an HTTP message. Each part of an HTTP request message can be set individually
+using methods on the request object or set in bulk using the ``setUrl()`` method. Here's the format of an HTTP request
+with each part of the request referencing the method used to change it::
+
+ PUT(a) /path(b)?query=123(c) HTTP/1.1(d)
+ X-Header(e): header
+ Content-Length(e): 4
+
+ data(f)
+
++-------------------------+---------------------------------------------------------------------------------+
+| a. **Method** | The request method can only be set when instantiating a request |
++-------------------------+---------------------------------------------------------------------------------+
+| b. **Path** | ``$request->setPath('/path');`` |
++-------------------------+---------------------------------------------------------------------------------+
+| c. **Query** | ``$request->getQuery()->set('query', '123');`` |
++-------------------------+---------------------------------------------------------------------------------+
+| d. **Protocol version** | ``$request->setProtocolVersion('1.1');`` |
++-------------------------+---------------------------------------------------------------------------------+
+| e. **Header** | ``$request->setHeader('X-Header', 'header');`` |
++-------------------------+---------------------------------------------------------------------------------+
+| f. **Entity Body** | ``$request->setBody('data'); // Only available with PUT, POST, PATCH, DELETE`` |
++-------------------------+---------------------------------------------------------------------------------+
+
+Creating requests with a client
+-------------------------------
+
+Client objects are responsible for creating HTTP request objects.
+
+GET requests
+~~~~~~~~~~~~
+
+`GET requests `_ are the most common form of HTTP
+requests. When you visit a website in your browser, the HTML of the website is downloaded using a GET request. GET
+requests are idempotent requests that are typically used to download content (an entity) identified by a request URL.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+
+ $client = new Client();
+
+ // Create a request that has a query string and an X-Foo header
+ $request = $client->get('http://www.amazon.com?a=1', array('X-Foo' => 'Bar'));
+
+ // Send the request and get the response
+ $response = $request->send();
+
+You can change where the body of a response is downloaded on any request using the
+``$request->setResponseBody(string|EntityBodyInterface|resource)`` method of a request. You can also set the ``save_to``
+option of a request:
+
+.. code-block:: php
+
+ // Send the response body to a file
+ $request = $client->get('http://test.com', array(), array('save_to' => '/path/to/file'));
+
+ // Send the response body to an fopen resource
+ $request = $client->get('http://test.com', array(), array('save_to' => fopen('/path/to/file', 'w')));
+
+HEAD requests
+~~~~~~~~~~~~~
+
+`HEAD requests `_ work exactly like GET requests except
+that they do not actually download the response body (entity) of the response message. HEAD requests are useful for
+retrieving meta information about an entity identified by a Request-URI.
+
+.. code-block:: php
+
+ $client = new Guzzle\Http\Client();
+ $request = $client->head('http://www.amazon.com');
+ $response = $request->send();
+ echo $response->getContentLength();
+ // >>> Will output the Content-Length header value
+
+DELETE requests
+~~~~~~~~~~~~~~~
+
+A `DELETE method `_ requests that the origin server
+delete the resource identified by the Request-URI.
+
+.. code-block:: php
+
+ $client = new Guzzle\Http\Client();
+ $request = $client->delete('http://example.com');
+ $response = $request->send();
+
+POST requests
+~~~~~~~~~~~~~
+
+While `POST requests `_ can be used for a number of
+reasons, POST requests are often used when submitting HTML form data to a website. POST requests can include an entity
+body in the HTTP request.
+
+POST requests in Guzzle are sent with an ``application/x-www-form-urlencoded`` Content-Type header if POST fields are
+present but no files are being sent in the POST. If files are specified in the POST request, then the Content-Type
+header will become ``multipart/form-data``.
+
+The ``post()`` method of a client object accepts four arguments: the URL, optional headers, post fields, and an array of
+request options. To send files in the POST request, prepend the ``@`` symbol to the array value (just like you would if
+you were using the PHP ``curl_setopt`` function).
+
+Here's how to create a multipart/form-data POST request containing files and fields:
+
+.. code-block:: php
+
+ $request = $client->post('http://httpbin.org/post', array(), array(
+ 'custom_field' => 'my custom value',
+ 'file_field' => '@/path/to/file.xml'
+ ));
+
+ $response = $request->send();
+
+.. note::
+
+ Remember to **always** sanitize user input when sending POST requests:
+
+ .. code-block:: php
+
+ // Prevent users from accessing sensitive files by sanitizing input
+ $_POST = array('firstname' => '@/etc/passwd');
+ $request = $client->post('http://www.example.com', array(), array (
+ 'firstname' => str_replace('@', '', $_POST['firstname'])
+ ));
+
+You can alternatively build up the contents of a POST request.
+
+.. code-block:: php
+
+ $request = $client->post('http://httpbin.org/post')
+ ->setPostField('custom_field', 'my custom value')
+ ->addPostFile('file', '/path/to/file.xml');
+
+ $response = $request->send();
+
+Raw POST data
+^^^^^^^^^^^^^
+
+POST requests can also contain raw POST data that is not related to HTML forms.
+
+.. code-block:: php
+
+ $request = $client->post('http://httpbin.org/post', array(), 'this is the body');
+ $response = $request->send();
+
+You can set the body of POST request using the ``setBody()`` method of the
+``Guzzle\Http\Message\EntityEnclosingRequest`` object. This method accepts a string, a resource returned from
+``fopen``, or a ``Guzzle\Http\EntityBodyInterface`` object.
+
+.. code-block:: php
+
+ $request = $client->post('http://httpbin.org/post');
+ // Set the body of the POST to stream the contents of /path/to/large_body.txt
+ $request->setBody(fopen('/path/to/large_body.txt', 'r'));
+ $response = $request->send();
+
+PUT requests
+~~~~~~~~~~~~
+
+The `PUT method `_ requests that the enclosed entity be
+stored under the supplied Request-URI. PUT requests are similar to POST requests in that they both can send an entity
+body in the request message.
+
+The body of a PUT request (any any ``Guzzle\Http\Message\EntityEnclosingRequestInterface`` object) is always stored as
+a ``Guzzle\Http\Message\EntityBodyInterface`` object. This allows a great deal of flexibility when sending data to a
+remote server. For example, you can stream the contents of a stream returned by fopen, stream the contents of a
+callback function, or simply send a string of data.
+
+.. code-block:: php
+
+ $request = $client->put('http://httpbin.org/put', array(), 'this is the body');
+ $response = $request->send();
+
+Just like with POST, PATH, and DELETE requests, you can set the body of a PUT request using the ``setBody()`` method.
+
+.. code-block:: php
+
+ $request = $client->put('http://httpbin.org/put');
+ $request->setBody(fopen('/path/to/large_body.txt', 'r'));
+ $response = $request->send();
+
+PATCH requests
+~~~~~~~~~~~~~~
+
+`PATCH requests `_ are used to modify a resource.
+
+.. code-block:: php
+
+ $request = $client->patch('http://httpbin.org', array(), 'this is the body');
+ $response = $request->send();
+
+OPTIONS requests
+~~~~~~~~~~~~~~~~
+
+The `OPTIONS method `_ represents a request for
+information about the communication options available on the request/response chain identified by the Request-URI.
+
+.. code-block:: php
+
+ $request = $client->options('http://httpbin.org');
+ $response = $request->send();
+
+ // Check if the PUT method is supported by this resource
+ var_export($response->isMethodAllows('PUT'));
+
+Custom requests
+~~~~~~~~~~~~~~~
+
+You can create custom HTTP requests that use non-standard HTTP methods using the ``createRequest()`` method of a
+client object.
+
+.. code-block:: php
+
+ $request = $client->createRequest('COPY', 'http://example.com/foo', array(
+ 'Destination' => 'http://example.com/bar',
+ 'Overwrite' => 'T'
+ ));
+ $response = $request->send();
+
+Query string parameters
+-----------------------
+
+Query string parameters of a request are owned by a request's ``Guzzle\Http\Query`` object that is accessible by
+calling ``$request->getQuery()``. The Query class extends from ``Guzzle\Common\Collection`` and allows you to set one
+or more query string parameters as key value pairs. You can set a parameter on a Query object using the
+``set($key, $value)`` method or access the query string object like an associative array. Any previously specified
+value for a key will be overwritten when using ``set()``. Use ``add($key, $value)`` to add a value to query string
+object, and in the event of a collision with an existing value at a specific key, the value will be converted to an
+array that contains all of the previously set values.
+
+.. code-block:: php
+
+ $request = new Guzzle\Http\Message\Request('GET', 'http://www.example.com?foo=bar&abc=123');
+
+ $query = $request->getQuery();
+ echo "{$query}\n";
+ // >>> foo=bar&abc=123
+
+ $query->remove('abc');
+ echo "{$query}\n";
+ // >>> foo=bar
+
+ $query->set('foo', 'baz');
+ echo "{$query}\n";
+ // >>> foo=baz
+
+ $query->add('foo', 'bar');
+ echo "{$query}\n";
+ // >>> foo%5B0%5D=baz&foo%5B1%5D=bar
+
+Whoah! What happened there? When ``foo=bar`` was added to the existing ``foo=baz`` query string parameter, the
+aggregator associated with the Query object was used to help convert multi-value query string parameters into a string.
+Let's disable URL-encoding to better see what's happening.
+
+.. code-block:: php
+
+ $query->useUrlEncoding(false);
+ echo "{$query}\n";
+ // >>> foo[0]=baz&foo[1]=bar
+
+.. note::
+
+ URL encoding can be disabled by passing false, enabled by passing true, set to use RFC 1738 by passing
+ ``Query::FORM_URLENCODED`` (internally uses PHP's ``urlencode`` function), or set to RFC 3986 by passing
+ ``Query::RFC_3986`` (this is the default and internally uses PHP's ``rawurlencode`` function).
+
+As you can see, the multiple values were converted into query string parameters following the default PHP convention of
+adding numerically indexed square bracket suffixes to each key (``foo[0]=baz&foo[1]=bar``). The strategy used to convert
+multi-value parameters into a string can be customized using the ``setAggregator()`` method of the Query class. Guzzle
+ships with the following query string aggregators by default:
+
+1. ``Guzzle\Http\QueryAggregator\PhpAggregator``: Aggregates using PHP style brackets (e.g. ``foo[0]=baz&foo[1]=bar``)
+2. ``Guzzle\Http\QueryAggregator\DuplicateAggregator``: Performs no aggregation and allows for key value pairs to be
+ repeated in a URL (e.g. ``foo=baz&foo=bar``)
+3. ``Guzzle\Http\QueryAggregator\CommaAggregator``: Aggregates using commas (e.g. ``foo=baz,bar``)
+
+.. _http-message-headers:
+
+HTTP Message Headers
+--------------------
+
+HTTP message headers are case insensitive, multiple occurrences of any header can be present in an HTTP message
+(whether it's valid or not), and some servers require specific casing of particular headers. Because of this, request
+and response headers are stored in ``Guzzle\Http\Message\Header`` objects. The Header object can be cast as a string,
+counted, or iterated to retrieve each value from the header. Casting a Header object to a string will return all of
+the header values concatenated together using a glue string (typically ", ").
+
+A request (and response) object have several methods that allow you to retrieve and modify headers.
+
+* ``getHeaders()``: Get all of the headers of a message as a ``Guzzle\Http\Message\Header\HeaderCollection`` object.
+* ``getHeader($header)``: Get a specific header from a message. If the header exists, you'll get a
+ ``Guzzle\Http\Message\Header`` object. If the header does not exist, this methods returns ``null``.
+* ``hasHeader($header)``: Returns true or false based on if the message has a particular header.
+* ``setHeader($header, $value)``: Set a header value and overwrite any previously set value for this header.
+* ``addHeader($header, $value)``: Add a header with a particular name. If a previous value was already set by the same,
+ then the header will contain multiple values.
+* ``removeHeader($header)``: Remove a header by name from the message.
+
+.. code-block:: php
+
+ $request = new Request('GET', 'http://httpbin.com/cookies');
+ // addHeader will set and append to any existing header values
+ $request->addHeader('Foo', 'bar');
+ $request->addHeader('foo', 'baz');
+ // setHeader overwrites any existing values
+ $request->setHeader('Test', '123');
+
+ // Request headers can be cast as a string
+ echo $request->getHeader('Foo');
+ // >>> bar, baz
+ echo $request->getHeader('Test');
+ // >>> 123
+
+ // You can count the number of headers of a particular case insensitive name
+ echo count($request->getHeader('foO'));
+ // >>> 2
+
+ // You can iterate over Header objects
+ foreach ($request->getHeader('foo') as $header) {
+ echo $header . "\n";
+ }
+
+ // You can get all of the request headers as a Guzzle\Http\Message\Header\HeaderCollection object
+ $headers = $request->getHeaders();
+
+ // Missing headers return NULL
+ var_export($request->getHeader('Missing'));
+ // >>> null
+
+ // You can see all of the different variations of a header by calling raw() on the Header
+ var_export($request->getHeader('foo')->raw());
+
+Setting the body of a request
+-----------------------------
+
+Requests that can send a body (e.g. PUT, POST, DELETE, PATCH) are instances of
+``Guzzle\Http\Message\EntityEnclosingRequestInterface``. Entity enclosing requests contain several methods that allow
+you to specify the body to send with a request.
+
+Use the ``setBody()`` method of a request to set the body that will be sent with a request. This method accepts a
+string, a resource returned by ``fopen()``, an array, or an instance of ``Guzzle\Http\EntityBodyInterface``. The body
+will then be streamed from the underlying ``EntityBodyInterface`` object owned by the request. When setting the body
+of the request, you can optionally specify a Content-Type header and whether or not to force the request to use
+chunked Transfer-Encoding.
+
+.. code-block:: php
+
+ $request = $client->put('/user.json');
+ $request->setBody('{"foo":"baz"}', 'application/json');
+
+Content-Type header
+~~~~~~~~~~~~~~~~~~~
+
+Guzzle will automatically add a Content-Type header to a request if the Content-Type can be guessed based on the file
+extension of the payload being sent or the file extension present in the path of a request.
+
+.. code-block:: php
+
+ $request = $client->put('/user.json', array(), '{"foo":"bar"}');
+ // The Content-Type was guessed based on the path of the request
+ echo $request->getHeader('Content-Type');
+ // >>> application/json
+
+ $request = $client->put('/user.json');
+ $request->setBody(fopen('/tmp/user_data.json', 'r'));
+ // The Content-Type was guessed based on the path of the entity body
+ echo $request->getHeader('Content-Type');
+ // >>> application/json
+
+Transfer-Encoding: chunked header
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When sending HTTP requests that contain a payload, you must let the remote server know how to determine when the entire
+message has been sent. This usually is done by supplying a ``Content-Length`` header that tells the origin server the
+size of the body that is to be sent. In some cases, the size of the payload being sent in a request cannot be known
+before initiating the transfer. In these cases (when using HTTP/1.1), you can use the ``Transfer-Encoding: chunked``
+header.
+
+If the Content-Length cannot be determined (i.e. using a PHP ``http://`` stream), then Guzzle will automatically add
+the ``Transfer-Encoding: chunked`` header to the request.
+
+.. code-block:: php
+
+ $request = $client->put('/user.json');
+ $request->setBody(fopen('http://httpbin.org/get', 'r'));
+
+ // The Content-Length could not be determined
+ echo $request->getHeader('Transfer-Encoding');
+ // >>> chunked
+
+See :doc:`/http-client/entity-bodies` for more information on entity bodies.
+
+Expect: 100-Continue header
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``Expect: 100-Continue`` header is used to help a client prevent sending a large payload to a server that will
+reject the request. This allows clients to fail fast rather than waste bandwidth sending an erroneous payload. Guzzle
+will automatically add the ``Expect: 100-Continue`` header to a request when the size of the payload exceeds 1MB or if
+the body of the request is not seekable (this helps to prevent errors when a non-seekable body request is redirected).
+
+.. note::
+
+ If you find that your larger requests are taking too long to complete, you should first check if the
+ ``Expect: 100-Continue`` header is being sent with the request. Some servers do not respond well to this header,
+ which causes cURL to sleep for `1 second `_.
+
+POST fields and files
+~~~~~~~~~~~~~~~~~~~~~
+
+Any entity enclosing request can send POST style fields and files. This includes POST, PUT, PATCH, and DELETE requests.
+Any request that has set POST fields or files will use cURL's POST message functionality.
+
+.. code-block:: php
+
+ $request = $client->post('/post');
+ // Set an overwrite any previously specified value
+ $request->setPostField('foo', 'bar');
+ // Append a value to any existing values
+ $request->getPostFields()->add('foo', 'baz');
+ // Remove a POST field by name
+ $request->removePostField('fizz');
+
+ // Add a file to upload (forces multipart/form-data)
+ $request->addPostFile('my_file', '/path/to/file', 'plain/text');
+ // Remove a POST file by POST key name
+ $request->removePostFile('my_other_file');
+
+.. tip::
+
+ Adding a large number of POST fields to a POST request is faster if you use the ``addPostFields()`` method so that
+ you can add and process multiple fields with a single call. Adding multiple POST files is also faster using
+ ``addPostFiles()``.
+
+Working with cookies
+--------------------
+
+Cookies can be modified and retrieved from a request using the following methods:
+
+.. code-block:: php
+
+ $request->addCookie($name, $value);
+ $request->removeCookie($name);
+ $value = $request->getCookie($name);
+ $valueArray = $request->getCookies();
+
+Use the :doc:`cookie plugin ` if you need to reuse cookies between requests.
+
+.. _request-set-response-body:
+
+Changing where a response is downloaded
+----------------------------------------
+
+When a request is sent, the body of the response will be stored in a PHP temp stream by default. You can change the
+location in which the response will be downloaded using ``$request->setResponseBody($body)`` or the ``save_to`` request
+option. This can be useful for downloading the contents of a URL to a specific file.
+
+Here's an example of using request options:
+
+.. code-block:: php
+
+ $request = $this->client->get('http://example.com/large.mov', array(), array(
+ 'save_to' => '/tmp/large_file.mov'
+ ));
+ $request->send();
+ var_export(file_exists('/tmp/large_file.mov'));
+ // >>> true
+
+Here's an example of using ``setResponseBody()``:
+
+.. code-block:: php
+
+ $body = fopen('/tmp/large_file.mov', 'w');
+ $request = $this->client->get('http://example.com/large.mov');
+ $request->setResponseBody($body);
+
+ // You can more easily specify the name of a file to save the contents
+ // of the response to by passing a string to ``setResponseBody()``.
+
+ $request = $this->client->get('http://example.com/large.mov');
+ $request->setResponseBody('/tmp/large_file.mov');
+
+Custom cURL options
+-------------------
+
+Most of the functionality implemented in the libcurl bindings has been simplified and abstracted by Guzzle. Developers
+who need access to `cURL specific functionality `_ can still add cURL handle
+specific behavior to Guzzle HTTP requests by modifying the cURL options collection of a request:
+
+.. code-block:: php
+
+ $request->getCurlOptions()->set(CURLOPT_LOW_SPEED_LIMIT, 200);
+
+Other special options that can be set in the ``curl.options`` array include:
+
++-------------------------+---------------------------------------------------------------------------------+
+| debug | Adds verbose cURL output to a temp stream owned by the cURL handle object |
++-------------------------+---------------------------------------------------------------------------------+
+| progress | Instructs cURL to emit events when IO events occur. This allows you to be |
+| | notified when bytes are transferred over the wire by subscribing to a request's |
+| | ``curl.callback.read``, ``curl.callback.write``, and ``curl.callback.progress`` |
+| | events. |
++-------------------------+---------------------------------------------------------------------------------+
+
+Request options
+---------------
+
+Requests options can be specified when creating a request or in the ``request.options`` parameter of a client. These
+options can control various aspects of a request including: headers to send, query string data, where the response
+should be downloaded, proxies, auth, etc.
+
+.. code-block:: php
+
+ $request = $client->get($url, $headers, array('proxy' => 'http://proxy.com'));
+
+See :ref:`Request options ` for more information.
+
+Working with errors
+-------------------
+
+HTTP errors
+~~~~~~~~~~~
+
+Requests that receive a 4xx or 5xx response will throw a ``Guzzle\Http\Exception\BadResponseException``. More
+specifically, 4xx errors throw a ``Guzzle\Http\Exception\ClientErrorResponseException``, and 5xx errors throw a
+``Guzzle\Http\Exception\ServerErrorResponseException``. You can catch the specific exceptions or just catch the
+BadResponseException to deal with either type of error. Here's an example of catching a generic BadResponseException:
+
+.. code-block:: php
+
+ try {
+ $response = $client->get('/not_found.xml')->send();
+ } catch (Guzzle\Http\Exception\BadResponseException $e) {
+ echo 'Uh oh! ' . $e->getMessage();
+ echo 'HTTP request URL: ' . $e->getRequest()->getUrl() . "\n";
+ echo 'HTTP request: ' . $e->getRequest() . "\n";
+ echo 'HTTP response status: ' . $e->getResponse()->getStatusCode() . "\n";
+ echo 'HTTP response: ' . $e->getResponse() . "\n";
+ }
+
+Throwing an exception when a 4xx or 5xx response is encountered is the default behavior of Guzzle requests. This
+behavior can be overridden by adding an event listener with a higher priority than -255 that stops event propagation.
+You can subscribe to ``request.error`` to receive notifications any time an unsuccessful response is received.
+
+You can change the response that will be associated with the request by calling ``setResponse()`` on the
+``$event['request']`` object passed into your listener, or by changing the ``$event['response']`` value of the
+``Guzzle\Common\Event`` object that is passed to your listener. Transparently changing the response associated with a
+request by modifying the event allows you to retry failed requests without complicating the code that uses the client.
+This might be useful for sending requests to a web service that has expiring auth tokens. When a response shows that
+your token has expired, you can get a new token, retry the request with the new token, and return the successful
+response to the user.
+
+Here's an example of retrying a request using updated authorization credentials when a 401 response is received,
+overriding the response of the original request with the new response, and still allowing the default exception
+behavior to be called when other non-200 response status codes are encountered:
+
+.. code-block:: php
+
+ // Add custom error handling to any request created by this client
+ $client->getEventDispatcher()->addListener('request.error', function(Event $event) {
+
+ if ($event['response']->getStatusCode() == 401) {
+
+ $newRequest = $event['request']->clone();
+ $newRequest->setHeader('X-Auth-Header', MyApplication::getNewAuthToken());
+ $newResponse = $newRequest->send();
+
+ // Set the response object of the request without firing more events
+ $event['response'] = $newResponse;
+
+ // You can also change the response and fire the normal chain of
+ // events by calling $event['request']->setResponse($newResponse);
+
+ // Stop other events from firing when you override 401 responses
+ $event->stopPropagation();
+ }
+
+ });
+
+cURL errors
+~~~~~~~~~~~
+
+Connection problems and cURL specific errors can also occur when transferring requests using Guzzle. When Guzzle
+encounters cURL specific errors while transferring a single request, a ``Guzzle\Http\Exception\CurlException`` is
+thrown with an informative error message and access to the cURL error message.
+
+A ``Guzzle\Http\Exception\MultiTransferException`` exception is thrown when a cURL specific error occurs while
+transferring multiple requests in parallel. You can then iterate over all of the exceptions encountered during the
+transfer.
+
+Plugins and events
+------------------
+
+Guzzle request objects expose various events that allow you to hook in custom logic. A request object owns a
+``Symfony\Component\EventDispatcher\EventDispatcher`` object that can be accessed by calling
+``$request->getEventDispatcher()``. You can use the event dispatcher to add listeners (a simple callback function) or
+event subscribers (classes that listen to specific events of a dispatcher). You can add event subscribers to a request
+directly by just calling ``$request->addSubscriber($mySubscriber);``.
+
+.. _request-events:
+
+Events emitted from a request
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A ``Guzzle\Http\Message\Request`` and ``Guzzle\Http\Message\EntityEnclosingRequest`` object emit the following events:
+
++------------------------------+--------------------------------------------+------------------------------------------+
+| Event name | Description | Event data |
++==============================+============================================+==========================================+
+| request.before_send | About to send request | * request: Request to be sent |
++------------------------------+--------------------------------------------+------------------------------------------+
+| request.sent | Sent the request | * request: Request that was sent |
+| | | * response: Received response |
++------------------------------+--------------------------------------------+------------------------------------------+
+| request.complete | Completed a full HTTP transaction | * request: Request that was sent |
+| | | * response: Received response |
++------------------------------+--------------------------------------------+------------------------------------------+
+| request.success | Completed a successful request | * request: Request that was sent |
+| | | * response: Received response |
++------------------------------+--------------------------------------------+------------------------------------------+
+| request.error | Completed an unsuccessful request | * request: Request that was sent |
+| | | * response: Received response |
++------------------------------+--------------------------------------------+------------------------------------------+
+| request.exception | An unsuccessful response was | * request: Request |
+| | received. | * response: Received response |
+| | | * exception: BadResponseException |
++------------------------------+--------------------------------------------+------------------------------------------+
+| request.receive.status_line | Received the start of a response | * line: Full response start line |
+| | | * status_code: Status code |
+| | | * reason_phrase: Reason phrase |
+| | | * previous_response: (e.g. redirect) |
++------------------------------+--------------------------------------------+------------------------------------------+
+| curl.callback.progress | cURL progress event (only dispatched when | * handle: CurlHandle |
+| | ``emit_io`` is set on a request's curl | * download_size: Total download size |
+| | options) | * downloaded: Bytes downloaded |
+| | | * upload_size: Total upload bytes |
+| | | * uploaded: Bytes uploaded |
++------------------------------+--------------------------------------------+------------------------------------------+
+| curl.callback.write | cURL event called when data is written to | * request: Request |
+| | an outgoing stream | * write: Data being written |
++------------------------------+--------------------------------------------+------------------------------------------+
+| curl.callback.read | cURL event called when data is written to | * request: Request |
+| | an incoming stream | * read: Data being read |
++------------------------------+--------------------------------------------+------------------------------------------+
+
+Creating a request event listener
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here's an example that listens to the ``request.complete`` event of a request and prints the request and response.
+
+.. code-block:: php
+
+ use Guzzle\Common\Event;
+
+ $request = $client->get('http://www.google.com');
+
+ // Echo out the response that was received
+ $request->getEventDispatcher()->addListener('request.complete', function (Event $e) {
+ echo $e['request'] . "\n\n";
+ echo $e['response'];
+ });
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/response.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/response.rst
new file mode 100755
index 0000000..ba48731
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/response.rst
@@ -0,0 +1,141 @@
+======================
+Using Response objects
+======================
+
+Sending a request will return a ``Guzzle\Http\Message\Response`` object. You can view the raw HTTP response message by
+casting the Response object to a string. Casting the response to a string will return the entity body of the response
+as a string too, so this might be an expensive operation if the entity body is stored in a file or network stream. If
+you only want to see the response headers, you can call ``getRawHeaders()``.
+
+Response status line
+--------------------
+
+The different parts of a response's `status line `_
+(the first line of the response HTTP message) are easily retrievable.
+
+.. code-block:: php
+
+ $response = $client->get('http://www.amazon.com')->send();
+
+ echo $response->getStatusCode(); // >>> 200
+ echo $response->getReasonPhrase(); // >>> OK
+ echo $response->getProtocol(); // >>> HTTP
+ echo $response->getProtocolVersion(); // >>> 1.1
+
+You can determine the type of the response using several helper methods:
+
+.. code-block:: php
+
+ $response->isSuccessful(); // true
+ $response->isInformational();
+ $response->isRedirect();
+ $response->isClientError();
+ $response->isServerError();
+
+Response headers
+----------------
+
+The Response object contains helper methods for retrieving common response headers. These helper methods normalize the
+variations of HTTP response headers.
+
+.. code-block:: php
+
+ $response->getCacheControl();
+ $response->getContentType();
+ $response->getContentLength();
+ $response->getContentEncoding();
+ $response->getContentMd5();
+ $response->getEtag();
+ // etc... There are methods for every known response header
+
+You can interact with the Response headers using the same exact methods used to interact with Request headers. See
+:ref:`http-message-headers` for more information.
+
+.. code-block:: php
+
+ echo $response->getHeader('Content-Type');
+ echo $response->getHeader('Content-Length');
+ echo $response->getHeaders()['Content-Type']; // PHP 5.4
+
+Response body
+-------------
+
+The entity body object of a response can be retrieved by calling ``$response->getBody()``. The response EntityBody can
+be cast to a string, or you can pass ``true`` to this method to retrieve the body as a string.
+
+.. code-block:: php
+
+ $request = $client->get('http://www.amazon.com');
+ $response = $request->send();
+ echo $response->getBody();
+
+See :doc:`/http-client/entity-bodies` for more information on entity bodies.
+
+JSON Responses
+~~~~~~~~~~~~~~
+
+You can easily parse and use a JSON response as an array using the ``json()`` method of a response. This method will
+always return an array if the response is valid JSON or if the response body is empty. You will get an exception if you
+call this method and the response is not valid JSON.
+
+.. code-block:: php
+
+ $data = $response->json();
+ echo gettype($data);
+ // >>> array
+
+XML Responses
+~~~~~~~~~~~~~
+
+You can easily parse and use a XML response as SimpleXMLElement object using the ``xml()`` method of a response. This
+method will always return a SimpleXMLElement object if the response is valid XML or if the response body is empty. You
+will get an exception if you call this method and the response is not valid XML.
+
+.. code-block:: php
+
+ $xml = $response->xml();
+ echo $xml->foo;
+ // >>> Bar!
+
+Streaming responses
+-------------------
+
+Some web services provide streaming APIs that allow a client to keep a HTTP request open for an extended period of
+time while polling and reading. Guzzle provides a simple way to convert HTTP request messages into
+``Guzzle\Stream\Stream`` objects so that you can send the initial headers of a request, read the response headers, and
+pull in the response body manually as needed.
+
+Here's an example using the Twitter Streaming API to track the keyword "bieber":
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Stream\PhpStreamRequestFactory;
+
+ $client = new Client('https://stream.twitter.com/1');
+
+ $request = $client->post('statuses/filter.json', null, array(
+ 'track' => 'bieber'
+ ));
+
+ $request->setAuth('myusername', 'mypassword');
+
+ $factory = new PhpStreamRequestFactory();
+ $stream = $factory->fromRequest($request);
+
+ // Read until the stream is closed
+ while (!$stream->feof()) {
+ // Read a line from the stream
+ $line = $stream->readLine();
+ // JSON decode the line of data
+ $data = json_decode($line, true);
+ }
+
+You can use the ``stream`` request option when using a static client to more easily create a streaming response.
+
+.. code-block:: php
+
+ $stream = Guzzle::get('http://guzzlephp.org', array('stream' => true));
+ while (!$stream->feof()) {
+ echo $stream->readLine();
+ }
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/uri-templates.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/uri-templates.rst
new file mode 100755
index 0000000..c18ac3e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/http-client/uri-templates.rst
@@ -0,0 +1,52 @@
+=============
+URI templates
+=============
+
+The ``$uri`` passed to one of the client's request creational methods or the base URL of a client can utilize URI
+templates. Guzzle supports the entire `URI templates RFC `_. URI templates add a
+special syntax to URIs that replace template place holders with user defined variables.
+
+Every request created by a Guzzle HTTP client passes through a URI template so that URI template expressions are
+automatically expanded:
+
+.. code-block:: php
+
+ $client = new Guzzle\Http\Client('https://example.com/', array('a' => 'hi'));
+ $request = $client->get('/{a}');
+
+Because of URI template expansion, the URL of the above request will become ``https://example.com/hi``. Notice that
+the template was expanded using configuration variables of the client. You can pass in custom URI template variables
+by passing the URI of your request as an array where the first index of the array is the URI template and the second
+index of the array are template variables that are merged into the client's configuration variables.
+
+.. code-block:: php
+
+ $request = $client->get(array('/test{?a,b}', array('b' => 'there')));
+
+The URL for this request will become ``https://test.com?a=hi&b=there``. URI templates aren't limited to just simple
+variable replacements; URI templates can provide an enormous amount of flexibility when creating request URIs.
+
+.. code-block:: php
+
+ $request = $client->get(array('http://example.com{+path}{/segments*}{?query,data*}', array(
+ 'path' => '/foo/bar',
+ 'segments' => array('one', 'two'),
+ 'query' => 'test',
+ 'data' => array(
+ 'more' => 'value'
+ )
+ )));
+
+The resulting URL would become ``http://example.com/foo/bar/one/two?query=test&more=value``.
+
+By default, URI template expressions are enclosed in an opening and closing brace (e.g. ``{var}``). If you are working
+with a web service that actually uses braces (e.g. Solr), then you can specify a custom regular expression to use to
+match URI template expressions.
+
+.. code-block:: php
+
+ $client->getUriTemplate()->setRegex('/\<\$(.+)\>/');
+ $client->get('/<$a>');
+
+You can learn about all of the different features of URI templates by reading the
+`URI templates RFC `_.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/index.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/index.rst
new file mode 100755
index 0000000..f76f3bb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/index.rst
@@ -0,0 +1,5 @@
+.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services
+.. toctree::
+ :hidden:
+
+ docs.rst
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst
new file mode 100755
index 0000000..a5c7fd3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/iterators/guzzle-iterators.rst
@@ -0,0 +1,97 @@
+================
+Guzzle iterators
+================
+
+Guzzle provides several SPL iterators that can be used with other SPL iterators, including Guzzle resource iterators.
+Guzzle's ``guzzle/iterator`` component can also be used independently of the rest of Guzzle through Packagist and
+Composer: https://packagist.org/packages/guzzle/iterator
+
+ChunkedIterator
+---------------
+
+Pulls out multiple values from an inner iterator and yields and array of values for each outer iteration -- essentially
+pulling out chunks of values from the inner iterator.
+
+.. code-block:: php
+
+ use Guzzle\Iterator\ChunkedIterator;
+
+ $inner = new ArrayIterator(range(0, 8));
+ $chunkedIterator = new ChunkedIterator($inner, 2);
+
+ foreach ($chunkedIterator as $chunk) {
+ echo implode(', ', $chunk) . "\n";
+ }
+
+ // >>> 0, 1
+ // >>> 2, 3
+ // >>> 4, 5
+ // >>> 6, 7
+ // >>> 8
+
+FilterIterator
+--------------
+
+This iterator is used to filter values out of the inner iterator. This iterator can be used when PHP 5.4's
+CallbackFilterIterator is not available.
+
+.. code-block:: php
+
+ use Guzzle\Iterator\FilterIterator;
+
+ $inner = new ArrayIterator(range(1, 10));
+ $filterIterator = new FilterIterator($inner, function ($value) {
+ return $value % 2;
+ });
+
+ foreach ($filterIterator as $value) {
+ echo $value . "\n";
+ }
+
+ // >>> 2
+ // >>> 4
+ // >>> 6
+ // >>> 8
+ // >>> 10
+
+MapIterator
+-----------
+
+This iterator modifies the values of the inner iterator before yielding.
+
+.. code-block:: php
+
+ use Guzzle\Iterator\MapIterator;
+
+ $inner = new ArrayIterator(range(0, 3));
+
+ $mapIterator = new MapIterator($inner, function ($value) {
+ return $value * 10;
+ });
+
+ foreach ($mapIterator as $value) {
+ echo $value . "\n";
+ }
+
+ // >>> 0
+ // >>> 10
+ // >>> 20
+ // >>> 30
+
+MethodProxyIterator
+-------------------
+
+This decorator is useful when you need to expose a specific method from an inner iterator that might be wrapper
+by one or more iterator decorators. This decorator proxies missing method calls to each inner iterator until one
+of the inner iterators can fulfill the call.
+
+.. code-block:: php
+
+ use Guzzle\Iterator\MethodProxyIterator;
+
+ $inner = new \ArrayIterator();
+ $proxy = new MethodProxyIterator($inner);
+
+ // Proxy method calls to the ArrayIterator
+ $proxy->append('a');
+ $proxy->append('b');
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst
new file mode 100755
index 0000000..ce0bee5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/iterators/resource-iterators.rst
@@ -0,0 +1,149 @@
+==================
+Resource iterators
+==================
+
+Web services often implement pagination in their responses which requires the end-user to issue a series of consecutive
+requests in order to fetch all of the data they asked for. Users of your web service client should not be responsible
+for implementing the logic involved in iterating through pages of results. Guzzle provides a simple resource iterator
+foundation to make it easier on web service client developers to offer a useful abstraction layer.
+
+Getting an iterator from a client
+---------------------------------
+
+ ResourceIteratorInterface Guzzle\Service\Client::getIterator($command [, array $commandOptions, array $iteratorOptions ])
+
+The ``getIterator`` method of a ``Guzzle\Service\ClientInterface`` object provides a convenient interface for
+instantiating a resource iterator for a specific command. This method implicitly uses a
+``Guzzle\Service\Resource\ResourceIteratorFactoryInterface`` object to create resource iterators. Pass an
+instantiated command object or the name of a command in the first argument. When passing the name of a command, the
+command factory of the client will create the command by name using the ``$commandOptions`` array. The third argument
+may be used to pass an array of options to the constructor of the instantiated ``ResourceIteratorInterface`` object.
+
+.. code-block:: php
+
+ $iterator = $client->getIterator('get_users');
+
+ foreach ($iterator as $user) {
+ echo $user['name'] . ' age ' . $user['age'] . PHP_EOL;
+ }
+
+The above code sample might execute a single request or a thousand requests. As a consumer of a web service, I don't
+care. I just want to iterate over all of the users.
+
+Iterator options
+~~~~~~~~~~~~~~~~
+
+The two universal options that iterators should support are ``limit`` and ``page_size``. Using the ``limit`` option
+tells the resource iterator to attempt to limit the total number of iterated resources to a specific amount. Keep in
+mind that this is not always possible due to limitations that may be inherent to a web service. The ``page_size``
+option is used to tell a resource iterator how many resources to request per page of results. Much like the ``limit``
+option, you can not rely on getting back exactly the number of resources your specify in the ``page_size`` option.
+
+.. note::
+
+ The ``limit`` and ``page_size`` options can also be specified on an iterator using the ``setLimit($limit)`` and
+ ``setPageSize($pageSize)`` methods.
+
+Resolving iterator class names
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default resource iterator factory of a client object expects that your iterators are stored under the ``Model``
+folder of your client and that an iterator is names after the CamelCase name of a command followed by the word
+"Iterator". For example, if you wanted to create an iterator for the ``get_users`` command, then your iterator class
+would be ``Model\GetUsersIterator`` and would be stored in ``Model/GetUsersIterator.php``.
+
+Creating an iterator
+--------------------
+
+While not required, resource iterators in Guzzle typically iterate using a ``Guzzle\Service\Command\CommandInterface``
+object. ``Guzzle\Service\Resource\ResourceIterator``, the default iterator implementation that you should extend,
+accepts a command object and array of iterator options in its constructor. The command object passed to the resource
+iterator is expected to be ready to execute and not previously executed. The resource iterator keeps a reference of
+this command and clones the original command each time a subsequent request needs to be made to fetch more data.
+
+Implement the sendRequest method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The most important thing (and usually the only thing) you need to do when creating a resource iterator is to implement
+the ``sendRequest()`` method of the resource iterator. The ``sendRequest()`` method is called when you begin
+iterating or if there are no resources left to iterate and it you expect to retrieve more resources by making a
+subsequent request. The ``$this->command`` property of the resource iterator is updated with a cloned copy of the
+original command object passed into the constructor of the iterator. Use this command object to issue your subsequent
+requests.
+
+The ``sendRequest()`` method must return an array of the resources you retrieved from making the subsequent call.
+Returning an empty array will stop the iteration. If you suspect that your web service client will occasionally return
+an empty result set but still requires further iteration, then you must implement a sort of loop in your
+``sendRequest()`` method that will continue to issue subsequent requests until your reach the end of the paginated
+result set or until additional resources are retrieved from the web service.
+
+Update the nextToken property
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Beyond fetching more results, the ``sendRequest()`` method is responsible for updating the ``$this->nextToken``
+property of the iterator. Setting this property to anything other than null tells the iterator that issuing a
+subsequent request using the nextToken value will probably return more results. You must continually update this
+value in your ``sendRequest()`` method as each response is received from the web service.
+
+Example iterator
+----------------
+
+Let's say you want to implement a resource iterator for the ``get_users`` command of your web service. The
+``get_users`` command receives a response that contains a list of users, and if there are more pages of results to
+retrieve, returns a value called ``next_user``. This return value is known as the **next token** and should be used to
+issue subsequent requests.
+
+Assume the response to a ``get_users`` command returns JSON data that looks like this:
+
+.. code-block:: javascript
+
+ {
+ "users": [
+ { "name": "Craig Johnson", "age": 10 },
+ { "name": "Tom Barker", "age": 20 },
+ { "name": "Bob Mitchell", "age": 74 }
+ ],
+ "next_user": "Michael Dowling"
+ }
+
+Assume that because there is a ``next_user`` value, there will be more users if a subsequent request is issued. If the
+``next_user`` value is missing or null, then we know there are no more results to fetch. Let's implement a resource
+iterator for this command.
+
+.. code-block:: php
+
+ namespace MyService\Model;
+
+ use Guzzle\Service\Resource\ResourceIterator;
+
+ /**
+ * Iterate over a get_users command
+ */
+ class GetUsersIterator extends ResourceIterator
+ {
+ protected function sendRequest()
+ {
+ // If a next token is set, then add it to the command
+ if ($this->nextToken) {
+ $this->command->set('next_user', $this->nextToken);
+ }
+
+ // Execute the command and parse the result
+ $result = $this->command->execute();
+
+ // Parse the next token
+ $this->nextToken = isset($result['next_user']) ? $result['next_user'] : false;
+
+ return $result['users'];
+ }
+ }
+
+As you can see, it's pretty simple to implement an iterator. There are a few things that you should notice from this
+example:
+
+1. You do not need to create a new command in the ``sendRequest()`` method. A new command object is cloned from the
+ original command passed into the constructor of the iterator before the ``sendRequest()`` method is called.
+ Remember that the resource iterator expects a command that has not been executed.
+2. When the ``sendRequest()`` method is first called, you will not have a ``$this->nextToken`` value, so always check
+ before setting it on a command. Notice that the next token is being updated each time a request is sent.
+3. After fetching more resources from the service, always return an array of resources.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/async-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/async-plugin.rst
new file mode 100755
index 0000000..9bd8f42
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/async-plugin.rst
@@ -0,0 +1,18 @@
+============
+Async plugin
+============
+
+The AsyncPlugin allows you to send requests that do not wait on a response. This is handled through cURL by utilizing
+the progress event. When a request has sent all of its data to the remote server, Guzzle adds a 1ms timeout on the
+request and instructs cURL to not download the body of the response. The async plugin then catches the exception and
+adds a mock response to the request, along with an X-Guzzle-Async header to let you know that the response was not
+fully downloaded.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\Async\AsyncPlugin;
+
+ $client = new Client('http://www.example.com');
+ $client->addSubscriber(new AsyncPlugin());
+ $response = $client->get()->send();
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst
new file mode 100755
index 0000000..5a76941
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/backoff-plugin.rst
@@ -0,0 +1,22 @@
+====================
+Backoff retry plugin
+====================
+
+The ``Guzzle\Plugin\Backoff\BackoffPlugin`` automatically retries failed HTTP requests using custom backoff strategies:
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\Backoff\BackoffPlugin;
+
+ $client = new Client('http://www.test.com/');
+ // Use a static factory method to get a backoff plugin using the exponential backoff strategy
+ $backoffPlugin = BackoffPlugin::getExponentialBackoff();
+
+ // Add the backoff plugin to the client object
+ $client->addSubscriber($backoffPlugin);
+
+The BackoffPlugin's constructor accepts a ``Guzzle\Plugin\Backoff\BackoffStrategyInterface`` object that is used to
+determine when a retry should be issued and how long to delay between retries. The above code example shows how to
+attach a BackoffPlugin to a client that is pre-configured to retry failed 500 and 503 responses using truncated
+exponential backoff (emulating the behavior of Guzzle 2's ExponentialBackoffPlugin).
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst
new file mode 100755
index 0000000..d2fd5df
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/cache-plugin.rst
@@ -0,0 +1,169 @@
+=================
+HTTP Cache plugin
+=================
+
+Guzzle can leverage HTTP's caching specifications using the ``Guzzle\Plugin\Cache\CachePlugin``. The CachePlugin
+provides a private transparent proxy cache that caches HTTP responses. The caching logic, based on
+`RFC 2616 `_, uses HTTP headers to control caching behavior,
+cache lifetime, and supports Vary, ETag, and Last-Modified based revalidation:
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Doctrine\Common\Cache\FilesystemCache;
+ use Guzzle\Cache\DoctrineCacheAdapter;
+ use Guzzle\Plugin\Cache\CachePlugin;
+ use Guzzle\Plugin\Cache\DefaultCacheStorage;
+
+ $client = new Client('http://www.test.com/');
+
+ $cachePlugin = new CachePlugin(array(
+ 'storage' => new DefaultCacheStorage(
+ new DoctrineCacheAdapter(
+ new FilesystemCache('/path/to/cache/files')
+ )
+ )
+ ));
+
+ // Add the cache plugin to the client object
+ $client->addSubscriber($cachePlugin);
+ $client->get('http://www.wikipedia.org/')->send();
+
+ // The next request will revalidate against the origin server to see if it
+ // has been modified. If a 304 response is received the response will be
+ // served from cache
+ $client->get('http://www.wikipedia.org/')->send();
+
+The cache plugin intercepts GET and HEAD requests before they are actually transferred to the origin server. The cache
+plugin then generates a hash key based on the request method and URL, and checks to see if a response exists in the cache. If
+a response exists in the cache, the cache adapter then checks to make sure that the caching rules associated with the response
+satisfy the request, and ensures that response still fresh. If the response is acceptable for the request any required
+revalidation, then the cached response is served instead of contacting the origin server.
+
+Vary
+----
+
+Cache keys are derived from a request method and a request URL. Multiple responses can map to the same cache key and
+stored in Guzzle's underlying cache storage object. You should use the ``Vary`` HTTP header to tell the cache storage
+object that the cache response must have been cached for a request that matches the headers specified in the Vary header
+of the request. This allows you to have specific cache entries for the same request URL but variations in a request's
+headers determine which cache entry is served. Please see the http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44
+for more information.
+
+Cache options
+-------------
+
+There are several options you can add to requests or clients to modify the behavior of the cache plugin.
+
+Override cache TTL
+~~~~~~~~~~~~~~~~~~
+
+You can override the number of seconds a cacheable response is stored in the cache by setting the
+``cache.override_ttl`` parameter on the params object of a request:
+
+.. code-block:: php
+
+ // If the response to the request is cacheable, then the response will be cached for 100 seconds
+ $request->getParams()->set('cache.override_ttl', 100);
+
+If a response doesn't specify any freshness policy, it will be kept in cache for 3600 seconds by default.
+
+Custom caching decision
+~~~~~~~~~~~~~~~~~~~~~~~
+
+If the service you are interacting with does not return caching headers or returns responses that are normally
+something that would not be cached, you can set a custom ``can_cache`` object on the constructor of the CachePlugin
+and provide a ``Guzzle\Plugin\Cache\CanCacheInterface`` object. You can use the
+``Guzzle\Plugin\Cache\CallbackCanCacheStrategy`` to easily make a caching decision based on an HTTP request and
+response.
+
+Revalidation options
+~~~~~~~~~~~~~~~~~~~~
+
+You can change the revalidation behavior of a request using the ``cache.revalidate`` parameter. Setting this
+parameter to ``never`` will ensure that a revalidation request is never sent, and the response is always served from
+the origin server. Setting this parameter to ``skip`` will never revalidate and uses the response stored in the cache.
+
+Normalizing requests for caching
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Use the ``cache.key_filter`` parameter if you wish to strip certain query string parameters from your
+request before creating a unique hash for the request. This parameter can be useful if your requests have query
+string values that cause each request URL to be unique (thus preventing a cache hit). The ``cache.key_filter``
+format is simply a comma separated list of query string values to remove from the URL when creating a cache key.
+For example, here we are saying that the ``a`` and ``q`` query string variables should be ignored when generating a
+cache key for the request:
+
+.. code-block:: php
+
+ $request->getParams()->set('cache.key_filter', 'a, q');
+
+Other options
+~~~~~~~~~~~~~
+
+There are many other options available to the CachePlugin that can meet almost any caching requirement, including
+custom revalidation implementations, custom cache key generators, custom caching decision strategies, and custom
+cache storage objects. Take a look the constructor of ``Guzzle\Plugin\Cache\CachePlugin`` for more information.
+
+Setting Client-wide cache settings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can specify cache settings for every request created by a client by adding cache settings to the configuration
+options of a client.
+
+.. code-block:: php
+
+ $client = new Guzzle\Http\Client('http://www.test.com', array(
+ 'request.params' => array(
+ 'cache.override_ttl' => 3600,
+ 'params.cache.revalidate' => 'never'
+ )
+ ));
+
+ echo $client->get('/')->getParams()->get('cache.override_ttl');
+ // >>> 3600
+
+ echo $client->get('/')->getParams()->get('cache.revalidate');
+ // >>> never
+
+Cache revalidation
+------------------
+
+If the cache plugin determines that a response to a GET request needs revalidation, a conditional GET is transferred
+to the origin server. If the origin server returns a 304 response, then a response containing the merged headers of
+the cached response with the new response and the entity body of the cached response is returned. Custom revalidation
+strategies can be injected into a CachePlugin if needed.
+
+Cache adapters
+--------------
+
+Guzzle doesn't try to reinvent the wheel when it comes to caching or logging. Plenty of other frameworks have
+excellent solutions in place that you are probably already using in your applications. Guzzle uses adapters for
+caching and logging. The cache plugin requires a cache adapter so that is can store responses in a cache. Guzzle
+currently supports cache adapters for `Doctrine 2.0 `_ and the
+`Zend Framework `_.
+
+Doctrine cache adapter
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: php
+
+ use Doctrine\Common\Cache\ArrayCache;
+ use Guzzle\Cache\DoctrineCacheAdapter;
+ use Guzzle\Plugin\Cache\CachePlugin;
+
+ $backend = new ArrayCache();
+ $adapter = new DoctrineCacheAdapter($backend);
+ $cache = new CachePlugin($adapter);
+
+Zend Framework cache adapter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: php
+
+ use Guzzle\Cache\ZendCacheAdapter;
+ use Zend\Cache\Backend\TestBackend;
+
+ $backend = new TestBackend();
+ $adapter = new ZendCacheAdapter($backend);
+ $cache = new CachePlugin($adapter);
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst
new file mode 100755
index 0000000..a6cc7d9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/cookie-plugin.rst
@@ -0,0 +1,33 @@
+=============
+Cookie plugin
+=============
+
+Some web services require a Cookie in order to maintain a session. The ``Guzzle\Plugin\Cookie\CookiePlugin`` will add
+cookies to requests and parse cookies from responses using a CookieJar object:
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\Cookie\CookiePlugin;
+ use Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar;
+
+ $cookiePlugin = new CookiePlugin(new ArrayCookieJar());
+
+ // Add the cookie plugin to a client
+ $client = new Client('http://www.test.com/');
+ $client->addSubscriber($cookiePlugin);
+
+ // Send the request with no cookies and parse the returned cookies
+ $client->get('http://www.yahoo.com/')->send();
+
+ // Send the request again, noticing that cookies are being sent
+ $request = $client->get('http://www.yahoo.com/');
+ $request->send();
+
+ echo $request;
+
+You can disable cookies per-request by setting the ``cookies.disable`` value to true on a request's params object.
+
+.. code-block:: php
+
+ $request->getParams()->set('cookies.disable', true);
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst
new file mode 100755
index 0000000..0870155
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/creating-plugins.rst
@@ -0,0 +1,93 @@
+================
+Creating plugins
+================
+
+.. highlight:: php
+
+Guzzle is extremely extensible because of the behavioral modifications that can be added to requests, clients, and
+commands using an event system. Before and after the majority of actions are taken in the library, an event is emitted
+with the name of the event and context surrounding the event. Observers can subscribe to a subject and modify the
+subject based on the events received. Guzzle's event system utilizes the Symfony2 EventDispatcher and is the backbone
+of its plugin architecture.
+
+Overview
+--------
+
+Plugins must implement the ``Symfony\Component\EventDispatcher\EventSubscriberInterface`` interface. The
+``EventSubscriberInterface`` requires that your class implements a static method, ``getSubscribedEvents()``, that
+returns an associative array mapping events to methods on the object. See the
+`Symfony2 documentation `_ for more information.
+
+Plugins can be attached to any subject, or object in Guzzle that implements that
+``Guzzle\Common\HasDispatcherInterface``.
+
+Subscribing to a subject
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can subscribe an instantiated observer to an event by calling ``addSubscriber`` on a subject.
+
+.. code-block:: php
+
+ $testPlugin = new TestPlugin();
+ $client->addSubscriber($testPlugin);
+
+You can also subscribe to only specific events using a closure::
+
+ $client->getEventDispatcher()->addListener('request.create', function(Event $event) {
+ echo $event->getName();
+ echo $event['request'];
+ });
+
+``Guzzle\Common\Event`` objects are passed to notified functions. The Event object has a ``getName()`` method which
+return the name of the emitted event and may contain contextual information that can be accessed like an array.
+
+Knowing what events to listen to
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Any class that implements the ``Guzzle\Common\HasDispatcherInterface`` must implement a static method,
+``getAllEvents()``, that returns an array of the events that are emitted from the object. You can browse the source
+to see each event, or you can call the static method directly in your code to get a list of available events.
+
+Event hooks
+-----------
+
+* :ref:`client-events`
+* :ref:`service-client-events`
+* :ref:`request-events`
+* ``Guzzle\Http\Curl\CurlMulti``:
+* :ref:`service-builder-events`
+
+Examples of the event system
+----------------------------
+
+Simple Echo plugin
+~~~~~~~~~~~~~~~~~~
+
+This simple plugin prints a string containing the request that is about to be sent by listening to the
+``request.before_send`` event::
+
+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+ class EchoPlugin implements EventSubscriberInterface
+ {
+ public static function getSubscribedEvents()
+ {
+ return array('request.before_send' => 'onBeforeSend');
+ }
+
+ public function onBeforeSend(Guzzle\Common\Event $event)
+ {
+ echo 'About to send a request: ' . $event['request'] . "\n";
+ }
+ }
+
+ $client = new Guzzle\Service\Client('http://www.test.com/');
+
+ // Create the plugin and add it as an event subscriber
+ $plugin = new EchoPlugin();
+ $client->addSubscriber($plugin);
+
+ // Send a request and notice that the request is printed to the screen
+ $client->get('/')->send();
+
+Running the above code will print a string containing the HTTP request that is about to be sent.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst
new file mode 100755
index 0000000..66d4a01
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/curl-auth-plugin.rst
@@ -0,0 +1,32 @@
+==========================
+cURL authentication plugin
+==========================
+
+.. warning::
+
+ The CurlAuthPlugin is deprecated. You should use the `auth` parameter of a client to add authorization headers to
+ every request created by a client.
+
+ .. code-block:: php
+
+ $client->setDefaultOption('auth', array('username', 'password', 'Basic|Digest|NTLM|Any'));
+
+If your web service client requires basic authorization, then you can use the CurlAuthPlugin to easily add an
+Authorization header to each request sent by the client.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\CurlAuth\CurlAuthPlugin;
+
+ $client = new Client('http://www.test.com/');
+
+ // Add the auth plugin to the client object
+ $authPlugin = new CurlAuthPlugin('username', 'password');
+ $client->addSubscriber($authPlugin);
+
+ $response = $client->get('projects/1/people')->send();
+ $xml = new SimpleXMLElement($response->getBody(true));
+ foreach ($xml->person as $person) {
+ echo $person->email . "\n";
+ }
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/history-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/history-plugin.rst
new file mode 100755
index 0000000..b96befe
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/history-plugin.rst
@@ -0,0 +1,24 @@
+==============
+History plugin
+==============
+
+The history plugin tracks all of the requests and responses sent through a request or client. This plugin can be
+useful for crawling or unit testing. By default, the history plugin stores up to 10 requests and responses.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\History\HistoryPlugin;
+
+ $client = new Client('http://www.test.com/');
+
+ // Add the history plugin to the client object
+ $history = new HistoryPlugin();
+ $history->setLimit(5);
+ $client->addSubscriber($history);
+
+ $client->get('http://www.yahoo.com/')->send();
+
+ echo $history->getLastRequest();
+ echo $history->getLastResponse();
+ echo count($history);
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/log-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/log-plugin.rst
new file mode 100755
index 0000000..3e2b229
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/log-plugin.rst
@@ -0,0 +1,69 @@
+==========
+Log plugin
+==========
+
+Use the ``Guzzle\Plugin\Log\LogPlugin`` to view all data sent over the wire, including entity bodies and redirects.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Log\Zf1LogAdapter;
+ use Guzzle\Plugin\Log\LogPlugin;
+ use Guzzle\Log\MessageFormatter;
+
+ $client = new Client('http://www.test.com/');
+
+ $adapter = new Zf1LogAdapter(
+ new \Zend_Log(new \Zend_Log_Writer_Stream('php://output'))
+ );
+ $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT);
+
+ // Attach the plugin to the client, which will in turn be attached to all
+ // requests generated by the client
+ $client->addSubscriber($logPlugin);
+
+ $response = $client->get('http://google.com')->send();
+
+The code sample above wraps a ``Zend_Log`` object using a ``Guzzle\Log\Zf1LogAdapter``. After attaching the plugin to
+the client, all data sent over the wire will be logged to stdout.
+
+The first argument of the LogPlugin's constructor accepts a ``Guzzle\Log\LogAdapterInterface`` object. This object is
+an adapter that allows you to use the logging capabilities of your favorite log implementation. The second argument of
+the constructor accepts a ``Guzzle\Log\MessageFormatter`` or a log messaged format string. The format string uses
+variable substitution and allows you to define the log data that is important to your application. The different
+variables that can be injected are as follows:
+
+================== ====================================================================================
+Variable Substitution
+================== ====================================================================================
+{request} Full HTTP request message
+{response} Full HTTP response message
+{ts} Timestamp
+{host} Host of the request
+{method} Method of the request
+{url} URL of the request
+{host} Host of the request
+{protocol} Request protocol
+{version} Protocol version
+{resource} Resource of the request (path + query + fragment)
+{port} Port of the request
+{hostname} Hostname of the machine that sent the request
+{code} Status code of the response (if available)
+{phrase} Reason phrase of the response (if available)
+{curl_error} Curl error message (if available)
+{curl_code} Curl error code (if available)
+{curl_stderr} Curl standard error (if available)
+{connect_time} Time in seconds it took to establish the connection (if available)
+{total_time} Total transaction time in seconds for last transfer (if available)
+{req_header_*} Replace `*` with the lowercased name of a request header to add to the message
+{res_header_*} Replace `*` with the lowercased name of a response header to add to the message
+{req_body} Request body
+{res_body} Response body
+================== ====================================================================================
+
+The LogPlugin has a helper method that can be used when debugging that will output the full HTTP request and
+response of a transaction:
+
+.. code-block:: php
+
+ $client->addSubscriber(LogPlugin::getDebugPlugin());
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst
new file mode 100755
index 0000000..1b1cfa8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/md5-validator-plugin.rst
@@ -0,0 +1,29 @@
+====================
+MD5 validator plugin
+====================
+
+Entity bodies can sometimes be modified over the wire due to a faulty TCP transport or misbehaving proxy. If an HTTP
+response contains a Content-MD5 header, then a MD5 hash of the entity body of a response can be compared against the
+Content-MD5 header of the response to determine if the response was delivered intact. The
+``Guzzle\Plugin\Md5\Md5ValidatorPlugin`` will throw an ``UnexpectedValueException`` if the calculated MD5 hash does
+not match the Content-MD5 header value:
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\Md5\Md5ValidatorPlugin;
+
+ $client = new Client('http://www.test.com/');
+
+ $md5Plugin = new Md5ValidatorPlugin();
+
+ // Add the md5 plugin to the client object
+ $client->addSubscriber($md5Plugin);
+
+ $request = $client->get('http://www.yahoo.com/');
+ $request->send();
+
+Calculating the MD5 hash of a large entity body or an entity body that was transferred using a Content-Encoding is an
+expensive operation. When working in high performance applications, you might consider skipping the MD5 hash
+validation for entity bodies bigger than a certain size or Content-Encoded entity bodies
+(see ``Guzzle\Plugin\Md5\Md5ValidatorPlugin`` for more information).
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst
new file mode 100755
index 0000000..4900cb5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/mock-plugin.rst
@@ -0,0 +1,27 @@
+===========
+Mock plugin
+===========
+
+The mock plugin is useful for testing Guzzle clients. The mock plugin allows you to queue an array of responses that
+will satisfy requests sent from a client by consuming the request queue in FIFO order.
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\Mock\MockPlugin;
+ use Guzzle\Http\Message\Response;
+
+ $client = new Client('http://www.test.com/');
+
+ $mock = new MockPlugin();
+ $mock->addResponse(new Response(200))
+ ->addResponse(new Response(404));
+
+ // Add the mock plugin to the client object
+ $client->addSubscriber($mock);
+
+ // The following request will receive a 200 response from the plugin
+ $client->get('http://www.example.com/')->send();
+
+ // The following request will receive a 404 response from the plugin
+ $client->get('http://www.test.com/')->send();
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst
new file mode 100755
index 0000000..e67eaba
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/oauth-plugin.rst
@@ -0,0 +1,30 @@
+============
+OAuth plugin
+============
+
+Guzzle ships with an OAuth 1.0 plugin that can sign requests using a consumer key, consumer secret, OAuth token,
+and OAuth secret. Here's an example showing how to send an authenticated request to the Twitter REST API:
+
+.. code-block:: php
+
+ use Guzzle\Http\Client;
+ use Guzzle\Plugin\Oauth\OauthPlugin;
+
+ $client = new Client('http://api.twitter.com/1');
+ $oauth = new OauthPlugin(array(
+ 'consumer_key' => 'my_key',
+ 'consumer_secret' => 'my_secret',
+ 'token' => 'my_token',
+ 'token_secret' => 'my_token_secret'
+ ));
+ $client->addSubscriber($oauth);
+
+ $response = $client->get('statuses/public_timeline.json')->send();
+
+If you need to use a custom signing method, you can pass a ``signature_method`` configuration option in the
+constructor of the OAuth plugin. The ``signature_method`` option must be a callable variable that accepts a string to
+sign and signing key and returns a signed string.
+
+.. note::
+
+ You can omit the ``token`` and ``token_secret`` options to use two-legged OAuth.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc
new file mode 100755
index 0000000..8d6d09b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/plugins-list.rst.inc
@@ -0,0 +1,9 @@
+* :doc:`/plugins/async-plugin`
+* :doc:`/plugins/backoff-plugin`
+* :doc:`/plugins/cache-plugin`
+* :doc:`/plugins/cookie-plugin`
+* :doc:`/plugins/history-plugin`
+* :doc:`/plugins/log-plugin`
+* :doc:`/plugins/md5-validator-plugin`
+* :doc:`/plugins/mock-plugin`
+* :doc:`/plugins/oauth-plugin`
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst
new file mode 100755
index 0000000..19ae57e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/plugins/plugins-overview.rst
@@ -0,0 +1,59 @@
+======================
+Plugin system overview
+======================
+
+The workflow of sending a request and parsing a response is driven by Guzzle's event system, which is powered by the
+`Symfony2 Event Dispatcher component `_.
+
+Any object in Guzzle that emits events will implement the ``Guzzle\Common\HasEventDispatcher`` interface. You can add
+event subscribers directly to these objects using the ``addSubscriber()`` method, or you can grab the
+``Symfony\Component\EventDispatcher\EventDispatcher`` object owned by the object using ``getEventDispatcher()`` and
+add a listener or event subscriber.
+
+Adding event subscribers to clients
+-----------------------------------
+
+Any event subscriber or event listener attached to the EventDispatcher of a ``Guzzle\Http\Client`` or
+``Guzzle\Service\Client`` object will automatically be attached to all request objects created by the client. This
+allows you to attach, for example, a HistoryPlugin to a client object, and from that point on, every request sent
+through that client will utilize the HistoryPlugin.
+
+.. code-block:: php
+
+ use Guzzle\Plugin\History\HistoryPlugin;
+ use Guzzle\Service\Client;
+
+ $client = new Client();
+
+ // Create a history plugin and attach it to the client
+ $history = new HistoryPlugin();
+ $client->addSubscriber($history);
+
+ // Create and send a request. This request will also utilize the HistoryPlugin
+ $client->get('http://httpbin.org')->send();
+
+ // Echo out the last sent request by the client
+ echo $history->getLastRequest();
+
+.. tip::
+
+ :doc:`Create event subscribers `, or *plugins*, to implement reusable logic that can be
+ shared across clients. Event subscribers are also easier to test than anonymous functions.
+
+Pre-Built plugins
+-----------------
+
+Guzzle provides easy to use request plugins that add behavior to requests based on signal slot event notifications
+powered by the Symfony2 Event Dispatcher component.
+
+* :doc:`async-plugin`
+* :doc:`backoff-plugin`
+* :doc:`cache-plugin`
+* :doc:`cookie-plugin`
+* :doc:`curl-auth-plugin`
+* :doc:`history-plugin`
+* :doc:`log-plugin`
+* :doc:`md5-validator-plugin`
+* :doc:`mock-plugin`
+* :doc:`oauth-plugin`
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/requirements.txt b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/requirements.txt
new file mode 100755
index 0000000..f62e318
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/requirements.txt
@@ -0,0 +1,2 @@
+Sphinx>=1.2b1
+guzzle_sphinx_theme>=0.5.0
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/testing/unit-testing.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/testing/unit-testing.rst
new file mode 100755
index 0000000..f4297af
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/testing/unit-testing.rst
@@ -0,0 +1,201 @@
+===========================
+Unit Testing Guzzle clients
+===========================
+
+Guzzle provides several tools that will enable you to easily unit test your web service clients.
+
+* PHPUnit integration
+* Mock responses
+* node.js web server for integration testing
+
+PHPUnit integration
+-------------------
+
+Guzzle is unit tested using `PHPUnit `_. Your web service client's unit tests should extend
+``Guzzle\Tests\GuzzleTestCase`` so that you can take advantage of some of the built in helpers.
+
+In order to unit test your client, a developer would need to copy phpunit.xml.dist to phpunit.xml and make any needed
+modifications. As a best practice and security measure for you and your contributors, it is recommended to add an
+ignore statement to your SCM so that phpunit.xml is ignored.
+
+Bootstrapping
+~~~~~~~~~~~~~
+
+Your web service client should have a tests/ folder that contains a bootstrap.php file. The bootstrap.php file
+responsible for autoloading and configuring a ``Guzzle\Service\Builder\ServiceBuilder`` that is used throughout your
+unit tests for loading a configured client. You can add custom parameters to your phpunit.xml file that expects users
+to provide the path to their configuration data.
+
+.. code-block:: php
+
+ Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Aws\Common\Aws::factory($_SERVER['CONFIG']));
+
+ Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Guzzle\Service\Builder\ServiceBuilder::factory(array(
+ 'test.unfuddle' => array(
+ 'class' => 'Guzzle.Unfuddle.UnfuddleClient',
+ 'params' => array(
+ 'username' => 'test_user',
+ 'password' => '****',
+ 'subdomain' => 'test'
+ )
+ )
+ )));
+
+The above code registers a service builder that can be used throughout your unit tests. You would then be able to
+retrieve an instantiated and configured Unfuddle client by calling ``$this->getServiceBuilder()->get('test.unfuddle)``.
+The above code assumes that ``$_SERVER['CONFIG']`` contains the path to a file that stores service description
+configuration.
+
+Unit testing remote APIs
+------------------------
+
+Mock responses
+~~~~~~~~~~~~~~
+
+One of the benefits of unit testing is the ability to quickly determine if there are errors in your code. If your
+unit tests run slowly, then they become tedious and will likely be run less frequently. Guzzle's philosophy on unit
+testing web service clients is that no network access should be required to run the unit tests. This means that
+responses are served from mock responses or local servers. By adhering to this principle, tests will run much faster
+and will not require an external resource to be available. The problem with this approach is that your mock responses
+must first be gathered and then subsequently updated each time the remote API changes.
+
+Integration testing over the internet
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can perform integration testing with a web service over the internet by making calls directly to the service. If
+the web service you are requesting uses a complex signing algorithm or some other specific implementation, then you
+may want to include at least one actual network test that can be run specifically through the command line using
+`PHPUnit group annotations `_.
+
+@group internet annotation
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When creating tests that require an internet connection, it is recommended that you add ``@group internet`` annotations
+to your unit tests to specify which tests require network connectivity.
+
+You can then `run PHPUnit tests `_ that exclude the @internet
+group by running ``phpunit --exclude-group internet``.
+
+API credentials
+^^^^^^^^^^^^^^^
+
+If API credentials are required to run your integration tests, you must add ```` parameters to your
+phpunit.xml.dist file and extract these parameters in your bootstrap.php file.
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+ ./Tests
+
+
+
+
+You can then extract the ``server`` variables in your bootstrap.php file by grabbing them from the ``$_SERVER``
+superglobal: ``$apiUser = $_SERVER['API_USER'];``
+
+Further reading
+^^^^^^^^^^^^^^^
+
+A good discussion on the topic of testing remote APIs can be found in Sebastian Bergmann's
+`Real-World Solutions for Developing High-Quality PHP Frameworks and Applications `_.
+
+Queueing Mock responses
+-----------------------
+
+Mock responses can be used to test if requests are being generated correctly and responses and handled correctly by
+your client. Mock responses can be queued up for a client using the ``$this->setMockResponse($client, $path)`` method
+of your test class. Pass the client you are adding mock responses to and a single path or array of paths to mock
+response files relative to the ``/tests/mock/ folder``. This will queue one or more mock responses for your client by
+creating a simple observer on the client. Mock response files must contain a full HTTP response message:
+
+.. code-block:: none
+
+ HTTP/1.1 200 OK
+ Date: Wed, 25 Nov 2009 12:00:00 GMT
+ Connection: close
+ Server: AmazonS3
+ Content-Type: application/xml
+
+
+ EU
+
+After queuing mock responses for a client, you can get an array of the requests that were sent by the client that
+were issued a mock response by calling ``$this->getMockedRequests()``.
+
+You can also use the ``Guzzle\Plugin\Mock\MockPlugin`` object directly with your clients.
+
+.. code-block:: php
+
+ $plugin = new Guzzle\Plugin\Mock\MockPlugin();
+ $plugin->addResponse(new Guzzle\Http\Message\Response(200));
+ $client = new Guzzle\Http\Client();
+ $client->addSubscriber($plugin);
+
+ // The following request will get the mock response from the plugin in FIFO order
+ $request = $client->get('http://www.test.com/');
+ $request->send();
+
+ // The MockPlugin maintains a list of requests that were mocked
+ $this->assertContainsOnly($request, $plugin->getReceivedRequests());
+
+node.js web server for integration testing
+------------------------------------------
+
+Using mock responses is usually enough when testing a web service client. If your client needs to add custom cURL
+options to requests, then you should use the node.js test web server to ensure that your HTTP request message is
+being created correctly.
+
+Guzzle is based around PHP's libcurl bindings. cURL sometimes modifies an HTTP request message based on
+``CURLOPT_*`` options. Headers that are added to your request by cURL will not be accounted for if you inject mock
+responses into your tests. Additionally, some request entity bodies cannot be loaded by the client before transmitting
+it to the sever (for example, when using a client as a sort of proxy and streaming content from a remote server). You
+might also need to inspect the entity body of a ``multipart/form-data`` POST request.
+
+.. note::
+
+ You can skip all of the tests that require the node.js test web server by excluding the ``server`` group:
+ ``phpunit --exclude-group server``
+
+Using the test server
+~~~~~~~~~~~~~~~~~~~~~
+
+The node.js test server receives requests and returns queued responses. The test server exposes a simple API that is
+used to enqueue responses and inspect the requests that it has received.
+
+Retrieve the server object by calling ``$this->getServer()``. If the node.js server is not running, it will be
+started as a forked process and an object that interfaces with the server will be returned. (note: stopping the
+server is handled internally by Guzzle.)
+
+You can queue an HTTP response or an array of responses by calling ``$this->getServer()->enqueue()``:
+
+.. code-block:: php
+
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+
+The above code queues a single 200 response with an empty body. Responses are queued using a FIFO order; this
+response will be returned by the server when it receives the first request and then removed from the queue. If a
+request is received by a server with no queued responses, an exception will be thrown in your unit test.
+
+You can inspect the requests that the server has retrieved by calling ``$this->getServer()->getReceivedRequests()``.
+This method accepts an optional ``$hydrate`` parameter that specifies if you are retrieving an array of string HTTP
+requests or an array of ``Guzzle\Http\RequestInterface`` subclassed objects. "Hydrating" the requests will allow
+greater flexibility in your unit tests so that you can easily assert the state of the various parts of a request.
+
+You will need to modify the base_url of your web service client in order to use it against the test server.
+
+.. code-block:: php
+
+ $client = $this->getServiceBuilder()->get('my_client');
+ $client->setBaseUrl($this->getServer()->getUrl());
+
+After running the above code, all calls made from the ``$client`` object will be sent to the test web server.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst
new file mode 100755
index 0000000..ad6070b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/guzzle-service-descriptions.rst
@@ -0,0 +1,619 @@
+===========================
+Guzzle service descriptions
+===========================
+
+Guzzle allows you to serialize HTTP requests and parse HTTP responses using a DSL called a service descriptions.
+Service descriptions define web service APIs by documenting each operation, the operation's parameters, validation
+options for each parameter, an operation's response, how the response is parsed, and any errors that can be raised for
+an operation. Writing a service description for a web service allows you to more quickly consume a web service than
+writing concrete commands for each web service operation.
+
+Guzzle service descriptions can be representing using a PHP array or JSON document. Guzzle's service descriptions are
+heavily inspired by `Swagger `_.
+
+Service description schema
+==========================
+
+A Guzzle Service description must match the following JSON schema document. This document can also serve as a guide when
+implementing a Guzzle service description.
+
+Download the schema here: :download:`Guzzle JSON schema document `
+
+.. class:: overflow-height-500px
+
+ .. literalinclude:: ../_downloads/guzzle-schema-1.0.json
+ :language: json
+
+Top-level attributes
+--------------------
+
+Service descriptions are comprised of the following top-level attributes:
+
+.. code-block:: json
+
+ {
+ "name": "string",
+ "apiVersion": "string|number",
+ "baseUrl": "string",
+ "description": "string",
+ "operations": {},
+ "models": {},
+ "includes": ["string.php", "string.json"]
+ }
+
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| Property Name | Value | Description |
++=========================================+=========================+=======================================================================================================================+
+| name | string | Name of the web service |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| apiVersion | string|number | Version identifier that the service description is compatible with |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| baseUrl or basePath | string | Base URL of the web service. Any relative URI specified in an operation will be merged with the baseUrl using the |
+| | | process defined in RFC 2396. Some clients require custom logic to determine the baseUrl. In those cases, it is best |
+| | | to not include a baseUrl in the service description, but rather allow the factory method of the client to configure |
+| | | the client’s baseUrl. |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| description | string | Short summary of the web service |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| operations | object containing | Operations of the service. The key is the name of the operation and value is the attributes of the operation. |
+| | :ref:`operation-schema` | |
+| | | |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| models | object containing | Schema models that can be referenced throughout the service description. Models can be used to define how an HTTP |
+| | :ref:`model-schema` | response is parsed into a ``Guzzle\Service\Resource\Model`` object when an operation uses a ``model`` ``responseType``|
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| includes | array of .js, | Service description files to include and extend from (can be a .json, .js, or .php file) |
+| | .json, or .php | |
+| | files. | |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+| (any additional properties) | mixed | Any additional properties specified as top-level attributes are allowed and will be treated as arbitrary data |
++-----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------------------------------+
+
+.. _operation-schema:
+
+Operations
+----------
+
+Operations are the actions that can be taken on a service. Each operation is given a unique name and has a distinct
+endpoint and HTTP method. If an API has a ``DELETE /users/:id`` operation, a satisfactory operation name might be
+``DeleteUser`` with a parameter of ``id`` that is inserted into the URI.
+
+.. class:: overflow-height-250px
+
+ .. code-block:: json
+
+ {
+ "operations": {
+ "operationName": {
+ "extends": "string",
+ "httpMethod": "GET|POST|PUT|DELETE|PATCH|string",
+ "uri": "string",
+ "summary": "string",
+ "class": "string",
+ "responseClass": "string",
+ "responseNotes": "string",
+ "type": "string",
+ "description": "string",
+ "responseType": "primitive|class|(model by name)|documentation|(string)",
+ "deprecated": false,
+ "errorResponses": [
+ {
+ "code": 500,
+ "reason": "Unexpected Error",
+ "class": "string"
+ }
+ ],
+ "data": {
+ "foo": "bar",
+ "baz": "bam"
+ },
+ "parameters": {}
+ }
+ }
+ }
+
+.. csv-table::
+ :header: "Property Name", "Value", "Description"
+ :widths: 20, 15, 65
+
+ "extends", "string", "Extend from another operation by name. The parent operation must be defined before the child."
+ "httpMethod", "string", "HTTP method used with the operation (e.g. GET, POST, PUT, DELETE, PATCH, etc)"
+ "uri", "string", "URI of the operation. The uri attribute can contain URI templates. The variables of the URI template are parameters of the operation with a location value of uri"
+ "summary", "string", "Short summary of what the operation does"
+ "class", "string", "Custom class to instantiate instead of the default Guzzle\\Service\\Command\\OperationCommand. Using this attribute allows you to define an operation using a service description, but allows more customized logic to be implemented in user-land code."
+ "responseClass", "string", "Defined what is returned from the method. Can be a primitive, class name, or model name. You can specify the name of a class to return a more customized result from the operation (for example, a domain model object). When using the name of a PHP class, the class must implement ``Guzzle\Service\Command\ResponseClassInterface``."
+ "responseNotes", "string", "A description of the response returned by the operation"
+ "responseType", "string", "The type of response that the operation creates: one of primitive, class, model, or documentation. If not specified, this value will be automatically inferred based on whether or not there is a model matching the name, if a matching class name is found, or set to 'primitive' by default."
+ "deprecated", "boolean", "Whether or not the operation is deprecated"
+ "errorResponses", "array", "Errors that could occur while executing the operation. Each item of the array is an object that can contain a 'code' (HTTP response status code of the error), 'reason' (reason phrase or description of the error), and 'class' (an exception class that will be raised when this error is encountered)"
+ "data", "object", "Any arbitrary data to associate with the operation"
+ "parameters", "object containing :ref:`parameter-schema` objects", "Parameters of the operation. Parameters are used to define how input data is serialized into a HTTP request."
+ "additionalParameters", "A single :ref:`parameter-schema` object", "Validation and serialization rules for any parameter supplied to the operation that was not explicitly defined."
+
+additionalParameters
+~~~~~~~~~~~~~~~~~~~~
+
+When a webservice offers a large number of parameters that all are set in the same location (for example the query
+string or a JSON document), defining each parameter individually can require a lot of time and repetition. Furthermore,
+some web services allow for completely arbitrary parameters to be supplied for an operation. The
+``additionalParameters`` attribute can be used to solve both of these issues.
+
+As an example, we can define a Twitter API operation quite easily using ``additionalParameters``. The
+GetMentions operation accepts a large number of query string parameters. Defining each of these parameters
+is ideal because it provide much more introspection for the client and opens the possibility to use the description with
+other tools (e.g. a documentation generator). However, you can very quickly provide a "catch-all" serialization rule
+that will place any custom parameters supplied to an operation the generated request's query string parameters.
+
+.. class:: overflow-height-250px
+
+ .. code-block:: json
+
+ {
+ "name": "Twitter",
+ "apiVersion": "1.1",
+ "baseUrl": "https://api.twitter.com/1.1",
+ "operations": {
+ "GetMentions": {
+ "httpMethod": "GET",
+ "uri": "statuses/mentions_timeline.json",
+ "responseClass": "GetMentionsOutput",
+ "additionalParameters": {
+ "location": "query"
+ }
+ }
+ },
+ "models": {
+ "GetMentionsOutput": {
+ "type": "object",
+ "additionalProperties": {
+ "location": "json"
+ }
+ }
+ }
+ }
+
+responseClass
+~~~~~~~~~~~~~
+
+The ``responseClass`` attribute is used to define the return value of an operation (what is returned by calling the
+``getResult()`` method of a command object). The value set in the responseClass attribute can be one of "primitive"
+(meaning the result with be primitive type like a string), a class name meaning the result will be an instance of a
+specific user-land class, or a model name meaning the result will be a ``Guzzle\Service\Resource\Model`` object that
+uses a :ref:`model schema ` to define how the HTTP response is parsed.
+
+.. note::
+
+ Using a class name with a ``responseClass`` will only work if it is supported by the ``class`` that is instantiated
+ for the operation. Keep this in mind when specifying a custom ``class`` attribute that points to a custom
+ ``Guzzle\Service\Command\CommandInterface`` class. The default ``class``,
+ ``Guzzle\Service\Command\OperationCommand``, does support setting custom ``class`` attributes.
+
+You can specify the name of a class to return a more customized result from the operation (for example, a domain model
+object). When using the name of a PHP class, the class must implement ``Guzzle\Service\Command\ResponseClassInterface``.
+Here's a very simple example of implementing a custom responseClass object.
+
+.. code-block:: json
+
+ {
+ "operations": {
+ "test": {
+ "responseClass": "MyApplication\\User"
+ }
+ }
+ }
+
+.. code-block:: php
+
+ namespace MyApplication;
+
+ use Guzzle\Service\Command\ResponseClassInterface;
+ use Guzzle\Service\Command\OperationCommand;
+
+ class User implements ResponseClassInterface
+ {
+ protected $name;
+
+ public static function fromCommand(OperationCommand $command)
+ {
+ $response = $command->getResponse();
+ $xml = $response->xml();
+
+ return new self((string) $xml->name);
+ }
+
+ public function __construct($name)
+ {
+ $this->name = $name;
+ }
+ }
+
+errorResponses
+~~~~~~~~~~~~~~
+
+``errorResponses`` is an array containing objects that define the errors that could occur while executing the
+operation. Each item of the array is an object that can contain a 'code' (HTTP response status code of the error),
+'reason' (reason phrase or description of the error), and 'class' (an exception class that will be raised when this
+error is encountered).
+
+ErrorResponsePlugin
+^^^^^^^^^^^^^^^^^^^
+
+Error responses are by default only used for documentation. If you don't need very complex exception logic for your web
+service errors, then you can use the ``Guzzle\Plugin\ErrorResponse\ErrorResponsePlugin`` to automatically throw defined
+exceptions when one of the ``errorResponse`` rules are matched. The error response plugin will listen for the
+``request.complete`` event of a request created by a command object. Every response (including a successful response) is
+checked against the list of error responses for an exact match using the following order of checks:
+
+1. Does the errorResponse have a defined ``class``?
+2. Is the errorResponse ``code`` equal to the status code of the response?
+3. Is the errorResponse ``reason`` equal to the reason phrase of the response?
+4. Throw the exception stored in the ``class`` attribute of the errorResponse.
+
+The ``class`` attribute must point to a class that implements
+``Guzzle\Plugin\ErrorResponse\ErrorResponseExceptionInterface``. This interface requires that an error response class
+implements ``public static function fromCommand(CommandInterface $command, Response $response)``. This method must
+return an object that extends from ``\Exception``. After an exception is returned, it is thrown by the plugin.
+
+.. _parameter-schema:
+
+Parameter schema
+----------------
+
+Parameters in both operations and models are represented using the
+`JSON schema `_ syntax.
+
+.. csv-table::
+ :header: "Property Name", "Value", "Description"
+ :widths: 20, 15, 65
+
+ "name", "string", "Unique name of the parameter"
+ "type", "string|array", "Type of variable (string, number, integer, boolean, object, array, numeric, null, any). Types are using for validation and determining the structure of a parameter. You can use a union type by providing an array of simple types. If one of the union types matches the provided value, then the value is valid."
+ "instanceOf", "string", "When the type is an object, you can specify the class that the object must implement"
+ "required", "boolean", "Whether or not the parameter is required"
+ "default", "mixed", "Default value to use if no value is supplied"
+ "static", "boolean", "Set to true to specify that the parameter value cannot be changed from the default setting"
+ "description", "string", "Documentation of the parameter"
+ "location", "string", "The location of a request used to apply a parameter. Custom locations can be registered with a command, but the defaults are uri, query, statusCode, reasonPhrase, header, body, json, xml, postField, postFile, responseBody"
+ "sentAs", "string", "Specifies how the data being modeled is sent over the wire. For example, you may wish to include certain headers in a response model that have a normalized casing of FooBar, but the actual header is x-foo-bar. In this case, sentAs would be set to x-foo-bar."
+ "filters", "array", "Array of functions to to run a parameter value through."
+
+filters
+~~~~~~~
+
+Each value in the array must be a string containing the full class path to a static method or an array of complex
+filter information. You can specify static methods of classes using the full namespace class name followed by
+"::" (e.g. ``FooBar::baz()``). Some filters require arguments in order to properly filter a value. For complex filters,
+use an object containing a ``method`` attribute pointing to a function, and an ``args`` attribute containing an
+array of positional arguments to pass to the function. Arguments can contain keywords that are replaced when filtering
+a value: ``@value`` is replaced with the value being filtered, and ``@api`` is replaced with the actual Parameter
+object.
+
+.. code-block:: json
+
+ {
+ "filters": [
+ "strtolower",
+ {
+ "method": "MyClass::convertString",
+ "args": [ "test", "@value", "@api" ]
+ }
+ ]
+ }
+
+The above example will filter a parameter using ``strtolower``. It will then call the ``convertString`` static method
+of ``MyClass``, passing in "test", the actual value of the parameter, and a ``Guzzle\Service\Description\Parameter``
+object.
+
+Operation parameter location attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The location field of top-level parameters control how a parameter is serialized when generating a request.
+
+uri location
+^^^^^^^^^^^^
+
+Parameters are injected into the ``uri`` attribute of the operation using
+`URI-template expansion `_.
+
+.. code-block:: json
+
+ {
+ "operations": {
+ "uriTest": {
+ "uri": "/test/{testValue}",
+ "parameters": {
+ "testValue": {
+ "location": "uri"
+ }
+ }
+ }
+ }
+ }
+
+query location
+^^^^^^^^^^^^^^
+
+Parameters are injected into the query string of a request. Query values can be nested, which would result in a PHP
+style nested query string. The name of a parameter is the default name of the query string parameter added to the
+request. You can override this behavior by specifying the ``sentAs`` attribute on the parameter.
+
+.. code-block:: json
+
+ {
+ "operations": {
+ "queryTest": {
+ "parameters": {
+ "testValue": {
+ "location": "query",
+ "sentAs": "test_value"
+ }
+ }
+ }
+ }
+ }
+
+header location
+^^^^^^^^^^^^^^^
+
+Parameters are injected as headers on an HTTP request. The name of the parameter is used as the name of the header by
+default. You can change the name of the header created by the parameter using the ``sentAs`` attribute.
+
+Headers that are of type ``object`` will be added as multiple headers to a request using the key of the input array as
+the header key. Setting a ``sentAs`` attribute along with a type ``object`` will use the value of ``sentAs`` as a
+prefix for each header key.
+
+body location
+^^^^^^^^^^^^^
+
+Parameters are injected as the body of a request. The input of these parameters may be anything that can be cast to a
+string or a ``Guzzle\Http\EntityBodyInterface`` object.
+
+postField location
+^^^^^^^^^^^^^^^^^^
+
+Parameters are inserted as POST fields in a request. Nested values may be supplied and will be represented using
+PHP style nested query strings. The POST field name is the same as the parameter name by default. You can use the
+``sentAs`` parameter to override the POST field name.
+
+postFile location
+^^^^^^^^^^^^^^^^^
+
+Parameters are added as POST files. A postFile value may be a string pointing to a local filename or a
+``Guzzle\Http\Message\PostFileInterface`` object. The name of the POST file will be the name of the parameter by
+default. You can use a custom POST file name by using the ``sentAs`` attribute.
+
+Supports "string" and "array" types.
+
+json location
+^^^^^^^^^^^^^
+
+Parameters are added to the body of a request as top level keys of a JSON document. Nested values may be specified,
+with any number of nested ``Guzzle\Common\ToArrayInterface`` objects. When JSON parameters are specified, the
+``Content-Type`` of the request will change to ``application/json`` if a ``Content-Type`` has not already been specified
+on the request.
+
+xml location
+^^^^^^^^^^^^
+
+Parameters are added to the body of a request as top level nodes of an XML document. Nested values may be specified,
+with any number of nested ``Guzzle\Common\ToArrayInterface`` objects. When XML parameters are specified, the
+``Content-Type`` of the request will change to ``application/xml`` if a ``Content-Type`` has not already been specified
+on the request.
+
+responseBody location
+^^^^^^^^^^^^^^^^^^^^^
+
+Specifies the EntityBody of a response. This can be used to download the response body to a file or a custom Guzzle
+EntityBody object.
+
+No location
+^^^^^^^^^^^
+
+If a parameter has no location attribute, then the parameter is simply used as a data value.
+
+Other locations
+^^^^^^^^^^^^^^^
+
+Custom locations can be registered as new locations or override default locations if needed.
+
+.. _model-schema:
+
+Model Schema
+------------
+
+Models are used in service descriptions to provide generic JSON schema definitions that can be extended from or used in
+``$ref`` attributes. Models can also be referenced in a ``responseClass`` attribute to provide valuable output to an
+operation. Models are JSON schema documents and use the exact syntax and attributes used in parameters.
+
+Response Models
+~~~~~~~~~~~~~~~
+
+Response models describe how a response is parsed into a ``Guzzle\Service\Resource\Model`` object. Response models are
+always modeled as JSON schema objects. When an HTTP response is parsed using a response model, the rules specified on
+each property of a response model will translate 1:1 as keys in a PHP associative array. When a ``sentAs`` attribute is
+found in response model parameters, the value retrieved from the HTTP response is retrieved using the ``sentAs``
+parameter but stored in the response model using the name of the parameter.
+
+The location field of top-level parameters in a response model tell response parsers how data is retrieved from a
+response.
+
+statusCode location
+^^^^^^^^^^^^^^^^^^^
+
+Retrieves the status code of the response.
+
+reasonPhrase location
+^^^^^^^^^^^^^^^^^^^^^
+
+Retrieves the reason phrase of the response.
+
+header location
+^^^^^^^^^^^^^^^
+
+Retrieves a header from the HTTP response.
+
+body location
+^^^^^^^^^^^^^
+
+Retrieves the body of an HTTP response.
+
+json location
+^^^^^^^^^^^^^
+
+Retrieves a top-level parameter from a JSON document contained in an HTTP response.
+
+You can use ``additionalProperties`` if the JSON document is wrapped in an outer array. This allows you to parse the
+contents of each item in the array using the parsing rules defined in the ``additionalProperties`` schema.
+
+xml location
+^^^^^^^^^^^^
+
+Retrieves a top-level node value from an XML document contained in an HTTP response.
+
+Other locations
+^^^^^^^^^^^^^^^
+
+Custom locations can be registered as new locations or override default locations if needed.
+
+Example service description
+---------------------------
+
+Let's say you're interacting with a web service called 'Foo' that allows for the following routes and methods::
+
+ GET/POST /users
+ GET/DELETE /users/:id
+
+The following JSON service description implements this simple web service:
+
+.. class:: overflow-height-500px
+
+ .. code-block:: json
+
+ {
+ "name": "Foo",
+ "apiVersion": "2012-10-14",
+ "baseUrl": "http://api.foo.com",
+ "description": "Foo is an API that allows you to Baz Bar",
+ "operations": {
+ "GetUsers": {
+ "httpMethod": "GET",
+ "uri": "/users",
+ "summary": "Gets a list of users",
+ "responseClass": "GetUsersOutput"
+ },
+ "CreateUser": {
+ "httpMethod": "POST",
+ "uri": "/users",
+ "summary": "Creates a new user",
+ "responseClass": "CreateUserOutput",
+ "parameters": {
+ "name": {
+ "location": "json",
+ "type": "string"
+ },
+ "age": {
+ "location": "json",
+ "type": "integer"
+ }
+ }
+ },
+ "GetUser": {
+ "httpMethod": "GET",
+ "uri": "/users/{id}",
+ "summary": "Retrieves a single user",
+ "responseClass": "GetUserOutput",
+ "parameters": {
+ "id": {
+ "location": "uri",
+ "description": "User to retrieve by ID",
+ "required": true
+ }
+ }
+ },
+ "DeleteUser": {
+ "httpMethod": "DELETE",
+ "uri": "/users/{id}",
+ "summary": "Deletes a user",
+ "responseClass": "DeleteUserOutput",
+ "parameters": {
+ "id": {
+ "location": "uri",
+ "description": "User to delete by ID",
+ "required": true
+ }
+ }
+ }
+ },
+ "models": {
+ "GetUsersOutput": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "location": "json",
+ "type": "string"
+ },
+ "age": {
+ "location": "json",
+ "type": "integer"
+ }
+ }
+ }
+ },
+ "CreateUserOutput": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "location": "json",
+ "type": "string"
+ },
+ "location": {
+ "location": "header",
+ "sentAs": "Location",
+ "type": "string"
+ }
+ }
+ },
+ "GetUserOutput": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "location": "json",
+ "type": "string"
+ },
+ "age": {
+ "location": "json",
+ "type": "integer"
+ }
+ }
+ },
+ "DeleteUserOutput": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "location": "statusCode",
+ "type": "integer"
+ }
+ }
+ }
+ }
+ }
+
+If you attach this service description to a client, you would completely configure the client to interact with the
+Foo web service and provide valuable response models for each operation.
+
+.. code-block:: php
+
+ use Guzzle\Service\Description\ServiceDescription;
+
+ $description = ServiceDescription::factory('/path/to/client.json');
+ $client->setDescription($description);
+
+ $command = $client->getCommand('DeleteUser', array('id' => 123));
+ $responseModel = $client->execute($command);
+ echo $responseModel['status'];
+
+.. note::
+
+ You can add the service description to your client's factory method or constructor.
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst
new file mode 100755
index 0000000..b7113d6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/using-the-service-builder.rst
@@ -0,0 +1,316 @@
+=======================
+Using a service builder
+=======================
+
+The best way to instantiate Guzzle web service clients is to let Guzzle handle building the clients for you using a
+ServiceBuilder. A ServiceBuilder is responsible for creating concrete client objects based on configuration settings
+and helps to manage credentials for different environments.
+
+You don't have to use a service builder, but they help to decouple your application from concrete classes and help to
+share configuration data across multiple clients. Consider the following example. Here we are creating two clients that
+require the same API public key and secret key. The clients are created using their ``factory()`` methods.
+
+.. code-block:: php
+
+ use MyService\FooClient;
+ use MyService\BarClient;
+
+ $foo = FooClient::factory(array(
+ 'key' => 'abc',
+ 'secret' => '123',
+ 'custom' => 'and above all'
+ ));
+
+ $bar = BarClient::factory(array(
+ 'key' => 'abc',
+ 'secret' => '123',
+ 'custom' => 'listen to me'
+ ));
+
+The redundant specification of the API keys can be removed using a service builder.
+
+.. code-block:: php
+
+ use Guzzle\Service\Builder\ServiceBuilder;
+
+ $builder = ServiceBuilder::factory(array(
+ 'services' => array(
+ 'abstract_client' => array(
+ 'params' => array(
+ 'key' => 'abc',
+ 'secret' => '123'
+ )
+ ),
+ 'foo' => array(
+ 'extends' => 'abstract_client',
+ 'class' => 'MyService\FooClient',
+ 'params' => array(
+ 'custom' => 'and above all'
+ )
+ ),
+ 'bar' => array(
+ 'extends' => 'abstract_client',
+ 'class' => 'MyService\FooClient',
+ 'params' => array(
+ 'custom' => 'listen to me'
+ )
+ )
+ )
+ ));
+
+ $foo = $builder->get('foo');
+ $bar = $builder->get('bar');
+
+You can make managing your API keys even easier by saving the service builder configuration in a JSON format in a
+.json file.
+
+Creating a service builder
+--------------------------
+
+A ServiceBuilder can source information from an array, an PHP include file that returns an array, or a JSON file.
+
+.. code-block:: php
+
+ use Guzzle\Service\Builder\ServiceBuilder;
+
+ // Source service definitions from a JSON file
+ $builder = ServiceBuilder::factory('services.json');
+
+Sourcing data from an array
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Data can be source from a PHP array. The array must contain an associative ``services`` array that maps the name of a
+client to the configuration information used by the service builder to create the client. Clients are given names
+which are used to identify how a client is retrieved from a service builder. This can be useful for using multiple
+accounts for the same service or creating development clients vs. production clients.
+
+.. code-block:: php
+
+ $services = array(
+ 'includes' => array(
+ '/path/to/other/services.json',
+ '/path/to/other/php_services.php'
+ ),
+ 'services' => array(
+ 'abstract.foo' => array(
+ 'params' => array(
+ 'username' => 'foo',
+ 'password' => 'bar'
+ )
+ ),
+ 'bar' => array(
+ 'extends' => 'abstract.foo',
+ 'class' => 'MyClientClass',
+ 'params' => array(
+ 'other' => 'abc'
+ )
+ )
+ )
+ );
+
+A service builder configuration array contains two top-level array keys:
+
++------------+---------------------------------------------------------------------------------------------------------+
+| Key | Description |
++============+=========================================================================================================+
+| includes | Array of paths to JSON or PHP include files to include in the configuration. |
++------------+---------------------------------------------------------------------------------------------------------+
+| services | Associative array of defined services that can be created by the service builder. Each service can |
+| | contain the following keys: |
+| | |
+| | +------------+----------------------------------------------------------------------------------------+ |
+| | | Key | Description | |
+| | +============+========================================================================================+ |
+| | | class | The concrete class to instantiate that implements the | |
+| | | | ``Guzzle\Common\FromConfigInterface``. | |
+| | +------------+----------------------------------------------------------------------------------------+ |
+| | | extends | The name of a previously defined service to extend from | |
+| | +------------+----------------------------------------------------------------------------------------+ |
+| | | params | Associative array of parameters to pass to the factory method of the service it is | |
+| | | | instantiated | |
+| | +------------+----------------------------------------------------------------------------------------+ |
+| | | alias | An alias that can be used in addition to the array key for retrieving a client from | |
+| | | | the service builder. | |
+| | +------------+----------------------------------------------------------------------------------------+ |
++------------+---------------------------------------------------------------------------------------------------------+
+
+The first client defined, ``abstract.foo``, is used as a placeholder of shared configuration values. Any service
+extending abstract.foo will inherit its params. As an example, this can be useful when clients share the same username
+and password.
+
+The next client, ``bar``, extends from ``abstract.foo`` using the ``extends`` attribute referencing the client from
+which to extend. Additional parameters can be merged into the original service definition when extending a parent
+service.
+
+.. important::
+
+ Each client that you intend to instantiate must specify a ``class`` attribute that references the full class name
+ of the client being created. The class referenced in the ``class`` parameter must implement a static ``factory()``
+ method that accepts an array or ``Guzzle\Common\Collection`` object and returns an instantiated object.
+
+Sourcing from a PHP include
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can create service builder configurations using a PHP include file. This can be useful if you wish to take
+advantage of an opcode cache like APC to speed up the process of loading and processing the configuration. The PHP
+include file is the same format as an array, but you simply create a PHP script that returns an array and save the
+file with the .php file extension.
+
+.. code-block:: php
+
+ '...');
+ // Saved as config.php
+
+This configuration file can then be used with a service builder.
+
+.. code-block:: php
+
+ $builder = ServiceBuilder::factory('/path/to/config.php');
+
+Sourcing from a JSON document
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can use JSON documents to serialize your service descriptions. The JSON format uses the exact same structure as
+the PHP array syntax, but it's just serialized using JSON.
+
+.. code-block:: javascript
+
+ {
+ "includes": ["/path/to/other/services.json", "/path/to/other/php_services.php"],
+ "services": {
+ "abstract.foo": {
+ "params": {
+ "username": "foo",
+ "password": "bar"
+ }
+ },
+ "bar": {
+ "extends": "abstract.foo",
+ "class": "MyClientClass",
+ "params": {
+ "other": "abc"
+ }
+ }
+ }
+ }
+
+Referencing other clients in parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If one of your clients depends on another client as one of its parameters, you can reference that client by name by
+enclosing the client's reference key in ``{}``.
+
+.. code-block:: javascript
+
+ {
+ "services": {
+ "token": {
+ "class": "My\Token\TokenFactory",
+ "params": {
+ "access_key": "xyz"
+ }
+ },
+ "client": {
+ "class": "My\Client",
+ "params": {
+ "token_client": "{token}",
+ "version": "1.0"
+ }
+ }
+ }
+ }
+
+When ``client`` is constructed by the service builder, the service builder will first create the ``token`` service
+and then inject the token service into ``client``'s factory method in the ``token_client`` parameter.
+
+Retrieving clients from a service builder
+-----------------------------------------
+
+Clients are referenced using a customizable name you provide in your service definition. The ServiceBuilder is a sort
+of multiton object-- it will only instantiate a client once and return that client for subsequent retrievals. Clients
+are retrieved by name (the array key used in the configuration) or by the ``alias`` setting of a service.
+
+Here's an example of retrieving a client from your ServiceBuilder:
+
+.. code-block:: php
+
+ $client = $builder->get('foo');
+
+ // You can also use the ServiceBuilder object as an array
+ $client = $builder['foo'];
+
+Creating throwaway clients
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can get a "throwaway" client (a client that is not persisted by the ServiceBuilder) by passing ``true`` in the
+second argument of ``ServiceBuilder::get()``. This allows you to create a client that will not be returned by other
+parts of your code that use the service builder. Instead of passing ``true``, you can pass an array of configuration
+settings that will override the configuration settings specified in the service builder.
+
+.. code-block:: php
+
+ // Get a throwaway client and overwrite the "custom" setting of the client
+ $foo = $builder->get('foo', array(
+ 'custom' => 'in this world there are rules'
+ ));
+
+Getting raw configuration settings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can get the raw configuration settings provided to the service builder for a specific service using the
+``getData($name)`` method of a service builder. This method will null if the service was not found in the service
+builder or an array of configuration settings if the service was found.
+
+.. code-block:: php
+
+ $data = $builder->getData('foo');
+ echo $data['key'] . "\n";
+ echo $data['secret'] . "\n";
+ echo $data['custom'] . "\n";
+
+Adding a plugin to all clients
+------------------------------
+
+You can add a plugin to all clients created by a service builder using the ``addGlobalPlugin($plugin)`` method of a
+service builder and passing a ``Symfony\Component\EventDispatcher\EventSubscriberInterface`` object. The service builder
+will then attach each global plugin to every client as it is created. This allows you to, for example, add a LogPlugin
+to every request created by a service builder for easy debugging.
+
+.. code-block:: php
+
+ use Guzzle\Plugin\Log\LogPlugin;
+
+ // Add a debug log plugin to every client as it is created
+ $builder->addGlobalPlugin(LogPlugin::getDebugPlugin());
+
+ $foo = $builder->get('foo');
+ $foo->get('/')->send();
+ // Should output all of the data sent over the wire
+
+.. _service-builder-events:
+
+Events emitted from a service builder
+-------------------------------------
+
+A ``Guzzle\Service\Builder\ServiceBuilder`` object emits the following events:
+
++-------------------------------+--------------------------------------------+-----------------------------------------+
+| Event name | Description | Event data |
++===============================+============================================+=========================================+
+| service_builder.create_client | Called when a client is created | * client: The created client object |
++-------------------------------+--------------------------------------------+-----------------------------------------+
+
+.. code-block:: php
+
+ use Guzzle\Common\Event;
+ use Guzzle\Service\Builder\ServiceBuilder;
+
+ $builder = ServiceBuilder::factory('/path/to/config.json');
+
+ // Add an event listener to print out each client client as it is created
+ $builder->getEventDispatcher()->addListener('service_builder.create_client', function (Event $e) {
+ echo 'Client created: ' . get_class($e['client']) . "\n";
+ });
+
+ $foo = $builder->get('foo');
+ // Should output the class used for the "foo" client
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst
new file mode 100755
index 0000000..7ec771e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/docs/webservice-client/webservice-client.rst
@@ -0,0 +1,659 @@
+======================
+The web service client
+======================
+
+The ``Guzzle\Service`` namespace contains various abstractions that help to make it easier to interact with a web
+service API, including commands, service descriptions, and resource iterators.
+
+In this chapter, we'll build a simple `Twitter API client `_.
+
+Creating a client
+=================
+
+A class that extends from ``Guzzle\Service\Client`` or implements ``Guzzle\Service\ClientInterface`` must implement a
+``factory()`` method in order to be used with a :doc:`service builder `.
+
+Factory method
+--------------
+
+You can use the ``factory()`` method of a client directly if you do not need a service builder.
+
+.. code-block:: php
+
+ use mtdowling\TwitterClient;
+
+ // Create a client and pass an array of configuration data
+ $twitter = TwitterClient::factory(array(
+ 'consumer_key' => '****',
+ 'consumer_secret' => '****',
+ 'token' => '****',
+ 'token_secret' => '****'
+ ));
+
+.. note::
+
+ If you'd like to follow along, here's how to get your Twitter API credentials:
+
+ 1. Visit https://dev.twitter.com/apps
+ 2. Click on an application that you've created
+ 3. Click on the "OAuth tool" tab
+ 4. Copy all of the settings under "OAuth Settings"
+
+Implementing a factory method
+-----------------------------
+
+Creating a client and its factory method is pretty simple. You just need to implement ``Guzzle\Service\ClientInterface``
+or extend from ``Guzzle\Service\Client``.
+
+.. code-block:: php
+
+ namespace mtdowling;
+
+ use Guzzle\Common\Collection;
+ use Guzzle\Plugin\Oauth\OauthPlugin;
+ use Guzzle\Service\Client;
+ use Guzzle\Service\Description\ServiceDescription;
+
+ /**
+ * A simple Twitter API client
+ */
+ class TwitterClient extends Client
+ {
+ public static function factory($config = array())
+ {
+ // Provide a hash of default client configuration options
+ $default = array('base_url' => 'https://api.twitter.com/1.1');
+
+ // The following values are required when creating the client
+ $required = array(
+ 'base_url',
+ 'consumer_key',
+ 'consumer_secret',
+ 'token',
+ 'token_secret'
+ );
+
+ // Merge in default settings and validate the config
+ $config = Collection::fromConfig($config, $default, $required);
+
+ // Create a new Twitter client
+ $client = new self($config->get('base_url'), $config);
+
+ // Ensure that the OauthPlugin is attached to the client
+ $client->addSubscriber(new OauthPlugin($config->toArray()));
+
+ return $client;
+ }
+ }
+
+Service Builder
+---------------
+
+A service builder is used to easily create web service clients, provides a simple configuration driven approach to
+creating clients, and allows you to share configuration settings across multiple clients. You can find out more about
+Guzzle's service builder in :doc:`using-the-service-builder`.
+
+.. code-block:: php
+
+ use Guzzle\Service\Builder\ServiceBuilder;
+
+ // Create a service builder and provide client configuration data
+ $builder = ServiceBuilder::factory('/path/to/client_config.json');
+
+ // Get the client from the service builder by name
+ $twitter = $builder->get('twitter');
+
+The above example assumes you have JSON data similar to the following stored in "/path/to/client_config.json":
+
+.. code-block:: json
+
+ {
+ "services": {
+ "twitter": {
+ "class": "mtdowling\\TwitterClient",
+ "params": {
+ "consumer_key": "****",
+ "consumer_secret": "****",
+ "token": "****",
+ "token_secret": "****"
+ }
+ }
+ }
+ }
+
+.. note::
+
+ A service builder becomes much more valuable when using multiple web service clients in a single application or
+ if you need to utilize the same client with varying configuration settings (e.g. multiple accounts).
+
+Commands
+========
+
+Commands are a concept in Guzzle that helps to hide the underlying implementation of an API by providing an easy to use
+parameter driven object for each action of an API. A command is responsible for accepting an array of configuration
+parameters, serializing an HTTP request, and parsing an HTTP response. Following the
+`command pattern `_, commands in Guzzle offer a greater level of
+flexibility when implementing and utilizing a web service client.
+
+Executing commands
+------------------
+
+You must explicitly execute a command after creating a command using the ``getCommand()`` method. A command has an
+``execute()`` method that may be called, or you can use the ``execute()`` method of a client object and pass in the
+command object. Calling either of these execute methods will return the result value of the command. The result value is
+the result of parsing the HTTP response with the ``process()`` method.
+
+.. code-block:: php
+
+ // Get a command from the client and pass an array of parameters
+ $command = $twitter->getCommand('getMentions', array(
+ 'count' => 5
+ ));
+
+ // Other parameters can be set on the command after it is created
+ $command['trim_user'] = false;
+
+ // Execute the command using the command object.
+ // The result value contains an array of JSON data from the response
+ $result = $command->execute();
+
+ // You can retrieve the result of the command later too
+ $result = $command->getResult().
+
+Command object also contains methods that allow you to inspect the HTTP request and response that was utilized with
+the command.
+
+.. code-block:: php
+
+ $request = $command->getRequest();
+ $response = $command->getResponse();
+
+.. note::
+
+ The format and notation used to retrieve commands from a client can be customized by injecting a custom command
+ factory, ``Guzzle\Service\Command\Factory\FactoryInterface``, on the client using ``$client->setCommandFactory()``.
+
+Executing with magic methods
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using method missing magic methods with a command, the command will be executed right away and the result of the
+command is returned.
+
+.. code-block:: php
+
+ $jsonData = $twitter->getMentions(array(
+ 'count' => 5,
+ 'trim_user' => true
+ ));
+
+Creating commands
+-----------------
+
+Commands are created using either the ``getCommand()`` method of a client or a magic missing method of a client. Using
+the ``getCommand()`` method allows you to create a command without executing it, allowing for customization of the
+command or the request serialized by the command.
+
+When a client attempts to create a command, it uses the client's ``Guzzle\Service\Command\Factory\FactoryInterface``.
+By default, Guzzle will utilize a command factory that first looks for a concrete class for a particular command
+(concrete commands) followed by a command defined by a service description (operation commands). We'll learn more about
+concrete commands and operation commands later in this chapter.
+
+.. code-block:: php
+
+ // Get a command from the twitter client.
+ $command = $twitter->getCommand('getMentions');
+ $result = $command->execute();
+
+Unless you've skipped ahead, running the above code will throw an exception.
+
+ PHP Fatal error: Uncaught exception 'Guzzle\Common\Exception\InvalidArgumentException' with message
+ 'Command was not found matching getMentions'
+
+This exception was thrown because the "getMentions" command has not yet been implemented. Let's implement one now.
+
+Concrete commands
+~~~~~~~~~~~~~~~~~
+
+Commands can be created in one of two ways: create a concrete command class that extends
+``Guzzle\Service\Command\AbstractCommand`` or
+:doc:`create an OperationCommand based on a service description `. The recommended
+approach is to use a service description to define your web service, but you can use concrete commands when custom
+logic must be implemented for marshaling or unmarshaling a HTTP message.
+
+Commands are the method in which you abstract away the underlying format of the requests that need to be sent to take
+action on a web service. Commands in Guzzle are meant to be built by executing a series of setter methods on a command
+object. Commands are only validated right before they are executed. A ``Guzzle\Service\Client`` object is responsible
+for executing commands. Commands created for your web service must implement
+``Guzzle\Service\Command\CommandInterface``, but it's easier to extend the ``Guzzle\Service\Command\AbstractCommand``
+class, implement the ``build()`` method, and optionally implement the ``process()`` method.
+
+Serializing requests
+^^^^^^^^^^^^^^^^^^^^
+
+The ``build()`` method of a command is responsible for using the arguments of the command to build and serialize a
+HTTP request and set the request on the ``$request`` property of the command object. This step is usually taken care of
+for you when using a service description driven command that uses the default
+``Guzzle\Service\Command\OperationCommand``. You may wish to implement the process method yourself when you aren't
+using a service description or need to implement more complex request serialization.
+
+.. important::::
+
+ When implementing a custom ``build()`` method, be sure to set the class property of ``$this->request`` to an
+ instantiated and ready to send request.
+
+The following example shows how to implement the ``getMentions``
+`Twitter API `_ method using a concrete command.
+
+.. code-block:: php
+
+ namespace mtdowling\Twitter\Command;
+
+ use Guzzle\Service\Command\AbstractCommand;
+
+ class GetMentions extends AbstractCommand
+ {
+ protected function build()
+ {
+ // Create the request property of the command
+ $this->request = $this->client->get('statuses/mentions_timeline.json');
+
+ // Grab the query object of the request because we will use it for
+ // serializing command parameters on the request
+ $query = $this->request->getQuery();
+
+ if ($this['count']) {
+ $query->set('count', $this['count']);
+ }
+
+ if ($this['since_id']) {
+ $query->set('since_id', $this['since_id']);
+ }
+
+ if ($this['max_id']) {
+ $query->set('max_id', $this['max_id']);
+ }
+
+ if ($this['trim_user'] !== null) {
+ $query->set('trim_user', $this['trim_user'] ? 'true' : 'false');
+ }
+
+ if ($this['contributor_details'] !== null) {
+ $query->set('contributor_details', $this['contributor_details'] ? 'true' : 'false');
+ }
+
+ if ($this['include_entities'] !== null) {
+ $query->set('include_entities', $this['include_entities'] ? 'true' : 'false');
+ }
+ }
+ }
+
+By default, a client will attempt to find concrete command classes under the ``Command`` namespace of a client. First
+the client will attempt to find an exact match for the name of the command to the name of the command class. If an
+exact match is not found, the client will calculate a class name using inflection. This is calculated based on the
+folder hierarchy of a command and converting the CamelCased named commands into snake_case. Here are some examples on
+how the command names are calculated:
+
+#. ``Foo\Command\JarJar`` **->** jar_jar
+#. ``Foo\Command\Test`` **->** test
+#. ``Foo\Command\People\GetCurrentPerson`` **->** people.get_current_person
+
+Notice how any sub-namespace beneath ``Command`` is converted from ``\`` to ``.`` (a period). CamelCasing is converted
+to lowercased snake_casing (e.g. JarJar == jar_jar).
+
+Parsing responses
+^^^^^^^^^^^^^^^^^
+
+The ``process()`` method of a command is responsible for converting an HTTP response into something more useful. For
+example, a service description operation that has specified a model object in the ``responseClass`` attribute of the
+operation will set a ``Guzzle\Service\Resource\Model`` object as the result of the command. This behavior can be
+completely modified as needed-- even if you are using operations and responseClass models. Simply implement a custom
+``process()`` method that sets the ``$this->result`` class property to whatever you choose. You can reuse parts of the
+default Guzzle response parsing functionality or get inspiration from existing code by using
+``Guzzle\Service\Command\OperationResponseParser`` and ``Guzzle\Service\Command\DefaultResponseParser`` classes.
+
+If you do not implement a custom ``process()`` method and are not using a service description, then Guzzle will attempt
+to guess how a response should be processed based on the Content-Type header of the response. Because the Twitter API
+sets a ``Content-Type: application/json`` header on this response, we do not need to implement any custom response
+parsing.
+
+Operation commands
+~~~~~~~~~~~~~~~~~~
+
+Operation commands are commands in which the serialization of an HTTP request and the parsing of an HTTP response are
+driven by a Guzzle service description. Because request serialization, validation, and response parsing are
+described using a DSL, creating operation commands is a much faster process than writing concrete commands.
+
+Creating operation commands for our Twitter client can remove a great deal of redundancy from the previous concrete
+command, and allows for a deeper runtime introspection of the API. Here's an example service description we can use to
+create the Twitter API client:
+
+.. code-block:: json
+
+ {
+ "name": "Twitter",
+ "apiVersion": "1.1",
+ "baseUrl": "https://api.twitter.com/1.1",
+ "description": "Twitter REST API client",
+ "operations": {
+ "GetMentions": {
+ "httpMethod": "GET",
+ "uri": "statuses/mentions_timeline.json",
+ "summary": "Returns the 20 most recent mentions for the authenticating user.",
+ "responseClass": "GetMentionsOutput",
+ "parameters": {
+ "count": {
+ "description": "Specifies the number of tweets to try and retrieve",
+ "type": "integer",
+ "location": "query"
+ },
+ "since_id": {
+ "description": "Returns results with an ID greater than the specified ID",
+ "type": "integer",
+ "location": "query"
+ },
+ "max_id": {
+ "description": "Returns results with an ID less than or equal to the specified ID.",
+ "type": "integer",
+ "location": "query"
+ },
+ "trim_user": {
+ "description": "Limits the amount of data returned for each user",
+ "type": "boolean",
+ "location": "query"
+ },
+ "contributor_details": {
+ "description": "Adds more data to contributor elements",
+ "type": "boolean",
+ "location": "query"
+ },
+ "include_entities": {
+ "description": "The entities node will be disincluded when set to false.",
+ "type": "boolean",
+ "location": "query"
+ }
+ }
+ }
+ },
+ "models": {
+ "GetMentionsOutput": {
+ "type": "object",
+ "additionalProperties": {
+ "location": "json"
+ }
+ }
+ }
+ }
+
+If you're lazy, you can define the API in a less descriptive manner using ``additionalParameters``.
+``additionalParameters`` define the serialization and validation rules of parameters that are not explicitly defined
+in a service description.
+
+.. code-block:: json
+
+ {
+ "name": "Twitter",
+ "apiVersion": "1.1",
+ "baseUrl": "https://api.twitter.com/1.1",
+ "description": "Twitter REST API client",
+ "operations": {
+ "GetMentions": {
+ "httpMethod": "GET",
+ "uri": "statuses/mentions_timeline.json",
+ "summary": "Returns the 20 most recent mentions for the authenticating user.",
+ "responseClass": "GetMentionsOutput",
+ "additionalParameters": {
+ "location": "query"
+ }
+ }
+ },
+ "models": {
+ "GetMentionsOutput": {
+ "type": "object",
+ "additionalProperties": {
+ "location": "json"
+ }
+ }
+ }
+ }
+
+You should attach the service description to the client at the end of the client's factory method:
+
+.. code-block:: php
+
+ // ...
+ class TwitterClient extends Client
+ {
+ public static function factory($config = array())
+ {
+ // ... same code as before ...
+
+ // Set the service description
+ $client->setDescription(ServiceDescription::factory('path/to/twitter.json'));
+
+ return $client;
+ }
+ }
+
+The client can now use operations defined in the service description instead of requiring you to create concrete
+command classes. Feel free to delete the concrete command class we created earlier.
+
+.. code-block:: php
+
+ $jsonData = $twitter->getMentions(array(
+ 'count' => 5,
+ 'trim_user' => true
+ ));
+
+Executing commands in parallel
+------------------------------
+
+Much like HTTP requests, Guzzle allows you to send multiple commands in parallel. You can send commands in parallel by
+passing an array of command objects to a client's ``execute()`` method. The client will serialize each request and
+send them all in parallel. If an error is encountered during the transfer, then a
+``Guzzle\Service\Exception\CommandTransferException`` is thrown, which allows you to retrieve a list of commands that
+succeeded and a list of commands that failed.
+
+.. code-block:: php
+
+ use Guzzle\Service\Exception\CommandTransferException;
+
+ $commands = array();
+ $commands[] = $twitter->getCommand('getMentions');
+ $commands[] = $twitter->getCommand('otherCommandName');
+ // etc...
+
+ try {
+ $result = $client->execute($commands);
+ foreach ($result as $command) {
+ echo $command->getName() . ': ' . $command->getResponse()->getStatusCode() . "\n";
+ }
+ } catch (CommandTransferException $e) {
+ // Get an array of the commands that succeeded
+ foreach ($e->getSuccessfulCommands() as $command) {
+ echo $command->getName() . " succeeded\n";
+ }
+ // Get an array of the commands that failed
+ foreach ($e->getFailedCommands() as $command) {
+ echo $command->getName() . " failed\n";
+ }
+ }
+
+.. note::
+
+ All commands executed from a client using an array must originate from the same client.
+
+Special command options
+-----------------------
+
+Guzzle exposes several options that help to control how commands are validated, serialized, and parsed.
+Command options can be specified when creating a command or in the ``command.params`` parameter in the
+``Guzzle\Service\Client``.
+
+=========================== ============================================================================================
+command.request_options Option used to add :ref:`Request options ` to the request created by a
+ command
+command.hidden_params An array of the names of parameters ignored by the ``additionalParameters`` parameter schema
+command.disable_validation Set to true to disable JSON schema validation of the command's input parameters
+command.response_processing Determines how the default response parser will parse the command. One of "raw" no parsing,
+ "model" (the default method used to parse commands using response models defined in service
+ descriptions)
+command.headers (deprecated) Option used to specify custom headers. Use ``command.request_options`` instead
+command.on_complete (deprecated) Option used to add an onComplete method to a command. Use
+ ``command.after_send`` event instead
+command.response_body (deprecated) Option used to change the entity body used to store a response.
+ Use ``command.request_options`` instead
+=========================== ============================================================================================
+
+Advanced client configuration
+=============================
+
+Default command parameters
+--------------------------
+
+When creating a client object, you can specify default command parameters to pass into all commands. Any key value pair
+present in the ``command.params`` settings of a client will be added as default parameters to any command created
+by the client.
+
+.. code-block:: php
+
+ $client = new Guzzle\Service\Client(array(
+ 'command.params' => array(
+ 'default_1' => 'foo',
+ 'another' => 'bar'
+ )
+ ));
+
+Magic methods
+-------------
+
+Client objects will, by default, attempt to create and execute commands when a missing method is invoked on a client.
+This powerful concept applies to both concrete commands and operation commands powered by a service description. This
+makes it appear to the end user that you have defined actual methods on a client object, when in fact, the methods are
+invoked using PHP's magic ``__call`` method.
+
+The ``__call`` method uses the ``getCommand()`` method of a client, which uses the client's internal
+``Guzzle\Service\Command\Factory\FactoryInterface`` object. The default command factory allows you to instantiate
+operations defined in a client's service description. The method in which a client determines which command to
+execute is defined as follows:
+
+1. The client will first try to find a literal match for an operation in the service description.
+2. If the literal match is not found, the client will try to uppercase the first character of the operation and find
+ the match again.
+3. If a match is still not found, the command factory will inflect the method name from CamelCase to snake_case and
+ attempt to find a matching command.
+4. If a command still does not match, an exception is thrown.
+
+.. code-block:: php
+
+ // Use the magic method
+ $result = $twitter->getMentions();
+
+ // This is exactly the same as:
+ $result = $twitter->getCommand('getMentions')->execute();
+
+You can disable magic methods on a client by passing ``false`` to the ``enableMagicMethod()`` method.
+
+Custom command factory
+----------------------
+
+A client by default uses the ``Guzzle\Service\Command\Factory\CompositeFactory`` which allows multiple command
+factories to attempt to create a command by a certain name. The default CompositeFactory uses a ``ConcreteClassFactory``
+and a ``ServiceDescriptionFactory`` if a service description is specified on a client. You can specify a custom
+command factory if your client requires custom command creation logic using the ``setCommandFactory()`` method of
+a client.
+
+Custom resource Iterator factory
+--------------------------------
+
+Resource iterators can be retrieved from a client using the ``getIterator($name)`` method of a client. This method uses
+a client's internal ``Guzzle\Service\Resource\ResourceIteratorFactoryInterface`` object. A client by default uses a
+``Guzzle\Service\Resource\ResourceIteratorClassFactory`` to attempt to find concrete classes that implement resource
+iterators. The default factory will first look for matching iterators in the ``Iterator`` subdirectory of the client
+followed by the ``Model`` subdirectory of a client. Use the ``setResourceIteratorFactory()`` method of a client to
+specify a custom resource iterator factory.
+
+Plugins and events
+==================
+
+``Guzzle\Service\Client`` exposes various events that allow you to hook in custom logic. A client object owns a
+``Symfony\Component\EventDispatcher\EventDispatcher`` object that can be accessed by calling
+``$client->getEventDispatcher()``. You can use the event dispatcher to add listeners (a simple callback function) or
+event subscribers (classes that listen to specific events of a dispatcher).
+
+.. _service-client-events:
+
+Events emitted from a Service Client
+------------------------------------
+
+A ``Guzzle\Service\Client`` object emits the following events:
+
++------------------------------+--------------------------------------------+------------------------------------------+
+| Event name | Description | Event data |
++==============================+============================================+==========================================+
+| client.command.create | The client created a command object | * client: Client object |
+| | | * command: Command object |
++------------------------------+--------------------------------------------+------------------------------------------+
+| command.before_prepare | Before a command is validated and built. | * command: Command being prepared |
+| | This is also before a request is created. | |
++------------------------------+--------------------------------------------+------------------------------------------+
+| command.after_prepare | After a command instantiates and | * command: Command that was prepared |
+| | configures its request object. | |
++------------------------------+--------------------------------------------+------------------------------------------+
+| command.before_send | The client is about to execute a prepared | * command: Command to execute |
+| | command | |
++------------------------------+--------------------------------------------+------------------------------------------+
+| command.after_send | The client successfully completed | * command: The command that was executed |
+| | executing a command | |
++------------------------------+--------------------------------------------+------------------------------------------+
+| command.parse_response | Called when ``responseType`` is ``class`` | * command: The command with a response |
+| | and the response is about to be parsed. | about to be parsed. |
++------------------------------+--------------------------------------------+------------------------------------------+
+
+.. code-block:: php
+
+ use Guzzle\Common\Event;
+ use Guzzle\Service\Client;
+
+ $client = new Client();
+
+ // create an event listener that operates on request objects
+ $client->getEventDispatcher()->addListener('command.after_prepare', function (Event $event) {
+ $command = $event['command'];
+ $request = $command->getRequest();
+
+ // do something with request
+ });
+
+.. code-block:: php
+
+ use Guzzle\Common\Event;
+ use Guzzle\Common\Client;
+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+ class EventSubscriber implements EventSubscriberInterface
+ {
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'client.command.create' => 'onCommandCreate',
+ 'command.parse_response' => 'onParseResponse'
+ );
+ }
+
+ public function onCommandCreate(Event $event)
+ {
+ $client = $event['client'];
+ $command = $event['command'];
+ // operate on client and command
+ }
+
+ public function onParseResponse(Event $event)
+ {
+ $command = $event['command'];
+ // operate on the command
+ }
+ }
+
+ $client = new Client();
+
+ $client->addSubscriber(new EventSubscriber());
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phar-stub.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phar-stub.php
new file mode 100755
index 0000000..cc2b53f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phar-stub.php
@@ -0,0 +1,16 @@
+registerNamespaces(array(
+ 'Guzzle' => 'phar://guzzle.phar/src',
+ 'Symfony\\Component\\EventDispatcher' => 'phar://guzzle.phar/vendor/symfony/event-dispatcher',
+ 'Doctrine' => 'phar://guzzle.phar/vendor/doctrine/common/lib',
+ 'Monolog' => 'phar://guzzle.phar/vendor/monolog/monolog/src'
+));
+$classLoader->register();
+
+__HALT_COMPILER();
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/build.properties.dist b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/build.properties.dist
new file mode 100755
index 0000000..c60d3d9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/build.properties.dist
@@ -0,0 +1,16 @@
+# you may need to update this if you're working on a fork.
+guzzle.remote=git@github.com:guzzle/guzzle.git
+
+# github credentials -- only used by GitHub API calls to create subtree repos
+github.basicauth=username:password
+# for the subtree split and testing
+github.org=guzzle
+
+# your git path
+cmd.git=git
+
+# your composer command
+cmd.composer=composer
+
+# test server start
+cmd.testserver=node
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/imports/dependencies.xml b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/imports/dependencies.xml
new file mode 100755
index 0000000..e40e037
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/imports/dependencies.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ using git at ${cmd.git}
+
+
+
+ found git at ${cmd.git}
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/imports/deploy.xml b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/imports/deploy.xml
new file mode 100755
index 0000000..109e5ec
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/imports/deploy.xml
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+ On branch ${head}
+
+
+
+
+
+
+
+
+
+ working directory clean
+
+
+ ${git.status}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChangeLog Match: ${version.changelog}
+ Guzzle\Common\Version Match: ${version.version}
+
+
+
+ releasing: phing -Dnew.version=3.0.x -Dhead=master release
+ --
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BEGINNING RELEASE FOR ${new.version}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tip: to create a new release, do: phing -Dnew.version=[TAG] -Dhead=[BRANCH] release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php
new file mode 100755
index 0000000..3b70409
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/ComposerLintTask.php
@@ -0,0 +1,152 @@
+
+ * @license http://claylo.mit-license.org/2012/ MIT License
+ */
+
+require_once 'phing/Task.php';
+
+class ComposerLintTask extends Task
+{
+ protected $dir = null;
+ protected $file = null;
+ protected $passthru = false;
+ protected $composer = null;
+
+ /**
+ * The setter for the dir
+ *
+ * @param string $str Directory to crawl recursively for composer files
+ */
+ public function setDir($str)
+ {
+ $this->dir = $str;
+ }
+
+ /**
+ * The setter for the file
+ *
+ * @param string $str Individual file to validate
+ */
+ public function setFile($str)
+ {
+ $this->file = $str;
+ }
+
+ /**
+ * Whether to use PHP's passthru() function instead of exec()
+ *
+ * @param boolean $passthru If passthru shall be used
+ */
+ public function setPassthru($passthru)
+ {
+ $this->passthru = (bool) $passthru;
+ }
+
+ /**
+ * Composer to execute. If unset, will attempt composer.phar in project
+ * basedir, and if that fails, will attempt global composer
+ * installation.
+ *
+ * @param string $str Individual file to validate
+ */
+ public function setComposer($str)
+ {
+ $this->file = $str;
+ }
+
+ /**
+ * The init method: do init steps
+ */
+ public function init()
+ {
+ // nothing needed here
+ }
+
+ /**
+ * The main entry point
+ */
+ public function main()
+ {
+ if ($this->composer === null) {
+ $this->findComposer();
+ }
+
+ $files = array();
+ if (!empty($this->file) && file_exists($this->file)) {
+ $files[] = $this->file;
+ }
+
+ if (!empty($this->dir)) {
+ $found = $this->findFiles();
+ foreach ($found as $file) {
+ $files[] = $this->dir . DIRECTORY_SEPARATOR . $file;
+ }
+ }
+
+ foreach ($files as $file) {
+
+ $cmd = $this->composer . ' validate ' . $file;
+ $cmd = escapeshellcmd($cmd);
+
+ if ($this->passthru) {
+ $retval = null;
+ passthru($cmd, $retval);
+ if ($retval == 1) {
+ throw new BuildException('invalid composer.json');
+ }
+ } else {
+ $out = array();
+ $retval = null;
+ exec($cmd, $out, $retval);
+ if ($retval == 1) {
+ $err = join("\n", $out);
+ throw new BuildException($err);
+ } else {
+ $this->log($out[0]);
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * Find the composer.json files using Phing's directory scanner
+ *
+ * @return array
+ */
+ protected function findFiles()
+ {
+ $ds = new DirectoryScanner();
+ $ds->setBasedir($this->dir);
+ $ds->setIncludes(array('**/composer.json'));
+ $ds->scan();
+ return $ds->getIncludedFiles();
+ }
+
+ /**
+ * Find composer installation
+ *
+ */
+ protected function findComposer()
+ {
+ $basedir = $this->project->getBasedir();
+ $php = $this->project->getProperty('php.interpreter');
+
+ if (file_exists($basedir . '/composer.phar')) {
+ $this->composer = "$php $basedir/composer.phar";
+ } else {
+ $out = array();
+ exec('which composer', $out);
+ if (empty($out)) {
+ throw new BuildException(
+ 'Could not determine composer location.'
+ );
+ }
+ $this->composer = $out[0];
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php
new file mode 100755
index 0000000..f72a6b5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/GuzzlePearPharPackageTask.php
@@ -0,0 +1,338 @@
+
+ * @license http://claylo.mit-license.org/2012/ MIT License
+ */
+
+require_once 'phing/Task.php';
+require_once 'PEAR/PackageFileManager2.php';
+require_once 'PEAR/PackageFileManager/File.php';
+require_once 'PEAR/Packager.php';
+
+class GuzzlePearPharPackageTask extends Task
+{
+ private $version;
+ private $deploy = true;
+ private $makephar = true;
+
+ private $subpackages = array();
+
+ public function setVersion($str)
+ {
+ $this->version = $str;
+ }
+
+ public function getVersion()
+ {
+ return $this->version;
+ }
+
+ public function setDeploy($deploy)
+ {
+ $this->deploy = (bool) $deploy;
+ }
+
+ public function getDeploy()
+ {
+ return $this->deploy;
+ }
+
+ public function setMakephar($makephar)
+ {
+ $this->makephar = (bool) $makephar;
+ }
+
+ public function getMakephar()
+ {
+ return $this->makephar;
+ }
+
+ private $basedir;
+ private $guzzleinfo;
+ private $changelog_release_date;
+ private $changelog_notes = '-';
+
+ public function main()
+ {
+ $this->basedir = $this->getProject()->getBasedir();
+
+ if (!is_dir((string) $this->basedir.'/.subsplit')) {
+ throw new BuildException('PEAR packaging requires .subsplit directory');
+ }
+
+ // main composer file
+ $composer_file = file_get_contents((string) $this->basedir.'/.subsplit/composer.json');
+ $this->guzzleinfo = json_decode($composer_file, true);
+
+ // make sure we have a target
+ $pearwork = (string) $this->basedir . '/build/pearwork';
+ if (!is_dir($pearwork)) {
+ mkdir($pearwork, 0777, true);
+ }
+ $pearlogs = (string) $this->basedir . '/build/artifacts/logs';
+ if (!is_dir($pearlogs)) {
+ mkdir($pearlogs, 0777, true);
+ }
+
+ $version = $this->getVersion();
+ $this->grabChangelog();
+ if ($version[0] == '2') {
+ $this->log('building single PEAR package');
+ $this->buildSinglePackage();
+ } else {
+ // $this->log("building PEAR subpackages");
+ // $this->createSubPackages();
+ // $this->log("building PEAR bundle package");
+ $this->buildSinglePackage();
+ }
+
+ if ($this->getMakephar()) {
+ $this->log("building PHAR");
+ $this->getProject()->executeTarget('package-phar');
+ }
+
+ if ($this->getDeploy()) {
+ $this->doDeployment();
+ }
+ }
+
+ public function doDeployment()
+ {
+ $basedir = (string) $this->basedir;
+ $this->log('beginning PEAR/PHAR deployment');
+
+ chdir($basedir . '/build/pearwork');
+ if (!is_dir('./channel')) {
+ mkdir('./channel');
+ }
+
+ // Pull the PEAR channel down locally
+ passthru('aws s3 sync s3://pear.guzzlephp.org ./channel');
+
+ // add PEAR packages
+ foreach (scandir('./') as $file) {
+ if (substr($file, -4) == '.tgz') {
+ passthru('pirum add ./channel ' . $file);
+ }
+ }
+
+ // if we have a new phar, add it
+ if ($this->getMakephar() && file_exists($basedir . '/build/artifacts/guzzle.phar')) {
+ rename($basedir . '/build/artifacts/guzzle.phar', './channel/guzzle.phar');
+ }
+
+ // Sync up with the S3 bucket
+ chdir($basedir . '/build/pearwork/channel');
+ passthru('aws s3 sync . s3://pear.guzzlephp.org');
+ }
+
+ public function buildSinglePackage()
+ {
+ $v = $this->getVersion();
+ $apiversion = $v[0] . '.0.0';
+
+ $opts = array(
+ 'packagedirectory' => (string) $this->basedir . '/.subsplit/src/',
+ 'filelistgenerator' => 'file',
+ 'ignore' => array('*composer.json'),
+ 'baseinstalldir' => '/',
+ 'packagefile' => 'package.xml'
+ //'outputdirectory' => (string) $this->basedir . '/build/pearwork/'
+ );
+ $pfm = new PEAR_PackageFileManager2();
+ $pfm->setOptions($opts);
+ $pfm->addRole('md', 'doc');
+ $pfm->addRole('pem', 'php');
+ $pfm->setPackage('Guzzle');
+ $pfm->setSummary("Object-oriented PHP HTTP Client for PHP 5.3+");
+ $pfm->setDescription($this->guzzleinfo['description']);
+ $pfm->setPackageType('php');
+ $pfm->setChannel('guzzlephp.org/pear');
+ $pfm->setAPIVersion($apiversion);
+ $pfm->setReleaseVersion($this->getVersion());
+ $pfm->setAPIStability('stable');
+ $pfm->setReleaseStability('stable');
+ $pfm->setNotes($this->changelog_notes);
+ $pfm->setPackageType('php');
+ $pfm->setLicense('MIT', 'http://github.com/guzzle/guzzle/blob/master/LICENSE');
+ $pfm->addMaintainer('lead', 'mtdowling', 'Michael Dowling', 'mtdowling@gmail.com', 'yes');
+ $pfm->setDate($this->changelog_release_date);
+ $pfm->generateContents();
+
+ $phpdep = $this->guzzleinfo['require']['php'];
+ $phpdep = str_replace('>=', '', $phpdep);
+ $pfm->setPhpDep($phpdep);
+ $pfm->addExtensionDep('required', 'curl');
+ $pfm->setPearinstallerDep('1.4.6');
+ $pfm->addPackageDepWithChannel('required', 'EventDispatcher', 'pear.symfony.com', '2.1.0');
+ if (!empty($this->subpackages)) {
+ foreach ($this->subpackages as $package) {
+ $pkg = dirname($package);
+ $pkg = str_replace('/', '_', $pkg);
+ $pfm->addConflictingPackageDepWithChannel($pkg, 'guzzlephp.org/pear', false, $apiversion);
+ }
+ }
+
+ ob_start();
+ $startdir = getcwd();
+ chdir((string) $this->basedir . '/build/pearwork');
+
+ echo "DEBUGGING GENERATED PACKAGE FILE\n";
+ $result = $pfm->debugPackageFile();
+ if ($result) {
+ $out = $pfm->writePackageFile();
+ echo "\n\n\nWRITE PACKAGE FILE RESULT:\n";
+ var_dump($out);
+ // load up package file and build package
+ $packager = new PEAR_Packager();
+ echo "\n\n\nBUILDING PACKAGE FROM PACKAGE FILE:\n";
+ $dest_package = $packager->package($opts['packagedirectory'].'package.xml');
+ var_dump($dest_package);
+ } else {
+ echo "\n\n\nDEBUGGING RESULT:\n";
+ var_dump($result);
+ }
+ echo "removing package.xml";
+ unlink($opts['packagedirectory'].'package.xml');
+ $log = ob_get_clean();
+ file_put_contents((string) $this->basedir . '/build/artifacts/logs/pear_package.log', $log);
+ chdir($startdir);
+ }
+
+ public function createSubPackages()
+ {
+ $this->findComponents();
+
+ foreach ($this->subpackages as $package) {
+ $baseinstalldir = dirname($package);
+ $dir = (string) $this->basedir.'/.subsplit/src/' . $baseinstalldir;
+ $composer_file = file_get_contents((string) $this->basedir.'/.subsplit/src/'. $package);
+ $package_info = json_decode($composer_file, true);
+ $this->log('building ' . $package_info['target-dir'] . ' subpackage');
+ $this->buildSubPackage($dir, $baseinstalldir, $package_info);
+ }
+ }
+
+ public function buildSubPackage($dir, $baseinstalldir, $info)
+ {
+ $package = str_replace('/', '_', $baseinstalldir);
+ $opts = array(
+ 'packagedirectory' => $dir,
+ 'filelistgenerator' => 'file',
+ 'ignore' => array('*composer.json', '*package.xml'),
+ 'baseinstalldir' => '/' . $info['target-dir'],
+ 'packagefile' => 'package.xml'
+ );
+ $pfm = new PEAR_PackageFileManager2();
+ $pfm->setOptions($opts);
+ $pfm->setPackage($package);
+ $pfm->setSummary($info['description']);
+ $pfm->setDescription($info['description']);
+ $pfm->setPackageType('php');
+ $pfm->setChannel('guzzlephp.org/pear');
+ $pfm->setAPIVersion('3.0.0');
+ $pfm->setReleaseVersion($this->getVersion());
+ $pfm->setAPIStability('stable');
+ $pfm->setReleaseStability('stable');
+ $pfm->setNotes($this->changelog_notes);
+ $pfm->setPackageType('php');
+ $pfm->setLicense('MIT', 'http://github.com/guzzle/guzzle/blob/master/LICENSE');
+ $pfm->addMaintainer('lead', 'mtdowling', 'Michael Dowling', 'mtdowling@gmail.com', 'yes');
+ $pfm->setDate($this->changelog_release_date);
+ $pfm->generateContents();
+
+ $phpdep = $this->guzzleinfo['require']['php'];
+ $phpdep = str_replace('>=', '', $phpdep);
+ $pfm->setPhpDep($phpdep);
+ $pfm->setPearinstallerDep('1.4.6');
+
+ foreach ($info['require'] as $type => $version) {
+ if ($type == 'php') {
+ continue;
+ }
+ if ($type == 'symfony/event-dispatcher') {
+ $pfm->addPackageDepWithChannel('required', 'EventDispatcher', 'pear.symfony.com', '2.1.0');
+ }
+ if ($type == 'ext-curl') {
+ $pfm->addExtensionDep('required', 'curl');
+ }
+ if (substr($type, 0, 6) == 'guzzle') {
+ $gdep = str_replace('/', ' ', $type);
+ $gdep = ucwords($gdep);
+ $gdep = str_replace(' ', '_', $gdep);
+ $pfm->addPackageDepWithChannel('required', $gdep, 'guzzlephp.org/pear', $this->getVersion());
+ }
+ }
+
+ // can't have main Guzzle package AND sub-packages
+ $pfm->addConflictingPackageDepWithChannel('Guzzle', 'guzzlephp.org/pear', false, $apiversion);
+
+ ob_start();
+ $startdir = getcwd();
+ chdir((string) $this->basedir . '/build/pearwork');
+
+ echo "DEBUGGING GENERATED PACKAGE FILE\n";
+ $result = $pfm->debugPackageFile();
+ if ($result) {
+ $out = $pfm->writePackageFile();
+ echo "\n\n\nWRITE PACKAGE FILE RESULT:\n";
+ var_dump($out);
+ // load up package file and build package
+ $packager = new PEAR_Packager();
+ echo "\n\n\nBUILDING PACKAGE FROM PACKAGE FILE:\n";
+ $dest_package = $packager->package($opts['packagedirectory'].'/package.xml');
+ var_dump($dest_package);
+ } else {
+ echo "\n\n\nDEBUGGING RESULT:\n";
+ var_dump($result);
+ }
+ echo "removing package.xml";
+ unlink($opts['packagedirectory'].'/package.xml');
+ $log = ob_get_clean();
+ file_put_contents((string) $this->basedir . '/build/artifacts/logs/pear_package_'.$package.'.log', $log);
+ chdir($startdir);
+ }
+
+ public function findComponents()
+ {
+ $ds = new DirectoryScanner();
+ $ds->setBasedir((string) $this->basedir.'/.subsplit/src');
+ $ds->setIncludes(array('**/composer.json'));
+ $ds->scan();
+ $files = $ds->getIncludedFiles();
+ $this->subpackages = $files;
+ }
+
+ public function grabChangelog()
+ {
+ $cl = file((string) $this->basedir.'/.subsplit/CHANGELOG.md');
+ $notes = '';
+ $in_version = false;
+ $release_date = null;
+
+ foreach ($cl as $line) {
+ $line = trim($line);
+ if (preg_match('/^\* '.$this->getVersion().' \(([0-9\-]+)\)$/', $line, $matches)) {
+ $release_date = $matches[1];
+ $in_version = true;
+ continue;
+ }
+ if ($in_version && empty($line) && empty($notes)) {
+ continue;
+ }
+ if ($in_version && ! empty($line)) {
+ $notes .= $line."\n";
+ }
+ if ($in_version && empty($line) && !empty($notes)) {
+ $in_version = false;
+ }
+ }
+ $this->changelog_release_date = $release_date;
+
+ if (! empty($notes)) {
+ $this->changelog_notes = $notes;
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php
new file mode 100755
index 0000000..5d56a5b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phing/tasks/GuzzleSubSplitTask.php
@@ -0,0 +1,385 @@
+
+ * @license http://claylo.mit-license.org/2012/ MIT License
+ */
+
+require_once 'phing/tasks/ext/git/GitBaseTask.php';
+
+// base - base of tree to split out
+// subIndicatorFile - composer.json, package.xml?
+class GuzzleSubSplitTask extends GitBaseTask
+{
+ /**
+ * What git repository to pull from and publish to
+ */
+ protected $remote = null;
+
+ /**
+ * Publish for comma-separated heads instead of all heads
+ */
+ protected $heads = null;
+
+ /**
+ * Publish for comma-separated tags instead of all tags
+ */
+ protected $tags = null;
+
+ /**
+ * Base of the tree RELATIVE TO .subsplit working dir
+ */
+ protected $base = null;
+
+ /**
+ * The presence of this file will indicate that the directory it resides
+ * in is at the top level of a split.
+ */
+ protected $subIndicatorFile = 'composer.json';
+
+ /**
+ * Do everything except actually send the update.
+ */
+ protected $dryRun = null;
+
+ /**
+ * Do not sync any heads.
+ */
+ protected $noHeads = false;
+
+ /**
+ * Do not sync any tags.
+ */
+ protected $noTags = false;
+
+ /**
+ * The splits we found in the heads
+ */
+ protected $splits;
+
+ public function setRemote($str)
+ {
+ $this->remote = $str;
+ }
+
+ public function getRemote()
+ {
+ return $this->remote;
+ }
+
+ public function setHeads($str)
+ {
+ $this->heads = explode(',', $str);
+ }
+
+ public function getHeads()
+ {
+ return $this->heads;
+ }
+
+ public function setTags($str)
+ {
+ $this->tags = explode(',', $str);
+ }
+
+ public function getTags()
+ {
+ return $this->tags;
+ }
+
+ public function setBase($str)
+ {
+ $this->base = $str;
+ }
+
+ public function getBase()
+ {
+ return $this->base;
+ }
+
+ public function setSubIndicatorFile($str)
+ {
+ $this->subIndicatorFile = $str;
+ }
+
+ public function getSubIndicatorFile()
+ {
+ return $this->subIndicatorFile;
+ }
+
+ public function setDryRun($bool)
+ {
+ $this->dryRun = (bool) $bool;
+ }
+
+ public function getDryRun()
+ {
+ return $this->dryRun;
+ }
+
+ public function setNoHeads($bool)
+ {
+ $this->noHeads = (bool) $bool;
+ }
+
+ public function getNoHeads()
+ {
+ return $this->noHeads;
+ }
+
+ public function setNoTags($bool)
+ {
+ $this->noTags = (bool) $bool;
+ }
+
+ public function getNoTags()
+ {
+ return $this->noTags;
+ }
+
+ /**
+ * GitClient from VersionControl_Git
+ */
+ protected $client = null;
+
+ /**
+ * The main entry point
+ */
+ public function main()
+ {
+ $repo = $this->getRepository();
+ if (empty($repo)) {
+ throw new BuildException('"repository" is a required parameter');
+ }
+
+ $remote = $this->getRemote();
+ if (empty($remote)) {
+ throw new BuildException('"remote" is a required parameter');
+ }
+
+ chdir($repo);
+ $this->client = $this->getGitClient(false, $repo);
+
+ // initalized yet?
+ if (!is_dir('.subsplit')) {
+ $this->subsplitInit();
+ } else {
+ // update
+ $this->subsplitUpdate();
+ }
+
+ // find all splits based on heads requested
+ $this->findSplits();
+
+ // check that GitHub has the repos
+ $this->verifyRepos();
+
+ // execute the subsplits
+ $this->publish();
+ }
+
+ public function publish()
+ {
+ $this->log('DRY RUN ONLY FOR NOW');
+ $base = $this->getBase();
+ $base = rtrim($base, '/') . '/';
+ $org = $this->getOwningTarget()->getProject()->getProperty('github.org');
+
+ $splits = array();
+
+ $heads = $this->getHeads();
+ foreach ($heads as $head) {
+ foreach ($this->splits[$head] as $component => $meta) {
+ $splits[] = $base . $component . ':git@github.com:'. $org.'/'.$meta['repo'];
+ }
+
+ $cmd = 'git subsplit publish ';
+ $cmd .= escapeshellarg(implode(' ', $splits));
+
+ if ($this->getNoHeads()) {
+ $cmd .= ' --no-heads';
+ } else {
+ $cmd .= ' --heads='.$head;
+ }
+
+ if ($this->getNoTags()) {
+ $cmd .= ' --no-tags';
+ } else {
+ if ($this->getTags()) {
+ $cmd .= ' --tags=' . escapeshellarg(implode(' ', $this->getTags()));
+ }
+ }
+
+ passthru($cmd);
+ }
+ }
+
+ /**
+ * Runs `git subsplit update`
+ */
+ public function subsplitUpdate()
+ {
+ $repo = $this->getRepository();
+ $this->log('git-subsplit update...');
+ $cmd = $this->client->getCommand('subsplit');
+ $cmd->addArgument('update');
+ try {
+ $cmd->execute();
+ } catch (Exception $e) {
+ throw new BuildException('git subsplit update failed'. $e);
+ }
+ chdir($repo . '/.subsplit');
+ passthru('php ../composer.phar update --dev');
+ chdir($repo);
+ }
+
+ /**
+ * Runs `git subsplit init` based on the remote repository.
+ */
+ public function subsplitInit()
+ {
+ $remote = $this->getRemote();
+ $cmd = $this->client->getCommand('subsplit');
+ $this->log('running git-subsplit init ' . $remote);
+
+ $cmd->setArguments(array(
+ 'init',
+ $remote
+ ));
+
+ try {
+ $output = $cmd->execute();
+ } catch (Exception $e) {
+ throw new BuildException('git subsplit init failed'. $e);
+ }
+ $this->log(trim($output), Project::MSG_INFO);
+ $repo = $this->getRepository();
+ chdir($repo . '/.subsplit');
+ passthru('php ../composer.phar install --dev');
+ chdir($repo);
+ }
+
+ /**
+ * Find the composer.json files using Phing's directory scanner
+ *
+ * @return array
+ */
+ protected function findSplits()
+ {
+ $this->log("checking heads for subsplits");
+ $repo = $this->getRepository();
+ $base = $this->getBase();
+
+ $splits = array();
+ $heads = $this->getHeads();
+
+ if (!empty($base)) {
+ $base = '/' . ltrim($base, '/');
+ } else {
+ $base = '/';
+ }
+
+ chdir($repo . '/.subsplit');
+ foreach ($heads as $head) {
+ $splits[$head] = array();
+
+ // check each head requested *BEFORE* the actual subtree split command gets it
+ passthru("git checkout '$head'");
+ $ds = new DirectoryScanner();
+ $ds->setBasedir($repo . '/.subsplit' . $base);
+ $ds->setIncludes(array('**/'.$this->subIndicatorFile));
+ $ds->scan();
+ $files = $ds->getIncludedFiles();
+
+ // Process the files we found
+ foreach ($files as $file) {
+ $pkg = file_get_contents($repo . '/.subsplit' . $base .'/'. $file);
+ $pkg_json = json_decode($pkg, true);
+ $name = $pkg_json['name'];
+ $component = str_replace('/composer.json', '', $file);
+ // keep this for split cmd
+ $tmpreponame = explode('/', $name);
+ $reponame = $tmpreponame[1];
+ $splits[$head][$component]['repo'] = $reponame;
+ $nscomponent = str_replace('/', '\\', $component);
+ $splits[$head][$component]['desc'] = "[READ ONLY] Subtree split of $nscomponent: " . $pkg_json['description'];
+ }
+ }
+
+ // go back to how we found it
+ passthru("git checkout master");
+ chdir($repo);
+ $this->splits = $splits;
+ }
+
+ /**
+ * Based on list of repositories we determined we *should* have, talk
+ * to GitHub and make sure they're all there.
+ *
+ */
+ protected function verifyRepos()
+ {
+ $this->log('verifying GitHub target repos');
+ $github_org = $this->getOwningTarget()->getProject()->getProperty('github.org');
+ $github_creds = $this->getOwningTarget()->getProject()->getProperty('github.basicauth');
+
+ if ($github_creds == 'username:password') {
+ $this->log('Skipping GitHub repo checks. Update github.basicauth in build.properties to verify repos.', 1);
+ return;
+ }
+
+ $ch = curl_init('https://api.github.com/orgs/'.$github_org.'/repos?type=all');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_USERPWD, $github_creds);
+ // change this when we know we can use our bundled CA bundle!
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ $result = curl_exec($ch);
+ curl_close($ch);
+ $repos = json_decode($result, true);
+ $existing_repos = array();
+
+ // parse out the repos we found on GitHub
+ foreach ($repos as $repo) {
+ $tmpreponame = explode('/', $repo['full_name']);
+ $reponame = $tmpreponame[1];
+ $existing_repos[$reponame] = $repo['description'];
+ }
+
+ $heads = $this->getHeads();
+ foreach ($heads as $head) {
+ foreach ($this->splits[$head] as $component => $meta) {
+
+ $reponame = $meta['repo'];
+
+ if (!isset($existing_repos[$reponame])) {
+ $this->log("Creating missing repo $reponame");
+ $payload = array(
+ 'name' => $reponame,
+ 'description' => $meta['desc'],
+ 'homepage' => 'http://www.guzzlephp.org/',
+ 'private' => true,
+ 'has_issues' => false,
+ 'has_wiki' => false,
+ 'has_downloads' => true,
+ 'auto_init' => false
+ );
+ $ch = curl_init('https://api.github.com/orgs/'.$github_org.'/repos');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_USERPWD, $github_creds);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
+ // change this when we know we can use our bundled CA bundle!
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ $result = curl_exec($ch);
+ echo "Response code: ".curl_getinfo($ch, CURLINFO_HTTP_CODE)."\n";
+ curl_close($ch);
+ } else {
+ $this->log("Repo $reponame exists", 2);
+ }
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phpunit.xml.dist b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phpunit.xml.dist
new file mode 100755
index 0000000..208fdc0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/phpunit.xml.dist
@@ -0,0 +1,48 @@
+
+
+
+
+
+ ./tests/Guzzle/Tests
+
+
+
+
+
+
+
+
+
+ ./src/Guzzle
+
+ ./src/Guzzle
+ ./src/Guzzle/Common/Exception/GuzzleException.php
+ ./src/Guzzle/Http/Exception/HttpException.php
+ ./src/Guzzle/Http/Exception/ServerErrorResponseException.php
+ ./src/Guzzle/Http/Exception/ClientErrorResponseException.php
+ ./src/Guzzle/Http/Exception/TooManyRedirectsException.php
+ ./src/Guzzle/Http/Exception/CouldNotRewindStreamException.php
+ ./src/Guzzle/Common/Exception/BadMethodCallException.php
+ ./src/Guzzle/Common/Exception/InvalidArgumentException.php
+ ./src/Guzzle/Common/Exception/RuntimeException.php
+ ./src/Guzzle/Common/Exception/UnexpectedValueException.php
+ ./src/Guzzle/Service/Exception/ClientNotFoundException.php
+ ./src/Guzzle/Service/Exception/CommandException.php
+ ./src/Guzzle/Service/Exception/DescriptionBuilderException.php
+ ./src/Guzzle/Service/Exception/ServiceBuilderException.php
+ ./src/Guzzle/Service/Exception/ServiceNotFoundException.php
+ ./src/Guzzle/Service/Exception/ValidationException.php
+ ./src/Guzzle/Service/Exception/JsonException.php
+
+
+
+
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php
new file mode 100755
index 0000000..0625d71
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/AbstractBatchDecorator.php
@@ -0,0 +1,66 @@
+decoratedBatch = $decoratedBatch;
+ }
+
+ /**
+ * Allow decorators to implement custom methods
+ *
+ * @param string $method Missing method name
+ * @param array $args Method arguments
+ *
+ * @return mixed
+ * @codeCoverageIgnore
+ */
+ public function __call($method, array $args)
+ {
+ return call_user_func_array(array($this->decoratedBatch, $method), $args);
+ }
+
+ public function add($item)
+ {
+ $this->decoratedBatch->add($item);
+
+ return $this;
+ }
+
+ public function flush()
+ {
+ return $this->decoratedBatch->flush();
+ }
+
+ public function isEmpty()
+ {
+ return $this->decoratedBatch->isEmpty();
+ }
+
+ /**
+ * Trace the decorators associated with the batch
+ *
+ * @return array
+ */
+ public function getDecorators()
+ {
+ $found = array($this);
+ if (method_exists($this->decoratedBatch, 'getDecorators')) {
+ $found = array_merge($found, $this->decoratedBatch->getDecorators());
+ }
+
+ return $found;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php
new file mode 100755
index 0000000..4d41c54
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/Batch.php
@@ -0,0 +1,92 @@
+transferStrategy = $transferStrategy;
+ $this->divisionStrategy = $divisionStrategy;
+ $this->queue = new \SplQueue();
+ $this->queue->setIteratorMode(\SplQueue::IT_MODE_DELETE);
+ $this->dividedBatches = array();
+ }
+
+ public function add($item)
+ {
+ $this->queue->enqueue($item);
+
+ return $this;
+ }
+
+ public function flush()
+ {
+ $this->createBatches();
+
+ $items = array();
+ foreach ($this->dividedBatches as $batchIndex => $dividedBatch) {
+ while ($dividedBatch->valid()) {
+ $batch = $dividedBatch->current();
+ $dividedBatch->next();
+ try {
+ $this->transferStrategy->transfer($batch);
+ $items = array_merge($items, $batch);
+ } catch (\Exception $e) {
+ throw new BatchTransferException($batch, $items, $e, $this->transferStrategy, $this->divisionStrategy);
+ }
+ }
+ // Keep the divided batch down to a minimum in case of a later exception
+ unset($this->dividedBatches[$batchIndex]);
+ }
+
+ return $items;
+ }
+
+ public function isEmpty()
+ {
+ return count($this->queue) == 0 && count($this->dividedBatches) == 0;
+ }
+
+ /**
+ * Create batches for any queued items
+ */
+ protected function createBatches()
+ {
+ if (count($this->queue)) {
+ if ($batches = $this->divisionStrategy->createBatches($this->queue)) {
+ // Convert arrays into iterators
+ if (is_array($batches)) {
+ $batches = new \ArrayIterator($batches);
+ }
+ $this->dividedBatches[] = $batches;
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php
new file mode 100755
index 0000000..ea99b4d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchBuilder.php
@@ -0,0 +1,199 @@
+ 'Guzzle\Batch\BatchRequestTransfer',
+ 'command' => 'Guzzle\Batch\BatchCommandTransfer'
+ );
+
+ /**
+ * Create a new instance of the BatchBuilder
+ *
+ * @return BatchBuilder
+ */
+ public static function factory()
+ {
+ return new self();
+ }
+
+ /**
+ * Automatically flush the batch when the size of the queue reaches a certain threshold. Adds {@see FlushingBatch}.
+ *
+ * @param $threshold Number of items to allow in the queue before a flush
+ *
+ * @return BatchBuilder
+ */
+ public function autoFlushAt($threshold)
+ {
+ $this->autoFlush = $threshold;
+
+ return $this;
+ }
+
+ /**
+ * Maintain a history of all items that have been transferred using the batch. Adds {@see HistoryBatch}.
+ *
+ * @return BatchBuilder
+ */
+ public function keepHistory()
+ {
+ $this->history = true;
+
+ return $this;
+ }
+
+ /**
+ * Buffer exceptions thrown during transfer so that you can transfer as much as possible, and after a transfer
+ * completes, inspect each exception that was thrown. Enables the {@see ExceptionBufferingBatch} decorator.
+ *
+ * @return BatchBuilder
+ */
+ public function bufferExceptions()
+ {
+ $this->exceptionBuffering = true;
+
+ return $this;
+ }
+
+ /**
+ * Notify a callable each time a batch flush completes. Enables the {@see NotifyingBatch} decorator.
+ *
+ * @param mixed $callable Callable function to notify
+ *
+ * @return BatchBuilder
+ * @throws InvalidArgumentException if the argument is not callable
+ */
+ public function notify($callable)
+ {
+ $this->afterFlush = $callable;
+
+ return $this;
+ }
+
+ /**
+ * Configures the batch to transfer batches of requests. Associates a {@see \Guzzle\Http\BatchRequestTransfer}
+ * object as both the transfer and divisor strategy.
+ *
+ * @param int $batchSize Batch size for each batch of requests
+ *
+ * @return BatchBuilder
+ */
+ public function transferRequests($batchSize = 50)
+ {
+ $className = self::$mapping['request'];
+ $this->transferStrategy = new $className($batchSize);
+ $this->divisorStrategy = $this->transferStrategy;
+
+ return $this;
+ }
+
+ /**
+ * Configures the batch to transfer batches commands. Associates as
+ * {@see \Guzzle\Service\Command\BatchCommandTransfer} as both the transfer and divisor strategy.
+ *
+ * @param int $batchSize Batch size for each batch of commands
+ *
+ * @return BatchBuilder
+ */
+ public function transferCommands($batchSize = 50)
+ {
+ $className = self::$mapping['command'];
+ $this->transferStrategy = new $className($batchSize);
+ $this->divisorStrategy = $this->transferStrategy;
+
+ return $this;
+ }
+
+ /**
+ * Specify the strategy used to divide the queue into an array of batches
+ *
+ * @param BatchDivisorInterface $divisorStrategy Strategy used to divide a batch queue into batches
+ *
+ * @return BatchBuilder
+ */
+ public function createBatchesWith(BatchDivisorInterface $divisorStrategy)
+ {
+ $this->divisorStrategy = $divisorStrategy;
+
+ return $this;
+ }
+
+ /**
+ * Specify the strategy used to transport the items when flush is called
+ *
+ * @param BatchTransferInterface $transferStrategy How items are transferred
+ *
+ * @return BatchBuilder
+ */
+ public function transferWith(BatchTransferInterface $transferStrategy)
+ {
+ $this->transferStrategy = $transferStrategy;
+
+ return $this;
+ }
+
+ /**
+ * Create and return the instantiated batch
+ *
+ * @return BatchInterface
+ * @throws RuntimeException if no transfer strategy has been specified
+ */
+ public function build()
+ {
+ if (!$this->transferStrategy) {
+ throw new RuntimeException('No transfer strategy has been specified');
+ }
+
+ if (!$this->divisorStrategy) {
+ throw new RuntimeException('No divisor strategy has been specified');
+ }
+
+ $batch = new Batch($this->transferStrategy, $this->divisorStrategy);
+
+ if ($this->exceptionBuffering) {
+ $batch = new ExceptionBufferingBatch($batch);
+ }
+
+ if ($this->afterFlush) {
+ $batch = new NotifyingBatch($batch, $this->afterFlush);
+ }
+
+ if ($this->autoFlush) {
+ $batch = new FlushingBatch($batch, $this->autoFlush);
+ }
+
+ if ($this->history) {
+ $batch = new HistoryBatch($batch);
+ }
+
+ return $batch;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php
new file mode 100755
index 0000000..e0a2d95
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureDivisor.php
@@ -0,0 +1,39 @@
+callable = $callable;
+ $this->context = $context;
+ }
+
+ public function createBatches(\SplQueue $queue)
+ {
+ return call_user_func($this->callable, $queue, $this->context);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php
new file mode 100755
index 0000000..9cbf1ab
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchClosureTransfer.php
@@ -0,0 +1,40 @@
+callable = $callable;
+ $this->context = $context;
+ }
+
+ public function transfer(array $batch)
+ {
+ return empty($batch) ? null : call_user_func($this->callable, $batch, $this->context);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php
new file mode 100755
index 0000000..d55ac7d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchCommandTransfer.php
@@ -0,0 +1,75 @@
+batchSize = $batchSize;
+ }
+
+ /**
+ * Creates batches by grouping commands by their associated client
+ * {@inheritdoc}
+ */
+ public function createBatches(\SplQueue $queue)
+ {
+ $groups = new \SplObjectStorage();
+ foreach ($queue as $item) {
+ if (!$item instanceof CommandInterface) {
+ throw new InvalidArgumentException('All items must implement Guzzle\Service\Command\CommandInterface');
+ }
+ $client = $item->getClient();
+ if (!$groups->contains($client)) {
+ $groups->attach($client, new \ArrayObject(array($item)));
+ } else {
+ $groups[$client]->append($item);
+ }
+ }
+
+ $batches = array();
+ foreach ($groups as $batch) {
+ $batches = array_merge($batches, array_chunk($groups[$batch]->getArrayCopy(), $this->batchSize));
+ }
+
+ return $batches;
+ }
+
+ public function transfer(array $batch)
+ {
+ if (empty($batch)) {
+ return;
+ }
+
+ // Get the client of the first found command
+ $client = reset($batch)->getClient();
+
+ // Keep a list of all commands with invalid clients
+ $invalid = array_filter($batch, function ($command) use ($client) {
+ return $command->getClient() !== $client;
+ });
+
+ if (!empty($invalid)) {
+ throw new InconsistentClientTransferException($invalid);
+ }
+
+ $client->execute($batch);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php
new file mode 100755
index 0000000..0214f05
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchDivisorInterface.php
@@ -0,0 +1,18 @@
+batchSize = $batchSize;
+ }
+
+ /**
+ * Creates batches of requests by grouping requests by their associated curl multi object.
+ * {@inheritdoc}
+ */
+ public function createBatches(\SplQueue $queue)
+ {
+ // Create batches by client objects
+ $groups = new \SplObjectStorage();
+ foreach ($queue as $item) {
+ if (!$item instanceof RequestInterface) {
+ throw new InvalidArgumentException('All items must implement Guzzle\Http\Message\RequestInterface');
+ }
+ $client = $item->getClient();
+ if (!$groups->contains($client)) {
+ $groups->attach($client, array($item));
+ } else {
+ $current = $groups[$client];
+ $current[] = $item;
+ $groups[$client] = $current;
+ }
+ }
+
+ $batches = array();
+ foreach ($groups as $batch) {
+ $batches = array_merge($batches, array_chunk($groups[$batch], $this->batchSize));
+ }
+
+ return $batches;
+ }
+
+ public function transfer(array $batch)
+ {
+ if ($batch) {
+ reset($batch)->getClient()->send($batch);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php
new file mode 100755
index 0000000..67f90a5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchSizeDivisor.php
@@ -0,0 +1,47 @@
+size = $size;
+ }
+
+ /**
+ * Set the size of each batch
+ *
+ * @param int $size Size of each batch
+ *
+ * @return BatchSizeDivisor
+ */
+ public function setSize($size)
+ {
+ $this->size = $size;
+
+ return $this;
+ }
+
+ /**
+ * Get the size of each batch
+ *
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function createBatches(\SplQueue $queue)
+ {
+ return array_chunk(iterator_to_array($queue, false), $this->size);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php
new file mode 100755
index 0000000..2e0b60d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/BatchTransferInterface.php
@@ -0,0 +1,16 @@
+batch = $batch;
+ $this->transferredItems = $transferredItems;
+ $this->transferStrategy = $transferStrategy;
+ $this->divisorStrategy = $divisorStrategy;
+ parent::__construct(
+ 'Exception encountered while transferring batch: ' . $exception->getMessage(),
+ $exception->getCode(),
+ $exception
+ );
+ }
+
+ /**
+ * Get the batch that we being sent when the exception occurred
+ *
+ * @return array
+ */
+ public function getBatch()
+ {
+ return $this->batch;
+ }
+
+ /**
+ * Get the items transferred at the point in which the exception was encountered
+ *
+ * @return array
+ */
+ public function getTransferredItems()
+ {
+ return $this->transferredItems;
+ }
+
+ /**
+ * Get the transfer strategy
+ *
+ * @return TransferStrategy
+ */
+ public function getTransferStrategy()
+ {
+ return $this->transferStrategy;
+ }
+
+ /**
+ * Get the divisor strategy
+ *
+ * @return DivisorStrategy
+ */
+ public function getDivisorStrategy()
+ {
+ return $this->divisorStrategy;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php
new file mode 100755
index 0000000..d7a8928
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/ExceptionBufferingBatch.php
@@ -0,0 +1,50 @@
+decoratedBatch->isEmpty()) {
+ try {
+ $transferredItems = $this->decoratedBatch->flush();
+ } catch (BatchTransferException $e) {
+ $this->exceptions[] = $e;
+ $transferredItems = $e->getTransferredItems();
+ }
+ $items = array_merge($items, $transferredItems);
+ }
+
+ return $items;
+ }
+
+ /**
+ * Get the buffered exceptions
+ *
+ * @return array Array of BatchTransferException objects
+ */
+ public function getExceptions()
+ {
+ return $this->exceptions;
+ }
+
+ /**
+ * Clear the buffered exceptions
+ */
+ public function clearExceptions()
+ {
+ $this->exceptions = array();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php
new file mode 100755
index 0000000..367b684
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/FlushingBatch.php
@@ -0,0 +1,60 @@
+threshold = $threshold;
+ parent::__construct($decoratedBatch);
+ }
+
+ /**
+ * Set the auto-flush threshold
+ *
+ * @param int $threshold The auto-flush threshold
+ *
+ * @return FlushingBatch
+ */
+ public function setThreshold($threshold)
+ {
+ $this->threshold = $threshold;
+
+ return $this;
+ }
+
+ /**
+ * Get the auto-flush threshold
+ *
+ * @return int
+ */
+ public function getThreshold()
+ {
+ return $this->threshold;
+ }
+
+ public function add($item)
+ {
+ $this->decoratedBatch->add($item);
+ if (++$this->currentTotal >= $this->threshold) {
+ $this->currentTotal = 0;
+ $this->decoratedBatch->flush();
+ }
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php
new file mode 100755
index 0000000..e345fdc
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/HistoryBatch.php
@@ -0,0 +1,39 @@
+history[] = $item;
+ $this->decoratedBatch->add($item);
+
+ return $this;
+ }
+
+ /**
+ * Get the batch history
+ *
+ * @return array
+ */
+ public function getHistory()
+ {
+ return $this->history;
+ }
+
+ /**
+ * Clear the batch history
+ */
+ public function clearHistory()
+ {
+ $this->history = array();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php
new file mode 100755
index 0000000..96d04da
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/NotifyingBatch.php
@@ -0,0 +1,38 @@
+callable = $callable;
+ parent::__construct($decoratedBatch);
+ }
+
+ public function flush()
+ {
+ $items = $this->decoratedBatch->flush();
+ call_user_func($this->callable, $items);
+
+ return $items;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json
new file mode 100755
index 0000000..12404d3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Batch/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "guzzle/batch",
+ "description": "Guzzle batch component for batching requests, commands, or custom transfers",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["batch", "HTTP", "REST", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/common": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Batch": "" }
+ },
+ "suggest": {
+ "guzzle/http": "self.version",
+ "guzzle/service": "self.version"
+ },
+ "target-dir": "Guzzle/Batch",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php
new file mode 100755
index 0000000..a5c5271
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/AbstractCacheAdapter.php
@@ -0,0 +1,21 @@
+cache;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php
new file mode 100755
index 0000000..94e6234
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterFactory.php
@@ -0,0 +1,117 @@
+newInstanceArgs($args);
+ }
+ } catch (\Exception $e) {
+ throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php
new file mode 100755
index 0000000..970c9e2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/CacheAdapterInterface.php
@@ -0,0 +1,55 @@
+callables = $callables;
+ }
+
+ public function contains($id, array $options = null)
+ {
+ return call_user_func($this->callables['contains'], $id, $options);
+ }
+
+ public function delete($id, array $options = null)
+ {
+ return call_user_func($this->callables['delete'], $id, $options);
+ }
+
+ public function fetch($id, array $options = null)
+ {
+ return call_user_func($this->callables['fetch'], $id, $options);
+ }
+
+ public function save($id, $data, $lifeTime = false, array $options = null)
+ {
+ return call_user_func($this->callables['save'], $id, $data, $lifeTime, $options);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php
new file mode 100755
index 0000000..e1aaf9f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/DoctrineCacheAdapter.php
@@ -0,0 +1,41 @@
+cache = $cache;
+ }
+
+ public function contains($id, array $options = null)
+ {
+ return $this->cache->contains($id);
+ }
+
+ public function delete($id, array $options = null)
+ {
+ return $this->cache->delete($id);
+ }
+
+ public function fetch($id, array $options = null)
+ {
+ return $this->cache->fetch($id);
+ }
+
+ public function save($id, $data, $lifeTime = false, array $options = null)
+ {
+ return $this->cache->save($id, $data, $lifeTime !== false ? $lifeTime : 0);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php
new file mode 100755
index 0000000..68bd4af
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/NullCacheAdapter.php
@@ -0,0 +1,31 @@
+cache = $cache;
+ }
+
+ public function contains($id, array $options = null)
+ {
+ return $this->cache->test($id);
+ }
+
+ public function delete($id, array $options = null)
+ {
+ return $this->cache->remove($id);
+ }
+
+ public function fetch($id, array $options = null)
+ {
+ return $this->cache->load($id);
+ }
+
+ public function save($id, $data, $lifeTime = false, array $options = null)
+ {
+ return $this->cache->save($data, $id, array(), $lifeTime);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php
new file mode 100755
index 0000000..1fc18a5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/Zf2CacheAdapter.php
@@ -0,0 +1,41 @@
+cache = $cache;
+ }
+
+ public function contains($id, array $options = null)
+ {
+ return $this->cache->hasItem($id);
+ }
+
+ public function delete($id, array $options = null)
+ {
+ return $this->cache->removeItem($id);
+ }
+
+ public function fetch($id, array $options = null)
+ {
+ return $this->cache->getItem($id);
+ }
+
+ public function save($id, $data, $lifeTime = false, array $options = null)
+ {
+ return $this->cache->setItem($id, $data);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json
new file mode 100755
index 0000000..a5d999b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Cache/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/cache",
+ "description": "Guzzle cache adapter component",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["cache", "adapter", "zf", "doctrine", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/common": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Cache": "" }
+ },
+ "target-dir": "Guzzle/Cache",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php
new file mode 100755
index 0000000..d1e842b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/AbstractHasDispatcher.php
@@ -0,0 +1,49 @@
+eventDispatcher = $eventDispatcher;
+
+ return $this;
+ }
+
+ public function getEventDispatcher()
+ {
+ if (!$this->eventDispatcher) {
+ $this->eventDispatcher = new EventDispatcher();
+ }
+
+ return $this->eventDispatcher;
+ }
+
+ public function dispatch($eventName, array $context = array())
+ {
+ return $this->getEventDispatcher()->dispatch($eventName, new Event($context));
+ }
+
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ $this->getEventDispatcher()->addSubscriber($subscriber);
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php
new file mode 100755
index 0000000..5cb1535
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Collection.php
@@ -0,0 +1,403 @@
+data = $data;
+ }
+
+ /**
+ * Create a new collection from an array, validate the keys, and add default values where missing
+ *
+ * @param array $config Configuration values to apply.
+ * @param array $defaults Default parameters
+ * @param array $required Required parameter names
+ *
+ * @return self
+ * @throws InvalidArgumentException if a parameter is missing
+ */
+ public static function fromConfig(array $config = array(), array $defaults = array(), array $required = array())
+ {
+ $data = $config + $defaults;
+
+ if ($missing = array_diff($required, array_keys($data))) {
+ throw new InvalidArgumentException('Config is missing the following keys: ' . implode(', ', $missing));
+ }
+
+ return new self($data);
+ }
+
+ public function count()
+ {
+ return count($this->data);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->data);
+ }
+
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Removes all key value pairs
+ *
+ * @return Collection
+ */
+ public function clear()
+ {
+ $this->data = array();
+
+ return $this;
+ }
+
+ /**
+ * Get all or a subset of matching key value pairs
+ *
+ * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs
+ *
+ * @return array Returns an array of all matching key value pairs
+ */
+ public function getAll(array $keys = null)
+ {
+ return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data;
+ }
+
+ /**
+ * Get a specific key value.
+ *
+ * @param string $key Key to retrieve.
+ *
+ * @return mixed|null Value of the key or NULL
+ */
+ public function get($key)
+ {
+ return isset($this->data[$key]) ? $this->data[$key] : null;
+ }
+
+ /**
+ * Set a key value pair
+ *
+ * @param string $key Key to set
+ * @param mixed $value Value to set
+ *
+ * @return Collection Returns a reference to the object
+ */
+ public function set($key, $value)
+ {
+ $this->data[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Add a value to a key. If a key of the same name has already been added, the key value will be converted into an
+ * array and the new value will be pushed to the end of the array.
+ *
+ * @param string $key Key to add
+ * @param mixed $value Value to add to the key
+ *
+ * @return Collection Returns a reference to the object.
+ */
+ public function add($key, $value)
+ {
+ if (!array_key_exists($key, $this->data)) {
+ $this->data[$key] = $value;
+ } elseif (is_array($this->data[$key])) {
+ $this->data[$key][] = $value;
+ } else {
+ $this->data[$key] = array($this->data[$key], $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Remove a specific key value pair
+ *
+ * @param string $key A key to remove
+ *
+ * @return Collection
+ */
+ public function remove($key)
+ {
+ unset($this->data[$key]);
+
+ return $this;
+ }
+
+ /**
+ * Get all keys in the collection
+ *
+ * @return array
+ */
+ public function getKeys()
+ {
+ return array_keys($this->data);
+ }
+
+ /**
+ * Returns whether or not the specified key is present.
+ *
+ * @param string $key The key for which to check the existence.
+ *
+ * @return bool
+ */
+ public function hasKey($key)
+ {
+ return array_key_exists($key, $this->data);
+ }
+
+ /**
+ * Case insensitive search the keys in the collection
+ *
+ * @param string $key Key to search for
+ *
+ * @return bool|string Returns false if not found, otherwise returns the key
+ */
+ public function keySearch($key)
+ {
+ foreach (array_keys($this->data) as $k) {
+ if (!strcasecmp($k, $key)) {
+ return $k;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if any keys contains a certain value
+ *
+ * @param string $value Value to search for
+ *
+ * @return mixed Returns the key if the value was found FALSE if the value was not found.
+ */
+ public function hasValue($value)
+ {
+ return array_search($value, $this->data);
+ }
+
+ /**
+ * Replace the data of the object with the value of an array
+ *
+ * @param array $data Associative array of data
+ *
+ * @return Collection Returns a reference to the object
+ */
+ public function replace(array $data)
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Add and merge in a Collection or array of key value pair data.
+ *
+ * @param Collection|array $data Associative array of key value pair data
+ *
+ * @return Collection Returns a reference to the object.
+ */
+ public function merge($data)
+ {
+ foreach ($data as $key => $value) {
+ $this->add($key, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Over write key value pairs in this collection with all of the data from an array or collection.
+ *
+ * @param array|\Traversable $data Values to override over this config
+ *
+ * @return self
+ */
+ public function overwriteWith($data)
+ {
+ if (is_array($data)) {
+ $this->data = $data + $this->data;
+ } elseif ($data instanceof Collection) {
+ $this->data = $data->toArray() + $this->data;
+ } else {
+ foreach ($data as $key => $value) {
+ $this->data[$key] = $value;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns a Collection containing all the elements of the collection after applying the callback function to each
+ * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a
+ * modified value
+ *
+ * @param \Closure $closure Closure to apply
+ * @param array $context Context to pass to the closure
+ * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection
+ *
+ * @return Collection
+ */
+ public function map(\Closure $closure, array $context = array(), $static = true)
+ {
+ $collection = $static ? new static() : new self();
+ foreach ($this as $key => $value) {
+ $collection->add($key, $closure($key, $value, $context));
+ }
+
+ return $collection;
+ }
+
+ /**
+ * Iterates over each key value pair in the collection passing them to the Closure. If the Closure function returns
+ * true, the current value from input is returned into the result Collection. The Closure must accept three
+ * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value.
+ *
+ * @param \Closure $closure Closure evaluation function
+ * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection
+ *
+ * @return Collection
+ */
+ public function filter(\Closure $closure, $static = true)
+ {
+ $collection = ($static) ? new static() : new self();
+ foreach ($this->data as $key => $value) {
+ if ($closure($key, $value)) {
+ $collection->add($key, $value);
+ }
+ }
+
+ return $collection;
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->data[$offset]);
+ }
+
+ public function offsetGet($offset)
+ {
+ return isset($this->data[$offset]) ? $this->data[$offset] : null;
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->data[$offset] = $value;
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->data[$offset]);
+ }
+
+ /**
+ * Set a value into a nested array key. Keys will be created as needed to set the value.
+ *
+ * @param string $path Path to set
+ * @param mixed $value Value to set at the key
+ *
+ * @return self
+ * @throws RuntimeException when trying to setPath using a nested path that travels through a scalar value
+ */
+ public function setPath($path, $value)
+ {
+ $current =& $this->data;
+ $queue = explode('/', $path);
+ while (null !== ($key = array_shift($queue))) {
+ if (!is_array($current)) {
+ throw new RuntimeException("Trying to setPath {$path}, but {$key} is set and is not an array");
+ } elseif (!$queue) {
+ $current[$key] = $value;
+ } elseif (isset($current[$key])) {
+ $current =& $current[$key];
+ } else {
+ $current[$key] = array();
+ $current =& $current[$key];
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Gets a value from the collection using an array path (e.g. foo/baz/bar would retrieve bar from two nested arrays)
+ * Allows for wildcard searches which recursively combine matches up to the level at which the wildcard occurs. This
+ * can be useful for accepting any key of a sub-array and combining matching keys from each diverging path.
+ *
+ * @param string $path Path to traverse and retrieve a value from
+ * @param string $separator Character used to add depth to the search
+ * @param mixed $data Optional data to descend into (used when wildcards are encountered)
+ *
+ * @return mixed|null
+ */
+ public function getPath($path, $separator = '/', $data = null)
+ {
+ if ($data === null) {
+ $data =& $this->data;
+ }
+
+ $path = is_array($path) ? $path : explode($separator, $path);
+ while (null !== ($part = array_shift($path))) {
+ if (!is_array($data)) {
+ return null;
+ } elseif (isset($data[$part])) {
+ $data =& $data[$part];
+ } elseif ($part != '*') {
+ return null;
+ } else {
+ // Perform a wildcard search by diverging and merging paths
+ $result = array();
+ foreach ($data as $value) {
+ if (!$path) {
+ $result = array_merge_recursive($result, (array) $value);
+ } elseif (null !== ($test = $this->getPath($path, $separator, $value))) {
+ $result = array_merge_recursive($result, (array) $test);
+ }
+ }
+ return $result;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Inject configuration settings into an input string
+ *
+ * @param string $input Input to inject
+ *
+ * @return string
+ * @deprecated
+ */
+ public function inject($input)
+ {
+ Version::warn(__METHOD__ . ' is deprecated');
+ $replace = array();
+ foreach ($this->data as $key => $val) {
+ $replace['{' . $key . '}'] = $val;
+ }
+
+ return strtr($input, $replace);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php
new file mode 100755
index 0000000..fad76a9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Event.php
@@ -0,0 +1,52 @@
+context = $context;
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->context);
+ }
+
+ public function offsetGet($offset)
+ {
+ return isset($this->context[$offset]) ? $this->context[$offset] : null;
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->context[$offset] = $value;
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->context[$offset]);
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->context[$offset]);
+ }
+
+ public function toArray()
+ {
+ return $this->context;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php
new file mode 100755
index 0000000..08d1c72
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/BadMethodCallException.php
@@ -0,0 +1,5 @@
+shortMessage = $message;
+ }
+
+ /**
+ * Set all of the exceptions
+ *
+ * @param array $exceptions Array of exceptions
+ *
+ * @return self
+ */
+ public function setExceptions(array $exceptions)
+ {
+ $this->exceptions = array();
+ foreach ($exceptions as $exception) {
+ $this->add($exception);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add exceptions to the collection
+ *
+ * @param ExceptionCollection|\Exception $e Exception to add
+ *
+ * @return ExceptionCollection;
+ */
+ public function add($e)
+ {
+ $this->exceptions[] = $e;
+ if ($this->message) {
+ $this->message .= "\n";
+ }
+
+ $this->message .= $this->getExceptionMessage($e, 0);
+
+ return $this;
+ }
+
+ /**
+ * Get the total number of request exceptions
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->exceptions);
+ }
+
+ /**
+ * Allows array-like iteration over the request exceptions
+ *
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->exceptions);
+ }
+
+ /**
+ * Get the first exception in the collection
+ *
+ * @return \Exception
+ */
+ public function getFirst()
+ {
+ return $this->exceptions ? $this->exceptions[0] : null;
+ }
+
+ private function getExceptionMessage(\Exception $e, $depth = 0)
+ {
+ static $sp = ' ';
+ $prefix = $depth ? str_repeat($sp, $depth) : '';
+ $message = "{$prefix}(" . get_class($e) . ') ' . $e->getFile() . ' line ' . $e->getLine() . "\n";
+
+ if ($e instanceof self) {
+ if ($e->shortMessage) {
+ $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->shortMessage) . "\n";
+ }
+ foreach ($e as $ee) {
+ $message .= "\n" . $this->getExceptionMessage($ee, $depth + 1);
+ }
+ } else {
+ $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->getMessage()) . "\n";
+ $message .= "\n{$prefix}{$sp}" . str_replace("\n", "\n{$prefix}{$sp}", $e->getTraceAsString()) . "\n";
+ }
+
+ return str_replace(getcwd(), '.', $message);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php
new file mode 100755
index 0000000..458e6f2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Common/Exception/GuzzleException.php
@@ -0,0 +1,8 @@
+=5.3.2",
+ "symfony/event-dispatcher": ">=2.1"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Common": "" }
+ },
+ "target-dir": "Guzzle/Common",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php
new file mode 100755
index 0000000..5005a88
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/AbstractEntityBodyDecorator.php
@@ -0,0 +1,221 @@
+body = $body;
+ }
+
+ public function __toString()
+ {
+ return (string) $this->body;
+ }
+
+ /**
+ * Allow decorators to implement custom methods
+ *
+ * @param string $method Missing method name
+ * @param array $args Method arguments
+ *
+ * @return mixed
+ */
+ public function __call($method, array $args)
+ {
+ return call_user_func_array(array($this->body, $method), $args);
+ }
+
+ public function close()
+ {
+ return $this->body->close();
+ }
+
+ public function setRewindFunction($callable)
+ {
+ $this->body->setRewindFunction($callable);
+
+ return $this;
+ }
+
+ public function rewind()
+ {
+ return $this->body->rewind();
+ }
+
+ public function compress($filter = 'zlib.deflate')
+ {
+ return $this->body->compress($filter);
+ }
+
+ public function uncompress($filter = 'zlib.inflate')
+ {
+ return $this->body->uncompress($filter);
+ }
+
+ public function getContentLength()
+ {
+ return $this->getSize();
+ }
+
+ public function getContentType()
+ {
+ return $this->body->getContentType();
+ }
+
+ public function getContentMd5($rawOutput = false, $base64Encode = false)
+ {
+ $hash = Stream::getHash($this, 'md5', $rawOutput);
+
+ return $hash && $base64Encode ? base64_encode($hash) : $hash;
+ }
+
+ public function getContentEncoding()
+ {
+ return $this->body->getContentEncoding();
+ }
+
+ public function getMetaData($key = null)
+ {
+ return $this->body->getMetaData($key);
+ }
+
+ public function getStream()
+ {
+ return $this->body->getStream();
+ }
+
+ public function setStream($stream, $size = 0)
+ {
+ $this->body->setStream($stream, $size);
+
+ return $this;
+ }
+
+ public function detachStream()
+ {
+ $this->body->detachStream();
+
+ return $this;
+ }
+
+ public function getWrapper()
+ {
+ return $this->body->getWrapper();
+ }
+
+ public function getWrapperData()
+ {
+ return $this->body->getWrapperData();
+ }
+
+ public function getStreamType()
+ {
+ return $this->body->getStreamType();
+ }
+
+ public function getUri()
+ {
+ return $this->body->getUri();
+ }
+
+ public function getSize()
+ {
+ return $this->body->getSize();
+ }
+
+ public function isReadable()
+ {
+ return $this->body->isReadable();
+ }
+
+ public function isRepeatable()
+ {
+ return $this->isSeekable() && $this->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->body->isWritable();
+ }
+
+ public function isConsumed()
+ {
+ return $this->body->isConsumed();
+ }
+
+ /**
+ * Alias of isConsumed()
+ * {@inheritdoc}
+ */
+ public function feof()
+ {
+ return $this->isConsumed();
+ }
+
+ public function isLocal()
+ {
+ return $this->body->isLocal();
+ }
+
+ public function isSeekable()
+ {
+ return $this->body->isSeekable();
+ }
+
+ public function setSize($size)
+ {
+ $this->body->setSize($size);
+
+ return $this;
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ return $this->body->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->body->read($length);
+ }
+
+ public function write($string)
+ {
+ return $this->body->write($string);
+ }
+
+ public function readLine($maxLength = null)
+ {
+ return $this->body->readLine($maxLength);
+ }
+
+ public function ftell()
+ {
+ return $this->body->ftell();
+ }
+
+ public function getCustomData($key)
+ {
+ return $this->body->getCustomData($key);
+ }
+
+ public function setCustomData($key, $value)
+ {
+ $this->body->setCustomData($key, $value);
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php
new file mode 100755
index 0000000..c65c136
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/CachingEntityBody.php
@@ -0,0 +1,229 @@
+remoteStream = $body;
+ $this->body = new EntityBody(fopen('php://temp', 'r+'));
+ }
+
+ /**
+ * Will give the contents of the buffer followed by the exhausted remote stream.
+ *
+ * Warning: Loads the entire stream into memory
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $pos = $this->ftell();
+ $this->rewind();
+
+ $str = '';
+ while (!$this->isConsumed()) {
+ $str .= $this->read(16384);
+ }
+
+ $this->seek($pos);
+
+ return $str;
+ }
+
+ public function getSize()
+ {
+ return max($this->body->getSize(), $this->remoteStream->getSize());
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws RuntimeException When seeking with SEEK_END or when seeking past the total size of the buffer stream
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence == SEEK_SET) {
+ $byte = $offset;
+ } elseif ($whence == SEEK_CUR) {
+ $byte = $offset + $this->ftell();
+ } else {
+ throw new RuntimeException(__CLASS__ . ' supports only SEEK_SET and SEEK_CUR seek operations');
+ }
+
+ // You cannot skip ahead past where you've read from the remote stream
+ if ($byte > $this->body->getSize()) {
+ throw new RuntimeException(
+ "Cannot seek to byte {$byte} when the buffered stream only contains {$this->body->getSize()} bytes"
+ );
+ }
+
+ return $this->body->seek($byte);
+ }
+
+ public function rewind()
+ {
+ return $this->seek(0);
+ }
+
+ /**
+ * Does not support custom rewind functions
+ *
+ * @throws RuntimeException
+ */
+ public function setRewindFunction($callable)
+ {
+ throw new RuntimeException(__CLASS__ . ' does not support custom stream rewind functions');
+ }
+
+ public function read($length)
+ {
+ // Perform a regular read on any previously read data from the buffer
+ $data = $this->body->read($length);
+ $remaining = $length - strlen($data);
+
+ // More data was requested so read from the remote stream
+ if ($remaining) {
+ // If data was written to the buffer in a position that would have been filled from the remote stream,
+ // then we must skip bytes on the remote stream to emulate overwriting bytes from that position. This
+ // mimics the behavior of other PHP stream wrappers.
+ $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes);
+
+ if ($this->skipReadBytes) {
+ $len = strlen($remoteData);
+ $remoteData = substr($remoteData, $this->skipReadBytes);
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
+ }
+
+ $data .= $remoteData;
+ $this->body->write($remoteData);
+ }
+
+ return $data;
+ }
+
+ public function write($string)
+ {
+ // When appending to the end of the currently read stream, you'll want to skip bytes from being read from
+ // the remote stream to emulate other stream wrappers. Basically replacing bytes of data of a fixed length.
+ $overflow = (strlen($string) + $this->ftell()) - $this->remoteStream->ftell();
+ if ($overflow > 0) {
+ $this->skipReadBytes += $overflow;
+ }
+
+ return $this->body->write($string);
+ }
+
+ /**
+ * {@inheritdoc}
+ * @link http://php.net/manual/en/function.fgets.php
+ */
+ public function readLine($maxLength = null)
+ {
+ $buffer = '';
+ $size = 0;
+ while (!$this->isConsumed()) {
+ $byte = $this->read(1);
+ $buffer .= $byte;
+ // Break when a new line is found or the max length - 1 is reached
+ if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
+ break;
+ }
+ }
+
+ return $buffer;
+ }
+
+ public function isConsumed()
+ {
+ return $this->body->isConsumed() && $this->remoteStream->isConsumed();
+ }
+
+ /**
+ * Close both the remote stream and buffer stream
+ */
+ public function close()
+ {
+ return $this->remoteStream->close() && $this->body->close();
+ }
+
+ public function setStream($stream, $size = 0)
+ {
+ $this->remoteStream->setStream($stream, $size);
+ }
+
+ public function getContentType()
+ {
+ return $this->remoteStream->getContentType();
+ }
+
+ public function getContentEncoding()
+ {
+ return $this->remoteStream->getContentEncoding();
+ }
+
+ public function getMetaData($key = null)
+ {
+ return $this->remoteStream->getMetaData($key);
+ }
+
+ public function getStream()
+ {
+ return $this->remoteStream->getStream();
+ }
+
+ public function getWrapper()
+ {
+ return $this->remoteStream->getWrapper();
+ }
+
+ public function getWrapperData()
+ {
+ return $this->remoteStream->getWrapperData();
+ }
+
+ public function getStreamType()
+ {
+ return $this->remoteStream->getStreamType();
+ }
+
+ public function getUri()
+ {
+ return $this->remoteStream->getUri();
+ }
+
+ /**
+ * Always retrieve custom data from the remote stream
+ * {@inheritdoc}
+ */
+ public function getCustomData($key)
+ {
+ return $this->remoteStream->getCustomData($key);
+ }
+
+ /**
+ * Always set custom data on the remote stream
+ * {@inheritdoc}
+ */
+ public function setCustomData($key, $value)
+ {
+ $this->remoteStream->setCustomData($key, $value);
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php
new file mode 100755
index 0000000..3d7298d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php
@@ -0,0 +1,524 @@
+setConfig($config ?: new Collection());
+ $this->initSsl();
+ $this->setBaseUrl($baseUrl);
+ $this->defaultHeaders = new Collection();
+ $this->setRequestFactory(RequestFactory::getInstance());
+ $this->userAgent = $this->getDefaultUserAgent();
+ if (!$this->config[self::DISABLE_REDIRECTS]) {
+ $this->addSubscriber(new RedirectPlugin());
+ }
+ }
+
+ final public function setConfig($config)
+ {
+ if ($config instanceof Collection) {
+ $this->config = $config;
+ } elseif (is_array($config)) {
+ $this->config = new Collection($config);
+ } else {
+ throw new InvalidArgumentException('Config must be an array or Collection');
+ }
+
+ return $this;
+ }
+
+ final public function getConfig($key = false)
+ {
+ return $key ? $this->config[$key] : $this->config;
+ }
+
+ /**
+ * Set a default request option on the client that will be used as a default for each request
+ *
+ * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo)
+ * @param mixed $value Value to set
+ *
+ * @return $this
+ */
+ public function setDefaultOption($keyOrPath, $value)
+ {
+ $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath;
+ $this->config->setPath($keyOrPath, $value);
+
+ return $this;
+ }
+
+ /**
+ * Retrieve a default request option from the client
+ *
+ * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo)
+ *
+ * @return mixed|null
+ */
+ public function getDefaultOption($keyOrPath)
+ {
+ $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath;
+
+ return $this->config->getPath($keyOrPath);
+ }
+
+ final public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2)
+ {
+ $opts = $this->config[self::CURL_OPTIONS] ?: array();
+
+ if ($certificateAuthority === true) {
+ // use bundled CA bundle, set secure defaults
+ $opts[CURLOPT_CAINFO] = __DIR__ . '/Resources/cacert.pem';
+ $opts[CURLOPT_SSL_VERIFYPEER] = true;
+ $opts[CURLOPT_SSL_VERIFYHOST] = 2;
+ } elseif ($certificateAuthority === false) {
+ unset($opts[CURLOPT_CAINFO]);
+ $opts[CURLOPT_SSL_VERIFYPEER] = false;
+ $opts[CURLOPT_SSL_VERIFYHOST] = 0;
+ } elseif ($verifyPeer !== true && $verifyPeer !== false && $verifyPeer !== 1 && $verifyPeer !== 0) {
+ throw new InvalidArgumentException('verifyPeer must be 1, 0 or boolean');
+ } elseif ($verifyHost !== 0 && $verifyHost !== 1 && $verifyHost !== 2) {
+ throw new InvalidArgumentException('verifyHost must be 0, 1 or 2');
+ } else {
+ $opts[CURLOPT_SSL_VERIFYPEER] = $verifyPeer;
+ $opts[CURLOPT_SSL_VERIFYHOST] = $verifyHost;
+ if (is_file($certificateAuthority)) {
+ unset($opts[CURLOPT_CAPATH]);
+ $opts[CURLOPT_CAINFO] = $certificateAuthority;
+ } elseif (is_dir($certificateAuthority)) {
+ unset($opts[CURLOPT_CAINFO]);
+ $opts[CURLOPT_CAPATH] = $certificateAuthority;
+ } else {
+ throw new RuntimeException(
+ 'Invalid option passed to ' . self::SSL_CERT_AUTHORITY . ': ' . $certificateAuthority
+ );
+ }
+ }
+
+ $this->config->set(self::CURL_OPTIONS, $opts);
+
+ return $this;
+ }
+
+ public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array())
+ {
+ if (!$uri) {
+ $url = $this->getBaseUrl();
+ } else {
+ if (!is_array($uri)) {
+ $templateVars = null;
+ } else {
+ list($uri, $templateVars) = $uri;
+ }
+ if (strpos($uri, '://')) {
+ // Use absolute URLs as-is
+ $url = $this->expandTemplate($uri, $templateVars);
+ } else {
+ $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars));
+ }
+ }
+
+ // If default headers are provided, then merge them under any explicitly provided headers for the request
+ if (count($this->defaultHeaders)) {
+ if (!$headers) {
+ $headers = $this->defaultHeaders->toArray();
+ } elseif (is_array($headers)) {
+ $headers += $this->defaultHeaders->toArray();
+ } elseif ($headers instanceof Collection) {
+ $headers = $headers->toArray() + $this->defaultHeaders->toArray();
+ }
+ }
+
+ return $this->prepareRequest($this->requestFactory->create($method, (string) $url, $headers, $body), $options);
+ }
+
+ public function getBaseUrl($expand = true)
+ {
+ return $expand ? $this->expandTemplate($this->baseUrl) : $this->baseUrl;
+ }
+
+ public function setBaseUrl($url)
+ {
+ $this->baseUrl = $url;
+
+ return $this;
+ }
+
+ public function setUserAgent($userAgent, $includeDefault = false)
+ {
+ if ($includeDefault) {
+ $userAgent .= ' ' . $this->getDefaultUserAgent();
+ }
+ $this->userAgent = $userAgent;
+
+ return $this;
+ }
+
+ /**
+ * Get the default User-Agent string to use with Guzzle
+ *
+ * @return string
+ */
+ public function getDefaultUserAgent()
+ {
+ return 'Guzzle/' . Version::VERSION
+ . ' curl/' . CurlVersion::getInstance()->get('version')
+ . ' PHP/' . PHP_VERSION;
+ }
+
+ public function get($uri = null, $headers = null, $options = array())
+ {
+ // BC compat: $options can be a string, resource, etc to specify where the response body is downloaded
+ return is_array($options)
+ ? $this->createRequest('GET', $uri, $headers, null, $options)
+ : $this->createRequest('GET', $uri, $headers, $options);
+ }
+
+ public function head($uri = null, $headers = null, array $options = array())
+ {
+ return $this->createRequest('HEAD', $uri, $headers, null, $options);
+ }
+
+ public function delete($uri = null, $headers = null, $body = null, array $options = array())
+ {
+ return $this->createRequest('DELETE', $uri, $headers, $body, $options);
+ }
+
+ public function put($uri = null, $headers = null, $body = null, array $options = array())
+ {
+ return $this->createRequest('PUT', $uri, $headers, $body, $options);
+ }
+
+ public function patch($uri = null, $headers = null, $body = null, array $options = array())
+ {
+ return $this->createRequest('PATCH', $uri, $headers, $body, $options);
+ }
+
+ public function post($uri = null, $headers = null, $postBody = null, array $options = array())
+ {
+ return $this->createRequest('POST', $uri, $headers, $postBody, $options);
+ }
+
+ public function options($uri = null, array $options = array())
+ {
+ return $this->createRequest('OPTIONS', $uri, $options);
+ }
+
+ public function send($requests)
+ {
+ if (!($requests instanceof RequestInterface)) {
+ return $this->sendMultiple($requests);
+ }
+
+ try {
+ /** @var $requests RequestInterface */
+ $this->getCurlMulti()->add($requests)->send();
+ return $requests->getResponse();
+ } catch (ExceptionCollection $e) {
+ throw $e->getFirst();
+ }
+ }
+
+ /**
+ * Set a curl multi object to be used internally by the client for transferring requests.
+ *
+ * @param CurlMultiInterface $curlMulti Multi object
+ *
+ * @return self
+ */
+ public function setCurlMulti(CurlMultiInterface $curlMulti)
+ {
+ $this->curlMulti = $curlMulti;
+
+ return $this;
+ }
+
+ /**
+ * @return CurlMultiInterface|CurlMultiProxy
+ */
+ public function getCurlMulti()
+ {
+ if (!$this->curlMulti) {
+ $this->curlMulti = new CurlMultiProxy(
+ self::MAX_HANDLES,
+ $this->getConfig('select_timeout') ?: self::DEFAULT_SELECT_TIMEOUT
+ );
+ }
+
+ return $this->curlMulti;
+ }
+
+ public function setRequestFactory(RequestFactoryInterface $factory)
+ {
+ $this->requestFactory = $factory;
+
+ return $this;
+ }
+
+ /**
+ * Set the URI template expander to use with the client
+ *
+ * @param UriTemplateInterface $uriTemplate URI template expander
+ *
+ * @return self
+ */
+ public function setUriTemplate(UriTemplateInterface $uriTemplate)
+ {
+ $this->uriTemplate = $uriTemplate;
+
+ return $this;
+ }
+
+ /**
+ * Expand a URI template while merging client config settings into the template variables
+ *
+ * @param string $template Template to expand
+ * @param array $variables Variables to inject
+ *
+ * @return string
+ */
+ protected function expandTemplate($template, array $variables = null)
+ {
+ $expansionVars = $this->getConfig()->toArray();
+ if ($variables) {
+ $expansionVars = $variables + $expansionVars;
+ }
+
+ return $this->getUriTemplate()->expand($template, $expansionVars);
+ }
+
+ /**
+ * Get the URI template expander used by the client
+ *
+ * @return UriTemplateInterface
+ */
+ protected function getUriTemplate()
+ {
+ if (!$this->uriTemplate) {
+ $this->uriTemplate = ParserRegistry::getInstance()->getParser('uri_template');
+ }
+
+ return $this->uriTemplate;
+ }
+
+ /**
+ * Send multiple requests in parallel
+ *
+ * @param array $requests Array of RequestInterface objects
+ *
+ * @return array Returns an array of Response objects
+ */
+ protected function sendMultiple(array $requests)
+ {
+ $curlMulti = $this->getCurlMulti();
+ foreach ($requests as $request) {
+ $curlMulti->add($request);
+ }
+ $curlMulti->send();
+
+ /** @var $request RequestInterface */
+ $result = array();
+ foreach ($requests as $request) {
+ $result[] = $request->getResponse();
+ }
+
+ return $result;
+ }
+
+ /**
+ * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request.
+ *
+ * @param RequestInterface $request Request to prepare for the client
+ * @param array $options Options to apply to the request
+ *
+ * @return RequestInterface
+ */
+ protected function prepareRequest(RequestInterface $request, array $options = array())
+ {
+ $request->setClient($this)->setEventDispatcher(clone $this->getEventDispatcher());
+
+ if ($curl = $this->config[self::CURL_OPTIONS]) {
+ $request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($curl));
+ }
+
+ if ($params = $this->config[self::REQUEST_PARAMS]) {
+ Version::warn('request.params is deprecated. Use request.options to add default request options.');
+ $request->getParams()->overwriteWith($params);
+ }
+
+ if ($this->userAgent && !$request->hasHeader('User-Agent')) {
+ $request->setHeader('User-Agent', $this->userAgent);
+ }
+
+ if ($defaults = $this->config[self::REQUEST_OPTIONS]) {
+ $this->requestFactory->applyOptions($request, $defaults, RequestFactoryInterface::OPTIONS_AS_DEFAULTS);
+ }
+
+ if ($options) {
+ $this->requestFactory->applyOptions($request, $options);
+ }
+
+ $this->dispatch('client.create_request', array('client' => $this, 'request' => $request));
+
+ return $request;
+ }
+
+ /**
+ * Initializes SSL settings
+ */
+ protected function initSsl()
+ {
+ $authority = $this->config[self::SSL_CERT_AUTHORITY];
+
+ if ($authority === 'system') {
+ return;
+ }
+
+ if ($authority === null) {
+ $authority = true;
+ }
+
+ if ($authority === true && substr(__FILE__, 0, 7) == 'phar://') {
+ $authority = self::extractPharCacert(__DIR__ . '/Resources/cacert.pem');
+ }
+
+ $this->setSslVerification($authority);
+ }
+
+ /**
+ * @deprecated
+ */
+ public function getDefaultHeaders()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to retrieve default request options');
+ return $this->defaultHeaders;
+ }
+
+ /**
+ * @deprecated
+ */
+ public function setDefaultHeaders($headers)
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to specify default request options');
+ if ($headers instanceof Collection) {
+ $this->defaultHeaders = $headers;
+ } elseif (is_array($headers)) {
+ $this->defaultHeaders = new Collection($headers);
+ } else {
+ throw new InvalidArgumentException('Headers must be an array or Collection');
+ }
+
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ */
+ public function preparePharCacert($md5Check = true)
+ {
+ return sys_get_temp_dir() . '/guzzle-cacert.pem';
+ }
+
+ /**
+ * Copies the phar cacert from a phar into the temp directory.
+ *
+ * @param string $pharCacertPath Path to the phar cacert. For example:
+ * 'phar://aws.phar/Guzzle/Http/Resources/cacert.pem'
+ *
+ * @return string Returns the path to the extracted cacert file.
+ * @throws \RuntimeException Throws if the phar cacert cannot be found or
+ * the file cannot be copied to the temp dir.
+ */
+ public static function extractPharCacert($pharCacertPath)
+ {
+ // Copy the cacert.pem file from the phar if it is not in the temp
+ // folder.
+ $certFile = sys_get_temp_dir() . '/guzzle-cacert.pem';
+
+ if (!file_exists($pharCacertPath)) {
+ throw new \RuntimeException("Could not find $pharCacertPath");
+ }
+
+ if (!file_exists($certFile) ||
+ filesize($certFile) != filesize($pharCacertPath)
+ ) {
+ if (!copy($pharCacertPath, $certFile)) {
+ throw new \RuntimeException(
+ "Could not copy {$pharCacertPath} to {$certFile}: "
+ . var_export(error_get_last(), true)
+ );
+ }
+ }
+
+ return $certFile;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php
new file mode 100755
index 0000000..10e4de2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/ClientInterface.php
@@ -0,0 +1,223 @@
+getCurlOptions();
+ $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io'));
+ $tempContentLength = null;
+ $method = $request->getMethod();
+ $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING);
+
+ // Prepare url
+ $url = (string)$request->getUrl();
+ if(($pos = strpos($url, '#')) !== false ){
+ // strip fragment from url
+ $url = substr($url, 0, $pos);
+ }
+
+ // Array of default cURL options.
+ $curlOptions = array(
+ CURLOPT_URL => $url,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_RETURNTRANSFER => false,
+ CURLOPT_HEADER => false,
+ CURLOPT_PORT => $request->getPort(),
+ CURLOPT_HTTPHEADER => array(),
+ CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'),
+ CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'),
+ CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0'
+ ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1,
+ // Verifies the authenticity of the peer's certificate
+ CURLOPT_SSL_VERIFYPEER => 1,
+ // Certificate must indicate that the server is the server to which you meant to connect
+ CURLOPT_SSL_VERIFYHOST => 2
+ );
+
+ if (defined('CURLOPT_PROTOCOLS')) {
+ // Allow only HTTP and HTTPS protocols
+ $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
+ }
+
+ // Add CURLOPT_ENCODING if Accept-Encoding header is provided
+ if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) {
+ $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader;
+ // Let cURL set the Accept-Encoding header, prevents duplicate values
+ $request->removeHeader('Accept-Encoding');
+ }
+
+ // Enable curl debug information if the 'debug' param was set
+ if ($requestCurlOptions->get('debug')) {
+ $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+');
+ // @codeCoverageIgnoreStart
+ if (false === $curlOptions[CURLOPT_STDERR]) {
+ throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR');
+ }
+ // @codeCoverageIgnoreEnd
+ $curlOptions[CURLOPT_VERBOSE] = true;
+ }
+
+ // Specify settings according to the HTTP method
+ if ($method == 'GET') {
+ $curlOptions[CURLOPT_HTTPGET] = true;
+ } elseif ($method == 'HEAD') {
+ $curlOptions[CURLOPT_NOBODY] = true;
+ // HEAD requests do not use a write function
+ unset($curlOptions[CURLOPT_WRITEFUNCTION]);
+ } elseif (!($request instanceof EntityEnclosingRequest)) {
+ $curlOptions[CURLOPT_CUSTOMREQUEST] = $method;
+ } else {
+
+ $curlOptions[CURLOPT_CUSTOMREQUEST] = $method;
+
+ // Handle sending raw bodies in a request
+ if ($request->getBody()) {
+ // You can send the body as a string using curl's CURLOPT_POSTFIELDS
+ if ($bodyAsString) {
+ $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody();
+ // Allow curl to add the Content-Length for us to account for the times when
+ // POST redirects are followed by GET requests
+ if ($tempContentLength = $request->getHeader('Content-Length')) {
+ $tempContentLength = (int) (string) $tempContentLength;
+ }
+ // Remove the curl generated Content-Type header if none was set manually
+ if (!$request->hasHeader('Content-Type')) {
+ $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:';
+ }
+ } else {
+ $curlOptions[CURLOPT_UPLOAD] = true;
+ // Let cURL handle setting the Content-Length header
+ if ($tempContentLength = $request->getHeader('Content-Length')) {
+ $tempContentLength = (int) (string) $tempContentLength;
+ $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength;
+ }
+ // Add a callback for curl to read data to send with the request only if a body was specified
+ $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody');
+ // Attempt to seek to the start of the stream
+ $request->getBody()->seek(0);
+ }
+
+ } else {
+
+ // Special handling for POST specific fields and files
+ $postFields = false;
+ if (count($request->getPostFiles())) {
+ $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode();
+ foreach ($request->getPostFiles() as $key => $data) {
+ $prefixKeys = count($data) > 1;
+ foreach ($data as $index => $file) {
+ // Allow multiple files in the same key
+ $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key;
+ $postFields[$fieldKey] = $file->getCurlValue();
+ }
+ }
+ } elseif (count($request->getPostFields())) {
+ $postFields = (string) $request->getPostFields()->useUrlEncoding(true);
+ }
+
+ if ($postFields !== false) {
+ if ($method == 'POST') {
+ unset($curlOptions[CURLOPT_CUSTOMREQUEST]);
+ $curlOptions[CURLOPT_POST] = true;
+ }
+ $curlOptions[CURLOPT_POSTFIELDS] = $postFields;
+ $request->removeHeader('Content-Length');
+ }
+ }
+
+ // If the Expect header is not present, prevent curl from adding it
+ if (!$request->hasHeader('Expect')) {
+ $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:';
+ }
+ }
+
+ // If a Content-Length header was specified but we want to allow curl to set one for us
+ if (null !== $tempContentLength) {
+ $request->removeHeader('Content-Length');
+ }
+
+ // Set custom cURL options
+ foreach ($requestCurlOptions->toArray() as $key => $value) {
+ if (is_numeric($key)) {
+ $curlOptions[$key] = $value;
+ }
+ }
+
+ // Do not set an Accept header by default
+ if (!isset($curlOptions[CURLOPT_ENCODING])) {
+ $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:';
+ }
+
+ // Add any custom headers to the request. Empty headers will cause curl to not send the header at all.
+ foreach ($request->getHeaderLines() as $line) {
+ $curlOptions[CURLOPT_HTTPHEADER][] = $line;
+ }
+
+ // Add the content-length header back if it was temporarily removed
+ if (null !== $tempContentLength) {
+ $request->setHeader('Content-Length', $tempContentLength);
+ }
+
+ // Apply the options to a new cURL handle.
+ $handle = curl_init();
+
+ // Enable the progress function if the 'progress' param was set
+ if ($requestCurlOptions->get('progress')) {
+ // Wrap the function in a function that provides the curl handle to the mediator's progress function
+ // Using this rather than injecting the handle into the mediator prevents a circular reference
+ $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use ($mediator, $handle) {
+ $args = func_get_args();
+ $args[] = $handle;
+
+ // PHP 5.5 pushed the handle onto the start of the args
+ if (is_resource($args[0])) {
+ array_shift($args);
+ }
+
+ call_user_func_array(array($mediator, 'progress'), $args);
+ };
+ $curlOptions[CURLOPT_NOPROGRESS] = false;
+ }
+
+ curl_setopt_array($handle, $curlOptions);
+
+ return new static($handle, $curlOptions);
+ }
+
+ /**
+ * Construct a new CurlHandle object that wraps a cURL handle
+ *
+ * @param resource $handle Configured cURL handle resource
+ * @param Collection|array $options Curl options to use with the handle
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($handle, $options)
+ {
+ if (!is_resource($handle)) {
+ throw new InvalidArgumentException('Invalid handle provided');
+ }
+ if (is_array($options)) {
+ $this->options = new Collection($options);
+ } elseif ($options instanceof Collection) {
+ $this->options = $options;
+ } else {
+ throw new InvalidArgumentException('Expected array or Collection');
+ }
+ $this->handle = $handle;
+ }
+
+ /**
+ * Destructor
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ /**
+ * Close the curl handle
+ */
+ public function close()
+ {
+ if (is_resource($this->handle)) {
+ curl_close($this->handle);
+ }
+ $this->handle = null;
+ }
+
+ /**
+ * Check if the handle is available and still OK
+ *
+ * @return bool
+ */
+ public function isAvailable()
+ {
+ return is_resource($this->handle);
+ }
+
+ /**
+ * Get the last error that occurred on the cURL handle
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ return $this->isAvailable() ? curl_error($this->handle) : '';
+ }
+
+ /**
+ * Get the last error number that occurred on the cURL handle
+ *
+ * @return int
+ */
+ public function getErrorNo()
+ {
+ if ($this->errorNo) {
+ return $this->errorNo;
+ }
+
+ return $this->isAvailable() ? curl_errno($this->handle) : CURLE_OK;
+ }
+
+ /**
+ * Set the curl error number
+ *
+ * @param int $error Error number to set
+ *
+ * @return CurlHandle
+ */
+ public function setErrorNo($error)
+ {
+ $this->errorNo = $error;
+
+ return $this;
+ }
+
+ /**
+ * Get cURL curl_getinfo data
+ *
+ * @param int $option Option to retrieve. Pass null to retrieve all data as an array.
+ *
+ * @return array|mixed
+ */
+ public function getInfo($option = null)
+ {
+ if (!is_resource($this->handle)) {
+ return null;
+ }
+
+ if (null !== $option) {
+ return curl_getinfo($this->handle, $option) ?: null;
+ }
+
+ return curl_getinfo($this->handle) ?: array();
+ }
+
+ /**
+ * Get the stderr output
+ *
+ * @param bool $asResource Set to TRUE to get an fopen resource
+ *
+ * @return string|resource|null
+ */
+ public function getStderr($asResource = false)
+ {
+ $stderr = $this->getOptions()->get(CURLOPT_STDERR);
+ if (!$stderr) {
+ return null;
+ }
+
+ if ($asResource) {
+ return $stderr;
+ }
+
+ fseek($stderr, 0);
+ $e = stream_get_contents($stderr);
+ fseek($stderr, 0, SEEK_END);
+
+ return $e;
+ }
+
+ /**
+ * Get the URL that this handle is connecting to
+ *
+ * @return Url
+ */
+ public function getUrl()
+ {
+ return Url::factory($this->options->get(CURLOPT_URL));
+ }
+
+ /**
+ * Get the wrapped curl handle
+ *
+ * @return resource|null Returns the cURL handle or null if it was closed
+ */
+ public function getHandle()
+ {
+ return $this->isAvailable() ? $this->handle : null;
+ }
+
+ /**
+ * Get the cURL setopt options of the handle. Changing values in the return object will have no effect on the curl
+ * handle after it is created.
+ *
+ * @return Collection
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Update a request based on the log messages of the CurlHandle
+ *
+ * @param RequestInterface $request Request to update
+ */
+ public function updateRequestFromTransfer(RequestInterface $request)
+ {
+ if (!$request->getResponse()) {
+ return;
+ }
+
+ // Update the transfer stats of the response
+ $request->getResponse()->setInfo($this->getInfo());
+
+ if (!$log = $this->getStderr(true)) {
+ return;
+ }
+
+ // Parse the cURL stderr output for outgoing requests
+ $headers = '';
+ fseek($log, 0);
+ while (($line = fgets($log)) !== false) {
+ if ($line && $line[0] == '>') {
+ $headers = substr(trim($line), 2) . "\r\n";
+ while (($line = fgets($log)) !== false) {
+ if ($line[0] == '*' || $line[0] == '<') {
+ break;
+ } else {
+ $headers .= trim($line) . "\r\n";
+ }
+ }
+ }
+ }
+
+ // Add request headers to the request exactly as they were sent
+ if ($headers) {
+ $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($headers);
+ if (!empty($parsed['headers'])) {
+ $request->setHeaders(array());
+ foreach ($parsed['headers'] as $name => $value) {
+ $request->setHeader($name, $value);
+ }
+ }
+ if (!empty($parsed['version'])) {
+ $request->setProtocolVersion($parsed['version']);
+ }
+ }
+ }
+
+ /**
+ * Parse the config and replace curl.* configurators into the constant based values so it can be used elsewhere
+ *
+ * @param array|Collection $config The configuration we want to parse
+ *
+ * @return array
+ */
+ public static function parseCurlConfig($config)
+ {
+ $curlOptions = array();
+ foreach ($config as $key => $value) {
+ if (is_string($key) && defined($key)) {
+ // Convert constants represented as string to constant int values
+ $key = constant($key);
+ }
+ if (is_string($value) && defined($value)) {
+ $value = constant($value);
+ }
+ $curlOptions[$key] = $value;
+ }
+
+ return $curlOptions;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
new file mode 100755
index 0000000..9e4e637
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
@@ -0,0 +1,423 @@
+ array('CURLM_BAD_HANDLE', 'The passed-in handle is not a valid CURLM handle.'),
+ CURLM_BAD_EASY_HANDLE => array('CURLM_BAD_EASY_HANDLE', "An easy handle was not good/valid. It could mean that it isn't an easy handle at all, or possibly that the handle already is in used by this or another multi handle."),
+ CURLM_OUT_OF_MEMORY => array('CURLM_OUT_OF_MEMORY', 'You are doomed.'),
+ CURLM_INTERNAL_ERROR => array('CURLM_INTERNAL_ERROR', 'This can only be returned if libcurl bugs. Please report it to us!')
+ );
+
+ /** @var float */
+ protected $selectTimeout;
+
+ public function __construct($selectTimeout = 1.0)
+ {
+ $this->selectTimeout = $selectTimeout;
+ $this->multiHandle = curl_multi_init();
+ // @codeCoverageIgnoreStart
+ if ($this->multiHandle === false) {
+ throw new CurlException('Unable to create multi handle');
+ }
+ // @codeCoverageIgnoreEnd
+ $this->reset();
+ }
+
+ public function __destruct()
+ {
+ if (is_resource($this->multiHandle)) {
+ curl_multi_close($this->multiHandle);
+ }
+ }
+
+ public function add(RequestInterface $request)
+ {
+ $this->requests[] = $request;
+ // If requests are currently transferring and this is async, then the
+ // request must be prepared now as the send() method is not called.
+ $this->beforeSend($request);
+ $this->dispatch(self::ADD_REQUEST, array('request' => $request));
+
+ return $this;
+ }
+
+ public function all()
+ {
+ return $this->requests;
+ }
+
+ public function remove(RequestInterface $request)
+ {
+ $this->removeHandle($request);
+ if (($index = array_search($request, $this->requests, true)) !== false) {
+ $request = $this->requests[$index];
+ unset($this->requests[$index]);
+ $this->requests = array_values($this->requests);
+ $this->dispatch(self::REMOVE_REQUEST, array('request' => $request));
+ return true;
+ }
+
+ return false;
+ }
+
+ public function reset($hard = false)
+ {
+ // Remove each request
+ if ($this->requests) {
+ foreach ($this->requests as $request) {
+ $this->remove($request);
+ }
+ }
+
+ $this->handles = new \SplObjectStorage();
+ $this->requests = $this->resourceHash = $this->exceptions = $this->successful = array();
+ }
+
+ public function send()
+ {
+ $this->perform();
+ $exceptions = $this->exceptions;
+ $successful = $this->successful;
+ $this->reset();
+
+ if ($exceptions) {
+ $this->throwMultiException($exceptions, $successful);
+ }
+ }
+
+ public function count()
+ {
+ return count($this->requests);
+ }
+
+ /**
+ * Build and throw a MultiTransferException
+ *
+ * @param array $exceptions Exceptions encountered
+ * @param array $successful Successful requests
+ * @throws MultiTransferException
+ */
+ protected function throwMultiException(array $exceptions, array $successful)
+ {
+ $multiException = new MultiTransferException('Errors during multi transfer');
+
+ while ($e = array_shift($exceptions)) {
+ $multiException->addFailedRequestWithException($e['request'], $e['exception']);
+ }
+
+ // Add successful requests
+ foreach ($successful as $request) {
+ if (!$multiException->containsRequest($request)) {
+ $multiException->addSuccessfulRequest($request);
+ }
+ }
+
+ throw $multiException;
+ }
+
+ /**
+ * Prepare for sending
+ *
+ * @param RequestInterface $request Request to prepare
+ * @throws \Exception on error preparing the request
+ */
+ protected function beforeSend(RequestInterface $request)
+ {
+ try {
+ $state = $request->setState(RequestInterface::STATE_TRANSFER);
+ if ($state == RequestInterface::STATE_TRANSFER) {
+ $this->addHandle($request);
+ } else {
+ // Requests might decide they don't need to be sent just before
+ // transfer (e.g. CachePlugin)
+ $this->remove($request);
+ if ($state == RequestInterface::STATE_COMPLETE) {
+ $this->successful[] = $request;
+ }
+ }
+ } catch (\Exception $e) {
+ // Queue the exception to be thrown when sent
+ $this->removeErroredRequest($request, $e);
+ }
+ }
+
+ private function addHandle(RequestInterface $request)
+ {
+ $handle = $this->createCurlHandle($request)->getHandle();
+ $this->checkCurlResult(
+ curl_multi_add_handle($this->multiHandle, $handle)
+ );
+ }
+
+ /**
+ * Create a curl handle for a request
+ *
+ * @param RequestInterface $request Request
+ *
+ * @return CurlHandle
+ */
+ protected function createCurlHandle(RequestInterface $request)
+ {
+ $wrapper = CurlHandle::factory($request);
+ $this->handles[$request] = $wrapper;
+ $this->resourceHash[(int) $wrapper->getHandle()] = $request;
+
+ return $wrapper;
+ }
+
+ /**
+ * Get the data from the multi handle
+ */
+ protected function perform()
+ {
+ $event = new Event(array('curl_multi' => $this));
+
+ while ($this->requests) {
+ // Notify each request as polling
+ $blocking = $total = 0;
+ foreach ($this->requests as $request) {
+ ++$total;
+ $event['request'] = $request;
+ $request->getEventDispatcher()->dispatch(self::POLLING_REQUEST, $event);
+ // The blocking variable just has to be non-falsey to block the loop
+ if ($request->getParams()->hasKey(self::BLOCKING)) {
+ ++$blocking;
+ }
+ }
+ if ($blocking == $total) {
+ // Sleep to prevent eating CPU because no requests are actually pending a select call
+ usleep(500);
+ } else {
+ $this->executeHandles();
+ }
+ }
+ }
+
+ /**
+ * Execute and select curl handles
+ */
+ private function executeHandles()
+ {
+ // The first curl_multi_select often times out no matter what, but is usually required for fast transfers
+ $selectTimeout = 0.001;
+ $active = false;
+ do {
+ while (($mrc = curl_multi_exec($this->multiHandle, $active)) == CURLM_CALL_MULTI_PERFORM);
+ $this->checkCurlResult($mrc);
+ $this->processMessages();
+ if ($active && curl_multi_select($this->multiHandle, $selectTimeout) === -1) {
+ // Perform a usleep if a select returns -1: https://bugs.php.net/bug.php?id=61141
+ usleep(150);
+ }
+ $selectTimeout = $this->selectTimeout;
+ } while ($active);
+ }
+
+ /**
+ * Process any received curl multi messages
+ */
+ private function processMessages()
+ {
+ while ($done = curl_multi_info_read($this->multiHandle)) {
+ $request = $this->resourceHash[(int) $done['handle']];
+ try {
+ $this->processResponse($request, $this->handles[$request], $done);
+ $this->successful[] = $request;
+ } catch (\Exception $e) {
+ $this->removeErroredRequest($request, $e);
+ }
+ }
+ }
+
+ /**
+ * Remove a request that encountered an exception
+ *
+ * @param RequestInterface $request Request to remove
+ * @param \Exception $e Exception encountered
+ */
+ protected function removeErroredRequest(RequestInterface $request, \Exception $e = null)
+ {
+ $this->exceptions[] = array('request' => $request, 'exception' => $e);
+ $this->remove($request);
+ $this->dispatch(self::MULTI_EXCEPTION, array('exception' => $e, 'all_exceptions' => $this->exceptions));
+ }
+
+ /**
+ * Check for errors and fix headers of a request based on a curl response
+ *
+ * @param RequestInterface $request Request to process
+ * @param CurlHandle $handle Curl handle object
+ * @param array $curl Array returned from curl_multi_info_read
+ *
+ * @throws CurlException on Curl error
+ */
+ protected function processResponse(RequestInterface $request, CurlHandle $handle, array $curl)
+ {
+ // Set the transfer stats on the response
+ $handle->updateRequestFromTransfer($request);
+ // Check if a cURL exception occurred, and if so, notify things
+ $curlException = $this->isCurlException($request, $handle, $curl);
+
+ // Always remove completed curl handles. They can be added back again
+ // via events if needed (e.g. ExponentialBackoffPlugin)
+ $this->removeHandle($request);
+
+ if (!$curlException) {
+ if ($this->validateResponseWasSet($request)) {
+ $state = $request->setState(
+ RequestInterface::STATE_COMPLETE,
+ array('handle' => $handle)
+ );
+ // Only remove the request if it wasn't resent as a result of
+ // the state change
+ if ($state != RequestInterface::STATE_TRANSFER) {
+ $this->remove($request);
+ }
+ }
+ return;
+ }
+
+ // Set the state of the request to an error
+ $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $curlException));
+ // Allow things to ignore the error if possible
+ if ($state != RequestInterface::STATE_TRANSFER) {
+ $this->remove($request);
+ }
+
+ // The error was not handled, so fail
+ if ($state == RequestInterface::STATE_ERROR) {
+ /** @var CurlException $curlException */
+ throw $curlException;
+ }
+ }
+
+ /**
+ * Remove a curl handle from the curl multi object
+ *
+ * @param RequestInterface $request Request that owns the handle
+ */
+ protected function removeHandle(RequestInterface $request)
+ {
+ if (isset($this->handles[$request])) {
+ $handle = $this->handles[$request];
+ curl_multi_remove_handle($this->multiHandle, $handle->getHandle());
+ unset($this->handles[$request]);
+ unset($this->resourceHash[(int) $handle->getHandle()]);
+ $handle->close();
+ }
+ }
+
+ /**
+ * Check if a cURL transfer resulted in what should be an exception
+ *
+ * @param RequestInterface $request Request to check
+ * @param CurlHandle $handle Curl handle object
+ * @param array $curl Array returned from curl_multi_info_read
+ *
+ * @return CurlException|bool
+ */
+ private function isCurlException(RequestInterface $request, CurlHandle $handle, array $curl)
+ {
+ if (CURLM_OK == $curl['result'] || CURLM_CALL_MULTI_PERFORM == $curl['result']) {
+ return false;
+ }
+
+ $handle->setErrorNo($curl['result']);
+ $e = new CurlException(sprintf('[curl] %s: %s [url] %s',
+ $handle->getErrorNo(), $handle->getError(), $handle->getUrl()));
+ $e->setCurlHandle($handle)
+ ->setRequest($request)
+ ->setCurlInfo($handle->getInfo())
+ ->setError($handle->getError(), $handle->getErrorNo());
+
+ return $e;
+ }
+
+ /**
+ * Throw an exception for a cURL multi response if needed
+ *
+ * @param int $code Curl response code
+ * @throws CurlException
+ */
+ private function checkCurlResult($code)
+ {
+ if ($code != CURLM_OK && $code != CURLM_CALL_MULTI_PERFORM) {
+ throw new CurlException(isset($this->multiErrors[$code])
+ ? "cURL error: {$code} ({$this->multiErrors[$code][0]}): cURL message: {$this->multiErrors[$code][1]}"
+ : 'Unexpected cURL error: ' . $code
+ );
+ }
+ }
+
+ /**
+ * @link https://github.com/guzzle/guzzle/issues/710
+ */
+ private function validateResponseWasSet(RequestInterface $request)
+ {
+ if ($request->getResponse()) {
+ return true;
+ }
+
+ $body = $request instanceof EntityEnclosingRequestInterface
+ ? $request->getBody()
+ : null;
+
+ if (!$body) {
+ $rex = new RequestException(
+ 'No response was received for a request with no body. This'
+ . ' could mean that you are saturating your network.'
+ );
+ $rex->setRequest($request);
+ $this->removeErroredRequest($request, $rex);
+ } elseif (!$body->isSeekable() || !$body->seek(0)) {
+ // Nothing we can do with this. Sorry!
+ $rex = new RequestException(
+ 'The connection was unexpectedly closed. The request would'
+ . ' have been retried, but attempting to rewind the'
+ . ' request body failed.'
+ );
+ $rex->setRequest($request);
+ $this->removeErroredRequest($request, $rex);
+ } else {
+ $this->remove($request);
+ // Add the request back to the batch to retry automatically.
+ $this->requests[] = $request;
+ $this->addHandle($request);
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php
new file mode 100755
index 0000000..0ead757
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiInterface.php
@@ -0,0 +1,58 @@
+maxHandles = $maxHandles;
+ $this->selectTimeout = $selectTimeout;
+ // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel.
+ // These two statements autoload classes before a system runs out of file descriptors so that you can get back
+ // valuable error messages if you run out.
+ class_exists('Guzzle\Http\Message\Response');
+ class_exists('Guzzle\Http\Exception\CurlException');
+ }
+
+ public function add(RequestInterface $request)
+ {
+ $this->queued[] = $request;
+
+ return $this;
+ }
+
+ public function all()
+ {
+ $requests = $this->queued;
+ foreach ($this->handles as $handle) {
+ $requests = array_merge($requests, $handle->all());
+ }
+
+ return $requests;
+ }
+
+ public function remove(RequestInterface $request)
+ {
+ foreach ($this->queued as $i => $r) {
+ if ($request === $r) {
+ unset($this->queued[$i]);
+ return true;
+ }
+ }
+
+ foreach ($this->handles as $handle) {
+ if ($handle->remove($request)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function reset($hard = false)
+ {
+ $this->queued = array();
+ $this->groups = array();
+ foreach ($this->handles as $handle) {
+ $handle->reset();
+ }
+ if ($hard) {
+ $this->handles = array();
+ }
+
+ return $this;
+ }
+
+ public function send()
+ {
+ if ($this->queued) {
+ $group = $this->getAvailableHandle();
+ // Add this handle to a list of handles than is claimed
+ $this->groups[] = $group;
+ while ($request = array_shift($this->queued)) {
+ $group->add($request);
+ }
+ try {
+ $group->send();
+ array_pop($this->groups);
+ $this->cleanupHandles();
+ } catch (\Exception $e) {
+ // Remove the group and cleanup if an exception was encountered and no more requests in group
+ if (!$group->count()) {
+ array_pop($this->groups);
+ $this->cleanupHandles();
+ }
+ throw $e;
+ }
+ }
+ }
+
+ public function count()
+ {
+ return count($this->all());
+ }
+
+ /**
+ * Get an existing available CurlMulti handle or create a new one
+ *
+ * @return CurlMulti
+ */
+ protected function getAvailableHandle()
+ {
+ // Grab a handle that is not claimed
+ foreach ($this->handles as $h) {
+ if (!in_array($h, $this->groups, true)) {
+ return $h;
+ }
+ }
+
+ // All are claimed, so create one
+ $handle = new CurlMulti($this->selectTimeout);
+ $handle->setEventDispatcher($this->getEventDispatcher());
+ $this->handles[] = $handle;
+
+ return $handle;
+ }
+
+ /**
+ * Trims down unused CurlMulti handles to limit the number of open connections
+ */
+ protected function cleanupHandles()
+ {
+ if ($diff = max(0, count($this->handles) - $this->maxHandles)) {
+ for ($i = count($this->handles) - 1; $i > 0 && $diff > 0; $i--) {
+ if (!count($this->handles[$i])) {
+ unset($this->handles[$i]);
+ $diff--;
+ }
+ }
+ $this->handles = array_values($this->handles);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php
new file mode 100755
index 0000000..c3f99dd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlVersion.php
@@ -0,0 +1,66 @@
+version) {
+ $this->version = curl_version();
+ }
+
+ return $this->version;
+ }
+
+ /**
+ * Get a specific type of curl information
+ *
+ * @param string $type Version information to retrieve. This value is one of:
+ * - version_number: cURL 24 bit version number
+ * - version: cURL version number, as a string
+ * - ssl_version_number: OpenSSL 24 bit version number
+ * - ssl_version: OpenSSL version number, as a string
+ * - libz_version: zlib version number, as a string
+ * - host: Information about the host where cURL was built
+ * - features: A bitmask of the CURL_VERSION_XXX constants
+ * - protocols: An array of protocols names supported by cURL
+ *
+ * @return string|float|bool if the $type is found, and false if not found
+ */
+ public function get($type)
+ {
+ $version = $this->getAll();
+
+ return isset($version[$type]) ? $version[$type] : false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php
new file mode 100755
index 0000000..5d1a0cd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/RequestMediator.php
@@ -0,0 +1,147 @@
+request = $request;
+ $this->emitIo = $emitIo;
+ }
+
+ /**
+ * Receive a response header from curl
+ *
+ * @param resource $curl Curl handle
+ * @param string $header Received header
+ *
+ * @return int
+ */
+ public function receiveResponseHeader($curl, $header)
+ {
+ static $normalize = array("\r", "\n");
+ $length = strlen($header);
+ $header = str_replace($normalize, '', $header);
+
+ if (strpos($header, 'HTTP/') === 0) {
+
+ $startLine = explode(' ', $header, 3);
+ $code = $startLine[1];
+ $status = isset($startLine[2]) ? $startLine[2] : '';
+
+ // Only download the body of the response to the specified response
+ // body when a successful response is received.
+ if ($code >= 200 && $code < 300) {
+ $body = $this->request->getResponseBody();
+ } else {
+ $body = EntityBody::factory();
+ }
+
+ $response = new Response($code, null, $body);
+ $response->setStatus($code, $status);
+ $this->request->startResponse($response);
+
+ $this->request->dispatch('request.receive.status_line', array(
+ 'request' => $this,
+ 'line' => $header,
+ 'status_code' => $code,
+ 'reason_phrase' => $status
+ ));
+
+ } elseif ($pos = strpos($header, ':')) {
+ $this->request->getResponse()->addHeader(
+ trim(substr($header, 0, $pos)),
+ trim(substr($header, $pos + 1))
+ );
+ }
+
+ return $length;
+ }
+
+ /**
+ * Received a progress notification
+ *
+ * @param int $downloadSize Total download size
+ * @param int $downloaded Amount of bytes downloaded
+ * @param int $uploadSize Total upload size
+ * @param int $uploaded Amount of bytes uploaded
+ * @param resource $handle CurlHandle object
+ */
+ public function progress($downloadSize, $downloaded, $uploadSize, $uploaded, $handle = null)
+ {
+ $this->request->dispatch('curl.callback.progress', array(
+ 'request' => $this->request,
+ 'handle' => $handle,
+ 'download_size' => $downloadSize,
+ 'downloaded' => $downloaded,
+ 'upload_size' => $uploadSize,
+ 'uploaded' => $uploaded
+ ));
+ }
+
+ /**
+ * Write data to the response body of a request
+ *
+ * @param resource $curl Curl handle
+ * @param string $write Data that was received
+ *
+ * @return int
+ */
+ public function writeResponseBody($curl, $write)
+ {
+ if ($this->emitIo) {
+ $this->request->dispatch('curl.callback.write', array(
+ 'request' => $this->request,
+ 'write' => $write
+ ));
+ }
+
+ if ($response = $this->request->getResponse()) {
+ return $response->getBody()->write($write);
+ } else {
+ // Unexpected data received before response headers - abort transfer
+ return 0;
+ }
+ }
+
+ /**
+ * Read data from the request body and send it to curl
+ *
+ * @param resource $ch Curl handle
+ * @param resource $fd File descriptor
+ * @param int $length Amount of data to read
+ *
+ * @return string
+ */
+ public function readRequestBody($ch, $fd, $length)
+ {
+ if (!($body = $this->request->getBody())) {
+ return '';
+ }
+
+ $read = (string) $body->read($length);
+ if ($this->emitIo) {
+ $this->request->dispatch('curl.callback.read', array('request' => $this->request, 'read' => $read));
+ }
+
+ return $read;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php
new file mode 100755
index 0000000..b60d170
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBody.php
@@ -0,0 +1,201 @@
+rewindFunction = $callable;
+
+ return $this;
+ }
+
+ public function rewind()
+ {
+ return $this->rewindFunction ? call_user_func($this->rewindFunction, $this) : parent::rewind();
+ }
+
+ /**
+ * Create a new EntityBody from a string
+ *
+ * @param string $string String of data
+ *
+ * @return EntityBody
+ */
+ public static function fromString($string)
+ {
+ $stream = fopen('php://temp', 'r+');
+ if ($string !== '') {
+ fwrite($stream, $string);
+ rewind($stream);
+ }
+
+ return new static($stream);
+ }
+
+ public function compress($filter = 'zlib.deflate')
+ {
+ $result = $this->handleCompression($filter);
+ $this->contentEncoding = $result ? $filter : false;
+
+ return $result;
+ }
+
+ public function uncompress($filter = 'zlib.inflate')
+ {
+ $offsetStart = 0;
+
+ // When inflating gzipped data, the first 10 bytes must be stripped
+ // if a gzip header is present
+ if ($filter == 'zlib.inflate') {
+ // @codeCoverageIgnoreStart
+ if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) {
+ return false;
+ }
+ // @codeCoverageIgnoreEnd
+ if (stream_get_contents($this->stream, 3, 0) === "\x1f\x8b\x08") {
+ $offsetStart = 10;
+ }
+ }
+
+ $this->contentEncoding = false;
+
+ return $this->handleCompression($filter, $offsetStart);
+ }
+
+ public function getContentLength()
+ {
+ return $this->getSize();
+ }
+
+ public function getContentType()
+ {
+ return $this->getUri() ? Mimetypes::getInstance()->fromFilename($this->getUri()) : null;
+ }
+
+ public function getContentMd5($rawOutput = false, $base64Encode = false)
+ {
+ if ($hash = self::getHash($this, 'md5', $rawOutput)) {
+ return $hash && $base64Encode ? base64_encode($hash) : $hash;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Calculate the MD5 hash of an entity body
+ *
+ * @param EntityBodyInterface $body Entity body to calculate the hash for
+ * @param bool $rawOutput Whether or not to use raw output
+ * @param bool $base64Encode Whether or not to base64 encode raw output (only if raw output is true)
+ *
+ * @return bool|string Returns an MD5 string on success or FALSE on failure
+ * @deprecated This will be deprecated soon
+ * @codeCoverageIgnore
+ */
+ public static function calculateMd5(EntityBodyInterface $body, $rawOutput = false, $base64Encode = false)
+ {
+ Version::warn(__CLASS__ . ' is deprecated. Use getContentMd5()');
+ return $body->getContentMd5($rawOutput, $base64Encode);
+ }
+
+ public function setStreamFilterContentEncoding($streamFilterContentEncoding)
+ {
+ $this->contentEncoding = $streamFilterContentEncoding;
+
+ return $this;
+ }
+
+ public function getContentEncoding()
+ {
+ return strtr($this->contentEncoding, array(
+ 'zlib.deflate' => 'gzip',
+ 'bzip2.compress' => 'compress'
+ )) ?: false;
+ }
+
+ protected function handleCompression($filter, $offsetStart = 0)
+ {
+ // @codeCoverageIgnoreStart
+ if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) {
+ return false;
+ }
+ // @codeCoverageIgnoreEnd
+
+ $handle = fopen('php://temp', 'r+');
+ $filter = @stream_filter_append($handle, $filter, STREAM_FILTER_WRITE);
+ if (!$filter) {
+ return false;
+ }
+
+ // Seek to the offset start if possible
+ $this->seek($offsetStart);
+ while ($data = fread($this->stream, 8096)) {
+ fwrite($handle, $data);
+ }
+
+ fclose($this->stream);
+ $this->stream = $handle;
+ stream_filter_remove($filter);
+ $stat = fstat($this->stream);
+ $this->size = $stat['size'];
+ $this->rebuildCache();
+ $this->seek(0);
+
+ // Remove any existing rewind function as the underlying stream has been replaced
+ $this->rewindFunction = null;
+
+ return true;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php
new file mode 100755
index 0000000..e640f57
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/EntityBodyInterface.php
@@ -0,0 +1,73 @@
+isClientError()) {
+ $label = 'Client error response';
+ $class = __NAMESPACE__ . '\\ClientErrorResponseException';
+ } elseif ($response->isServerError()) {
+ $label = 'Server error response';
+ $class = __NAMESPACE__ . '\\ServerErrorResponseException';
+ } else {
+ $label = 'Unsuccessful response';
+ $class = __CLASS__;
+ }
+
+ $message = $label . PHP_EOL . implode(PHP_EOL, array(
+ '[status code] ' . $response->getStatusCode(),
+ '[reason phrase] ' . $response->getReasonPhrase(),
+ '[url] ' . $request->getUrl(),
+ ));
+
+ $e = new $class($message);
+ $e->setResponse($response);
+ $e->setRequest($request);
+
+ return $e;
+ }
+
+ /**
+ * Set the response that caused the exception
+ *
+ * @param Response $response Response to set
+ */
+ public function setResponse(Response $response)
+ {
+ $this->response = $response;
+ }
+
+ /**
+ * Get the response that caused the exception
+ *
+ * @return Response
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php
new file mode 100755
index 0000000..04d7ddc
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ClientErrorResponseException.php
@@ -0,0 +1,8 @@
+curlError = $error;
+ $this->curlErrorNo = $number;
+
+ return $this;
+ }
+
+ /**
+ * Set the associated curl handle
+ *
+ * @param CurlHandle $handle Curl handle
+ *
+ * @return self
+ */
+ public function setCurlHandle(CurlHandle $handle)
+ {
+ $this->handle = $handle;
+
+ return $this;
+ }
+
+ /**
+ * Get the associated cURL handle
+ *
+ * @return CurlHandle|null
+ */
+ public function getCurlHandle()
+ {
+ return $this->handle;
+ }
+
+ /**
+ * Get the associated cURL error message
+ *
+ * @return string|null
+ */
+ public function getError()
+ {
+ return $this->curlError;
+ }
+
+ /**
+ * Get the associated cURL error number
+ *
+ * @return int|null
+ */
+ public function getErrorNo()
+ {
+ return $this->curlErrorNo;
+ }
+
+ /**
+ * Returns curl information about the transfer
+ *
+ * @return array
+ */
+ public function getCurlInfo()
+ {
+ return $this->curlInfo;
+ }
+
+ /**
+ * Set curl transfer information
+ *
+ * @param array $info Array of curl transfer information
+ *
+ * @return self
+ * @link http://php.net/manual/en/function.curl-getinfo.php
+ */
+ public function setCurlInfo(array $info)
+ {
+ $this->curlInfo = $info;
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php
new file mode 100755
index 0000000..ee87295
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/HttpException.php
@@ -0,0 +1,10 @@
+successfulRequests, $this->failedRequests);
+ }
+
+ /**
+ * Add to the array of successful requests
+ *
+ * @param RequestInterface $request Successful request
+ *
+ * @return self
+ */
+ public function addSuccessfulRequest(RequestInterface $request)
+ {
+ $this->successfulRequests[] = $request;
+
+ return $this;
+ }
+
+ /**
+ * Add to the array of failed requests
+ *
+ * @param RequestInterface $request Failed request
+ *
+ * @return self
+ */
+ public function addFailedRequest(RequestInterface $request)
+ {
+ $this->failedRequests[] = $request;
+
+ return $this;
+ }
+
+ /**
+ * Add to the array of failed requests and associate with exceptions
+ *
+ * @param RequestInterface $request Failed request
+ * @param \Exception $exception Exception to add and associate with
+ *
+ * @return self
+ */
+ public function addFailedRequestWithException(RequestInterface $request, \Exception $exception)
+ {
+ $this->add($exception)
+ ->addFailedRequest($request)
+ ->exceptionForRequest[spl_object_hash($request)] = $exception;
+
+ return $this;
+ }
+
+ /**
+ * Get the Exception that caused the given $request to fail
+ *
+ * @param RequestInterface $request Failed command
+ *
+ * @return \Exception|null
+ */
+ public function getExceptionForFailedRequest(RequestInterface $request)
+ {
+ $oid = spl_object_hash($request);
+
+ return isset($this->exceptionForRequest[$oid]) ? $this->exceptionForRequest[$oid] : null;
+ }
+
+ /**
+ * Set all of the successful requests
+ *
+ * @param array Array of requests
+ *
+ * @return self
+ */
+ public function setSuccessfulRequests(array $requests)
+ {
+ $this->successfulRequests = $requests;
+
+ return $this;
+ }
+
+ /**
+ * Set all of the failed requests
+ *
+ * @param array Array of requests
+ *
+ * @return self
+ */
+ public function setFailedRequests(array $requests)
+ {
+ $this->failedRequests = $requests;
+
+ return $this;
+ }
+
+ /**
+ * Get an array of successful requests sent in the multi transfer
+ *
+ * @return array
+ */
+ public function getSuccessfulRequests()
+ {
+ return $this->successfulRequests;
+ }
+
+ /**
+ * Get an array of failed requests sent in the multi transfer
+ *
+ * @return array
+ */
+ public function getFailedRequests()
+ {
+ return $this->failedRequests;
+ }
+
+ /**
+ * Check if the exception object contains a request
+ *
+ * @param RequestInterface $request Request to check
+ *
+ * @return bool
+ */
+ public function containsRequest(RequestInterface $request)
+ {
+ return in_array($request, $this->failedRequests, true) || in_array($request, $this->successfulRequests, true);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php
new file mode 100755
index 0000000..274df2c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/RequestException.php
@@ -0,0 +1,39 @@
+request = $request;
+
+ return $this;
+ }
+
+ /**
+ * Get the request that caused the exception
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php
new file mode 100755
index 0000000..f0f7cfe
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/ServerErrorResponseException.php
@@ -0,0 +1,8 @@
+eventDispatcher = $eventDispatcher;
+
+ return $this;
+ }
+
+ public function getEventDispatcher()
+ {
+ if (!$this->eventDispatcher) {
+ $this->eventDispatcher = new EventDispatcher();
+ }
+
+ return $this->eventDispatcher;
+ }
+
+ public function dispatch($eventName, array $context = array())
+ {
+ return $this->getEventDispatcher()->dispatch($eventName, new Event($context));
+ }
+
+ /**
+ * {@inheritdoc}
+ * @codeCoverageIgnore
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ $this->getEventDispatcher()->addSubscriber($subscriber);
+
+ return $this;
+ }
+
+ public function read($length)
+ {
+ $event = array(
+ 'body' => $this,
+ 'length' => $length,
+ 'read' => $this->body->read($length)
+ );
+ $this->dispatch('body.read', $event);
+
+ return $event['read'];
+ }
+
+ public function write($string)
+ {
+ $event = array(
+ 'body' => $this,
+ 'write' => $string,
+ 'result' => $this->body->write($string)
+ );
+ $this->dispatch('body.write', $event);
+
+ return $event['result'];
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php
new file mode 100755
index 0000000..0d066ff
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/AbstractMessage.php
@@ -0,0 +1,220 @@
+params = new Collection();
+ $this->headerFactory = new HeaderFactory();
+ $this->headers = new HeaderCollection();
+ }
+
+ /**
+ * Set the header factory to use to create headers
+ *
+ * @param HeaderFactoryInterface $factory
+ *
+ * @return self
+ */
+ public function setHeaderFactory(HeaderFactoryInterface $factory)
+ {
+ $this->headerFactory = $factory;
+
+ return $this;
+ }
+
+ public function getParams()
+ {
+ return $this->params;
+ }
+
+ public function addHeader($header, $value)
+ {
+ if (isset($this->headers[$header])) {
+ $this->headers[$header]->add($value);
+ } elseif ($value instanceof HeaderInterface) {
+ $this->headers[$header] = $value;
+ } else {
+ $this->headers[$header] = $this->headerFactory->createHeader($header, $value);
+ }
+
+ return $this;
+ }
+
+ public function addHeaders(array $headers)
+ {
+ foreach ($headers as $key => $value) {
+ $this->addHeader($key, $value);
+ }
+
+ return $this;
+ }
+
+ public function getHeader($header)
+ {
+ return $this->headers[$header];
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ public function getHeaderLines()
+ {
+ $headers = array();
+ foreach ($this->headers as $value) {
+ $headers[] = $value->getName() . ': ' . $value;
+ }
+
+ return $headers;
+ }
+
+ public function setHeader($header, $value)
+ {
+ unset($this->headers[$header]);
+ $this->addHeader($header, $value);
+
+ return $this;
+ }
+
+ public function setHeaders(array $headers)
+ {
+ $this->headers->clear();
+ foreach ($headers as $key => $value) {
+ $this->addHeader($key, $value);
+ }
+
+ return $this;
+ }
+
+ public function hasHeader($header)
+ {
+ return isset($this->headers[$header]);
+ }
+
+ public function removeHeader($header)
+ {
+ unset($this->headers[$header]);
+
+ return $this;
+ }
+
+ /**
+ * @deprecated Use $message->getHeader()->parseParams()
+ * @codeCoverageIgnore
+ */
+ public function getTokenizedHeader($header, $token = ';')
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader()->parseParams()');
+ if ($this->hasHeader($header)) {
+ $data = new Collection();
+ foreach ($this->getHeader($header)->parseParams() as $values) {
+ foreach ($values as $key => $value) {
+ if ($value === '') {
+ $data->set($data->count(), $key);
+ } else {
+ $data->add($key, $value);
+ }
+ }
+ }
+ return $data;
+ }
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setTokenizedHeader($header, $data, $token = ';')
+ {
+ Version::warn(__METHOD__ . ' is deprecated.');
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getCacheControlDirective($directive)
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->getDirective()');
+ if (!($header = $this->getHeader('Cache-Control'))) {
+ return null;
+ }
+
+ return $header->getDirective($directive);
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function hasCacheControlDirective($directive)
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->hasDirective()');
+ if ($header = $this->getHeader('Cache-Control')) {
+ return $header->hasDirective($directive);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function addCacheControlDirective($directive, $value = true)
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->addDirective()');
+ if (!($header = $this->getHeader('Cache-Control'))) {
+ $this->addHeader('Cache-Control', '');
+ $header = $this->getHeader('Cache-Control');
+ }
+
+ $header->addDirective($directive, $value);
+
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function removeCacheControlDirective($directive)
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->removeDirective()');
+ if ($header = $this->getHeader('Cache-Control')) {
+ $header->removeDirective($directive);
+ }
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php
new file mode 100755
index 0000000..212850a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php
@@ -0,0 +1,247 @@
+postFields = new QueryString();
+ parent::__construct($method, $url, $headers);
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ // Only attempt to include the POST data if it's only fields
+ if (count($this->postFields) && empty($this->postFiles)) {
+ return parent::__toString() . (string) $this->postFields;
+ }
+
+ return parent::__toString() . $this->body;
+ }
+
+ public function setState($state, array $context = array())
+ {
+ parent::setState($state, $context);
+ if ($state == self::STATE_TRANSFER && !$this->body && !count($this->postFields) && !count($this->postFiles)) {
+ $this->setHeader('Content-Length', 0)->removeHeader('Transfer-Encoding');
+ }
+
+ return $this->state;
+ }
+
+ public function setBody($body, $contentType = null)
+ {
+ $this->body = EntityBody::factory($body);
+
+ // Auto detect the Content-Type from the path of the request if possible
+ if ($contentType === null && !$this->hasHeader('Content-Type')) {
+ $contentType = $this->body->getContentType();
+ }
+
+ if ($contentType) {
+ $this->setHeader('Content-Type', $contentType);
+ }
+
+ // Always add the Expect 100-Continue header if the body cannot be rewound. This helps with redirects.
+ if (!$this->body->isSeekable() && $this->expectCutoff !== false) {
+ $this->setHeader('Expect', '100-Continue');
+ }
+
+ // Set the Content-Length header if it can be determined
+ $size = $this->body->getContentLength();
+ if ($size !== null && $size !== false) {
+ $this->setHeader('Content-Length', $size);
+ if ($size > $this->expectCutoff) {
+ $this->setHeader('Expect', '100-Continue');
+ }
+ } elseif (!$this->hasHeader('Content-Length')) {
+ if ('1.1' == $this->protocolVersion) {
+ $this->setHeader('Transfer-Encoding', 'chunked');
+ } else {
+ throw new RequestException(
+ 'Cannot determine Content-Length and cannot use chunked Transfer-Encoding when using HTTP/1.0'
+ );
+ }
+ }
+
+ return $this;
+ }
+
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+ /**
+ * Set the size that the entity body of the request must exceed before adding the Expect: 100-Continue header.
+ *
+ * @param int|bool $size Cutoff in bytes. Set to false to never send the expect header (even with non-seekable data)
+ *
+ * @return self
+ */
+ public function setExpectHeaderCutoff($size)
+ {
+ $this->expectCutoff = $size;
+ if ($size === false || !$this->body) {
+ $this->removeHeader('Expect');
+ } elseif ($this->body && $this->body->getSize() && $this->body->getSize() > $size) {
+ $this->setHeader('Expect', '100-Continue');
+ }
+
+ return $this;
+ }
+
+ public function configureRedirects($strict = false, $maxRedirects = 5)
+ {
+ $this->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, $strict);
+ if ($maxRedirects == 0) {
+ $this->getParams()->set(RedirectPlugin::DISABLE, true);
+ } else {
+ $this->getParams()->set(RedirectPlugin::MAX_REDIRECTS, $maxRedirects);
+ }
+
+ return $this;
+ }
+
+ public function getPostField($field)
+ {
+ return $this->postFields->get($field);
+ }
+
+ public function getPostFields()
+ {
+ return $this->postFields;
+ }
+
+ public function setPostField($key, $value)
+ {
+ $this->postFields->set($key, $value);
+ $this->processPostFields();
+
+ return $this;
+ }
+
+ public function addPostFields($fields)
+ {
+ $this->postFields->merge($fields);
+ $this->processPostFields();
+
+ return $this;
+ }
+
+ public function removePostField($field)
+ {
+ $this->postFields->remove($field);
+ $this->processPostFields();
+
+ return $this;
+ }
+
+ public function getPostFiles()
+ {
+ return $this->postFiles;
+ }
+
+ public function getPostFile($fieldName)
+ {
+ return isset($this->postFiles[$fieldName]) ? $this->postFiles[$fieldName] : null;
+ }
+
+ public function removePostFile($fieldName)
+ {
+ unset($this->postFiles[$fieldName]);
+ $this->processPostFields();
+
+ return $this;
+ }
+
+ public function addPostFile($field, $filename = null, $contentType = null, $postname = null)
+ {
+ $data = null;
+
+ if ($field instanceof PostFileInterface) {
+ $data = $field;
+ } elseif (is_array($filename)) {
+ // Allow multiple values to be set in a single key
+ foreach ($filename as $file) {
+ $this->addPostFile($field, $file, $contentType);
+ }
+ return $this;
+ } elseif (!is_string($filename)) {
+ throw new RequestException('The path to a file must be a string');
+ } elseif (!empty($filename)) {
+ // Adding an empty file will cause cURL to error out
+ $data = new PostFile($field, $filename, $contentType, $postname);
+ }
+
+ if ($data) {
+ if (!isset($this->postFiles[$data->getFieldName()])) {
+ $this->postFiles[$data->getFieldName()] = array($data);
+ } else {
+ $this->postFiles[$data->getFieldName()][] = $data;
+ }
+ $this->processPostFields();
+ }
+
+ return $this;
+ }
+
+ public function addPostFiles(array $files)
+ {
+ foreach ($files as $key => $file) {
+ if ($file instanceof PostFileInterface) {
+ $this->addPostFile($file, null, null, false);
+ } elseif (is_string($file)) {
+ // Convert non-associative array keys into 'file'
+ if (is_numeric($key)) {
+ $key = 'file';
+ }
+ $this->addPostFile($key, $file, null, false);
+ } else {
+ throw new RequestException('File must be a string or instance of PostFileInterface');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Determine what type of request should be sent based on post fields
+ */
+ protected function processPostFields()
+ {
+ if (!$this->postFiles) {
+ $this->removeHeader('Expect')->setHeader('Content-Type', self::URL_ENCODED);
+ } else {
+ $this->setHeader('Content-Type', self::MULTIPART);
+ if ($this->expectCutoff !== false) {
+ $this->setHeader('Expect', '100-Continue');
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php
new file mode 100755
index 0000000..49ad459
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequestInterface.php
@@ -0,0 +1,137 @@
+ filenames where filename can be a string or PostFileInterface
+ *
+ * @return self
+ */
+ public function addPostFiles(array $files);
+
+ /**
+ * Configure how redirects are handled for the request
+ *
+ * @param bool $strict Set to true to follow strict RFC compliance when redirecting POST requests. Most
+ * browsers with follow a 301-302 redirect for a POST request with a GET request. This is
+ * the default behavior of Guzzle. Enable strict redirects to redirect these responses
+ * with a POST rather than a GET request.
+ * @param int $maxRedirects Specify the maximum number of allowed redirects. Set to 0 to disable redirects.
+ *
+ * @return self
+ */
+ public function configureRedirects($strict = false, $maxRedirects = 5);
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php
new file mode 100755
index 0000000..50597b2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header.php
@@ -0,0 +1,182 @@
+header = trim($header);
+ $this->glue = $glue;
+
+ foreach ((array) $values as $value) {
+ foreach ((array) $value as $v) {
+ $this->values[] = $v;
+ }
+ }
+ }
+
+ public function __toString()
+ {
+ return implode($this->glue . ' ', $this->toArray());
+ }
+
+ public function add($value)
+ {
+ $this->values[] = $value;
+
+ return $this;
+ }
+
+ public function getName()
+ {
+ return $this->header;
+ }
+
+ public function setName($name)
+ {
+ $this->header = $name;
+
+ return $this;
+ }
+
+ public function setGlue($glue)
+ {
+ $this->glue = $glue;
+
+ return $this;
+ }
+
+ public function getGlue()
+ {
+ return $this->glue;
+ }
+
+ /**
+ * Normalize the header to be a single header with an array of values.
+ *
+ * If any values of the header contains the glue string value (e.g. ","), then the value will be exploded into
+ * multiple entries in the header.
+ *
+ * @return self
+ */
+ public function normalize()
+ {
+ $values = $this->toArray();
+
+ for ($i = 0, $total = count($values); $i < $total; $i++) {
+ if (strpos($values[$i], $this->glue) !== false) {
+ // Explode on glue when the glue is not inside of a comma
+ foreach (preg_split('/' . preg_quote($this->glue) . '(?=([^"]*"[^"]*")*[^"]*$)/', $values[$i]) as $v) {
+ $values[] = trim($v);
+ }
+ unset($values[$i]);
+ }
+ }
+
+ $this->values = array_values($values);
+
+ return $this;
+ }
+
+ public function hasValue($searchValue)
+ {
+ return in_array($searchValue, $this->toArray());
+ }
+
+ public function removeValue($searchValue)
+ {
+ $this->values = array_values(array_filter($this->values, function ($value) use ($searchValue) {
+ return $value != $searchValue;
+ }));
+
+ return $this;
+ }
+
+ public function toArray()
+ {
+ return $this->values;
+ }
+
+ public function count()
+ {
+ return count($this->toArray());
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->toArray());
+ }
+
+ public function parseParams()
+ {
+ $params = $matches = array();
+ $callback = array($this, 'trimHeader');
+
+ // Normalize the header into a single array and iterate over all values
+ foreach ($this->normalize()->toArray() as $val) {
+ $part = array();
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
+ if (!preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
+ continue;
+ }
+ $pieces = array_map($callback, $matches[0]);
+ $part[$pieces[0]] = isset($pieces[1]) ? $pieces[1] : '';
+ }
+ if ($part) {
+ $params[] = $part;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function hasExactHeader($header)
+ {
+ Version::warn(__METHOD__ . ' is deprecated');
+ return $this->header == $header;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function raw()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use toArray()');
+ return $this->toArray();
+ }
+
+ /**
+ * Trim a header by removing excess spaces and wrapping quotes
+ *
+ * @param $str
+ *
+ * @return string
+ */
+ protected function trimHeader($str)
+ {
+ static $trimmed = "\"' \n\t";
+
+ return trim($str, $trimmed);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php
new file mode 100755
index 0000000..77789e5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/CacheControl.php
@@ -0,0 +1,121 @@
+directives = null;
+ }
+
+ public function removeValue($searchValue)
+ {
+ parent::removeValue($searchValue);
+ $this->directives = null;
+ }
+
+ /**
+ * Check if a specific cache control directive exists
+ *
+ * @param string $param Directive to retrieve
+ *
+ * @return bool
+ */
+ public function hasDirective($param)
+ {
+ $directives = $this->getDirectives();
+
+ return isset($directives[$param]);
+ }
+
+ /**
+ * Get a specific cache control directive
+ *
+ * @param string $param Directive to retrieve
+ *
+ * @return string|bool|null
+ */
+ public function getDirective($param)
+ {
+ $directives = $this->getDirectives();
+
+ return isset($directives[$param]) ? $directives[$param] : null;
+ }
+
+ /**
+ * Add a cache control directive
+ *
+ * @param string $param Directive to add
+ * @param string $value Value to set
+ *
+ * @return self
+ */
+ public function addDirective($param, $value)
+ {
+ $directives = $this->getDirectives();
+ $directives[$param] = $value;
+ $this->updateFromDirectives($directives);
+
+ return $this;
+ }
+
+ /**
+ * Remove a cache control directive by name
+ *
+ * @param string $param Directive to remove
+ *
+ * @return self
+ */
+ public function removeDirective($param)
+ {
+ $directives = $this->getDirectives();
+ unset($directives[$param]);
+ $this->updateFromDirectives($directives);
+
+ return $this;
+ }
+
+ /**
+ * Get an associative array of cache control directives
+ *
+ * @return array
+ */
+ public function getDirectives()
+ {
+ if ($this->directives === null) {
+ $this->directives = array();
+ foreach ($this->parseParams() as $collection) {
+ foreach ($collection as $key => $value) {
+ $this->directives[$key] = $value === '' ? true : $value;
+ }
+ }
+ }
+
+ return $this->directives;
+ }
+
+ /**
+ * Updates the header value based on the parsed directives
+ *
+ * @param array $directives Array of cache control directives
+ */
+ protected function updateFromDirectives(array $directives)
+ {
+ $this->directives = $directives;
+ $this->values = array();
+
+ foreach ($directives as $key => $value) {
+ $this->values[] = $value === true ? $key : "{$key}={$value}";
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php
new file mode 100755
index 0000000..8c7f6ae
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderCollection.php
@@ -0,0 +1,108 @@
+headers = $headers;
+ }
+
+ public function __clone()
+ {
+ foreach ($this->headers as &$header) {
+ $header = clone $header;
+ }
+ }
+
+ /**
+ * Clears the header collection
+ */
+ public function clear()
+ {
+ $this->headers = array();
+ }
+
+ /**
+ * Set a header on the collection
+ *
+ * @param HeaderInterface $header Header to add
+ *
+ * @return self
+ */
+ public function add(HeaderInterface $header)
+ {
+ $this->headers[strtolower($header->getName())] = $header;
+
+ return $this;
+ }
+
+ /**
+ * Get an array of header objects
+ *
+ * @return array
+ */
+ public function getAll()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Alias of offsetGet
+ */
+ public function get($key)
+ {
+ return $this->offsetGet($key);
+ }
+
+ public function count()
+ {
+ return count($this->headers);
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->headers[strtolower($offset)]);
+ }
+
+ public function offsetGet($offset)
+ {
+ $l = strtolower($offset);
+
+ return isset($this->headers[$l]) ? $this->headers[$l] : null;
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->add($value);
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->headers[strtolower($offset)]);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->headers);
+ }
+
+ public function toArray()
+ {
+ $result = array();
+ foreach ($this->headers as $header) {
+ $result[$header->getName()] = $header->toArray();
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php
new file mode 100755
index 0000000..0273be5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactory.php
@@ -0,0 +1,26 @@
+ 'Guzzle\Http\Message\Header\CacheControl',
+ 'link' => 'Guzzle\Http\Message\Header\Link',
+ );
+
+ public function createHeader($header, $value = null)
+ {
+ $lowercase = strtolower($header);
+
+ return isset($this->mapping[$lowercase])
+ ? new $this->mapping[$lowercase]($header, $value)
+ : new Header($header, $value);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php
new file mode 100755
index 0000000..9457cf6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Header/HeaderFactoryInterface.php
@@ -0,0 +1,19 @@
+", "rel=\"{$rel}\"");
+
+ foreach ($params as $k => $v) {
+ $values[] = "{$k}=\"{$v}\"";
+ }
+
+ return $this->add(implode('; ', $values));
+ }
+
+ /**
+ * Check if a specific link exists for a given rel attribute
+ *
+ * @param string $rel rel value
+ *
+ * @return bool
+ */
+ public function hasLink($rel)
+ {
+ return $this->getLink($rel) !== null;
+ }
+
+ /**
+ * Get a specific link for a given rel attribute
+ *
+ * @param string $rel Rel value
+ *
+ * @return array|null
+ */
+ public function getLink($rel)
+ {
+ foreach ($this->getLinks() as $link) {
+ if (isset($link['rel']) && $link['rel'] == $rel) {
+ return $link;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get an associative array of links
+ *
+ * For example:
+ * Link: ; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg"
+ *
+ *
+ * var_export($response->getLinks());
+ * array(
+ * array(
+ * 'url' => 'http:/.../front.jpeg',
+ * 'rel' => 'back',
+ * 'type' => 'image/jpeg',
+ * )
+ * )
+ *
+ *
+ * @return array
+ */
+ public function getLinks()
+ {
+ $links = $this->parseParams();
+
+ foreach ($links as &$link) {
+ $key = key($link);
+ unset($link[$key]);
+ $link['url'] = trim($key, '<> ');
+ }
+
+ return $links;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php
new file mode 100755
index 0000000..62bcd43
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php
@@ -0,0 +1,102 @@
+fieldName = $fieldName;
+ $this->setFilename($filename);
+ $this->postname = $postname ? $postname : basename($filename);
+ $this->contentType = $contentType ?: $this->guessContentType();
+ }
+
+ public function setFieldName($name)
+ {
+ $this->fieldName = $name;
+
+ return $this;
+ }
+
+ public function getFieldName()
+ {
+ return $this->fieldName;
+ }
+
+ public function setFilename($filename)
+ {
+ // Remove leading @ symbol
+ if (strpos($filename, '@') === 0) {
+ $filename = substr($filename, 1);
+ }
+
+ if (!is_readable($filename)) {
+ throw new InvalidArgumentException("Unable to open {$filename} for reading");
+ }
+
+ $this->filename = $filename;
+
+ return $this;
+ }
+
+ public function setPostname($postname)
+ {
+ $this->postname = $postname;
+
+ return $this;
+ }
+
+ public function getFilename()
+ {
+ return $this->filename;
+ }
+
+ public function getPostname()
+ {
+ return $this->postname;
+ }
+
+ public function setContentType($type)
+ {
+ $this->contentType = $type;
+
+ return $this;
+ }
+
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+ public function getCurlValue()
+ {
+ // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax
+ // See: https://wiki.php.net/rfc/curl-file-upload
+ if (function_exists('curl_file_create')) {
+ return curl_file_create($this->filename, $this->contentType, $this->postname);
+ }
+
+ // Use the old style if using an older version of PHP
+ $value = "@{$this->filename};filename=" . $this->postname;
+ if ($this->contentType) {
+ $value .= ';type=' . $this->contentType;
+ }
+
+ return $value;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getCurlString()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use getCurlValue()');
+ return $this->getCurlValue();
+ }
+
+ /**
+ * Determine the Content-Type of the file
+ */
+ protected function guessContentType()
+ {
+ return Mimetypes::getInstance()->fromFilename($this->filename) ?: 'application/octet-stream';
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php
new file mode 100755
index 0000000..7f0779d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/PostFileInterface.php
@@ -0,0 +1,83 @@
+method = strtoupper($method);
+ $this->curlOptions = new Collection();
+ $this->setUrl($url);
+
+ if ($headers) {
+ // Special handling for multi-value headers
+ foreach ($headers as $key => $value) {
+ // Deal with collisions with Host and Authorization
+ if ($key == 'host' || $key == 'Host') {
+ $this->setHeader($key, $value);
+ } elseif ($value instanceof HeaderInterface) {
+ $this->addHeader($key, $value);
+ } else {
+ foreach ((array) $value as $v) {
+ $this->addHeader($key, $v);
+ }
+ }
+ }
+ }
+
+ $this->setState(self::STATE_NEW);
+ }
+
+ public function __clone()
+ {
+ if ($this->eventDispatcher) {
+ $this->eventDispatcher = clone $this->eventDispatcher;
+ }
+ $this->curlOptions = clone $this->curlOptions;
+ $this->params = clone $this->params;
+ $this->url = clone $this->url;
+ $this->response = $this->responseBody = null;
+ $this->headers = clone $this->headers;
+
+ $this->setState(RequestInterface::STATE_NEW);
+ $this->dispatch('request.clone', array('request' => $this));
+ }
+
+ /**
+ * Get the HTTP request as a string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getRawHeaders() . "\r\n\r\n";
+ }
+
+ /**
+ * Default method that will throw exceptions if an unsuccessful response is received.
+ *
+ * @param Event $event Received
+ * @throws BadResponseException if the response is not successful
+ */
+ public static function onRequestError(Event $event)
+ {
+ $e = BadResponseException::factory($event['request'], $event['response']);
+ $event['request']->setState(self::STATE_ERROR, array('exception' => $e) + $event->toArray());
+ throw $e;
+ }
+
+ public function setClient(ClientInterface $client)
+ {
+ $this->client = $client;
+
+ return $this;
+ }
+
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ public function getRawHeaders()
+ {
+ $protocolVersion = $this->protocolVersion ?: '1.1';
+
+ return trim($this->method . ' ' . $this->getResource()) . ' '
+ . strtoupper(str_replace('https', 'http', $this->url->getScheme()))
+ . '/' . $protocolVersion . "\r\n" . implode("\r\n", $this->getHeaderLines());
+ }
+
+ public function setUrl($url)
+ {
+ if ($url instanceof Url) {
+ $this->url = $url;
+ } else {
+ $this->url = Url::factory($url);
+ }
+
+ // Update the port and host header
+ $this->setPort($this->url->getPort());
+
+ if ($this->url->getUsername() || $this->url->getPassword()) {
+ $this->setAuth($this->url->getUsername(), $this->url->getPassword());
+ // Remove the auth info from the URL
+ $this->url->setUsername(null);
+ $this->url->setPassword(null);
+ }
+
+ return $this;
+ }
+
+ public function send()
+ {
+ if (!$this->client) {
+ throw new RuntimeException('A client must be set on the request');
+ }
+
+ return $this->client->send($this);
+ }
+
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ public function getQuery($asString = false)
+ {
+ return $asString
+ ? (string) $this->url->getQuery()
+ : $this->url->getQuery();
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function getScheme()
+ {
+ return $this->url->getScheme();
+ }
+
+ public function setScheme($scheme)
+ {
+ $this->url->setScheme($scheme);
+
+ return $this;
+ }
+
+ public function getHost()
+ {
+ return $this->url->getHost();
+ }
+
+ public function setHost($host)
+ {
+ $this->url->setHost($host);
+ $this->setPort($this->url->getPort());
+
+ return $this;
+ }
+
+ public function getProtocolVersion()
+ {
+ return $this->protocolVersion;
+ }
+
+ public function setProtocolVersion($protocol)
+ {
+ $this->protocolVersion = $protocol;
+
+ return $this;
+ }
+
+ public function getPath()
+ {
+ return '/' . ltrim($this->url->getPath(), '/');
+ }
+
+ public function setPath($path)
+ {
+ $this->url->setPath($path);
+
+ return $this;
+ }
+
+ public function getPort()
+ {
+ return $this->url->getPort();
+ }
+
+ public function setPort($port)
+ {
+ $this->url->setPort($port);
+
+ // Include the port in the Host header if it is not the default port for the scheme of the URL
+ $scheme = $this->url->getScheme();
+ if ($port && (($scheme == 'http' && $port != 80) || ($scheme == 'https' && $port != 443))) {
+ $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost() . ':' . $port);
+ } else {
+ $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost());
+ }
+
+ return $this;
+ }
+
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ public function setAuth($user, $password = '', $scheme = CURLAUTH_BASIC)
+ {
+ static $authMap = array(
+ 'basic' => CURLAUTH_BASIC,
+ 'digest' => CURLAUTH_DIGEST,
+ 'ntlm' => CURLAUTH_NTLM,
+ 'any' => CURLAUTH_ANY
+ );
+
+ // If we got false or null, disable authentication
+ if (!$user) {
+ $this->password = $this->username = null;
+ $this->removeHeader('Authorization');
+ $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH);
+ return $this;
+ }
+
+ if (!is_numeric($scheme)) {
+ $scheme = strtolower($scheme);
+ if (!isset($authMap[$scheme])) {
+ throw new InvalidArgumentException($scheme . ' is not a valid authentication type');
+ }
+ $scheme = $authMap[$scheme];
+ }
+
+ $this->username = $user;
+ $this->password = $password;
+
+ // Bypass CURL when using basic auth to promote connection reuse
+ if ($scheme == CURLAUTH_BASIC) {
+ $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH);
+ $this->setHeader('Authorization', 'Basic ' . base64_encode($this->username . ':' . $this->password));
+ } else {
+ $this->getCurlOptions()
+ ->set(CURLOPT_HTTPAUTH, $scheme)
+ ->set(CURLOPT_USERPWD, $this->username . ':' . $this->password);
+ }
+
+ return $this;
+ }
+
+ public function getResource()
+ {
+ $resource = $this->getPath();
+ if ($query = (string) $this->url->getQuery()) {
+ $resource .= '?' . $query;
+ }
+
+ return $resource;
+ }
+
+ public function getUrl($asObject = false)
+ {
+ return $asObject ? clone $this->url : (string) $this->url;
+ }
+
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ public function setState($state, array $context = array())
+ {
+ $oldState = $this->state;
+ $this->state = $state;
+
+ switch ($state) {
+ case self::STATE_NEW:
+ $this->response = null;
+ break;
+ case self::STATE_TRANSFER:
+ if ($oldState !== $state) {
+ // Fix Content-Length and Transfer-Encoding collisions
+ if ($this->hasHeader('Transfer-Encoding') && $this->hasHeader('Content-Length')) {
+ $this->removeHeader('Transfer-Encoding');
+ }
+ $this->dispatch('request.before_send', array('request' => $this));
+ }
+ break;
+ case self::STATE_COMPLETE:
+ if ($oldState !== $state) {
+ $this->processResponse($context);
+ $this->responseBody = null;
+ }
+ break;
+ case self::STATE_ERROR:
+ if (isset($context['exception'])) {
+ $this->dispatch('request.exception', array(
+ 'request' => $this,
+ 'response' => isset($context['response']) ? $context['response'] : $this->response,
+ 'exception' => isset($context['exception']) ? $context['exception'] : null
+ ));
+ }
+ }
+
+ return $this->state;
+ }
+
+ public function getCurlOptions()
+ {
+ return $this->curlOptions;
+ }
+
+ public function startResponse(Response $response)
+ {
+ $this->state = self::STATE_TRANSFER;
+ $response->setEffectiveUrl((string) $this->getUrl());
+ $this->response = $response;
+
+ return $this;
+ }
+
+ public function setResponse(Response $response, $queued = false)
+ {
+ $response->setEffectiveUrl((string) $this->url);
+
+ if ($queued) {
+ $ed = $this->getEventDispatcher();
+ $ed->addListener('request.before_send', $f = function ($e) use ($response, &$f, $ed) {
+ $e['request']->setResponse($response);
+ $ed->removeListener('request.before_send', $f);
+ }, -9999);
+ } else {
+ $this->response = $response;
+ // If a specific response body is specified, then use it instead of the response's body
+ if ($this->responseBody && !$this->responseBody->getCustomData('default') && !$response->isRedirect()) {
+ $this->getResponseBody()->write((string) $this->response->getBody());
+ } else {
+ $this->responseBody = $this->response->getBody();
+ }
+ $this->setState(self::STATE_COMPLETE);
+ }
+
+ return $this;
+ }
+
+ public function setResponseBody($body)
+ {
+ // Attempt to open a file for writing if a string was passed
+ if (is_string($body)) {
+ // @codeCoverageIgnoreStart
+ if (!($body = fopen($body, 'w+'))) {
+ throw new InvalidArgumentException('Could not open ' . $body . ' for writing');
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ $this->responseBody = EntityBody::factory($body);
+
+ return $this;
+ }
+
+ public function getResponseBody()
+ {
+ if ($this->responseBody === null) {
+ $this->responseBody = EntityBody::factory()->setCustomData('default', true);
+ }
+
+ return $this->responseBody;
+ }
+
+ /**
+ * Determine if the response body is repeatable (readable + seekable)
+ *
+ * @return bool
+ * @deprecated Use getResponseBody()->isSeekable()
+ * @codeCoverageIgnore
+ */
+ public function isResponseBodyRepeatable()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use $request->getResponseBody()->isRepeatable()');
+ return !$this->responseBody ? true : $this->responseBody->isRepeatable();
+ }
+
+ public function getCookies()
+ {
+ if ($cookie = $this->getHeader('Cookie')) {
+ $data = ParserRegistry::getInstance()->getParser('cookie')->parseCookie($cookie);
+ return $data['cookies'];
+ }
+
+ return array();
+ }
+
+ public function getCookie($name)
+ {
+ $cookies = $this->getCookies();
+
+ return isset($cookies[$name]) ? $cookies[$name] : null;
+ }
+
+ public function addCookie($name, $value)
+ {
+ if (!$this->hasHeader('Cookie')) {
+ $this->setHeader('Cookie', "{$name}={$value}");
+ } else {
+ $this->getHeader('Cookie')->add("{$name}={$value}");
+ }
+
+ // Always use semicolons to separate multiple cookie headers
+ $this->getHeader('Cookie')->setGlue(';');
+
+ return $this;
+ }
+
+ public function removeCookie($name)
+ {
+ if ($cookie = $this->getHeader('Cookie')) {
+ foreach ($cookie as $cookieValue) {
+ if (strpos($cookieValue, $name . '=') === 0) {
+ $cookie->removeValue($cookieValue);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher)
+ {
+ $this->eventDispatcher = $eventDispatcher;
+ $this->eventDispatcher->addListener('request.error', array(__CLASS__, 'onRequestError'), -255);
+
+ return $this;
+ }
+
+ public function getEventDispatcher()
+ {
+ if (!$this->eventDispatcher) {
+ $this->setEventDispatcher(new EventDispatcher());
+ }
+
+ return $this->eventDispatcher;
+ }
+
+ public function dispatch($eventName, array $context = array())
+ {
+ $context['request'] = $this;
+
+ return $this->getEventDispatcher()->dispatch($eventName, new Event($context));
+ }
+
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ $this->getEventDispatcher()->addSubscriber($subscriber);
+
+ return $this;
+ }
+
+ /**
+ * Get an array containing the request and response for event notifications
+ *
+ * @return array
+ */
+ protected function getEventArray()
+ {
+ return array(
+ 'request' => $this,
+ 'response' => $this->response
+ );
+ }
+
+ /**
+ * Process a received response
+ *
+ * @param array $context Contextual information
+ * @throws RequestException|BadResponseException on unsuccessful responses
+ */
+ protected function processResponse(array $context = array())
+ {
+ if (!$this->response) {
+ // If no response, then processResponse shouldn't have been called
+ $e = new RequestException('Error completing request');
+ $e->setRequest($this);
+ throw $e;
+ }
+
+ $this->state = self::STATE_COMPLETE;
+
+ // A request was sent, but we don't know if we'll send more or if the final response will be successful
+ $this->dispatch('request.sent', $this->getEventArray() + $context);
+
+ // Some response processors will remove the response or reset the state (example: ExponentialBackoffPlugin)
+ if ($this->state == RequestInterface::STATE_COMPLETE) {
+
+ // The request completed, so the HTTP transaction is complete
+ $this->dispatch('request.complete', $this->getEventArray());
+
+ // If the response is bad, allow listeners to modify it or throw exceptions. You can change the response by
+ // modifying the Event object in your listeners or calling setResponse() on the request
+ if ($this->response->isError()) {
+ $event = new Event($this->getEventArray());
+ $this->getEventDispatcher()->dispatch('request.error', $event);
+ // Allow events of request.error to quietly change the response
+ if ($event['response'] !== $this->response) {
+ $this->response = $event['response'];
+ }
+ }
+
+ // If a successful response was received, dispatch an event
+ if ($this->response->isSuccessful()) {
+ $this->dispatch('request.success', $this->getEventArray());
+ }
+ }
+ }
+
+ /**
+ * @deprecated Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy
+ * @codeCoverageIgnore
+ */
+ public function canCache()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy.');
+ if (class_exists('Guzzle\Plugin\Cache\DefaultCanCacheStrategy')) {
+ $canCache = new \Guzzle\Plugin\Cache\DefaultCanCacheStrategy();
+ return $canCache->canCacheRequest($this);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @deprecated Use the history plugin (not emitting a warning as this is built-into the RedirectPlugin for now)
+ * @codeCoverageIgnore
+ */
+ public function setIsRedirect($isRedirect)
+ {
+ $this->isRedirect = $isRedirect;
+
+ return $this;
+ }
+
+ /**
+ * @deprecated Use the history plugin
+ * @codeCoverageIgnore
+ */
+ public function isRedirect()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin to track this.');
+ return $this->isRedirect;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php
new file mode 100755
index 0000000..ba00a76
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactory.php
@@ -0,0 +1,359 @@
+methods = array_flip(get_class_methods(__CLASS__));
+ }
+
+ public function fromMessage($message)
+ {
+ $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($message);
+
+ if (!$parsed) {
+ return false;
+ }
+
+ $request = $this->fromParts($parsed['method'], $parsed['request_url'],
+ $parsed['headers'], $parsed['body'], $parsed['protocol'],
+ $parsed['version']);
+
+ // EntityEnclosingRequest adds an "Expect: 100-Continue" header when using a raw request body for PUT or POST
+ // requests. This factory method should accurately reflect the message, so here we are removing the Expect
+ // header if one was not supplied in the message.
+ if (!isset($parsed['headers']['Expect']) && !isset($parsed['headers']['expect'])) {
+ $request->removeHeader('Expect');
+ }
+
+ return $request;
+ }
+
+ public function fromParts(
+ $method,
+ array $urlParts,
+ $headers = null,
+ $body = null,
+ $protocol = 'HTTP',
+ $protocolVersion = '1.1'
+ ) {
+ return $this->create($method, Url::buildUrl($urlParts), $headers, $body)
+ ->setProtocolVersion($protocolVersion);
+ }
+
+ public function create($method, $url, $headers = null, $body = null, array $options = array())
+ {
+ $method = strtoupper($method);
+
+ if ($method == 'GET' || $method == 'HEAD' || $method == 'TRACE') {
+ // Handle non-entity-enclosing request methods
+ $request = new $this->requestClass($method, $url, $headers);
+ if ($body) {
+ // The body is where the response body will be stored
+ $type = gettype($body);
+ if ($type == 'string' || $type == 'resource' || $type == 'object') {
+ $request->setResponseBody($body);
+ }
+ }
+ } else {
+ // Create an entity enclosing request by default
+ $request = new $this->entityEnclosingRequestClass($method, $url, $headers);
+ if ($body || $body === '0') {
+ // Add POST fields and files to an entity enclosing request if an array is used
+ if (is_array($body) || $body instanceof Collection) {
+ // Normalize PHP style cURL uploads with a leading '@' symbol
+ foreach ($body as $key => $value) {
+ if (is_string($value) && substr($value, 0, 1) == '@') {
+ $request->addPostFile($key, $value);
+ unset($body[$key]);
+ }
+ }
+ // Add the fields if they are still present and not all files
+ $request->addPostFields($body);
+ } else {
+ // Add a raw entity body body to the request
+ $request->setBody($body, (string) $request->getHeader('Content-Type'));
+ if ((string) $request->getHeader('Transfer-Encoding') == 'chunked') {
+ $request->removeHeader('Content-Length');
+ }
+ }
+ }
+ }
+
+ if ($options) {
+ $this->applyOptions($request, $options);
+ }
+
+ return $request;
+ }
+
+ /**
+ * Clone a request while changing the method. Emulates the behavior of
+ * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method.
+ *
+ * @param RequestInterface $request Request to clone
+ * @param string $method Method to set
+ *
+ * @return RequestInterface
+ */
+ public function cloneRequestWithMethod(RequestInterface $request, $method)
+ {
+ // Create the request with the same client if possible
+ if ($request->getClient()) {
+ $cloned = $request->getClient()->createRequest($method, $request->getUrl(), $request->getHeaders());
+ } else {
+ $cloned = $this->create($method, $request->getUrl(), $request->getHeaders());
+ }
+
+ $cloned->getCurlOptions()->replace($request->getCurlOptions()->toArray());
+ $cloned->setEventDispatcher(clone $request->getEventDispatcher());
+ // Ensure that that the Content-Length header is not copied if changing to GET or HEAD
+ if (!($cloned instanceof EntityEnclosingRequestInterface)) {
+ $cloned->removeHeader('Content-Length');
+ } elseif ($request instanceof EntityEnclosingRequestInterface) {
+ $cloned->setBody($request->getBody());
+ }
+ $cloned->getParams()->replace($request->getParams()->toArray());
+ $cloned->dispatch('request.clone', array('request' => $cloned));
+
+ return $cloned;
+ }
+
+ public function applyOptions(RequestInterface $request, array $options = array(), $flags = self::OPTIONS_NONE)
+ {
+ // Iterate over each key value pair and attempt to apply a config using function visitors
+ foreach ($options as $key => $value) {
+ $method = "visit_{$key}";
+ if (isset($this->methods[$method])) {
+ $this->{$method}($request, $value, $flags);
+ }
+ }
+ }
+
+ protected function visit_headers(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('headers value must be an array');
+ }
+
+ if ($flags & self::OPTIONS_AS_DEFAULTS) {
+ // Merge headers in but do not overwrite existing values
+ foreach ($value as $key => $header) {
+ if (!$request->hasHeader($key)) {
+ $request->setHeader($key, $header);
+ }
+ }
+ } else {
+ $request->addHeaders($value);
+ }
+ }
+
+ protected function visit_body(RequestInterface $request, $value, $flags)
+ {
+ if ($request instanceof EntityEnclosingRequestInterface) {
+ $request->setBody($value);
+ } else {
+ throw new InvalidArgumentException('Attempting to set a body on a non-entity-enclosing request');
+ }
+ }
+
+ protected function visit_allow_redirects(RequestInterface $request, $value, $flags)
+ {
+ if ($value === false) {
+ $request->getParams()->set(RedirectPlugin::DISABLE, true);
+ }
+ }
+
+ protected function visit_auth(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('auth value must be an array');
+ }
+
+ $request->setAuth($value[0], isset($value[1]) ? $value[1] : null, isset($value[2]) ? $value[2] : 'basic');
+ }
+
+ protected function visit_query(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('query value must be an array');
+ }
+
+ if ($flags & self::OPTIONS_AS_DEFAULTS) {
+ // Merge query string values in but do not overwrite existing values
+ $query = $request->getQuery();
+ $query->overwriteWith(array_diff_key($value, $query->toArray()));
+ } else {
+ $request->getQuery()->overwriteWith($value);
+ }
+ }
+
+ protected function visit_cookies(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('cookies value must be an array');
+ }
+
+ foreach ($value as $name => $v) {
+ $request->addCookie($name, $v);
+ }
+ }
+
+ protected function visit_events(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('events value must be an array');
+ }
+
+ foreach ($value as $name => $method) {
+ if (is_array($method)) {
+ $request->getEventDispatcher()->addListener($name, $method[0], $method[1]);
+ } else {
+ $request->getEventDispatcher()->addListener($name, $method);
+ }
+ }
+ }
+
+ protected function visit_plugins(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('plugins value must be an array');
+ }
+
+ foreach ($value as $plugin) {
+ $request->addSubscriber($plugin);
+ }
+ }
+
+ protected function visit_exceptions(RequestInterface $request, $value, $flags)
+ {
+ if ($value === false || $value === 0) {
+ $dispatcher = $request->getEventDispatcher();
+ foreach ($dispatcher->getListeners('request.error') as $listener) {
+ if (is_array($listener) && $listener[0] == 'Guzzle\Http\Message\Request' && $listener[1] = 'onRequestError') {
+ $dispatcher->removeListener('request.error', $listener);
+ break;
+ }
+ }
+ }
+ }
+
+ protected function visit_save_to(RequestInterface $request, $value, $flags)
+ {
+ $request->setResponseBody($value);
+ }
+
+ protected function visit_params(RequestInterface $request, $value, $flags)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('params value must be an array');
+ }
+
+ $request->getParams()->overwriteWith($value);
+ }
+
+ protected function visit_timeout(RequestInterface $request, $value, $flags)
+ {
+ if (defined('CURLOPT_TIMEOUT_MS')) {
+ $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, $value * 1000);
+ } else {
+ $request->getCurlOptions()->set(CURLOPT_TIMEOUT, $value);
+ }
+ }
+
+ protected function visit_connect_timeout(RequestInterface $request, $value, $flags)
+ {
+ if (defined('CURLOPT_CONNECTTIMEOUT_MS')) {
+ $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, $value * 1000);
+ } else {
+ $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT, $value);
+ }
+ }
+
+ protected function visit_debug(RequestInterface $request, $value, $flags)
+ {
+ if ($value) {
+ $request->getCurlOptions()->set(CURLOPT_VERBOSE, true);
+ }
+ }
+
+ protected function visit_verify(RequestInterface $request, $value, $flags)
+ {
+ $curl = $request->getCurlOptions();
+ if ($value === true || is_string($value)) {
+ $curl[CURLOPT_SSL_VERIFYHOST] = 2;
+ $curl[CURLOPT_SSL_VERIFYPEER] = true;
+ if ($value !== true) {
+ $curl[CURLOPT_CAINFO] = $value;
+ }
+ } elseif ($value === false) {
+ unset($curl[CURLOPT_CAINFO]);
+ $curl[CURLOPT_SSL_VERIFYHOST] = 0;
+ $curl[CURLOPT_SSL_VERIFYPEER] = false;
+ }
+ }
+
+ protected function visit_proxy(RequestInterface $request, $value, $flags)
+ {
+ $request->getCurlOptions()->set(CURLOPT_PROXY, $value, $flags);
+ }
+
+ protected function visit_cert(RequestInterface $request, $value, $flags)
+ {
+ if (is_array($value)) {
+ $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value[0]);
+ $request->getCurlOptions()->set(CURLOPT_SSLCERTPASSWD, $value[1]);
+ } else {
+ $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value);
+ }
+ }
+
+ protected function visit_ssl_key(RequestInterface $request, $value, $flags)
+ {
+ if (is_array($value)) {
+ $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value[0]);
+ $request->getCurlOptions()->set(CURLOPT_SSLKEYPASSWD, $value[1]);
+ } else {
+ $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php
new file mode 100755
index 0000000..6088f10
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestFactoryInterface.php
@@ -0,0 +1,105 @@
+ 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status',
+ 208 => 'Already Reported',
+ 226 => 'IM Used',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+ 308 => 'Permanent Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Reserved for WebDAV advanced collections expired proposal',
+ 426 => 'Upgrade required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 506 => 'Variant Also Negotiates (Experimental)',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 510 => 'Not Extended',
+ 511 => 'Network Authentication Required',
+ );
+
+ /** @var EntityBodyInterface The response body */
+ protected $body;
+
+ /** @var string The reason phrase of the response (human readable code) */
+ protected $reasonPhrase;
+
+ /** @var string The status code of the response */
+ protected $statusCode;
+
+ /** @var array Information about the request */
+ protected $info = array();
+
+ /** @var string The effective URL that returned this response */
+ protected $effectiveUrl;
+
+ /** @var array Cacheable response codes (see RFC 2616:13.4) */
+ protected static $cacheResponseCodes = array(200, 203, 206, 300, 301, 410);
+
+ /**
+ * Create a new Response based on a raw response message
+ *
+ * @param string $message Response message
+ *
+ * @return self|bool Returns false on error
+ */
+ public static function fromMessage($message)
+ {
+ $data = ParserRegistry::getInstance()->getParser('message')->parseResponse($message);
+ if (!$data) {
+ return false;
+ }
+
+ $response = new static($data['code'], $data['headers'], $data['body']);
+ $response->setProtocol($data['protocol'], $data['version'])
+ ->setStatus($data['code'], $data['reason_phrase']);
+
+ // Set the appropriate Content-Length if the one set is inaccurate (e.g. setting to X)
+ $contentLength = (string) $response->getHeader('Content-Length');
+ $actualLength = strlen($data['body']);
+ if (strlen($data['body']) > 0 && $contentLength != $actualLength) {
+ $response->setHeader('Content-Length', $actualLength);
+ }
+
+ return $response;
+ }
+
+ /**
+ * Construct the response
+ *
+ * @param string $statusCode The response status code (e.g. 200, 404, etc)
+ * @param ToArrayInterface|array $headers The response headers
+ * @param string|resource|EntityBodyInterface $body The body of the response
+ *
+ * @throws BadResponseException if an invalid response code is given
+ */
+ public function __construct($statusCode, $headers = null, $body = null)
+ {
+ parent::__construct();
+ $this->setStatus($statusCode);
+ $this->body = EntityBody::factory($body !== null ? $body : '');
+
+ if ($headers) {
+ if (is_array($headers)) {
+ $this->setHeaders($headers);
+ } elseif ($headers instanceof ToArrayInterface) {
+ $this->setHeaders($headers->toArray());
+ } else {
+ throw new BadResponseException('Invalid headers argument received');
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getMessage();
+ }
+
+ public function serialize()
+ {
+ return json_encode(array(
+ 'status' => $this->statusCode,
+ 'body' => (string) $this->body,
+ 'headers' => $this->headers->toArray()
+ ));
+ }
+
+ public function unserialize($serialize)
+ {
+ $data = json_decode($serialize, true);
+ $this->__construct($data['status'], $data['headers'], $data['body']);
+ }
+
+ /**
+ * Get the response entity body
+ *
+ * @param bool $asString Set to TRUE to return a string of the body rather than a full body object
+ *
+ * @return EntityBodyInterface|string
+ */
+ public function getBody($asString = false)
+ {
+ return $asString ? (string) $this->body : $this->body;
+ }
+
+ /**
+ * Set the response entity body
+ *
+ * @param EntityBodyInterface|string $body Body to set
+ *
+ * @return self
+ */
+ public function setBody($body)
+ {
+ $this->body = EntityBody::factory($body);
+
+ return $this;
+ }
+
+ /**
+ * Set the protocol and protocol version of the response
+ *
+ * @param string $protocol Response protocol
+ * @param string $version Protocol version
+ *
+ * @return self
+ */
+ public function setProtocol($protocol, $version)
+ {
+ $this->protocol = $protocol;
+ $this->protocolVersion = $version;
+
+ return $this;
+ }
+
+ /**
+ * Get the protocol used for the response (e.g. HTTP)
+ *
+ * @return string
+ */
+ public function getProtocol()
+ {
+ return $this->protocol;
+ }
+
+ /**
+ * Get the HTTP protocol version
+ *
+ * @return string
+ */
+ public function getProtocolVersion()
+ {
+ return $this->protocolVersion;
+ }
+
+ /**
+ * Get a cURL transfer information
+ *
+ * @param string $key A single statistic to check
+ *
+ * @return array|string|null Returns all stats if no key is set, a single stat if a key is set, or null if a key
+ * is set and not found
+ * @link http://www.php.net/manual/en/function.curl-getinfo.php
+ */
+ public function getInfo($key = null)
+ {
+ if ($key === null) {
+ return $this->info;
+ } elseif (array_key_exists($key, $this->info)) {
+ return $this->info[$key];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Set the transfer information
+ *
+ * @param array $info Array of cURL transfer stats
+ *
+ * @return self
+ */
+ public function setInfo(array $info)
+ {
+ $this->info = $info;
+
+ return $this;
+ }
+
+ /**
+ * Set the response status
+ *
+ * @param int $statusCode Response status code to set
+ * @param string $reasonPhrase Response reason phrase
+ *
+ * @return self
+ * @throws BadResponseException when an invalid response code is received
+ */
+ public function setStatus($statusCode, $reasonPhrase = '')
+ {
+ $this->statusCode = (int) $statusCode;
+
+ if (!$reasonPhrase && isset(self::$statusTexts[$this->statusCode])) {
+ $this->reasonPhrase = self::$statusTexts[$this->statusCode];
+ } else {
+ $this->reasonPhrase = $reasonPhrase;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the response status code
+ *
+ * @return integer
+ */
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ /**
+ * Get the entire response as a string
+ *
+ * @return string
+ */
+ public function getMessage()
+ {
+ $message = $this->getRawHeaders();
+
+ // Only include the body in the message if the size is < 2MB
+ $size = $this->body->getSize();
+ if ($size < 2097152) {
+ $message .= (string) $this->body;
+ }
+
+ return $message;
+ }
+
+ /**
+ * Get the the raw message headers as a string
+ *
+ * @return string
+ */
+ public function getRawHeaders()
+ {
+ $headers = 'HTTP/1.1 ' . $this->statusCode . ' ' . $this->reasonPhrase . "\r\n";
+ $lines = $this->getHeaderLines();
+ if (!empty($lines)) {
+ $headers .= implode("\r\n", $lines) . "\r\n";
+ }
+
+ return $headers . "\r\n";
+ }
+
+ /**
+ * Get the response reason phrase- a human readable version of the numeric
+ * status code
+ *
+ * @return string
+ */
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ /**
+ * Get the Accept-Ranges HTTP header
+ *
+ * @return string Returns what partial content range types this server supports.
+ */
+ public function getAcceptRanges()
+ {
+ return (string) $this->getHeader('Accept-Ranges');
+ }
+
+ /**
+ * Calculate the age of the response
+ *
+ * @return integer
+ */
+ public function calculateAge()
+ {
+ $age = $this->getHeader('Age');
+
+ if ($age === null && $this->getDate()) {
+ $age = time() - strtotime($this->getDate());
+ }
+
+ return $age === null ? null : (int) (string) $age;
+ }
+
+ /**
+ * Get the Age HTTP header
+ *
+ * @return integer|null Returns the age the object has been in a proxy cache in seconds.
+ */
+ public function getAge()
+ {
+ return (string) $this->getHeader('Age');
+ }
+
+ /**
+ * Get the Allow HTTP header
+ *
+ * @return string|null Returns valid actions for a specified resource. To be used for a 405 Method not allowed.
+ */
+ public function getAllow()
+ {
+ return (string) $this->getHeader('Allow');
+ }
+
+ /**
+ * Check if an HTTP method is allowed by checking the Allow response header
+ *
+ * @param string $method Method to check
+ *
+ * @return bool
+ */
+ public function isMethodAllowed($method)
+ {
+ $allow = $this->getHeader('Allow');
+ if ($allow) {
+ foreach (explode(',', $allow) as $allowable) {
+ if (!strcasecmp(trim($allowable), $method)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the Cache-Control HTTP header
+ *
+ * @return string
+ */
+ public function getCacheControl()
+ {
+ return (string) $this->getHeader('Cache-Control');
+ }
+
+ /**
+ * Get the Connection HTTP header
+ *
+ * @return string
+ */
+ public function getConnection()
+ {
+ return (string) $this->getHeader('Connection');
+ }
+
+ /**
+ * Get the Content-Encoding HTTP header
+ *
+ * @return string|null
+ */
+ public function getContentEncoding()
+ {
+ return (string) $this->getHeader('Content-Encoding');
+ }
+
+ /**
+ * Get the Content-Language HTTP header
+ *
+ * @return string|null Returns the language the content is in.
+ */
+ public function getContentLanguage()
+ {
+ return (string) $this->getHeader('Content-Language');
+ }
+
+ /**
+ * Get the Content-Length HTTP header
+ *
+ * @return integer Returns the length of the response body in bytes
+ */
+ public function getContentLength()
+ {
+ return (int) (string) $this->getHeader('Content-Length');
+ }
+
+ /**
+ * Get the Content-Location HTTP header
+ *
+ * @return string|null Returns an alternate location for the returned data (e.g /index.htm)
+ */
+ public function getContentLocation()
+ {
+ return (string) $this->getHeader('Content-Location');
+ }
+
+ /**
+ * Get the Content-Disposition HTTP header
+ *
+ * @return string|null Returns the Content-Disposition header
+ */
+ public function getContentDisposition()
+ {
+ return (string) $this->getHeader('Content-Disposition');
+ }
+
+ /**
+ * Get the Content-MD5 HTTP header
+ *
+ * @return string|null Returns a Base64-encoded binary MD5 sum of the content of the response.
+ */
+ public function getContentMd5()
+ {
+ return (string) $this->getHeader('Content-MD5');
+ }
+
+ /**
+ * Get the Content-Range HTTP header
+ *
+ * @return string Returns where in a full body message this partial message belongs (e.g. bytes 21010-47021/47022).
+ */
+ public function getContentRange()
+ {
+ return (string) $this->getHeader('Content-Range');
+ }
+
+ /**
+ * Get the Content-Type HTTP header
+ *
+ * @return string Returns the mime type of this content.
+ */
+ public function getContentType()
+ {
+ return (string) $this->getHeader('Content-Type');
+ }
+
+ /**
+ * Checks if the Content-Type is of a certain type. This is useful if the
+ * Content-Type header contains charset information and you need to know if
+ * the Content-Type matches a particular type.
+ *
+ * @param string $type Content type to check against
+ *
+ * @return bool
+ */
+ public function isContentType($type)
+ {
+ return stripos($this->getHeader('Content-Type'), $type) !== false;
+ }
+
+ /**
+ * Get the Date HTTP header
+ *
+ * @return string|null Returns the date and time that the message was sent.
+ */
+ public function getDate()
+ {
+ return (string) $this->getHeader('Date');
+ }
+
+ /**
+ * Get the ETag HTTP header
+ *
+ * @return string|null Returns an identifier for a specific version of a resource, often a Message digest.
+ */
+ public function getEtag()
+ {
+ return (string) $this->getHeader('ETag');
+ }
+
+ /**
+ * Get the Expires HTTP header
+ *
+ * @return string|null Returns the date/time after which the response is considered stale.
+ */
+ public function getExpires()
+ {
+ return (string) $this->getHeader('Expires');
+ }
+
+ /**
+ * Get the Last-Modified HTTP header
+ *
+ * @return string|null Returns the last modified date for the requested object, in RFC 2822 format
+ * (e.g. Tue, 15 Nov 1994 12:45:26 GMT)
+ */
+ public function getLastModified()
+ {
+ return (string) $this->getHeader('Last-Modified');
+ }
+
+ /**
+ * Get the Location HTTP header
+ *
+ * @return string|null Used in redirection, or when a new resource has been created.
+ */
+ public function getLocation()
+ {
+ return (string) $this->getHeader('Location');
+ }
+
+ /**
+ * Get the Pragma HTTP header
+ *
+ * @return Header|null Returns the implementation-specific headers that may have various effects anywhere along
+ * the request-response chain.
+ */
+ public function getPragma()
+ {
+ return (string) $this->getHeader('Pragma');
+ }
+
+ /**
+ * Get the Proxy-Authenticate HTTP header
+ *
+ * @return string|null Authentication to access the proxy (e.g. Basic)
+ */
+ public function getProxyAuthenticate()
+ {
+ return (string) $this->getHeader('Proxy-Authenticate');
+ }
+
+ /**
+ * Get the Retry-After HTTP header
+ *
+ * @return int|null If an entity is temporarily unavailable, this instructs the client to try again after a
+ * specified period of time.
+ */
+ public function getRetryAfter()
+ {
+ return (string) $this->getHeader('Retry-After');
+ }
+
+ /**
+ * Get the Server HTTP header
+ *
+ * @return string|null A name for the server
+ */
+ public function getServer()
+ {
+ return (string) $this->getHeader('Server');
+ }
+
+ /**
+ * Get the Set-Cookie HTTP header
+ *
+ * @return string|null An HTTP cookie.
+ */
+ public function getSetCookie()
+ {
+ return (string) $this->getHeader('Set-Cookie');
+ }
+
+ /**
+ * Get the Trailer HTTP header
+ *
+ * @return string|null The Trailer general field value indicates that the given set of header fields is present in
+ * the trailer of a message encoded with chunked transfer-coding.
+ */
+ public function getTrailer()
+ {
+ return (string) $this->getHeader('Trailer');
+ }
+
+ /**
+ * Get the Transfer-Encoding HTTP header
+ *
+ * @return string|null The form of encoding used to safely transfer the entity to the user
+ */
+ public function getTransferEncoding()
+ {
+ return (string) $this->getHeader('Transfer-Encoding');
+ }
+
+ /**
+ * Get the Vary HTTP header
+ *
+ * @return string|null Tells downstream proxies how to match future request headers to decide whether the cached
+ * response can be used rather than requesting a fresh one from the origin server.
+ */
+ public function getVary()
+ {
+ return (string) $this->getHeader('Vary');
+ }
+
+ /**
+ * Get the Via HTTP header
+ *
+ * @return string|null Informs the client of proxies through which the response was sent.
+ */
+ public function getVia()
+ {
+ return (string) $this->getHeader('Via');
+ }
+
+ /**
+ * Get the Warning HTTP header
+ *
+ * @return string|null A general warning about possible problems with the entity body
+ */
+ public function getWarning()
+ {
+ return (string) $this->getHeader('Warning');
+ }
+
+ /**
+ * Get the WWW-Authenticate HTTP header
+ *
+ * @return string|null Indicates the authentication scheme that should be used to access the requested entity
+ */
+ public function getWwwAuthenticate()
+ {
+ return (string) $this->getHeader('WWW-Authenticate');
+ }
+
+ /**
+ * Checks if HTTP Status code is a Client Error (4xx)
+ *
+ * @return bool
+ */
+ public function isClientError()
+ {
+ return $this->statusCode >= 400 && $this->statusCode < 500;
+ }
+
+ /**
+ * Checks if HTTP Status code is Server OR Client Error (4xx or 5xx)
+ *
+ * @return boolean
+ */
+ public function isError()
+ {
+ return $this->isClientError() || $this->isServerError();
+ }
+
+ /**
+ * Checks if HTTP Status code is Information (1xx)
+ *
+ * @return bool
+ */
+ public function isInformational()
+ {
+ return $this->statusCode < 200;
+ }
+
+ /**
+ * Checks if HTTP Status code is a Redirect (3xx)
+ *
+ * @return bool
+ */
+ public function isRedirect()
+ {
+ return $this->statusCode >= 300 && $this->statusCode < 400;
+ }
+
+ /**
+ * Checks if HTTP Status code is Server Error (5xx)
+ *
+ * @return bool
+ */
+ public function isServerError()
+ {
+ return $this->statusCode >= 500 && $this->statusCode < 600;
+ }
+
+ /**
+ * Checks if HTTP Status code is Successful (2xx | 304)
+ *
+ * @return bool
+ */
+ public function isSuccessful()
+ {
+ return ($this->statusCode >= 200 && $this->statusCode < 300) || $this->statusCode == 304;
+ }
+
+ /**
+ * Check if the response can be cached based on the response headers
+ *
+ * @return bool Returns TRUE if the response can be cached or false if not
+ */
+ public function canCache()
+ {
+ // Check if the response is cacheable based on the code
+ if (!in_array((int) $this->getStatusCode(), self::$cacheResponseCodes)) {
+ return false;
+ }
+
+ // Make sure a valid body was returned and can be cached
+ if ((!$this->getBody()->isReadable() || !$this->getBody()->isSeekable())
+ && ($this->getContentLength() > 0 || $this->getTransferEncoding() == 'chunked')) {
+ return false;
+ }
+
+ // Never cache no-store resources (this is a private cache, so private
+ // can be cached)
+ if ($this->getHeader('Cache-Control') && $this->getHeader('Cache-Control')->hasDirective('no-store')) {
+ return false;
+ }
+
+ return $this->isFresh() || $this->getFreshness() === null || $this->canValidate();
+ }
+
+ /**
+ * Gets the number of seconds from the current time in which this response is still considered fresh
+ *
+ * @return int|null Returns the number of seconds
+ */
+ public function getMaxAge()
+ {
+ if ($header = $this->getHeader('Cache-Control')) {
+ // s-max-age, then max-age, then Expires
+ if ($age = $header->getDirective('s-maxage')) {
+ return $age;
+ }
+ if ($age = $header->getDirective('max-age')) {
+ return $age;
+ }
+ }
+
+ if ($this->getHeader('Expires')) {
+ return strtotime($this->getExpires()) - time();
+ }
+
+ return null;
+ }
+
+ /**
+ * Check if the response is considered fresh.
+ *
+ * A response is considered fresh when its age is less than or equal to the freshness lifetime (maximum age) of the
+ * response.
+ *
+ * @return bool|null
+ */
+ public function isFresh()
+ {
+ $fresh = $this->getFreshness();
+
+ return $fresh === null ? null : $fresh >= 0;
+ }
+
+ /**
+ * Check if the response can be validated against the origin server using a conditional GET request.
+ *
+ * @return bool
+ */
+ public function canValidate()
+ {
+ return $this->getEtag() || $this->getLastModified();
+ }
+
+ /**
+ * Get the freshness of the response by returning the difference of the maximum lifetime of the response and the
+ * age of the response (max-age - age).
+ *
+ * Freshness values less than 0 mean that the response is no longer fresh and is ABS(freshness) seconds expired.
+ * Freshness values of greater than zero is the number of seconds until the response is no longer fresh. A NULL
+ * result means that no freshness information is available.
+ *
+ * @return int
+ */
+ public function getFreshness()
+ {
+ $maxAge = $this->getMaxAge();
+ $age = $this->calculateAge();
+
+ return $maxAge && $age ? ($maxAge - $age) : null;
+ }
+
+ /**
+ * Parse the JSON response body and return an array
+ *
+ * @return array|string|int|bool|float
+ * @throws RuntimeException if the response body is not in JSON format
+ */
+ public function json()
+ {
+ $data = json_decode((string) $this->body, true);
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ throw new RuntimeException('Unable to parse response body into JSON: ' . json_last_error());
+ }
+
+ return $data === null ? array() : $data;
+ }
+
+ /**
+ * Parse the XML response body and return a \SimpleXMLElement.
+ *
+ * In order to prevent XXE attacks, this method disables loading external
+ * entities. If you rely on external entities, then you must parse the
+ * XML response manually by accessing the response body directly.
+ *
+ * @return \SimpleXMLElement
+ * @throws RuntimeException if the response body is not in XML format
+ * @link http://websec.io/2012/08/27/Preventing-XXE-in-PHP.html
+ */
+ public function xml()
+ {
+ $errorMessage = null;
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
+ try {
+ $xml = new \SimpleXMLElement((string) $this->body ?: ' ', LIBXML_NONET);
+ if ($error = libxml_get_last_error()) {
+ $errorMessage = $error->message;
+ }
+ } catch (\Exception $e) {
+ $errorMessage = $e->getMessage();
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+ libxml_disable_entity_loader($disableEntities);
+
+ if ($errorMessage) {
+ throw new RuntimeException('Unable to parse response body into XML: ' . $errorMessage);
+ }
+
+ return $xml;
+ }
+
+ /**
+ * Get the redirect count of this response
+ *
+ * @return int
+ */
+ public function getRedirectCount()
+ {
+ return (int) $this->params->get(RedirectPlugin::REDIRECT_COUNT);
+ }
+
+ /**
+ * Set the effective URL that resulted in this response (e.g. the last redirect URL)
+ *
+ * @param string $url The effective URL
+ *
+ * @return self
+ */
+ public function setEffectiveUrl($url)
+ {
+ $this->effectiveUrl = $url;
+
+ return $this;
+ }
+
+ /**
+ * Get the effective URL that resulted in this response (e.g. the last redirect URL)
+ *
+ * @return string
+ */
+ public function getEffectiveUrl()
+ {
+ return $this->effectiveUrl;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getPreviousResponse()
+ {
+ Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin.');
+ return null;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function setRequest($request)
+ {
+ Version::warn(__METHOD__ . ' is deprecated');
+ return $this;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function getRequest()
+ {
+ Version::warn(__METHOD__ . ' is deprecated');
+ return null;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php
new file mode 100755
index 0000000..d71586a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Mimetypes.php
@@ -0,0 +1,962 @@
+ 'text/vnd.in3d.3dml',
+ '3g2' => 'video/3gpp2',
+ '3gp' => 'video/3gpp',
+ '7z' => 'application/x-7z-compressed',
+ 'aab' => 'application/x-authorware-bin',
+ 'aac' => 'audio/x-aac',
+ 'aam' => 'application/x-authorware-map',
+ 'aas' => 'application/x-authorware-seg',
+ 'abw' => 'application/x-abiword',
+ 'ac' => 'application/pkix-attr-cert',
+ 'acc' => 'application/vnd.americandynamics.acc',
+ 'ace' => 'application/x-ace-compressed',
+ 'acu' => 'application/vnd.acucobol',
+ 'acutc' => 'application/vnd.acucorp',
+ 'adp' => 'audio/adpcm',
+ 'aep' => 'application/vnd.audiograph',
+ 'afm' => 'application/x-font-type1',
+ 'afp' => 'application/vnd.ibm.modcap',
+ 'ahead' => 'application/vnd.ahead.space',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
+ 'ait' => 'application/vnd.dvb.ait',
+ 'ami' => 'application/vnd.amiga.ami',
+ 'apk' => 'application/vnd.android.package-archive',
+ 'application' => 'application/x-ms-application',
+ 'apr' => 'application/vnd.lotus-approach',
+ 'asa' => 'text/plain',
+ 'asax' => 'application/octet-stream',
+ 'asc' => 'application/pgp-signature',
+ 'ascx' => 'text/plain',
+ 'asf' => 'video/x-ms-asf',
+ 'ashx' => 'text/plain',
+ 'asm' => 'text/x-asm',
+ 'asmx' => 'text/plain',
+ 'aso' => 'application/vnd.accpac.simply.aso',
+ 'asp' => 'text/plain',
+ 'aspx' => 'text/plain',
+ 'asx' => 'video/x-ms-asf',
+ 'atc' => 'application/vnd.acucorp',
+ 'atom' => 'application/atom+xml',
+ 'atomcat' => 'application/atomcat+xml',
+ 'atomsvc' => 'application/atomsvc+xml',
+ 'atx' => 'application/vnd.antix.game-component',
+ 'au' => 'audio/basic',
+ 'avi' => 'video/x-msvideo',
+ 'aw' => 'application/applixware',
+ 'axd' => 'text/plain',
+ 'azf' => 'application/vnd.airzip.filesecure.azf',
+ 'azs' => 'application/vnd.airzip.filesecure.azs',
+ 'azw' => 'application/vnd.amazon.ebook',
+ 'bat' => 'application/x-msdownload',
+ 'bcpio' => 'application/x-bcpio',
+ 'bdf' => 'application/x-font-bdf',
+ 'bdm' => 'application/vnd.syncml.dm+wbxml',
+ 'bed' => 'application/vnd.realvnc.bed',
+ 'bh2' => 'application/vnd.fujitsu.oasysprs',
+ 'bin' => 'application/octet-stream',
+ 'bmi' => 'application/vnd.bmi',
+ 'bmp' => 'image/bmp',
+ 'book' => 'application/vnd.framemaker',
+ 'box' => 'application/vnd.previewsystems.box',
+ 'boz' => 'application/x-bzip2',
+ 'bpk' => 'application/octet-stream',
+ 'btif' => 'image/prs.btif',
+ 'bz' => 'application/x-bzip',
+ 'bz2' => 'application/x-bzip2',
+ 'c' => 'text/x-c',
+ 'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
+ 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
+ 'c4d' => 'application/vnd.clonk.c4group',
+ 'c4f' => 'application/vnd.clonk.c4group',
+ 'c4g' => 'application/vnd.clonk.c4group',
+ 'c4p' => 'application/vnd.clonk.c4group',
+ 'c4u' => 'application/vnd.clonk.c4group',
+ 'cab' => 'application/vnd.ms-cab-compressed',
+ 'car' => 'application/vnd.curl.car',
+ 'cat' => 'application/vnd.ms-pki.seccat',
+ 'cc' => 'text/x-c',
+ 'cct' => 'application/x-director',
+ 'ccxml' => 'application/ccxml+xml',
+ 'cdbcmsg' => 'application/vnd.contact.cmsg',
+ 'cdf' => 'application/x-netcdf',
+ 'cdkey' => 'application/vnd.mediastation.cdkey',
+ 'cdmia' => 'application/cdmi-capability',
+ 'cdmic' => 'application/cdmi-container',
+ 'cdmid' => 'application/cdmi-domain',
+ 'cdmio' => 'application/cdmi-object',
+ 'cdmiq' => 'application/cdmi-queue',
+ 'cdx' => 'chemical/x-cdx',
+ 'cdxml' => 'application/vnd.chemdraw+xml',
+ 'cdy' => 'application/vnd.cinderella',
+ 'cer' => 'application/pkix-cert',
+ 'cfc' => 'application/x-coldfusion',
+ 'cfm' => 'application/x-coldfusion',
+ 'cgm' => 'image/cgm',
+ 'chat' => 'application/x-chat',
+ 'chm' => 'application/vnd.ms-htmlhelp',
+ 'chrt' => 'application/vnd.kde.kchart',
+ 'cif' => 'chemical/x-cif',
+ 'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
+ 'cil' => 'application/vnd.ms-artgalry',
+ 'cla' => 'application/vnd.claymore',
+ 'class' => 'application/java-vm',
+ 'clkk' => 'application/vnd.crick.clicker.keyboard',
+ 'clkp' => 'application/vnd.crick.clicker.palette',
+ 'clkt' => 'application/vnd.crick.clicker.template',
+ 'clkw' => 'application/vnd.crick.clicker.wordbank',
+ 'clkx' => 'application/vnd.crick.clicker',
+ 'clp' => 'application/x-msclip',
+ 'cmc' => 'application/vnd.cosmocaller',
+ 'cmdf' => 'chemical/x-cmdf',
+ 'cml' => 'chemical/x-cml',
+ 'cmp' => 'application/vnd.yellowriver-custom-menu',
+ 'cmx' => 'image/x-cmx',
+ 'cod' => 'application/vnd.rim.cod',
+ 'com' => 'application/x-msdownload',
+ 'conf' => 'text/plain',
+ 'cpio' => 'application/x-cpio',
+ 'cpp' => 'text/x-c',
+ 'cpt' => 'application/mac-compactpro',
+ 'crd' => 'application/x-mscardfile',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'cryptonote' => 'application/vnd.rig.cryptonote',
+ 'cs' => 'text/plain',
+ 'csh' => 'application/x-csh',
+ 'csml' => 'chemical/x-csml',
+ 'csp' => 'application/vnd.commonspace',
+ 'css' => 'text/css',
+ 'cst' => 'application/x-director',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'curl' => 'text/vnd.curl',
+ 'cww' => 'application/prs.cww',
+ 'cxt' => 'application/x-director',
+ 'cxx' => 'text/x-c',
+ 'dae' => 'model/vnd.collada+xml',
+ 'daf' => 'application/vnd.mobius.daf',
+ 'dataless' => 'application/vnd.fdsn.seed',
+ 'davmount' => 'application/davmount+xml',
+ 'dcr' => 'application/x-director',
+ 'dcurl' => 'text/vnd.curl.dcurl',
+ 'dd2' => 'application/vnd.oma.dd2+xml',
+ 'ddd' => 'application/vnd.fujixerox.ddd',
+ 'deb' => 'application/x-debian-package',
+ 'def' => 'text/plain',
+ 'deploy' => 'application/octet-stream',
+ 'der' => 'application/x-x509-ca-cert',
+ 'dfac' => 'application/vnd.dreamfactory',
+ 'dic' => 'text/x-c',
+ 'dir' => 'application/x-director',
+ 'dis' => 'application/vnd.mobius.dis',
+ 'dist' => 'application/octet-stream',
+ 'distz' => 'application/octet-stream',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'dll' => 'application/x-msdownload',
+ 'dmg' => 'application/octet-stream',
+ 'dms' => 'application/octet-stream',
+ 'dna' => 'application/vnd.dna',
+ 'doc' => 'application/msword',
+ 'docm' => 'application/vnd.ms-word.document.macroenabled.12',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dot' => 'application/msword',
+ 'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dp' => 'application/vnd.osgi.dp',
+ 'dpg' => 'application/vnd.dpgraph',
+ 'dra' => 'audio/vnd.dra',
+ 'dsc' => 'text/prs.lines.tag',
+ 'dssc' => 'application/dssc+der',
+ 'dtb' => 'application/x-dtbook+xml',
+ 'dtd' => 'application/xml-dtd',
+ 'dts' => 'audio/vnd.dts',
+ 'dtshd' => 'audio/vnd.dts.hd',
+ 'dump' => 'application/octet-stream',
+ 'dvi' => 'application/x-dvi',
+ 'dwf' => 'model/vnd.dwf',
+ 'dwg' => 'image/vnd.dwg',
+ 'dxf' => 'image/vnd.dxf',
+ 'dxp' => 'application/vnd.spotfire.dxp',
+ 'dxr' => 'application/x-director',
+ 'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
+ 'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
+ 'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
+ 'ecma' => 'application/ecmascript',
+ 'edm' => 'application/vnd.novadigm.edm',
+ 'edx' => 'application/vnd.novadigm.edx',
+ 'efif' => 'application/vnd.picsel',
+ 'ei6' => 'application/vnd.pg.osasli',
+ 'elc' => 'application/octet-stream',
+ 'eml' => 'message/rfc822',
+ 'emma' => 'application/emma+xml',
+ 'eol' => 'audio/vnd.digital-winds',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'es3' => 'application/vnd.eszigno3+xml',
+ 'esf' => 'application/vnd.epson.esf',
+ 'et3' => 'application/vnd.eszigno3+xml',
+ 'etx' => 'text/x-setext',
+ 'exe' => 'application/x-msdownload',
+ 'exi' => 'application/exi',
+ 'ext' => 'application/vnd.novadigm.ext',
+ 'ez' => 'application/andrew-inset',
+ 'ez2' => 'application/vnd.ezpix-album',
+ 'ez3' => 'application/vnd.ezpix-package',
+ 'f' => 'text/x-fortran',
+ 'f4v' => 'video/x-f4v',
+ 'f77' => 'text/x-fortran',
+ 'f90' => 'text/x-fortran',
+ 'fbs' => 'image/vnd.fastbidsheet',
+ 'fcs' => 'application/vnd.isac.fcs',
+ 'fdf' => 'application/vnd.fdf',
+ 'fe_launch' => 'application/vnd.denovo.fcselayout-link',
+ 'fg5' => 'application/vnd.fujitsu.oasysgp',
+ 'fgd' => 'application/x-director',
+ 'fh' => 'image/x-freehand',
+ 'fh4' => 'image/x-freehand',
+ 'fh5' => 'image/x-freehand',
+ 'fh7' => 'image/x-freehand',
+ 'fhc' => 'image/x-freehand',
+ 'fig' => 'application/x-xfig',
+ 'fli' => 'video/x-fli',
+ 'flo' => 'application/vnd.micrografx.flo',
+ 'flv' => 'video/x-flv',
+ 'flw' => 'application/vnd.kde.kivio',
+ 'flx' => 'text/vnd.fmi.flexstor',
+ 'fly' => 'text/vnd.fly',
+ 'fm' => 'application/vnd.framemaker',
+ 'fnc' => 'application/vnd.frogans.fnc',
+ 'for' => 'text/x-fortran',
+ 'fpx' => 'image/vnd.fpx',
+ 'frame' => 'application/vnd.framemaker',
+ 'fsc' => 'application/vnd.fsc.weblaunch',
+ 'fst' => 'image/vnd.fst',
+ 'ftc' => 'application/vnd.fluxtime.clip',
+ 'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
+ 'fvt' => 'video/vnd.fvt',
+ 'fxp' => 'application/vnd.adobe.fxp',
+ 'fxpl' => 'application/vnd.adobe.fxp',
+ 'fzs' => 'application/vnd.fuzzysheet',
+ 'g2w' => 'application/vnd.geoplan',
+ 'g3' => 'image/g3fax',
+ 'g3w' => 'application/vnd.geospace',
+ 'gac' => 'application/vnd.groove-account',
+ 'gdl' => 'model/vnd.gdl',
+ 'geo' => 'application/vnd.dynageo',
+ 'gex' => 'application/vnd.geometry-explorer',
+ 'ggb' => 'application/vnd.geogebra.file',
+ 'ggt' => 'application/vnd.geogebra.tool',
+ 'ghf' => 'application/vnd.groove-help',
+ 'gif' => 'image/gif',
+ 'gim' => 'application/vnd.groove-identity-message',
+ 'gmx' => 'application/vnd.gmx',
+ 'gnumeric' => 'application/x-gnumeric',
+ 'gph' => 'application/vnd.flographit',
+ 'gqf' => 'application/vnd.grafeq',
+ 'gqs' => 'application/vnd.grafeq',
+ 'gram' => 'application/srgs',
+ 'gre' => 'application/vnd.geometry-explorer',
+ 'grv' => 'application/vnd.groove-injector',
+ 'grxml' => 'application/srgs+xml',
+ 'gsf' => 'application/x-font-ghostscript',
+ 'gtar' => 'application/x-gtar',
+ 'gtm' => 'application/vnd.groove-tool-message',
+ 'gtw' => 'model/vnd.gtw',
+ 'gv' => 'text/vnd.graphviz',
+ 'gxt' => 'application/vnd.geonext',
+ 'h' => 'text/x-c',
+ 'h261' => 'video/h261',
+ 'h263' => 'video/h263',
+ 'h264' => 'video/h264',
+ 'hal' => 'application/vnd.hal+xml',
+ 'hbci' => 'application/vnd.hbci',
+ 'hdf' => 'application/x-hdf',
+ 'hh' => 'text/x-c',
+ 'hlp' => 'application/winhlp',
+ 'hpgl' => 'application/vnd.hp-hpgl',
+ 'hpid' => 'application/vnd.hp-hpid',
+ 'hps' => 'application/vnd.hp-hps',
+ 'hqx' => 'application/mac-binhex40',
+ 'hta' => 'application/octet-stream',
+ 'htc' => 'text/html',
+ 'htke' => 'application/vnd.kenameaapp',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'hvd' => 'application/vnd.yamaha.hv-dic',
+ 'hvp' => 'application/vnd.yamaha.hv-voice',
+ 'hvs' => 'application/vnd.yamaha.hv-script',
+ 'i2g' => 'application/vnd.intergeo',
+ 'icc' => 'application/vnd.iccprofile',
+ 'ice' => 'x-conference/x-cooltalk',
+ 'icm' => 'application/vnd.iccprofile',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ief' => 'image/ief',
+ 'ifb' => 'text/calendar',
+ 'ifm' => 'application/vnd.shana.informed.formdata',
+ 'iges' => 'model/iges',
+ 'igl' => 'application/vnd.igloader',
+ 'igm' => 'application/vnd.insors.igm',
+ 'igs' => 'model/iges',
+ 'igx' => 'application/vnd.micrografx.igx',
+ 'iif' => 'application/vnd.shana.informed.interchange',
+ 'imp' => 'application/vnd.accpac.simply.imp',
+ 'ims' => 'application/vnd.ms-ims',
+ 'in' => 'text/plain',
+ 'ini' => 'text/plain',
+ 'ipfix' => 'application/ipfix',
+ 'ipk' => 'application/vnd.shana.informed.package',
+ 'irm' => 'application/vnd.ibm.rights-management',
+ 'irp' => 'application/vnd.irepository.package+xml',
+ 'iso' => 'application/octet-stream',
+ 'itp' => 'application/vnd.shana.informed.formtemplate',
+ 'ivp' => 'application/vnd.immervision-ivp',
+ 'ivu' => 'application/vnd.immervision-ivu',
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
+ 'jam' => 'application/vnd.jam',
+ 'jar' => 'application/java-archive',
+ 'java' => 'text/x-java-source',
+ 'jisp' => 'application/vnd.jisp',
+ 'jlt' => 'application/vnd.hp-jlyt',
+ 'jnlp' => 'application/x-java-jnlp-file',
+ 'joda' => 'application/vnd.joost.joda-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpgm' => 'video/jpm',
+ 'jpgv' => 'video/jpeg',
+ 'jpm' => 'video/jpm',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'kar' => 'audio/midi',
+ 'karbon' => 'application/vnd.kde.karbon',
+ 'kfo' => 'application/vnd.kde.kformula',
+ 'kia' => 'application/vnd.kidspiration',
+ 'kml' => 'application/vnd.google-earth.kml+xml',
+ 'kmz' => 'application/vnd.google-earth.kmz',
+ 'kne' => 'application/vnd.kinar',
+ 'knp' => 'application/vnd.kinar',
+ 'kon' => 'application/vnd.kde.kontour',
+ 'kpr' => 'application/vnd.kde.kpresenter',
+ 'kpt' => 'application/vnd.kde.kpresenter',
+ 'ksp' => 'application/vnd.kde.kspread',
+ 'ktr' => 'application/vnd.kahootz',
+ 'ktx' => 'image/ktx',
+ 'ktz' => 'application/vnd.kahootz',
+ 'kwd' => 'application/vnd.kde.kword',
+ 'kwt' => 'application/vnd.kde.kword',
+ 'lasxml' => 'application/vnd.las.las+xml',
+ 'latex' => 'application/x-latex',
+ 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
+ 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
+ 'les' => 'application/vnd.hhe.lesson-player',
+ 'lha' => 'application/octet-stream',
+ 'link66' => 'application/vnd.route66.link66+xml',
+ 'list' => 'text/plain',
+ 'list3820' => 'application/vnd.ibm.modcap',
+ 'listafp' => 'application/vnd.ibm.modcap',
+ 'log' => 'text/plain',
+ 'lostxml' => 'application/lost+xml',
+ 'lrf' => 'application/octet-stream',
+ 'lrm' => 'application/vnd.ms-lrm',
+ 'ltf' => 'application/vnd.frogans.ltf',
+ 'lvp' => 'audio/vnd.lucent.voice',
+ 'lwp' => 'application/vnd.lotus-wordpro',
+ 'lzh' => 'application/octet-stream',
+ 'm13' => 'application/x-msmediaview',
+ 'm14' => 'application/x-msmediaview',
+ 'm1v' => 'video/mpeg',
+ 'm21' => 'application/mp21',
+ 'm2a' => 'audio/mpeg',
+ 'm2v' => 'video/mpeg',
+ 'm3a' => 'audio/mpeg',
+ 'm3u' => 'audio/x-mpegurl',
+ 'm3u8' => 'application/vnd.apple.mpegurl',
+ 'm4a' => 'audio/mp4',
+ 'm4u' => 'video/vnd.mpegurl',
+ 'm4v' => 'video/mp4',
+ 'ma' => 'application/mathematica',
+ 'mads' => 'application/mads+xml',
+ 'mag' => 'application/vnd.ecowin.chart',
+ 'maker' => 'application/vnd.framemaker',
+ 'man' => 'text/troff',
+ 'mathml' => 'application/mathml+xml',
+ 'mb' => 'application/mathematica',
+ 'mbk' => 'application/vnd.mobius.mbk',
+ 'mbox' => 'application/mbox',
+ 'mc1' => 'application/vnd.medcalcdata',
+ 'mcd' => 'application/vnd.mcd',
+ 'mcurl' => 'text/vnd.curl.mcurl',
+ 'mdb' => 'application/x-msaccess',
+ 'mdi' => 'image/vnd.ms-modi',
+ 'me' => 'text/troff',
+ 'mesh' => 'model/mesh',
+ 'meta4' => 'application/metalink4+xml',
+ 'mets' => 'application/mets+xml',
+ 'mfm' => 'application/vnd.mfmp',
+ 'mgp' => 'application/vnd.osgeo.mapguide.package',
+ 'mgz' => 'application/vnd.proteus.magazine',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mif' => 'application/vnd.mif',
+ 'mime' => 'message/rfc822',
+ 'mj2' => 'video/mj2',
+ 'mjp2' => 'video/mj2',
+ 'mlp' => 'application/vnd.dolby.mlp',
+ 'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
+ 'mmf' => 'application/vnd.smaf',
+ 'mmr' => 'image/vnd.fujixerox.edmics-mmr',
+ 'mny' => 'application/x-msmoney',
+ 'mobi' => 'application/x-mobipocket-ebook',
+ 'mods' => 'application/mods+xml',
+ 'mov' => 'video/quicktime',
+ 'movie' => 'video/x-sgi-movie',
+ 'mp2' => 'audio/mpeg',
+ 'mp21' => 'application/mp21',
+ 'mp2a' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4s' => 'application/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpc' => 'application/vnd.mophun.certificate',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'mpga' => 'audio/mpeg',
+ 'mpkg' => 'application/vnd.apple.installer+xml',
+ 'mpm' => 'application/vnd.blueice.multipass',
+ 'mpn' => 'application/vnd.mophun.application',
+ 'mpp' => 'application/vnd.ms-project',
+ 'mpt' => 'application/vnd.ms-project',
+ 'mpy' => 'application/vnd.ibm.minipay',
+ 'mqy' => 'application/vnd.mobius.mqy',
+ 'mrc' => 'application/marc',
+ 'mrcx' => 'application/marcxml+xml',
+ 'ms' => 'text/troff',
+ 'mscml' => 'application/mediaservercontrol+xml',
+ 'mseed' => 'application/vnd.fdsn.mseed',
+ 'mseq' => 'application/vnd.mseq',
+ 'msf' => 'application/vnd.epson.msf',
+ 'msh' => 'model/mesh',
+ 'msi' => 'application/x-msdownload',
+ 'msl' => 'application/vnd.mobius.msl',
+ 'msty' => 'application/vnd.muvee.style',
+ 'mts' => 'model/vnd.mts',
+ 'mus' => 'application/vnd.musician',
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
+ 'mvb' => 'application/x-msmediaview',
+ 'mwf' => 'application/vnd.mfer',
+ 'mxf' => 'application/mxf',
+ 'mxl' => 'application/vnd.recordare.musicxml',
+ 'mxml' => 'application/xv+xml',
+ 'mxs' => 'application/vnd.triscape.mxs',
+ 'mxu' => 'video/vnd.mpegurl',
+ 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
+ 'n3' => 'text/n3',
+ 'nb' => 'application/mathematica',
+ 'nbp' => 'application/vnd.wolfram.player',
+ 'nc' => 'application/x-netcdf',
+ 'ncx' => 'application/x-dtbncx+xml',
+ 'ngdat' => 'application/vnd.nokia.n-gage.data',
+ 'nlu' => 'application/vnd.neurolanguage.nlu',
+ 'nml' => 'application/vnd.enliven',
+ 'nnd' => 'application/vnd.noblenet-directory',
+ 'nns' => 'application/vnd.noblenet-sealer',
+ 'nnw' => 'application/vnd.noblenet-web',
+ 'npx' => 'image/vnd.net-fpx',
+ 'nsf' => 'application/vnd.lotus-notes',
+ 'oa2' => 'application/vnd.fujitsu.oasys2',
+ 'oa3' => 'application/vnd.fujitsu.oasys3',
+ 'oas' => 'application/vnd.fujitsu.oasys',
+ 'obd' => 'application/x-msbinder',
+ 'oda' => 'application/oda',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'odft' => 'application/vnd.oasis.opendocument.formula-template',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'onepkg' => 'application/onenote',
+ 'onetmp' => 'application/onenote',
+ 'onetoc' => 'application/onenote',
+ 'onetoc2' => 'application/onenote',
+ 'opf' => 'application/oebps-package+xml',
+ 'oprc' => 'application/vnd.palm',
+ 'org' => 'application/vnd.lotus-organizer',
+ 'osf' => 'application/vnd.yamaha.openscoreformat',
+ 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
+ 'otf' => 'application/x-font-otf',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oxt' => 'application/vnd.openofficeorg.extension',
+ 'p' => 'text/x-pascal',
+ 'p10' => 'application/pkcs10',
+ 'p12' => 'application/x-pkcs12',
+ 'p7b' => 'application/x-pkcs7-certificates',
+ 'p7c' => 'application/pkcs7-mime',
+ 'p7m' => 'application/pkcs7-mime',
+ 'p7r' => 'application/x-pkcs7-certreqresp',
+ 'p7s' => 'application/pkcs7-signature',
+ 'p8' => 'application/pkcs8',
+ 'pas' => 'text/x-pascal',
+ 'paw' => 'application/vnd.pawaafile',
+ 'pbd' => 'application/vnd.powerbuilder6',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pcf' => 'application/x-font-pcf',
+ 'pcl' => 'application/vnd.hp-pcl',
+ 'pclxl' => 'application/vnd.hp-pclxl',
+ 'pct' => 'image/x-pict',
+ 'pcurl' => 'application/vnd.curl.pcurl',
+ 'pcx' => 'image/x-pcx',
+ 'pdb' => 'application/vnd.palm',
+ 'pdf' => 'application/pdf',
+ 'pfa' => 'application/x-font-type1',
+ 'pfb' => 'application/x-font-type1',
+ 'pfm' => 'application/x-font-type1',
+ 'pfr' => 'application/font-tdpfr',
+ 'pfx' => 'application/x-pkcs12',
+ 'pgm' => 'image/x-portable-graymap',
+ 'pgn' => 'application/x-chess-pgn',
+ 'pgp' => 'application/pgp-encrypted',
+ 'php' => 'text/x-php',
+ 'phps' => 'application/x-httpd-phps',
+ 'pic' => 'image/x-pict',
+ 'pkg' => 'application/octet-stream',
+ 'pki' => 'application/pkixcmp',
+ 'pkipath' => 'application/pkix-pkipath',
+ 'plb' => 'application/vnd.3gpp.pic-bw-large',
+ 'plc' => 'application/vnd.mobius.plc',
+ 'plf' => 'application/vnd.pocketlearn',
+ 'pls' => 'application/pls+xml',
+ 'pml' => 'application/vnd.ctc-posml',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'portpkg' => 'application/vnd.macports.portpkg',
+ 'pot' => 'application/vnd.ms-powerpoint',
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
+ 'ppd' => 'application/vnd.cups-ppd',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'pps' => 'application/vnd.ms-powerpoint',
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'pqa' => 'application/vnd.palm',
+ 'prc' => 'application/x-mobipocket-ebook',
+ 'pre' => 'application/vnd.lotus-freelance',
+ 'prf' => 'application/pics-rules',
+ 'ps' => 'application/postscript',
+ 'psb' => 'application/vnd.3gpp.pic-bw-small',
+ 'psd' => 'image/vnd.adobe.photoshop',
+ 'psf' => 'application/x-font-linux-psf',
+ 'pskcxml' => 'application/pskc+xml',
+ 'ptid' => 'application/vnd.pvi.ptid1',
+ 'pub' => 'application/x-mspublisher',
+ 'pvb' => 'application/vnd.3gpp.pic-bw-var',
+ 'pwn' => 'application/vnd.3m.post-it-notes',
+ 'pya' => 'audio/vnd.ms-playready.media.pya',
+ 'pyv' => 'video/vnd.ms-playready.media.pyv',
+ 'qam' => 'application/vnd.epson.quickanime',
+ 'qbo' => 'application/vnd.intu.qbo',
+ 'qfx' => 'application/vnd.intu.qfx',
+ 'qps' => 'application/vnd.publishare-delta-tree',
+ 'qt' => 'video/quicktime',
+ 'qwd' => 'application/vnd.quark.quarkxpress',
+ 'qwt' => 'application/vnd.quark.quarkxpress',
+ 'qxb' => 'application/vnd.quark.quarkxpress',
+ 'qxd' => 'application/vnd.quark.quarkxpress',
+ 'qxl' => 'application/vnd.quark.quarkxpress',
+ 'qxt' => 'application/vnd.quark.quarkxpress',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rb' => 'text/plain',
+ 'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
+ 'rdf' => 'application/rdf+xml',
+ 'rdz' => 'application/vnd.data-vision.rdz',
+ 'rep' => 'application/vnd.businessobjects',
+ 'res' => 'application/x-dtbresource+xml',
+ 'resx' => 'text/xml',
+ 'rgb' => 'image/x-rgb',
+ 'rif' => 'application/reginfo+xml',
+ 'rip' => 'audio/vnd.rip',
+ 'rl' => 'application/resource-lists+xml',
+ 'rlc' => 'image/vnd.fujixerox.edmics-rlc',
+ 'rld' => 'application/resource-lists-diff+xml',
+ 'rm' => 'application/vnd.rn-realmedia',
+ 'rmi' => 'audio/midi',
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
+ 'rms' => 'application/vnd.jcp.javame.midlet-rms',
+ 'rnc' => 'application/relax-ng-compact-syntax',
+ 'roff' => 'text/troff',
+ 'rp9' => 'application/vnd.cloanto.rp9',
+ 'rpss' => 'application/vnd.nokia.radio-presets',
+ 'rpst' => 'application/vnd.nokia.radio-preset',
+ 'rq' => 'application/sparql-query',
+ 'rs' => 'application/rls-services+xml',
+ 'rsd' => 'application/rsd+xml',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'rtx' => 'text/richtext',
+ 's' => 'text/x-asm',
+ 'saf' => 'application/vnd.yamaha.smaf-audio',
+ 'sbml' => 'application/sbml+xml',
+ 'sc' => 'application/vnd.ibm.secure-container',
+ 'scd' => 'application/x-msschedule',
+ 'scm' => 'application/vnd.lotus-screencam',
+ 'scq' => 'application/scvp-cv-request',
+ 'scs' => 'application/scvp-cv-response',
+ 'scurl' => 'text/vnd.curl.scurl',
+ 'sda' => 'application/vnd.stardivision.draw',
+ 'sdc' => 'application/vnd.stardivision.calc',
+ 'sdd' => 'application/vnd.stardivision.impress',
+ 'sdkd' => 'application/vnd.solent.sdkm+xml',
+ 'sdkm' => 'application/vnd.solent.sdkm+xml',
+ 'sdp' => 'application/sdp',
+ 'sdw' => 'application/vnd.stardivision.writer',
+ 'see' => 'application/vnd.seemail',
+ 'seed' => 'application/vnd.fdsn.seed',
+ 'sema' => 'application/vnd.sema',
+ 'semd' => 'application/vnd.semd',
+ 'semf' => 'application/vnd.semf',
+ 'ser' => 'application/java-serialized-object',
+ 'setpay' => 'application/set-payment-initiation',
+ 'setreg' => 'application/set-registration-initiation',
+ 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
+ 'sfs' => 'application/vnd.spotfire.sfs',
+ 'sgl' => 'application/vnd.stardivision.writer-global',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'sh' => 'application/x-sh',
+ 'shar' => 'application/x-shar',
+ 'shf' => 'application/shf+xml',
+ 'sig' => 'application/pgp-signature',
+ 'silo' => 'model/mesh',
+ 'sis' => 'application/vnd.symbian.install',
+ 'sisx' => 'application/vnd.symbian.install',
+ 'sit' => 'application/x-stuffit',
+ 'sitx' => 'application/x-stuffitx',
+ 'skd' => 'application/vnd.koan',
+ 'skm' => 'application/vnd.koan',
+ 'skp' => 'application/vnd.koan',
+ 'skt' => 'application/vnd.koan',
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'slt' => 'application/vnd.epson.salt',
+ 'sm' => 'application/vnd.stepmania.stepchart',
+ 'smf' => 'application/vnd.stardivision.math',
+ 'smi' => 'application/smil+xml',
+ 'smil' => 'application/smil+xml',
+ 'snd' => 'audio/basic',
+ 'snf' => 'application/x-font-snf',
+ 'so' => 'application/octet-stream',
+ 'spc' => 'application/x-pkcs7-certificates',
+ 'spf' => 'application/vnd.yamaha.smaf-phrase',
+ 'spl' => 'application/x-futuresplash',
+ 'spot' => 'text/vnd.in3d.spot',
+ 'spp' => 'application/scvp-vp-response',
+ 'spq' => 'application/scvp-vp-request',
+ 'spx' => 'audio/ogg',
+ 'src' => 'application/x-wais-source',
+ 'sru' => 'application/sru+xml',
+ 'srx' => 'application/sparql-results+xml',
+ 'sse' => 'application/vnd.kodak-descriptor',
+ 'ssf' => 'application/vnd.epson.ssf',
+ 'ssml' => 'application/ssml+xml',
+ 'st' => 'application/vnd.sailingtracker.track',
+ 'stc' => 'application/vnd.sun.xml.calc.template',
+ 'std' => 'application/vnd.sun.xml.draw.template',
+ 'stf' => 'application/vnd.wt.stf',
+ 'sti' => 'application/vnd.sun.xml.impress.template',
+ 'stk' => 'application/hyperstudio',
+ 'stl' => 'application/vnd.ms-pki.stl',
+ 'str' => 'application/vnd.pg.format',
+ 'stw' => 'application/vnd.sun.xml.writer.template',
+ 'sub' => 'image/vnd.dvb.subtitle',
+ 'sus' => 'application/vnd.sus-calendar',
+ 'susp' => 'application/vnd.sus-calendar',
+ 'sv4cpio' => 'application/x-sv4cpio',
+ 'sv4crc' => 'application/x-sv4crc',
+ 'svc' => 'application/vnd.dvb.service',
+ 'svd' => 'application/vnd.svd',
+ 'svg' => 'image/svg+xml',
+ 'svgz' => 'image/svg+xml',
+ 'swa' => 'application/x-director',
+ 'swf' => 'application/x-shockwave-flash',
+ 'swi' => 'application/vnd.aristanetworks.swi',
+ 'sxc' => 'application/vnd.sun.xml.calc',
+ 'sxd' => 'application/vnd.sun.xml.draw',
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
+ 'sxi' => 'application/vnd.sun.xml.impress',
+ 'sxm' => 'application/vnd.sun.xml.math',
+ 'sxw' => 'application/vnd.sun.xml.writer',
+ 't' => 'text/troff',
+ 'tao' => 'application/vnd.tao.intent-module-archive',
+ 'tar' => 'application/x-tar',
+ 'tcap' => 'application/vnd.3gpp2.tcap',
+ 'tcl' => 'application/x-tcl',
+ 'teacher' => 'application/vnd.smart.teacher',
+ 'tei' => 'application/tei+xml',
+ 'teicorpus' => 'application/tei+xml',
+ 'tex' => 'application/x-tex',
+ 'texi' => 'application/x-texinfo',
+ 'texinfo' => 'application/x-texinfo',
+ 'text' => 'text/plain',
+ 'tfi' => 'application/thraud+xml',
+ 'tfm' => 'application/x-tex-tfm',
+ 'thmx' => 'application/vnd.ms-officetheme',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'tmo' => 'application/vnd.tmobile-livetv',
+ 'torrent' => 'application/x-bittorrent',
+ 'tpl' => 'application/vnd.groove-tool-template',
+ 'tpt' => 'application/vnd.trid.tpt',
+ 'tr' => 'text/troff',
+ 'tra' => 'application/vnd.trueapp',
+ 'trm' => 'application/x-msterminal',
+ 'tsd' => 'application/timestamped-data',
+ 'tsv' => 'text/tab-separated-values',
+ 'ttc' => 'application/x-font-ttf',
+ 'ttf' => 'application/x-font-ttf',
+ 'ttl' => 'text/turtle',
+ 'twd' => 'application/vnd.simtech-mindmapper',
+ 'twds' => 'application/vnd.simtech-mindmapper',
+ 'txd' => 'application/vnd.genomatix.tuxedo',
+ 'txf' => 'application/vnd.mobius.txf',
+ 'txt' => 'text/plain',
+ 'u32' => 'application/x-authorware-bin',
+ 'udeb' => 'application/x-debian-package',
+ 'ufd' => 'application/vnd.ufdl',
+ 'ufdl' => 'application/vnd.ufdl',
+ 'umj' => 'application/vnd.umajin',
+ 'unityweb' => 'application/vnd.unity',
+ 'uoml' => 'application/vnd.uoml+xml',
+ 'uri' => 'text/uri-list',
+ 'uris' => 'text/uri-list',
+ 'urls' => 'text/uri-list',
+ 'ustar' => 'application/x-ustar',
+ 'utz' => 'application/vnd.uiq.theme',
+ 'uu' => 'text/x-uuencode',
+ 'uva' => 'audio/vnd.dece.audio',
+ 'uvd' => 'application/vnd.dece.data',
+ 'uvf' => 'application/vnd.dece.data',
+ 'uvg' => 'image/vnd.dece.graphic',
+ 'uvh' => 'video/vnd.dece.hd',
+ 'uvi' => 'image/vnd.dece.graphic',
+ 'uvm' => 'video/vnd.dece.mobile',
+ 'uvp' => 'video/vnd.dece.pd',
+ 'uvs' => 'video/vnd.dece.sd',
+ 'uvt' => 'application/vnd.dece.ttml+xml',
+ 'uvu' => 'video/vnd.uvvu.mp4',
+ 'uvv' => 'video/vnd.dece.video',
+ 'uvva' => 'audio/vnd.dece.audio',
+ 'uvvd' => 'application/vnd.dece.data',
+ 'uvvf' => 'application/vnd.dece.data',
+ 'uvvg' => 'image/vnd.dece.graphic',
+ 'uvvh' => 'video/vnd.dece.hd',
+ 'uvvi' => 'image/vnd.dece.graphic',
+ 'uvvm' => 'video/vnd.dece.mobile',
+ 'uvvp' => 'video/vnd.dece.pd',
+ 'uvvs' => 'video/vnd.dece.sd',
+ 'uvvt' => 'application/vnd.dece.ttml+xml',
+ 'uvvu' => 'video/vnd.uvvu.mp4',
+ 'uvvv' => 'video/vnd.dece.video',
+ 'uvvx' => 'application/vnd.dece.unspecified',
+ 'uvx' => 'application/vnd.dece.unspecified',
+ 'vcd' => 'application/x-cdlink',
+ 'vcf' => 'text/x-vcard',
+ 'vcg' => 'application/vnd.groove-vcard',
+ 'vcs' => 'text/x-vcalendar',
+ 'vcx' => 'application/vnd.vcx',
+ 'vis' => 'application/vnd.visionary',
+ 'viv' => 'video/vnd.vivo',
+ 'vor' => 'application/vnd.stardivision.writer',
+ 'vox' => 'application/x-authorware-bin',
+ 'vrml' => 'model/vrml',
+ 'vsd' => 'application/vnd.visio',
+ 'vsf' => 'application/vnd.vsf',
+ 'vss' => 'application/vnd.visio',
+ 'vst' => 'application/vnd.visio',
+ 'vsw' => 'application/vnd.visio',
+ 'vtu' => 'model/vnd.vtu',
+ 'vxml' => 'application/voicexml+xml',
+ 'w3d' => 'application/x-director',
+ 'wad' => 'application/x-doom',
+ 'wav' => 'audio/x-wav',
+ 'wax' => 'audio/x-ms-wax',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'wbs' => 'application/vnd.criticaltools.wbs+xml',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wcm' => 'application/vnd.ms-works',
+ 'wdb' => 'application/vnd.ms-works',
+ 'weba' => 'audio/webm',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wg' => 'application/vnd.pmi.widget',
+ 'wgt' => 'application/widget',
+ 'wks' => 'application/vnd.ms-works',
+ 'wm' => 'video/x-ms-wm',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmd' => 'application/x-ms-wmd',
+ 'wmf' => 'application/x-msmetafile',
+ 'wml' => 'text/vnd.wap.wml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'wmls' => 'text/vnd.wap.wmlscript',
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wmz' => 'application/x-ms-wmz',
+ 'woff' => 'application/x-font-woff',
+ 'wpd' => 'application/vnd.wordperfect',
+ 'wpl' => 'application/vnd.ms-wpl',
+ 'wps' => 'application/vnd.ms-works',
+ 'wqd' => 'application/vnd.wqd',
+ 'wri' => 'application/x-mswrite',
+ 'wrl' => 'model/vrml',
+ 'wsdl' => 'application/wsdl+xml',
+ 'wspolicy' => 'application/wspolicy+xml',
+ 'wtb' => 'application/vnd.webturbo',
+ 'wvx' => 'video/x-ms-wvx',
+ 'x32' => 'application/x-authorware-bin',
+ 'x3d' => 'application/vnd.hzn-3d-crossword',
+ 'xap' => 'application/x-silverlight-app',
+ 'xar' => 'application/vnd.xara',
+ 'xbap' => 'application/x-ms-xbap',
+ 'xbd' => 'application/vnd.fujixerox.docuworks.binder',
+ 'xbm' => 'image/x-xbitmap',
+ 'xdf' => 'application/xcap-diff+xml',
+ 'xdm' => 'application/vnd.syncml.dm+xml',
+ 'xdp' => 'application/vnd.adobe.xdp+xml',
+ 'xdssc' => 'application/dssc+xml',
+ 'xdw' => 'application/vnd.fujixerox.docuworks',
+ 'xenc' => 'application/xenc+xml',
+ 'xer' => 'application/patch-ops-error+xml',
+ 'xfdf' => 'application/vnd.adobe.xfdf',
+ 'xfdl' => 'application/vnd.xfdl',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xhvml' => 'application/xv+xml',
+ 'xif' => 'image/vnd.xiff',
+ 'xla' => 'application/vnd.ms-excel',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
+ 'xlc' => 'application/vnd.ms-excel',
+ 'xlm' => 'application/vnd.ms-excel',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xlt' => 'application/vnd.ms-excel',
+ 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'xlw' => 'application/vnd.ms-excel',
+ 'xml' => 'application/xml',
+ 'xo' => 'application/vnd.olpc-sugar',
+ 'xop' => 'application/xop+xml',
+ 'xpi' => 'application/x-xpinstall',
+ 'xpm' => 'image/x-xpixmap',
+ 'xpr' => 'application/vnd.is-xpr',
+ 'xps' => 'application/vnd.ms-xpsdocument',
+ 'xpw' => 'application/vnd.intercon.formnet',
+ 'xpx' => 'application/vnd.intercon.formnet',
+ 'xsl' => 'application/xml',
+ 'xslt' => 'application/xslt+xml',
+ 'xsm' => 'application/vnd.syncml+xml',
+ 'xspf' => 'application/xspf+xml',
+ 'xul' => 'application/vnd.mozilla.xul+xml',
+ 'xvm' => 'application/xv+xml',
+ 'xvml' => 'application/xv+xml',
+ 'xwd' => 'image/x-xwindowdump',
+ 'xyz' => 'chemical/x-xyz',
+ 'yaml' => 'text/yaml',
+ 'yang' => 'application/yang',
+ 'yin' => 'application/yin+xml',
+ 'yml' => 'text/yaml',
+ 'zaz' => 'application/vnd.zzazz.deck+xml',
+ 'zip' => 'application/zip',
+ 'zir' => 'application/vnd.zul',
+ 'zirz' => 'application/vnd.zul',
+ 'zmm' => 'application/vnd.handheld-entertainment+xml'
+ );
+
+ /**
+ * Get a singleton instance of the class
+ *
+ * @return self
+ * @codeCoverageIgnore
+ */
+ public static function getInstance()
+ {
+ if (!self::$instance) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get a mimetype value from a file extension
+ *
+ * @param string $extension File extension
+ *
+ * @return string|null
+ *
+ */
+ public function fromExtension($extension)
+ {
+ $extension = strtolower($extension);
+
+ return isset($this->mimetypes[$extension]) ? $this->mimetypes[$extension] : null;
+ }
+
+ /**
+ * Get a mimetype from a filename
+ *
+ * @param string $filename Filename to generate a mimetype from
+ *
+ * @return string|null
+ */
+ public function fromFilename($filename)
+ {
+ return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php
new file mode 100755
index 0000000..4b4e49d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/CommaAggregator.php
@@ -0,0 +1,20 @@
+isUrlEncoding()) {
+ return array($query->encodeValue($key) => implode(',', array_map(array($query, 'encodeValue'), $value)));
+ } else {
+ return array($key => implode(',', $value));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php
new file mode 100755
index 0000000..1bf1730
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/DuplicateAggregator.php
@@ -0,0 +1,22 @@
+isUrlEncoding()) {
+ return array($query->encodeValue($key) => array_map(array($query, 'encodeValue'), $value));
+ } else {
+ return array($key => $value);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php
new file mode 100755
index 0000000..133ea2b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/PhpAggregator.php
@@ -0,0 +1,27 @@
+ $v) {
+ $k = "{$key}[{$k}]";
+ if (is_array($v)) {
+ $ret = array_merge($ret, self::aggregate($k, $v, $query));
+ } else {
+ $ret[$query->encodeValue($k)] = $query->encodeValue($v);
+ }
+ }
+
+ return $ret;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php
new file mode 100755
index 0000000..72bee62
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php
@@ -0,0 +1,22 @@
+add($key, $value);
+ $foundDuplicates = true;
+ } elseif ($paramIsPhpStyleArray) {
+ $q[$key] = array($value);
+ } else {
+ $q[$key] = $value;
+ }
+ } else {
+ // Uses false by default to represent keys with no trailing "=" sign.
+ $q->add($key, false);
+ }
+ }
+
+ // Use the duplicate aggregator if duplicates were found and not using PHP style arrays
+ if ($foundDuplicates && !$foundPhpStyle) {
+ $q->setAggregator(new DuplicateAggregator());
+ }
+
+ return $q;
+ }
+
+ /**
+ * Convert the query string parameters to a query string string
+ *
+ * @return string
+ * @throws RuntimeException
+ */
+ public function __toString()
+ {
+ if (!$this->data) {
+ return '';
+ }
+
+ $queryList = array();
+ foreach ($this->prepareData($this->data) as $name => $value) {
+ $queryList[] = $this->convertKvp($name, $value);
+ }
+
+ return implode($this->fieldSeparator, $queryList);
+ }
+
+ /**
+ * Get the query string field separator
+ *
+ * @return string
+ */
+ public function getFieldSeparator()
+ {
+ return $this->fieldSeparator;
+ }
+
+ /**
+ * Get the query string value separator
+ *
+ * @return string
+ */
+ public function getValueSeparator()
+ {
+ return $this->valueSeparator;
+ }
+
+ /**
+ * Returns the type of URL encoding used by the query string
+ *
+ * One of: false, "RFC 3986", or "application/x-www-form-urlencoded"
+ *
+ * @return bool|string
+ */
+ public function getUrlEncoding()
+ {
+ return $this->urlEncode;
+ }
+
+ /**
+ * Returns true or false if using URL encoding
+ *
+ * @return bool
+ */
+ public function isUrlEncoding()
+ {
+ return $this->urlEncode !== false;
+ }
+
+ /**
+ * Provide a function for combining multi-valued query string parameters into a single or multiple fields
+ *
+ * @param null|QueryAggregatorInterface $aggregator Pass in a QueryAggregatorInterface object to handle converting
+ * deeply nested query string variables into a flattened array.
+ * Pass null to use the default PHP style aggregator. For legacy
+ * reasons, this function accepts a callable that must accepts a
+ * $key, $value, and query object.
+ * @return self
+ * @see \Guzzle\Http\QueryString::aggregateUsingComma()
+ */
+ public function setAggregator(QueryAggregatorInterface $aggregator = null)
+ {
+ // Use the default aggregator if none was set
+ if (!$aggregator) {
+ if (!self::$defaultAggregator) {
+ self::$defaultAggregator = new PhpAggregator();
+ }
+ $aggregator = self::$defaultAggregator;
+ }
+
+ $this->aggregator = $aggregator;
+
+ return $this;
+ }
+
+ /**
+ * Set whether or not field names and values should be rawurlencoded
+ *
+ * @param bool|string $encode Set to TRUE to use RFC 3986 encoding (rawurlencode), false to disable encoding, or
+ * form_urlencoding to use application/x-www-form-urlencoded encoding (urlencode)
+ * @return self
+ */
+ public function useUrlEncoding($encode)
+ {
+ $this->urlEncode = ($encode === true) ? self::RFC_3986 : $encode;
+
+ return $this;
+ }
+
+ /**
+ * Set the query string separator
+ *
+ * @param string $separator The query string separator that will separate fields
+ *
+ * @return self
+ */
+ public function setFieldSeparator($separator)
+ {
+ $this->fieldSeparator = $separator;
+
+ return $this;
+ }
+
+ /**
+ * Set the query string value separator
+ *
+ * @param string $separator The query string separator that will separate values from fields
+ *
+ * @return self
+ */
+ public function setValueSeparator($separator)
+ {
+ $this->valueSeparator = $separator;
+
+ return $this;
+ }
+
+ /**
+ * Returns an array of url encoded field names and values
+ *
+ * @return array
+ */
+ public function urlEncode()
+ {
+ return $this->prepareData($this->data);
+ }
+
+ /**
+ * URL encodes a value based on the url encoding type of the query string object
+ *
+ * @param string $value Value to encode
+ *
+ * @return string
+ */
+ public function encodeValue($value)
+ {
+ if ($this->urlEncode == self::RFC_3986) {
+ return rawurlencode($value);
+ } elseif ($this->urlEncode == self::FORM_URLENCODED) {
+ return urlencode($value);
+ } else {
+ return (string) $value;
+ }
+ }
+
+ /**
+ * Url encode parameter data and convert nested query strings into a flattened hash.
+ *
+ * @param array $data The data to encode
+ *
+ * @return array Returns an array of encoded values and keys
+ */
+ protected function prepareData(array $data)
+ {
+ // If no aggregator is present then set the default
+ if (!$this->aggregator) {
+ $this->setAggregator(null);
+ }
+
+ $temp = array();
+ foreach ($data as $key => $value) {
+ if ($value === false || $value === null) {
+ // False and null will not include the "=". Use an empty string to include the "=".
+ $temp[$this->encodeValue($key)] = $value;
+ } elseif (is_array($value)) {
+ $temp = array_merge($temp, $this->aggregator->aggregate($key, $value, $this));
+ } else {
+ $temp[$this->encodeValue($key)] = $this->encodeValue($value);
+ }
+ }
+
+ return $temp;
+ }
+
+ /**
+ * Converts a key value pair that can contain strings, nulls, false, or arrays
+ * into a single string.
+ *
+ * @param string $name Name of the field
+ * @param mixed $value Value of the field
+ * @return string
+ */
+ private function convertKvp($name, $value)
+ {
+ if ($value === self::BLANK || $value === null || $value === false) {
+ return $name;
+ } elseif (!is_array($value)) {
+ return $name . $this->valueSeparator . $value;
+ }
+
+ $result = '';
+ foreach ($value as $v) {
+ $result .= $this->convertKvp($name, $v) . $this->fieldSeparator;
+ }
+
+ return rtrim($result, $this->fieldSeparator);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php
new file mode 100755
index 0000000..ef28273
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/ReadLimitEntityBody.php
@@ -0,0 +1,122 @@
+setLimit($limit)->setOffset($offset);
+ }
+
+ /**
+ * Returns only a subset of the decorated entity body when cast as a string
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ if (!$this->body->isReadable() ||
+ (!$this->body->isSeekable() && $this->body->isConsumed())
+ ) {
+ return '';
+ }
+
+ $originalPos = $this->body->ftell();
+ $this->body->seek($this->offset);
+ $data = '';
+ while (!$this->feof()) {
+ $data .= $this->read(1048576);
+ }
+ $this->body->seek($originalPos);
+
+ return (string) $data ?: '';
+ }
+
+ public function isConsumed()
+ {
+ return $this->body->isConsumed() ||
+ ($this->body->ftell() >= $this->offset + $this->limit);
+ }
+
+ /**
+ * Returns the Content-Length of the limited subset of data
+ * {@inheritdoc}
+ */
+ public function getContentLength()
+ {
+ $length = $this->body->getContentLength();
+
+ return $length === false
+ ? $this->limit
+ : min($this->limit, min($length, $this->offset + $this->limit) - $this->offset);
+ }
+
+ /**
+ * Allow for a bounded seek on the read limited entity body
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ return $whence === SEEK_SET
+ ? $this->body->seek(max($this->offset, min($this->offset + $this->limit, $offset)))
+ : false;
+ }
+
+ /**
+ * Set the offset to start limiting from
+ *
+ * @param int $offset Offset to seek to and begin byte limiting from
+ *
+ * @return self
+ */
+ public function setOffset($offset)
+ {
+ $this->body->seek($offset);
+ $this->offset = $offset;
+
+ return $this;
+ }
+
+ /**
+ * Set the limit of bytes that the decorator allows to be read from the stream
+ *
+ * @param int $limit Total number of bytes to allow to be read from the stream
+ *
+ * @return self
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+
+ return $this;
+ }
+
+ public function read($length)
+ {
+ // Check if the current position is less than the total allowed bytes + original offset
+ $remaining = ($this->offset + $this->limit) - $this->body->ftell();
+ if ($remaining > 0) {
+ // Only return the amount of requested data, ensuring that the byte limit is not exceeded
+ return $this->body->read(min($remaining, $length));
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php
new file mode 100755
index 0000000..1a824b8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/RedirectPlugin.php
@@ -0,0 +1,250 @@
+ array('onRequestSent', 100),
+ 'request.clone' => 'cleanupRequest',
+ 'request.before_send' => 'cleanupRequest'
+ );
+ }
+
+ /**
+ * Clean up the parameters of a request when it is cloned
+ *
+ * @param Event $event Event emitted
+ */
+ public function cleanupRequest(Event $event)
+ {
+ $params = $event['request']->getParams();
+ unset($params[self::REDIRECT_COUNT]);
+ unset($params[self::PARENT_REQUEST]);
+ }
+
+ /**
+ * Called when a request receives a redirect response
+ *
+ * @param Event $event Event emitted
+ */
+ public function onRequestSent(Event $event)
+ {
+ $response = $event['response'];
+ $request = $event['request'];
+
+ // Only act on redirect requests with Location headers
+ if (!$response || $request->getParams()->get(self::DISABLE)) {
+ return;
+ }
+
+ // Trace the original request based on parameter history
+ $original = $this->getOriginalRequest($request);
+
+ // Terminating condition to set the effective response on the original request
+ if (!$response->isRedirect() || !$response->hasHeader('Location')) {
+ if ($request !== $original) {
+ // This is a terminating redirect response, so set it on the original request
+ $response->getParams()->set(self::REDIRECT_COUNT, $original->getParams()->get(self::REDIRECT_COUNT));
+ $original->setResponse($response);
+ $response->setEffectiveUrl($request->getUrl());
+ }
+ return;
+ }
+
+ $this->sendRedirectRequest($original, $request, $response);
+ }
+
+ /**
+ * Get the original request that initiated a series of redirects
+ *
+ * @param RequestInterface $request Request to get the original request from
+ *
+ * @return RequestInterface
+ */
+ protected function getOriginalRequest(RequestInterface $request)
+ {
+ $original = $request;
+ // The number of redirects is held on the original request, so determine which request that is
+ while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) {
+ $original = $parent;
+ }
+
+ return $original;
+ }
+
+ /**
+ * Create a redirect request for a specific request object
+ *
+ * Takes into account strict RFC compliant redirection (e.g. redirect POST with POST) vs doing what most clients do
+ * (e.g. redirect POST with GET).
+ *
+ * @param RequestInterface $request Request being redirected
+ * @param RequestInterface $original Original request
+ * @param int $statusCode Status code of the redirect
+ * @param string $location Location header of the redirect
+ *
+ * @return RequestInterface Returns a new redirect request
+ * @throws CouldNotRewindStreamException If the body needs to be rewound but cannot
+ */
+ protected function createRedirectRequest(
+ RequestInterface $request,
+ $statusCode,
+ $location,
+ RequestInterface $original
+ ) {
+ $redirectRequest = null;
+ $strict = $original->getParams()->get(self::STRICT_REDIRECTS);
+
+ // Switch method to GET for 303 redirects. 301 and 302 redirects also switch to GET unless we are forcing RFC
+ // compliance to emulate what most browsers do. NOTE: IE only switches methods on 301/302 when coming from a POST.
+ if ($request instanceof EntityEnclosingRequestInterface && ($statusCode == 303 || (!$strict && $statusCode <= 302))) {
+ $redirectRequest = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET');
+ } else {
+ $redirectRequest = clone $request;
+ }
+
+ $redirectRequest->setIsRedirect(true);
+ // Always use the same response body when redirecting
+ $redirectRequest->setResponseBody($request->getResponseBody());
+
+ $location = Url::factory($location);
+ // If the location is not absolute, then combine it with the original URL
+ if (!$location->isAbsolute()) {
+ $originalUrl = $redirectRequest->getUrl(true);
+ // Remove query string parameters and just take what is present on the redirect Location header
+ $originalUrl->getQuery()->clear();
+ $location = $originalUrl->combine((string) $location, true);
+ }
+
+ $redirectRequest->setUrl($location);
+
+ // Add the parent request to the request before it sends (make sure it's before the onRequestClone event too)
+ $redirectRequest->getEventDispatcher()->addListener(
+ 'request.before_send',
+ $func = function ($e) use (&$func, $request, $redirectRequest) {
+ $redirectRequest->getEventDispatcher()->removeListener('request.before_send', $func);
+ $e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST, $request);
+ }
+ );
+
+ // Rewind the entity body of the request if needed
+ if ($redirectRequest instanceof EntityEnclosingRequestInterface && $redirectRequest->getBody()) {
+ $body = $redirectRequest->getBody();
+ // Only rewind the body if some of it has been read already, and throw an exception if the rewind fails
+ if ($body->ftell() && !$body->rewind()) {
+ throw new CouldNotRewindStreamException(
+ 'Unable to rewind the non-seekable entity body of the request after redirecting. cURL probably '
+ . 'sent part of body before the redirect occurred. Try adding acustom rewind function using on the '
+ . 'entity body of the request using setRewindFunction().'
+ );
+ }
+ }
+
+ return $redirectRequest;
+ }
+
+ /**
+ * Prepare the request for redirection and enforce the maximum number of allowed redirects per client
+ *
+ * @param RequestInterface $original Original request
+ * @param RequestInterface $request Request to prepare and validate
+ * @param Response $response The current response
+ *
+ * @return RequestInterface
+ */
+ protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response)
+ {
+ $params = $original->getParams();
+ // This is a new redirect, so increment the redirect counter
+ $current = $params[self::REDIRECT_COUNT] + 1;
+ $params[self::REDIRECT_COUNT] = $current;
+ // Use a provided maximum value or default to a max redirect count of 5
+ $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects;
+
+ // Throw an exception if the redirect count is exceeded
+ if ($current > $max) {
+ $this->throwTooManyRedirectsException($original, $max);
+ return false;
+ } else {
+ // Create a redirect request based on the redirect rules set on the request
+ return $this->createRedirectRequest(
+ $request,
+ $response->getStatusCode(),
+ trim($response->getLocation()),
+ $original
+ );
+ }
+ }
+
+ /**
+ * Send a redirect request and handle any errors
+ *
+ * @param RequestInterface $original The originating request
+ * @param RequestInterface $request The current request being redirected
+ * @param Response $response The response of the current request
+ *
+ * @throws BadResponseException|\Exception
+ */
+ protected function sendRedirectRequest(RequestInterface $original, RequestInterface $request, Response $response)
+ {
+ // Validate and create a redirect request based on the original request and current response
+ if ($redirectRequest = $this->prepareRedirection($original, $request, $response)) {
+ try {
+ $redirectRequest->send();
+ } catch (BadResponseException $e) {
+ $e->getResponse();
+ if (!$e->getResponse()) {
+ throw $e;
+ }
+ }
+ }
+ }
+
+ /**
+ * Throw a too many redirects exception for a request
+ *
+ * @param RequestInterface $original Request
+ * @param int $max Max allowed redirects
+ *
+ * @throws TooManyRedirectsException when too many redirects have been issued
+ */
+ protected function throwTooManyRedirectsException(RequestInterface $original, $max)
+ {
+ $original->getEventDispatcher()->addListener(
+ 'request.complete',
+ $func = function ($e) use (&$func, $original, $max) {
+ $original->getEventDispatcher()->removeListener('request.complete', $func);
+ $str = "{$max} redirects were issued for this request:\n" . $e['request']->getRawHeaders();
+ throw new TooManyRedirectsException($str);
+ }
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem
new file mode 100755
index 0000000..18ce703
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Resources/cacert.pem
@@ -0,0 +1,3870 @@
+##
+## Bundle of CA Root Certificates
+##
+## Certificate data from Mozilla downloaded on: Wed Aug 13 21:49:32 2014
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt). This file can be found in the mozilla source tree:
+## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
+##
+## It contains the certificates in PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+## Conversion done with mk-ca-bundle.pl verison 1.22.
+## SHA1: bf2c15b3019e696660321d2227d942936dc50aa7
+##
+
+
+GTE CyberTrust Global Root
+==========================
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg
+Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG
+A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz
+MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL
+Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0
+IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u
+sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql
+HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID
+AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW
+M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF
+NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+Thawte Server CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
+dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE
+AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j
+b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV
+BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u
+c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG
+A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
+ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
+/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7
+1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J
+GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ
+GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+Thawte Premium Server CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
+dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE
+AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl
+ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU
+VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2
+aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ
+cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
+aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh
+Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/
+qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm
+SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf
+8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t
+UCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+Equifax Secure CA
+=================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
+ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
+B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
+fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
+8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
+A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
+CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
+A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
+spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
+Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
+zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
+BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
+70+sB3c4
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
+f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
+hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA
+TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah
+WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf
+Tqj/ZA1k
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G2
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO
+FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71
+lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT
+1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD
+Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
+-----END CERTIFICATE-----
+
+GlobalSign Root CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
+GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
+b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
+BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
+VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
+DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
+THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
+Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
+c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
+gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
+AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
+Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
+j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
+hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
+X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
+ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
+s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
+S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
+TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
+ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
+YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
+BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
+9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
+01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
+9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+ValiCert Class 1 VA
+===================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy
+MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi
+GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm
+DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG
+lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX
+icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP
+Orf1LXLI
+-----END CERTIFICATE-----
+
+ValiCert Class 2 VA
+===================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
+MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC
+CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf
+ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ
+SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV
+UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8
+W9ViH0Pd
+-----END CERTIFICATE-----
+
+RSA Root Certificate 1
+======================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
+MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td
+3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H
+BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs
+3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF
+V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r
+on+jjBXu
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
+EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
+cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
+EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
+055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
+j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
+xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
+t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+Verisign Class 4 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS
+tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM
+8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW
+Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX
+Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
+mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd
+RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG
+UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+Entrust.net Secure Server CA
+============================
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV
+BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg
+cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl
+ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG
+A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi
+eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p
+dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ
+aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5
+gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw
+ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw
+CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l
+dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw
+NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow
+HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN
+Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9
+n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+Entrust.net Premium 2048 Secure Server CA
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
+ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
+bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
+NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
+d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
+ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
+hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
+nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
+KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
+T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
+J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
+nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
+-----END CERTIFICATE-----
+
+Baltimore CyberTrust Root
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
+ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
+ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
+SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
+dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
+uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
+UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
+G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
+XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
+l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
+VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
+BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
+cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
+hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
+Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
+RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+Equifax Secure Global eBusiness CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp
+bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx
+HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds
+b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV
+PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN
+qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn
+hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
+BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs
+MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN
+I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY
+NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+Equifax Secure eBusiness CA 1
+=============================
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB
+LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE
+ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz
+IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ
+1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a
+IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk
+MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW
+Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF
+AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5
+lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+
+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+AddTrust Low-Value Services Root
+================================
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU
+cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw
+CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO
+ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6
+54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr
+oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1
+Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui
+GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w
+HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT
+RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw
+HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt
+ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
+iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr
+mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj
+ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+AddTrust External Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
+VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
+NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
+cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
+Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
+Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
+aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
+2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
+7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
+VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
+VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
+j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
+e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
+G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+AddTrust Public Services Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU
+cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ
+BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l
+dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu
+nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i
+d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG
+Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw
+HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G
+A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G
+A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4
+JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9
+Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H
+EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+AddTrust Qualified Certificates Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU
+cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx
+CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
+IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx
+64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3
+KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o
+L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR
+wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU
+MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE
+BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y
+azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
+GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze
+RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB
+iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
+b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
+A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
+MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
+MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
+Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
+A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
+Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
+j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
+rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
+MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
+hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
+Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
+v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
+W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
+tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+RSA Security 2048 v3
+====================
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
+ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
+MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
+BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
+Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
+WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
+KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
+FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
+v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
+0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
+VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
+nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
+pKnXwiJPZ9d37CAFYd4=
+-----END CERTIFICATE-----
+
+GeoTrust Global CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
+MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
+BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
+8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
+T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
+vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
+DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
+zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
+d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
+mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
+XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
+Mw==
+-----END CERTIFICATE-----
+
+GeoTrust Global CA 2
+====================
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw
+MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/
+NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k
+LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA
+Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b
+HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH
+K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7
+srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh
+ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL
+OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC
+x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
+H4z1Ir+rzoPz4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
+MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
+Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
+JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
+RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
+7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
+8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
+qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
+Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
+Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
+KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
+ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
+XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
+hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
+qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
+oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
+xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
+KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
+DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
+xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
+p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
+P/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA 2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
+MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
+SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
+DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
+j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
+JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
+QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
+WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
+20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
+ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
+SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
+8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
+BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
+4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
+A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
+Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
+pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
+FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
+gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
+X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+America Online Root Certification Authority 1
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG
+A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
+T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG
+v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z
+DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh
+sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP
+8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T
+AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z
+o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf
+GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF
+VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft
+3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
+Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
+America Online Root Certification Authority 2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG
+A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
+T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en
+fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8
+f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO
+qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN
+RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0
+gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn
+6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid
+FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6
+Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj
+B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op
+aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY
+T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p
++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg
+JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy
+zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO
+ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh
+1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf
+GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff
+Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP
+cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk=
+-----END CERTIFICATE-----
+
+Visa eCommerce Root
+===================
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG
+EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug
+QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2
+WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm
+VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL
+F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b
+RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0
+TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI
+/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs
+GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc
+CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW
+YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz
+zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
+YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+
+Certum Root CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK
+ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla
+Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u
+by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x
+wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL
+kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ
+89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K
+Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P
+NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+
+GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg
+GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/
+0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS
+qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+Comodo AAA Services root
+========================
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
+MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
+c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
+BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
+C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
+i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
+Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
+Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
+Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
+BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
+cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
+LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
+7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
+8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
+12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+Comodo Secure Services root
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw
+MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
+Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi
+BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP
+9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc
+rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC
+oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V
+p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E
+FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj
+YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm
+aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
+4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL
+DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw
+pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H
+RR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+Comodo Trusted Services root
+============================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw
+MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h
+bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw
+IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7
+3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y
+/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6
+juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS
+ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud
+DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp
+ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl
+cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
+uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA
+BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l
+R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O
+9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+QuoVadis Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
+ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
+MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
+cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
+EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
+J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
+F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
+YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
+AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
+PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
+ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
+MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
+ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
+Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
+BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
+FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
+tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
+fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
+LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
+gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
+5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
+5nrQNiOKSnQ2+Q==
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
+ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
+XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
+lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
+lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
+lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
+66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
+wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
+D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
+BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
+J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
+DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
+a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
+Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
+UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
+VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
+IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
+WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
+f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
+4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
+VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3
+==================
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
+OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
+DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
+KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
+DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
+BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
+p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
+nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
+MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
+Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
+uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
+BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
+YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
+BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
+VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
+ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
+AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
+qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
+hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
+POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
+Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
+8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
+bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
+g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
+vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
+qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+Security Communication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
+8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
+DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
+5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
+DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
+JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
+0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
+mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
+s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
+6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
+FL39vmwLAw==
+-----END CERTIFICATE-----
+
+Sonera Class 2 Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
+NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
+IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
+/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
+dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
+f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
+tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
+nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
+XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
+0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
+cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
+Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
+EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
+llpwrN9M
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA
+=============================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE
+ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w
+HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh
+bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt
+vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P
+jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca
+C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth
+vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6
+22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV
+HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v
+dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN
+BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR
+EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw
+MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
+nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+
+TDC Internet Root CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE
+ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx
+NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu
+ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j
+xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL
+znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc
+5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6
+otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI
+AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM
+VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM
+MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC
+AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe
+UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G
+CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m
+gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb
+O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU
+Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+
+UTN DATACorp SGC Root CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ
+BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa
+MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w
+HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
+dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys
+raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo
+wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA
+9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv
+33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud
+DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9
+BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD
+LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
+DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0
+I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx
+EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP
+DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+UTN USERFirst Hardware Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
+BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
+OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
+eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
+ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
+wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
+tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
+i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
+Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
+gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
+lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
+UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
+BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
+XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
+lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
+iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
+nfhmqA==
+-----END CERTIFICATE-----
+
+Camerfirma Chambers of Commerce Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
+NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
+cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
+MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
+AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
+xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
+NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
+DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
+d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
+EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
+cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
+AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
+bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
+VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
+fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
+L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
+UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
+ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
+erfutGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+
+Camerfirma Global Chambersign Root
+==================================
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
+NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
+YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
+MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
+ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
+1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
+by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
+6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
+8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
+BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
+aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
+Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
+aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
+ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
+PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
+gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
+PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
+IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
+t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+
+NetLock Notary (Class A) Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI
+EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
+dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j
+ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX
+DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH
+EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD
+VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz
+cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM
+D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ
+z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC
+/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7
+tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6
+4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG
+A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC
+Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
+bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn
+LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0
+ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz
+IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh
+IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu
+b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg
+Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp
+bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5
+ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP
+ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB
+CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr
+KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM
+8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+
+NetLock Business (Class B) Root
+===============================
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg
+VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD
+VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv
+bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg
+VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S
+o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr
+1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV
+HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ
+RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh
+dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0
+ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv
+c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg
+YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz
+Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA
+bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl
+IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2
+YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj
+cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM
+43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR
+stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+
+NetLock Express (Class C) Root
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ
+BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
+dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j
+ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z
+W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63
+euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw
+DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN
+RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn
+YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB
+IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i
+aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0
+ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y
+emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k
+IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ
+UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg
+YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2
+xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW
+gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+
+XRamp Global CA Root
+====================
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
+BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
+dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
+HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
+U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
+IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
+foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
+zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
+AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
+xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
+oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
+AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
+/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
+nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
+8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+Go Daddy Class 2 CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
+VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
+A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
+ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
+qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
+YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
+vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
+BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
+atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
+MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
+PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
+I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
+Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
+vZ8=
+-----END CERTIFICATE-----
+
+Starfield Class 2 CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
+U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
+MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
+A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
+SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
+bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
+JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
+epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
+F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
+MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
+hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
+bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
+afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
+PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
+KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
+QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj
+YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH
+AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw
+Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg
+U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5
+LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh
+cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT
+dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC
+AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh
+3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm
+vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk
+fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3
+fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ
+EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl
+1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/
+lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro
+g14=
+-----END CERTIFICATE-----
+
+Taiwan GRCA
+===========
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG
+EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
+DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv
+dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN
+w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5
+BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O
+1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO
+htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov
+J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7
+Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t
+B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB
+O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8
+lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV
+HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
+09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj
+Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2
+Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU
+D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz
+DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk
+Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk
+7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ
+CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
+-----END CERTIFICATE-----
+
+Swisscom Root CA 1
+==================
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG
+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4
+MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM
+MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF
+NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe
+AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC
+b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn
+7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN
+cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp
+WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5
+haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY
+MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9
+MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn
+jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ
+MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H
+VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl
+vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl
+OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3
+1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq
+nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy
+x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW
+NY6E0F/6MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
+MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
+9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
+UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
+/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
+oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
+GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
+66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
+hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
+EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
+SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
+8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+DigiCert Global Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
+MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
+TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
+BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
+4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
+7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
+o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
+8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
+BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
+EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
+tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
+UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+DigiCert High Assurance EV Root CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
+KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
+MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
+MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
+Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
+Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
+OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
+MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
+NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
+h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
+Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
+JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
+V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
+myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
+mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
+-----END CERTIFICATE-----
+
+Certplus Class 2 Primary CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
+BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
+OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
+dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
+5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
+Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
+YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
+e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
+CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
+YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
+L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
+P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
+TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
+7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
+//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+
+DST Root CA X3
+==============
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
+ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
+DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
+cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
+rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
+UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
+xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
+utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
+MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
+dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
+GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
+RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
+fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+DST ACES CA X6
+==============
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
+MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
+MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
+CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
+DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
+pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
+GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
+MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
+Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
+dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
+CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
+5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
+Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
+vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
+oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 1
+==============================================
+-----BEGIN CERTIFICATE-----
+MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP
+MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0
+acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx
+MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg
+U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB
+TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC
+aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX
+yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i
+Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ
+8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4
+W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME
+BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46
+sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE
+q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
+B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY
+nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2
+==============================================
+-----BEGIN CERTIFICATE-----
+MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN
+MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr
+dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G
+A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
+acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe
+LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI
+x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g
+QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr
+5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB
+AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
+Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
+Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+
+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P
+9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5
+UrbnBEI=
+-----END CERTIFICATE-----
+
+SwissSign Gold CA - G2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
+EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
+MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
+c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
+t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
+jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
+vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
+ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
+AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
+jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
+peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
+7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
+GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
+OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
+5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
+44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
+Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
+Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
+mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
+vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
+KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
+NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
+viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+
+SwissSign Silver CA - G2
+========================
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
+BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
+DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
+aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
+N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
+6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
+MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
+qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
+FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
+ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
+celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
+CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
+tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
+4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
+kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
+3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
+/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
+DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
+e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
+WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
+DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
+DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
+cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
+b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
+nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
+RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
+tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
+hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
+Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
+NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
+Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
+1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+thawte Primary Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
+MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
+SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
+KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
+FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
+oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
+1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
+q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
+aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
+afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
+AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
+uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
+jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
+z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G5
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
+biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
+dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
+j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
+Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
+fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
+Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
+SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
+KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
+Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
+ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+SecureTrust CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
+dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
+BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
+OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
+DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
+GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
+01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
+ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
+aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
+SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
+mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
+nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+
+Secure Global CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
+bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
+MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
+Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
+YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
+bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
+8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
+HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
+0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
+oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
+MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
+CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
+3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+
+COMODO Certification Authority
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
+MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
+xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
+4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
+1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
+rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
+AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
+OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
+IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
+-----END CERTIFICATE-----
+
+Network Solutions Certificate Authority
+=======================================
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
+EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
+IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
+MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
+jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
+aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
+crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
+/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
+AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
+bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
+A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
+4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
+GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
+ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+WellsSecure Public Root Certificate Authority
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM
+F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw
+NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
+MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl
+bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD
+VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1
+iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13
+i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8
+bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB
+K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB
+AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu
+cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm
+lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB
+i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww
+GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI
+K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0
+bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj
+qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es
+E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ
+tylv2G0xffX8oRAHh84vWdw+WNs=
+-----END CERTIFICATE-----
+
+COMODO ECC Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
+GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
+4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
+wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
+FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
+U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+IGC/A
+=====
+-----BEGIN CERTIFICATE-----
+MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
+VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
+Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
+MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
+EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
+STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
+TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
+So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
+HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
+frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
+tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
+egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
+iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
+q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
+MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
+Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
+lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
+0mBWWg==
+-----END CERTIFICATE-----
+
+Security Communication EV RootCA1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
+BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
+Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
+/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
+WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
+ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
+bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
+9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
+iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
+Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
+mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
+T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GA CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
+BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
+A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
+bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
+VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
+IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
+IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
+Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
+Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
+d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
+/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
+LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
+MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
+okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE
+BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL
+EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0
+MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz
+dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT
+GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG
+d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N
+oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc
+QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ
+PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb
+MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG
+IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD
+VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
+LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A
+dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
+AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA
+4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg
+AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA
+egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6
+Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO
+PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv
+c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h
+cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw
+IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT
+WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV
+MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER
+MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp
+Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal
+HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT
+nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE
+aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
+86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK
+yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB
+S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
+-----END CERTIFICATE-----
+
+Certigna
+========
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
+EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
+MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
+Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
+XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
+GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
+ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
+DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
+Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
+tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
+BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
+SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
+hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
+PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
+1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+
+AC Ra\xC3\xADz Certic\xC3\xA1mara S.A.
+======================================
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT
+AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg
+LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w
+HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+
+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh
+IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN
+yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU
+2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3
+4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP
+2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm
+8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf
+HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa
+Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK
+5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b
+czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g
+ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF
+BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug
+cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf
+AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX
+EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v
+/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3
+MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4
+3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk
+eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f
+/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h
+RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU
+Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
+
+TC TrustCenter Class 2 CA II
+============================
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
+IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw
+MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
+c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE
+AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw
+IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2
+xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ
+Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u
+SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB
+7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
+Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
+cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
+SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G
+dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ
+KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj
+TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP
+JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk
+vQ==
+-----END CERTIFICATE-----
+
+TC TrustCenter Class 3 CA II
+============================
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
+IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw
+MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
+c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE
+AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W
+yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo
+6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ
+uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk
+2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB
+7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
+Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
+cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
+SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE
+O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8
+yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9
+IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal
+092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc
+5A==
+-----END CERTIFICATE-----
+
+TC TrustCenter Universal CA I
+=============================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
+IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN
+MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg
+VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw
+JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC
+qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv
+xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw
+ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O
+gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j
+BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG
+1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy
+vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3
+ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a
+7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+
+Deutsche Telekom Root CA 2
+==========================
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
+RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
+A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
+MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
+A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
+b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
+bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
+KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
+AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
+Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
+jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
+HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
+E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
+zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
+rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
+dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
+ComSign Secured CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE
+AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w
+NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD
+QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs
+49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH
+7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB
+kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1
+9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw
+AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t
+U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA
+j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC
+AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a
+BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp
+FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP
+51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
+OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
+-----END CERTIFICATE-----
+
+Cybertrust Global Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
+ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
+MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
+ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
+0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
+AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
+89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
+8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
+MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
+A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
+lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
+5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
+hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
+X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+ePKI Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
+EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
+MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
+MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
+IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
+lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
+qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
+12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
+WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
+lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
+vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
+Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
+MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
+1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
+KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
+xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
+NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
+GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
+xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
+gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
+sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
+BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+
+T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3
+=============================================================================================================================
+-----BEGIN CERTIFICATE-----
+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH
+DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q
+aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry
+b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV
+BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg
+S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4
+MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl
+IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF
+n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl
+IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft
+dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl
+cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO
+Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1
+xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR
+6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd
+BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4
+N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT
+y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh
+LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
+dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
+-----END CERTIFICATE-----
+
+Buypass Class 2 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
+MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
+cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
+0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
+0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
+uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
+1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
+7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
+fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
+wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
+-----END CERTIFICATE-----
+
+Buypass Class 3 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1
+MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx
+ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0
+n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia
+AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c
+1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7
+pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA
+EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5
+htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj
+el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
+-----END CERTIFICATE-----
+
+EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
+==========================================================================
+-----BEGIN CERTIFICATE-----
+MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg
+QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe
+Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p
+ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt
+IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by
+X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b
+gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr
+eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ
+TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy
+Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn
+uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI
+qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm
+ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0
+Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW
+Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t
+FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm
+zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k
+XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT
+bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU
+RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK
+1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt
+2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ
+Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9
+AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
+-----END CERTIFICATE-----
+
+certSIGN ROOT CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
+VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
+Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
+CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
+JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
+rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
+ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
+0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
+AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
+AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
+SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
+x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
+vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
+TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+
+CNNIC ROOT
+==========
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE
+ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw
+OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD
+o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz
+VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT
+VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or
+czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK
+y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC
+wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S
+lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5
+Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM
+O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8
+BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2
+G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m
+mxE=
+-----END CERTIFICATE-----
+
+ApplicationCA - Japanese Government
+===================================
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT
+SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw
+MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl
+cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4
+fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN
+wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE
+jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu
+nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU
+WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD
+vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs
+o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g
+/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD
+io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW
+dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
+rosot4LKGAfmt1t06SAZf7IbiVQ=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G3
+=============================================
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
+NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
+YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
+LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
+K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
+c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
+IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
+dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
+2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
+cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
+Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
+t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
+VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
+IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
+Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
+MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
+b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
+IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
+LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
+8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
+mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
+G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
+rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
+ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
+VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
+A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
+P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
+7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
+vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
+KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
+A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
+8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
+er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
+OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
+b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
+BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
+KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
+EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
+ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
+npaqBA+K
+-----END CERTIFICATE-----
+
+VeriSign Universal Root Certification Authority
+===============================================
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
+1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
+MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
+9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
+AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
+tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
+CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
+a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
+Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
+Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
+P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
+wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
+mJO37M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G4
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
+VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
+b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
+ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
+cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
+b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
+Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
+rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
+HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
+Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
+A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
+AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+NetLock Arany (Class Gold) Főtanúsítvány
+============================================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
+A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
+dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
+cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
+MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
+ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
+c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
+0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
+/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
+H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
+fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
+neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
+qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
+YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
+NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
+dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G2
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ
+5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn
+vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj
+CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil
+e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR
+OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI
+CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65
+48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi
+trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737
+qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB
+AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC
+ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA
+A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz
++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj
+f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN
+kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk
+CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF
+URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb
+CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h
+oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV
+IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
+66+KAQ==
+-----END CERTIFICATE-----
+
+CA Disig
+========
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK
+QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw
+MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz
+bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm
+GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD
+Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo
+hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt
+ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w
+gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P
+AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz
+aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff
+ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa
+BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t
+WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3
+mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
+CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K
+ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA
+4Z7CRneC9VkGjCFMhwnN5ag=
+-----END CERTIFICATE-----
+
+Juur-SK
+=======
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
+DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
+SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
+aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
+TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
+UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
+Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
+MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
+HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
+AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
+cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
+AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
+cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
+A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
+ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
+abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
+IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
+Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
+yyqcjg==
+-----END CERTIFICATE-----
+
+Hongkong Post Root CA 1
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
+DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
+NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
+IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
+ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
+auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
+qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
+V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
+HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
+h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
+l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
+IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
+T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
+c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
+-----END CERTIFICATE-----
+
+SecureSign RootCA11
+===================
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
+SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
+b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
+KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
+cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
+TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
+wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
+g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
+O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
+bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
+t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
+OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
+bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
+Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
+y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
+lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+
+ACEDICOM Root
+=============
+-----BEGIN CERTIFICATE-----
+MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD
+T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4
+MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG
+A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk
+WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD
+YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew
+MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb
+m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk
+HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT
+xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2
+3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9
+2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq
+TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz
+4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU
+9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv
+bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg
+aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP
+eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk
+zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1
+ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI
+KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq
+nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE
+I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp
+MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o
+tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
+f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
+hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky
+CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX
+bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/
+D/xwzoiQ
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
+MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
+c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
+BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
+U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
+fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
+0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
+pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
+1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
+AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
+QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
+FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
+lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
+I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
+yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
+LXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+
+E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
+===================================================
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz
+ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3
+MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0
+cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u
+aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY
+8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y
+jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI
+JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk
+9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG
+SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d
+F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq
+D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4
+Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
+fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R3
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
+iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
+0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
+rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
+OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
+xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
+lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
+EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
+bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
+YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
+kpeDMdmztcpHWD9f
+-----END CERTIFICATE-----
+
+Autoridad de Certificacion Firmaprofesional CIF A62634068
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
+BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
+QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
+NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
+Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
+B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
+7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
+ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
+plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
+MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
+LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
+bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
+vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
+EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
+DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
+bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
+ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
+51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
+R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
+T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
+Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
+osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
+crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
+saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
+KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
+6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+
+Izenpe.com
+==========
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
+EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
+MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
+QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
+03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
+ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
+PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
+OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
+F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
+0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
+leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
+AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
+NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
+Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
+kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
+hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
+g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
+aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
+nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
+ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
+Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
+WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+
+Chambers of Commerce Root - 2008
+================================
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
+Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
+ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
+EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
+cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
+XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
+h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
+ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
+NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
+D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
+lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
+0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
+EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
+G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
+BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
+bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
+bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
+CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
+AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
+wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
+3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
+RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
+M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
+YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
+9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
+zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
+nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
+-----END CERTIFICATE-----
+
+Global Chambersign Root - 2008
+==============================
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
+NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
+Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
+QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
+VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
+XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
+ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
+/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
+TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
+H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
+Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
+HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
+AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
+BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
+BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
+aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
+aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
+1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
+dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
+/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
+ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
+dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
+9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
+foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
+qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
+P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
+c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+
+Go Daddy Root Certificate Authority - G2
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
+MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
+A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
+9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
+fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
+NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
+BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
+vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
+5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
+N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+Starfield Root Certificate Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
+eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
+DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
+VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
+W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
+bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
+N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
+ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
+JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
+TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
+4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
+F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
+c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+Starfield Services Root Certificate Authority - G2
+==================================================
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
+IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
+dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
+h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
+hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
+LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
+rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
+SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
+E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
+xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
+YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
+-----END CERTIFICATE-----
+
+AffirmTrust Commercial
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
+MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
+DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
+C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
+BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
+MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
+HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
+hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
+qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
+0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
+sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+AffirmTrust Networking
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
+MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
+Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
+dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
+/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
+h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
+HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
+UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
+12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
+WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
+/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+AffirmTrust Premium
+===================
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
+OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
+dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
+BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
+5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
+GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
+p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
+S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
+6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
+/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
+MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
+6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
+L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
+BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
+IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
+g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
+zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+AffirmTrust Premium ECC
+=======================
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
+BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
+MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
+cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
+N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
+BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
+BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
+57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
+eQ==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
+ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
+MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
+ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
+l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
+J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
+fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
+cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
+Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
+jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
+mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
+Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+
+Certinomis - Autorité Racine
+=============================
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
+LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG
+A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw
+JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa
+wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly
+Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw
+2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N
+jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q
+c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC
+lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb
+xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g
+530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna
+4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x
+WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva
+R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40
+nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B
+CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv
+JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE
+qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b
+WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE
+wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
+vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+
+Root CA Generalitat Valenciana
+==============================
+-----BEGIN CERTIFICATE-----
+MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
+ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
+IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
+WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
+CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
+F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
+ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
+D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
+JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
+AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
+dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
+ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
+AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
+YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
+AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
+aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
+AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
+YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
+AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
+OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
+dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
+BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
+A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
+b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
+TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
+Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
+NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
+iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
+-----END CERTIFICATE-----
+
+A-Trust-nQual-03
+================
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE
+Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
+a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R
+dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw
+RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0
+ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1
+c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA
+zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n
+yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE
+SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4
+iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V
+cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV
+eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40
+ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr
+sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd
+JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
+mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6
+ahq97BvIxYSazQ==
+-----END CERTIFICATE-----
+
+TWCA Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
+VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
+EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
+IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
+QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
+oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
+4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
+y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
+9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
+mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
+QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
+T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
+Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+
+Security Communication RootCA2
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
+SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
+aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
+3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
+spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
+EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
+QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
+u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
+3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
+tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
+mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+
+EC-ACC
+======
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
+BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
+ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
+VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
+CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
+BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
+MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
+SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
+Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
+cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
+w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
+ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
+HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
+E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
+0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
+VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
+Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
+dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
+lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
+Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
+l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
+E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
+5EI=
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2011
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
+O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
+aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
+AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
+IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
+1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
+71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
+8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
+3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
+MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
+b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
+XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
+/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
+7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+
+Actalis Authentication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
+BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
+AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
+MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
+IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
+wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
+by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
+zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
+YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
+oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
+EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
+hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
+EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
+jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
+iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
+WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
+JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
+K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
+Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
+4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
+2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
+lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
+OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
+vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+
+Trustis FPS Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
+EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
+IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
+BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
+RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
+H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
+cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
+o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
+AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
+BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
+GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
+yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
+8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
+l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
+iB6XzCGcKQENZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ
+Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0
+dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu
+c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv
+bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0
+aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
+L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5
+fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm
+N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN
+Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T
+tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX
+e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA
+2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs
+HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib
+D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority G2
+===================================
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE
+ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O
+o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG
+4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi
+Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul
+Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs
+O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H
+vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L
+nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS
+FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa
+z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ
+KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk
+J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+
+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG
+/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc
+nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld
+blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc
+l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm
+7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm
+obp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+Buypass Class 2 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
+DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
+g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
+9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
+/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
+CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
+awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
+zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
+Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
+Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
+M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
+osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
+aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
+DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
+LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
+oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
+wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
+CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
+rJgWVqA=
+-----END CERTIFICATE-----
+
+Buypass Class 3 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
+DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
+sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
+5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
+7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
+ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
+2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
+/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
+RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
+Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
+j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
+uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
+Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
+ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
+KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
+6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
+UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
+eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
+Cp/HuZc=
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 3
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
+MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
+9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
+NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
+iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
+0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
+AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
+fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
+ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
+P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
+-----END CERTIFICATE-----
+
+EE Certification Centre Root CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
+dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
+MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
+UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
+ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
+TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
+rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
+93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
+P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
+MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
+BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
+xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
+lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
+3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
+dcGWxZ0=
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2007
+=================================================
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X
+DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl
+a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N
+YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv
+KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya
+KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT
+rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC
+AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s
+Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO
+Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb
+BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK
+poRq0Tl9
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
+Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
+LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
+ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
+BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
+KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
+p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
+AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
+4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
+eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
+MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
+PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
+OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
+2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
+dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
+X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 EV 2009
+=================================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
+egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
+zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
+7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
+sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
+11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
+cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
+ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
+MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
+b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
+c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
+PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
+ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
+NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
+w9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+
+PSCProcert
+==========
+-----BEGIN CERTIFICATE-----
+MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk
+ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ
+MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz
+dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl
+cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw
+IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw
+MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w
+DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD
+ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp
+Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC
+wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA
+3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh
+RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO
+EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2
+0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH
+0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU
+td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw
+Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp
+r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/
+AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz
+Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId
+xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp
+ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH
+EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h
+Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k
+ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG
+9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG
+MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG
+LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52
+ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy
+YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v
+Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o
+dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq
+T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN
+g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q
+uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1
+n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn
+FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo
+5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq
+3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5
+poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y
+eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
+-----END CERTIFICATE-----
+
+China Internet Network Information Center EV Certificates Root
+==============================================================
+-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D
+aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg
+Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG
+A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM
+PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl
+cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y
+jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV
+98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H
+klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23
+KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC
+7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD
+glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5
+0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM
+7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
+ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0
+5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=
+-----END CERTIFICATE-----
+
+Swisscom Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG
+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2
+MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM
+LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo
+ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ
+wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH
+Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a
+SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS
+NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab
+mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY
+Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3
+qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O
+BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu
+MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO
+v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ
+82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz
+o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs
+a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx
+OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW
+mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o
++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC
+rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX
+5OfNeOI5wSsSnqaeG8XmDtkx2Q==
+-----END CERTIFICATE-----
+
+Swisscom Root EV CA 2
+=====================
+-----BEGIN CERTIFICATE-----
+MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE
+BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl
+cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN
+MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT
+HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg
+Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz
+o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy
+Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti
+GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li
+qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH
+Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG
+alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa
+m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox
+bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi
+xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED
+MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB
+bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL
+j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU
+wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7
+XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH
+59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/
+23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq
+J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA
+HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi
+uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW
+l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=
+-----END CERTIFICATE-----
+
+CA Disig Root R1
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
+3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
+u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
+m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
+CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
+YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
+vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
+LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
+ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
+XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
+04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
+xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
+LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
+CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
+VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
+YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
+ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
+lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
+UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
+a7+h89n07eLw4+1knj0vllJPgFOL
+-----END CERTIFICATE-----
+
+CA Disig Root R2
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
+w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
+xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
+A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
+GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
+g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
+5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
+koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
+Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
+Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
+Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
+sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
+dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
+1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
+mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
+utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
+sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
+UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
+7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+
+ACCVRAIZ1
+=========
+-----BEGIN CERTIFICATE-----
+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
+SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
+MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
+UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
+jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
+RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
+aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
+0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
+WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
+8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
+5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
+9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
+Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
+Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
+Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
+Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
+QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
+AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
+YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
+AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
+IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
+aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
+dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
+MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
+hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
+R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
+YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
+nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
+TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
+sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
+Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
+3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
+EfbRD0tVNEYqi4Y7
+-----END CERTIFICATE-----
+
+TWCA Global Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
+CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
+QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
+EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
+nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
+r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
+Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
+tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
+KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
+sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
+yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
+kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
+zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
+cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
+8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
+/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
+lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
+A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
+i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
+EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
+zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
+-----END CERTIFICATE-----
+
+TeliaSonera Root CA v1
+======================
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
+CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
+MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
+VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
+6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
+3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
+B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
+Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
+oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
+F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
+oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
+gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
+TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
+AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
+DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
+zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
+pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
+G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
+c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
+JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
+qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
+Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
+WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
+-----END CERTIFICATE-----
+
+E-Tugra Certification Authority
+===============================
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
+DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
+ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
+ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
+NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
+QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
+cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
+DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
+hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
+CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
+ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
+BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
+E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
+rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
+jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
+rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
+dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
+/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
+kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
+XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
+VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
+a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
+dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
+KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
+Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
+8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
+C7TbO6Orb1wdtn7os4I07QZcJA==
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 2
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
+MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
+SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
+vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
+2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
+WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
+YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
+r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
+vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
+3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
+-----END CERTIFICATE-----
+
+Atos TrustedRoot 2011
+=====================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
+cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
+MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
+A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
+hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
+54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
+HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
+z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
+l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
+bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
+k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
+TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
+61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
+3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
+-----END CERTIFICATE-----
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php
new file mode 100755
index 0000000..dbd4c18
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/StaticClient.php
@@ -0,0 +1,157 @@
+createRequest($method, $url, null, null, $options);
+
+ if (isset($options['stream'])) {
+ if ($options['stream'] instanceof StreamRequestFactoryInterface) {
+ return $options['stream']->fromRequest($request);
+ } elseif ($options['stream'] == true) {
+ $streamFactory = new PhpStreamRequestFactory();
+ return $streamFactory->fromRequest($request);
+ }
+ }
+
+ return $request->send();
+ }
+
+ /**
+ * Send a GET request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function get($url, $options = array())
+ {
+ return self::request('GET', $url, $options);
+ }
+
+ /**
+ * Send a HEAD request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function head($url, $options = array())
+ {
+ return self::request('HEAD', $url, $options);
+ }
+
+ /**
+ * Send a DELETE request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function delete($url, $options = array())
+ {
+ return self::request('DELETE', $url, $options);
+ }
+
+ /**
+ * Send a POST request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function post($url, $options = array())
+ {
+ return self::request('POST', $url, $options);
+ }
+
+ /**
+ * Send a PUT request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function put($url, $options = array())
+ {
+ return self::request('PUT', $url, $options);
+ }
+
+ /**
+ * Send a PATCH request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function patch($url, $options = array())
+ {
+ return self::request('PATCH', $url, $options);
+ }
+
+ /**
+ * Send an OPTIONS request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return \Guzzle\Http\Message\Response
+ * @see Guzzle::request for a list of available options
+ */
+ public static function options($url, $options = array())
+ {
+ return self::request('OPTIONS', $url, $options);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Url.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Url.php
new file mode 100755
index 0000000..6a4e772
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/Url.php
@@ -0,0 +1,554 @@
+ null, 'host' => null, 'path' => null, 'port' => null, 'query' => null,
+ 'user' => null, 'pass' => null, 'fragment' => null);
+
+ if (false === ($parts = parse_url($url))) {
+ throw new InvalidArgumentException('Was unable to parse malformed url: ' . $url);
+ }
+
+ $parts += $defaults;
+
+ // Convert the query string into a QueryString object
+ if ($parts['query'] || 0 !== strlen($parts['query'])) {
+ $parts['query'] = QueryString::fromString($parts['query']);
+ }
+
+ return new static($parts['scheme'], $parts['host'], $parts['user'],
+ $parts['pass'], $parts['port'], $parts['path'], $parts['query'],
+ $parts['fragment']);
+ }
+
+ /**
+ * Build a URL from parse_url parts. The generated URL will be a relative URL if a scheme or host are not provided.
+ *
+ * @param array $parts Array of parse_url parts
+ *
+ * @return string
+ */
+ public static function buildUrl(array $parts)
+ {
+ $url = $scheme = '';
+
+ if (isset($parts['scheme'])) {
+ $scheme = $parts['scheme'];
+ $url .= $scheme . ':';
+ }
+
+ if (isset($parts['host'])) {
+ $url .= '//';
+ if (isset($parts['user'])) {
+ $url .= $parts['user'];
+ if (isset($parts['pass'])) {
+ $url .= ':' . $parts['pass'];
+ }
+ $url .= '@';
+ }
+
+ $url .= $parts['host'];
+
+ // Only include the port if it is not the default port of the scheme
+ if (isset($parts['port'])
+ && !(($scheme == 'http' && $parts['port'] == 80) || ($scheme == 'https' && $parts['port'] == 443))
+ ) {
+ $url .= ':' . $parts['port'];
+ }
+ }
+
+ // Add the path component if present
+ if (isset($parts['path']) && 0 !== strlen($parts['path'])) {
+ // Always ensure that the path begins with '/' if set and something is before the path
+ if ($url && $parts['path'][0] != '/' && substr($url, -1) != '/') {
+ $url .= '/';
+ }
+ $url .= $parts['path'];
+ }
+
+ // Add the query string if present
+ if (isset($parts['query'])) {
+ $url .= '?' . $parts['query'];
+ }
+
+ // Ensure that # is only added to the url if fragment contains anything.
+ if (isset($parts['fragment'])) {
+ $url .= '#' . $parts['fragment'];
+ }
+
+ return $url;
+ }
+
+ /**
+ * Create a new URL from URL parts
+ *
+ * @param string $scheme Scheme of the URL
+ * @param string $host Host of the URL
+ * @param string $username Username of the URL
+ * @param string $password Password of the URL
+ * @param int $port Port of the URL
+ * @param string $path Path of the URL
+ * @param QueryString|array|string $query Query string of the URL
+ * @param string $fragment Fragment of the URL
+ */
+ public function __construct($scheme, $host, $username = null, $password = null, $port = null, $path = null, QueryString $query = null, $fragment = null)
+ {
+ $this->scheme = $scheme;
+ $this->host = $host;
+ $this->port = $port;
+ $this->username = $username;
+ $this->password = $password;
+ $this->fragment = $fragment;
+ if (!$query) {
+ $this->query = new QueryString();
+ } else {
+ $this->setQuery($query);
+ }
+ $this->setPath($path);
+ }
+
+ /**
+ * Clone the URL
+ */
+ public function __clone()
+ {
+ $this->query = clone $this->query;
+ }
+
+ /**
+ * Returns the URL as a URL string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return self::buildUrl($this->getParts());
+ }
+
+ /**
+ * Get the parts of the URL as an array
+ *
+ * @return array
+ */
+ public function getParts()
+ {
+ $query = (string) $this->query;
+
+ return array(
+ 'scheme' => $this->scheme,
+ 'user' => $this->username,
+ 'pass' => $this->password,
+ 'host' => $this->host,
+ 'port' => $this->port,
+ 'path' => $this->getPath(),
+ 'query' => $query !== '' ? $query : null,
+ 'fragment' => $this->fragment,
+ );
+ }
+
+ /**
+ * Set the host of the request.
+ *
+ * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com)
+ *
+ * @return Url
+ */
+ public function setHost($host)
+ {
+ if (strpos($host, ':') === false) {
+ $this->host = $host;
+ } else {
+ list($host, $port) = explode(':', $host);
+ $this->host = $host;
+ $this->setPort($port);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the host part of the URL
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Set the scheme part of the URL (http, https, ftp, etc)
+ *
+ * @param string $scheme Scheme to set
+ *
+ * @return Url
+ */
+ public function setScheme($scheme)
+ {
+ if ($this->scheme == 'http' && $this->port == 80) {
+ $this->port = null;
+ } elseif ($this->scheme == 'https' && $this->port == 443) {
+ $this->port = null;
+ }
+
+ $this->scheme = $scheme;
+
+ return $this;
+ }
+
+ /**
+ * Get the scheme part of the URL
+ *
+ * @return string
+ */
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ /**
+ * Set the port part of the URL
+ *
+ * @param int $port Port to set
+ *
+ * @return Url
+ */
+ public function setPort($port)
+ {
+ $this->port = $port;
+
+ return $this;
+ }
+
+ /**
+ * Get the port part of the URl. Will return the default port for a given scheme if no port has been set.
+ *
+ * @return int|null
+ */
+ public function getPort()
+ {
+ if ($this->port) {
+ return $this->port;
+ } elseif ($this->scheme == 'http') {
+ return 80;
+ } elseif ($this->scheme == 'https') {
+ return 443;
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the path part of the URL
+ *
+ * @param array|string $path Path string or array of path segments
+ *
+ * @return Url
+ */
+ public function setPath($path)
+ {
+ static $pathReplace = array(' ' => '%20', '?' => '%3F');
+ if (is_array($path)) {
+ $path = '/' . implode('/', $path);
+ }
+
+ $this->path = strtr($path, $pathReplace);
+
+ return $this;
+ }
+
+ /**
+ * Normalize the URL so that double slashes and relative paths are removed
+ *
+ * @return Url
+ */
+ public function normalizePath()
+ {
+ if (!$this->path || $this->path == '/' || $this->path == '*') {
+ return $this;
+ }
+
+ $results = array();
+ $segments = $this->getPathSegments();
+ foreach ($segments as $segment) {
+ if ($segment == '..') {
+ array_pop($results);
+ } elseif ($segment != '.' && $segment != '') {
+ $results[] = $segment;
+ }
+ }
+
+ // Combine the normalized parts and add the leading slash if needed
+ $this->path = ($this->path[0] == '/' ? '/' : '') . implode('/', $results);
+
+ // Add the trailing slash if necessary
+ if ($this->path != '/' && end($segments) == '') {
+ $this->path .= '/';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a relative path to the currently set path.
+ *
+ * @param string $relativePath Relative path to add
+ *
+ * @return Url
+ */
+ public function addPath($relativePath)
+ {
+ if ($relativePath != '/' && is_string($relativePath) && strlen($relativePath) > 0) {
+ // Add a leading slash if needed
+ if ($relativePath[0] != '/') {
+ $relativePath = '/' . $relativePath;
+ }
+ $this->setPath(str_replace('//', '/', $this->path . $relativePath));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the path part of the URL
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Get the path segments of the URL as an array
+ *
+ * @return array
+ */
+ public function getPathSegments()
+ {
+ return array_slice(explode('/', $this->getPath()), 1);
+ }
+
+ /**
+ * Set the password part of the URL
+ *
+ * @param string $password Password to set
+ *
+ * @return Url
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+
+ return $this;
+ }
+
+ /**
+ * Get the password part of the URL
+ *
+ * @return null|string
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * Set the username part of the URL
+ *
+ * @param string $username Username to set
+ *
+ * @return Url
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+
+ return $this;
+ }
+
+ /**
+ * Get the username part of the URl
+ *
+ * @return null|string
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Get the query part of the URL as a QueryString object
+ *
+ * @return QueryString
+ */
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ /**
+ * Set the query part of the URL
+ *
+ * @param QueryString|string|array $query Query to set
+ *
+ * @return Url
+ */
+ public function setQuery($query)
+ {
+ if (is_string($query)) {
+ $output = null;
+ parse_str($query, $output);
+ $this->query = new QueryString($output);
+ } elseif (is_array($query)) {
+ $this->query = new QueryString($query);
+ } elseif ($query instanceof QueryString) {
+ $this->query = $query;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the fragment part of the URL
+ *
+ * @return null|string
+ */
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ /**
+ * Set the fragment part of the URL
+ *
+ * @param string $fragment Fragment to set
+ *
+ * @return Url
+ */
+ public function setFragment($fragment)
+ {
+ $this->fragment = $fragment;
+
+ return $this;
+ }
+
+ /**
+ * Check if this is an absolute URL
+ *
+ * @return bool
+ */
+ public function isAbsolute()
+ {
+ return $this->scheme && $this->host;
+ }
+
+ /**
+ * Combine the URL with another URL. Follows the rules specific in RFC 3986 section 5.4.
+ *
+ * @param string $url Relative URL to combine with
+ * @param bool $strictRfc3986 Set to true to use strict RFC 3986 compliance when merging paths. When first
+ * released, Guzzle used an incorrect algorithm for combining relative URL paths. In
+ * order to not break users, we introduced this flag to allow the merging of URLs based
+ * on strict RFC 3986 section 5.4.1. This means that "http://a.com/foo/baz" merged with
+ * "bar" would become "http://a.com/foo/bar". When this value is set to false, it would
+ * become "http://a.com/foo/baz/bar".
+ * @return Url
+ * @throws InvalidArgumentException
+ * @link http://tools.ietf.org/html/rfc3986#section-5.4
+ */
+ public function combine($url, $strictRfc3986 = false)
+ {
+ $url = self::factory($url);
+
+ // Use the more absolute URL as the base URL
+ if (!$this->isAbsolute() && $url->isAbsolute()) {
+ $url = $url->combine($this);
+ }
+
+ // Passing a URL with a scheme overrides everything
+ if ($buffer = $url->getScheme()) {
+ $this->scheme = $buffer;
+ $this->host = $url->getHost();
+ $this->port = $url->getPort();
+ $this->username = $url->getUsername();
+ $this->password = $url->getPassword();
+ $this->path = $url->getPath();
+ $this->query = $url->getQuery();
+ $this->fragment = $url->getFragment();
+ return $this;
+ }
+
+ // Setting a host overrides the entire rest of the URL
+ if ($buffer = $url->getHost()) {
+ $this->host = $buffer;
+ $this->port = $url->getPort();
+ $this->username = $url->getUsername();
+ $this->password = $url->getPassword();
+ $this->path = $url->getPath();
+ $this->query = $url->getQuery();
+ $this->fragment = $url->getFragment();
+ return $this;
+ }
+
+ $path = $url->getPath();
+ $query = $url->getQuery();
+
+ if (!$path) {
+ if (count($query)) {
+ $this->addQuery($query, $strictRfc3986);
+ }
+ } else {
+ if ($path[0] == '/') {
+ $this->path = $path;
+ } elseif ($strictRfc3986) {
+ $this->path .= '/../' . $path;
+ } else {
+ $this->path .= '/' . $path;
+ }
+ $this->normalizePath();
+ $this->addQuery($query, $strictRfc3986);
+ }
+
+ $this->fragment = $url->getFragment();
+
+ return $this;
+ }
+
+ private function addQuery(QueryString $new, $strictRfc386)
+ {
+ if (!$strictRfc386) {
+ $new->merge($this->query);
+ }
+
+ $this->query = $new;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/composer.json
new file mode 100755
index 0000000..9384a5b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Http/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "guzzle/http",
+ "description": "HTTP libraries used by Guzzle",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["http client", "http", "client", "Guzzle", "curl"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/common": "self.version",
+ "guzzle/parser": "self.version",
+ "guzzle/stream": "self.version"
+ },
+ "suggest": {
+ "ext-curl": "*"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Http": "" }
+ },
+ "target-dir": "Guzzle/Http",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php
new file mode 100755
index 0000000..c699773
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/Inflector.php
@@ -0,0 +1,38 @@
+ array(),
+ 'camel' => array()
+ );
+
+ /** @var int Max entries per cache */
+ protected $maxCacheSize;
+
+ /** @var InflectorInterface Decorated inflector */
+ protected $decoratedInflector;
+
+ /**
+ * @param InflectorInterface $inflector Inflector being decorated
+ * @param int $maxCacheSize Maximum number of cached items to hold per cache
+ */
+ public function __construct(InflectorInterface $inflector, $maxCacheSize = 500)
+ {
+ $this->decoratedInflector = $inflector;
+ $this->maxCacheSize = $maxCacheSize;
+ }
+
+ public function snake($word)
+ {
+ if (!isset($this->cache['snake'][$word])) {
+ $this->pruneCache('snake');
+ $this->cache['snake'][$word] = $this->decoratedInflector->snake($word);
+ }
+
+ return $this->cache['snake'][$word];
+ }
+
+ /**
+ * Converts strings from snake_case to upper CamelCase
+ *
+ * @param string $word Value to convert into upper CamelCase
+ *
+ * @return string
+ */
+ public function camel($word)
+ {
+ if (!isset($this->cache['camel'][$word])) {
+ $this->pruneCache('camel');
+ $this->cache['camel'][$word] = $this->decoratedInflector->camel($word);
+ }
+
+ return $this->cache['camel'][$word];
+ }
+
+ /**
+ * Prune one of the named caches by removing 20% of the cache if it is full
+ *
+ * @param string $cache Type of cache to prune
+ */
+ protected function pruneCache($cache)
+ {
+ if (count($this->cache[$cache]) == $this->maxCacheSize) {
+ $this->cache[$cache] = array_slice($this->cache[$cache], $this->maxCacheSize * 0.2);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php
new file mode 100755
index 0000000..db37e4f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/PreComputedInflector.php
@@ -0,0 +1,59 @@
+ array(),
+ 'camel' => array()
+ );
+
+ /** @var InflectorInterface Decorated inflector */
+ protected $decoratedInflector;
+
+ /**
+ * @param InflectorInterface $inflector Inflector being decorated
+ * @param array $snake Hash of pre-computed camel to snake
+ * @param array $camel Hash of pre-computed snake to camel
+ * @param bool $mirror Mirror snake and camel reflections
+ */
+ public function __construct(InflectorInterface $inflector, array $snake = array(), array $camel = array(), $mirror = false)
+ {
+ if ($mirror) {
+ $camel = array_merge(array_flip($snake), $camel);
+ $snake = array_merge(array_flip($camel), $snake);
+ }
+
+ $this->decoratedInflector = $inflector;
+ $this->mapping = array(
+ 'snake' => $snake,
+ 'camel' => $camel
+ );
+ }
+
+ public function snake($word)
+ {
+ return isset($this->mapping['snake'][$word])
+ ? $this->mapping['snake'][$word]
+ : $this->decoratedInflector->snake($word);
+ }
+
+ /**
+ * Converts strings from snake_case to upper CamelCase
+ *
+ * @param string $word Value to convert into upper CamelCase
+ *
+ * @return string
+ */
+ public function camel($word)
+ {
+ return isset($this->mapping['camel'][$word])
+ ? $this->mapping['camel'][$word]
+ : $this->decoratedInflector->camel($word);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json
new file mode 100755
index 0000000..93f9e7b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Inflection/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "guzzle/inflection",
+ "description": "Guzzle inflection component",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["inflection", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Inflection": "" }
+ },
+ "target-dir": "Guzzle/Inflection",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php
new file mode 100755
index 0000000..1b6bd7e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/AppendIterator.php
@@ -0,0 +1,19 @@
+getArrayIterator()->append($iterator);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php
new file mode 100755
index 0000000..d76cdd4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/ChunkedIterator.php
@@ -0,0 +1,56 @@
+chunkSize = $chunkSize;
+ }
+
+ public function rewind()
+ {
+ parent::rewind();
+ $this->next();
+ }
+
+ public function next()
+ {
+ $this->chunk = array();
+ for ($i = 0; $i < $this->chunkSize && parent::valid(); $i++) {
+ $this->chunk[] = parent::current();
+ parent::next();
+ }
+ }
+
+ public function current()
+ {
+ return $this->chunk;
+ }
+
+ public function valid()
+ {
+ return (bool) $this->chunk;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php
new file mode 100755
index 0000000..b103367
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/FilterIterator.php
@@ -0,0 +1,36 @@
+callback = $callback;
+ }
+
+ public function accept()
+ {
+ return call_user_func($this->callback, $this->current());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php
new file mode 100755
index 0000000..7e586bd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/MapIterator.php
@@ -0,0 +1,34 @@
+callback = $callback;
+ }
+
+ public function current()
+ {
+ return call_user_func($this->callback, parent::current());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php
new file mode 100755
index 0000000..de4ab03
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/MethodProxyIterator.php
@@ -0,0 +1,27 @@
+getInnerIterator();
+ while ($i instanceof \OuterIterator) {
+ $i = $i->getInnerIterator();
+ }
+
+ return call_user_func_array(array($i, $name), $args);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md
new file mode 100755
index 0000000..8bb7e08
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/README.md
@@ -0,0 +1,25 @@
+Guzzle Iterator
+===============
+
+Provides useful Iterators and Iterator decorators
+
+- ChunkedIterator: Pulls out chunks from an inner iterator and yields the chunks as arrays
+- FilterIterator: Used when PHP 5.4's CallbackFilterIterator is not available
+- MapIterator: Maps values before yielding
+- MethodProxyIterator: Proxies missing method calls to the innermost iterator
+
+### Installing via Composer
+
+```bash
+# Install Composer
+curl -sS https://getcomposer.org/installer | php
+
+# Add Guzzle as a dependency
+php composer.phar require guzzle/iterator:~3.0
+```
+
+After installing, you need to require Composer's autoloader:
+
+```php
+require 'vendor/autoload.php';
+```
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json
new file mode 100755
index 0000000..ee17379
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Iterator/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/iterator",
+ "description": "Provides helpful iterators and iterator decorators",
+ "keywords": ["iterator", "guzzle"],
+ "homepage": "http://guzzlephp.org/",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/common": ">=2.8.0"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Iterator": "/" }
+ },
+ "target-dir": "Guzzle/Iterator",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php
new file mode 100755
index 0000000..7f6271b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/AbstractLogAdapter.php
@@ -0,0 +1,16 @@
+log;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php
new file mode 100755
index 0000000..a70fc8d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/ArrayLogAdapter.php
@@ -0,0 +1,34 @@
+logs[] = array('message' => $message, 'priority' => $priority, 'extras' => $extras);
+ }
+
+ /**
+ * Get logged entries
+ *
+ * @return array
+ */
+ public function getLogs()
+ {
+ return $this->logs;
+ }
+
+ /**
+ * Clears logged entries
+ */
+ public function clearLogs()
+ {
+ $this->logs = array();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php
new file mode 100755
index 0000000..d4bb73f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/ClosureLogAdapter.php
@@ -0,0 +1,23 @@
+log = $logObject;
+ }
+
+ public function log($message, $priority = LOG_INFO, $extras = array())
+ {
+ call_user_func($this->log, $message, $priority, $extras);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php
new file mode 100755
index 0000000..d7ac4ea
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/LogAdapterInterface.php
@@ -0,0 +1,18 @@
+>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{curl_stderr}";
+ const SHORT_FORMAT = '[{ts}] "{method} {resource} {protocol}/{version}" {code}';
+
+ /**
+ * @var string Template used to format log messages
+ */
+ protected $template;
+
+ /**
+ * @param string $template Log message template
+ */
+ public function __construct($template = self::DEFAULT_FORMAT)
+ {
+ $this->template = $template ?: self::DEFAULT_FORMAT;
+ }
+
+ /**
+ * Set the template to use for logging
+ *
+ * @param string $template Log message template
+ *
+ * @return self
+ */
+ public function setTemplate($template)
+ {
+ $this->template = $template;
+
+ return $this;
+ }
+
+ /**
+ * Returns a formatted message
+ *
+ * @param RequestInterface $request Request that was sent
+ * @param Response $response Response that was received
+ * @param CurlHandle $handle Curl handle associated with the message
+ * @param array $customData Associative array of custom template data
+ *
+ * @return string
+ */
+ public function format(
+ RequestInterface $request,
+ Response $response = null,
+ CurlHandle $handle = null,
+ array $customData = array()
+ ) {
+ $cache = $customData;
+
+ return preg_replace_callback(
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
+ function (array $matches) use ($request, $response, $handle, &$cache) {
+
+ if (array_key_exists($matches[1], $cache)) {
+ return $cache[$matches[1]];
+ }
+
+ $result = '';
+ switch ($matches[1]) {
+ case 'request':
+ $result = (string) $request;
+ break;
+ case 'response':
+ $result = (string) $response;
+ break;
+ case 'req_body':
+ $result = $request instanceof EntityEnclosingRequestInterface
+ ? (string) $request->getBody() : '';
+ break;
+ case 'res_body':
+ $result = $response ? $response->getBody(true) : '';
+ break;
+ case 'ts':
+ $result = gmdate('c');
+ break;
+ case 'method':
+ $result = $request->getMethod();
+ break;
+ case 'url':
+ $result = (string) $request->getUrl();
+ break;
+ case 'resource':
+ $result = $request->getResource();
+ break;
+ case 'protocol':
+ $result = 'HTTP';
+ break;
+ case 'version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'host':
+ $result = $request->getHost();
+ break;
+ case 'hostname':
+ $result = gethostname();
+ break;
+ case 'port':
+ $result = $request->getPort();
+ break;
+ case 'code':
+ $result = $response ? $response->getStatusCode() : '';
+ break;
+ case 'phrase':
+ $result = $response ? $response->getReasonPhrase() : '';
+ break;
+ case 'connect_time':
+ $result = $handle && $handle->getInfo(CURLINFO_CONNECT_TIME)
+ ? $handle->getInfo(CURLINFO_CONNECT_TIME)
+ : ($response ? $response->getInfo('connect_time') : '');
+ break;
+ case 'total_time':
+ $result = $handle && $handle->getInfo(CURLINFO_TOTAL_TIME)
+ ? $handle->getInfo(CURLINFO_TOTAL_TIME)
+ : ($response ? $response->getInfo('total_time') : '');
+ break;
+ case 'curl_error':
+ $result = $handle ? $handle->getError() : '';
+ break;
+ case 'curl_code':
+ $result = $handle ? $handle->getErrorNo() : '';
+ break;
+ case 'curl_stderr':
+ $result = $handle ? $handle->getStderr() : '';
+ break;
+ default:
+ if (strpos($matches[1], 'req_header_') === 0) {
+ $result = $request->getHeader(substr($matches[1], 11));
+ } elseif ($response && strpos($matches[1], 'res_header_') === 0) {
+ $result = $response->getHeader(substr($matches[1], 11));
+ }
+ }
+
+ $cache[$matches[1]] = $result;
+ return $result;
+ },
+ $this->template
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php
new file mode 100755
index 0000000..6afe7b6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/MonologLogAdapter.php
@@ -0,0 +1,34 @@
+ Logger::DEBUG,
+ LOG_INFO => Logger::INFO,
+ LOG_WARNING => Logger::WARNING,
+ LOG_ERR => Logger::ERROR,
+ LOG_CRIT => Logger::CRITICAL,
+ LOG_ALERT => Logger::ALERT
+ );
+
+ public function __construct(Logger $logObject)
+ {
+ $this->log = $logObject;
+ }
+
+ public function log($message, $priority = LOG_INFO, $extras = array())
+ {
+ $this->log->addRecord(self::$mapping[$priority], $message, $extras);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php
new file mode 100755
index 0000000..38a2b60
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/PsrLogAdapter.php
@@ -0,0 +1,36 @@
+ LogLevel::DEBUG,
+ LOG_INFO => LogLevel::INFO,
+ LOG_WARNING => LogLevel::WARNING,
+ LOG_ERR => LogLevel::ERROR,
+ LOG_CRIT => LogLevel::CRITICAL,
+ LOG_ALERT => LogLevel::ALERT
+ );
+
+ public function __construct(LoggerInterface $logObject)
+ {
+ $this->log = $logObject;
+ }
+
+ public function log($message, $priority = LOG_INFO, $extras = array())
+ {
+ $this->log->log(self::$mapping[$priority], $message, $extras);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php
new file mode 100755
index 0000000..0ea8e3b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/Zf1LogAdapter.php
@@ -0,0 +1,24 @@
+log = $logObject;
+ Version::warn(__CLASS__ . ' is deprecated');
+ }
+
+ public function log($message, $priority = LOG_INFO, $extras = array())
+ {
+ $this->log->log($message, $priority, $extras);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php
new file mode 100755
index 0000000..863f6a1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/Zf2LogAdapter.php
@@ -0,0 +1,21 @@
+log = $logObject;
+ }
+
+ public function log($message, $priority = LOG_INFO, $extras = array())
+ {
+ $this->log->log($priority, $message, $extras);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/composer.json
new file mode 100755
index 0000000..a8213e8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Log/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "guzzle/log",
+ "description": "Guzzle log adapter component",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["log", "adapter", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Log": "" }
+ },
+ "suggest": {
+ "guzzle/http": "self.version"
+ },
+ "target-dir": "Guzzle/Log",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php
new file mode 100755
index 0000000..4349eeb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParser.php
@@ -0,0 +1,131 @@
+ 'Domain',
+ 'path' => 'Path',
+ 'max_age' => 'Max-Age',
+ 'expires' => 'Expires',
+ 'version' => 'Version',
+ 'secure' => 'Secure',
+ 'port' => 'Port',
+ 'discard' => 'Discard',
+ 'comment' => 'Comment',
+ 'comment_url' => 'Comment-Url',
+ 'http_only' => 'HttpOnly'
+ );
+
+ public function parseCookie($cookie, $host = null, $path = null, $decode = false)
+ {
+ // Explode the cookie string using a series of semicolons
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
+
+ // The name of the cookie (first kvp) must include an equal sign.
+ if (empty($pieces) || !strpos($pieces[0], '=')) {
+ return false;
+ }
+
+ // Create the default return array
+ $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array(
+ 'cookies' => array(),
+ 'data' => array(),
+ 'path' => null,
+ 'http_only' => false,
+ 'discard' => false,
+ 'domain' => $host
+ ));
+ $foundNonCookies = 0;
+
+ // Add the cookie pieces into the parsed data array
+ foreach ($pieces as $part) {
+
+ $cookieParts = explode('=', $part, 2);
+ $key = trim($cookieParts[0]);
+
+ if (count($cookieParts) == 1) {
+ // Can be a single value (e.g. secure, httpOnly)
+ $value = true;
+ } else {
+ // Be sure to strip wrapping quotes
+ $value = trim($cookieParts[1], " \n\r\t\0\x0B\"");
+ if ($decode) {
+ $value = urldecode($value);
+ }
+ }
+
+ // Only check for non-cookies when cookies have been found
+ if (!empty($data['cookies'])) {
+ foreach (self::$cookieParts as $mapValue => $search) {
+ if (!strcasecmp($search, $key)) {
+ $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value;
+ $foundNonCookies++;
+ continue 2;
+ }
+ }
+ }
+
+ // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a
+ // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data.
+ $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value;
+ }
+
+ // Calculate the expires date
+ if (!$data['expires'] && $data['max_age']) {
+ $data['expires'] = time() + (int) $data['max_age'];
+ }
+
+ // Check path attribute according RFC6265 http://tools.ietf.org/search/rfc6265#section-5.2.4
+ // "If the attribute-value is empty or if the first character of the
+ // attribute-value is not %x2F ("/"):
+ // Let cookie-path be the default-path.
+ // Otherwise:
+ // Let cookie-path be the attribute-value."
+ if (!$data['path'] || substr($data['path'], 0, 1) !== '/') {
+ $data['path'] = $this->getDefaultPath($path);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Get default cookie path according to RFC 6265
+ * http://tools.ietf.org/search/rfc6265#section-5.1.4 Paths and Path-Match
+ *
+ * @param string $path Request uri-path
+ *
+ * @return string
+ */
+ protected function getDefaultPath($path) {
+ // "The user agent MUST use an algorithm equivalent to the following algorithm
+ // to compute the default-path of a cookie:"
+
+ // "2. If the uri-path is empty or if the first character of the uri-path is not
+ // a %x2F ("/") character, output %x2F ("/") and skip the remaining steps.
+ if (empty($path) || substr($path, 0, 1) !== '/') {
+ return '/';
+ }
+
+ // "3. If the uri-path contains no more than one %x2F ("/") character, output
+ // %x2F ("/") and skip the remaining step."
+ if ($path === "/") {
+ return $path;
+ }
+
+ $rightSlashPos = strrpos($path, '/');
+ if ($rightSlashPos === 0) {
+ return "/";
+ }
+
+ // "4. Output the characters of the uri-path from the first character up to,
+ // but not including, the right-most %x2F ("/")."
+ return substr($path, 0, $rightSlashPos);
+
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php
new file mode 100755
index 0000000..d21ffe2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Cookie/CookieParserInterface.php
@@ -0,0 +1,33 @@
+ $requestUrl,
+ 'scheme' => 'http'
+ );
+
+ // Check for the Host header
+ if (isset($parts['headers']['Host'])) {
+ $urlParts['host'] = $parts['headers']['Host'];
+ } elseif (isset($parts['headers']['host'])) {
+ $urlParts['host'] = $parts['headers']['host'];
+ } else {
+ $urlParts['host'] = null;
+ }
+
+ if (false === strpos($urlParts['host'], ':')) {
+ $urlParts['port'] = '';
+ } else {
+ $hostParts = explode(':', $urlParts['host']);
+ $urlParts['host'] = trim($hostParts[0]);
+ $urlParts['port'] = (int) trim($hostParts[1]);
+ if ($urlParts['port'] == 443) {
+ $urlParts['scheme'] = 'https';
+ }
+ }
+
+ // Check if a query is present
+ $path = $urlParts['path'];
+ $qpos = strpos($path, '?');
+ if ($qpos) {
+ $urlParts['query'] = substr($path, $qpos + 1);
+ $urlParts['path'] = substr($path, 0, $qpos);
+ } else {
+ $urlParts['query'] = '';
+ }
+
+ return $urlParts;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php
new file mode 100755
index 0000000..efc1aa3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParser.php
@@ -0,0 +1,110 @@
+parseMessage($message);
+
+ // Parse the protocol and protocol version
+ if (isset($parts['start_line'][2])) {
+ $startParts = explode('/', $parts['start_line'][2]);
+ $protocol = strtoupper($startParts[0]);
+ $version = isset($startParts[1]) ? $startParts[1] : '1.1';
+ } else {
+ $protocol = 'HTTP';
+ $version = '1.1';
+ }
+
+ $parsed = array(
+ 'method' => strtoupper($parts['start_line'][0]),
+ 'protocol' => $protocol,
+ 'version' => $version,
+ 'headers' => $parts['headers'],
+ 'body' => $parts['body']
+ );
+
+ $parsed['request_url'] = $this->getUrlPartsFromMessage(isset($parts['start_line'][1]) ? $parts['start_line'][1] : '' , $parsed);
+
+ return $parsed;
+ }
+
+ public function parseResponse($message)
+ {
+ if (!$message) {
+ return false;
+ }
+
+ $parts = $this->parseMessage($message);
+ list($protocol, $version) = explode('/', trim($parts['start_line'][0]));
+
+ return array(
+ 'protocol' => $protocol,
+ 'version' => $version,
+ 'code' => $parts['start_line'][1],
+ 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
+ 'headers' => $parts['headers'],
+ 'body' => $parts['body']
+ );
+ }
+
+ /**
+ * Parse a message into parts
+ *
+ * @param string $message Message to parse
+ *
+ * @return array
+ */
+ protected function parseMessage($message)
+ {
+ $startLine = null;
+ $headers = array();
+ $body = '';
+
+ // Iterate over each line in the message, accounting for line endings
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
+ for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
+
+ $line = $lines[$i];
+
+ // If two line breaks were encountered, then this is the end of body
+ if (empty($line)) {
+ if ($i < $totalLines - 1) {
+ $body = implode('', array_slice($lines, $i + 2));
+ }
+ break;
+ }
+
+ // Parse message headers
+ if (!$startLine) {
+ $startLine = explode(' ', $line, 3);
+ } elseif (strpos($line, ':')) {
+ $parts = explode(':', $line, 2);
+ $key = trim($parts[0]);
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
+ if (!isset($headers[$key])) {
+ $headers[$key] = $value;
+ } elseif (!is_array($headers[$key])) {
+ $headers[$key] = array($headers[$key], $value);
+ } else {
+ $headers[$key][] = $value;
+ }
+ }
+ }
+
+ return array(
+ 'start_line' => $startLine,
+ 'headers' => $headers,
+ 'body' => $body
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php
new file mode 100755
index 0000000..cc44808
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Message/MessageParserInterface.php
@@ -0,0 +1,27 @@
+ $parts->requestMethod,
+ 'protocol' => 'HTTP',
+ 'version' => number_format($parts->httpVersion, 1),
+ 'headers' => $parts->headers,
+ 'body' => $parts->body
+ );
+
+ $parsed['request_url'] = $this->getUrlPartsFromMessage($parts->requestUrl, $parsed);
+
+ return $parsed;
+ }
+
+ public function parseResponse($message)
+ {
+ if (!$message) {
+ return false;
+ }
+
+ $parts = http_parse_message($message);
+
+ return array(
+ 'protocol' => 'HTTP',
+ 'version' => number_format($parts->httpVersion, 1),
+ 'code' => $parts->responseCode,
+ 'reason_phrase' => $parts->responseStatus,
+ 'headers' => $parts->headers,
+ 'body' => $parts->body
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php
new file mode 100755
index 0000000..f838683
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/ParserRegistry.php
@@ -0,0 +1,75 @@
+ 'Guzzle\\Parser\\Message\\MessageParser',
+ 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser',
+ 'url' => 'Guzzle\\Parser\\Url\\UrlParser',
+ 'uri_template' => 'Guzzle\\Parser\\UriTemplate\\UriTemplate',
+ );
+
+ /**
+ * @return self
+ * @codeCoverageIgnore
+ */
+ public static function getInstance()
+ {
+ if (!self::$instance) {
+ self::$instance = new static;
+ }
+
+ return self::$instance;
+ }
+
+ public function __construct()
+ {
+ // Use the PECL URI template parser if available
+ if (extension_loaded('uri_template')) {
+ $this->mapping['uri_template'] = 'Guzzle\\Parser\\UriTemplate\\PeclUriTemplate';
+ }
+ }
+
+ /**
+ * Get a parser by name from an instance
+ *
+ * @param string $name Name of the parser to retrieve
+ *
+ * @return mixed|null
+ */
+ public function getParser($name)
+ {
+ if (!isset($this->instances[$name])) {
+ if (!isset($this->mapping[$name])) {
+ return null;
+ }
+ $class = $this->mapping[$name];
+ $this->instances[$name] = new $class();
+ }
+
+ return $this->instances[$name];
+ }
+
+ /**
+ * Register a custom parser by name with the register
+ *
+ * @param string $name Name or handle of the parser to register
+ * @param mixed $parser Instantiated parser to register
+ */
+ public function registerParser($name, $parser)
+ {
+ $this->instances[$name] = $parser;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php
new file mode 100755
index 0000000..b0764e8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/PeclUriTemplate.php
@@ -0,0 +1,26 @@
+ true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true
+ );
+
+ /** @var array Delimiters */
+ private static $delims = array(
+ ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '='
+ );
+
+ /** @var array Percent encoded delimiters */
+ private static $delimsPct = array(
+ '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
+ '%3B', '%3D'
+ );
+
+ public function expand($template, array $variables)
+ {
+ if ($this->regex == self::DEFAULT_PATTERN && false === strpos($template, '{')) {
+ return $template;
+ }
+
+ $this->template = $template;
+ $this->variables = $variables;
+
+ return preg_replace_callback($this->regex, array($this, 'expandMatch'), $this->template);
+ }
+
+ /**
+ * Set the regex patten used to expand URI templates
+ *
+ * @param string $regexPattern
+ */
+ public function setRegex($regexPattern)
+ {
+ $this->regex = $regexPattern;
+ }
+
+ /**
+ * Parse an expression into parts
+ *
+ * @param string $expression Expression to parse
+ *
+ * @return array Returns an associative array of parts
+ */
+ private function parseExpression($expression)
+ {
+ // Check for URI operators
+ $operator = '';
+
+ if (isset(self::$operatorHash[$expression[0]])) {
+ $operator = $expression[0];
+ $expression = substr($expression, 1);
+ }
+
+ $values = explode(',', $expression);
+ foreach ($values as &$value) {
+ $value = trim($value);
+ $varspec = array();
+ $substrPos = strpos($value, ':');
+ if ($substrPos) {
+ $varspec['value'] = substr($value, 0, $substrPos);
+ $varspec['modifier'] = ':';
+ $varspec['position'] = (int) substr($value, $substrPos + 1);
+ } elseif (substr($value, -1) == '*') {
+ $varspec['modifier'] = '*';
+ $varspec['value'] = substr($value, 0, -1);
+ } else {
+ $varspec['value'] = (string) $value;
+ $varspec['modifier'] = '';
+ }
+ $value = $varspec;
+ }
+
+ return array(
+ 'operator' => $operator,
+ 'values' => $values
+ );
+ }
+
+ /**
+ * Process an expansion
+ *
+ * @param array $matches Matches met in the preg_replace_callback
+ *
+ * @return string Returns the replacement string
+ */
+ private function expandMatch(array $matches)
+ {
+ static $rfc1738to3986 = array(
+ '+' => '%20',
+ '%7e' => '~'
+ );
+
+ $parsed = self::parseExpression($matches[1]);
+ $replacements = array();
+
+ $prefix = $parsed['operator'];
+ $joiner = $parsed['operator'];
+ $useQueryString = false;
+ if ($parsed['operator'] == '?') {
+ $joiner = '&';
+ $useQueryString = true;
+ } elseif ($parsed['operator'] == '&') {
+ $useQueryString = true;
+ } elseif ($parsed['operator'] == '#') {
+ $joiner = ',';
+ } elseif ($parsed['operator'] == ';') {
+ $useQueryString = true;
+ } elseif ($parsed['operator'] == '' || $parsed['operator'] == '+') {
+ $joiner = ',';
+ $prefix = '';
+ }
+
+ foreach ($parsed['values'] as $value) {
+
+ if (!array_key_exists($value['value'], $this->variables) || $this->variables[$value['value']] === null) {
+ continue;
+ }
+
+ $variable = $this->variables[$value['value']];
+ $actuallyUseQueryString = $useQueryString;
+ $expanded = '';
+
+ if (is_array($variable)) {
+
+ $isAssoc = $this->isAssoc($variable);
+ $kvp = array();
+ foreach ($variable as $key => $var) {
+
+ if ($isAssoc) {
+ $key = rawurlencode($key);
+ $isNestedArray = is_array($var);
+ } else {
+ $isNestedArray = false;
+ }
+
+ if (!$isNestedArray) {
+ $var = rawurlencode($var);
+ if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
+ $var = $this->decodeReserved($var);
+ }
+ }
+
+ if ($value['modifier'] == '*') {
+ if ($isAssoc) {
+ if ($isNestedArray) {
+ // Nested arrays must allow for deeply nested structures
+ $var = strtr(http_build_query(array($key => $var)), $rfc1738to3986);
+ } else {
+ $var = $key . '=' . $var;
+ }
+ } elseif ($key > 0 && $actuallyUseQueryString) {
+ $var = $value['value'] . '=' . $var;
+ }
+ }
+
+ $kvp[$key] = $var;
+ }
+
+ if (empty($variable)) {
+ $actuallyUseQueryString = false;
+ } elseif ($value['modifier'] == '*') {
+ $expanded = implode($joiner, $kvp);
+ if ($isAssoc) {
+ // Don't prepend the value name when using the explode modifier with an associative array
+ $actuallyUseQueryString = false;
+ }
+ } else {
+ if ($isAssoc) {
+ // When an associative array is encountered and the explode modifier is not set, then the
+ // result must be a comma separated list of keys followed by their respective values.
+ foreach ($kvp as $k => &$v) {
+ $v = $k . ',' . $v;
+ }
+ }
+ $expanded = implode(',', $kvp);
+ }
+
+ } else {
+ if ($value['modifier'] == ':') {
+ $variable = substr($variable, 0, $value['position']);
+ }
+ $expanded = rawurlencode($variable);
+ if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
+ $expanded = $this->decodeReserved($expanded);
+ }
+ }
+
+ if ($actuallyUseQueryString) {
+ if (!$expanded && $joiner != '&') {
+ $expanded = $value['value'];
+ } else {
+ $expanded = $value['value'] . '=' . $expanded;
+ }
+ }
+
+ $replacements[] = $expanded;
+ }
+
+ $ret = implode($joiner, $replacements);
+ if ($ret && $prefix) {
+ return $prefix . $ret;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Determines if an array is associative
+ *
+ * @param array $array Array to check
+ *
+ * @return bool
+ */
+ private function isAssoc(array $array)
+ {
+ return (bool) count(array_filter(array_keys($array), 'is_string'));
+ }
+
+ /**
+ * Removes percent encoding on reserved characters (used with + and # modifiers)
+ *
+ * @param string $string String to fix
+ *
+ * @return string
+ */
+ private function decodeReserved($string)
+ {
+ return str_replace(self::$delimsPct, self::$delims, $string);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php
new file mode 100755
index 0000000..c81d515
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/UriTemplate/UriTemplateInterface.php
@@ -0,0 +1,21 @@
+utf8 = $utf8;
+ }
+
+ public function parseUrl($url)
+ {
+ Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()');
+
+ static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null,
+ 'user' => null, 'pass' => null, 'fragment' => null);
+
+ $parts = parse_url($url);
+
+ // Need to handle query parsing specially for UTF-8 requirements
+ if ($this->utf8 && isset($parts['query'])) {
+ $queryPos = strpos($url, '?');
+ if (isset($parts['fragment'])) {
+ $parts['query'] = substr($url, $queryPos + 1, strpos($url, '#') - $queryPos - 1);
+ } else {
+ $parts['query'] = substr($url, $queryPos + 1);
+ }
+ }
+
+ return $parts + $defaults;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php
new file mode 100755
index 0000000..89ac4b3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Parser/Url/UrlParserInterface.php
@@ -0,0 +1,19 @@
+=5.3.2"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Parser": "" }
+ },
+ "target-dir": "Guzzle/Parser",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php
new file mode 100755
index 0000000..ae59418
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/AsyncPlugin.php
@@ -0,0 +1,84 @@
+ 'onBeforeSend',
+ 'request.exception' => 'onRequestTimeout',
+ 'request.sent' => 'onRequestSent',
+ 'curl.callback.progress' => 'onCurlProgress'
+ );
+ }
+
+ /**
+ * Event used to ensure that progress callback are emitted from the curl handle's request mediator.
+ *
+ * @param Event $event
+ */
+ public function onBeforeSend(Event $event)
+ {
+ // Ensure that progress callbacks are dispatched
+ $event['request']->getCurlOptions()->set('progress', true);
+ }
+
+ /**
+ * Event emitted when a curl progress function is called. When the amount of data uploaded == the amount of data to
+ * upload OR any bytes have been downloaded, then time the request out after 1ms because we're done with
+ * transmitting the request, and tell curl not download a body.
+ *
+ * @param Event $event
+ */
+ public function onCurlProgress(Event $event)
+ {
+ if ($event['handle'] &&
+ ($event['downloaded'] || (isset($event['uploaded']) && $event['upload_size'] === $event['uploaded']))
+ ) {
+ // Timeout after 1ms
+ curl_setopt($event['handle'], CURLOPT_TIMEOUT_MS, 1);
+ // Even if the response is quick, tell curl not to download the body.
+ // - Note that we can only perform this shortcut if the request transmitted a body so as to ensure that the
+ // request method is not converted to a HEAD request before the request was sent via curl.
+ if ($event['uploaded']) {
+ curl_setopt($event['handle'], CURLOPT_NOBODY, true);
+ }
+ }
+ }
+
+ /**
+ * Event emitted when a curl exception occurs. Ignore the exception and set a mock response.
+ *
+ * @param Event $event
+ */
+ public function onRequestTimeout(Event $event)
+ {
+ if ($event['exception'] instanceof CurlException) {
+ $event['request']->setResponse(new Response(200, array(
+ 'X-Guzzle-Async' => 'Did not wait for the response'
+ )));
+ }
+ }
+
+ /**
+ * Event emitted when a request completes because it took less than 1ms. Add an X-Guzzle-Async header to notify the
+ * caller that there is no body in the message.
+ *
+ * @param Event $event
+ */
+ public function onRequestSent(Event $event)
+ {
+ // Let the caller know this was meant to be async
+ $event['request']->getResponse()->setHeader('X-Guzzle-Async', 'Did not wait for the response');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json
new file mode 100755
index 0000000..dc3fc5b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Async/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/plugin-async",
+ "description": "Guzzle async request plugin",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["plugin", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Async": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Async",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php
new file mode 100755
index 0000000..0a85983
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractBackoffStrategy.php
@@ -0,0 +1,91 @@
+next = $next;
+ }
+
+ /**
+ * Get the next backoff strategy in the chain
+ *
+ * @return AbstractBackoffStrategy|null
+ */
+ public function getNext()
+ {
+ return $this->next;
+ }
+
+ public function getBackoffPeriod(
+ $retries,
+ RequestInterface $request,
+ Response $response = null,
+ HttpException $e = null
+ ) {
+ $delay = $this->getDelay($retries, $request, $response, $e);
+ if ($delay === false) {
+ // The strategy knows that this must not be retried
+ return false;
+ } elseif ($delay === null) {
+ // If the strategy is deferring a decision and the next strategy will not make a decision then return false
+ return !$this->next || !$this->next->makesDecision()
+ ? false
+ : $this->next->getBackoffPeriod($retries, $request, $response, $e);
+ } elseif ($delay === true) {
+ // if the strategy knows that it must retry but is deferring to the next to determine the delay
+ if (!$this->next) {
+ return 0;
+ } else {
+ $next = $this->next;
+ while ($next->makesDecision() && $next->getNext()) {
+ $next = $next->getNext();
+ }
+ return !$next->makesDecision() ? $next->getBackoffPeriod($retries, $request, $response, $e) : 0;
+ }
+ } else {
+ return $delay;
+ }
+ }
+
+ /**
+ * Check if the strategy does filtering and makes decisions on whether or not to retry.
+ *
+ * Strategies that return false will never retry if all of the previous strategies in a chain defer on a backoff
+ * decision.
+ *
+ * @return bool
+ */
+ abstract public function makesDecision();
+
+ /**
+ * Implement the concrete strategy
+ *
+ * @param int $retries Number of retries of the request
+ * @param RequestInterface $request Request that was sent
+ * @param Response $response Response that was received. Note that there may not be a response
+ * @param HttpException $e Exception that was encountered if any
+ *
+ * @return bool|int|null Returns false to not retry or the number of seconds to delay between retries. Return true
+ * or null to defer to the next strategy if available, and if not, return 0.
+ */
+ abstract protected function getDelay(
+ $retries,
+ RequestInterface $request,
+ Response $response = null,
+ HttpException $e = null
+ );
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php
new file mode 100755
index 0000000..6ebee6c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/AbstractErrorCodeBackoffStrategy.php
@@ -0,0 +1,40 @@
+errorCodes = array_fill_keys($codes ?: static::$defaultErrorCodes, 1);
+ $this->next = $next;
+ }
+
+ /**
+ * Get the default failure codes to retry
+ *
+ * @return array
+ */
+ public static function getDefaultFailureCodes()
+ {
+ return static::$defaultErrorCodes;
+ }
+
+ public function makesDecision()
+ {
+ return true;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php
new file mode 100755
index 0000000..ec54c28
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffLogger.php
@@ -0,0 +1,76 @@
+logger = $logger;
+ $this->formatter = $formatter ?: new MessageFormatter(self::DEFAULT_FORMAT);
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(BackoffPlugin::RETRY_EVENT => 'onRequestRetry');
+ }
+
+ /**
+ * Set the template to use for logging
+ *
+ * @param string $template Log message template
+ *
+ * @return self
+ */
+ public function setTemplate($template)
+ {
+ $this->formatter->setTemplate($template);
+
+ return $this;
+ }
+
+ /**
+ * Called when a request is being retried
+ *
+ * @param Event $event Event emitted
+ */
+ public function onRequestRetry(Event $event)
+ {
+ $this->logger->log($this->formatter->format(
+ $event['request'],
+ $event['response'],
+ $event['handle'],
+ array(
+ 'retries' => $event['retries'],
+ 'delay' => $event['delay']
+ )
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php
new file mode 100755
index 0000000..99ace05
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffPlugin.php
@@ -0,0 +1,126 @@
+strategy = $strategy;
+ }
+
+ /**
+ * Retrieve a basic truncated exponential backoff plugin that will retry HTTP errors and cURL errors
+ *
+ * @param int $maxRetries Maximum number of retries
+ * @param array $httpCodes HTTP response codes to retry
+ * @param array $curlCodes cURL error codes to retry
+ *
+ * @return self
+ */
+ public static function getExponentialBackoff(
+ $maxRetries = 3,
+ array $httpCodes = null,
+ array $curlCodes = null
+ ) {
+ return new self(new TruncatedBackoffStrategy($maxRetries,
+ new HttpBackoffStrategy($httpCodes,
+ new CurlBackoffStrategy($curlCodes,
+ new ExponentialBackoffStrategy()
+ )
+ )
+ ));
+ }
+
+ public static function getAllEvents()
+ {
+ return array(self::RETRY_EVENT);
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'request.sent' => 'onRequestSent',
+ 'request.exception' => 'onRequestSent',
+ CurlMultiInterface::POLLING_REQUEST => 'onRequestPoll'
+ );
+ }
+
+ /**
+ * Called when a request has been sent and isn't finished processing
+ *
+ * @param Event $event
+ */
+ public function onRequestSent(Event $event)
+ {
+ $request = $event['request'];
+ $response = $event['response'];
+ $exception = $event['exception'];
+
+ $params = $request->getParams();
+ $retries = (int) $params->get(self::RETRY_PARAM);
+ $delay = $this->strategy->getBackoffPeriod($retries, $request, $response, $exception);
+
+ if ($delay !== false) {
+ // Calculate how long to wait until the request should be retried
+ $params->set(self::RETRY_PARAM, ++$retries)
+ ->set(self::DELAY_PARAM, microtime(true) + $delay);
+ // Send the request again
+ $request->setState(RequestInterface::STATE_TRANSFER);
+ $this->dispatch(self::RETRY_EVENT, array(
+ 'request' => $request,
+ 'response' => $response,
+ 'handle' => ($exception && $exception instanceof CurlException) ? $exception->getCurlHandle() : null,
+ 'retries' => $retries,
+ 'delay' => $delay
+ ));
+ }
+ }
+
+ /**
+ * Called when a request is polling in the curl multi object
+ *
+ * @param Event $event
+ */
+ public function onRequestPoll(Event $event)
+ {
+ $request = $event['request'];
+ $delay = $request->getParams()->get(self::DELAY_PARAM);
+
+ // If the duration of the delay has passed, retry the request using the pool
+ if (null !== $delay && microtime(true) >= $delay) {
+ // Remove the request from the pool and then add it back again. This is required for cURL to know that we
+ // want to retry sending the easy handle.
+ $request->getParams()->remove(self::DELAY_PARAM);
+ // Rewind the request body if possible
+ if ($request instanceof EntityEnclosingRequestInterface && $request->getBody()) {
+ $request->getBody()->seek(0);
+ }
+ $multi = $event['curl_multi'];
+ $multi->remove($request);
+ $multi->add($request);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php
new file mode 100755
index 0000000..4e590db
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/BackoffStrategyInterface.php
@@ -0,0 +1,30 @@
+callback = $callback;
+ $this->decision = (bool) $decision;
+ $this->next = $next;
+ }
+
+ public function makesDecision()
+ {
+ return $this->decision;
+ }
+
+ protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null)
+ {
+ return call_user_func($this->callback, $retries, $request, $response, $e);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php
new file mode 100755
index 0000000..061d2a4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ConstantBackoffStrategy.php
@@ -0,0 +1,34 @@
+delay = $delay;
+ }
+
+ public function makesDecision()
+ {
+ return false;
+ }
+
+ protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null)
+ {
+ return $this->delay;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php
new file mode 100755
index 0000000..a584ed4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/CurlBackoffStrategy.php
@@ -0,0 +1,28 @@
+errorCodes[$e->getErrorNo()]) ? true : null;
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php
new file mode 100755
index 0000000..fb2912d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ExponentialBackoffStrategy.php
@@ -0,0 +1,25 @@
+isSuccessful()) {
+ return false;
+ } else {
+ return isset($this->errorCodes[$response->getStatusCode()]) ? true : null;
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php
new file mode 100755
index 0000000..b35e8a4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/LinearBackoffStrategy.php
@@ -0,0 +1,36 @@
+step = $step;
+ }
+
+ public function makesDecision()
+ {
+ return false;
+ }
+
+ protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null)
+ {
+ return $retries * $this->step;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php
new file mode 100755
index 0000000..4fd73fe
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/ReasonPhraseBackoffStrategy.php
@@ -0,0 +1,25 @@
+errorCodes[$response->getReasonPhrase()]) ? true : null;
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php
new file mode 100755
index 0000000..3608f35
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/TruncatedBackoffStrategy.php
@@ -0,0 +1,36 @@
+max = $maxRetries;
+ $this->next = $next;
+ }
+
+ public function makesDecision()
+ {
+ return true;
+ }
+
+ protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null)
+ {
+ return $retries < $this->max ? null : false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json
new file mode 100755
index 0000000..91c122c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Backoff/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "guzzle/plugin-backoff",
+ "description": "Guzzle backoff retry plugins",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["plugin", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version",
+ "guzzle/log": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Backoff": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Backoff",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php
new file mode 100755
index 0000000..7790f88
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheKeyProviderInterface.php
@@ -0,0 +1,11 @@
+ new DefaultCacheStorage($options));
+ } elseif ($options instanceof CacheStorageInterface) {
+ $options = array('storage' => $options);
+ } elseif ($options) {
+ $options = array('storage' => new DefaultCacheStorage(CacheAdapterFactory::fromCache($options)));
+ } elseif (!class_exists('Doctrine\Common\Cache\ArrayCache')) {
+ // @codeCoverageIgnoreStart
+ throw new InvalidArgumentException('No cache was provided and Doctrine is not installed');
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ $this->autoPurge = isset($options['auto_purge']) ? $options['auto_purge'] : false;
+
+ // Add a cache storage if a cache adapter was provided
+ $this->storage = isset($options['storage'])
+ ? $options['storage']
+ : new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache()));
+
+ if (!isset($options['can_cache'])) {
+ $this->canCache = new DefaultCanCacheStrategy();
+ } else {
+ $this->canCache = is_callable($options['can_cache'])
+ ? new CallbackCanCacheStrategy($options['can_cache'])
+ : $options['can_cache'];
+ }
+
+ // Use the provided revalidation strategy or the default
+ $this->revalidation = isset($options['revalidation'])
+ ? $options['revalidation']
+ : new DefaultRevalidation($this->storage, $this->canCache);
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'request.before_send' => array('onRequestBeforeSend', -255),
+ 'request.sent' => array('onRequestSent', 255),
+ 'request.error' => array('onRequestError', 0),
+ 'request.exception' => array('onRequestException', 0),
+ );
+ }
+
+ /**
+ * Check if a response in cache will satisfy the request before sending
+ *
+ * @param Event $event
+ */
+ public function onRequestBeforeSend(Event $event)
+ {
+ $request = $event['request'];
+ $request->addHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION));
+
+ if (!$this->canCache->canCacheRequest($request)) {
+ switch ($request->getMethod()) {
+ case 'PURGE':
+ $this->purge($request);
+ $request->setResponse(new Response(200, array(), 'purged'));
+ break;
+ case 'PUT':
+ case 'POST':
+ case 'DELETE':
+ case 'PATCH':
+ if ($this->autoPurge) {
+ $this->purge($request);
+ }
+ }
+ return;
+ }
+
+ if ($response = $this->storage->fetch($request)) {
+ $params = $request->getParams();
+ $params['cache.lookup'] = true;
+ $response->setHeader(
+ 'Age',
+ time() - strtotime($response->getDate() ? : $response->getLastModified() ?: 'now')
+ );
+ // Validate that the response satisfies the request
+ if ($this->canResponseSatisfyRequest($request, $response)) {
+ if (!isset($params['cache.hit'])) {
+ $params['cache.hit'] = true;
+ }
+ $request->setResponse($response);
+ }
+ }
+ }
+
+ /**
+ * If possible, store a response in cache after sending
+ *
+ * @param Event $event
+ */
+ public function onRequestSent(Event $event)
+ {
+ $request = $event['request'];
+ $response = $event['response'];
+
+ if ($request->getParams()->get('cache.hit') === null &&
+ $this->canCache->canCacheRequest($request) &&
+ $this->canCache->canCacheResponse($response)
+ ) {
+ $this->storage->cache($request, $response);
+ }
+
+ $this->addResponseHeaders($request, $response);
+ }
+
+ /**
+ * If possible, return a cache response on an error
+ *
+ * @param Event $event
+ */
+ public function onRequestError(Event $event)
+ {
+ $request = $event['request'];
+
+ if (!$this->canCache->canCacheRequest($request)) {
+ return;
+ }
+
+ if ($response = $this->storage->fetch($request)) {
+ $response->setHeader(
+ 'Age',
+ time() - strtotime($response->getLastModified() ? : $response->getDate() ?: 'now')
+ );
+
+ if ($this->canResponseSatisfyFailedRequest($request, $response)) {
+ $request->getParams()->set('cache.hit', 'error');
+ $this->addResponseHeaders($request, $response);
+ $event['response'] = $response;
+ $event->stopPropagation();
+ }
+ }
+ }
+
+ /**
+ * If possible, set a cache response on a cURL exception
+ *
+ * @param Event $event
+ *
+ * @return null
+ */
+ public function onRequestException(Event $event)
+ {
+ if (!$event['exception'] instanceof CurlException) {
+ return;
+ }
+
+ $request = $event['request'];
+ if (!$this->canCache->canCacheRequest($request)) {
+ return;
+ }
+
+ if ($response = $this->storage->fetch($request)) {
+ $response->setHeader('Age', time() - strtotime($response->getDate() ? : 'now'));
+ if (!$this->canResponseSatisfyFailedRequest($request, $response)) {
+ return;
+ }
+ $request->getParams()->set('cache.hit', 'error');
+ $request->setResponse($response);
+ $this->addResponseHeaders($request, $response);
+ $event->stopPropagation();
+ }
+ }
+
+ /**
+ * Check if a cache response satisfies a request's caching constraints
+ *
+ * @param RequestInterface $request Request to validate
+ * @param Response $response Response to validate
+ *
+ * @return bool
+ */
+ public function canResponseSatisfyRequest(RequestInterface $request, Response $response)
+ {
+ $responseAge = $response->calculateAge();
+ $reqc = $request->getHeader('Cache-Control');
+ $resc = $response->getHeader('Cache-Control');
+
+ // Check the request's max-age header against the age of the response
+ if ($reqc && $reqc->hasDirective('max-age') &&
+ $responseAge > $reqc->getDirective('max-age')) {
+ return false;
+ }
+
+ // Check the response's max-age header
+ if ($response->isFresh() === false) {
+ $maxStale = $reqc ? $reqc->getDirective('max-stale') : null;
+ if (null !== $maxStale) {
+ if ($maxStale !== true && $response->getFreshness() < (-1 * $maxStale)) {
+ return false;
+ }
+ } elseif ($resc && $resc->hasDirective('max-age')
+ && $responseAge > $resc->getDirective('max-age')
+ ) {
+ return false;
+ }
+ }
+
+ if ($this->revalidation->shouldRevalidate($request, $response)) {
+ try {
+ return $this->revalidation->revalidate($request, $response);
+ } catch (CurlException $e) {
+ $request->getParams()->set('cache.hit', 'error');
+ return $this->canResponseSatisfyFailedRequest($request, $response);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if a cache response satisfies a failed request's caching constraints
+ *
+ * @param RequestInterface $request Request to validate
+ * @param Response $response Response to validate
+ *
+ * @return bool
+ */
+ public function canResponseSatisfyFailedRequest(RequestInterface $request, Response $response)
+ {
+ $reqc = $request->getHeader('Cache-Control');
+ $resc = $response->getHeader('Cache-Control');
+ $requestStaleIfError = $reqc ? $reqc->getDirective('stale-if-error') : null;
+ $responseStaleIfError = $resc ? $resc->getDirective('stale-if-error') : null;
+
+ if (!$requestStaleIfError && !$responseStaleIfError) {
+ return false;
+ }
+
+ if (is_numeric($requestStaleIfError) && $response->getAge() - $response->getMaxAge() > $requestStaleIfError) {
+ return false;
+ }
+
+ if (is_numeric($responseStaleIfError) && $response->getAge() - $response->getMaxAge() > $responseStaleIfError) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Purge all cache entries for a given URL
+ *
+ * @param string $url URL to purge
+ */
+ public function purge($url)
+ {
+ // BC compatibility with previous version that accepted a Request object
+ $url = $url instanceof RequestInterface ? $url->getUrl() : $url;
+ $this->storage->purge($url);
+ }
+
+ /**
+ * Add the plugin's headers to a response
+ *
+ * @param RequestInterface $request Request
+ * @param Response $response Response to add headers to
+ */
+ protected function addResponseHeaders(RequestInterface $request, Response $response)
+ {
+ $params = $request->getParams();
+ $response->setHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION));
+
+ $lookup = ($params['cache.lookup'] === true ? 'HIT' : 'MISS') . ' from GuzzleCache';
+ if ($header = $response->getHeader('X-Cache-Lookup')) {
+ // Don't add duplicates
+ $values = $header->toArray();
+ $values[] = $lookup;
+ $response->setHeader('X-Cache-Lookup', array_unique($values));
+ } else {
+ $response->setHeader('X-Cache-Lookup', $lookup);
+ }
+
+ if ($params['cache.hit'] === true) {
+ $xcache = 'HIT from GuzzleCache';
+ } elseif ($params['cache.hit'] == 'error') {
+ $xcache = 'HIT_ERROR from GuzzleCache';
+ } else {
+ $xcache = 'MISS from GuzzleCache';
+ }
+
+ if ($header = $response->getHeader('X-Cache')) {
+ // Don't add duplicates
+ $values = $header->toArray();
+ $values[] = $xcache;
+ $response->setHeader('X-Cache', array_unique($values));
+ } else {
+ $response->setHeader('X-Cache', $xcache);
+ }
+
+ if ($response->isFresh() === false) {
+ $response->addHeader('Warning', sprintf('110 GuzzleCache/%s "Response is stale"', Version::VERSION));
+ if ($params['cache.hit'] === 'error') {
+ $response->addHeader('Warning', sprintf('111 GuzzleCache/%s "Revalidation failed"', Version::VERSION));
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php
new file mode 100755
index 0000000..f3d9154
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CacheStorageInterface.php
@@ -0,0 +1,43 @@
+requestCallback = $requestCallback;
+ $this->responseCallback = $responseCallback;
+ }
+
+ public function canCacheRequest(RequestInterface $request)
+ {
+ return $this->requestCallback
+ ? call_user_func($this->requestCallback, $request)
+ : parent::canCacheRequest($request);
+ }
+
+ public function canCacheResponse(Response $response)
+ {
+ return $this->responseCallback
+ ? call_user_func($this->responseCallback, $response)
+ : parent::canCacheResponse($response);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php
new file mode 100755
index 0000000..6e01a8e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/CanCacheStrategyInterface.php
@@ -0,0 +1,30 @@
+getParams()->get(self::CACHE_KEY);
+
+ if (!$key) {
+
+ $cloned = clone $request;
+ $cloned->removeHeader('Cache-Control');
+
+ // Check to see how and if the key should be filtered
+ foreach (explode(';', $request->getParams()->get(self::CACHE_KEY_FILTER)) as $part) {
+ $pieces = array_map('trim', explode('=', $part));
+ if (isset($pieces[1])) {
+ foreach (array_map('trim', explode(',', $pieces[1])) as $remove) {
+ if ($pieces[0] == 'header') {
+ $cloned->removeHeader($remove);
+ } elseif ($pieces[0] == 'query') {
+ $cloned->getQuery()->remove($remove);
+ }
+ }
+ }
+ }
+
+ $raw = (string) $cloned;
+ $key = 'GZ' . md5($raw);
+ $request->getParams()->set(self::CACHE_KEY, $key)->set(self::CACHE_KEY_RAW, $raw);
+ }
+
+ return $key;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php
new file mode 100755
index 0000000..26d7a8b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCacheStorage.php
@@ -0,0 +1,266 @@
+cache = CacheAdapterFactory::fromCache($cache);
+ $this->defaultTtl = $defaultTtl;
+ $this->keyPrefix = $keyPrefix;
+ }
+
+ public function cache(RequestInterface $request, Response $response)
+ {
+ $currentTime = time();
+
+ $overrideTtl = $request->getParams()->get('cache.override_ttl');
+ if ($overrideTtl) {
+ $ttl = $overrideTtl;
+ } else {
+ $maxAge = $response->getMaxAge();
+ if ($maxAge !== null) {
+ $ttl = $maxAge;
+ } else {
+ $ttl = $this->defaultTtl;
+ }
+ }
+
+ if ($cacheControl = $response->getHeader('Cache-Control')) {
+ $stale = $cacheControl->getDirective('stale-if-error');
+ if ($stale === true) {
+ $ttl += $ttl;
+ } else if (is_numeric($stale)) {
+ $ttl += $stale;
+ }
+ }
+
+ // Determine which manifest key should be used
+ $key = $this->getCacheKey($request);
+ $persistedRequest = $this->persistHeaders($request);
+ $entries = array();
+
+ if ($manifest = $this->cache->fetch($key)) {
+ // Determine which cache entries should still be in the cache
+ $vary = $response->getVary();
+ foreach (unserialize($manifest) as $entry) {
+ // Check if the entry is expired
+ if ($entry[4] < $currentTime) {
+ continue;
+ }
+ $entry[1]['vary'] = isset($entry[1]['vary']) ? $entry[1]['vary'] : '';
+ if ($vary != $entry[1]['vary'] || !$this->requestsMatch($vary, $entry[0], $persistedRequest)) {
+ $entries[] = $entry;
+ }
+ }
+ }
+
+ // Persist the response body if needed
+ $bodyDigest = null;
+ if ($response->getBody() && $response->getBody()->getContentLength() > 0) {
+ $bodyDigest = $this->getBodyKey($request->getUrl(), $response->getBody());
+ $this->cache->save($bodyDigest, (string) $response->getBody(), $ttl);
+ }
+
+ array_unshift($entries, array(
+ $persistedRequest,
+ $this->persistHeaders($response),
+ $response->getStatusCode(),
+ $bodyDigest,
+ $currentTime + $ttl
+ ));
+
+ $this->cache->save($key, serialize($entries));
+ }
+
+ public function delete(RequestInterface $request)
+ {
+ $key = $this->getCacheKey($request);
+ if ($entries = $this->cache->fetch($key)) {
+ // Delete each cached body
+ foreach (unserialize($entries) as $entry) {
+ if ($entry[3]) {
+ $this->cache->delete($entry[3]);
+ }
+ }
+ $this->cache->delete($key);
+ }
+ }
+
+ public function purge($url)
+ {
+ foreach (array('GET', 'HEAD', 'POST', 'PUT', 'DELETE') as $method) {
+ $this->delete(new Request($method, $url));
+ }
+ }
+
+ public function fetch(RequestInterface $request)
+ {
+ $key = $this->getCacheKey($request);
+ if (!($entries = $this->cache->fetch($key))) {
+ return null;
+ }
+
+ $match = null;
+ $headers = $this->persistHeaders($request);
+ $entries = unserialize($entries);
+ foreach ($entries as $index => $entry) {
+ if ($this->requestsMatch(isset($entry[1]['vary']) ? $entry[1]['vary'] : '', $headers, $entry[0])) {
+ $match = $entry;
+ break;
+ }
+ }
+
+ if (!$match) {
+ return null;
+ }
+
+ // Ensure that the response is not expired
+ $response = null;
+ if ($match[4] < time()) {
+ $response = -1;
+ } else {
+ $response = new Response($match[2], $match[1]);
+ if ($match[3]) {
+ if ($body = $this->cache->fetch($match[3])) {
+ $response->setBody($body);
+ } else {
+ // The response is not valid because the body was somehow deleted
+ $response = -1;
+ }
+ }
+ }
+
+ if ($response === -1) {
+ // Remove the entry from the metadata and update the cache
+ unset($entries[$index]);
+ if ($entries) {
+ $this->cache->save($key, serialize($entries));
+ } else {
+ $this->cache->delete($key);
+ }
+ return null;
+ }
+
+ return $response;
+ }
+
+ /**
+ * Hash a request URL into a string that returns cache metadata
+ *
+ * @param RequestInterface $request
+ *
+ * @return string
+ */
+ protected function getCacheKey(RequestInterface $request)
+ {
+ // Allow cache.key_filter to trim down the URL cache key by removing generate query string values (e.g. auth)
+ if ($filter = $request->getParams()->get('cache.key_filter')) {
+ $url = $request->getUrl(true);
+ foreach (explode(',', $filter) as $remove) {
+ $url->getQuery()->remove(trim($remove));
+ }
+ } else {
+ $url = $request->getUrl();
+ }
+
+ return $this->keyPrefix . md5($request->getMethod() . ' ' . $url);
+ }
+
+ /**
+ * Create a cache key for a response's body
+ *
+ * @param string $url URL of the entry
+ * @param EntityBodyInterface $body Response body
+ *
+ * @return string
+ */
+ protected function getBodyKey($url, EntityBodyInterface $body)
+ {
+ return $this->keyPrefix . md5($url) . $body->getContentMd5();
+ }
+
+ /**
+ * Determines whether two Request HTTP header sets are non-varying
+ *
+ * @param string $vary Response vary header
+ * @param array $r1 HTTP header array
+ * @param array $r2 HTTP header array
+ *
+ * @return bool
+ */
+ private function requestsMatch($vary, $r1, $r2)
+ {
+ if ($vary) {
+ foreach (explode(',', $vary) as $header) {
+ $key = trim(strtolower($header));
+ $v1 = isset($r1[$key]) ? $r1[$key] : null;
+ $v2 = isset($r2[$key]) ? $r2[$key] : null;
+ if ($v1 !== $v2) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Creates an array of cacheable and normalized message headers
+ *
+ * @param MessageInterface $message
+ *
+ * @return array
+ */
+ private function persistHeaders(MessageInterface $message)
+ {
+ // Headers are excluded from the caching (see RFC 2616:13.5.1)
+ static $noCache = array(
+ 'age' => true,
+ 'connection' => true,
+ 'keep-alive' => true,
+ 'proxy-authenticate' => true,
+ 'proxy-authorization' => true,
+ 'te' => true,
+ 'trailers' => true,
+ 'transfer-encoding' => true,
+ 'upgrade' => true,
+ 'set-cookie' => true,
+ 'set-cookie2' => true
+ );
+
+ // Clone the response to not destroy any necessary headers when caching
+ $headers = $message->getHeaders()->getAll();
+ $headers = array_diff_key($headers, $noCache);
+ // Cast the headers to a string
+ $headers = array_map(function ($h) { return (string) $h; }, $headers);
+
+ return $headers;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php
new file mode 100755
index 0000000..3ca1fbf
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultCanCacheStrategy.php
@@ -0,0 +1,32 @@
+getMethod() != RequestInterface::GET && $request->getMethod() != RequestInterface::HEAD) {
+ return false;
+ }
+
+ // Never cache requests when using no-store
+ if ($request->hasHeader('Cache-Control') && $request->getHeader('Cache-Control')->hasDirective('no-store')) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public function canCacheResponse(Response $response)
+ {
+ return $response->isSuccessful() && $response->canCache();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php
new file mode 100755
index 0000000..af33234
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DefaultRevalidation.php
@@ -0,0 +1,174 @@
+storage = $cache;
+ $this->canCache = $canCache ?: new DefaultCanCacheStrategy();
+ }
+
+ public function revalidate(RequestInterface $request, Response $response)
+ {
+ try {
+ $revalidate = $this->createRevalidationRequest($request, $response);
+ $validateResponse = $revalidate->send();
+ if ($validateResponse->getStatusCode() == 200) {
+ return $this->handle200Response($request, $validateResponse);
+ } elseif ($validateResponse->getStatusCode() == 304) {
+ return $this->handle304Response($request, $validateResponse, $response);
+ }
+ } catch (BadResponseException $e) {
+ $this->handleBadResponse($e);
+ }
+
+ // Other exceptions encountered in the revalidation request are ignored
+ // in hopes that sending a request to the origin server will fix it
+ return false;
+ }
+
+ public function shouldRevalidate(RequestInterface $request, Response $response)
+ {
+ if ($request->getMethod() != RequestInterface::GET) {
+ return false;
+ }
+
+ $reqCache = $request->getHeader('Cache-Control');
+ $resCache = $response->getHeader('Cache-Control');
+
+ $revalidate = $request->getHeader('Pragma') == 'no-cache' ||
+ ($reqCache && ($reqCache->hasDirective('no-cache') || $reqCache->hasDirective('must-revalidate'))) ||
+ ($resCache && ($resCache->hasDirective('no-cache') || $resCache->hasDirective('must-revalidate')));
+
+ // Use the strong ETag validator if available and the response contains no Cache-Control directive
+ if (!$revalidate && !$resCache && $response->hasHeader('ETag')) {
+ $revalidate = true;
+ }
+
+ return $revalidate;
+ }
+
+ /**
+ * Handles a bad response when attempting to revalidate
+ *
+ * @param BadResponseException $e Exception encountered
+ *
+ * @throws BadResponseException
+ */
+ protected function handleBadResponse(BadResponseException $e)
+ {
+ // 404 errors mean the resource no longer exists, so remove from
+ // cache, and prevent an additional request by throwing the exception
+ if ($e->getResponse()->getStatusCode() == 404) {
+ $this->storage->delete($e->getRequest());
+ throw $e;
+ }
+ }
+
+ /**
+ * Creates a request to use for revalidation
+ *
+ * @param RequestInterface $request Request
+ * @param Response $response Response to revalidate
+ *
+ * @return RequestInterface returns a revalidation request
+ */
+ protected function createRevalidationRequest(RequestInterface $request, Response $response)
+ {
+ $revalidate = clone $request;
+ $revalidate->removeHeader('Pragma')->removeHeader('Cache-Control');
+
+ if ($response->getLastModified()) {
+ $revalidate->setHeader('If-Modified-Since', $response->getLastModified());
+ }
+
+ if ($response->getEtag()) {
+ $revalidate->setHeader('If-None-Match', $response->getEtag());
+ }
+
+ // Remove any cache plugins that might be on the request to prevent infinite recursive revalidations
+ $dispatcher = $revalidate->getEventDispatcher();
+ foreach ($dispatcher->getListeners() as $eventName => $listeners) {
+ foreach ($listeners as $listener) {
+ if (is_array($listener) && $listener[0] instanceof CachePlugin) {
+ $dispatcher->removeListener($eventName, $listener);
+ }
+ }
+ }
+
+ return $revalidate;
+ }
+
+ /**
+ * Handles a 200 response response from revalidating. The server does not support validation, so use this response.
+ *
+ * @param RequestInterface $request Request that was sent
+ * @param Response $validateResponse Response received
+ *
+ * @return bool Returns true if valid, false if invalid
+ */
+ protected function handle200Response(RequestInterface $request, Response $validateResponse)
+ {
+ $request->setResponse($validateResponse);
+ if ($this->canCache->canCacheResponse($validateResponse)) {
+ $this->storage->cache($request, $validateResponse);
+ }
+
+ return false;
+ }
+
+ /**
+ * Handle a 304 response and ensure that it is still valid
+ *
+ * @param RequestInterface $request Request that was sent
+ * @param Response $validateResponse Response received
+ * @param Response $response Original cached response
+ *
+ * @return bool Returns true if valid, false if invalid
+ */
+ protected function handle304Response(RequestInterface $request, Response $validateResponse, Response $response)
+ {
+ static $replaceHeaders = array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified');
+
+ // Make sure that this response has the same ETag
+ if ($validateResponse->getEtag() != $response->getEtag()) {
+ return false;
+ }
+
+ // Replace cached headers with any of these headers from the
+ // origin server that might be more up to date
+ $modified = false;
+ foreach ($replaceHeaders as $name) {
+ if ($validateResponse->hasHeader($name)) {
+ $modified = true;
+ $response->setHeader($name, $validateResponse->getHeader($name));
+ }
+ }
+
+ // Store the updated response in cache
+ if ($modified && $this->canCache->canCacheResponse($response)) {
+ $this->storage->cache($request, $response);
+ }
+
+ return true;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php
new file mode 100755
index 0000000..88b86f3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cache/DenyRevalidation.php
@@ -0,0 +1,19 @@
+=5.3.2",
+ "guzzle/http": "self.version",
+ "guzzle/cache": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Cache": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Cache",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php
new file mode 100755
index 0000000..5218e5f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Cookie.php
@@ -0,0 +1,538 @@
+ '',
+ 'value' => '',
+ 'domain' => '',
+ 'path' => '/',
+ 'expires' => null,
+ 'max_age' => 0,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'port' => array(),
+ 'version' => null,
+ 'secure' => false,
+ 'discard' => false,
+ 'http_only' => false
+ );
+
+ $this->data = array_merge($defaults, $data);
+ // Extract the expires value and turn it into a UNIX timestamp if needed
+ if (!$this->getExpires() && $this->getMaxAge()) {
+ // Calculate the expires date
+ $this->setExpires(time() + (int) $this->getMaxAge());
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
+ $this->setExpires(strtotime($this->getExpires()));
+ }
+ }
+
+ /**
+ * Get the cookie as an array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Get the cookie name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->data['name'];
+ }
+
+ /**
+ * Set the cookie name
+ *
+ * @param string $name Cookie name
+ *
+ * @return Cookie
+ */
+ public function setName($name)
+ {
+ return $this->setData('name', $name);
+ }
+
+ /**
+ * Get the cookie value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->data['value'];
+ }
+
+ /**
+ * Set the cookie value
+ *
+ * @param string $value Cookie value
+ *
+ * @return Cookie
+ */
+ public function setValue($value)
+ {
+ return $this->setData('value', $value);
+ }
+
+ /**
+ * Get the domain
+ *
+ * @return string|null
+ */
+ public function getDomain()
+ {
+ return $this->data['domain'];
+ }
+
+ /**
+ * Set the domain of the cookie
+ *
+ * @param string $domain
+ *
+ * @return Cookie
+ */
+ public function setDomain($domain)
+ {
+ return $this->setData('domain', $domain);
+ }
+
+ /**
+ * Get the path
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->data['path'];
+ }
+
+ /**
+ * Set the path of the cookie
+ *
+ * @param string $path Path of the cookie
+ *
+ * @return Cookie
+ */
+ public function setPath($path)
+ {
+ return $this->setData('path', $path);
+ }
+
+ /**
+ * Maximum lifetime of the cookie in seconds
+ *
+ * @return int|null
+ */
+ public function getMaxAge()
+ {
+ return $this->data['max_age'];
+ }
+
+ /**
+ * Set the max-age of the cookie
+ *
+ * @param int $maxAge Max age of the cookie in seconds
+ *
+ * @return Cookie
+ */
+ public function setMaxAge($maxAge)
+ {
+ return $this->setData('max_age', $maxAge);
+ }
+
+ /**
+ * The UNIX timestamp when the cookie expires
+ *
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->data['expires'];
+ }
+
+ /**
+ * Set the unix timestamp for which the cookie will expire
+ *
+ * @param int $timestamp Unix timestamp
+ *
+ * @return Cookie
+ */
+ public function setExpires($timestamp)
+ {
+ return $this->setData('expires', $timestamp);
+ }
+
+ /**
+ * Version of the cookie specification. RFC 2965 is 1
+ *
+ * @return mixed
+ */
+ public function getVersion()
+ {
+ return $this->data['version'];
+ }
+
+ /**
+ * Set the cookie version
+ *
+ * @param string|int $version Version to set
+ *
+ * @return Cookie
+ */
+ public function setVersion($version)
+ {
+ return $this->setData('version', $version);
+ }
+
+ /**
+ * Get whether or not this is a secure cookie
+ *
+ * @return null|bool
+ */
+ public function getSecure()
+ {
+ return $this->data['secure'];
+ }
+
+ /**
+ * Set whether or not the cookie is secure
+ *
+ * @param bool $secure Set to true or false if secure
+ *
+ * @return Cookie
+ */
+ public function setSecure($secure)
+ {
+ return $this->setData('secure', (bool) $secure);
+ }
+
+ /**
+ * Get whether or not this is a session cookie
+ *
+ * @return null|bool
+ */
+ public function getDiscard()
+ {
+ return $this->data['discard'];
+ }
+
+ /**
+ * Set whether or not this is a session cookie
+ *
+ * @param bool $discard Set to true or false if this is a session cookie
+ *
+ * @return Cookie
+ */
+ public function setDiscard($discard)
+ {
+ return $this->setData('discard', $discard);
+ }
+
+ /**
+ * Get the comment
+ *
+ * @return string|null
+ */
+ public function getComment()
+ {
+ return $this->data['comment'];
+ }
+
+ /**
+ * Set the comment of the cookie
+ *
+ * @param string $comment Cookie comment
+ *
+ * @return Cookie
+ */
+ public function setComment($comment)
+ {
+ return $this->setData('comment', $comment);
+ }
+
+ /**
+ * Get the comment URL of the cookie
+ *
+ * @return string|null
+ */
+ public function getCommentUrl()
+ {
+ return $this->data['comment_url'];
+ }
+
+ /**
+ * Set the comment URL of the cookie
+ *
+ * @param string $commentUrl Cookie comment URL for more information
+ *
+ * @return Cookie
+ */
+ public function setCommentUrl($commentUrl)
+ {
+ return $this->setData('comment_url', $commentUrl);
+ }
+
+ /**
+ * Get an array of acceptable ports this cookie can be used with
+ *
+ * @return array
+ */
+ public function getPorts()
+ {
+ return $this->data['port'];
+ }
+
+ /**
+ * Set a list of acceptable ports this cookie can be used with
+ *
+ * @param array $ports Array of acceptable ports
+ *
+ * @return Cookie
+ */
+ public function setPorts(array $ports)
+ {
+ return $this->setData('port', $ports);
+ }
+
+ /**
+ * Get whether or not this is an HTTP only cookie
+ *
+ * @return bool
+ */
+ public function getHttpOnly()
+ {
+ return $this->data['http_only'];
+ }
+
+ /**
+ * Set whether or not this is an HTTP only cookie
+ *
+ * @param bool $httpOnly Set to true or false if this is HTTP only
+ *
+ * @return Cookie
+ */
+ public function setHttpOnly($httpOnly)
+ {
+ return $this->setData('http_only', $httpOnly);
+ }
+
+ /**
+ * Get an array of extra cookie data
+ *
+ * @return array
+ */
+ public function getAttributes()
+ {
+ return $this->data['data'];
+ }
+
+ /**
+ * Get a specific data point from the extra cookie data
+ *
+ * @param string $name Name of the data point to retrieve
+ *
+ * @return null|string
+ */
+ public function getAttribute($name)
+ {
+ return array_key_exists($name, $this->data['data']) ? $this->data['data'][$name] : null;
+ }
+
+ /**
+ * Set a cookie data attribute
+ *
+ * @param string $name Name of the attribute to set
+ * @param string $value Value to set
+ *
+ * @return Cookie
+ */
+ public function setAttribute($name, $value)
+ {
+ $this->data['data'][$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Check if the cookie matches a path value
+ *
+ * @param string $path Path to check against
+ *
+ * @return bool
+ */
+ public function matchesPath($path)
+ {
+ // RFC6265 http://tools.ietf.org/search/rfc6265#section-5.1.4
+ // A request-path path-matches a given cookie-path if at least one of
+ // the following conditions holds:
+
+ // o The cookie-path and the request-path are identical.
+ if ($path == $this->getPath()) {
+ return true;
+ }
+
+ $pos = stripos($path, $this->getPath());
+ if ($pos === 0) {
+ // o The cookie-path is a prefix of the request-path, and the last
+ // character of the cookie-path is %x2F ("/").
+ if (substr($this->getPath(), -1, 1) === "/") {
+ return true;
+ }
+
+ // o The cookie-path is a prefix of the request-path, and the first
+ // character of the request-path that is not included in the cookie-
+ // path is a %x2F ("/") character.
+ if (substr($path, strlen($this->getPath()), 1) === "/") {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if the cookie matches a domain value
+ *
+ * @param string $domain Domain to check against
+ *
+ * @return bool
+ */
+ public function matchesDomain($domain)
+ {
+ // Remove the leading '.' as per spec in RFC 6265: http://tools.ietf.org/html/rfc6265#section-5.2.3
+ $cookieDomain = ltrim($this->getDomain(), '.');
+
+ // Domain not set or exact match.
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
+ return true;
+ }
+
+ // Matching the subdomain according to RFC 6265: http://tools.ietf.org/html/rfc6265#section-5.1.3
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
+ return false;
+ }
+
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/i', $domain);
+ }
+
+ /**
+ * Check if the cookie is compatible with a specific port
+ *
+ * @param int $port Port to check
+ *
+ * @return bool
+ */
+ public function matchesPort($port)
+ {
+ return count($this->getPorts()) == 0 || in_array($port, $this->getPorts());
+ }
+
+ /**
+ * Check if the cookie is expired
+ *
+ * @return bool
+ */
+ public function isExpired()
+ {
+ return $this->getExpires() && time() > $this->getExpires();
+ }
+
+ /**
+ * Check if the cookie is valid according to RFC 6265
+ *
+ * @return bool|string Returns true if valid or an error message if invalid
+ */
+ public function validate()
+ {
+ // Names must not be empty, but can be 0
+ $name = $this->getName();
+ if (empty($name) && !is_numeric($name)) {
+ return 'The cookie name must not be empty';
+ }
+
+ // Check if any of the invalid characters are present in the cookie name
+ if (strpbrk($name, self::getInvalidCharacters()) !== false) {
+ return 'The cookie name must not contain invalid characters: ' . $name;
+ }
+
+ // Value must not be empty, but can be 0
+ $value = $this->getValue();
+ if (empty($value) && !is_numeric($value)) {
+ return 'The cookie value must not be empty';
+ }
+
+ // Domains must not be empty, but can be 0
+ // A "0" is not a valid internet domain, but may be used as server name in a private network
+ $domain = $this->getDomain();
+ if (empty($domain) && !is_numeric($domain)) {
+ return 'The cookie domain must not be empty';
+ }
+
+ return true;
+ }
+
+ /**
+ * Set a value and return the cookie object
+ *
+ * @param string $key Key to set
+ * @param string $value Value to set
+ *
+ * @return Cookie
+ */
+ private function setData($key, $value)
+ {
+ $this->data[$key] = $value;
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php
new file mode 100755
index 0000000..6b67503
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/ArrayCookieJar.php
@@ -0,0 +1,237 @@
+strictMode = $strictMode;
+ }
+
+ /**
+ * Enable or disable strict mode on the cookie jar
+ *
+ * @param bool $strictMode Set to true to throw exceptions when invalid cookies are added. False to ignore them.
+ *
+ * @return self
+ */
+ public function setStrictMode($strictMode)
+ {
+ $this->strictMode = $strictMode;
+ }
+
+ public function remove($domain = null, $path = null, $name = null)
+ {
+ $cookies = $this->all($domain, $path, $name, false, false);
+ $this->cookies = array_filter($this->cookies, function (Cookie $cookie) use ($cookies) {
+ return !in_array($cookie, $cookies, true);
+ });
+
+ return $this;
+ }
+
+ public function removeTemporary()
+ {
+ $this->cookies = array_filter($this->cookies, function (Cookie $cookie) {
+ return !$cookie->getDiscard() && $cookie->getExpires();
+ });
+
+ return $this;
+ }
+
+ public function removeExpired()
+ {
+ $currentTime = time();
+ $this->cookies = array_filter($this->cookies, function (Cookie $cookie) use ($currentTime) {
+ return !$cookie->getExpires() || $currentTime < $cookie->getExpires();
+ });
+
+ return $this;
+ }
+
+ public function all($domain = null, $path = null, $name = null, $skipDiscardable = false, $skipExpired = true)
+ {
+ return array_values(array_filter($this->cookies, function (Cookie $cookie) use (
+ $domain,
+ $path,
+ $name,
+ $skipDiscardable,
+ $skipExpired
+ ) {
+ return false === (($name && $cookie->getName() != $name) ||
+ ($skipExpired && $cookie->isExpired()) ||
+ ($skipDiscardable && ($cookie->getDiscard() || !$cookie->getExpires())) ||
+ ($path && !$cookie->matchesPath($path)) ||
+ ($domain && !$cookie->matchesDomain($domain)));
+ }));
+ }
+
+ public function add(Cookie $cookie)
+ {
+ // Only allow cookies with set and valid domain, name, value
+ $result = $cookie->validate();
+ if ($result !== true) {
+ if ($this->strictMode) {
+ throw new InvalidCookieException($result);
+ } else {
+ $this->removeCookieIfEmpty($cookie);
+ return false;
+ }
+ }
+
+ // Resolve conflicts with previously set cookies
+ foreach ($this->cookies as $i => $c) {
+
+ // Two cookies are identical, when their path, domain, port and name are identical
+ if ($c->getPath() != $cookie->getPath() ||
+ $c->getDomain() != $cookie->getDomain() ||
+ $c->getPorts() != $cookie->getPorts() ||
+ $c->getName() != $cookie->getName()
+ ) {
+ continue;
+ }
+
+ // The previously set cookie is a discard cookie and this one is not so allow the new cookie to be set
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the new cookie's expiration is further into the future, then replace the old cookie
+ if ($cookie->getExpires() > $c->getExpires()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the value has changed, we better change it
+ if ($cookie->getValue() !== $c->getValue()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // The cookie exists, so no need to continue
+ return false;
+ }
+
+ $this->cookies[] = $cookie;
+
+ return true;
+ }
+
+ /**
+ * Serializes the cookie cookieJar
+ *
+ * @return string
+ */
+ public function serialize()
+ {
+ // Only serialize long term cookies and unexpired cookies
+ return json_encode(array_map(function (Cookie $cookie) {
+ return $cookie->toArray();
+ }, $this->all(null, null, null, true, true)));
+ }
+
+ /**
+ * Unserializes the cookie cookieJar
+ */
+ public function unserialize($data)
+ {
+ $data = json_decode($data, true);
+ if (empty($data)) {
+ $this->cookies = array();
+ } else {
+ $this->cookies = array_map(function (array $cookie) {
+ return new Cookie($cookie);
+ }, $data);
+ }
+ }
+
+ /**
+ * Returns the total number of stored cookies
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->cookies);
+ }
+
+ /**
+ * Returns an iterator
+ *
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->cookies);
+ }
+
+ public function addCookiesFromResponse(Response $response, RequestInterface $request = null)
+ {
+ if ($cookieHeader = $response->getHeader('Set-Cookie')) {
+ $parser = ParserRegistry::getInstance()->getParser('cookie');
+ foreach ($cookieHeader as $cookie) {
+ if ($parsed = $request
+ ? $parser->parseCookie($cookie, $request->getHost(), $request->getPath())
+ : $parser->parseCookie($cookie)
+ ) {
+ // Break up cookie v2 into multiple cookies
+ foreach ($parsed['cookies'] as $key => $value) {
+ $row = $parsed;
+ $row['name'] = $key;
+ $row['value'] = $value;
+ unset($row['cookies']);
+ $this->add(new Cookie($row));
+ }
+ }
+ }
+ }
+ }
+
+ public function getMatchingCookies(RequestInterface $request)
+ {
+ // Find cookies that match this request
+ $cookies = $this->all($request->getHost(), $request->getPath());
+ // Remove ineligible cookies
+ foreach ($cookies as $index => $cookie) {
+ if (!$cookie->matchesPort($request->getPort()) || ($cookie->getSecure() && $request->getScheme() != 'https')) {
+ unset($cookies[$index]);
+ }
+ };
+
+ return $cookies;
+ }
+
+ /**
+ * If a cookie already exists and the server asks to set it again with a null value, the
+ * cookie must be deleted.
+ *
+ * @param \Guzzle\Plugin\Cookie\Cookie $cookie
+ */
+ private function removeCookieIfEmpty(Cookie $cookie)
+ {
+ $cookieValue = $cookie->getValue();
+ if ($cookieValue === null || $cookieValue === '') {
+ $this->remove($cookie->getDomain(), $cookie->getPath(), $cookie->getName());
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php
new file mode 100755
index 0000000..7faa7d2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookieJar/CookieJarInterface.php
@@ -0,0 +1,85 @@
+filename = $cookieFile;
+ $this->load();
+ }
+
+ /**
+ * Saves the file when shutting down
+ */
+ public function __destruct()
+ {
+ $this->persist();
+ }
+
+ /**
+ * Save the contents of the data array to the file
+ *
+ * @throws RuntimeException if the file cannot be found or created
+ */
+ protected function persist()
+ {
+ if (false === file_put_contents($this->filename, $this->serialize())) {
+ // @codeCoverageIgnoreStart
+ throw new RuntimeException('Unable to open file ' . $this->filename);
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ /**
+ * Load the contents of the json formatted file into the data array and discard any unsaved state
+ */
+ protected function load()
+ {
+ $json = file_get_contents($this->filename);
+ if (false === $json) {
+ // @codeCoverageIgnoreStart
+ throw new RuntimeException('Unable to open file ' . $this->filename);
+ // @codeCoverageIgnoreEnd
+ }
+
+ $this->unserialize($json);
+ $this->cookies = $this->cookies ?: array();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php
new file mode 100755
index 0000000..df3210e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/CookiePlugin.php
@@ -0,0 +1,70 @@
+cookieJar = $cookieJar ?: new ArrayCookieJar();
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'request.before_send' => array('onRequestBeforeSend', 125),
+ 'request.sent' => array('onRequestSent', 125)
+ );
+ }
+
+ /**
+ * Get the cookie cookieJar
+ *
+ * @return CookieJarInterface
+ */
+ public function getCookieJar()
+ {
+ return $this->cookieJar;
+ }
+
+ /**
+ * Add cookies before a request is sent
+ *
+ * @param Event $event
+ */
+ public function onRequestBeforeSend(Event $event)
+ {
+ $request = $event['request'];
+ if (!$request->getParams()->get('cookies.disable')) {
+ $request->removeHeader('Cookie');
+ // Find cookies that match this request
+ foreach ($this->cookieJar->getMatchingCookies($request) as $cookie) {
+ $request->addCookie($cookie->getName(), $cookie->getValue());
+ }
+ }
+ }
+
+ /**
+ * Extract cookies from a sent request
+ *
+ * @param Event $event
+ */
+ public function onRequestSent(Event $event)
+ {
+ $this->cookieJar->addCookiesFromResponse($event['response'], $event['request']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php
new file mode 100755
index 0000000..b1fa6fd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Cookie/Exception/InvalidCookieException.php
@@ -0,0 +1,7 @@
+=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Cookie": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Cookie",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php
new file mode 100755
index 0000000..610e60c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/CurlAuthPlugin.php
@@ -0,0 +1,46 @@
+getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');
+ */
+class CurlAuthPlugin implements EventSubscriberInterface
+{
+ private $username;
+ private $password;
+ private $scheme;
+
+ /**
+ * @param string $username HTTP basic auth username
+ * @param string $password Password
+ * @param int $scheme Curl auth scheme
+ */
+ public function __construct($username, $password, $scheme=CURLAUTH_BASIC)
+ {
+ Version::warn(__CLASS__ . " is deprecated. Use \$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');");
+ $this->username = $username;
+ $this->password = $password;
+ $this->scheme = $scheme;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array('client.create_request' => array('onRequestCreate', 255));
+ }
+
+ /**
+ * Add basic auth
+ *
+ * @param Event $event
+ */
+ public function onRequestCreate(Event $event)
+ {
+ $event['request']->setAuth($this->username, $this->password, $this->scheme);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json
new file mode 100755
index 0000000..edc8b24
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/CurlAuth/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/plugin-curlauth",
+ "description": "Guzzle cURL authorization plugin",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["plugin", "curl", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\CurlAuth": "" }
+ },
+ "target-dir": "Guzzle/Plugin/CurlAuth",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php
new file mode 100755
index 0000000..5dce8bd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/ErrorResponseExceptionInterface.php
@@ -0,0 +1,22 @@
+ array('onCommandBeforeSend', -1));
+ }
+
+ /**
+ * Adds a listener to requests before they sent from a command
+ *
+ * @param Event $event Event emitted
+ */
+ public function onCommandBeforeSend(Event $event)
+ {
+ $command = $event['command'];
+ if ($operation = $command->getOperation()) {
+ if ($operation->getErrorResponses()) {
+ $request = $command->getRequest();
+ $request->getEventDispatcher()
+ ->addListener('request.complete', $this->getErrorClosure($request, $command, $operation));
+ }
+ }
+ }
+
+ /**
+ * @param RequestInterface $request Request that received an error
+ * @param CommandInterface $command Command that created the request
+ * @param Operation $operation Operation that defines the request and errors
+ *
+ * @return \Closure Returns a closure
+ * @throws ErrorResponseException
+ */
+ protected function getErrorClosure(RequestInterface $request, CommandInterface $command, Operation $operation)
+ {
+ return function (Event $event) use ($request, $command, $operation) {
+ $response = $event['response'];
+ foreach ($operation->getErrorResponses() as $error) {
+ if (!isset($error['class'])) {
+ continue;
+ }
+ if (isset($error['code']) && $response->getStatusCode() != $error['code']) {
+ continue;
+ }
+ if (isset($error['reason']) && $response->getReasonPhrase() != $error['reason']) {
+ continue;
+ }
+ $className = $error['class'];
+ $errorClassInterface = __NAMESPACE__ . '\\ErrorResponseExceptionInterface';
+ if (!class_exists($className)) {
+ throw new ErrorResponseException("{$className} does not exist");
+ } elseif (!(in_array($errorClassInterface, class_implements($className)))) {
+ throw new ErrorResponseException("{$className} must implement {$errorClassInterface}");
+ }
+ throw $className::fromCommand($command, $response);
+ }
+ };
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php
new file mode 100755
index 0000000..1d89e40
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/ErrorResponse/Exception/ErrorResponseException.php
@@ -0,0 +1,7 @@
+=5.3.2",
+ "guzzle/service": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\ErrorResponse": "" }
+ },
+ "target-dir": "Guzzle/Plugin/ErrorResponse",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php
new file mode 100755
index 0000000..7375e89
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/HistoryPlugin.php
@@ -0,0 +1,163 @@
+ array('onRequestSent', 9999));
+ }
+
+ /**
+ * Convert to a string that contains all request and response headers
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $lines = array();
+ foreach ($this->transactions as $entry) {
+ $response = isset($entry['response']) ? $entry['response'] : '';
+ $lines[] = '> ' . trim($entry['request']) . "\n\n< " . trim($response) . "\n";
+ }
+
+ return implode("\n", $lines);
+ }
+
+ /**
+ * Add a request to the history
+ *
+ * @param RequestInterface $request Request to add
+ * @param Response $response Response of the request
+ *
+ * @return HistoryPlugin
+ */
+ public function add(RequestInterface $request, Response $response = null)
+ {
+ if (!$response && $request->getResponse()) {
+ $response = $request->getResponse();
+ }
+
+ $this->transactions[] = array('request' => $request, 'response' => $response);
+ if (count($this->transactions) > $this->getlimit()) {
+ array_shift($this->transactions);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the max number of requests to store
+ *
+ * @param int $limit Limit
+ *
+ * @return HistoryPlugin
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = (int) $limit;
+
+ return $this;
+ }
+
+ /**
+ * Get the request limit
+ *
+ * @return int
+ */
+ public function getLimit()
+ {
+ return $this->limit;
+ }
+
+ /**
+ * Get all of the raw transactions in the form of an array of associative arrays containing
+ * 'request' and 'response' keys.
+ *
+ * @return array
+ */
+ public function getAll()
+ {
+ return $this->transactions;
+ }
+
+ /**
+ * Get the requests in the history
+ *
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ // Return an iterator just like the old iteration of the HistoryPlugin for BC compatibility (use getAll())
+ return new \ArrayIterator(array_map(function ($entry) {
+ $entry['request']->getParams()->set('actual_response', $entry['response']);
+ return $entry['request'];
+ }, $this->transactions));
+ }
+
+ /**
+ * Get the number of requests in the history
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->transactions);
+ }
+
+ /**
+ * Get the last request sent
+ *
+ * @return RequestInterface
+ */
+ public function getLastRequest()
+ {
+ $last = end($this->transactions);
+
+ return $last['request'];
+ }
+
+ /**
+ * Get the last response in the history
+ *
+ * @return Response|null
+ */
+ public function getLastResponse()
+ {
+ $last = end($this->transactions);
+
+ return isset($last['response']) ? $last['response'] : null;
+ }
+
+ /**
+ * Clears the history
+ *
+ * @return HistoryPlugin
+ */
+ public function clear()
+ {
+ $this->transactions = array();
+
+ return $this;
+ }
+
+ public function onRequestSent(Event $event)
+ {
+ $this->add($event['request'], $event['response']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json
new file mode 100755
index 0000000..ba0bf2c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/History/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/plugin-history",
+ "description": "Guzzle history plugin",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["plugin", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\History": "" }
+ },
+ "target-dir": "Guzzle/Plugin/History",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php
new file mode 100755
index 0000000..cabdea8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/LogPlugin.php
@@ -0,0 +1,161 @@
+logAdapter = $logAdapter;
+ $this->formatter = $formatter instanceof MessageFormatter ? $formatter : new MessageFormatter($formatter);
+ $this->wireBodies = $wireBodies;
+ }
+
+ /**
+ * Get a log plugin that outputs full request, response, and curl error information to stderr
+ *
+ * @param bool $wireBodies Set to false to disable request/response body output when they use are not repeatable
+ * @param resource $stream Stream to write to when logging. Defaults to STDERR when it is available
+ *
+ * @return self
+ */
+ public static function getDebugPlugin($wireBodies = true, $stream = null)
+ {
+ if ($stream === null) {
+ if (defined('STDERR')) {
+ $stream = STDERR;
+ } else {
+ $stream = fopen('php://output', 'w');
+ }
+ }
+
+ return new self(new ClosureLogAdapter(function ($m) use ($stream) {
+ fwrite($stream, $m . PHP_EOL);
+ }), "# Request:\n{request}\n\n# Response:\n{response}\n\n# Errors: {curl_code} {curl_error}", $wireBodies);
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'curl.callback.write' => array('onCurlWrite', 255),
+ 'curl.callback.read' => array('onCurlRead', 255),
+ 'request.before_send' => array('onRequestBeforeSend', 255),
+ 'request.sent' => array('onRequestSent', 255)
+ );
+ }
+
+ /**
+ * Event triggered when curl data is read from a request
+ *
+ * @param Event $event
+ */
+ public function onCurlRead(Event $event)
+ {
+ // Stream the request body to the log if the body is not repeatable
+ if ($wire = $event['request']->getParams()->get('request_wire')) {
+ $wire->write($event['read']);
+ }
+ }
+
+ /**
+ * Event triggered when curl data is written to a response
+ *
+ * @param Event $event
+ */
+ public function onCurlWrite(Event $event)
+ {
+ // Stream the response body to the log if the body is not repeatable
+ if ($wire = $event['request']->getParams()->get('response_wire')) {
+ $wire->write($event['write']);
+ }
+ }
+
+ /**
+ * Called before a request is sent
+ *
+ * @param Event $event
+ */
+ public function onRequestBeforeSend(Event $event)
+ {
+ if ($this->wireBodies) {
+ $request = $event['request'];
+ // Ensure that curl IO events are emitted
+ $request->getCurlOptions()->set('emit_io', true);
+ // We need to make special handling for content wiring and non-repeatable streams.
+ if ($request instanceof EntityEnclosingRequestInterface && $request->getBody()
+ && (!$request->getBody()->isSeekable() || !$request->getBody()->isReadable())
+ ) {
+ // The body of the request cannot be recalled so logging the body will require us to buffer it
+ $request->getParams()->set('request_wire', EntityBody::factory());
+ }
+ if (!$request->getResponseBody()->isRepeatable()) {
+ // The body of the response cannot be recalled so logging the body will require us to buffer it
+ $request->getParams()->set('response_wire', EntityBody::factory());
+ }
+ }
+ }
+
+ /**
+ * Triggers the actual log write when a request completes
+ *
+ * @param Event $event
+ */
+ public function onRequestSent(Event $event)
+ {
+ $request = $event['request'];
+ $response = $event['response'];
+ $handle = $event['handle'];
+
+ if ($wire = $request->getParams()->get('request_wire')) {
+ $request = clone $request;
+ $request->setBody($wire);
+ }
+
+ if ($wire = $request->getParams()->get('response_wire')) {
+ $response = clone $response;
+ $response->setBody($wire);
+ }
+
+ // Send the log message to the adapter, adding a category and host
+ $priority = $response && $response->isError() ? LOG_ERR : LOG_DEBUG;
+ $message = $this->formatter->format($request, $response, $handle);
+ $this->logAdapter->log($message, $priority, array(
+ 'request' => $request,
+ 'response' => $response,
+ 'handle' => $handle
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json
new file mode 100755
index 0000000..130e6da
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Log/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "guzzle/plugin-log",
+ "description": "Guzzle log plugin for over the wire logging",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["plugin", "log", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version",
+ "guzzle/log": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Log": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Log",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php
new file mode 100755
index 0000000..8512424
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/CommandContentMd5Plugin.php
@@ -0,0 +1,57 @@
+contentMd5Param = $contentMd5Param;
+ $this->validateMd5Param = $validateMd5Param;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array('command.before_send' => array('onCommandBeforeSend', -255));
+ }
+
+ public function onCommandBeforeSend(Event $event)
+ {
+ $command = $event['command'];
+ $request = $command->getRequest();
+
+ // Only add an MD5 is there is a MD5 option on the operation and it has a payload
+ if ($request instanceof EntityEnclosingRequestInterface && $request->getBody()
+ && $command->getOperation()->hasParam($this->contentMd5Param)) {
+ // Check if an MD5 checksum value should be passed along to the request
+ if ($command[$this->contentMd5Param] === true) {
+ if (false !== ($md5 = $request->getBody()->getContentMd5(true, true))) {
+ $request->setHeader('Content-MD5', $md5);
+ }
+ }
+ }
+
+ // Check if MD5 validation should be used with the response
+ if ($command[$this->validateMd5Param] === true) {
+ $request->addSubscriber(new Md5ValidatorPlugin(true, false));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php
new file mode 100755
index 0000000..5d7a378
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/Md5ValidatorPlugin.php
@@ -0,0 +1,88 @@
+contentLengthCutoff = $contentLengthCutoff;
+ $this->contentEncoded = $contentEncoded;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array('request.complete' => array('onRequestComplete', 255));
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws UnexpectedValueException
+ */
+ public function onRequestComplete(Event $event)
+ {
+ $response = $event['response'];
+
+ if (!$contentMd5 = $response->getContentMd5()) {
+ return;
+ }
+
+ $contentEncoding = $response->getContentEncoding();
+ if ($contentEncoding && !$this->contentEncoded) {
+ return false;
+ }
+
+ // Make sure that the size of the request is under the cutoff size
+ if ($this->contentLengthCutoff) {
+ $size = $response->getContentLength() ?: $response->getBody()->getSize();
+ if (!$size || $size > $this->contentLengthCutoff) {
+ return;
+ }
+ }
+
+ if (!$contentEncoding) {
+ $hash = $response->getBody()->getContentMd5();
+ } elseif ($contentEncoding == 'gzip') {
+ $response->getBody()->compress('zlib.deflate');
+ $hash = $response->getBody()->getContentMd5();
+ $response->getBody()->uncompress();
+ } elseif ($contentEncoding == 'compress') {
+ $response->getBody()->compress('bzip2.compress');
+ $hash = $response->getBody()->getContentMd5();
+ $response->getBody()->uncompress();
+ } else {
+ return;
+ }
+
+ if ($contentMd5 !== $hash) {
+ throw new UnexpectedValueException(
+ "The response entity body may have been modified over the wire. The Content-MD5 "
+ . "received ({$contentMd5}) did not match the calculated MD5 hash ({$hash})."
+ );
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json
new file mode 100755
index 0000000..0602d06
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Md5/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/plugin-md5",
+ "description": "Guzzle MD5 plugins",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["plugin", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Md5": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Md5",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php
new file mode 100755
index 0000000..2440578
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/MockPlugin.php
@@ -0,0 +1,245 @@
+readBodies = $readBodies;
+ $this->temporary = $temporary;
+ if ($items) {
+ foreach ($items as $item) {
+ if ($item instanceof \Exception) {
+ $this->addException($item);
+ } else {
+ $this->addResponse($item);
+ }
+ }
+ }
+ }
+
+ public static function getSubscribedEvents()
+ {
+ // Use a number lower than the CachePlugin
+ return array('request.before_send' => array('onRequestBeforeSend', -999));
+ }
+
+ public static function getAllEvents()
+ {
+ return array('mock.request');
+ }
+
+ /**
+ * Get a mock response from a file
+ *
+ * @param string $path File to retrieve a mock response from
+ *
+ * @return Response
+ * @throws InvalidArgumentException if the file is not found
+ */
+ public static function getMockFile($path)
+ {
+ if (!file_exists($path)) {
+ throw new InvalidArgumentException('Unable to open mock file: ' . $path);
+ }
+
+ return Response::fromMessage(file_get_contents($path));
+ }
+
+ /**
+ * Set whether or not to consume the entity body of a request when a mock
+ * response is used
+ *
+ * @param bool $readBodies Set to true to read and consume entity bodies
+ *
+ * @return self
+ */
+ public function readBodies($readBodies)
+ {
+ $this->readBodies = $readBodies;
+
+ return $this;
+ }
+
+ /**
+ * Returns the number of remaining mock responses
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->queue);
+ }
+
+ /**
+ * Add a response to the end of the queue
+ *
+ * @param string|Response $response Response object or path to response file
+ *
+ * @return MockPlugin
+ * @throws InvalidArgumentException if a string or Response is not passed
+ */
+ public function addResponse($response)
+ {
+ if (!($response instanceof Response)) {
+ if (!is_string($response)) {
+ throw new InvalidArgumentException('Invalid response');
+ }
+ $response = self::getMockFile($response);
+ }
+
+ $this->queue[] = $response;
+
+ return $this;
+ }
+
+ /**
+ * Add an exception to the end of the queue
+ *
+ * @param CurlException $e Exception to throw when the request is executed
+ *
+ * @return MockPlugin
+ */
+ public function addException(CurlException $e)
+ {
+ $this->queue[] = $e;
+
+ return $this;
+ }
+
+ /**
+ * Clear the queue
+ *
+ * @return MockPlugin
+ */
+ public function clearQueue()
+ {
+ $this->queue = array();
+
+ return $this;
+ }
+
+ /**
+ * Returns an array of mock responses remaining in the queue
+ *
+ * @return array
+ */
+ public function getQueue()
+ {
+ return $this->queue;
+ }
+
+ /**
+ * Check if this is a temporary plugin
+ *
+ * @return bool
+ */
+ public function isTemporary()
+ {
+ return $this->temporary;
+ }
+
+ /**
+ * Get a response from the front of the list and add it to a request
+ *
+ * @param RequestInterface $request Request to mock
+ *
+ * @return self
+ * @throws CurlException When request.send is called and an exception is queued
+ */
+ public function dequeue(RequestInterface $request)
+ {
+ $this->dispatch('mock.request', array('plugin' => $this, 'request' => $request));
+
+ $item = array_shift($this->queue);
+ if ($item instanceof Response) {
+ if ($this->readBodies && $request instanceof EntityEnclosingRequestInterface) {
+ $request->getEventDispatcher()->addListener('request.sent', $f = function (Event $event) use (&$f) {
+ while ($data = $event['request']->getBody()->read(8096));
+ // Remove the listener after one-time use
+ $event['request']->getEventDispatcher()->removeListener('request.sent', $f);
+ });
+ }
+ $request->setResponse($item);
+ } elseif ($item instanceof CurlException) {
+ // Emulates exceptions encountered while transferring requests
+ $item->setRequest($request);
+ $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $item));
+ // Only throw if the exception wasn't handled
+ if ($state == RequestInterface::STATE_ERROR) {
+ throw $item;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Clear the array of received requests
+ */
+ public function flush()
+ {
+ $this->received = array();
+ }
+
+ /**
+ * Get an array of requests that were mocked by this plugin
+ *
+ * @return array
+ */
+ public function getReceivedRequests()
+ {
+ return $this->received;
+ }
+
+ /**
+ * Called when a request is about to be sent
+ *
+ * @param Event $event
+ * @throws \OutOfBoundsException When queue is empty
+ */
+ public function onRequestBeforeSend(Event $event)
+ {
+ if (!$this->queue) {
+ throw new \OutOfBoundsException('Mock queue is empty');
+ }
+
+ $request = $event['request'];
+ $this->received[] = $request;
+ // Detach the filter from the client so it's a one-time use
+ if ($this->temporary && count($this->queue) == 1 && $request->getClient()) {
+ $request->getClient()->getEventDispatcher()->removeSubscriber($this);
+ }
+ $this->dequeue($request);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json
new file mode 100755
index 0000000..f8201e3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Mock/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/plugin-mock",
+ "description": "Guzzle Mock plugin",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["mock", "plugin", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Mock": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Mock",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php
new file mode 100755
index 0000000..95e0c3e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/OauthPlugin.php
@@ -0,0 +1,306 @@
+config = Collection::fromConfig($config, array(
+ 'version' => '1.0',
+ 'request_method' => self::REQUEST_METHOD_HEADER,
+ 'consumer_key' => 'anonymous',
+ 'consumer_secret' => 'anonymous',
+ 'signature_method' => 'HMAC-SHA1',
+ 'signature_callback' => function($stringToSign, $key) {
+ return hash_hmac('sha1', $stringToSign, $key, true);
+ }
+ ), array(
+ 'signature_method', 'signature_callback', 'version',
+ 'consumer_key', 'consumer_secret'
+ ));
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'request.before_send' => array('onRequestBeforeSend', -1000)
+ );
+ }
+
+ /**
+ * Request before-send event handler
+ *
+ * @param Event $event Event received
+ * @return array
+ * @throws \InvalidArgumentException
+ */
+ public function onRequestBeforeSend(Event $event)
+ {
+ $timestamp = $this->getTimestamp($event);
+ $request = $event['request'];
+ $nonce = $this->generateNonce($request);
+ $authorizationParams = $this->getOauthParams($timestamp, $nonce);
+ $authorizationParams['oauth_signature'] = $this->getSignature($request, $timestamp, $nonce);
+
+ switch ($this->config['request_method']) {
+ case self::REQUEST_METHOD_HEADER:
+ $request->setHeader(
+ 'Authorization',
+ $this->buildAuthorizationHeader($authorizationParams)
+ );
+ break;
+ case self::REQUEST_METHOD_QUERY:
+ foreach ($authorizationParams as $key => $value) {
+ $request->getQuery()->set($key, $value);
+ }
+ break;
+ default:
+ throw new \InvalidArgumentException(sprintf(
+ 'Invalid consumer method "%s"',
+ $this->config['request_method']
+ ));
+ }
+
+ return $authorizationParams;
+ }
+
+ /**
+ * Builds the Authorization header for a request
+ *
+ * @param array $authorizationParams Associative array of authorization parameters
+ *
+ * @return string
+ */
+ private function buildAuthorizationHeader($authorizationParams)
+ {
+ $authorizationString = 'OAuth ';
+ foreach ($authorizationParams as $key => $val) {
+ if ($val) {
+ $authorizationString .= $key . '="' . urlencode($val) . '", ';
+ }
+ }
+
+ return substr($authorizationString, 0, -2);
+ }
+
+ /**
+ * Calculate signature for request
+ *
+ * @param RequestInterface $request Request to generate a signature for
+ * @param integer $timestamp Timestamp to use for nonce
+ * @param string $nonce
+ *
+ * @return string
+ */
+ public function getSignature(RequestInterface $request, $timestamp, $nonce)
+ {
+ $string = $this->getStringToSign($request, $timestamp, $nonce);
+ $key = urlencode($this->config['consumer_secret']) . '&' . urlencode($this->config['token_secret']);
+
+ return base64_encode(call_user_func($this->config['signature_callback'], $string, $key));
+ }
+
+ /**
+ * Calculate string to sign
+ *
+ * @param RequestInterface $request Request to generate a signature for
+ * @param int $timestamp Timestamp to use for nonce
+ * @param string $nonce
+ *
+ * @return string
+ */
+ public function getStringToSign(RequestInterface $request, $timestamp, $nonce)
+ {
+ $params = $this->getParamsToSign($request, $timestamp, $nonce);
+
+ // Convert booleans to strings.
+ $params = $this->prepareParameters($params);
+
+ // Build signing string from combined params
+ $parameterString = clone $request->getQuery();
+ $parameterString->replace($params);
+
+ $url = Url::factory($request->getUrl())->setQuery('')->setFragment(null);
+
+ return strtoupper($request->getMethod()) . '&'
+ . rawurlencode($url) . '&'
+ . rawurlencode((string) $parameterString);
+ }
+
+ /**
+ * Get the oauth parameters as named by the oauth spec
+ *
+ * @param $timestamp
+ * @param $nonce
+ * @return Collection
+ */
+ protected function getOauthParams($timestamp, $nonce)
+ {
+ $params = new Collection(array(
+ 'oauth_consumer_key' => $this->config['consumer_key'],
+ 'oauth_nonce' => $nonce,
+ 'oauth_signature_method' => $this->config['signature_method'],
+ 'oauth_timestamp' => $timestamp,
+ ));
+
+ // Optional parameters should not be set if they have not been set in the config as
+ // the parameter may be considered invalid by the Oauth service.
+ $optionalParams = array(
+ 'callback' => 'oauth_callback',
+ 'token' => 'oauth_token',
+ 'verifier' => 'oauth_verifier',
+ 'version' => 'oauth_version'
+ );
+
+ foreach ($optionalParams as $optionName => $oauthName) {
+ if (isset($this->config[$optionName]) == true) {
+ $params[$oauthName] = $this->config[$optionName];
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Get all of the parameters required to sign a request including:
+ * * The oauth params
+ * * The request GET params
+ * * The params passed in the POST body (with a content-type of application/x-www-form-urlencoded)
+ *
+ * @param RequestInterface $request Request to generate a signature for
+ * @param integer $timestamp Timestamp to use for nonce
+ * @param string $nonce
+ *
+ * @return array
+ */
+ public function getParamsToSign(RequestInterface $request, $timestamp, $nonce)
+ {
+ $params = $this->getOauthParams($timestamp, $nonce);
+
+ // Add query string parameters
+ $params->merge($request->getQuery());
+
+ // Add POST fields to signing string if required
+ if ($this->shouldPostFieldsBeSigned($request))
+ {
+ $params->merge($request->getPostFields());
+ }
+
+ // Sort params
+ $params = $params->toArray();
+ uksort($params, 'strcmp');
+
+ return $params;
+ }
+
+ /**
+ * Decide whether the post fields should be added to the base string that Oauth signs.
+ * This implementation is correct. Non-conformant APIs may require that this method be
+ * overwritten e.g. the Flickr API incorrectly adds the post fields when the Content-Type
+ * is 'application/x-www-form-urlencoded'
+ *
+ * @param $request
+ * @return bool Whether the post fields should be signed or not
+ */
+ public function shouldPostFieldsBeSigned($request)
+ {
+ if (!$this->config->get('disable_post_params') &&
+ $request instanceof EntityEnclosingRequestInterface &&
+ false !== strpos($request->getHeader('Content-Type'), 'application/x-www-form-urlencoded'))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a Nonce Based on the unique id and URL. This will allow for multiple requests in parallel with the same
+ * exact timestamp to use separate nonce's.
+ *
+ * @param RequestInterface $request Request to generate a nonce for
+ *
+ * @return string
+ */
+ public function generateNonce(RequestInterface $request)
+ {
+ return sha1(uniqid('', true) . $request->getUrl());
+ }
+
+ /**
+ * Gets timestamp from event or create new timestamp
+ *
+ * @param Event $event Event containing contextual information
+ *
+ * @return int
+ */
+ public function getTimestamp(Event $event)
+ {
+ return $event['timestamp'] ?: time();
+ }
+
+ /**
+ * Convert booleans to strings, removed unset parameters, and sorts the array
+ *
+ * @param array $data Data array
+ *
+ * @return array
+ */
+ protected function prepareParameters($data)
+ {
+ ksort($data);
+ foreach ($data as $key => &$value) {
+ switch (gettype($value)) {
+ case 'NULL':
+ unset($data[$key]);
+ break;
+ case 'array':
+ $data[$key] = self::prepareParameters($value);
+ break;
+ case 'boolean':
+ $data[$key] = $value ? 'true' : 'false';
+ break;
+ }
+ }
+
+ return $data;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json
new file mode 100755
index 0000000..c9766ba
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/Oauth/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "guzzle/plugin-oauth",
+ "description": "Guzzle OAuth plugin",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["oauth", "plugin", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin\\Oauth": "" }
+ },
+ "target-dir": "Guzzle/Plugin/Oauth",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json
new file mode 100755
index 0000000..2bbe64c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Plugin/composer.json
@@ -0,0 +1,44 @@
+{
+ "name": "guzzle/plugin",
+ "description": "Guzzle plugin component containing all Guzzle HTTP plugins",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": ["http", "client", "plugin", "extension", "guzzle"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2",
+ "guzzle/http": "self.version"
+ },
+ "suggest": {
+ "guzzle/cache": "self.version",
+ "guzzle/log": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Plugin": "" }
+ },
+ "target-dir": "Guzzle/Plugin",
+ "replace": {
+ "guzzle/plugin-async": "self.version",
+ "guzzle/plugin-backoff": "self.version",
+ "guzzle/plugin-cache": "self.version",
+ "guzzle/plugin-cookie": "self.version",
+ "guzzle/plugin-curlauth": "self.version",
+ "guzzle/plugin-error-response": "self.version",
+ "guzzle/plugin-history": "self.version",
+ "guzzle/plugin-log": "self.version",
+ "guzzle/plugin-md5": "self.version",
+ "guzzle/plugin-mock": "self.version",
+ "guzzle/plugin-oauth": "self.version"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php
new file mode 100755
index 0000000..cd06f57
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/AbstractConfigLoader.php
@@ -0,0 +1,177 @@
+ 'JSON_ERROR_NONE - No errors',
+ JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
+ JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
+ JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
+ JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
+ JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
+ );
+
+ public function load($config, array $options = array())
+ {
+ // Reset the array of loaded files because this is a new config
+ $this->loadedFiles = array();
+
+ if (is_string($config)) {
+ $config = $this->loadFile($config);
+ } elseif (!is_array($config)) {
+ throw new InvalidArgumentException('Unknown type passed to configuration loader: ' . gettype($config));
+ } else {
+ $this->mergeIncludes($config);
+ }
+
+ return $this->build($config, $options);
+ }
+
+ /**
+ * Add an include alias to the loader
+ *
+ * @param string $filename Filename to alias (e.g. _foo)
+ * @param string $alias Actual file to use (e.g. /path/to/foo.json)
+ *
+ * @return self
+ */
+ public function addAlias($filename, $alias)
+ {
+ $this->aliases[$filename] = $alias;
+
+ return $this;
+ }
+
+ /**
+ * Remove an alias from the loader
+ *
+ * @param string $alias Alias to remove
+ *
+ * @return self
+ */
+ public function removeAlias($alias)
+ {
+ unset($this->aliases[$alias]);
+
+ return $this;
+ }
+
+ /**
+ * Perform the parsing of a config file and create the end result
+ *
+ * @param array $config Configuration data
+ * @param array $options Options to use when building
+ *
+ * @return mixed
+ */
+ protected abstract function build($config, array $options);
+
+ /**
+ * Load a configuration file (can load JSON or PHP files that return an array when included)
+ *
+ * @param string $filename File to load
+ *
+ * @return array
+ * @throws InvalidArgumentException
+ * @throws RuntimeException when the JSON cannot be parsed
+ */
+ protected function loadFile($filename)
+ {
+ if (isset($this->aliases[$filename])) {
+ $filename = $this->aliases[$filename];
+ }
+
+ switch (pathinfo($filename, PATHINFO_EXTENSION)) {
+ case 'js':
+ case 'json':
+ $level = error_reporting(0);
+ $json = file_get_contents($filename);
+ error_reporting($level);
+
+ if ($json === false) {
+ $err = error_get_last();
+ throw new InvalidArgumentException("Unable to open {$filename}: " . $err['message']);
+ }
+
+ $config = json_decode($json, true);
+ // Throw an exception if there was an error loading the file
+ if ($error = json_last_error()) {
+ $message = isset(self::$jsonErrors[$error]) ? self::$jsonErrors[$error] : 'Unknown error';
+ throw new RuntimeException("Error loading JSON data from {$filename}: ({$error}) - {$message}");
+ }
+ break;
+ case 'php':
+ if (!is_readable($filename)) {
+ throw new InvalidArgumentException("Unable to open {$filename} for reading");
+ }
+ $config = require $filename;
+ if (!is_array($config)) {
+ throw new InvalidArgumentException('PHP files must return an array of configuration data');
+ }
+ break;
+ default:
+ throw new InvalidArgumentException('Unknown file extension: ' . $filename);
+ }
+
+ // Keep track of this file being loaded to prevent infinite recursion
+ $this->loadedFiles[$filename] = true;
+
+ // Merge include files into the configuration array
+ $this->mergeIncludes($config, dirname($filename));
+
+ return $config;
+ }
+
+ /**
+ * Merges in all include files
+ *
+ * @param array $config Config data that contains includes
+ * @param string $basePath Base path to use when a relative path is encountered
+ *
+ * @return array Returns the merged and included data
+ */
+ protected function mergeIncludes(&$config, $basePath = null)
+ {
+ if (!empty($config['includes'])) {
+ foreach ($config['includes'] as &$path) {
+ // Account for relative paths
+ if ($path[0] != DIRECTORY_SEPARATOR && !isset($this->aliases[$path]) && $basePath) {
+ $path = "{$basePath}/{$path}";
+ }
+ // Don't load the same files more than once
+ if (!isset($this->loadedFiles[$path])) {
+ $this->loadedFiles[$path] = true;
+ $config = $this->mergeData($this->loadFile($path), $config);
+ }
+ }
+ }
+ }
+
+ /**
+ * Default implementation for merging two arrays of data (uses array_merge_recursive)
+ *
+ * @param array $a Original data
+ * @param array $b Data to merge into the original and overwrite existing values
+ *
+ * @return array
+ */
+ protected function mergeData(array $a, array $b)
+ {
+ return array_merge_recursive($a, $b);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php
new file mode 100755
index 0000000..38150db
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilder.php
@@ -0,0 +1,189 @@
+load($config, $globalParameters);
+ }
+
+ /**
+ * @param array $serviceBuilderConfig Service configuration settings:
+ * - name: Name of the service
+ * - class: Client class to instantiate using a factory method
+ * - params: array of key value pair configuration settings for the builder
+ */
+ public function __construct(array $serviceBuilderConfig = array())
+ {
+ $this->builderConfig = $serviceBuilderConfig;
+ }
+
+ public static function getAllEvents()
+ {
+ return array('service_builder.create_client');
+ }
+
+ public function unserialize($serialized)
+ {
+ $this->builderConfig = json_decode($serialized, true);
+ }
+
+ public function serialize()
+ {
+ return json_encode($this->builderConfig);
+ }
+
+ /**
+ * Attach a plugin to every client created by the builder
+ *
+ * @param EventSubscriberInterface $plugin Plugin to attach to each client
+ *
+ * @return self
+ */
+ public function addGlobalPlugin(EventSubscriberInterface $plugin)
+ {
+ $this->plugins[] = $plugin;
+
+ return $this;
+ }
+
+ /**
+ * Get data from the service builder without triggering the building of a service
+ *
+ * @param string $name Name of the service to retrieve
+ *
+ * @return array|null
+ */
+ public function getData($name)
+ {
+ return isset($this->builderConfig[$name]) ? $this->builderConfig[$name] : null;
+ }
+
+ public function get($name, $throwAway = false)
+ {
+ if (!isset($this->builderConfig[$name])) {
+
+ // Check to see if arbitrary data is being referenced
+ if (isset($this->clients[$name])) {
+ return $this->clients[$name];
+ }
+
+ // Check aliases and return a match if found
+ foreach ($this->builderConfig as $actualName => $config) {
+ if (isset($config['alias']) && $config['alias'] == $name) {
+ return $this->get($actualName, $throwAway);
+ }
+ }
+ throw new ServiceNotFoundException('No service is registered as ' . $name);
+ }
+
+ if (!$throwAway && isset($this->clients[$name])) {
+ return $this->clients[$name];
+ }
+
+ $builder =& $this->builderConfig[$name];
+
+ // Convert references to the actual client
+ foreach ($builder['params'] as &$v) {
+ if (is_string($v) && substr($v, 0, 1) == '{' && substr($v, -1) == '}') {
+ $v = $this->get(trim($v, '{} '));
+ }
+ }
+
+ // Get the configured parameters and merge in any parameters provided for throw-away clients
+ $config = $builder['params'];
+ if (is_array($throwAway)) {
+ $config = $throwAway + $config;
+ }
+
+ $client = $builder['class']::factory($config);
+
+ if (!$throwAway) {
+ $this->clients[$name] = $client;
+ }
+
+ if ($client instanceof ClientInterface) {
+ foreach ($this->plugins as $plugin) {
+ $client->addSubscriber($plugin);
+ }
+ // Dispatch an event letting listeners know a client was created
+ $this->dispatch('service_builder.create_client', array('client' => $client));
+ }
+
+ return $client;
+ }
+
+ public function set($key, $service)
+ {
+ if (is_array($service) && isset($service['class']) && isset($service['params'])) {
+ $this->builderConfig[$key] = $service;
+ } else {
+ $this->clients[$key] = $service;
+ }
+
+ return $this;
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->set($offset, $value);
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->builderConfig[$offset]);
+ unset($this->clients[$offset]);
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->builderConfig[$offset]) || isset($this->clients[$offset]);
+ }
+
+ public function offsetGet($offset)
+ {
+ return $this->get($offset);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php
new file mode 100755
index 0000000..4fc310a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Builder/ServiceBuilderInterface.php
@@ -0,0 +1,40 @@
+ &$service) {
+
+ $service['params'] = isset($service['params']) ? $service['params'] : array();
+
+ // Check if this client builder extends another client
+ if (!empty($service['extends'])) {
+
+ // Make sure that the service it's extending has been defined
+ if (!isset($services[$service['extends']])) {
+ throw new ServiceNotFoundException(
+ "{$name} is trying to extend a non-existent service: {$service['extends']}"
+ );
+ }
+
+ $extended = &$services[$service['extends']];
+
+ // Use the correct class attribute
+ if (empty($service['class'])) {
+ $service['class'] = isset($extended['class']) ? $extended['class'] : '';
+ }
+ if ($extendsParams = isset($extended['params']) ? $extended['params'] : false) {
+ $service['params'] = $service['params'] + $extendsParams;
+ }
+ }
+
+ // Overwrite default values with global parameter values
+ if (!empty($options)) {
+ $service['params'] = $options + $service['params'];
+ }
+
+ $service['class'] = isset($service['class']) ? $service['class'] : '';
+ }
+
+ return new $class($services);
+ }
+
+ protected function mergeData(array $a, array $b)
+ {
+ $result = $b + $a;
+
+ // Merge services using a recursive union of arrays
+ if (isset($a['services']) && $b['services']) {
+
+ // Get a union of the services of the two arrays
+ $result['services'] = $b['services'] + $a['services'];
+
+ // Merge each service in using a union of the two arrays
+ foreach ($result['services'] as $name => &$service) {
+
+ // By default, services completely override a previously defined service unless it extends itself
+ if (isset($a['services'][$name]['extends'])
+ && isset($b['services'][$name]['extends'])
+ && $b['services'][$name]['extends'] == $name
+ ) {
+ $service += $a['services'][$name];
+ // Use the `extends` attribute of the parent
+ $service['extends'] = $a['services'][$name]['extends'];
+ // Merge parameters using a union if both have parameters
+ if (isset($a['services'][$name]['params'])) {
+ $service['params'] += $a['services'][$name]['params'];
+ }
+ }
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php
new file mode 100755
index 0000000..26f8360
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/CachingConfigLoader.php
@@ -0,0 +1,46 @@
+loader = $loader;
+ $this->cache = $cache;
+ }
+
+ public function load($config, array $options = array())
+ {
+ if (!is_string($config)) {
+ $key = false;
+ } else {
+ $key = 'loader_' . crc32($config);
+ if ($result = $this->cache->fetch($key)) {
+ return $result;
+ }
+ }
+
+ $result = $this->loader->load($config, $options);
+ if ($key) {
+ $this->cache->save($key, $result);
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Client.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Client.php
new file mode 100755
index 0000000..3e5f8e5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Client.php
@@ -0,0 +1,297 @@
+getCommand($method, isset($args[0]) ? $args[0] : array())->getResult();
+ }
+
+ public function getCommand($name, array $args = array())
+ {
+ // Add global client options to the command
+ if ($options = $this->getConfig(self::COMMAND_PARAMS)) {
+ $args += $options;
+ }
+
+ if (!($command = $this->getCommandFactory()->factory($name, $args))) {
+ throw new InvalidArgumentException("Command was not found matching {$name}");
+ }
+
+ $command->setClient($this);
+ $this->dispatch('client.command.create', array('client' => $this, 'command' => $command));
+
+ return $command;
+ }
+
+ /**
+ * Set the command factory used to create commands by name
+ *
+ * @param CommandFactoryInterface $factory Command factory
+ *
+ * @return self
+ */
+ public function setCommandFactory(CommandFactoryInterface $factory)
+ {
+ $this->commandFactory = $factory;
+
+ return $this;
+ }
+
+ /**
+ * Set the resource iterator factory associated with the client
+ *
+ * @param ResourceIteratorFactoryInterface $factory Resource iterator factory
+ *
+ * @return self
+ */
+ public function setResourceIteratorFactory(ResourceIteratorFactoryInterface $factory)
+ {
+ $this->resourceIteratorFactory = $factory;
+
+ return $this;
+ }
+
+ public function getIterator($command, array $commandOptions = null, array $iteratorOptions = array())
+ {
+ if (!($command instanceof CommandInterface)) {
+ $command = $this->getCommand($command, $commandOptions ?: array());
+ }
+
+ return $this->getResourceIteratorFactory()->build($command, $iteratorOptions);
+ }
+
+ public function execute($command)
+ {
+ if ($command instanceof CommandInterface) {
+ $this->send($this->prepareCommand($command));
+ $this->dispatch('command.after_send', array('command' => $command));
+ return $command->getResult();
+ } elseif (is_array($command) || $command instanceof \Traversable) {
+ return $this->executeMultiple($command);
+ } else {
+ throw new InvalidArgumentException('Command must be a command or array of commands');
+ }
+ }
+
+ public function setDescription(ServiceDescriptionInterface $service)
+ {
+ $this->serviceDescription = $service;
+
+ if ($this->getCommandFactory() && $this->getCommandFactory() instanceof CompositeFactory) {
+ $this->commandFactory->add(new Command\Factory\ServiceDescriptionFactory($service));
+ }
+
+ // If a baseUrl was set on the description, then update the client
+ if ($baseUrl = $service->getBaseUrl()) {
+ $this->setBaseUrl($baseUrl);
+ }
+
+ return $this;
+ }
+
+ public function getDescription()
+ {
+ return $this->serviceDescription;
+ }
+
+ /**
+ * Set the inflector used with the client
+ *
+ * @param InflectorInterface $inflector Inflection object
+ *
+ * @return self
+ */
+ public function setInflector(InflectorInterface $inflector)
+ {
+ $this->inflector = $inflector;
+
+ return $this;
+ }
+
+ /**
+ * Get the inflector used with the client
+ *
+ * @return self
+ */
+ public function getInflector()
+ {
+ if (!$this->inflector) {
+ $this->inflector = Inflector::getDefault();
+ }
+
+ return $this->inflector;
+ }
+
+ /**
+ * Prepare a command for sending and get the RequestInterface object created by the command
+ *
+ * @param CommandInterface $command Command to prepare
+ *
+ * @return RequestInterface
+ */
+ protected function prepareCommand(CommandInterface $command)
+ {
+ // Set the client and prepare the command
+ $request = $command->setClient($this)->prepare();
+ // Set the state to new if the command was previously executed
+ $request->setState(RequestInterface::STATE_NEW);
+ $this->dispatch('command.before_send', array('command' => $command));
+
+ return $request;
+ }
+
+ /**
+ * Execute multiple commands in parallel
+ *
+ * @param array|Traversable $commands Array of CommandInterface objects to execute
+ *
+ * @return array Returns an array of the executed commands
+ * @throws Exception\CommandTransferException
+ */
+ protected function executeMultiple($commands)
+ {
+ $requests = array();
+ $commandRequests = new \SplObjectStorage();
+
+ foreach ($commands as $command) {
+ $request = $this->prepareCommand($command);
+ $commandRequests[$request] = $command;
+ $requests[] = $request;
+ }
+
+ try {
+ $this->send($requests);
+ foreach ($commands as $command) {
+ $this->dispatch('command.after_send', array('command' => $command));
+ }
+ return $commands;
+ } catch (MultiTransferException $failureException) {
+ // Throw a CommandTransferException using the successful and failed commands
+ $e = CommandTransferException::fromMultiTransferException($failureException);
+
+ // Remove failed requests from the successful requests array and add to the failures array
+ foreach ($failureException->getFailedRequests() as $request) {
+ if (isset($commandRequests[$request])) {
+ $e->addFailedCommand($commandRequests[$request]);
+ unset($commandRequests[$request]);
+ }
+ }
+
+ // Always emit the command after_send events for successful commands
+ foreach ($commandRequests as $success) {
+ $e->addSuccessfulCommand($commandRequests[$success]);
+ $this->dispatch('command.after_send', array('command' => $commandRequests[$success]));
+ }
+
+ throw $e;
+ }
+ }
+
+ protected function getResourceIteratorFactory()
+ {
+ if (!$this->resourceIteratorFactory) {
+ // Build the default resource iterator factory if one is not set
+ $clientClass = get_class($this);
+ $prefix = substr($clientClass, 0, strrpos($clientClass, '\\'));
+ $this->resourceIteratorFactory = new ResourceIteratorClassFactory(array(
+ "{$prefix}\\Iterator",
+ "{$prefix}\\Model"
+ ));
+ }
+
+ return $this->resourceIteratorFactory;
+ }
+
+ /**
+ * Get the command factory associated with the client
+ *
+ * @return CommandFactoryInterface
+ */
+ protected function getCommandFactory()
+ {
+ if (!$this->commandFactory) {
+ $this->commandFactory = CompositeFactory::getDefaultChain($this);
+ }
+
+ return $this->commandFactory;
+ }
+
+ /**
+ * @deprecated
+ * @codeCoverageIgnore
+ */
+ public function enableMagicMethods($isEnabled)
+ {
+ Version::warn(__METHOD__ . ' is deprecated');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php
new file mode 100755
index 0000000..814154f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/ClientInterface.php
@@ -0,0 +1,68 @@
+operation = $operation ?: $this->createOperation();
+ foreach ($this->operation->getParams() as $name => $arg) {
+ $currentValue = $this[$name];
+ $configValue = $arg->getValue($currentValue);
+ // If default or static values are set, then this should always be updated on the config object
+ if ($currentValue !== $configValue) {
+ $this[$name] = $configValue;
+ }
+ }
+
+ $headers = $this[self::HEADERS_OPTION];
+ if (!$headers instanceof Collection) {
+ $this[self::HEADERS_OPTION] = new Collection((array) $headers);
+ }
+
+ // You can set a command.on_complete option in your parameters to set an onComplete callback
+ if ($onComplete = $this['command.on_complete']) {
+ unset($this['command.on_complete']);
+ $this->setOnComplete($onComplete);
+ }
+
+ // Set the hidden additional parameters
+ if (!$this[self::HIDDEN_PARAMS]) {
+ $this[self::HIDDEN_PARAMS] = array(
+ self::HEADERS_OPTION,
+ self::RESPONSE_PROCESSING,
+ self::HIDDEN_PARAMS,
+ self::REQUEST_OPTIONS
+ );
+ }
+
+ $this->init();
+ }
+
+ /**
+ * Custom clone behavior
+ */
+ public function __clone()
+ {
+ $this->request = null;
+ $this->result = null;
+ }
+
+ /**
+ * Execute the command in the same manner as calling a function
+ *
+ * @return mixed Returns the result of {@see AbstractCommand::execute}
+ */
+ public function __invoke()
+ {
+ return $this->execute();
+ }
+
+ public function getName()
+ {
+ return $this->operation->getName();
+ }
+
+ /**
+ * Get the API command information about the command
+ *
+ * @return OperationInterface
+ */
+ public function getOperation()
+ {
+ return $this->operation;
+ }
+
+ public function setOnComplete($callable)
+ {
+ if (!is_callable($callable)) {
+ throw new InvalidArgumentException('The onComplete function must be callable');
+ }
+
+ $this->onComplete = $callable;
+
+ return $this;
+ }
+
+ public function execute()
+ {
+ if (!$this->client) {
+ throw new CommandException('A client must be associated with the command before it can be executed.');
+ }
+
+ return $this->client->execute($this);
+ }
+
+ public function getClient()
+ {
+ return $this->client;
+ }
+
+ public function setClient(ClientInterface $client)
+ {
+ $this->client = $client;
+
+ return $this;
+ }
+
+ public function getRequest()
+ {
+ if (!$this->request) {
+ throw new CommandException('The command must be prepared before retrieving the request');
+ }
+
+ return $this->request;
+ }
+
+ public function getResponse()
+ {
+ if (!$this->isExecuted()) {
+ $this->execute();
+ }
+
+ return $this->request->getResponse();
+ }
+
+ public function getResult()
+ {
+ if (!$this->isExecuted()) {
+ $this->execute();
+ }
+
+ if (null === $this->result) {
+ $this->process();
+ // Call the onComplete method if one is set
+ if ($this->onComplete) {
+ call_user_func($this->onComplete, $this);
+ }
+ }
+
+ return $this->result;
+ }
+
+ public function setResult($result)
+ {
+ $this->result = $result;
+
+ return $this;
+ }
+
+ public function isPrepared()
+ {
+ return $this->request !== null;
+ }
+
+ public function isExecuted()
+ {
+ return $this->request !== null && $this->request->getState() == 'complete';
+ }
+
+ public function prepare()
+ {
+ if (!$this->isPrepared()) {
+ if (!$this->client) {
+ throw new CommandException('A client must be associated with the command before it can be prepared.');
+ }
+
+ // If no response processing value was specified, then attempt to use the highest level of processing
+ if (!isset($this[self::RESPONSE_PROCESSING])) {
+ $this[self::RESPONSE_PROCESSING] = self::TYPE_MODEL;
+ }
+
+ // Notify subscribers of the client that the command is being prepared
+ $this->client->dispatch('command.before_prepare', array('command' => $this));
+
+ // Fail on missing required arguments, and change parameters via filters
+ $this->validate();
+ // Delegate to the subclass that implements the build method
+ $this->build();
+
+ // Add custom request headers set on the command
+ if ($headers = $this[self::HEADERS_OPTION]) {
+ foreach ($headers as $key => $value) {
+ $this->request->setHeader($key, $value);
+ }
+ }
+
+ // Add any curl options to the request
+ if ($options = $this[Client::CURL_OPTIONS]) {
+ $this->request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($options));
+ }
+
+ // Set a custom response body
+ if ($responseBody = $this[self::RESPONSE_BODY]) {
+ $this->request->setResponseBody($responseBody);
+ }
+
+ $this->client->dispatch('command.after_prepare', array('command' => $this));
+ }
+
+ return $this->request;
+ }
+
+ /**
+ * Set the validator used to validate and prepare command parameters and nested JSON schemas. If no validator is
+ * set, then the command will validate using the default {@see SchemaValidator}.
+ *
+ * @param ValidatorInterface $validator Validator used to prepare and validate properties against a JSON schema
+ *
+ * @return self
+ */
+ public function setValidator(ValidatorInterface $validator)
+ {
+ $this->validator = $validator;
+
+ return $this;
+ }
+
+ public function getRequestHeaders()
+ {
+ return $this[self::HEADERS_OPTION];
+ }
+
+ /**
+ * Initialize the command (hook that can be implemented in subclasses)
+ */
+ protected function init() {}
+
+ /**
+ * Create the request object that will carry out the command
+ */
+ abstract protected function build();
+
+ /**
+ * Hook used to create an operation for concrete commands that are not associated with a service description
+ *
+ * @return OperationInterface
+ */
+ protected function createOperation()
+ {
+ return new Operation(array('name' => get_class($this)));
+ }
+
+ /**
+ * Create the result of the command after the request has been completed.
+ * Override this method in subclasses to customize this behavior
+ */
+ protected function process()
+ {
+ $this->result = $this[self::RESPONSE_PROCESSING] != self::TYPE_RAW
+ ? DefaultResponseParser::getInstance()->parse($this)
+ : $this->request->getResponse();
+ }
+
+ /**
+ * Validate and prepare the command based on the schema and rules defined by the command's Operation object
+ *
+ * @throws ValidationException when validation errors occur
+ */
+ protected function validate()
+ {
+ // Do not perform request validation/transformation if it is disable
+ if ($this[self::DISABLE_VALIDATION]) {
+ return;
+ }
+
+ $errors = array();
+ $validator = $this->getValidator();
+ foreach ($this->operation->getParams() as $name => $schema) {
+ $value = $this[$name];
+ if (!$validator->validate($schema, $value)) {
+ $errors = array_merge($errors, $validator->getErrors());
+ } elseif ($value !== $this[$name]) {
+ // Update the config value if it changed and no validation errors were encountered
+ $this->data[$name] = $value;
+ }
+ }
+
+ // Validate additional parameters
+ $hidden = $this[self::HIDDEN_PARAMS];
+
+ if ($properties = $this->operation->getAdditionalParameters()) {
+ foreach ($this->toArray() as $name => $value) {
+ // It's only additional if it isn't defined in the schema
+ if (!$this->operation->hasParam($name) && !in_array($name, $hidden)) {
+ // Always set the name so that error messages are useful
+ $properties->setName($name);
+ if (!$validator->validate($properties, $value)) {
+ $errors = array_merge($errors, $validator->getErrors());
+ } elseif ($value !== $this[$name]) {
+ $this->data[$name] = $value;
+ }
+ }
+ }
+ }
+
+ if (!empty($errors)) {
+ $e = new ValidationException('Validation errors: ' . implode("\n", $errors));
+ $e->setErrors($errors);
+ throw $e;
+ }
+ }
+
+ /**
+ * Get the validator used to prepare and validate properties. If no validator has been set on the command, then
+ * the default {@see SchemaValidator} will be used.
+ *
+ * @return ValidatorInterface
+ */
+ protected function getValidator()
+ {
+ if (!$this->validator) {
+ $this->validator = SchemaValidator::getInstance();
+ }
+
+ return $this->validator;
+ }
+
+ /**
+ * Get array of any validation errors
+ * If no validator has been set then return false
+ */
+ public function getValidationErrors()
+ {
+ if (!$this->validator) {
+ return false;
+ }
+
+ return $this->validator->getErrors();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php
new file mode 100755
index 0000000..cb6ac40
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/ClosureCommand.php
@@ -0,0 +1,41 @@
+request = $closure($this, $this->operation);
+
+ if (!$this->request || !$this->request instanceof RequestInterface) {
+ throw new UnexpectedValueException('Closure command did not return a RequestInterface object');
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php
new file mode 100755
index 0000000..fbb61d2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/CommandInterface.php
@@ -0,0 +1,128 @@
+stopPropagation();
+ }
+
+ /**
+ * Get the created object
+ *
+ * @return mixed
+ */
+ public function getResult()
+ {
+ return $this['result'];
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php
new file mode 100755
index 0000000..2dc4acd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultRequestSerializer.php
@@ -0,0 +1,169 @@
+factory = $factory;
+ }
+
+ /**
+ * Add a location visitor to the serializer
+ *
+ * @param string $location Location to associate with the visitor
+ * @param RequestVisitorInterface $visitor Visitor to attach
+ *
+ * @return self
+ */
+ public function addVisitor($location, RequestVisitorInterface $visitor)
+ {
+ $this->factory->addRequestVisitor($location, $visitor);
+
+ return $this;
+ }
+
+ public function prepare(CommandInterface $command)
+ {
+ $request = $this->createRequest($command);
+ // Keep an array of visitors found in the operation
+ $foundVisitors = array();
+ $operation = $command->getOperation();
+
+ // Add arguments to the request using the location attribute
+ foreach ($operation->getParams() as $name => $arg) {
+ /** @var $arg \Guzzle\Service\Description\Parameter */
+ $location = $arg->getLocation();
+ // Skip 'uri' locations because they've already been processed
+ if ($location && $location != 'uri') {
+ // Instantiate visitors as they are detected in the properties
+ if (!isset($foundVisitors[$location])) {
+ $foundVisitors[$location] = $this->factory->getRequestVisitor($location);
+ }
+ // Ensure that a value has been set for this parameter
+ $value = $command[$name];
+ if ($value !== null) {
+ // Apply the parameter value with the location visitor
+ $foundVisitors[$location]->visit($command, $request, $arg, $value);
+ }
+ }
+ }
+
+ // Serialize additional parameters
+ if ($additional = $operation->getAdditionalParameters()) {
+ if ($visitor = $this->prepareAdditionalParameters($operation, $command, $request, $additional)) {
+ $foundVisitors[$additional->getLocation()] = $visitor;
+ }
+ }
+
+ // Call the after method on each visitor found in the operation
+ foreach ($foundVisitors as $visitor) {
+ $visitor->after($command, $request);
+ }
+
+ return $request;
+ }
+
+ /**
+ * Serialize additional parameters
+ *
+ * @param OperationInterface $operation Operation that owns the command
+ * @param CommandInterface $command Command to prepare
+ * @param RequestInterface $request Request to serialize
+ * @param Parameter $additional Additional parameters
+ *
+ * @return null|RequestVisitorInterface
+ */
+ protected function prepareAdditionalParameters(
+ OperationInterface $operation,
+ CommandInterface $command,
+ RequestInterface $request,
+ Parameter $additional
+ ) {
+ if (!($location = $additional->getLocation())) {
+ return;
+ }
+
+ $visitor = $this->factory->getRequestVisitor($location);
+ $hidden = $command[$command::HIDDEN_PARAMS];
+
+ foreach ($command->toArray() as $key => $value) {
+ // Ignore values that are null or built-in command options
+ if ($value !== null
+ && !in_array($key, $hidden)
+ && !$operation->hasParam($key)
+ ) {
+ $additional->setName($key);
+ $visitor->visit($command, $request, $additional, $value);
+ }
+ }
+
+ return $visitor;
+ }
+
+ /**
+ * Create a request for the command and operation
+ *
+ * @param CommandInterface $command Command to create a request for
+ *
+ * @return RequestInterface
+ */
+ protected function createRequest(CommandInterface $command)
+ {
+ $operation = $command->getOperation();
+ $client = $command->getClient();
+ $options = $command[AbstractCommand::REQUEST_OPTIONS] ?: array();
+
+ // If the command does not specify a template, then assume the base URL of the client
+ if (!($uri = $operation->getUri())) {
+ return $client->createRequest($operation->getHttpMethod(), $client->getBaseUrl(), null, null, $options);
+ }
+
+ // Get the path values and use the client config settings
+ $variables = array();
+ foreach ($operation->getParams() as $name => $arg) {
+ if ($arg->getLocation() == 'uri') {
+ if (isset($command[$name])) {
+ $variables[$name] = $arg->filter($command[$name]);
+ if (!is_array($variables[$name])) {
+ $variables[$name] = (string) $variables[$name];
+ }
+ }
+ }
+ }
+
+ return $client->createRequest($operation->getHttpMethod(), array($uri, $variables), null, null, $options);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php
new file mode 100755
index 0000000..4fe3803
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/DefaultResponseParser.php
@@ -0,0 +1,55 @@
+getRequest()->getResponse();
+
+ // Account for hard coded content-type values specified in service descriptions
+ if ($contentType = $command['command.expects']) {
+ $response->setHeader('Content-Type', $contentType);
+ } else {
+ $contentType = (string) $response->getHeader('Content-Type');
+ }
+
+ return $this->handleParsing($command, $response, $contentType);
+ }
+
+ protected function handleParsing(CommandInterface $command, Response $response, $contentType)
+ {
+ $result = $response;
+ if ($result->getBody()) {
+ if (stripos($contentType, 'json') !== false) {
+ $result = $result->json();
+ } elseif (stripos($contentType, 'xml') !== false) {
+ $result = $result->xml();
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php
new file mode 100755
index 0000000..1c5ce07
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/AliasFactory.php
@@ -0,0 +1,39 @@
+client = $client;
+ $this->aliases = $aliases;
+ }
+
+ public function factory($name, array $args = array())
+ {
+ if (isset($this->aliases[$name])) {
+ try {
+ return $this->client->getCommand($this->aliases[$name], $args);
+ } catch (InvalidArgumentException $e) {
+ return null;
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php
new file mode 100755
index 0000000..8c46983
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/CompositeFactory.php
@@ -0,0 +1,154 @@
+getDescription()) {
+ $factories[] = new ServiceDescriptionFactory($description);
+ }
+ $factories[] = new ConcreteClassFactory($client);
+
+ return new self($factories);
+ }
+
+ /**
+ * @param array $factories Array of command factories
+ */
+ public function __construct(array $factories = array())
+ {
+ $this->factories = $factories;
+ }
+
+ /**
+ * Add a command factory to the chain
+ *
+ * @param FactoryInterface $factory Factory to add
+ * @param string|FactoryInterface $before Insert the new command factory before a command factory class or object
+ * matching a class name.
+ * @return CompositeFactory
+ */
+ public function add(FactoryInterface $factory, $before = null)
+ {
+ $pos = null;
+
+ if ($before) {
+ foreach ($this->factories as $i => $f) {
+ if ($before instanceof FactoryInterface) {
+ if ($f === $before) {
+ $pos = $i;
+ break;
+ }
+ } elseif (is_string($before)) {
+ if ($f instanceof $before) {
+ $pos = $i;
+ break;
+ }
+ }
+ }
+ }
+
+ if ($pos === null) {
+ $this->factories[] = $factory;
+ } else {
+ array_splice($this->factories, $i, 0, array($factory));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Check if the chain contains a specific command factory
+ *
+ * @param FactoryInterface|string $factory Factory to check
+ *
+ * @return bool
+ */
+ public function has($factory)
+ {
+ return (bool) $this->find($factory);
+ }
+
+ /**
+ * Remove a specific command factory from the chain
+ *
+ * @param string|FactoryInterface $factory Factory to remove by name or instance
+ *
+ * @return CompositeFactory
+ */
+ public function remove($factory = null)
+ {
+ if (!($factory instanceof FactoryInterface)) {
+ $factory = $this->find($factory);
+ }
+
+ $this->factories = array_values(array_filter($this->factories, function($f) use ($factory) {
+ return $f !== $factory;
+ }));
+
+ return $this;
+ }
+
+ /**
+ * Get a command factory by class name
+ *
+ * @param string|FactoryInterface $factory Command factory class or instance
+ *
+ * @return null|FactoryInterface
+ */
+ public function find($factory)
+ {
+ foreach ($this->factories as $f) {
+ if ($factory === $f || (is_string($factory) && $f instanceof $factory)) {
+ return $f;
+ }
+ }
+ }
+
+ /**
+ * Create a command using the associated command factories
+ *
+ * @param string $name Name of the command
+ * @param array $args Command arguments
+ *
+ * @return CommandInterface
+ */
+ public function factory($name, array $args = array())
+ {
+ foreach ($this->factories as $factory) {
+ $command = $factory->factory($name, $args);
+ if ($command) {
+ return $command;
+ }
+ }
+ }
+
+ public function count()
+ {
+ return count($this->factories);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->factories);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php
new file mode 100755
index 0000000..0e93dea
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ConcreteClassFactory.php
@@ -0,0 +1,47 @@
+client = $client;
+ $this->inflector = $inflector ?: Inflector::getDefault();
+ }
+
+ public function factory($name, array $args = array())
+ {
+ // Determine the class to instantiate based on the namespace of the current client and the default directory
+ $prefix = $this->client->getConfig('command.prefix');
+ if (!$prefix) {
+ // The prefix can be specified in a factory method and is cached
+ $prefix = implode('\\', array_slice(explode('\\', get_class($this->client)), 0, -1)) . '\\Command\\';
+ $this->client->getConfig()->set('command.prefix', $prefix);
+ }
+
+ $class = $prefix . str_replace(' ', '\\', ucwords(str_replace('.', ' ', $this->inflector->camel($name))));
+
+ // Create the concrete command if it exists
+ if (class_exists($class)) {
+ return new $class($args);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php
new file mode 100755
index 0000000..35c299d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/FactoryInterface.php
@@ -0,0 +1,21 @@
+map = $map;
+ }
+
+ public function factory($name, array $args = array())
+ {
+ if (isset($this->map[$name])) {
+ $class = $this->map[$name];
+
+ return new $class($args);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php
new file mode 100755
index 0000000..b943a5b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/Factory/ServiceDescriptionFactory.php
@@ -0,0 +1,71 @@
+setServiceDescription($description);
+ $this->inflector = $inflector;
+ }
+
+ /**
+ * Change the service description used with the factory
+ *
+ * @param ServiceDescriptionInterface $description Service description to use
+ *
+ * @return FactoryInterface
+ */
+ public function setServiceDescription(ServiceDescriptionInterface $description)
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
+ /**
+ * Returns the service description
+ *
+ * @return ServiceDescriptionInterface
+ */
+ public function getServiceDescription()
+ {
+ return $this->description;
+ }
+
+ public function factory($name, array $args = array())
+ {
+ $command = $this->description->getOperation($name);
+
+ // If a command wasn't found, then try to uppercase the first letter and try again
+ if (!$command) {
+ $command = $this->description->getOperation(ucfirst($name));
+ // If an inflector was passed, then attempt to get the command using snake_case inflection
+ if (!$command && $this->inflector) {
+ $command = $this->description->getOperation($this->inflector->snake($name));
+ }
+ }
+
+ if ($command) {
+ $class = $command->getClass();
+ return new $class($args, $command, $this->description);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php
new file mode 100755
index 0000000..adcfca1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/AbstractRequestVisitor.php
@@ -0,0 +1,69 @@
+resolveRecursively($value, $param)
+ : $param->filter($value);
+ }
+
+ /**
+ * Map nested parameters into the location_key based parameters
+ *
+ * @param array $value Value to map
+ * @param Parameter $param Parameter that holds information about the current key
+ *
+ * @return array Returns the mapped array
+ */
+ protected function resolveRecursively(array $value, Parameter $param)
+ {
+ foreach ($value as $name => &$v) {
+ switch ($param->getType()) {
+ case 'object':
+ if ($subParam = $param->getProperty($name)) {
+ $key = $subParam->getWireName();
+ $value[$key] = $this->prepareValue($v, $subParam);
+ if ($name != $key) {
+ unset($value[$name]);
+ }
+ } elseif ($param->getAdditionalProperties() instanceof Parameter) {
+ $v = $this->prepareValue($v, $param->getAdditionalProperties());
+ }
+ break;
+ case 'array':
+ if ($items = $param->getItems()) {
+ $v = $this->prepareValue($v, $items);
+ }
+ break;
+ }
+ }
+
+ return $param->filter($value);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php
new file mode 100755
index 0000000..168d780
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/BodyVisitor.php
@@ -0,0 +1,58 @@
+filter($value);
+ $entityBody = EntityBody::factory($value);
+ $request->setBody($entityBody);
+ $this->addExpectHeader($request, $entityBody, $param->getData('expect_header'));
+ // Add the Content-Encoding header if one is set on the EntityBody
+ if ($encoding = $entityBody->getContentEncoding()) {
+ $request->setHeader('Content-Encoding', $encoding);
+ }
+ }
+
+ /**
+ * Add the appropriate expect header to a request
+ *
+ * @param EntityEnclosingRequestInterface $request Request to update
+ * @param EntityBodyInterface $body Entity body of the request
+ * @param string|int $expect Expect header setting
+ */
+ protected function addExpectHeader(EntityEnclosingRequestInterface $request, EntityBodyInterface $body, $expect)
+ {
+ // Allow the `expect` data parameter to be set to remove the Expect header from the request
+ if ($expect === false) {
+ $request->removeHeader('Expect');
+ } elseif ($expect !== true) {
+ // Default to using a MB as the point in which to start using the expect header
+ $expect = $expect ?: 1048576;
+ // If the expect_header value is numeric then only add if the size is greater than the cutoff
+ if (is_numeric($expect) && $body->getSize()) {
+ if ($body->getSize() < $expect) {
+ $request->removeHeader('Expect');
+ } else {
+ $request->setHeader('Expect', '100-Continue');
+ }
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php
new file mode 100755
index 0000000..2a53754
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/HeaderVisitor.php
@@ -0,0 +1,44 @@
+filter($value);
+ if ($param->getType() == 'object' && $param->getAdditionalProperties() instanceof Parameter) {
+ $this->addPrefixedHeaders($request, $param, $value);
+ } else {
+ $request->setHeader($param->getWireName(), $value);
+ }
+ }
+
+ /**
+ * Add a prefixed array of headers to the request
+ *
+ * @param RequestInterface $request Request to update
+ * @param Parameter $param Parameter object
+ * @param array $value Header array to add
+ *
+ * @throws InvalidArgumentException
+ */
+ protected function addPrefixedHeaders(RequestInterface $request, Parameter $param, $value)
+ {
+ if (!is_array($value)) {
+ throw new InvalidArgumentException('An array of mapped headers expected, but received a single value');
+ }
+ $prefix = $param->getSentAs();
+ foreach ($value as $headerName => $headerValue) {
+ $request->setHeader($prefix . $headerName, $headerValue);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php
new file mode 100755
index 0000000..757e1c5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/JsonVisitor.php
@@ -0,0 +1,63 @@
+data = new \SplObjectStorage();
+ }
+
+ /**
+ * Set the Content-Type header to add to the request if JSON is added to the body. This visitor does not add a
+ * Content-Type header unless you specify one here.
+ *
+ * @param string $header Header to set when JSON is added (e.g. application/json)
+ *
+ * @return self
+ */
+ public function setContentTypeHeader($header = 'application/json')
+ {
+ $this->jsonContentType = $header;
+
+ return $this;
+ }
+
+ public function visit(CommandInterface $command, RequestInterface $request, Parameter $param, $value)
+ {
+ if (isset($this->data[$command])) {
+ $json = $this->data[$command];
+ } else {
+ $json = array();
+ }
+ $json[$param->getWireName()] = $this->prepareValue($value, $param);
+ $this->data[$command] = $json;
+ }
+
+ public function after(CommandInterface $command, RequestInterface $request)
+ {
+ if (isset($this->data[$command])) {
+ // Don't overwrite the Content-Type if one is set
+ if ($this->jsonContentType && !$request->hasHeader('Content-Type')) {
+ $request->setHeader('Content-Type', $this->jsonContentType);
+ }
+
+ $request->setBody(json_encode($this->data[$command]));
+ unset($this->data[$command]);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php
new file mode 100755
index 0000000..975850b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFieldVisitor.php
@@ -0,0 +1,18 @@
+setPostField($param->getWireName(), $this->prepareValue($value, $param));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php
new file mode 100755
index 0000000..0853ebe
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/PostFileVisitor.php
@@ -0,0 +1,24 @@
+filter($value);
+ if ($value instanceof PostFileInterface) {
+ $request->addPostFile($value);
+ } else {
+ $request->addPostFile($param->getWireName(), $value);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php
new file mode 100755
index 0000000..315877a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/QueryVisitor.php
@@ -0,0 +1,18 @@
+getQuery()->set($param->getWireName(), $this->prepareValue($value, $param));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php
new file mode 100755
index 0000000..14e0b2d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/RequestVisitorInterface.php
@@ -0,0 +1,31 @@
+setResponseBody($value);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php
new file mode 100755
index 0000000..5b71487
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Request/XmlVisitor.php
@@ -0,0 +1,252 @@
+data = new \SplObjectStorage();
+ }
+
+ /**
+ * Change the content-type header that is added when XML is found
+ *
+ * @param string $header Header to set when XML is found
+ *
+ * @return self
+ */
+ public function setContentTypeHeader($header)
+ {
+ $this->contentType = $header;
+
+ return $this;
+ }
+
+ public function visit(CommandInterface $command, RequestInterface $request, Parameter $param, $value)
+ {
+ $xml = isset($this->data[$command])
+ ? $this->data[$command]
+ : $this->createRootElement($param->getParent());
+ $this->addXml($xml, $param, $value);
+
+ $this->data[$command] = $xml;
+ }
+
+ public function after(CommandInterface $command, RequestInterface $request)
+ {
+ $xml = null;
+
+ // If data was found that needs to be serialized, then do so
+ if (isset($this->data[$command])) {
+ $xml = $this->finishDocument($this->data[$command]);
+ unset($this->data[$command]);
+ } else {
+ // Check if XML should always be sent for the command
+ $operation = $command->getOperation();
+ if ($operation->getData('xmlAllowEmpty')) {
+ $xmlWriter = $this->createRootElement($operation);
+ $xml = $this->finishDocument($xmlWriter);
+ }
+ }
+
+ if ($xml) {
+ // Don't overwrite the Content-Type if one is set
+ if ($this->contentType && !$request->hasHeader('Content-Type')) {
+ $request->setHeader('Content-Type', $this->contentType);
+ }
+ $request->setBody($xml);
+ }
+ }
+
+ /**
+ * Create the root XML element to use with a request
+ *
+ * @param Operation $operation Operation object
+ *
+ * @return \XMLWriter
+ */
+ protected function createRootElement(Operation $operation)
+ {
+ static $defaultRoot = array('name' => 'Request');
+ // If no root element was specified, then just wrap the XML in 'Request'
+ $root = $operation->getData('xmlRoot') ?: $defaultRoot;
+ // Allow the XML declaration to be customized with xmlEncoding
+ $encoding = $operation->getData('xmlEncoding');
+
+ $xmlWriter = $this->startDocument($encoding);
+
+ $xmlWriter->startElement($root['name']);
+ // Create the wrapping element with no namespaces if no namespaces were present
+ if (!empty($root['namespaces'])) {
+ // Create the wrapping element with an array of one or more namespaces
+ foreach ((array) $root['namespaces'] as $prefix => $uri) {
+ $nsLabel = 'xmlns';
+ if (!is_numeric($prefix)) {
+ $nsLabel .= ':'.$prefix;
+ }
+ $xmlWriter->writeAttribute($nsLabel, $uri);
+ }
+ }
+ return $xmlWriter;
+ }
+
+ /**
+ * Recursively build the XML body
+ *
+ * @param \XMLWriter $xmlWriter XML to modify
+ * @param Parameter $param API Parameter
+ * @param mixed $value Value to add
+ */
+ protected function addXml(\XMLWriter $xmlWriter, Parameter $param, $value)
+ {
+ if ($value === null) {
+ return;
+ }
+
+ $value = $param->filter($value);
+ $type = $param->getType();
+ $name = $param->getWireName();
+ $prefix = null;
+ $namespace = $param->getData('xmlNamespace');
+ if (false !== strpos($name, ':')) {
+ list($prefix, $name) = explode(':', $name, 2);
+ }
+
+ if ($type == 'object' || $type == 'array') {
+ if (!$param->getData('xmlFlattened')) {
+ $xmlWriter->startElementNS(null, $name, $namespace);
+ }
+ if ($param->getType() == 'array') {
+ $this->addXmlArray($xmlWriter, $param, $value);
+ } elseif ($param->getType() == 'object') {
+ $this->addXmlObject($xmlWriter, $param, $value);
+ }
+ if (!$param->getData('xmlFlattened')) {
+ $xmlWriter->endElement();
+ }
+ return;
+ }
+ if ($param->getData('xmlAttribute')) {
+ $this->writeAttribute($xmlWriter, $prefix, $name, $namespace, $value);
+ } else {
+ $this->writeElement($xmlWriter, $prefix, $name, $namespace, $value);
+ }
+ }
+
+ /**
+ * Write an attribute with namespace if used
+ *
+ * @param \XMLWriter $xmlWriter XMLWriter instance
+ * @param string $prefix Namespace prefix if any
+ * @param string $name Attribute name
+ * @param string $namespace The uri of the namespace
+ * @param string $value The attribute content
+ */
+ protected function writeAttribute($xmlWriter, $prefix, $name, $namespace, $value)
+ {
+ if (empty($namespace)) {
+ $xmlWriter->writeAttribute($name, $value);
+ } else {
+ $xmlWriter->writeAttributeNS($prefix, $name, $namespace, $value);
+ }
+ }
+
+ /**
+ * Write an element with namespace if used
+ *
+ * @param \XMLWriter $xmlWriter XML writer resource
+ * @param string $prefix Namespace prefix if any
+ * @param string $name Element name
+ * @param string $namespace The uri of the namespace
+ * @param string $value The element content
+ */
+ protected function writeElement(\XMLWriter $xmlWriter, $prefix, $name, $namespace, $value)
+ {
+ $xmlWriter->startElementNS($prefix, $name, $namespace);
+ if (strpbrk($value, '<>&')) {
+ $xmlWriter->writeCData($value);
+ } else {
+ $xmlWriter->writeRaw($value);
+ }
+ $xmlWriter->endElement();
+ }
+
+ /**
+ * Create a new xml writer and start a document
+ *
+ * @param string $encoding document encoding
+ *
+ * @return \XMLWriter the writer resource
+ */
+ protected function startDocument($encoding)
+ {
+ $xmlWriter = new \XMLWriter();
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument('1.0', $encoding);
+
+ return $xmlWriter;
+ }
+
+ /**
+ * End the document and return the output
+ *
+ * @param \XMLWriter $xmlWriter
+ *
+ * @return \string the writer resource
+ */
+ protected function finishDocument($xmlWriter)
+ {
+ $xmlWriter->endDocument();
+
+ return $xmlWriter->outputMemory();
+ }
+
+ /**
+ * Add an array to the XML
+ */
+ protected function addXmlArray(\XMLWriter $xmlWriter, Parameter $param, &$value)
+ {
+ if ($items = $param->getItems()) {
+ foreach ($value as $v) {
+ $this->addXml($xmlWriter, $items, $v);
+ }
+ }
+ }
+
+ /**
+ * Add an object to the XML
+ */
+ protected function addXmlObject(\XMLWriter $xmlWriter, Parameter $param, &$value)
+ {
+ $noAttributes = array();
+ // add values which have attributes
+ foreach ($value as $name => $v) {
+ if ($property = $param->getProperty($name)) {
+ if ($property->getData('xmlAttribute')) {
+ $this->addXml($xmlWriter, $property, $v);
+ } else {
+ $noAttributes[] = array('value' => $v, 'property' => $property);
+ }
+ }
+ }
+ // now add values with no attributes
+ foreach ($noAttributes as $element) {
+ $this->addXml($xmlWriter, $element['property'], $element['value']);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php
new file mode 100755
index 0000000..d87eeb9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/AbstractResponseVisitor.php
@@ -0,0 +1,26 @@
+getName()] = $param->filter($response->getBody());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php
new file mode 100755
index 0000000..0f8737c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/HeaderVisitor.php
@@ -0,0 +1,50 @@
+getType() == 'object' && $param->getAdditionalProperties() instanceof Parameter) {
+ $this->processPrefixedHeaders($response, $param, $value);
+ } else {
+ $value[$param->getName()] = $param->filter((string) $response->getHeader($param->getWireName()));
+ }
+ }
+
+ /**
+ * Process a prefixed header array
+ *
+ * @param Response $response Response that contains the headers
+ * @param Parameter $param Parameter object
+ * @param array $value Value response array to modify
+ */
+ protected function processPrefixedHeaders(Response $response, Parameter $param, &$value)
+ {
+ // Grab prefixed headers that should be placed into an array with the prefix stripped
+ if ($prefix = $param->getSentAs()) {
+ $container = $param->getName();
+ $len = strlen($prefix);
+ // Find all matching headers and place them into the containing element
+ foreach ($response->getHeaders()->toArray() as $key => $header) {
+ if (stripos($key, $prefix) === 0) {
+ // Account for multi-value headers
+ $value[$container][substr($key, $len)] = count($header) == 1 ? end($header) : $header;
+ }
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php
new file mode 100755
index 0000000..a609ebd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/JsonVisitor.php
@@ -0,0 +1,93 @@
+getResponse()->json();
+ }
+
+ public function visit(
+ CommandInterface $command,
+ Response $response,
+ Parameter $param,
+ &$value,
+ $context = null
+ ) {
+ $name = $param->getName();
+ $key = $param->getWireName();
+ if (isset($value[$key])) {
+ $this->recursiveProcess($param, $value[$key]);
+ if ($key != $name) {
+ $value[$name] = $value[$key];
+ unset($value[$key]);
+ }
+ }
+ }
+
+ /**
+ * Recursively process a parameter while applying filters
+ *
+ * @param Parameter $param API parameter being validated
+ * @param mixed $value Value to validate and process. The value may change during this process.
+ */
+ protected function recursiveProcess(Parameter $param, &$value)
+ {
+ if ($value === null) {
+ return;
+ }
+
+ if (is_array($value)) {
+ $type = $param->getType();
+ if ($type == 'array') {
+ foreach ($value as &$item) {
+ $this->recursiveProcess($param->getItems(), $item);
+ }
+ } elseif ($type == 'object' && !isset($value[0])) {
+ // On the above line, we ensure that the array is associative and not numerically indexed
+ $knownProperties = array();
+ if ($properties = $param->getProperties()) {
+ foreach ($properties as $property) {
+ $name = $property->getName();
+ $key = $property->getWireName();
+ $knownProperties[$name] = 1;
+ if (isset($value[$key])) {
+ $this->recursiveProcess($property, $value[$key]);
+ if ($key != $name) {
+ $value[$name] = $value[$key];
+ unset($value[$key]);
+ }
+ }
+ }
+ }
+
+ // Remove any unknown and potentially unsafe properties
+ if ($param->getAdditionalProperties() === false) {
+ $value = array_intersect_key($value, $knownProperties);
+ } elseif (($additional = $param->getAdditionalProperties()) !== true) {
+ // Validate and filter additional properties
+ foreach ($value as &$v) {
+ $this->recursiveProcess($additional, $v);
+ }
+ }
+ }
+ }
+
+ $value = $param->filter($value);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php
new file mode 100755
index 0000000..1b10ebc
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ReasonPhraseVisitor.php
@@ -0,0 +1,23 @@
+getName()] = $response->getReasonPhrase();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php
new file mode 100755
index 0000000..033f40c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/ResponseVisitorInterface.php
@@ -0,0 +1,46 @@
+getName()] = $response->getStatusCode();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php
new file mode 100755
index 0000000..bb7124b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/Response/XmlVisitor.php
@@ -0,0 +1,151 @@
+getResponse()->xml()), true);
+ }
+
+ public function visit(
+ CommandInterface $command,
+ Response $response,
+ Parameter $param,
+ &$value,
+ $context = null
+ ) {
+ $sentAs = $param->getWireName();
+ $name = $param->getName();
+ if (isset($value[$sentAs])) {
+ $this->recursiveProcess($param, $value[$sentAs]);
+ if ($name != $sentAs) {
+ $value[$name] = $value[$sentAs];
+ unset($value[$sentAs]);
+ }
+ }
+ }
+
+ /**
+ * Recursively process a parameter while applying filters
+ *
+ * @param Parameter $param API parameter being processed
+ * @param mixed $value Value to validate and process. The value may change during this process.
+ */
+ protected function recursiveProcess(Parameter $param, &$value)
+ {
+ $type = $param->getType();
+
+ if (!is_array($value)) {
+ if ($type == 'array') {
+ // Cast to an array if the value was a string, but should be an array
+ $this->recursiveProcess($param->getItems(), $value);
+ $value = array($value);
+ }
+ } elseif ($type == 'object') {
+ $this->processObject($param, $value);
+ } elseif ($type == 'array') {
+ $this->processArray($param, $value);
+ } elseif ($type == 'string' && gettype($value) == 'array') {
+ $value = '';
+ }
+
+ if ($value !== null) {
+ $value = $param->filter($value);
+ }
+ }
+
+ /**
+ * Process an array
+ *
+ * @param Parameter $param API parameter being parsed
+ * @param mixed $value Value to process
+ */
+ protected function processArray(Parameter $param, &$value)
+ {
+ // Convert the node if it was meant to be an array
+ if (!isset($value[0])) {
+ // Collections fo nodes are sometimes wrapped in an additional array. For example:
+ // 1 2 should become:
+ // array('Items' => array(array('a' => 1), array('a' => 2))
+ // Some nodes are not wrapped. For example: 1 2
+ // should become array('Foo' => array(array('a' => 1), array('a' => 2))
+ if ($param->getItems() && isset($value[$param->getItems()->getWireName()])) {
+ // Account for the case of a collection wrapping wrapped nodes: Items => Item[]
+ $value = $value[$param->getItems()->getWireName()];
+ // If the wrapped node only had one value, then make it an array of nodes
+ if (!isset($value[0]) || !is_array($value)) {
+ $value = array($value);
+ }
+ } elseif (!empty($value)) {
+ // Account for repeated nodes that must be an array: Foo => Baz, Foo => Baz, but only if the
+ // value is set and not empty
+ $value = array($value);
+ }
+ }
+
+ foreach ($value as &$item) {
+ $this->recursiveProcess($param->getItems(), $item);
+ }
+ }
+
+ /**
+ * Process an object
+ *
+ * @param Parameter $param API parameter being parsed
+ * @param mixed $value Value to process
+ */
+ protected function processObject(Parameter $param, &$value)
+ {
+ // Ensure that the array is associative and not numerically indexed
+ if (!isset($value[0]) && ($properties = $param->getProperties())) {
+ $knownProperties = array();
+ foreach ($properties as $property) {
+ $name = $property->getName();
+ $sentAs = $property->getWireName();
+ $knownProperties[$name] = 1;
+ if ($property->getData('xmlAttribute')) {
+ $this->processXmlAttribute($property, $value);
+ } elseif (isset($value[$sentAs])) {
+ $this->recursiveProcess($property, $value[$sentAs]);
+ if ($name != $sentAs) {
+ $value[$name] = $value[$sentAs];
+ unset($value[$sentAs]);
+ }
+ }
+ }
+
+ // Remove any unknown and potentially unsafe properties
+ if ($param->getAdditionalProperties() === false) {
+ $value = array_intersect_key($value, $knownProperties);
+ }
+ }
+ }
+
+ /**
+ * Process an XML attribute property
+ *
+ * @param Parameter $property Property to process
+ * @param array $value Value to process and update
+ */
+ protected function processXmlAttribute(Parameter $property, array &$value)
+ {
+ $sentAs = $property->getWireName();
+ if (isset($value['@attributes'][$sentAs])) {
+ $value[$property->getName()] = $value['@attributes'][$sentAs];
+ unset($value['@attributes'][$sentAs]);
+ if (empty($value['@attributes'])) {
+ unset($value['@attributes']);
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php
new file mode 100755
index 0000000..74cb628
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/LocationVisitor/VisitorFlyweight.php
@@ -0,0 +1,138 @@
+ 'Guzzle\Service\Command\LocationVisitor\Request\BodyVisitor',
+ 'request.header' => 'Guzzle\Service\Command\LocationVisitor\Request\HeaderVisitor',
+ 'request.json' => 'Guzzle\Service\Command\LocationVisitor\Request\JsonVisitor',
+ 'request.postField' => 'Guzzle\Service\Command\LocationVisitor\Request\PostFieldVisitor',
+ 'request.postFile' => 'Guzzle\Service\Command\LocationVisitor\Request\PostFileVisitor',
+ 'request.query' => 'Guzzle\Service\Command\LocationVisitor\Request\QueryVisitor',
+ 'request.response_body' => 'Guzzle\Service\Command\LocationVisitor\Request\ResponseBodyVisitor',
+ 'request.responseBody' => 'Guzzle\Service\Command\LocationVisitor\Request\ResponseBodyVisitor',
+ 'request.xml' => 'Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor',
+ 'response.body' => 'Guzzle\Service\Command\LocationVisitor\Response\BodyVisitor',
+ 'response.header' => 'Guzzle\Service\Command\LocationVisitor\Response\HeaderVisitor',
+ 'response.json' => 'Guzzle\Service\Command\LocationVisitor\Response\JsonVisitor',
+ 'response.reasonPhrase' => 'Guzzle\Service\Command\LocationVisitor\Response\ReasonPhraseVisitor',
+ 'response.statusCode' => 'Guzzle\Service\Command\LocationVisitor\Response\StatusCodeVisitor',
+ 'response.xml' => 'Guzzle\Service\Command\LocationVisitor\Response\XmlVisitor'
+ );
+
+ /** @var array Array of mappings of location names to classes */
+ protected $mappings;
+
+ /** @var array Cache of instantiated visitors */
+ protected $cache = array();
+
+ /**
+ * @return self
+ * @codeCoverageIgnore
+ */
+ public static function getInstance()
+ {
+ if (!self::$instance) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * @param array $mappings Array mapping request.name and response.name to location visitor classes. Leave null to
+ * use the default values.
+ */
+ public function __construct(array $mappings = null)
+ {
+ $this->mappings = $mappings === null ? self::$defaultMappings : $mappings;
+ }
+
+ /**
+ * Get an instance of a request visitor by location name
+ *
+ * @param string $visitor Visitor name
+ *
+ * @return RequestVisitorInterface
+ */
+ public function getRequestVisitor($visitor)
+ {
+ return $this->getKey('request.' . $visitor);
+ }
+
+ /**
+ * Get an instance of a response visitor by location name
+ *
+ * @param string $visitor Visitor name
+ *
+ * @return ResponseVisitorInterface
+ */
+ public function getResponseVisitor($visitor)
+ {
+ return $this->getKey('response.' . $visitor);
+ }
+
+ /**
+ * Add a response visitor to the factory by name
+ *
+ * @param string $name Name of the visitor
+ * @param RequestVisitorInterface $visitor Visitor to add
+ *
+ * @return self
+ */
+ public function addRequestVisitor($name, RequestVisitorInterface $visitor)
+ {
+ $this->cache['request.' . $name] = $visitor;
+
+ return $this;
+ }
+
+ /**
+ * Add a response visitor to the factory by name
+ *
+ * @param string $name Name of the visitor
+ * @param ResponseVisitorInterface $visitor Visitor to add
+ *
+ * @return self
+ */
+ public function addResponseVisitor($name, ResponseVisitorInterface $visitor)
+ {
+ $this->cache['response.' . $name] = $visitor;
+
+ return $this;
+ }
+
+ /**
+ * Get a visitor by key value name
+ *
+ * @param string $key Key name to retrieve
+ *
+ * @return mixed
+ * @throws InvalidArgumentException
+ */
+ private function getKey($key)
+ {
+ if (!isset($this->cache[$key])) {
+ if (!isset($this->mappings[$key])) {
+ list($type, $name) = explode('.', $key);
+ throw new InvalidArgumentException("No {$type} visitor has been mapped for {$name}");
+ }
+ $this->cache[$key] = new $this->mappings[$key];
+ }
+
+ return $this->cache[$key];
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php
new file mode 100755
index 0000000..0748b5a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationCommand.php
@@ -0,0 +1,89 @@
+responseParser = $parser;
+
+ return $this;
+ }
+
+ /**
+ * Set the request serializer used with the command
+ *
+ * @param RequestSerializerInterface $serializer Request serializer
+ *
+ * @return self
+ */
+ public function setRequestSerializer(RequestSerializerInterface $serializer)
+ {
+ $this->requestSerializer = $serializer;
+
+ return $this;
+ }
+
+ /**
+ * Get the request serializer used with the command
+ *
+ * @return RequestSerializerInterface
+ */
+ public function getRequestSerializer()
+ {
+ if (!$this->requestSerializer) {
+ // Use the default request serializer if none was found
+ $this->requestSerializer = DefaultRequestSerializer::getInstance();
+ }
+
+ return $this->requestSerializer;
+ }
+
+ /**
+ * Get the response parser used for the operation
+ *
+ * @return ResponseParserInterface
+ */
+ public function getResponseParser()
+ {
+ if (!$this->responseParser) {
+ // Use the default response parser if none was found
+ $this->responseParser = OperationResponseParser::getInstance();
+ }
+
+ return $this->responseParser;
+ }
+
+ protected function build()
+ {
+ // Prepare and serialize the request
+ $this->request = $this->getRequestSerializer()->prepare($this);
+ }
+
+ protected function process()
+ {
+ // Do not process the response if 'command.response_processing' is set to 'raw'
+ $this->result = $this[self::RESPONSE_PROCESSING] == self::TYPE_RAW
+ ? $this->request->getResponse()
+ : $this->getResponseParser()->parse($this);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php
new file mode 100755
index 0000000..ca00bc0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/OperationResponseParser.php
@@ -0,0 +1,195 @@
+factory = $factory;
+ $this->schemaInModels = $schemaInModels;
+ }
+
+ /**
+ * Add a location visitor to the command
+ *
+ * @param string $location Location to associate with the visitor
+ * @param ResponseVisitorInterface $visitor Visitor to attach
+ *
+ * @return self
+ */
+ public function addVisitor($location, ResponseVisitorInterface $visitor)
+ {
+ $this->factory->addResponseVisitor($location, $visitor);
+
+ return $this;
+ }
+
+ protected function handleParsing(CommandInterface $command, Response $response, $contentType)
+ {
+ $operation = $command->getOperation();
+ $type = $operation->getResponseType();
+ $model = null;
+
+ if ($type == OperationInterface::TYPE_MODEL) {
+ $model = $operation->getServiceDescription()->getModel($operation->getResponseClass());
+ } elseif ($type == OperationInterface::TYPE_CLASS) {
+ return $this->parseClass($command);
+ }
+
+ if (!$model) {
+ // Return basic processing if the responseType is not model or the model cannot be found
+ return parent::handleParsing($command, $response, $contentType);
+ } elseif ($command[AbstractCommand::RESPONSE_PROCESSING] != AbstractCommand::TYPE_MODEL) {
+ // Returns a model with no visiting if the command response processing is not model
+ return new Model(parent::handleParsing($command, $response, $contentType));
+ } else {
+ // Only inject the schema into the model if "schemaInModel" is true
+ return new Model($this->visitResult($model, $command, $response), $this->schemaInModels ? $model : null);
+ }
+ }
+
+ /**
+ * Parse a class object
+ *
+ * @param CommandInterface $command Command to parse into an object
+ *
+ * @return mixed
+ * @throws ResponseClassException
+ */
+ protected function parseClass(CommandInterface $command)
+ {
+ // Emit the operation.parse_class event. If a listener injects a 'result' property, then that will be the result
+ $event = new CreateResponseClassEvent(array('command' => $command));
+ $command->getClient()->getEventDispatcher()->dispatch('command.parse_response', $event);
+ if ($result = $event->getResult()) {
+ return $result;
+ }
+
+ $className = $command->getOperation()->getResponseClass();
+ if (!method_exists($className, 'fromCommand')) {
+ throw new ResponseClassException("{$className} must exist and implement a static fromCommand() method");
+ }
+
+ return $className::fromCommand($command);
+ }
+
+ /**
+ * Perform transformations on the result array
+ *
+ * @param Parameter $model Model that defines the structure
+ * @param CommandInterface $command Command that performed the operation
+ * @param Response $response Response received
+ *
+ * @return array Returns the array of result data
+ */
+ protected function visitResult(Parameter $model, CommandInterface $command, Response $response)
+ {
+ $foundVisitors = $result = $knownProps = array();
+ $props = $model->getProperties();
+
+ foreach ($props as $schema) {
+ if ($location = $schema->getLocation()) {
+ // Trigger the before method on the first found visitor of this type
+ if (!isset($foundVisitors[$location])) {
+ $foundVisitors[$location] = $this->factory->getResponseVisitor($location);
+ $foundVisitors[$location]->before($command, $result);
+ }
+ }
+ }
+
+ // Visit additional properties when it is an actual schema
+ if (($additional = $model->getAdditionalProperties()) instanceof Parameter) {
+ $this->visitAdditionalProperties($model, $command, $response, $additional, $result, $foundVisitors);
+ }
+
+ // Apply the parameter value with the location visitor
+ foreach ($props as $schema) {
+ $knownProps[$schema->getName()] = 1;
+ if ($location = $schema->getLocation()) {
+ $foundVisitors[$location]->visit($command, $response, $schema, $result);
+ }
+ }
+
+ // Remove any unknown and potentially unsafe top-level properties
+ if ($additional === false) {
+ $result = array_intersect_key($result, $knownProps);
+ }
+
+ // Call the after() method of each found visitor
+ foreach ($foundVisitors as $visitor) {
+ $visitor->after($command);
+ }
+
+ return $result;
+ }
+
+ protected function visitAdditionalProperties(
+ Parameter $model,
+ CommandInterface $command,
+ Response $response,
+ Parameter $additional,
+ &$result,
+ array &$foundVisitors
+ ) {
+ // Only visit when a location is specified
+ if ($location = $additional->getLocation()) {
+ if (!isset($foundVisitors[$location])) {
+ $foundVisitors[$location] = $this->factory->getResponseVisitor($location);
+ $foundVisitors[$location]->before($command, $result);
+ }
+ // Only traverse if an array was parsed from the before() visitors
+ if (is_array($result)) {
+ // Find each additional property
+ foreach (array_keys($result) as $key) {
+ // Check if the model actually knows this property. If so, then it is not additional
+ if (!$model->getProperty($key)) {
+ // Set the name to the key so that we can parse it with each visitor
+ $additional->setName($key);
+ $foundVisitors[$location]->visit($command, $response, $additional, $result);
+ }
+ }
+ // Reset the additionalProperties name to null
+ $additional->setName(null);
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php
new file mode 100755
index 0000000..60b9334
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Command/RequestSerializerInterface.php
@@ -0,0 +1,21 @@
+ true, 'httpMethod' => true, 'uri' => true, 'class' => true, 'responseClass' => true,
+ 'responseType' => true, 'responseNotes' => true, 'notes' => true, 'summary' => true, 'documentationUrl' => true,
+ 'deprecated' => true, 'data' => true, 'parameters' => true, 'additionalParameters' => true,
+ 'errorResponses' => true
+ );
+
+ /** @var array Parameters */
+ protected $parameters = array();
+
+ /** @var Parameter Additional parameters schema */
+ protected $additionalParameters;
+
+ /** @var string Name of the command */
+ protected $name;
+
+ /** @var string HTTP method */
+ protected $httpMethod;
+
+ /** @var string This is a short summary of what the operation does */
+ protected $summary;
+
+ /** @var string A longer text field to explain the behavior of the operation. */
+ protected $notes;
+
+ /** @var string Reference URL providing more information about the operation */
+ protected $documentationUrl;
+
+ /** @var string HTTP URI of the command */
+ protected $uri;
+
+ /** @var string Class of the command object */
+ protected $class;
+
+ /** @var string This is what is returned from the method */
+ protected $responseClass;
+
+ /** @var string Type information about the response */
+ protected $responseType;
+
+ /** @var string Information about the response returned by the operation */
+ protected $responseNotes;
+
+ /** @var bool Whether or not the command is deprecated */
+ protected $deprecated;
+
+ /** @var array Array of errors that could occur when running the command */
+ protected $errorResponses;
+
+ /** @var ServiceDescriptionInterface */
+ protected $description;
+
+ /** @var array Extra operation information */
+ protected $data;
+
+ /**
+ * Builds an Operation object using an array of configuration data:
+ * - name: (string) Name of the command
+ * - httpMethod: (string) HTTP method of the operation
+ * - uri: (string) URI template that can create a relative or absolute URL
+ * - class: (string) Concrete class that implements this command
+ * - parameters: (array) Associative array of parameters for the command. {@see Parameter} for information.
+ * - summary: (string) This is a short summary of what the operation does
+ * - notes: (string) A longer text field to explain the behavior of the operation.
+ * - documentationUrl: (string) Reference URL providing more information about the operation
+ * - responseClass: (string) This is what is returned from the method. Can be a primitive, PSR-0 compliant
+ * class name, or model.
+ * - responseNotes: (string) Information about the response returned by the operation
+ * - responseType: (string) One of 'primitive', 'class', 'model', or 'documentation'. If not specified, this
+ * value will be automatically inferred based on whether or not there is a model matching the
+ * name, if a matching PSR-0 compliant class name is found, or set to 'primitive' by default.
+ * - deprecated: (bool) Set to true if this is a deprecated command
+ * - errorResponses: (array) Errors that could occur when executing the command. Array of hashes, each with a
+ * 'code' (the HTTP response code), 'reason' (response reason phrase or description of the
+ * error), and 'class' (a custom exception class that would be thrown if the error is
+ * encountered).
+ * - data: (array) Any extra data that might be used to help build or serialize the operation
+ * - additionalParameters: (null|array) Parameter schema to use when an option is passed to the operation that is
+ * not in the schema
+ *
+ * @param array $config Array of configuration data
+ * @param ServiceDescriptionInterface $description Service description used to resolve models if $ref tags are found
+ */
+ public function __construct(array $config = array(), ServiceDescriptionInterface $description = null)
+ {
+ $this->description = $description;
+
+ // Get the intersection of the available properties and properties set on the operation
+ foreach (array_intersect_key($config, self::$properties) as $key => $value) {
+ $this->{$key} = $value;
+ }
+
+ $this->class = $this->class ?: self::DEFAULT_COMMAND_CLASS;
+ $this->deprecated = (bool) $this->deprecated;
+ $this->errorResponses = $this->errorResponses ?: array();
+ $this->data = $this->data ?: array();
+
+ if (!$this->responseClass) {
+ $this->responseClass = 'array';
+ $this->responseType = 'primitive';
+ } elseif ($this->responseType) {
+ // Set the response type to perform validation
+ $this->setResponseType($this->responseType);
+ } else {
+ // A response class was set and no response type was set, so guess what the type is
+ $this->inferResponseType();
+ }
+
+ // Parameters need special handling when adding
+ if ($this->parameters) {
+ foreach ($this->parameters as $name => $param) {
+ if ($param instanceof Parameter) {
+ $param->setName($name)->setParent($this);
+ } elseif (is_array($param)) {
+ $param['name'] = $name;
+ $this->addParam(new Parameter($param, $this->description));
+ }
+ }
+ }
+
+ if ($this->additionalParameters) {
+ if ($this->additionalParameters instanceof Parameter) {
+ $this->additionalParameters->setParent($this);
+ } elseif (is_array($this->additionalParameters)) {
+ $this->setadditionalParameters(new Parameter($this->additionalParameters, $this->description));
+ }
+ }
+ }
+
+ public function toArray()
+ {
+ $result = array();
+ // Grab valid properties and filter out values that weren't set
+ foreach (array_keys(self::$properties) as $check) {
+ if ($value = $this->{$check}) {
+ $result[$check] = $value;
+ }
+ }
+ // Remove the name property
+ unset($result['name']);
+ // Parameters need to be converted to arrays
+ $result['parameters'] = array();
+ foreach ($this->parameters as $key => $param) {
+ $result['parameters'][$key] = $param->toArray();
+ }
+ // Additional parameters need to be cast to an array
+ if ($this->additionalParameters instanceof Parameter) {
+ $result['additionalParameters'] = $this->additionalParameters->toArray();
+ }
+
+ return $result;
+ }
+
+ public function getServiceDescription()
+ {
+ return $this->description;
+ }
+
+ public function setServiceDescription(ServiceDescriptionInterface $description)
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
+ public function getParams()
+ {
+ return $this->parameters;
+ }
+
+ public function getParamNames()
+ {
+ return array_keys($this->parameters);
+ }
+
+ public function hasParam($name)
+ {
+ return isset($this->parameters[$name]);
+ }
+
+ public function getParam($param)
+ {
+ return isset($this->parameters[$param]) ? $this->parameters[$param] : null;
+ }
+
+ /**
+ * Add a parameter to the command
+ *
+ * @param Parameter $param Parameter to add
+ *
+ * @return self
+ */
+ public function addParam(Parameter $param)
+ {
+ $this->parameters[$param->getName()] = $param;
+ $param->setParent($this);
+
+ return $this;
+ }
+
+ /**
+ * Remove a parameter from the command
+ *
+ * @param string $name Name of the parameter to remove
+ *
+ * @return self
+ */
+ public function removeParam($name)
+ {
+ unset($this->parameters[$name]);
+
+ return $this;
+ }
+
+ public function getHttpMethod()
+ {
+ return $this->httpMethod;
+ }
+
+ /**
+ * Set the HTTP method of the command
+ *
+ * @param string $httpMethod Method to set
+ *
+ * @return self
+ */
+ public function setHttpMethod($httpMethod)
+ {
+ $this->httpMethod = $httpMethod;
+
+ return $this;
+ }
+
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+ /**
+ * Set the concrete class of the command
+ *
+ * @param string $className Concrete class name
+ *
+ * @return self
+ */
+ public function setClass($className)
+ {
+ $this->class = $className;
+
+ return $this;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Set the name of the command
+ *
+ * @param string $name Name of the command
+ *
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getSummary()
+ {
+ return $this->summary;
+ }
+
+ /**
+ * Set a short summary of what the operation does
+ *
+ * @param string $summary Short summary of the operation
+ *
+ * @return self
+ */
+ public function setSummary($summary)
+ {
+ $this->summary = $summary;
+
+ return $this;
+ }
+
+ public function getNotes()
+ {
+ return $this->notes;
+ }
+
+ /**
+ * Set a longer text field to explain the behavior of the operation.
+ *
+ * @param string $notes Notes on the operation
+ *
+ * @return self
+ */
+ public function setNotes($notes)
+ {
+ $this->notes = $notes;
+
+ return $this;
+ }
+
+ public function getDocumentationUrl()
+ {
+ return $this->documentationUrl;
+ }
+
+ /**
+ * Set the URL pointing to additional documentation on the command
+ *
+ * @param string $docUrl Documentation URL
+ *
+ * @return self
+ */
+ public function setDocumentationUrl($docUrl)
+ {
+ $this->documentationUrl = $docUrl;
+
+ return $this;
+ }
+
+ public function getResponseClass()
+ {
+ return $this->responseClass;
+ }
+
+ /**
+ * Set what is returned from the method. Can be a primitive, class name, or model. For example: 'array',
+ * 'Guzzle\\Foo\\Baz', or 'MyModelName' (to reference a model by ID).
+ *
+ * @param string $responseClass Type of response
+ *
+ * @return self
+ */
+ public function setResponseClass($responseClass)
+ {
+ $this->responseClass = $responseClass;
+ $this->inferResponseType();
+
+ return $this;
+ }
+
+ public function getResponseType()
+ {
+ return $this->responseType;
+ }
+
+ /**
+ * Set qualifying information about the responseClass. One of 'primitive', 'class', 'model', or 'documentation'
+ *
+ * @param string $responseType Response type information
+ *
+ * @return self
+ * @throws InvalidArgumentException
+ */
+ public function setResponseType($responseType)
+ {
+ static $types = array(
+ self::TYPE_PRIMITIVE => true,
+ self::TYPE_CLASS => true,
+ self::TYPE_MODEL => true,
+ self::TYPE_DOCUMENTATION => true
+ );
+ if (!isset($types[$responseType])) {
+ throw new InvalidArgumentException('responseType must be one of ' . implode(', ', array_keys($types)));
+ }
+
+ $this->responseType = $responseType;
+
+ return $this;
+ }
+
+ public function getResponseNotes()
+ {
+ return $this->responseNotes;
+ }
+
+ /**
+ * Set notes about the response of the operation
+ *
+ * @param string $notes Response notes
+ *
+ * @return self
+ */
+ public function setResponseNotes($notes)
+ {
+ $this->responseNotes = $notes;
+
+ return $this;
+ }
+
+ public function getDeprecated()
+ {
+ return $this->deprecated;
+ }
+
+ /**
+ * Set whether or not the command is deprecated
+ *
+ * @param bool $isDeprecated Set to true to mark as deprecated
+ *
+ * @return self
+ */
+ public function setDeprecated($isDeprecated)
+ {
+ $this->deprecated = $isDeprecated;
+
+ return $this;
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ /**
+ * Set the URI template of the command
+ *
+ * @param string $uri URI template to set
+ *
+ * @return self
+ */
+ public function setUri($uri)
+ {
+ $this->uri = $uri;
+
+ return $this;
+ }
+
+ public function getErrorResponses()
+ {
+ return $this->errorResponses;
+ }
+
+ /**
+ * Add an error to the command
+ *
+ * @param string $code HTTP response code
+ * @param string $reason HTTP response reason phrase or information about the error
+ * @param string $class Exception class associated with the error
+ *
+ * @return self
+ */
+ public function addErrorResponse($code, $reason, $class)
+ {
+ $this->errorResponses[] = array('code' => $code, 'reason' => $reason, 'class' => $class);
+
+ return $this;
+ }
+
+ /**
+ * Set all of the error responses of the operation
+ *
+ * @param array $errorResponses Hash of error name to a hash containing a code, reason, class
+ *
+ * @return self
+ */
+ public function setErrorResponses(array $errorResponses)
+ {
+ $this->errorResponses = $errorResponses;
+
+ return $this;
+ }
+
+ public function getData($name)
+ {
+ return isset($this->data[$name]) ? $this->data[$name] : null;
+ }
+
+ /**
+ * Set a particular data point on the operation
+ *
+ * @param string $name Name of the data value
+ * @param mixed $value Value to set
+ *
+ * @return self
+ */
+ public function setData($name, $value)
+ {
+ $this->data[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get the additionalParameters of the operation
+ *
+ * @return Parameter|null
+ */
+ public function getAdditionalParameters()
+ {
+ return $this->additionalParameters;
+ }
+
+ /**
+ * Set the additionalParameters of the operation
+ *
+ * @param Parameter|null $parameter Parameter to set
+ *
+ * @return self
+ */
+ public function setAdditionalParameters($parameter)
+ {
+ if ($this->additionalParameters = $parameter) {
+ $this->additionalParameters->setParent($this);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Infer the response type from the responseClass value
+ */
+ protected function inferResponseType()
+ {
+ static $primitives = array('array' => 1, 'boolean' => 1, 'string' => 1, 'integer' => 1, '' => 1);
+ if (isset($primitives[$this->responseClass])) {
+ $this->responseType = self::TYPE_PRIMITIVE;
+ } elseif ($this->description && $this->description->hasModel($this->responseClass)) {
+ $this->responseType = self::TYPE_MODEL;
+ } else {
+ $this->responseType = self::TYPE_CLASS;
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php
new file mode 100755
index 0000000..4de41bd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/OperationInterface.php
@@ -0,0 +1,159 @@
+getModel($data['$ref'])) {
+ $data = $model->toArray() + $data;
+ }
+ } elseif (isset($data['extends'])) {
+ // If this parameter extends from another parameter then start with the actual data
+ // union in the parent's data (e.g. actual supersedes parent)
+ if ($extends = $description->getModel($data['extends'])) {
+ $data += $extends->toArray();
+ }
+ }
+ }
+
+ // Pull configuration data into the parameter
+ foreach ($data as $key => $value) {
+ $this->{$key} = $value;
+ }
+
+ $this->serviceDescription = $description;
+ $this->required = (bool) $this->required;
+ $this->data = (array) $this->data;
+
+ if ($this->filters) {
+ $this->setFilters((array) $this->filters);
+ }
+
+ if ($this->type == 'object' && $this->additionalProperties === null) {
+ $this->additionalProperties = true;
+ }
+ }
+
+ /**
+ * Convert the object to an array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ static $checks = array('required', 'description', 'static', 'type', 'format', 'instanceOf', 'location', 'sentAs',
+ 'pattern', 'minimum', 'maximum', 'minItems', 'maxItems', 'minLength', 'maxLength', 'data', 'enum',
+ 'filters');
+
+ $result = array();
+
+ // Anything that is in the `Items` attribute of an array *must* include it's name if available
+ if ($this->parent instanceof self && $this->parent->getType() == 'array' && isset($this->name)) {
+ $result['name'] = $this->name;
+ }
+
+ foreach ($checks as $c) {
+ if ($value = $this->{$c}) {
+ $result[$c] = $value;
+ }
+ }
+
+ if ($this->default !== null) {
+ $result['default'] = $this->default;
+ }
+
+ if ($this->items !== null) {
+ $result['items'] = $this->getItems()->toArray();
+ }
+
+ if ($this->additionalProperties !== null) {
+ $result['additionalProperties'] = $this->getAdditionalProperties();
+ if ($result['additionalProperties'] instanceof self) {
+ $result['additionalProperties'] = $result['additionalProperties']->toArray();
+ }
+ }
+
+ if ($this->type == 'object' && $this->properties) {
+ $result['properties'] = array();
+ foreach ($this->getProperties() as $name => $property) {
+ $result['properties'][$name] = $property->toArray();
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get the default or static value of the command based on a value
+ *
+ * @param string $value Value that is currently set
+ *
+ * @return mixed Returns the value, a static value if one is present, or a default value
+ */
+ public function getValue($value)
+ {
+ if ($this->static || ($this->default !== null && $value === null)) {
+ return $this->default;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Run a value through the filters OR format attribute associated with the parameter
+ *
+ * @param mixed $value Value to filter
+ *
+ * @return mixed Returns the filtered value
+ */
+ public function filter($value)
+ {
+ // Formats are applied exclusively and supersed filters
+ if ($this->format) {
+ return SchemaFormatter::format($this->format, $value);
+ }
+
+ // Convert Boolean values
+ if ($this->type == 'boolean' && !is_bool($value)) {
+ $value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
+ }
+
+ // Apply filters to the value
+ if ($this->filters) {
+ foreach ($this->filters as $filter) {
+ if (is_array($filter)) {
+ // Convert complex filters that hold value place holders
+ foreach ($filter['args'] as &$data) {
+ if ($data == '@value') {
+ $data = $value;
+ } elseif ($data == '@api') {
+ $data = $this;
+ }
+ }
+ $value = call_user_func_array($filter['method'], $filter['args']);
+ } else {
+ $value = call_user_func($filter, $value);
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the name of the parameter
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get the key of the parameter, where sentAs will supersede name if it is set
+ *
+ * @return string
+ */
+ public function getWireName()
+ {
+ return $this->sentAs ?: $this->name;
+ }
+
+ /**
+ * Set the name of the parameter
+ *
+ * @param string $name Name to set
+ *
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ /**
+ * Get the type(s) of the parameter
+ *
+ * @return string|array
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set the type(s) of the parameter
+ *
+ * @param string|array $type Type of parameter or array of simple types used in a union
+ *
+ * @return self
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ /**
+ * Get if the parameter is required
+ *
+ * @return bool
+ */
+ public function getRequired()
+ {
+ return $this->required;
+ }
+
+ /**
+ * Set if the parameter is required
+ *
+ * @param bool $isRequired Whether or not the parameter is required
+ *
+ * @return self
+ */
+ public function setRequired($isRequired)
+ {
+ $this->required = (bool) $isRequired;
+
+ return $this;
+ }
+
+ /**
+ * Get the default value of the parameter
+ *
+ * @return string|null
+ */
+ public function getDefault()
+ {
+ return $this->default;
+ }
+
+ /**
+ * Set the default value of the parameter
+ *
+ * @param string|null $default Default value to set
+ *
+ * @return self
+ */
+ public function setDefault($default)
+ {
+ $this->default = $default;
+
+ return $this;
+ }
+
+ /**
+ * Get the description of the parameter
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ /**
+ * Set the description of the parameter
+ *
+ * @param string $description Description
+ *
+ * @return self
+ */
+ public function setDescription($description)
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
+ /**
+ * Get the minimum acceptable value for an integer
+ *
+ * @return int|null
+ */
+ public function getMinimum()
+ {
+ return $this->minimum;
+ }
+
+ /**
+ * Set the minimum acceptable value for an integer
+ *
+ * @param int|null $min Minimum
+ *
+ * @return self
+ */
+ public function setMinimum($min)
+ {
+ $this->minimum = $min;
+
+ return $this;
+ }
+
+ /**
+ * Get the maximum acceptable value for an integer
+ *
+ * @return int|null
+ */
+ public function getMaximum()
+ {
+ return $this->maximum;
+ }
+
+ /**
+ * Set the maximum acceptable value for an integer
+ *
+ * @param int $max Maximum
+ *
+ * @return self
+ */
+ public function setMaximum($max)
+ {
+ $this->maximum = $max;
+
+ return $this;
+ }
+
+ /**
+ * Get the minimum allowed length of a string value
+ *
+ * @return int
+ */
+ public function getMinLength()
+ {
+ return $this->minLength;
+ }
+
+ /**
+ * Set the minimum allowed length of a string value
+ *
+ * @param int|null $min Minimum
+ *
+ * @return self
+ */
+ public function setMinLength($min)
+ {
+ $this->minLength = $min;
+
+ return $this;
+ }
+
+ /**
+ * Get the maximum allowed length of a string value
+ *
+ * @return int|null
+ */
+ public function getMaxLength()
+ {
+ return $this->maxLength;
+ }
+
+ /**
+ * Set the maximum allowed length of a string value
+ *
+ * @param int $max Maximum length
+ *
+ * @return self
+ */
+ public function setMaxLength($max)
+ {
+ $this->maxLength = $max;
+
+ return $this;
+ }
+
+ /**
+ * Get the maximum allowed number of items in an array value
+ *
+ * @return int|null
+ */
+ public function getMaxItems()
+ {
+ return $this->maxItems;
+ }
+
+ /**
+ * Set the maximum allowed number of items in an array value
+ *
+ * @param int $max Maximum
+ *
+ * @return self
+ */
+ public function setMaxItems($max)
+ {
+ $this->maxItems = $max;
+
+ return $this;
+ }
+
+ /**
+ * Get the minimum allowed number of items in an array value
+ *
+ * @return int
+ */
+ public function getMinItems()
+ {
+ return $this->minItems;
+ }
+
+ /**
+ * Set the minimum allowed number of items in an array value
+ *
+ * @param int|null $min Minimum
+ *
+ * @return self
+ */
+ public function setMinItems($min)
+ {
+ $this->minItems = $min;
+
+ return $this;
+ }
+
+ /**
+ * Get the location of the parameter
+ *
+ * @return string|null
+ */
+ public function getLocation()
+ {
+ return $this->location;
+ }
+
+ /**
+ * Set the location of the parameter
+ *
+ * @param string|null $location Location of the parameter
+ *
+ * @return self
+ */
+ public function setLocation($location)
+ {
+ $this->location = $location;
+
+ return $this;
+ }
+
+ /**
+ * Get the sentAs attribute of the parameter that used with locations to sentAs an attribute when it is being
+ * applied to a location.
+ *
+ * @return string|null
+ */
+ public function getSentAs()
+ {
+ return $this->sentAs;
+ }
+
+ /**
+ * Set the sentAs attribute
+ *
+ * @param string|null $name Name of the value as it is sent over the wire
+ *
+ * @return self
+ */
+ public function setSentAs($name)
+ {
+ $this->sentAs = $name;
+
+ return $this;
+ }
+
+ /**
+ * Retrieve a known property from the parameter by name or a data property by name. When not specific name value
+ * is specified, all data properties will be returned.
+ *
+ * @param string|null $name Specify a particular property name to retrieve
+ *
+ * @return array|mixed|null
+ */
+ public function getData($name = null)
+ {
+ if (!$name) {
+ return $this->data;
+ }
+
+ if (isset($this->data[$name])) {
+ return $this->data[$name];
+ } elseif (isset($this->{$name})) {
+ return $this->{$name};
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the extra data properties of the parameter or set a specific extra property
+ *
+ * @param string|array|null $nameOrData The name of a specific extra to set or an array of extras to set
+ * @param mixed|null $data When setting a specific extra property, specify the data to set for it
+ *
+ * @return self
+ */
+ public function setData($nameOrData, $data = null)
+ {
+ if (is_array($nameOrData)) {
+ $this->data = $nameOrData;
+ } else {
+ $this->data[$nameOrData] = $data;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get whether or not the default value can be changed
+ *
+ * @return mixed|null
+ */
+ public function getStatic()
+ {
+ return $this->static;
+ }
+
+ /**
+ * Set to true if the default value cannot be changed
+ *
+ * @param bool $static True or false
+ *
+ * @return self
+ */
+ public function setStatic($static)
+ {
+ $this->static = (bool) $static;
+
+ return $this;
+ }
+
+ /**
+ * Get an array of filters used by the parameter
+ *
+ * @return array
+ */
+ public function getFilters()
+ {
+ return $this->filters ?: array();
+ }
+
+ /**
+ * Set the array of filters used by the parameter
+ *
+ * @param array $filters Array of functions to use as filters
+ *
+ * @return self
+ */
+ public function setFilters(array $filters)
+ {
+ $this->filters = array();
+ foreach ($filters as $filter) {
+ $this->addFilter($filter);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a filter to the parameter
+ *
+ * @param string|array $filter Method to filter the value through
+ *
+ * @return self
+ * @throws InvalidArgumentException
+ */
+ public function addFilter($filter)
+ {
+ if (is_array($filter)) {
+ if (!isset($filter['method'])) {
+ throw new InvalidArgumentException('A [method] value must be specified for each complex filter');
+ }
+ }
+
+ if (!$this->filters) {
+ $this->filters = array($filter);
+ } else {
+ $this->filters[] = $filter;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the parent object (an {@see OperationInterface} or {@see Parameter}
+ *
+ * @return OperationInterface|Parameter|null
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Set the parent object of the parameter
+ *
+ * @param OperationInterface|Parameter|null $parent Parent container of the parameter
+ *
+ * @return self
+ */
+ public function setParent($parent)
+ {
+ $this->parent = $parent;
+
+ return $this;
+ }
+
+ /**
+ * Get the properties of the parameter
+ *
+ * @return array
+ */
+ public function getProperties()
+ {
+ if (!$this->propertiesCache) {
+ $this->propertiesCache = array();
+ foreach (array_keys($this->properties) as $name) {
+ $this->propertiesCache[$name] = $this->getProperty($name);
+ }
+ }
+
+ return $this->propertiesCache;
+ }
+
+ /**
+ * Get a specific property from the parameter
+ *
+ * @param string $name Name of the property to retrieve
+ *
+ * @return null|Parameter
+ */
+ public function getProperty($name)
+ {
+ if (!isset($this->properties[$name])) {
+ return null;
+ }
+
+ if (!($this->properties[$name] instanceof self)) {
+ $this->properties[$name]['name'] = $name;
+ $this->properties[$name] = new static($this->properties[$name], $this->serviceDescription);
+ $this->properties[$name]->setParent($this);
+ }
+
+ return $this->properties[$name];
+ }
+
+ /**
+ * Remove a property from the parameter
+ *
+ * @param string $name Name of the property to remove
+ *
+ * @return self
+ */
+ public function removeProperty($name)
+ {
+ unset($this->properties[$name]);
+ $this->propertiesCache = null;
+
+ return $this;
+ }
+
+ /**
+ * Add a property to the parameter
+ *
+ * @param Parameter $property Properties to set
+ *
+ * @return self
+ */
+ public function addProperty(Parameter $property)
+ {
+ $this->properties[$property->getName()] = $property;
+ $property->setParent($this);
+ $this->propertiesCache = null;
+
+ return $this;
+ }
+
+ /**
+ * Get the additionalProperties value of the parameter
+ *
+ * @return bool|Parameter|null
+ */
+ public function getAdditionalProperties()
+ {
+ if (is_array($this->additionalProperties)) {
+ $this->additionalProperties = new static($this->additionalProperties, $this->serviceDescription);
+ $this->additionalProperties->setParent($this);
+ }
+
+ return $this->additionalProperties;
+ }
+
+ /**
+ * Set the additionalProperties value of the parameter
+ *
+ * @param bool|Parameter|null $additional Boolean to allow any, an Parameter to specify a schema, or false to disallow
+ *
+ * @return self
+ */
+ public function setAdditionalProperties($additional)
+ {
+ $this->additionalProperties = $additional;
+
+ return $this;
+ }
+
+ /**
+ * Set the items data of the parameter
+ *
+ * @param Parameter|null $items Items to set
+ *
+ * @return self
+ */
+ public function setItems(Parameter $items = null)
+ {
+ if ($this->items = $items) {
+ $this->items->setParent($this);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the item data of the parameter
+ *
+ * @return Parameter|null
+ */
+ public function getItems()
+ {
+ if (is_array($this->items)) {
+ $this->items = new static($this->items, $this->serviceDescription);
+ $this->items->setParent($this);
+ }
+
+ return $this->items;
+ }
+
+ /**
+ * Get the class that the parameter must implement
+ *
+ * @return null|string
+ */
+ public function getInstanceOf()
+ {
+ return $this->instanceOf;
+ }
+
+ /**
+ * Set the class that the parameter must be an instance of
+ *
+ * @param string|null $instanceOf Class or interface name
+ *
+ * @return self
+ */
+ public function setInstanceOf($instanceOf)
+ {
+ $this->instanceOf = $instanceOf;
+
+ return $this;
+ }
+
+ /**
+ * Get the enum of strings that are valid for the parameter
+ *
+ * @return array|null
+ */
+ public function getEnum()
+ {
+ return $this->enum;
+ }
+
+ /**
+ * Set the enum of strings that are valid for the parameter
+ *
+ * @param array|null $enum Array of strings or null
+ *
+ * @return self
+ */
+ public function setEnum(array $enum = null)
+ {
+ $this->enum = $enum;
+
+ return $this;
+ }
+
+ /**
+ * Get the regex pattern that must match a value when the value is a string
+ *
+ * @return string
+ */
+ public function getPattern()
+ {
+ return $this->pattern;
+ }
+
+ /**
+ * Set the regex pattern that must match a value when the value is a string
+ *
+ * @param string $pattern Regex pattern
+ *
+ * @return self
+ */
+ public function setPattern($pattern)
+ {
+ $this->pattern = $pattern;
+
+ return $this;
+ }
+
+ /**
+ * Get the format attribute of the schema
+ *
+ * @return string
+ */
+ public function getFormat()
+ {
+ return $this->format;
+ }
+
+ /**
+ * Set the format attribute of the schema
+ *
+ * @param string $format Format to set (e.g. date, date-time, timestamp, time, date-time-http)
+ *
+ * @return self
+ */
+ public function setFormat($format)
+ {
+ $this->format = $format;
+
+ return $this;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php
new file mode 100755
index 0000000..7f47fc9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaFormatter.php
@@ -0,0 +1,156 @@
+setTimezone(self::getUtcTimeZone())->format($format);
+ }
+
+ throw new InvalidArgumentException('Date/Time values must be either a string, integer, or DateTime object');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php
new file mode 100755
index 0000000..b045422
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/SchemaValidator.php
@@ -0,0 +1,291 @@
+castIntegerToStringType = $castIntegerToStringType;
+ }
+
+ public function validate(Parameter $param, &$value)
+ {
+ $this->errors = array();
+ $this->recursiveProcess($param, $value);
+
+ if (empty($this->errors)) {
+ return true;
+ } else {
+ sort($this->errors);
+ return false;
+ }
+ }
+
+ /**
+ * Get the errors encountered while validating
+ *
+ * @return array
+ */
+ public function getErrors()
+ {
+ return $this->errors ?: array();
+ }
+
+ /**
+ * Recursively validate a parameter
+ *
+ * @param Parameter $param API parameter being validated
+ * @param mixed $value Value to validate and validate. The value may change during this validate.
+ * @param string $path Current validation path (used for error reporting)
+ * @param int $depth Current depth in the validation validate
+ *
+ * @return bool Returns true if valid, or false if invalid
+ */
+ protected function recursiveProcess(Parameter $param, &$value, $path = '', $depth = 0)
+ {
+ // Update the value by adding default or static values
+ $value = $param->getValue($value);
+
+ $required = $param->getRequired();
+ // if the value is null and the parameter is not required or is static, then skip any further recursion
+ if ((null === $value && !$required) || $param->getStatic()) {
+ return true;
+ }
+
+ $type = $param->getType();
+ // Attempt to limit the number of times is_array is called by tracking if the value is an array
+ $valueIsArray = is_array($value);
+ // If a name is set then update the path so that validation messages are more helpful
+ if ($name = $param->getName()) {
+ $path .= "[{$name}]";
+ }
+
+ if ($type == 'object') {
+
+ // Objects are either associative arrays, ToArrayInterface, or some other object
+ if ($param->getInstanceOf()) {
+ $instance = $param->getInstanceOf();
+ if (!($value instanceof $instance)) {
+ $this->errors[] = "{$path} must be an instance of {$instance}";
+ return false;
+ }
+ }
+
+ // Determine whether or not this "value" has properties and should be traversed
+ $traverse = $temporaryValue = false;
+
+ // Convert the value to an array
+ if (!$valueIsArray && $value instanceof ToArrayInterface) {
+ $value = $value->toArray();
+ }
+
+ if ($valueIsArray) {
+ // Ensure that the array is associative and not numerically indexed
+ if (isset($value[0])) {
+ $this->errors[] = "{$path} must be an array of properties. Got a numerically indexed array.";
+ return false;
+ }
+ $traverse = true;
+ } elseif ($value === null) {
+ // Attempt to let the contents be built up by default values if possible
+ $value = array();
+ $temporaryValue = $valueIsArray = $traverse = true;
+ }
+
+ if ($traverse) {
+
+ if ($properties = $param->getProperties()) {
+ // if properties were found, the validate each property of the value
+ foreach ($properties as $property) {
+ $name = $property->getName();
+ if (isset($value[$name])) {
+ $this->recursiveProcess($property, $value[$name], $path, $depth + 1);
+ } else {
+ $current = null;
+ $this->recursiveProcess($property, $current, $path, $depth + 1);
+ // Only set the value if it was populated with something
+ if (null !== $current) {
+ $value[$name] = $current;
+ }
+ }
+ }
+ }
+
+ $additional = $param->getAdditionalProperties();
+ if ($additional !== true) {
+ // If additional properties were found, then validate each against the additionalProperties attr.
+ $keys = array_keys($value);
+ // Determine the keys that were specified that were not listed in the properties of the schema
+ $diff = array_diff($keys, array_keys($properties));
+ if (!empty($diff)) {
+ // Determine which keys are not in the properties
+ if ($additional instanceOf Parameter) {
+ foreach ($diff as $key) {
+ $this->recursiveProcess($additional, $value[$key], "{$path}[{$key}]", $depth);
+ }
+ } else {
+ // if additionalProperties is set to false and there are additionalProperties in the values, then fail
+ foreach ($diff as $prop) {
+ $this->errors[] = sprintf('%s[%s] is not an allowed property', $path, $prop);
+ }
+ }
+ }
+ }
+
+ // A temporary value will be used to traverse elements that have no corresponding input value.
+ // This allows nested required parameters with default values to bubble up into the input.
+ // Here we check if we used a temp value and nothing bubbled up, then we need to remote the value.
+ if ($temporaryValue && empty($value)) {
+ $value = null;
+ $valueIsArray = false;
+ }
+ }
+
+ } elseif ($type == 'array' && $valueIsArray && $param->getItems()) {
+ foreach ($value as $i => &$item) {
+ // Validate each item in an array against the items attribute of the schema
+ $this->recursiveProcess($param->getItems(), $item, $path . "[{$i}]", $depth + 1);
+ }
+ }
+
+ // If the value is required and the type is not null, then there is an error if the value is not set
+ if ($required && $value === null && $type != 'null') {
+ $message = "{$path} is " . ($param->getType() ? ('a required ' . implode(' or ', (array) $param->getType())) : 'required');
+ if ($param->getDescription()) {
+ $message .= ': ' . $param->getDescription();
+ }
+ $this->errors[] = $message;
+ return false;
+ }
+
+ // Validate that the type is correct. If the type is string but an integer was passed, the class can be
+ // instructed to cast the integer to a string to pass validation. This is the default behavior.
+ if ($type && (!$type = $this->determineType($type, $value))) {
+ if ($this->castIntegerToStringType && $param->getType() == 'string' && is_integer($value)) {
+ $value = (string) $value;
+ } else {
+ $this->errors[] = "{$path} must be of type " . implode(' or ', (array) $param->getType());
+ }
+ }
+
+ // Perform type specific validation for strings, arrays, and integers
+ if ($type == 'string') {
+
+ // Strings can have enums which are a list of predefined values
+ if (($enum = $param->getEnum()) && !in_array($value, $enum)) {
+ $this->errors[] = "{$path} must be one of " . implode(' or ', array_map(function ($s) {
+ return '"' . addslashes($s) . '"';
+ }, $enum));
+ }
+ // Strings can have a regex pattern that the value must match
+ if (($pattern = $param->getPattern()) && !preg_match($pattern, $value)) {
+ $this->errors[] = "{$path} must match the following regular expression: {$pattern}";
+ }
+
+ $strLen = null;
+ if ($min = $param->getMinLength()) {
+ $strLen = strlen($value);
+ if ($strLen < $min) {
+ $this->errors[] = "{$path} length must be greater than or equal to {$min}";
+ }
+ }
+ if ($max = $param->getMaxLength()) {
+ if (($strLen ?: strlen($value)) > $max) {
+ $this->errors[] = "{$path} length must be less than or equal to {$max}";
+ }
+ }
+
+ } elseif ($type == 'array') {
+
+ $size = null;
+ if ($min = $param->getMinItems()) {
+ $size = count($value);
+ if ($size < $min) {
+ $this->errors[] = "{$path} must contain {$min} or more elements";
+ }
+ }
+ if ($max = $param->getMaxItems()) {
+ if (($size ?: count($value)) > $max) {
+ $this->errors[] = "{$path} must contain {$max} or fewer elements";
+ }
+ }
+
+ } elseif ($type == 'integer' || $type == 'number' || $type == 'numeric') {
+ if (($min = $param->getMinimum()) && $value < $min) {
+ $this->errors[] = "{$path} must be greater than or equal to {$min}";
+ }
+ if (($max = $param->getMaximum()) && $value > $max) {
+ $this->errors[] = "{$path} must be less than or equal to {$max}";
+ }
+ }
+
+ return empty($this->errors);
+ }
+
+ /**
+ * From the allowable types, determine the type that the variable matches
+ *
+ * @param string $type Parameter type
+ * @param mixed $value Value to determine the type
+ *
+ * @return string|bool Returns the matching type on
+ */
+ protected function determineType($type, $value)
+ {
+ foreach ((array) $type as $t) {
+ if ($t == 'string' && (is_string($value) || (is_object($value) && method_exists($value, '__toString')))) {
+ return 'string';
+ } elseif ($t == 'object' && (is_array($value) || is_object($value))) {
+ return 'object';
+ } elseif ($t == 'array' && is_array($value)) {
+ return 'array';
+ } elseif ($t == 'integer' && is_integer($value)) {
+ return 'integer';
+ } elseif ($t == 'boolean' && is_bool($value)) {
+ return 'boolean';
+ } elseif ($t == 'number' && is_numeric($value)) {
+ return 'number';
+ } elseif ($t == 'numeric' && is_numeric($value)) {
+ return 'numeric';
+ } elseif ($t == 'null' && !$value) {
+ return 'null';
+ } elseif ($t == 'any') {
+ return 'any';
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php
new file mode 100755
index 0000000..286e65e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescription.php
@@ -0,0 +1,271 @@
+load($config, $options);
+ }
+
+ /**
+ * @param array $config Array of configuration data
+ */
+ public function __construct(array $config = array())
+ {
+ $this->fromArray($config);
+ }
+
+ public function serialize()
+ {
+ return json_encode($this->toArray());
+ }
+
+ public function unserialize($json)
+ {
+ $this->operations = array();
+ $this->fromArray(json_decode($json, true));
+ }
+
+ public function toArray()
+ {
+ $result = array(
+ 'name' => $this->name,
+ 'apiVersion' => $this->apiVersion,
+ 'baseUrl' => $this->baseUrl,
+ 'description' => $this->description
+ ) + $this->extraData;
+ $result['operations'] = array();
+ foreach ($this->getOperations() as $name => $operation) {
+ $result['operations'][$operation->getName() ?: $name] = $operation->toArray();
+ }
+ if (!empty($this->models)) {
+ $result['models'] = array();
+ foreach ($this->models as $id => $model) {
+ $result['models'][$id] = $model instanceof Parameter ? $model->toArray(): $model;
+ }
+ }
+
+ return array_filter($result);
+ }
+
+ public function getBaseUrl()
+ {
+ return $this->baseUrl;
+ }
+
+ /**
+ * Set the baseUrl of the description
+ *
+ * @param string $baseUrl Base URL of each operation
+ *
+ * @return self
+ */
+ public function setBaseUrl($baseUrl)
+ {
+ $this->baseUrl = $baseUrl;
+
+ return $this;
+ }
+
+ public function getOperations()
+ {
+ foreach (array_keys($this->operations) as $name) {
+ $this->getOperation($name);
+ }
+
+ return $this->operations;
+ }
+
+ public function hasOperation($name)
+ {
+ return isset($this->operations[$name]);
+ }
+
+ public function getOperation($name)
+ {
+ // Lazily retrieve and build operations
+ if (!isset($this->operations[$name])) {
+ return null;
+ }
+
+ if (!($this->operations[$name] instanceof Operation)) {
+ $this->operations[$name] = new Operation($this->operations[$name], $this);
+ }
+
+ return $this->operations[$name];
+ }
+
+ /**
+ * Add a operation to the service description
+ *
+ * @param OperationInterface $operation Operation to add
+ *
+ * @return self
+ */
+ public function addOperation(OperationInterface $operation)
+ {
+ $this->operations[$operation->getName()] = $operation->setServiceDescription($this);
+
+ return $this;
+ }
+
+ public function getModel($id)
+ {
+ if (!isset($this->models[$id])) {
+ return null;
+ }
+
+ if (!($this->models[$id] instanceof Parameter)) {
+ $this->models[$id] = new Parameter($this->models[$id] + array('name' => $id), $this);
+ }
+
+ return $this->models[$id];
+ }
+
+ public function getModels()
+ {
+ // Ensure all models are converted into parameter objects
+ foreach (array_keys($this->models) as $id) {
+ $this->getModel($id);
+ }
+
+ return $this->models;
+ }
+
+ public function hasModel($id)
+ {
+ return isset($this->models[$id]);
+ }
+
+ /**
+ * Add a model to the service description
+ *
+ * @param Parameter $model Model to add
+ *
+ * @return self
+ */
+ public function addModel(Parameter $model)
+ {
+ $this->models[$model->getName()] = $model;
+
+ return $this;
+ }
+
+ public function getApiVersion()
+ {
+ return $this->apiVersion;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ public function getData($key)
+ {
+ return isset($this->extraData[$key]) ? $this->extraData[$key] : null;
+ }
+
+ public function setData($key, $value)
+ {
+ $this->extraData[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Initialize the state from an array
+ *
+ * @param array $config Configuration data
+ * @throws InvalidArgumentException
+ */
+ protected function fromArray(array $config)
+ {
+ // Keep a list of default keys used in service descriptions that is later used to determine extra data keys
+ static $defaultKeys = array('name', 'models', 'apiVersion', 'baseUrl', 'description');
+ // Pull in the default configuration values
+ foreach ($defaultKeys as $key) {
+ if (isset($config[$key])) {
+ $this->{$key} = $config[$key];
+ }
+ }
+
+ // Account for the Swagger name for Guzzle's baseUrl
+ if (isset($config['basePath'])) {
+ $this->baseUrl = $config['basePath'];
+ }
+
+ // Ensure that the models and operations properties are always arrays
+ $this->models = (array) $this->models;
+ $this->operations = (array) $this->operations;
+
+ // We want to add operations differently than adding the other properties
+ $defaultKeys[] = 'operations';
+
+ // Create operations for each operation
+ if (isset($config['operations'])) {
+ foreach ($config['operations'] as $name => $operation) {
+ if (!($operation instanceof Operation) && !is_array($operation)) {
+ throw new InvalidArgumentException('Invalid operation in service description: '
+ . gettype($operation));
+ }
+ $this->operations[$name] = $operation;
+ }
+ }
+
+ // Get all of the additional properties of the service description and store them in a data array
+ foreach (array_diff(array_keys($config), $defaultKeys) as $key) {
+ $this->extraData[$key] = $config[$key];
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php
new file mode 100755
index 0000000..5983e58
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ServiceDescriptionInterface.php
@@ -0,0 +1,106 @@
+ $op) {
+ $name = $op['name'] = isset($op['name']) ? $op['name'] : $name;
+ // Extend other operations
+ if (!empty($op['extends'])) {
+ $this->resolveExtension($name, $op, $operations);
+ }
+ $op['parameters'] = isset($op['parameters']) ? $op['parameters'] : array();
+ $operations[$name] = $op;
+ }
+ }
+
+ return new ServiceDescription(array(
+ 'apiVersion' => isset($config['apiVersion']) ? $config['apiVersion'] : null,
+ 'baseUrl' => isset($config['baseUrl']) ? $config['baseUrl'] : null,
+ 'description' => isset($config['description']) ? $config['description'] : null,
+ 'operations' => $operations,
+ 'models' => isset($config['models']) ? $config['models'] : null
+ ) + $config);
+ }
+
+ /**
+ * @param string $name Name of the operation
+ * @param array $op Operation value array
+ * @param array $operations Currently loaded operations
+ * @throws DescriptionBuilderException when extending a non-existent operation
+ */
+ protected function resolveExtension($name, array &$op, array &$operations)
+ {
+ $resolved = array();
+ $original = empty($op['parameters']) ? false: $op['parameters'];
+ $hasClass = !empty($op['class']);
+ foreach ((array) $op['extends'] as $extendedCommand) {
+ if (empty($operations[$extendedCommand])) {
+ throw new DescriptionBuilderException("{$name} extends missing operation {$extendedCommand}");
+ }
+ $toArray = $operations[$extendedCommand];
+ $resolved = empty($resolved)
+ ? $toArray['parameters']
+ : array_merge($resolved, $toArray['parameters']);
+
+ $op = $op + $toArray;
+ if (!$hasClass && isset($toArray['class'])) {
+ $op['class'] = $toArray['class'];
+ }
+ }
+ $op['parameters'] = $original ? array_merge($resolved, $original) : $resolved;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php
new file mode 100755
index 0000000..94ca77d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Description/ValidatorInterface.php
@@ -0,0 +1,28 @@
+getMessage(), $e->getCode(), $e->getPrevious());
+ $ce->setSuccessfulRequests($e->getSuccessfulRequests());
+
+ $alreadyAddedExceptions = array();
+ foreach ($e->getFailedRequests() as $request) {
+ if ($re = $e->getExceptionForFailedRequest($request)) {
+ $alreadyAddedExceptions[] = $re;
+ $ce->addFailedRequestWithException($request, $re);
+ } else {
+ $ce->addFailedRequest($request);
+ }
+ }
+
+ // Add any exceptions that did not map to a request
+ if (count($alreadyAddedExceptions) < count($e)) {
+ foreach ($e as $ex) {
+ if (!in_array($ex, $alreadyAddedExceptions)) {
+ $ce->add($ex);
+ }
+ }
+ }
+
+ return $ce;
+ }
+
+ /**
+ * Get all of the commands in the transfer
+ *
+ * @return array
+ */
+ public function getAllCommands()
+ {
+ return array_merge($this->successfulCommands, $this->failedCommands);
+ }
+
+ /**
+ * Add to the array of successful commands
+ *
+ * @param CommandInterface $command Successful command
+ *
+ * @return self
+ */
+ public function addSuccessfulCommand(CommandInterface $command)
+ {
+ $this->successfulCommands[] = $command;
+
+ return $this;
+ }
+
+ /**
+ * Add to the array of failed commands
+ *
+ * @param CommandInterface $command Failed command
+ *
+ * @return self
+ */
+ public function addFailedCommand(CommandInterface $command)
+ {
+ $this->failedCommands[] = $command;
+
+ return $this;
+ }
+
+ /**
+ * Get an array of successful commands
+ *
+ * @return array
+ */
+ public function getSuccessfulCommands()
+ {
+ return $this->successfulCommands;
+ }
+
+ /**
+ * Get an array of failed commands
+ *
+ * @return array
+ */
+ public function getFailedCommands()
+ {
+ return $this->failedCommands;
+ }
+
+ /**
+ * Get the Exception that caused the given $command to fail
+ *
+ * @param CommandInterface $command Failed command
+ *
+ * @return \Exception|null
+ */
+ public function getExceptionForFailedCommand(CommandInterface $command)
+ {
+ return $this->getExceptionForFailedRequest($command->getRequest());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php
new file mode 100755
index 0000000..1407e56
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/DescriptionBuilderException.php
@@ -0,0 +1,7 @@
+invalidCommands = $commands;
+ parent::__construct(
+ 'Encountered commands in a batch transfer that use inconsistent clients. The batching ' .
+ 'strategy you use with a command transfer must divide command batches by client.'
+ );
+ }
+
+ /**
+ * Get the invalid commands
+ *
+ * @return array
+ */
+ public function getCommands()
+ {
+ return $this->invalidCommands;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php
new file mode 100755
index 0000000..d59ff21
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Exception/ResponseClassException.php
@@ -0,0 +1,9 @@
+errors = $errors;
+ }
+
+ /**
+ * Get any validation errors
+ *
+ * @return array
+ */
+ public function getErrors()
+ {
+ return $this->errors;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php
new file mode 100755
index 0000000..21140e7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/AbstractResourceIteratorFactory.php
@@ -0,0 +1,37 @@
+canBuild($command)) {
+ throw new InvalidArgumentException('Iterator was not found for ' . $command->getName());
+ }
+
+ $className = $this->getClassName($command);
+
+ return new $className($command, $options);
+ }
+
+ public function canBuild(CommandInterface $command)
+ {
+ return (bool) $this->getClassName($command);
+ }
+
+ /**
+ * Get the name of the class to instantiate for the command
+ *
+ * @param CommandInterface $command Command that is associated with the iterator
+ *
+ * @return string
+ */
+ abstract protected function getClassName(CommandInterface $command);
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php
new file mode 100755
index 0000000..2efc133
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/CompositeResourceIteratorFactory.php
@@ -0,0 +1,67 @@
+factories = $factories;
+ }
+
+ public function build(CommandInterface $command, array $options = array())
+ {
+ if (!($factory = $this->getFactory($command))) {
+ throw new InvalidArgumentException('Iterator was not found for ' . $command->getName());
+ }
+
+ return $factory->build($command, $options);
+ }
+
+ public function canBuild(CommandInterface $command)
+ {
+ return $this->getFactory($command) !== false;
+ }
+
+ /**
+ * Add a factory to the composite factory
+ *
+ * @param ResourceIteratorFactoryInterface $factory Factory to add
+ *
+ * @return self
+ */
+ public function addFactory(ResourceIteratorFactoryInterface $factory)
+ {
+ $this->factories[] = $factory;
+
+ return $this;
+ }
+
+ /**
+ * Get the factory that matches the command object
+ *
+ * @param CommandInterface $command Command retrieving the iterator for
+ *
+ * @return ResourceIteratorFactoryInterface|bool
+ */
+ protected function getFactory(CommandInterface $command)
+ {
+ foreach ($this->factories as $factory) {
+ if ($factory->canBuild($command)) {
+ return $factory;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php
new file mode 100755
index 0000000..c71ca9d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/MapResourceIteratorFactory.php
@@ -0,0 +1,34 @@
+map = $map;
+ }
+
+ public function getClassName(CommandInterface $command)
+ {
+ $className = $command->getName();
+
+ if (isset($this->map[$className])) {
+ return $this->map[$className];
+ } elseif (isset($this->map['*'])) {
+ // If a wildcard was added, then always use that
+ return $this->map['*'];
+ }
+
+ return null;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php
new file mode 100755
index 0000000..2322434
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/Model.php
@@ -0,0 +1,64 @@
+data = $data;
+ $this->structure = $structure;
+ }
+
+ /**
+ * Get the structure of the model
+ *
+ * @return Parameter
+ */
+ public function getStructure()
+ {
+ return $this->structure ?: new Parameter();
+ }
+
+ /**
+ * Provides debug information about the model object
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $output = 'Debug output of ';
+ if ($this->structure) {
+ $output .= $this->structure->getName() . ' ';
+ }
+ $output .= 'model';
+ $output = str_repeat('=', strlen($output)) . "\n" . $output . "\n" . str_repeat('=', strlen($output)) . "\n\n";
+ $output .= "Model data\n-----------\n\n";
+ $output .= "This data can be retrieved from the model object using the get() method of the model "
+ . "(e.g. \$model->get(\$key)) or accessing the model like an associative array (e.g. \$model['key']).\n\n";
+ $lines = array_slice(explode("\n", trim(print_r($this->toArray(), true))), 2, -1);
+ $output .= implode("\n", $lines);
+
+ if ($this->structure) {
+ $output .= "\n\nModel structure\n---------------\n\n";
+ $output .= "The following JSON document defines how the model was parsed from an HTTP response into the "
+ . "associative array structure you see above.\n\n";
+ $output .= ' ' . json_encode($this->structure->toArray()) . "\n\n";
+ }
+
+ return $output . "\n";
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php
new file mode 100755
index 0000000..e141524
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIterator.php
@@ -0,0 +1,254 @@
+originalCommand = $command;
+
+ // Parse options from the array of options
+ $this->data = $data;
+ $this->limit = array_key_exists('limit', $data) ? $data['limit'] : 0;
+ $this->pageSize = array_key_exists('page_size', $data) ? $data['page_size'] : false;
+ }
+
+ /**
+ * Get all of the resources as an array (Warning: this could issue a large number of requests)
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ return iterator_to_array($this, false);
+ }
+
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+ $this->resetState();
+
+ return $this;
+ }
+
+ public function setPageSize($pageSize)
+ {
+ $this->pageSize = $pageSize;
+ $this->resetState();
+
+ return $this;
+ }
+
+ /**
+ * Get an option from the iterator
+ *
+ * @param string $key Key of the option to retrieve
+ *
+ * @return mixed|null Returns NULL if not set or the value if set
+ */
+ public function get($key)
+ {
+ return array_key_exists($key, $this->data) ? $this->data[$key] : null;
+ }
+
+ /**
+ * Set an option on the iterator
+ *
+ * @param string $key Key of the option to set
+ * @param mixed $value Value to set for the option
+ *
+ * @return ResourceIterator
+ */
+ public function set($key, $value)
+ {
+ $this->data[$key] = $value;
+
+ return $this;
+ }
+
+ public function current()
+ {
+ return $this->resources ? current($this->resources) : false;
+ }
+
+ public function key()
+ {
+ return max(0, $this->iteratedCount - 1);
+ }
+
+ public function count()
+ {
+ return $this->retrievedCount;
+ }
+
+ /**
+ * Get the total number of requests sent
+ *
+ * @return int
+ */
+ public function getRequestCount()
+ {
+ return $this->requestCount;
+ }
+
+ /**
+ * Rewind the Iterator to the first element and send the original command
+ */
+ public function rewind()
+ {
+ // Use the original command
+ $this->command = clone $this->originalCommand;
+ $this->resetState();
+ $this->next();
+ }
+
+ public function valid()
+ {
+ return !$this->invalid && (!$this->resources || $this->current() || $this->nextToken)
+ && (!$this->limit || $this->iteratedCount < $this->limit + 1);
+ }
+
+ public function next()
+ {
+ $this->iteratedCount++;
+
+ // Check if a new set of resources needs to be retrieved
+ $sendRequest = false;
+ if (!$this->resources) {
+ $sendRequest = true;
+ } else {
+ // iterate over the internal array
+ $current = next($this->resources);
+ $sendRequest = $current === false && $this->nextToken && (!$this->limit || $this->iteratedCount < $this->limit + 1);
+ }
+
+ if ($sendRequest) {
+
+ $this->dispatch('resource_iterator.before_send', array(
+ 'iterator' => $this,
+ 'resources' => $this->resources
+ ));
+
+ // Get a new command object from the original command
+ $this->command = clone $this->originalCommand;
+ // Send a request and retrieve the newly loaded resources
+ $this->resources = $this->sendRequest();
+ $this->requestCount++;
+
+ // If no resources were found, then the last request was not needed
+ // and iteration must stop
+ if (empty($this->resources)) {
+ $this->invalid = true;
+ } else {
+ // Add to the number of retrieved resources
+ $this->retrievedCount += count($this->resources);
+ // Ensure that we rewind to the beginning of the array
+ reset($this->resources);
+ }
+
+ $this->dispatch('resource_iterator.after_send', array(
+ 'iterator' => $this,
+ 'resources' => $this->resources
+ ));
+ }
+ }
+
+ /**
+ * Retrieve the NextToken that can be used in other iterators.
+ *
+ * @return string Returns a NextToken
+ */
+ public function getNextToken()
+ {
+ return $this->nextToken;
+ }
+
+ /**
+ * Returns the value that should be specified for the page size for a request that will maintain any hard limits,
+ * but still honor the specified pageSize if the number of items retrieved + pageSize < hard limit
+ *
+ * @return int Returns the page size of the next request.
+ */
+ protected function calculatePageSize()
+ {
+ if ($this->limit && $this->iteratedCount + $this->pageSize > $this->limit) {
+ return 1 + ($this->limit - $this->iteratedCount);
+ }
+
+ return (int) $this->pageSize;
+ }
+
+ /**
+ * Reset the internal state of the iterator without triggering a rewind()
+ */
+ protected function resetState()
+ {
+ $this->iteratedCount = 0;
+ $this->retrievedCount = 0;
+ $this->nextToken = false;
+ $this->resources = null;
+ $this->invalid = false;
+ }
+
+ /**
+ * Send a request to retrieve the next page of results. Hook for subclasses to implement.
+ *
+ * @return array Returns the newly loaded resources
+ */
+ abstract protected function sendRequest();
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php
new file mode 100755
index 0000000..6aa3615
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorApplyBatched.php
@@ -0,0 +1,111 @@
+iterator = $iterator;
+ $this->callback = $callback;
+ Version::warn(__CLASS__ . ' is deprecated');
+ }
+
+ /**
+ * Apply the callback to the contents of the resource iterator
+ *
+ * @param int $perBatch The number of records to group per batch transfer
+ *
+ * @return int Returns the number of iterated resources
+ */
+ public function apply($perBatch = 50)
+ {
+ $this->iterated = $this->batches = $batches = 0;
+ $that = $this;
+ $it = $this->iterator;
+ $callback = $this->callback;
+
+ $batch = BatchBuilder::factory()
+ ->createBatchesWith(new BatchSizeDivisor($perBatch))
+ ->transferWith(new BatchClosureTransfer(function (array $batch) use ($that, $callback, &$batches, $it) {
+ $batches++;
+ $that->dispatch('iterator_batch.before_batch', array('iterator' => $it, 'batch' => $batch));
+ call_user_func_array($callback, array($it, $batch));
+ $that->dispatch('iterator_batch.after_batch', array('iterator' => $it, 'batch' => $batch));
+ }))
+ ->autoFlushAt($perBatch)
+ ->build();
+
+ $this->dispatch('iterator_batch.created_batch', array('batch' => $batch));
+
+ foreach ($this->iterator as $resource) {
+ $this->iterated++;
+ $batch->add($resource);
+ }
+
+ $batch->flush();
+ $this->batches = $batches;
+
+ return $this->iterated;
+ }
+
+ /**
+ * Get the total number of batches sent
+ *
+ * @return int
+ */
+ public function getBatchCount()
+ {
+ return $this->batches;
+ }
+
+ /**
+ * Get the total number of iterated resources
+ *
+ * @return int
+ */
+ public function getIteratedCount()
+ {
+ return $this->iterated;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php
new file mode 100755
index 0000000..2fd9980
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorClassFactory.php
@@ -0,0 +1,60 @@
+ AbcFoo).
+ */
+class ResourceIteratorClassFactory extends AbstractResourceIteratorFactory
+{
+ /** @var array List of namespaces used to look for classes */
+ protected $namespaces;
+
+ /** @var InflectorInterface Inflector used to determine class names */
+ protected $inflector;
+
+ /**
+ * @param string|array $namespaces List of namespaces for iterator objects
+ * @param InflectorInterface $inflector Inflector used to resolve class names
+ */
+ public function __construct($namespaces = array(), InflectorInterface $inflector = null)
+ {
+ $this->namespaces = (array) $namespaces;
+ $this->inflector = $inflector ?: Inflector::getDefault();
+ }
+
+ /**
+ * Registers a namespace to check for Iterators
+ *
+ * @param string $namespace Namespace which contains Iterator classes
+ *
+ * @return self
+ */
+ public function registerNamespace($namespace)
+ {
+ array_unshift($this->namespaces, $namespace);
+
+ return $this;
+ }
+
+ protected function getClassName(CommandInterface $command)
+ {
+ $iteratorName = $this->inflector->camel($command->getName()) . 'Iterator';
+
+ // Determine the name of the class to load
+ foreach ($this->namespaces as $namespace) {
+ $potentialClassName = $namespace . '\\' . $iteratorName;
+ if (class_exists($potentialClassName)) {
+ return $potentialClassName;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php
new file mode 100755
index 0000000..8b4e8db
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Service/Resource/ResourceIteratorFactoryInterface.php
@@ -0,0 +1,30 @@
+=5.3.2",
+ "guzzle/cache": "self.version",
+ "guzzle/http": "self.version",
+ "guzzle/inflection": "self.version"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Service": "" }
+ },
+ "target-dir": "Guzzle/Service",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php
new file mode 100755
index 0000000..d115fd8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/PhpStreamRequestFactory.php
@@ -0,0 +1,284 @@
+contextOptions = stream_context_get_options($context);
+ $this->context = $context;
+ } elseif (is_array($context) || !$context) {
+ $this->contextOptions = $context;
+ $this->createContext($params);
+ } elseif ($context) {
+ throw new InvalidArgumentException('$context must be an array or resource');
+ }
+
+ // Dispatch the before send event
+ $request->dispatch('request.before_send', array(
+ 'request' => $request,
+ 'context' => $this->context,
+ 'context_options' => $this->contextOptions
+ ));
+
+ $this->setUrl($request);
+ $this->addDefaultContextOptions($request);
+ $this->addSslOptions($request);
+ $this->addBodyOptions($request);
+ $this->addProxyOptions($request);
+
+ // Create the file handle but silence errors
+ return $this->createStream($params)
+ ->setCustomData('request', $request)
+ ->setCustomData('response_headers', $this->getLastResponseHeaders());
+ }
+
+ /**
+ * Set an option on the context and the internal options array
+ *
+ * @param string $wrapper Stream wrapper name of http
+ * @param string $name Context name
+ * @param mixed $value Context value
+ * @param bool $overwrite Set to true to overwrite an existing value
+ */
+ protected function setContextValue($wrapper, $name, $value, $overwrite = false)
+ {
+ if (!isset($this->contextOptions[$wrapper])) {
+ $this->contextOptions[$wrapper] = array($name => $value);
+ } elseif (!$overwrite && isset($this->contextOptions[$wrapper][$name])) {
+ return;
+ }
+ $this->contextOptions[$wrapper][$name] = $value;
+ stream_context_set_option($this->context, $wrapper, $name, $value);
+ }
+
+ /**
+ * Create a stream context
+ *
+ * @param array $params Parameter array
+ */
+ protected function createContext(array $params)
+ {
+ $options = $this->contextOptions;
+ $this->context = $this->createResource(function () use ($params, $options) {
+ return stream_context_create($options, $params);
+ });
+ }
+
+ /**
+ * Get the last response headers received by the HTTP request
+ *
+ * @return array
+ */
+ public function getLastResponseHeaders()
+ {
+ return $this->lastResponseHeaders;
+ }
+
+ /**
+ * Adds the default context options to the stream context options
+ *
+ * @param RequestInterface $request Request
+ */
+ protected function addDefaultContextOptions(RequestInterface $request)
+ {
+ $this->setContextValue('http', 'method', $request->getMethod());
+ $headers = $request->getHeaderLines();
+
+ // "Connection: close" is required to get streams to work in HTTP 1.1
+ if (!$request->hasHeader('Connection')) {
+ $headers[] = 'Connection: close';
+ }
+
+ $this->setContextValue('http', 'header', $headers);
+ $this->setContextValue('http', 'protocol_version', $request->getProtocolVersion());
+ $this->setContextValue('http', 'ignore_errors', true);
+ }
+
+ /**
+ * Set the URL to use with the factory
+ *
+ * @param RequestInterface $request Request that owns the URL
+ */
+ protected function setUrl(RequestInterface $request)
+ {
+ $this->url = $request->getUrl(true);
+
+ // Check for basic Auth username
+ if ($request->getUsername()) {
+ $this->url->setUsername($request->getUsername());
+ }
+
+ // Check for basic Auth password
+ if ($request->getPassword()) {
+ $this->url->setPassword($request->getPassword());
+ }
+ }
+
+ /**
+ * Add SSL options to the stream context
+ *
+ * @param RequestInterface $request Request
+ */
+ protected function addSslOptions(RequestInterface $request)
+ {
+ if ($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)) {
+ $this->setContextValue('ssl', 'verify_peer', true, true);
+ if ($cafile = $request->getCurlOptions()->get(CURLOPT_CAINFO)) {
+ $this->setContextValue('ssl', 'cafile', $cafile, true);
+ }
+ } else {
+ $this->setContextValue('ssl', 'verify_peer', false, true);
+ }
+ }
+
+ /**
+ * Add body (content) specific options to the context options
+ *
+ * @param RequestInterface $request
+ */
+ protected function addBodyOptions(RequestInterface $request)
+ {
+ // Add the content for the request if needed
+ if (!($request instanceof EntityEnclosingRequestInterface)) {
+ return;
+ }
+
+ if (count($request->getPostFields())) {
+ $this->setContextValue('http', 'content', (string) $request->getPostFields(), true);
+ } elseif ($request->getBody()) {
+ $this->setContextValue('http', 'content', (string) $request->getBody(), true);
+ }
+
+ // Always ensure a content-length header is sent
+ if (isset($this->contextOptions['http']['content'])) {
+ $headers = isset($this->contextOptions['http']['header']) ? $this->contextOptions['http']['header'] : array();
+ $headers[] = 'Content-Length: ' . strlen($this->contextOptions['http']['content']);
+ $this->setContextValue('http', 'header', $headers, true);
+ }
+ }
+
+ /**
+ * Add proxy parameters to the context if needed
+ *
+ * @param RequestInterface $request Request
+ */
+ protected function addProxyOptions(RequestInterface $request)
+ {
+ if ($proxy = $request->getCurlOptions()->get(CURLOPT_PROXY)) {
+ $this->setContextValue('http', 'proxy', $proxy);
+ }
+ }
+
+ /**
+ * Create the stream for the request with the context options
+ *
+ * @param array $params Parameters of the stream
+ *
+ * @return StreamInterface
+ */
+ protected function createStream(array $params)
+ {
+ $http_response_header = null;
+ $url = $this->url;
+ $context = $this->context;
+ $fp = $this->createResource(function () use ($context, $url, &$http_response_header) {
+ return fopen((string) $url, 'r', false, $context);
+ });
+
+ // Determine the class to instantiate
+ $className = isset($params['stream_class']) ? $params['stream_class'] : __NAMESPACE__ . '\\Stream';
+
+ /** @var $stream StreamInterface */
+ $stream = new $className($fp);
+
+ // Track the response headers of the request
+ if (isset($http_response_header)) {
+ $this->lastResponseHeaders = $http_response_header;
+ $this->processResponseHeaders($stream);
+ }
+
+ return $stream;
+ }
+
+ /**
+ * Process response headers
+ *
+ * @param StreamInterface $stream
+ */
+ protected function processResponseHeaders(StreamInterface $stream)
+ {
+ // Set the size on the stream if it was returned in the response
+ foreach ($this->lastResponseHeaders as $header) {
+ if ((stripos($header, 'Content-Length:')) === 0) {
+ $stream->setSize(trim(substr($header, 15)));
+ }
+ }
+ }
+
+ /**
+ * Create a resource and check to ensure it was created successfully
+ *
+ * @param callable $callback Closure to invoke that must return a valid resource
+ *
+ * @return resource
+ * @throws RuntimeException on error
+ */
+ protected function createResource($callback)
+ {
+ $errors = null;
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
+ $errors[] = array(
+ 'message' => $msg,
+ 'file' => $file,
+ 'line' => $line
+ );
+ return true;
+ });
+ $resource = call_user_func($callback);
+ restore_error_handler();
+
+ if (!$resource) {
+ $message = 'Error creating resource. ';
+ foreach ($errors as $err) {
+ foreach ($err as $key => $value) {
+ $message .= "[$key] $value" . PHP_EOL;
+ }
+ }
+ throw new RuntimeException(trim($message));
+ }
+
+ return $resource;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php
new file mode 100755
index 0000000..12bed26
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/Stream.php
@@ -0,0 +1,289 @@
+ array(
+ 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
+ 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true,
+ 'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a+' => true
+ ),
+ 'write' => array(
+ 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, 'c+' => true,
+ 'wb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true,
+ 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
+ )
+ );
+
+ /**
+ * @param resource $stream Stream resource to wrap
+ * @param int $size Size of the stream in bytes. Only pass if the size cannot be obtained from the stream.
+ *
+ * @throws InvalidArgumentException if the stream is not a stream resource
+ */
+ public function __construct($stream, $size = null)
+ {
+ $this->setStream($stream, $size);
+ }
+
+ /**
+ * Closes the stream when the helper is destructed
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ public function __toString()
+ {
+ if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) {
+ return '';
+ }
+
+ $originalPos = $this->ftell();
+ $body = stream_get_contents($this->stream, -1, 0);
+ $this->seek($originalPos);
+
+ return $body;
+ }
+
+ public function close()
+ {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->cache[self::IS_READABLE] = false;
+ $this->cache[self::IS_WRITABLE] = false;
+ }
+
+ /**
+ * Calculate a hash of a Stream
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return bool|string Returns false on failure or a hash string on success
+ */
+ public static function getHash(StreamInterface $stream, $algo, $rawOutput = false)
+ {
+ $pos = $stream->ftell();
+ if (!$stream->seek(0)) {
+ return false;
+ }
+
+ $ctx = hash_init($algo);
+ while (!$stream->feof()) {
+ hash_update($ctx, $stream->read(8192));
+ }
+
+ $out = hash_final($ctx, (bool) $rawOutput);
+ $stream->seek($pos);
+
+ return $out;
+ }
+
+ public function getMetaData($key = null)
+ {
+ $meta = stream_get_meta_data($this->stream);
+
+ return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null);
+ }
+
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ public function setStream($stream, $size = null)
+ {
+ if (!is_resource($stream)) {
+ throw new InvalidArgumentException('Stream must be a resource');
+ }
+
+ $this->size = $size;
+ $this->stream = $stream;
+ $this->rebuildCache();
+
+ return $this;
+ }
+
+ public function detachStream()
+ {
+ $this->stream = null;
+
+ return $this;
+ }
+
+ public function getWrapper()
+ {
+ return $this->cache[self::WRAPPER_TYPE];
+ }
+
+ public function getWrapperData()
+ {
+ return $this->getMetaData('wrapper_data') ?: array();
+ }
+
+ public function getStreamType()
+ {
+ return $this->cache[self::STREAM_TYPE];
+ }
+
+ public function getUri()
+ {
+ return $this->cache['uri'];
+ }
+
+ public function getSize()
+ {
+ if ($this->size !== null) {
+ return $this->size;
+ }
+
+ // If the stream is a file based stream and local, then use fstat
+ clearstatcache(true, $this->cache['uri']);
+ $stats = fstat($this->stream);
+ if (isset($stats['size'])) {
+ $this->size = $stats['size'];
+ return $this->size;
+ } elseif ($this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]) {
+ // Only get the size based on the content if the the stream is readable and seekable
+ $pos = $this->ftell();
+ $this->size = strlen((string) $this);
+ $this->seek($pos);
+ return $this->size;
+ }
+
+ return false;
+ }
+
+ public function isReadable()
+ {
+ return $this->cache[self::IS_READABLE];
+ }
+
+ public function isRepeatable()
+ {
+ return $this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE];
+ }
+
+ public function isWritable()
+ {
+ return $this->cache[self::IS_WRITABLE];
+ }
+
+ public function isConsumed()
+ {
+ return feof($this->stream);
+ }
+
+ public function feof()
+ {
+ return $this->isConsumed();
+ }
+
+ public function isLocal()
+ {
+ return $this->cache[self::IS_LOCAL];
+ }
+
+ public function isSeekable()
+ {
+ return $this->cache[self::SEEKABLE];
+ }
+
+ public function setSize($size)
+ {
+ $this->size = $size;
+
+ return $this;
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false;
+ }
+
+ public function read($length)
+ {
+ return fread($this->stream, $length);
+ }
+
+ public function write($string)
+ {
+ // We can't know the size after writing anything
+ $this->size = null;
+
+ return fwrite($this->stream, $string);
+ }
+
+ public function ftell()
+ {
+ return ftell($this->stream);
+ }
+
+ public function rewind()
+ {
+ return $this->seek(0);
+ }
+
+ public function readLine($maxLength = null)
+ {
+ if (!$this->cache[self::IS_READABLE]) {
+ return false;
+ } else {
+ return $maxLength ? fgets($this->getStream(), $maxLength) : fgets($this->getStream());
+ }
+ }
+
+ public function setCustomData($key, $value)
+ {
+ $this->customData[$key] = $value;
+
+ return $this;
+ }
+
+ public function getCustomData($key)
+ {
+ return isset($this->customData[$key]) ? $this->customData[$key] : null;
+ }
+
+ /**
+ * Reprocess stream metadata
+ */
+ protected function rebuildCache()
+ {
+ $this->cache = stream_get_meta_data($this->stream);
+ $this->cache[self::IS_LOCAL] = stream_is_local($this->stream);
+ $this->cache[self::IS_READABLE] = isset(self::$readWriteHash['read'][$this->cache['mode']]);
+ $this->cache[self::IS_WRITABLE] = isset(self::$readWriteHash['write'][$this->cache['mode']]);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php
new file mode 100755
index 0000000..6d7dc37
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/src/Guzzle/Stream/StreamInterface.php
@@ -0,0 +1,218 @@
+=5.3.2",
+ "guzzle/common": "self.version"
+ },
+ "suggest": {
+ "guzzle/http": "To convert Guzzle request objects to PHP streams"
+ },
+ "autoload": {
+ "psr-0": { "Guzzle\\Stream": "" }
+ },
+ "target-dir": "Guzzle/Stream",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php
new file mode 100755
index 0000000..951738d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/AbstractBatchDecoratorTest.php
@@ -0,0 +1,33 @@
+getMock('Guzzle\Batch\BatchTransferInterface'),
+ $this->getMock('Guzzle\Batch\BatchDivisorInterface')
+ );
+
+ $decoratorA = $this->getMockBuilder('Guzzle\Batch\AbstractBatchDecorator')
+ ->setConstructorArgs(array($batch))
+ ->getMockForAbstractClass();
+
+ $decoratorB = $this->getMockBuilder('Guzzle\Batch\AbstractBatchDecorator')
+ ->setConstructorArgs(array($decoratorA))
+ ->getMockForAbstractClass();
+
+ $decoratorA->add('foo');
+ $this->assertFalse($decoratorB->isEmpty());
+ $this->assertFalse($batch->isEmpty());
+ $this->assertEquals(array($decoratorB, $decoratorA), $decoratorB->getDecorators());
+ $this->assertEquals(array(), $decoratorB->flush());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php
new file mode 100755
index 0000000..4da09d3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchBuilderTest.php
@@ -0,0 +1,86 @@
+getMock('Guzzle\Batch\BatchTransferInterface');
+ }
+
+ private function getMockDivisor()
+ {
+ return $this->getMock('Guzzle\Batch\BatchDivisorInterface');
+ }
+
+ private function getMockBatchBuilder()
+ {
+ return BatchBuilder::factory()
+ ->transferWith($this->getMockTransfer())
+ ->createBatchesWith($this->getMockDivisor());
+ }
+
+ public function testFactoryCreatesInstance()
+ {
+ $builder = BatchBuilder::factory();
+ $this->assertInstanceOf('Guzzle\Batch\BatchBuilder', $builder);
+ }
+
+ public function testAddsAutoFlush()
+ {
+ $batch = $this->getMockBatchBuilder()->autoFlushAt(10)->build();
+ $this->assertInstanceOf('Guzzle\Batch\FlushingBatch', $batch);
+ }
+
+ public function testAddsExceptionBuffering()
+ {
+ $batch = $this->getMockBatchBuilder()->bufferExceptions()->build();
+ $this->assertInstanceOf('Guzzle\Batch\ExceptionBufferingBatch', $batch);
+ }
+
+ public function testAddHistory()
+ {
+ $batch = $this->getMockBatchBuilder()->keepHistory()->build();
+ $this->assertInstanceOf('Guzzle\Batch\HistoryBatch', $batch);
+ }
+
+ public function testAddsNotify()
+ {
+ $batch = $this->getMockBatchBuilder()->notify(function() {})->build();
+ $this->assertInstanceOf('Guzzle\Batch\NotifyingBatch', $batch);
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\RuntimeException
+ */
+ public function testTransferStrategyMustBeSet()
+ {
+ $batch = BatchBuilder::factory()->createBatchesWith($this->getMockDivisor())->build();
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\RuntimeException
+ */
+ public function testDivisorStrategyMustBeSet()
+ {
+ $batch = BatchBuilder::factory()->transferWith($this->getMockTransfer())->build();
+ }
+
+ public function testTransfersRequests()
+ {
+ $batch = BatchBuilder::factory()->transferRequests(10)->build();
+ $this->assertInstanceOf('Guzzle\Batch\BatchRequestTransfer', $this->readAttribute($batch, 'transferStrategy'));
+ }
+
+ public function testTransfersCommands()
+ {
+ $batch = BatchBuilder::factory()->transferCommands(10)->build();
+ $this->assertInstanceOf('Guzzle\Batch\BatchCommandTransfer', $this->readAttribute($batch, 'transferStrategy'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php
new file mode 100755
index 0000000..753db7d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureDivisorTest.php
@@ -0,0 +1,36 @@
+createBatches($queue);
+ $this->assertEquals(array(array('foo'), array('baz')), $batches);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php
new file mode 100755
index 0000000..6ba7ae0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchClosureTransferTest.php
@@ -0,0 +1,52 @@
+itemsTransferred = null;
+ $itemsTransferred =& $this->itemsTransferred;
+
+ $this->transferStrategy = new BatchClosureTransfer(function (array $batch) use (&$itemsTransferred) {
+ $itemsTransferred = $batch;
+ return;
+ });
+ }
+
+ public function testTransfersBatch()
+ {
+ $batchedItems = array('foo', 'bar', 'baz');
+ $this->transferStrategy->transfer($batchedItems);
+
+ $this->assertEquals($batchedItems, $this->itemsTransferred);
+ }
+
+ public function testTransferBailsOnEmptyBatch()
+ {
+ $batchedItems = array();
+ $this->transferStrategy->transfer($batchedItems);
+
+ $this->assertNull($this->itemsTransferred);
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testEnsuresCallableIsCallable()
+ {
+ $foo = new BatchClosureTransfer('uh oh!');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php
new file mode 100755
index 0000000..a04efab
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchCommandTransferTest.php
@@ -0,0 +1,83 @@
+ $command) {
+ if ($i % 2) {
+ $command->setClient($client1);
+ } else {
+ $command->setClient($client2);
+ }
+ $queue[] = $command;
+ }
+
+ $batch = new BatchCommandTransfer(2);
+ $this->assertEquals(array(
+ array($commands[0], $commands[2]),
+ array($commands[4]),
+ array($commands[1], $commands[3])
+ ), $batch->createBatches($queue));
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testEnsuresAllItemsAreCommands()
+ {
+ $queue = new \SplQueue();
+ $queue[] = 'foo';
+ $batch = new BatchCommandTransfer(2);
+ $batch->createBatches($queue);
+ }
+
+ public function testTransfersBatches()
+ {
+ $client = $this->getMockBuilder('Guzzle\Service\Client')
+ ->setMethods(array('send'))
+ ->getMock();
+ $client->expects($this->once())
+ ->method('send');
+ $command = new Mc();
+ $command->setClient($client);
+ $batch = new BatchCommandTransfer(2);
+ $batch->transfer(array($command));
+ }
+
+ public function testDoesNotTransfersEmptyBatches()
+ {
+ $batch = new BatchCommandTransfer(2);
+ $batch->transfer(array());
+ }
+
+ /**
+ * @expectedException Guzzle\Service\Exception\InconsistentClientTransferException
+ */
+ public function testEnsuresAllCommandsUseTheSameClient()
+ {
+ $batch = new BatchCommandTransfer(2);
+ $client1 = new Client('http://www.example.com');
+ $client2 = new Client('http://www.example.com');
+ $command1 = new Mc();
+ $command1->setClient($client1);
+ $command2 = new Mc();
+ $command2->setClient($client2);
+ $batch->transfer(array($command1, $command2));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php
new file mode 100755
index 0000000..dec7bd5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchRequestTransferTest.php
@@ -0,0 +1,80 @@
+setCurlMulti(new CurlMulti());
+
+ $client2 = new Client('http://www.example.com');
+ $client2->setCurlMulti(new CurlMulti());
+
+ $request1 = $client1->get();
+ $request2 = $client2->get();
+ $request3 = $client1->get();
+ $request4 = $client2->get();
+ $request5 = $client1->get();
+
+ $queue = new \SplQueue();
+ $queue[] = $request1;
+ $queue[] = $request2;
+ $queue[] = $request3;
+ $queue[] = $request4;
+ $queue[] = $request5;
+
+ $batch = new BatchRequestTransfer(2);
+ $this->assertEquals(array(
+ array($request1, $request3),
+ array($request3),
+ array($request2, $request4)
+ ), $batch->createBatches($queue));
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testEnsuresAllItemsAreRequests()
+ {
+ $queue = new \SplQueue();
+ $queue[] = 'foo';
+ $batch = new BatchRequestTransfer(2);
+ $batch->createBatches($queue);
+ }
+
+ public function testTransfersBatches()
+ {
+ $client = new Client('http://127.0.0.1:123');
+ $request = $client->get();
+ // For some reason... PHP unit clones the request, which emits a request.clone event. This causes the
+ // 'sorted' property of the event dispatcher to contain an array in the cloned request that is not present in
+ // the original.
+ $request->dispatch('request.clone');
+
+ $multi = $this->getMock('Guzzle\Http\Curl\CurlMultiInterface');
+ $client->setCurlMulti($multi);
+ $multi->expects($this->once())
+ ->method('add')
+ ->with($request);
+ $multi->expects($this->once())
+ ->method('send');
+
+ $batch = new BatchRequestTransfer(2);
+ $batch->transfer(array($request));
+ }
+
+ public function testDoesNotTransfersEmptyBatches()
+ {
+ $batch = new BatchRequestTransfer(2);
+ $batch->transfer(array());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php
new file mode 100755
index 0000000..5542228
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchSizeDivisorTest.php
@@ -0,0 +1,24 @@
+assertEquals(3, $d->getSize());
+ $d->setSize(2);
+ $batches = $d->createBatches($queue);
+ $this->assertEquals(array(array('foo', 'baz'), array('bar')), $batches);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php
new file mode 100755
index 0000000..296f57a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/BatchTest.php
@@ -0,0 +1,91 @@
+getMock('Guzzle\Batch\BatchTransferInterface');
+ }
+
+ private function getMockDivisor()
+ {
+ return $this->getMock('Guzzle\Batch\BatchDivisorInterface');
+ }
+
+ public function testAddsItemsToQueue()
+ {
+ $batch = new Batch($this->getMockTransfer(), $this->getMockDivisor());
+ $this->assertSame($batch, $batch->add('foo'));
+ $this->assertEquals(1, count($batch));
+ }
+
+ public function testFlushReturnsItems()
+ {
+ $transfer = $this->getMockTransfer();
+ $transfer->expects($this->exactly(2))
+ ->method('transfer');
+
+ $divisor = $this->getMockDivisor();
+ $divisor->expects($this->once())
+ ->method('createBatches')
+ ->will($this->returnValue(array(array('foo', 'baz'), array('bar'))));
+
+ $batch = new Batch($transfer, $divisor);
+
+ $batch->add('foo')->add('baz')->add('bar');
+ $items = $batch->flush();
+
+ $this->assertEquals(array('foo', 'baz', 'bar'), $items);
+ }
+
+ public function testThrowsExceptionContainingTheFailedBatch()
+ {
+ $called = 0;
+ $originalException = new \Exception('Foo!');
+
+ $transfer = $this->getMockTransfer();
+ $transfer->expects($this->exactly(2))
+ ->method('transfer')
+ ->will($this->returnCallback(function () use (&$called, $originalException) {
+ if (++$called == 2) {
+ throw $originalException;
+ }
+ }));
+
+ $divisor = $this->getMockDivisor();
+ $batch = new Batch($transfer, $divisor);
+
+ // PHPunit clones objects before passing them to a callback.
+ // Horrible hack to get around this!
+ $queue = $this->readAttribute($batch, 'queue');
+
+ $divisor->expects($this->once())
+ ->method('createBatches')
+ ->will($this->returnCallback(function ($batch) use ($queue) {
+ foreach ($queue as $item) {
+ $items[] = $item;
+ }
+ return array_chunk($items, 2);
+ }));
+
+ $batch->add('foo')->add('baz')->add('bar')->add('bee')->add('boo');
+ $this->assertFalse($batch->isEmpty());
+
+ try {
+ $items = $batch->flush();
+ $this->fail('Expected exception');
+ } catch (BatchTransferException $e) {
+ $this->assertEquals($originalException, $e->getPrevious());
+ $this->assertEquals(array('bar', 'bee'), array_values($e->getBatch()));
+ $this->assertEquals(1, count($batch));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php
new file mode 100755
index 0000000..fd810b1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/ExceptionBufferingBatchTest.php
@@ -0,0 +1,45 @@
+getMockBuilder('Guzzle\Batch\BatchTransferInterface')
+ ->setMethods(array('transfer'))
+ ->getMock();
+
+ $d = new BatchSizeDivisor(1);
+ $batch = new Batch($t, $d);
+
+ $called = 0;
+ $t->expects($this->exactly(3))
+ ->method('transfer')
+ ->will($this->returnCallback(function ($batch) use (&$called) {
+ if (++$called === 2) {
+ throw new \Exception('Foo');
+ }
+ }));
+
+ $decorator = new ExceptionBufferingBatch($batch);
+ $decorator->add('foo')->add('baz')->add('bar');
+ $result = $decorator->flush();
+
+ $e = $decorator->getExceptions();
+ $this->assertEquals(1, count($e));
+ $this->assertEquals(array('baz'), $e[0]->getBatch());
+
+ $decorator->clearExceptions();
+ $this->assertEquals(0, count($decorator->getExceptions()));
+
+ $this->assertEquals(array('foo', 'bar'), $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php
new file mode 100755
index 0000000..9b37a48
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/FlushingBatchTest.php
@@ -0,0 +1,40 @@
+getMock('Guzzle\Batch\BatchTransferInterface', array('transfer'));
+ $d = $this->getMock('Guzzle\Batch\BatchDivisorInterface', array('createBatches'));
+
+ $batch = new Batch($t, $d);
+ $queue = $this->readAttribute($batch, 'queue');
+
+ $d->expects($this->exactly(2))
+ ->method('createBatches')
+ ->will($this->returnCallback(function () use ($queue) {
+ $items = array();
+ foreach ($queue as $item) {
+ $items[] = $item;
+ }
+ return array($items);
+ }));
+
+ $t->expects($this->exactly(2))
+ ->method('transfer');
+
+ $flush = new FlushingBatch($batch, 3);
+ $this->assertEquals(3, $flush->getThreshold());
+ $flush->setThreshold(2);
+ $flush->add('foo')->add('baz')->add('bar')->add('bee')->add('boo');
+ $this->assertEquals(1, count($flush));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php
new file mode 100755
index 0000000..60d6f95
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/HistoryBatchTest.php
@@ -0,0 +1,26 @@
+getMock('Guzzle\Batch\BatchTransferInterface'),
+ $this->getMock('Guzzle\Batch\BatchDivisorInterface')
+ );
+
+ $history = new HistoryBatch($batch);
+ $history->add('foo')->add('baz');
+ $this->assertEquals(array('foo', 'baz'), $history->getHistory());
+ $history->clearHistory();
+ $this->assertEquals(array(), $history->getHistory());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php
new file mode 100755
index 0000000..69a8900
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Batch/NotifyingBatchTest.php
@@ -0,0 +1,45 @@
+getMock('Guzzle\Batch\Batch', array('flush'), array(
+ $this->getMock('Guzzle\Batch\BatchTransferInterface'),
+ $this->getMock('Guzzle\Batch\BatchDivisorInterface')
+ ));
+
+ $batch->expects($this->once())
+ ->method('flush')
+ ->will($this->returnValue(array('foo', 'baz')));
+
+ $data = array();
+ $decorator = new NotifyingBatch($batch, function ($batch) use (&$data) {
+ $data[] = $batch;
+ });
+
+ $decorator->add('foo')->add('baz');
+ $decorator->flush();
+ $this->assertEquals(array(array('foo', 'baz')), $data);
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testEnsuresCallableIsValid()
+ {
+ $batch = new Batch(
+ $this->getMock('Guzzle\Batch\BatchTransferInterface'),
+ $this->getMock('Guzzle\Batch\BatchDivisorInterface')
+ );
+ $decorator = new NotifyingBatch($batch, 'foo');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php
new file mode 100755
index 0000000..c4140a9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterFactoryTest.php
@@ -0,0 +1,64 @@
+cache = new ArrayCache();
+ $this->adapter = new DoctrineCacheAdapter($this->cache);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testEnsuresConfigIsObject()
+ {
+ CacheAdapterFactory::fromCache(array());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testEnsuresKnownType()
+ {
+ CacheAdapterFactory::fromCache(new \stdClass());
+ }
+
+ public function cacheProvider()
+ {
+ return array(
+ array(new DoctrineCacheAdapter(new ArrayCache()), 'Guzzle\Cache\DoctrineCacheAdapter'),
+ array(new ArrayCache(), 'Guzzle\Cache\DoctrineCacheAdapter'),
+ array(StorageFactory::factory(array('adapter' => 'memory')), 'Guzzle\Cache\Zf2CacheAdapter'),
+ );
+ }
+
+ /**
+ * @dataProvider cacheProvider
+ */
+ public function testCreatesNullCacheAdapterByDefault($cache, $type)
+ {
+ $adapter = CacheAdapterFactory::fromCache($cache);
+ $this->assertInstanceOf($type, $adapter);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php
new file mode 100755
index 0000000..3e30ddd
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/CacheAdapterTest.php
@@ -0,0 +1,68 @@
+cache = new ArrayCache();
+ $this->adapter = new DoctrineCacheAdapter($this->cache);
+ }
+
+ /**
+ * Cleans up the environment after running a test.
+ */
+ protected function tearDown()
+ {
+ $this->adapter = null;
+ $this->cache = null;
+ parent::tearDown();
+ }
+
+ public function testGetCacheObject()
+ {
+ $this->assertEquals($this->cache, $this->adapter->getCacheObject());
+ }
+
+ public function testSave()
+ {
+ $this->assertTrue($this->adapter->save('test', 'data', 1000));
+ }
+
+ public function testFetch()
+ {
+ $this->assertTrue($this->adapter->save('test', 'data', 1000));
+ $this->assertEquals('data', $this->adapter->fetch('test'));
+ }
+
+ public function testContains()
+ {
+ $this->assertTrue($this->adapter->save('test', 'data', 1000));
+ $this->assertTrue($this->adapter->contains('test'));
+ }
+
+ public function testDelete()
+ {
+ $this->assertTrue($this->adapter->save('test', 'data', 1000));
+ $this->assertTrue($this->adapter->delete('test'));
+ $this->assertFalse($this->adapter->contains('test'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php
new file mode 100755
index 0000000..12de65b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/ClosureCacheAdapterTest.php
@@ -0,0 +1,94 @@
+callables = array(
+ 'contains' => function($id, $options = array()) use ($that) {
+ return array_key_exists($id, $that->data);
+ },
+ 'delete' => function($id, $options = array()) use ($that) {
+ unset($that->data[$id]);
+ return true;
+ },
+ 'fetch' => function($id, $options = array()) use ($that) {
+ return array_key_exists($id, $that->data) ? $that->data[$id] : null;
+ },
+ 'save' => function($id, $data, $lifeTime, $options = array()) use ($that) {
+ $that->data[$id] = $data;
+ return true;
+ }
+ );
+
+ $this->adapter = new ClosureCacheAdapter($this->callables);
+ }
+
+ /**
+ * Cleans up the environment after running a test.
+ */
+ protected function tearDown()
+ {
+ $this->cache = null;
+ $this->callables = null;
+ parent::tearDown();
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testEnsuresCallablesArePresent()
+ {
+ $callables = $this->callables;
+ unset($callables['delete']);
+ $cache = new ClosureCacheAdapter($callables);
+ }
+
+ public function testAllCallablesMustBePresent()
+ {
+ $cache = new ClosureCacheAdapter($this->callables);
+ }
+
+ public function testCachesDataUsingCallables()
+ {
+ $this->assertTrue($this->adapter->save('test', 'data', 1000));
+ $this->assertEquals('data', $this->adapter->fetch('test'));
+ }
+
+ public function testChecksIfCacheContainsKeys()
+ {
+ $this->adapter->save('test', 'data', 1000);
+ $this->assertTrue($this->adapter->contains('test'));
+ $this->assertFalse($this->adapter->contains('foo'));
+ }
+
+ public function testDeletesFromCacheByKey()
+ {
+ $this->adapter->save('test', 'data', 1000);
+ $this->assertTrue($this->adapter->contains('test'));
+ $this->adapter->delete('test');
+ $this->assertFalse($this->adapter->contains('test'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php
new file mode 100755
index 0000000..e05df3f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/NullCacheAdapterTest.php
@@ -0,0 +1,20 @@
+assertEquals(false, $c->contains('foo'));
+ $this->assertEquals(true, $c->delete('foo'));
+ $this->assertEquals(false, $c->fetch('foo'));
+ $this->assertEquals(true, $c->save('foo', 'bar'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php
new file mode 100755
index 0000000..9077c12
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Cache/Zf2CacheAdapterTest.php
@@ -0,0 +1,58 @@
+cache = StorageFactory::factory(array(
+ 'adapter' => 'memory'
+ ));
+ $this->adapter = new Zf2CacheAdapter($this->cache);
+ }
+
+ /**
+ * Cleans up the environment after running a test.
+ */
+ protected function tearDown()
+ {
+ $this->adapter = null;
+ $this->cache = null;
+ parent::tearDown();
+ }
+
+ public function testCachesDataUsingCallables()
+ {
+ $this->assertTrue($this->adapter->save('test', 'data', 1000));
+ $this->assertEquals('data', $this->adapter->fetch('test'));
+ }
+
+ public function testChecksIfCacheContainsKeys()
+ {
+ $this->adapter->save('test', 'data', 1000);
+ $this->assertTrue($this->adapter->contains('test'));
+ $this->assertFalse($this->adapter->contains('foo'));
+ }
+
+ public function testDeletesFromCacheByKey()
+ {
+ $this->adapter->save('test', 'data', 1000);
+ $this->assertTrue($this->adapter->contains('test'));
+ $this->adapter->delete('test');
+ $this->assertFalse($this->adapter->contains('test'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php
new file mode 100755
index 0000000..19d12e6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/AbstractHasDispatcherTest.php
@@ -0,0 +1,63 @@
+assertEquals(array(), AbstractHasDispatcher::getAllEvents());
+ }
+
+ public function testAllowsDispatcherToBeInjected()
+ {
+ $d = new EventDispatcher();
+ $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher');
+ $this->assertSame($mock, $mock->setEventDispatcher($d));
+ $this->assertSame($d, $mock->getEventDispatcher());
+ }
+
+ public function testCreatesDefaultEventDispatcherIfNeeded()
+ {
+ $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher');
+ $this->assertInstanceOf('Symfony\Component\EventDispatcher\EventDispatcher', $mock->getEventDispatcher());
+ }
+
+ public function testHelperDispatchesEvents()
+ {
+ $data = array();
+ $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher');
+ $mock->getEventDispatcher()->addListener('test', function(Event $e) use (&$data) {
+ $data = $e->getIterator()->getArrayCopy();
+ });
+ $mock->dispatch('test', array(
+ 'param' => 'abc'
+ ));
+ $this->assertEquals(array(
+ 'param' => 'abc',
+ ), $data);
+ }
+
+ public function testHelperAttachesSubscribers()
+ {
+ $mock = $this->getMockForAbstractClass('Guzzle\Common\AbstractHasDispatcher');
+ $subscriber = $this->getMockForAbstractClass('Symfony\Component\EventDispatcher\EventSubscriberInterface');
+
+ $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcher')
+ ->setMethods(array('addSubscriber'))
+ ->getMock();
+
+ $dispatcher->expects($this->once())
+ ->method('addSubscriber');
+
+ $mock->setEventDispatcher($dispatcher);
+ $mock->addSubscriber($subscriber);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php
new file mode 100755
index 0000000..0648a02
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/CollectionTest.php
@@ -0,0 +1,529 @@
+coll = new Collection();
+ }
+
+ public function testConstructorCanBeCalledWithNoParams()
+ {
+ $this->coll = new Collection();
+ $p = $this->coll->getAll();
+ $this->assertEmpty($p, '-> Collection must be empty when no data is passed');
+ }
+
+ public function testConstructorCanBeCalledWithParams()
+ {
+ $testData = array(
+ 'test' => 'value',
+ 'test_2' => 'value2'
+ );
+ $this->coll = new Collection($testData);
+ $this->assertEquals($this->coll->getAll(), $testData, '-> getAll() must return the data passed in the constructor');
+ $this->assertEquals($this->coll->getAll(), $this->coll->toArray());
+ }
+
+ public function testImplementsIteratorAggregate()
+ {
+ $this->coll->set('key', 'value');
+ $this->assertInstanceOf('ArrayIterator', $this->coll->getIterator());
+ $this->assertEquals(1, count($this->coll));
+ $total = 0;
+ foreach ($this->coll as $key => $value) {
+ $this->assertEquals('key', $key);
+ $this->assertEquals('value', $value);
+ $total++;
+ }
+ $this->assertEquals(1, $total);
+ }
+
+ public function testCanAddValuesToExistingKeysByUsingArray()
+ {
+ $this->coll->add('test', 'value1');
+ $this->assertEquals($this->coll->getAll(), array('test' => 'value1'));
+ $this->coll->add('test', 'value2');
+ $this->assertEquals($this->coll->getAll(), array('test' => array('value1', 'value2')));
+ $this->coll->add('test', 'value3');
+ $this->assertEquals($this->coll->getAll(), array('test' => array('value1', 'value2', 'value3')));
+ }
+
+ public function testHandlesMergingInDisparateDataSources()
+ {
+ $params = array(
+ 'test' => 'value1',
+ 'test2' => 'value2',
+ 'test3' => array('value3', 'value4')
+ );
+ $this->coll->merge($params);
+ $this->assertEquals($this->coll->getAll(), $params);
+
+ // Pass the same object to itself
+ $this->assertEquals($this->coll->merge($this->coll), $this->coll);
+ }
+
+ public function testCanClearAllDataOrSpecificKeys()
+ {
+ $this->coll->merge(array(
+ 'test' => 'value1',
+ 'test2' => 'value2'
+ ));
+
+ // Clear a specific parameter by name
+ $this->coll->remove('test');
+
+ $this->assertEquals($this->coll->getAll(), array(
+ 'test2' => 'value2'
+ ));
+
+ // Clear all parameters
+ $this->coll->clear();
+
+ $this->assertEquals($this->coll->getAll(), array());
+ }
+
+ public function testGetsValuesByKey()
+ {
+ $this->assertNull($this->coll->get('test'));
+ $this->coll->add('test', 'value');
+ $this->assertEquals('value', $this->coll->get('test'));
+ $this->coll->set('test2', 'v2');
+ $this->coll->set('test3', 'v3');
+ $this->assertEquals(array(
+ 'test' => 'value',
+ 'test2' => 'v2'
+ ), $this->coll->getAll(array('test', 'test2')));
+ }
+
+ public function testProvidesKeys()
+ {
+ $this->assertEquals(array(), $this->coll->getKeys());
+ $this->coll->merge(array(
+ 'test1' => 'value1',
+ 'test2' => 'value2'
+ ));
+ $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys());
+ // Returns the cached array previously returned
+ $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys());
+ $this->coll->remove('test1');
+ $this->assertEquals(array('test2'), $this->coll->getKeys());
+ $this->coll->add('test3', 'value3');
+ $this->assertEquals(array('test2', 'test3'), $this->coll->getKeys());
+ }
+
+ public function testChecksIfHasKey()
+ {
+ $this->assertFalse($this->coll->hasKey('test'));
+ $this->coll->add('test', 'value');
+ $this->assertEquals(true, $this->coll->hasKey('test'));
+ $this->coll->add('test2', 'value2');
+ $this->assertEquals(true, $this->coll->hasKey('test'));
+ $this->assertEquals(true, $this->coll->hasKey('test2'));
+ $this->assertFalse($this->coll->hasKey('testing'));
+ $this->assertEquals(false, $this->coll->hasKey('AB-C', 'junk'));
+ }
+
+ public function testChecksIfHasValue()
+ {
+ $this->assertFalse($this->coll->hasValue('value'));
+ $this->coll->add('test', 'value');
+ $this->assertEquals('test', $this->coll->hasValue('value'));
+ $this->coll->add('test2', 'value2');
+ $this->assertEquals('test', $this->coll->hasValue('value'));
+ $this->assertEquals('test2', $this->coll->hasValue('value2'));
+ $this->assertFalse($this->coll->hasValue('val'));
+ }
+
+ public function testCanGetAllValuesByArray()
+ {
+ $this->coll->add('foo', 'bar');
+ $this->coll->add('tEsT', 'value');
+ $this->coll->add('tesTing', 'v2');
+ $this->coll->add('key', 'v3');
+ $this->assertNull($this->coll->get('test'));
+ $this->assertEquals(array(
+ 'foo' => 'bar',
+ 'tEsT' => 'value',
+ 'tesTing' => 'v2'
+ ), $this->coll->getAll(array(
+ 'foo', 'tesTing', 'tEsT'
+ )));
+ }
+
+ public function testImplementsCount()
+ {
+ $data = new Collection();
+ $this->assertEquals(0, $data->count());
+ $data->add('key', 'value');
+ $this->assertEquals(1, count($data));
+ $data->add('key', 'value2');
+ $this->assertEquals(1, count($data));
+ $data->add('key_2', 'value3');
+ $this->assertEquals(2, count($data));
+ }
+
+ public function testAddParamsByMerging()
+ {
+ $params = array(
+ 'test' => 'value1',
+ 'test2' => 'value2',
+ 'test3' => array('value3', 'value4')
+ );
+
+ // Add some parameters
+ $this->coll->merge($params);
+
+ // Add more parameters by merging them in
+ $this->coll->merge(array(
+ 'test' => 'another',
+ 'different_key' => 'new value'
+ ));
+
+ $this->assertEquals(array(
+ 'test' => array('value1', 'another'),
+ 'test2' => 'value2',
+ 'test3' => array('value3', 'value4'),
+ 'different_key' => 'new value'
+ ), $this->coll->getAll());
+ }
+
+ public function testAllowsFunctionalFilter()
+ {
+ $this->coll->merge(array(
+ 'fruit' => 'apple',
+ 'number' => 'ten',
+ 'prepositions' => array('about', 'above', 'across', 'after'),
+ 'same_number' => 'ten'
+ ));
+
+ $filtered = $this->coll->filter(function($key, $value) {
+ return $value == 'ten';
+ });
+
+ $this->assertNotEquals($filtered, $this->coll);
+
+ $this->assertEquals(array(
+ 'number' => 'ten',
+ 'same_number' => 'ten'
+ ), $filtered->getAll());
+ }
+
+ public function testAllowsFunctionalMapping()
+ {
+ $this->coll->merge(array(
+ 'number_1' => 1,
+ 'number_2' => 2,
+ 'number_3' => 3
+ ));
+
+ $mapped = $this->coll->map(function($key, $value) {
+ return $value * $value;
+ });
+
+ $this->assertNotEquals($mapped, $this->coll);
+
+ $this->assertEquals(array(
+ 'number_1' => 1,
+ 'number_2' => 4,
+ 'number_3' => 9
+ ), $mapped->getAll());
+ }
+
+ public function testImplementsArrayAccess()
+ {
+ $this->coll->merge(array(
+ 'k1' => 'v1',
+ 'k2' => 'v2'
+ ));
+
+ $this->assertTrue($this->coll->offsetExists('k1'));
+ $this->assertFalse($this->coll->offsetExists('Krull'));
+
+ $this->coll->offsetSet('k3', 'v3');
+ $this->assertEquals('v3', $this->coll->offsetGet('k3'));
+ $this->assertEquals('v3', $this->coll->get('k3'));
+
+ $this->coll->offsetUnset('k1');
+ $this->assertFalse($this->coll->offsetExists('k1'));
+ }
+
+ public function testUsesStaticWhenCreatingNew()
+ {
+ $qs = new QueryString(array(
+ 'a' => 'b',
+ 'c' => 'd'
+ ));
+
+ $this->assertInstanceOf('Guzzle\\Http\\QueryString', $qs->map(function($a, $b) {}));
+ $this->assertInstanceOf('Guzzle\\Common\\Collection', $qs->map(function($a, $b) {}, array(), false));
+
+ $this->assertInstanceOf('Guzzle\\Http\\QueryString', $qs->filter(function($a, $b) {}));
+ $this->assertInstanceOf('Guzzle\\Common\\Collection', $qs->filter(function($a, $b) {}, false));
+ }
+
+ public function testCanReplaceAllData()
+ {
+ $this->assertSame($this->coll, $this->coll->replace(array(
+ 'a' => '123'
+ )));
+
+ $this->assertEquals(array(
+ 'a' => '123'
+ ), $this->coll->getAll());
+ }
+
+ public function dataProvider()
+ {
+ return array(
+ array('this_is_a_test', '{a}_is_a_{b}', array(
+ 'a' => 'this',
+ 'b' => 'test'
+ )),
+ array('this_is_a_test', '{abc}_is_a_{0}', array(
+ 'abc' => 'this',
+ 0 => 'test'
+ )),
+ array('this_is_a_test', '{abc}_is_a_{0}', array(
+ 'abc' => 'this',
+ 0 => 'test'
+ )),
+ array('this_is_a_test', 'this_is_a_test', array(
+ 'abc' => 'this'
+ )),
+ array('{abc}_is_{not_found}a_{0}', '{abc}_is_{not_found}a_{0}', array())
+ );
+ }
+
+ /**
+ * @dataProvider dataProvider
+ */
+ public function testInjectsConfigData($output, $input, $config)
+ {
+ $collection = new Collection($config);
+ $this->assertEquals($output, $collection->inject($input));
+ }
+
+ public function testCanSearchByKey()
+ {
+ $collection = new Collection(array(
+ 'foo' => 'bar',
+ 'BaZ' => 'pho'
+ ));
+
+ $this->assertEquals('foo', $collection->keySearch('FOO'));
+ $this->assertEquals('BaZ', $collection->keySearch('baz'));
+ $this->assertEquals(false, $collection->keySearch('Bar'));
+ }
+
+ public function testPreparesFromConfig()
+ {
+ $c = Collection::fromConfig(array(
+ 'a' => '123',
+ 'base_url' => 'http://www.test.com/'
+ ), array(
+ 'a' => 'xyz',
+ 'b' => 'lol'
+ ), array('a'));
+
+ $this->assertInstanceOf('Guzzle\Common\Collection', $c);
+ $this->assertEquals(array(
+ 'a' => '123',
+ 'b' => 'lol',
+ 'base_url' => 'http://www.test.com/'
+ ), $c->getAll());
+
+ try {
+ $c = Collection::fromConfig(array(), array(), array('a'));
+ $this->fail('Exception not throw when missing config');
+ } catch (InvalidArgumentException $e) {
+ }
+ }
+
+ function falseyDataProvider()
+ {
+ return array(
+ array(false, false),
+ array(null, null),
+ array('', ''),
+ array(array(), array()),
+ array(0, 0),
+ );
+ }
+
+ /**
+ * @dataProvider falseyDataProvider
+ */
+ public function testReturnsCorrectData($a, $b)
+ {
+ $c = new Collection(array('value' => $a));
+ $this->assertSame($b, $c->get('value'));
+ }
+
+ public function testRetrievesNestedKeysUsingPath()
+ {
+ $data = array(
+ 'foo' => 'bar',
+ 'baz' => array(
+ 'mesa' => array(
+ 'jar' => 'jar'
+ )
+ )
+ );
+ $collection = new Collection($data);
+ $this->assertEquals('bar', $collection->getPath('foo'));
+ $this->assertEquals('jar', $collection->getPath('baz/mesa/jar'));
+ $this->assertNull($collection->getPath('wewewf'));
+ $this->assertNull($collection->getPath('baz/mesa/jar/jar'));
+ }
+
+ public function testFalseyKeysStillDescend()
+ {
+ $collection = new Collection(array(
+ '0' => array(
+ 'a' => 'jar'
+ ),
+ 1 => 'other'
+ ));
+ $this->assertEquals('jar', $collection->getPath('0/a'));
+ $this->assertEquals('other', $collection->getPath('1'));
+ }
+
+ public function getPathProvider()
+ {
+ $data = array(
+ 'foo' => 'bar',
+ 'baz' => array(
+ 'mesa' => array(
+ 'jar' => 'jar',
+ 'array' => array('a', 'b', 'c')
+ ),
+ 'bar' => array(
+ 'baz' => 'bam',
+ 'array' => array('d', 'e', 'f')
+ )
+ ),
+ 'bam' => array(
+ array('foo' => 1),
+ array('foo' => 2),
+ array('array' => array('h', 'i'))
+ )
+ );
+ $c = new Collection($data);
+
+ return array(
+ // Simple path selectors
+ array($c, 'foo', 'bar'),
+ array($c, 'baz', $data['baz']),
+ array($c, 'bam', $data['bam']),
+ array($c, 'baz/mesa', $data['baz']['mesa']),
+ array($c, 'baz/mesa/jar', 'jar'),
+ // Merge everything two levels under baz
+ array($c, 'baz/*', array(
+ 'jar' => 'jar',
+ 'array' => array_merge($data['baz']['mesa']['array'], $data['baz']['bar']['array']),
+ 'baz' => 'bam'
+ )),
+ // Does not barf on missing keys
+ array($c, 'fefwfw', null),
+ // Does not barf when a wildcard does not resolve correctly
+ array($c, '*/*/*/*/*/wefwfe', array()),
+ // Allows custom separator
+ array($c, '*|mesa', $data['baz']['mesa'], '|'),
+ // Merge all 'array' keys two levels under baz (the trailing * does not hurt the results)
+ array($c, 'baz/*/array/*', array_merge($data['baz']['mesa']['array'], $data['baz']['bar']['array'])),
+ // Merge all 'array' keys two levels under baz
+ array($c, 'baz/*/array', array_merge($data['baz']['mesa']['array'], $data['baz']['bar']['array'])),
+ array($c, 'baz/mesa/array', $data['baz']['mesa']['array']),
+ // Having a trailing * does not hurt the results
+ array($c, 'baz/mesa/array/*', $data['baz']['mesa']['array']),
+ // Merge of anything one level deep
+ array($c, '*', array_merge(array('bar'), $data['baz'], $data['bam'])),
+ // Funky merge of anything two levels deep
+ array($c, '*/*', array(
+ 'jar' => 'jar',
+ 'array' => array('a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'),
+ 'baz' => 'bam',
+ 'foo' => array(1, 2)
+ )),
+ // Funky merge of all 'array' keys that are two levels deep
+ array($c, '*/*/array', array('a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'))
+ );
+ }
+
+ /**
+ * @dataProvider getPathProvider
+ */
+ public function testGetPath(Collection $c, $path, $expected, $separator = '/')
+ {
+ $this->assertEquals($expected, $c->getPath($path, $separator));
+ }
+
+ public function testOverridesSettings()
+ {
+ $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
+ $c->overwriteWith(array('foo' => 10, 'bar' => 300));
+ $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->getAll());
+ }
+
+ public function testOverwriteWithCollection()
+ {
+ $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
+ $b = new Collection(array('foo' => 10, 'bar' => 300));
+ $c->overwriteWith($b);
+ $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->getAll());
+ }
+
+ public function testOverwriteWithTraversable()
+ {
+ $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3));
+ $b = new Collection(array('foo' => 10, 'bar' => 300));
+ $c->overwriteWith($b->getIterator());
+ $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->getAll());
+ }
+
+ public function testCanSetNestedPathValueThatDoesNotExist()
+ {
+ $c = new Collection(array());
+ $c->setPath('foo/bar/baz/123', 'hi');
+ $this->assertEquals('hi', $c['foo']['bar']['baz']['123']);
+ }
+
+ public function testCanSetNestedPathValueThatExists()
+ {
+ $c = new Collection(array('foo' => array('bar' => 'test')));
+ $c->setPath('foo/bar', 'hi');
+ $this->assertEquals('hi', $c['foo']['bar']);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ */
+ public function testVerifiesNestedPathIsValidAtExactLevel()
+ {
+ $c = new Collection(array('foo' => 'bar'));
+ $c->setPath('foo/bar', 'hi');
+ $this->assertEquals('hi', $c['foo']['bar']);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ */
+ public function testVerifiesThatNestedPathIsValidAtAnyLevel()
+ {
+ $c = new Collection(array('foo' => 'bar'));
+ $c->setPath('foo/bar/baz', 'test');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php
new file mode 100755
index 0000000..5484e14
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/EventTest.php
@@ -0,0 +1,62 @@
+ '123',
+ 'other' => '456',
+ 'event' => 'test.notify'
+ ));
+ }
+
+ public function testAllowsParameterInjection()
+ {
+ $event = new Event(array(
+ 'test' => '123'
+ ));
+ $this->assertEquals('123', $event['test']);
+ }
+
+ public function testImplementsArrayAccess()
+ {
+ $event = $this->getEvent();
+ $this->assertEquals('123', $event['test']);
+ $this->assertNull($event['foobar']);
+
+ $this->assertTrue($event->offsetExists('test'));
+ $this->assertFalse($event->offsetExists('foobar'));
+
+ unset($event['test']);
+ $this->assertFalse($event->offsetExists('test'));
+
+ $event['test'] = 'new';
+ $this->assertEquals('new', $event['test']);
+ }
+
+ public function testImplementsIteratorAggregate()
+ {
+ $event = $this->getEvent();
+ $this->assertInstanceOf('ArrayIterator', $event->getIterator());
+ }
+
+ public function testConvertsToArray()
+ {
+ $this->assertEquals(array(
+ 'test' => '123',
+ 'other' => '456',
+ 'event' => 'test.notify'
+ ), $this->getEvent()->toArray());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php
new file mode 100755
index 0000000..c72a2a6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/BatchTransferExceptionTest.php
@@ -0,0 +1,21 @@
+getMock('Guzzle\Batch\BatchTransferInterface');
+ $d = $this->getMock('Guzzle\Batch\BatchDivisorInterface');
+ $transferException = new BatchTransferException(array('foo'), array(1, 2), $e, $t, $d);
+ $this->assertEquals(array('foo'), $transferException->getBatch());
+ $this->assertSame($t, $transferException->getTransferStrategy());
+ $this->assertSame($d, $transferException->getDivisorStrategy());
+ $this->assertSame($e, $transferException->getPrevious());
+ $this->assertEquals(array(1, 2), $transferException->getTransferredItems());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php
new file mode 100755
index 0000000..2aecf2a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php
@@ -0,0 +1,66 @@
+getExceptions();
+ $e->add($exceptions[0]);
+ $e->add($exceptions[1]);
+ $this->assertContains("(Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $e->getMessage());
+ $this->assertContains(" Test\n\n #0 ./", $e->getMessage());
+ $this->assertSame($exceptions[0], $e->getFirst());
+ }
+
+ public function testCanSetExceptions()
+ {
+ $ex = new \Exception('foo');
+ $e = new ExceptionCollection();
+ $e->setExceptions(array($ex));
+ $this->assertSame($ex, $e->getFirst());
+ }
+
+ public function testActsAsArray()
+ {
+ $e = new ExceptionCollection();
+ $exceptions = $this->getExceptions();
+ $e->add($exceptions[0]);
+ $e->add($exceptions[1]);
+ $this->assertEquals(2, count($e));
+ $this->assertEquals($exceptions, $e->getIterator()->getArrayCopy());
+ }
+
+ public function testCanAddSelf()
+ {
+ $e1 = new ExceptionCollection();
+ $e1->add(new \Exception("Test"));
+ $e2 = new ExceptionCollection('Meta description!');
+ $e2->add(new \Exception("Test 2"));
+ $e3 = new ExceptionCollection();
+ $e3->add(new \Exception('Baz'));
+ $e2->add($e3);
+ $e1->add($e2);
+ $message = $e1->getMessage();
+ $this->assertContains("(Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message);
+ $this->assertContains("\n Test\n\n #0 ", $message);
+ $this->assertContains("\n\n(Guzzle\\Common\\Exception\\ExceptionCollection) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message);
+ $this->assertContains("\n\n Meta description!\n\n", $message);
+ $this->assertContains(" (Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message);
+ $this->assertContains("\n Test 2\n\n #0 ", $message);
+ $this->assertContains(" (Exception) ./tests/Guzzle/Tests/Common/Exception/ExceptionCollectionTest.php line ", $message);
+ $this->assertContains(" Baz\n\n #0", $message);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php
new file mode 100755
index 0000000..c3a81d1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Common/VersionTest.php
@@ -0,0 +1,27 @@
+isRunning()) {
+ self::$server->flush();
+ } else {
+ self::$server->start();
+ }
+ }
+
+ return self::$server;
+ }
+
+ /**
+ * Set the service builder to use for tests
+ *
+ * @param ServiceBuilderInterface $builder Service builder
+ */
+ public static function setServiceBuilder(ServiceBuilderInterface $builder)
+ {
+ self::$serviceBuilder = $builder;
+ }
+
+ /**
+ * Get a service builder object that can be used throughout the service tests
+ *
+ * @return ServiceBuilder
+ */
+ public static function getServiceBuilder()
+ {
+ if (!self::$serviceBuilder) {
+ throw new RuntimeException('No service builder has been set via setServiceBuilder()');
+ }
+
+ return self::$serviceBuilder;
+ }
+
+ /**
+ * Check if an event dispatcher has a subscriber
+ *
+ * @param HasDispatcherInterface $dispatcher
+ * @param EventSubscriberInterface $subscriber
+ *
+ * @return bool
+ */
+ protected function hasSubscriber(HasDispatcherInterface $dispatcher, EventSubscriberInterface $subscriber)
+ {
+ $class = get_class($subscriber);
+ $all = array_keys(call_user_func(array($class, 'getSubscribedEvents')));
+
+ foreach ($all as $i => $event) {
+ foreach ($dispatcher->getEventDispatcher()->getListeners($event) as $e) {
+ if ($e[0] === $subscriber) {
+ unset($all[$i]);
+ break;
+ }
+ }
+ }
+
+ return count($all) == 0;
+ }
+
+ /**
+ * Get a wildcard observer for an event dispatcher
+ *
+ * @param HasDispatcherInterface $hasDispatcher
+ *
+ * @return MockObserver
+ */
+ public function getWildcardObserver(HasDispatcherInterface $hasDispatcher)
+ {
+ $class = get_class($hasDispatcher);
+ $o = new MockObserver();
+ $events = call_user_func(array($class, 'getAllEvents'));
+ foreach ($events as $event) {
+ $hasDispatcher->getEventDispatcher()->addListener($event, array($o, 'update'));
+ }
+
+ return $o;
+ }
+
+ /**
+ * Set the mock response base path
+ *
+ * @param string $path Path to mock response folder
+ *
+ * @return GuzzleTestCase
+ */
+ public static function setMockBasePath($path)
+ {
+ self::$mockBasePath = $path;
+ }
+
+ /**
+ * Mark a request as being mocked
+ *
+ * @param RequestInterface $request
+ *
+ * @return self
+ */
+ public function addMockedRequest(RequestInterface $request)
+ {
+ $this->requests[] = $request;
+
+ return $this;
+ }
+
+ /**
+ * Get all of the mocked requests
+ *
+ * @return array
+ */
+ public function getMockedRequests()
+ {
+ return $this->requests;
+ }
+
+ /**
+ * Get a mock response for a client by mock file name
+ *
+ * @param string $path Relative path to the mock response file
+ *
+ * @return Response
+ */
+ public function getMockResponse($path)
+ {
+ return $path instanceof Response
+ ? $path
+ : MockPlugin::getMockFile(self::$mockBasePath . DIRECTORY_SEPARATOR . $path);
+ }
+
+ /**
+ * Set a mock response from a mock file on the next client request.
+ *
+ * This method assumes that mock response files are located under the
+ * Command/Mock/ directory of the Service being tested
+ * (e.g. Unfuddle/Command/Mock/). A mock response is added to the next
+ * request sent by the client.
+ *
+ * @param Client $client Client object to modify
+ * @param string $paths Path to files within the Mock folder of the service
+ *
+ * @return MockPlugin returns the created mock plugin
+ */
+ public function setMockResponse(Client $client, $paths)
+ {
+ $this->requests = array();
+ $that = $this;
+ $mock = new MockPlugin(null, true);
+ $client->getEventDispatcher()->removeSubscriber($mock);
+ $mock->getEventDispatcher()->addListener('mock.request', function(Event $event) use ($that) {
+ $that->addMockedRequest($event['request']);
+ });
+
+ if ($paths instanceof Response) {
+ // A single response instance has been specified, create an array with that instance
+ // as the only element for the following loop to work as expected
+ $paths = array($paths);
+ }
+
+ foreach ((array) $paths as $path) {
+ $mock->addResponse($this->getMockResponse($path));
+ }
+
+ $client->getEventDispatcher()->addSubscriber($mock);
+
+ return $mock;
+ }
+
+ /**
+ * Compare HTTP headers and use special markup to filter values
+ * A header prefixed with '!' means it must not exist
+ * A header prefixed with '_' means it must be ignored
+ * A header value of '*' means anything after the * will be ignored
+ *
+ * @param array $filteredHeaders Array of special headers
+ * @param array $actualHeaders Array of headers to check against
+ *
+ * @return array|bool Returns an array of the differences or FALSE if none
+ */
+ public function compareHeaders($filteredHeaders, $actualHeaders)
+ {
+ $comparison = new HeaderComparison();
+
+ return $comparison->compare($filteredHeaders, $actualHeaders);
+ }
+
+ /**
+ * Case insensitive assertContains
+ *
+ * @param string $needle Search string
+ * @param string $haystack Search this
+ * @param string $message Optional failure message
+ */
+ public function assertContainsIns($needle, $haystack, $message = null)
+ {
+ $this->assertContains(strtolower($needle), strtolower($haystack), $message);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php
new file mode 100755
index 0000000..20feaa8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/AbstractEntityBodyDecoratorTest.php
@@ -0,0 +1,34 @@
+getMockForAbstractClass('Guzzle\Http\AbstractEntityBodyDecorator', array($e));
+
+ $this->assertSame($e->getStream(), $mock->getStream());
+ $this->assertSame($e->getContentLength(), $mock->getContentLength());
+ $this->assertSame($e->getSize(), $mock->getSize());
+ $this->assertSame($e->getContentMd5(), $mock->getContentMd5());
+ $this->assertSame($e->getContentType(), $mock->getContentType());
+ $this->assertSame($e->__toString(), $mock->__toString());
+ $this->assertSame($e->getUri(), $mock->getUri());
+ $this->assertSame($e->getStreamType(), $mock->getStreamType());
+ $this->assertSame($e->getWrapper(), $mock->getWrapper());
+ $this->assertSame($e->getWrapperData(), $mock->getWrapperData());
+ $this->assertSame($e->isReadable(), $mock->isReadable());
+ $this->assertSame($e->isWritable(), $mock->isWritable());
+ $this->assertSame($e->isConsumed(), $mock->isConsumed());
+ $this->assertSame($e->isLocal(), $mock->isLocal());
+ $this->assertSame($e->isSeekable(), $mock->isSeekable());
+ $this->assertSame($e->getContentEncoding(), $mock->getContentEncoding());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php
new file mode 100755
index 0000000..e6e6cdb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/CachingEntityBodyTest.php
@@ -0,0 +1,249 @@
+decorated = EntityBody::factory('testing');
+ $this->body = new CachingEntityBody($this->decorated);
+ }
+
+ public function testUsesRemoteSizeIfPossible()
+ {
+ $body = EntityBody::factory('test');
+ $caching = new CachingEntityBody($body);
+ $this->assertEquals(4, $caching->getSize());
+ $this->assertEquals(4, $caching->getContentLength());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ * @expectedExceptionMessage does not support custom stream rewind
+ */
+ public function testDoesNotAllowRewindFunction()
+ {
+ $this->body->setRewindFunction(true);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ * @expectedExceptionMessage Cannot seek to byte 10
+ */
+ public function testCannotSeekPastWhatHasBeenRead()
+ {
+ $this->body->seek(10);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ * @expectedExceptionMessage supports only SEEK_SET and SEEK_CUR
+ */
+ public function testCannotUseSeekEnd()
+ {
+ $this->body->seek(2, SEEK_END);
+ }
+
+ public function testChangingUnderlyingStreamUpdatesSizeAndStream()
+ {
+ $size = filesize(__FILE__);
+ $s = fopen(__FILE__, 'r');
+ $this->body->setStream($s, $size);
+ $this->assertEquals($size, $this->body->getSize());
+ $this->assertEquals($size, $this->decorated->getSize());
+ $this->assertSame($s, $this->body->getStream());
+ $this->assertSame($s, $this->decorated->getStream());
+ }
+
+ public function testRewindUsesSeek()
+ {
+ $a = EntityBody::factory('foo');
+ $d = $this->getMockBuilder('Guzzle\Http\CachingEntityBody')
+ ->setMethods(array('seek'))
+ ->setConstructorArgs(array($a))
+ ->getMock();
+ $d->expects($this->once())
+ ->method('seek')
+ ->with(0)
+ ->will($this->returnValue(true));
+ $d->rewind();
+ }
+
+ public function testCanSeekToReadBytes()
+ {
+ $this->assertEquals('te', $this->body->read(2));
+ $this->body->seek(0);
+ $this->assertEquals('test', $this->body->read(4));
+ $this->assertEquals(4, $this->body->ftell());
+ $this->body->seek(2);
+ $this->assertEquals(2, $this->body->ftell());
+ $this->body->seek(2, SEEK_CUR);
+ $this->assertEquals(4, $this->body->ftell());
+ $this->assertEquals('ing', $this->body->read(3));
+ }
+
+ public function testWritesToBufferStream()
+ {
+ $this->body->read(2);
+ $this->body->write('hi');
+ $this->body->rewind();
+ $this->assertEquals('tehiing', (string) $this->body);
+ }
+
+ public function testReadLinesFromBothStreams()
+ {
+ $this->body->seek($this->body->ftell());
+ $this->body->write("test\n123\nhello\n1234567890\n");
+ $this->body->rewind();
+ $this->assertEquals("test\n", $this->body->readLine(7));
+ $this->assertEquals("123\n", $this->body->readLine(7));
+ $this->assertEquals("hello\n", $this->body->readLine(7));
+ $this->assertEquals("123456", $this->body->readLine(7));
+ $this->assertEquals("7890\n", $this->body->readLine(7));
+ // We overwrote the decorated stream, so no more data
+ $this->assertEquals('', $this->body->readLine(7));
+ }
+
+ public function testSkipsOverwrittenBytes()
+ {
+ $decorated = EntityBody::factory(
+ implode("\n", array_map(function ($n) {
+ return str_pad($n, 4, '0', STR_PAD_LEFT);
+ }, range(0, 25)))
+ );
+
+ $body = new CachingEntityBody($decorated);
+
+ $this->assertEquals("0000\n", $body->readLine());
+ $this->assertEquals("0001\n", $body->readLine());
+ // Write over part of the body yet to be read, so skip some bytes
+ $this->assertEquals(5, $body->write("TEST\n"));
+ $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes'));
+ // Read, which skips bytes, then reads
+ $this->assertEquals("0003\n", $body->readLine());
+ $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes'));
+ $this->assertEquals("0004\n", $body->readLine());
+ $this->assertEquals("0005\n", $body->readLine());
+
+ // Overwrite part of the cached body (so don't skip any bytes)
+ $body->seek(5);
+ $this->assertEquals(5, $body->write("ABCD\n"));
+ $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes'));
+ $this->assertEquals("TEST\n", $body->readLine());
+ $this->assertEquals("0003\n", $body->readLine());
+ $this->assertEquals("0004\n", $body->readLine());
+ $this->assertEquals("0005\n", $body->readLine());
+ $this->assertEquals("0006\n", $body->readLine());
+ $this->assertEquals(5, $body->write("1234\n"));
+ $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes'));
+
+ // Seek to 0 and ensure the overwritten bit is replaced
+ $body->rewind();
+ $this->assertEquals("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", $body->read(50));
+
+ // Ensure that casting it to a string does not include the bit that was overwritten
+ $this->assertContains("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", (string) $body);
+ }
+
+ public function testWrapsContentType()
+ {
+ $a = $this->getMockBuilder('Guzzle\Http\EntityBody')
+ ->setMethods(array('getContentType'))
+ ->setConstructorArgs(array(fopen(__FILE__, 'r')))
+ ->getMock();
+ $a->expects($this->once())
+ ->method('getContentType')
+ ->will($this->returnValue('foo'));
+ $d = new CachingEntityBody($a);
+ $this->assertEquals('foo', $d->getContentType());
+ }
+
+ public function testWrapsContentEncoding()
+ {
+ $a = $this->getMockBuilder('Guzzle\Http\EntityBody')
+ ->setMethods(array('getContentEncoding'))
+ ->setConstructorArgs(array(fopen(__FILE__, 'r')))
+ ->getMock();
+ $a->expects($this->once())
+ ->method('getContentEncoding')
+ ->will($this->returnValue('foo'));
+ $d = new CachingEntityBody($a);
+ $this->assertEquals('foo', $d->getContentEncoding());
+ }
+
+ public function testWrapsMetadata()
+ {
+ $a = $this->getMockBuilder('Guzzle\Http\EntityBody')
+ ->setMethods(array('getMetadata', 'getWrapper', 'getWrapperData', 'getStreamType', 'getUri'))
+ ->setConstructorArgs(array(fopen(__FILE__, 'r')))
+ ->getMock();
+
+ $a->expects($this->once())
+ ->method('getMetadata')
+ ->will($this->returnValue(array()));
+ // Called twice for getWrapper and getWrapperData
+ $a->expects($this->exactly(1))
+ ->method('getWrapper')
+ ->will($this->returnValue('wrapper'));
+ $a->expects($this->once())
+ ->method('getWrapperData')
+ ->will($this->returnValue(array()));
+ $a->expects($this->once())
+ ->method('getStreamType')
+ ->will($this->returnValue('baz'));
+ $a->expects($this->once())
+ ->method('getUri')
+ ->will($this->returnValue('path/to/foo'));
+
+ $d = new CachingEntityBody($a);
+ $this->assertEquals(array(), $d->getMetaData());
+ $this->assertEquals('wrapper', $d->getWrapper());
+ $this->assertEquals(array(), $d->getWrapperData());
+ $this->assertEquals('baz', $d->getStreamType());
+ $this->assertEquals('path/to/foo', $d->getUri());
+ }
+
+ public function testWrapsCustomData()
+ {
+ $a = $this->getMockBuilder('Guzzle\Http\EntityBody')
+ ->setMethods(array('getCustomData', 'setCustomData'))
+ ->setConstructorArgs(array(fopen(__FILE__, 'r')))
+ ->getMock();
+
+ $a->expects($this->exactly(1))
+ ->method('getCustomData')
+ ->with('foo')
+ ->will($this->returnValue('bar'));
+
+ $a->expects($this->exactly(1))
+ ->method('setCustomData')
+ ->with('foo', 'bar')
+ ->will($this->returnSelf());
+
+ $d = new CachingEntityBody($a);
+ $this->assertSame($d, $d->setCustomData('foo', 'bar'));
+ $this->assertEquals('bar', $d->getCustomData('foo'));
+ }
+
+ public function testClosesBothStreams()
+ {
+ $s = fopen('php://temp', 'r');
+ $a = EntityBody::factory($s);
+ $d = new CachingEntityBody($a);
+ $d->close();
+ $this->assertFalse(is_resource($s));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php
new file mode 100755
index 0000000..4a91a18
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ClientTest.php
@@ -0,0 +1,601 @@
+assertEquals('http://www.google.com/', $client->getBaseUrl());
+ $this->assertSame($client, $client->setConfig(array(
+ 'test' => '123'
+ )));
+ $this->assertEquals(array('test' => '123'), $client->getConfig()->getAll());
+ $this->assertEquals('123', $client->getConfig('test'));
+ $this->assertSame($client, $client->setBaseUrl('http://www.test.com/{test}'));
+ $this->assertEquals('http://www.test.com/123', $client->getBaseUrl());
+ $this->assertEquals('http://www.test.com/{test}', $client->getBaseUrl(false));
+
+ try {
+ $client->setConfig(false);
+ } catch (\InvalidArgumentException $e) {
+ }
+ }
+
+ public function testDescribesEvents()
+ {
+ $this->assertEquals(array('client.create_request'), Client::getAllEvents());
+ }
+
+ public function testConstructorCanAcceptConfig()
+ {
+ $client = new Client('http://www.test.com/', array(
+ 'data' => '123'
+ ));
+ $this->assertEquals('123', $client->getConfig('data'));
+ }
+
+ public function testCanUseCollectionAsConfig()
+ {
+ $client = new Client('http://www.google.com/');
+ $client->setConfig(new Collection(array(
+ 'api' => 'v1',
+ 'key' => 'value',
+ 'base_url' => 'http://www.google.com/'
+ )));
+ $this->assertEquals('v1', $client->getConfig('api'));
+ }
+
+ public function testExpandsUriTemplatesUsingConfig()
+ {
+ $client = new Client('http://www.google.com/');
+ $client->setConfig(array('api' => 'v1', 'key' => 'value', 'foo' => 'bar'));
+ $ref = new \ReflectionMethod($client, 'expandTemplate');
+ $ref->setAccessible(true);
+ $this->assertEquals('Testing...api/v1/key/value', $ref->invoke($client, 'Testing...api/{api}/key/{key}'));
+ }
+
+ public function testClientAttachersObserversToRequests()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+
+ $client = new Client($this->getServer()->getUrl());
+ $logPlugin = $this->getLogPlugin();
+ $client->getEventDispatcher()->addSubscriber($logPlugin);
+
+ // Get a request from the client and ensure the the observer was
+ // attached to the new request
+ $request = $client->createRequest();
+ $this->assertTrue($this->hasSubscriber($request, $logPlugin));
+ }
+
+ public function testClientReturnsValidBaseUrls()
+ {
+ $client = new Client('http://www.{foo}.{data}/', array(
+ 'data' => '123',
+ 'foo' => 'bar'
+ ));
+ $this->assertEquals('http://www.bar.123/', $client->getBaseUrl());
+ $client->setBaseUrl('http://www.google.com/');
+ $this->assertEquals('http://www.google.com/', $client->getBaseUrl());
+ }
+
+ public function testClientAddsCurlOptionsToRequests()
+ {
+ $client = new Client('http://www.test.com/', array(
+ 'api' => 'v1',
+ // Adds the option using the curl values
+ 'curl.options' => array(
+ 'CURLOPT_HTTPAUTH' => 'CURLAUTH_DIGEST',
+ 'abc' => 'foo',
+ 'blacklist' => 'abc',
+ 'debug' => true
+ )
+ ));
+
+ $request = $client->createRequest();
+ $options = $request->getCurlOptions();
+ $this->assertEquals(CURLAUTH_DIGEST, $options->get(CURLOPT_HTTPAUTH));
+ $this->assertEquals('foo', $options->get('abc'));
+ $this->assertEquals('abc', $options->get('blacklist'));
+ }
+
+ public function testClientAllowsFineGrainedSslControlButIsSecureByDefault()
+ {
+ $client = new Client('https://www.secure.com/');
+
+ // secure by default
+ $request = $client->createRequest();
+ $options = $request->getCurlOptions();
+ $this->assertTrue($options->get(CURLOPT_SSL_VERIFYPEER));
+
+ // set a capath if you prefer
+ $client = new Client('https://www.secure.com/');
+ $client->setSslVerification(__DIR__);
+ $request = $client->createRequest();
+ $options = $request->getCurlOptions();
+ $this->assertSame(__DIR__, $options->get(CURLOPT_CAPATH));
+ }
+
+ public function testConfigSettingsControlSslConfiguration()
+ {
+ // Use the default ca certs on the system
+ $client = new Client('https://www.secure.com/', array('ssl.certificate_authority' => 'system'));
+ $this->assertNull($client->getConfig('curl.options'));
+ // Can set the cacert value as well
+ $client = new Client('https://www.secure.com/', array('ssl.certificate_authority' => false));
+ $options = $client->getConfig('curl.options');
+ $this->assertArrayNotHasKey(CURLOPT_CAINFO, $options);
+ $this->assertSame(false, $options[CURLOPT_SSL_VERIFYPEER]);
+ $this->assertSame(0, $options[CURLOPT_SSL_VERIFYHOST]);
+ }
+
+ public function testClientAllowsUnsafeOperationIfRequested()
+ {
+ // be really unsafe if you insist
+ $client = new Client('https://www.secure.com/', array(
+ 'api' => 'v1'
+ ));
+
+ $client->setSslVerification(false);
+ $request = $client->createRequest();
+ $options = $request->getCurlOptions();
+ $this->assertFalse($options->get(CURLOPT_SSL_VERIFYPEER));
+ $this->assertNull($options->get(CURLOPT_CAINFO));
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ */
+ public function testThrowsExceptionForInvalidCertificate()
+ {
+ $client = new Client('https://www.secure.com/');
+ $client->setSslVerification('/path/to/missing/file');
+ }
+
+ public function testClientAllowsSettingSpecificSslCaInfo()
+ {
+ // set a file other than the provided cacert.pem
+ $client = new Client('https://www.secure.com/', array(
+ 'api' => 'v1'
+ ));
+
+ $client->setSslVerification(__FILE__);
+ $request = $client->createRequest();
+ $options = $request->getCurlOptions();
+ $this->assertSame(__FILE__, $options->get(CURLOPT_CAINFO));
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testClientPreventsInadvertentInsecureVerifyHostSetting()
+ {
+ // set a file other than the provided cacert.pem
+ $client = new Client('https://www.secure.com/', array(
+ 'api' => 'v1'
+ ));
+ $client->setSslVerification(__FILE__, true, true);
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testClientPreventsInvalidVerifyPeerSetting()
+ {
+ // set a file other than the provided cacert.pem
+ $client = new Client('https://www.secure.com/', array(
+ 'api' => 'v1'
+ ));
+ $client->setSslVerification(__FILE__, 'yes');
+ }
+
+ public function testClientAddsParamsToRequests()
+ {
+ Version::$emitWarnings = false;
+ $client = new Client('http://www.example.com', array(
+ 'api' => 'v1',
+ 'request.params' => array(
+ 'foo' => 'bar',
+ 'baz' => 'jar'
+ )
+ ));
+ $request = $client->createRequest();
+ $this->assertEquals('bar', $request->getParams()->get('foo'));
+ $this->assertEquals('jar', $request->getParams()->get('baz'));
+ Version::$emitWarnings = true;
+ }
+
+ public function urlProvider()
+ {
+ $u = $this->getServer()->getUrl() . 'base/';
+ $u2 = $this->getServer()->getUrl() . 'base?z=1';
+ return array(
+ array($u, '', $u),
+ array($u, 'relative/path/to/resource', $u . 'relative/path/to/resource'),
+ array($u, 'relative/path/to/resource?a=b&c=d', $u . 'relative/path/to/resource?a=b&c=d'),
+ array($u, '/absolute/path/to/resource', $this->getServer()->getUrl() . 'absolute/path/to/resource'),
+ array($u, '/absolute/path/to/resource?a=b&c=d', $this->getServer()->getUrl() . 'absolute/path/to/resource?a=b&c=d'),
+ array($u2, '/absolute/path/to/resource?a=b&c=d', $this->getServer()->getUrl() . 'absolute/path/to/resource?a=b&c=d&z=1'),
+ array($u2, 'relative/path/to/resource', $this->getServer()->getUrl() . 'base/relative/path/to/resource?z=1'),
+ array($u2, 'relative/path/to/resource?another=query', $this->getServer()->getUrl() . 'base/relative/path/to/resource?another=query&z=1')
+ );
+ }
+
+ /**
+ * @dataProvider urlProvider
+ */
+ public function testBuildsRelativeUrls($baseUrl, $url, $result)
+ {
+ $client = new Client($baseUrl);
+ $this->assertEquals($result, $client->get($url)->getUrl());
+ }
+
+ public function testAllowsConfigsToBeChangedAndInjectedInBaseUrl()
+ {
+ $client = new Client('http://{a}/{b}');
+ $this->assertEquals('http:///', $client->getBaseUrl());
+ $this->assertEquals('http://{a}/{b}', $client->getBaseUrl(false));
+ $client->setConfig(array(
+ 'a' => 'test.com',
+ 'b' => 'index.html'
+ ));
+ $this->assertEquals('http://test.com/index.html', $client->getBaseUrl());
+ }
+
+ public function testCreatesRequestsWithDefaultValues()
+ {
+ $client = new Client($this->getServer()->getUrl() . 'base');
+
+ // Create a GET request
+ $request = $client->createRequest();
+ $this->assertEquals('GET', $request->getMethod());
+ $this->assertEquals($client->getBaseUrl(), $request->getUrl());
+
+ // Create a DELETE request
+ $request = $client->createRequest('DELETE');
+ $this->assertEquals('DELETE', $request->getMethod());
+ $this->assertEquals($client->getBaseUrl(), $request->getUrl());
+
+ // Create a HEAD request with custom headers
+ $request = $client->createRequest('HEAD', 'http://www.test.com/');
+ $this->assertEquals('HEAD', $request->getMethod());
+ $this->assertEquals('http://www.test.com/', $request->getUrl());
+
+ // Create a PUT request
+ $request = $client->createRequest('PUT');
+ $this->assertEquals('PUT', $request->getMethod());
+
+ // Create a PUT request with injected config
+ $client->getConfig()->set('a', 1)->set('b', 2);
+ $request = $client->createRequest('PUT', '/path/{a}?q={b}');
+ $this->assertEquals($request->getUrl(), $this->getServer()->getUrl() . 'path/1?q=2');
+ }
+
+ public function testClientHasHelperMethodsForCreatingRequests()
+ {
+ $url = $this->getServer()->getUrl();
+ $client = new Client($url . 'base');
+ $this->assertEquals('GET', $client->get()->getMethod());
+ $this->assertEquals('PUT', $client->put()->getMethod());
+ $this->assertEquals('POST', $client->post()->getMethod());
+ $this->assertEquals('HEAD', $client->head()->getMethod());
+ $this->assertEquals('DELETE', $client->delete()->getMethod());
+ $this->assertEquals('OPTIONS', $client->options()->getMethod());
+ $this->assertEquals('PATCH', $client->patch()->getMethod());
+ $this->assertEquals($url . 'base/abc', $client->get('abc')->getUrl());
+ $this->assertEquals($url . 'zxy', $client->put('/zxy')->getUrl());
+ $this->assertEquals($url . 'zxy?a=b', $client->post('/zxy?a=b')->getUrl());
+ $this->assertEquals($url . 'base?a=b', $client->head('?a=b')->getUrl());
+ $this->assertEquals($url . 'base?a=b', $client->delete('/base?a=b')->getUrl());
+ }
+
+ public function testClientInjectsConfigsIntoUrls()
+ {
+ $client = new Client('http://www.test.com/api/v1', array(
+ 'test' => '123'
+ ));
+ $request = $client->get('relative/{test}');
+ $this->assertEquals('http://www.test.com/api/v1/relative/123', $request->getUrl());
+ }
+
+ public function testAllowsEmptyBaseUrl()
+ {
+ $client = new Client();
+ $request = $client->get('http://www.google.com/');
+ $this->assertEquals('http://www.google.com/', $request->getUrl());
+ $request->setResponse(new Response(200), true);
+ $request->send();
+ }
+
+ public function testAllowsCustomCurlMultiObjects()
+ {
+ $mock = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('add', 'send'));
+ $mock->expects($this->once())
+ ->method('add')
+ ->will($this->returnSelf());
+ $mock->expects($this->once())
+ ->method('send')
+ ->will($this->returnSelf());
+
+ $client = new Client();
+ $client->setCurlMulti($mock);
+
+ $request = $client->get();
+ $request->setResponse(new Response(200), true);
+ $client->send($request);
+ }
+
+ public function testClientSendsMultipleRequests()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $mock = new MockPlugin();
+
+ $responses = array(
+ new Response(200),
+ new Response(201),
+ new Response(202)
+ );
+
+ $mock->addResponse($responses[0]);
+ $mock->addResponse($responses[1]);
+ $mock->addResponse($responses[2]);
+
+ $client->getEventDispatcher()->addSubscriber($mock);
+
+ $requests = array(
+ $client->get(),
+ $client->head(),
+ $client->put('/', null, 'test')
+ );
+
+ $this->assertEquals(array(
+ $responses[0],
+ $responses[1],
+ $responses[2]
+ ), $client->send($requests));
+ }
+
+ public function testClientSendsSingleRequest()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $mock = new MockPlugin();
+ $response = new Response(200);
+ $mock->addResponse($response);
+ $client->getEventDispatcher()->addSubscriber($mock);
+ $this->assertEquals($response, $client->send($client->get()));
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\BadResponseException
+ */
+ public function testClientThrowsExceptionForSingleRequest()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $mock = new MockPlugin();
+ $response = new Response(404);
+ $mock->addResponse($response);
+ $client->getEventDispatcher()->addSubscriber($mock);
+ $client->send($client->get());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\ExceptionCollection
+ */
+ public function testClientThrowsExceptionForMultipleRequests()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $mock = new MockPlugin();
+ $mock->addResponse(new Response(200));
+ $mock->addResponse(new Response(404));
+ $client->getEventDispatcher()->addSubscriber($mock);
+ $client->send(array($client->get(), $client->head()));
+ }
+
+ public function testQueryStringsAreNotDoubleEncoded()
+ {
+ $client = new Client('http://test.com', array(
+ 'path' => array('foo', 'bar'),
+ 'query' => 'hi there',
+ 'data' => array(
+ 'test' => 'a&b'
+ )
+ ));
+
+ $request = $client->get('{/path*}{?query,data*}');
+ $this->assertEquals('http://test.com/foo/bar?query=hi%20there&test=a%26b', $request->getUrl());
+ $this->assertEquals('hi there', $request->getQuery()->get('query'));
+ $this->assertEquals('a&b', $request->getQuery()->get('test'));
+ }
+
+ public function testQueryStringsAreNotDoubleEncodedUsingAbsolutePaths()
+ {
+ $client = new Client('http://test.com', array(
+ 'path' => array('foo', 'bar'),
+ 'query' => 'hi there',
+ ));
+ $request = $client->get('http://test.com{?query}');
+ $this->assertEquals('http://test.com?query=hi%20there', $request->getUrl());
+ $this->assertEquals('hi there', $request->getQuery()->get('query'));
+ }
+
+ public function testAllowsUriTemplateInjection()
+ {
+ $client = new Client('http://test.com');
+ $ref = new \ReflectionMethod($client, 'getUriTemplate');
+ $ref->setAccessible(true);
+ $a = $ref->invoke($client);
+ $this->assertSame($a, $ref->invoke($client));
+ $client->setUriTemplate(new UriTemplate());
+ $this->assertNotSame($a, $ref->invoke($client));
+ }
+
+ public function testAllowsCustomVariablesWhenExpandingTemplates()
+ {
+ $client = new Client('http://test.com', array('test' => 'hi'));
+ $ref = new \ReflectionMethod($client, 'expandTemplate');
+ $ref->setAccessible(true);
+ $uri = $ref->invoke($client, 'http://{test}{?query*}', array('query' => array('han' => 'solo')));
+ $this->assertEquals('http://hi?han=solo', $uri);
+ }
+
+ public function testUriArrayAllowsCustomTemplateVariables()
+ {
+ $client = new Client();
+ $vars = array(
+ 'var' => 'hi'
+ );
+ $this->assertEquals('/hi', (string) $client->createRequest('GET', array('/{var}', $vars))->getUrl());
+ $this->assertEquals('/hi', (string) $client->get(array('/{var}', $vars))->getUrl());
+ $this->assertEquals('/hi', (string) $client->put(array('/{var}', $vars))->getUrl());
+ $this->assertEquals('/hi', (string) $client->post(array('/{var}', $vars))->getUrl());
+ $this->assertEquals('/hi', (string) $client->head(array('/{var}', $vars))->getUrl());
+ $this->assertEquals('/hi', (string) $client->options(array('/{var}', $vars))->getUrl());
+ }
+
+ public function testAllowsDefaultHeaders()
+ {
+ Version::$emitWarnings = false;
+ $default = array('X-Test' => 'Hi!');
+ $other = array('X-Other' => 'Foo');
+
+ $client = new Client();
+ $client->setDefaultHeaders($default);
+ $this->assertEquals($default, $client->getDefaultHeaders()->getAll());
+ $client->setDefaultHeaders(new Collection($default));
+ $this->assertEquals($default, $client->getDefaultHeaders()->getAll());
+
+ $request = $client->createRequest('GET', null, $other);
+ $this->assertEquals('Hi!', $request->getHeader('X-Test'));
+ $this->assertEquals('Foo', $request->getHeader('X-Other'));
+
+ $request = $client->createRequest('GET', null, new Collection($other));
+ $this->assertEquals('Hi!', $request->getHeader('X-Test'));
+ $this->assertEquals('Foo', $request->getHeader('X-Other'));
+
+ $request = $client->createRequest('GET');
+ $this->assertEquals('Hi!', $request->getHeader('X-Test'));
+ Version::$emitWarnings = true;
+ }
+
+ public function testDontReuseCurlMulti()
+ {
+ $client1 = new Client();
+ $client2 = new Client();
+ $this->assertNotSame($client1->getCurlMulti(), $client2->getCurlMulti());
+ }
+
+ public function testGetDefaultUserAgent()
+ {
+ $client = new Client();
+ $agent = $this->readAttribute($client, 'userAgent');
+ $version = curl_version();
+ $testAgent = sprintf('Guzzle/%s curl/%s PHP/%s', Version::VERSION, $version['version'], PHP_VERSION);
+ $this->assertEquals($agent, $testAgent);
+
+ $client->setUserAgent('foo');
+ $this->assertEquals('foo', $this->readAttribute($client, 'userAgent'));
+ }
+
+ public function testOverwritesUserAgent()
+ {
+ $client = new Client();
+ $request = $client->createRequest('GET', 'http://www.foo.com', array('User-agent' => 'foo'));
+ $this->assertEquals('foo', (string) $request->getHeader('User-Agent'));
+ }
+
+ public function testUsesDefaultUserAgent()
+ {
+ $client = new Client();
+ $request = $client->createRequest('GET', 'http://www.foo.com');
+ $this->assertContains('Guzzle/', (string) $request->getHeader('User-Agent'));
+ }
+
+ public function testCanSetDefaultRequestOptions()
+ {
+ $client = new Client();
+ $client->getConfig()->set('request.options', array(
+ 'query' => array('test' => '123', 'other' => 'abc'),
+ 'headers' => array('Foo' => 'Bar', 'Baz' => 'Bam')
+ ));
+ $request = $client->createRequest('GET', 'http://www.foo.com?test=hello', array('Foo' => 'Test'));
+ // Explicit options on a request should overrule default options
+ $this->assertEquals('Test', (string) $request->getHeader('Foo'));
+ $this->assertEquals('hello', $request->getQuery()->get('test'));
+ // Default options should still be set
+ $this->assertEquals('abc', $request->getQuery()->get('other'));
+ $this->assertEquals('Bam', (string) $request->getHeader('Baz'));
+ }
+
+ public function testCanSetSetOptionsOnRequests()
+ {
+ $client = new Client();
+ $request = $client->createRequest('GET', 'http://www.foo.com?test=hello', array('Foo' => 'Test'), null, array(
+ 'cookies' => array('michael' => 'test')
+ ));
+ $this->assertEquals('test', $request->getCookie('michael'));
+ }
+
+ public function testHasDefaultOptionsHelperMethods()
+ {
+ $client = new Client();
+ // With path
+ $client->setDefaultOption('headers/foo', 'bar');
+ $this->assertEquals('bar', $client->getDefaultOption('headers/foo'));
+ // With simple key
+ $client->setDefaultOption('allow_redirects', false);
+ $this->assertFalse($client->getDefaultOption('allow_redirects'));
+
+ $this->assertEquals(array(
+ 'headers' => array('foo' => 'bar'),
+ 'allow_redirects' => false
+ ), $client->getConfig('request.options'));
+
+ $request = $client->get('/');
+ $this->assertEquals('bar', $request->getHeader('foo'));
+ }
+
+ public function testHeadCanUseOptions()
+ {
+ $client = new Client();
+ $head = $client->head('http://www.foo.com', array(), array('query' => array('foo' => 'bar')));
+ $this->assertEquals('bar', $head->getQuery()->get('foo'));
+ }
+
+ public function testCanSetRelativeUrlStartingWithHttp()
+ {
+ $client = new Client('http://www.foo.com');
+ $this->assertEquals(
+ 'http://www.foo.com/httpfoo',
+ $client->createRequest('GET', 'httpfoo')->getUrl()
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php
new file mode 100755
index 0000000..5bf28de
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlHandleTest.php
@@ -0,0 +1,947 @@
+getEventDispatcher()->addListener('request.sent', function (Event $e) use ($that) {
+ $that->requestHandle = $e['handle'];
+ });
+
+ return $request;
+ }
+
+ public function setUp()
+ {
+ $this->requestHandle = null;
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testConstructorExpectsCurlResource()
+ {
+ $h = new CurlHandle(false, array());
+ }
+
+ public function testConstructorExpectsProperOptions()
+ {
+ $h = curl_init($this->getServer()->getUrl());
+ try {
+ $ha = new CurlHandle($h, false);
+ $this->fail('Expected InvalidArgumentException');
+ } catch (\InvalidArgumentException $e) {
+ }
+
+ $ha = new CurlHandle($h, array(
+ CURLOPT_URL => $this->getServer()->getUrl()
+ ));
+ $this->assertEquals($this->getServer()->getUrl(), $ha->getOptions()->get(CURLOPT_URL));
+
+ $ha = new CurlHandle($h, new Collection(array(
+ CURLOPT_URL => $this->getServer()->getUrl()
+ )));
+ $this->assertEquals($this->getServer()->getUrl(), $ha->getOptions()->get(CURLOPT_URL));
+ }
+
+ public function testConstructorInitializesObject()
+ {
+ $handle = curl_init($this->getServer()->getUrl());
+ $h = new CurlHandle($handle, array(
+ CURLOPT_URL => $this->getServer()->getUrl()
+ ));
+ $this->assertSame($handle, $h->getHandle());
+ $this->assertInstanceOf('Guzzle\\Http\\Url', $h->getUrl());
+ $this->assertEquals($this->getServer()->getUrl(), (string) $h->getUrl());
+ $this->assertEquals($this->getServer()->getUrl(), $h->getOptions()->get(CURLOPT_URL));
+ }
+
+ public function testStoresStdErr()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://test.com');
+ $request->getCurlOptions()->set('debug', true);
+ $h = CurlHandle::factory($request);
+ $this->assertEquals($h->getStderr(true), $h->getOptions()->get(CURLOPT_STDERR));
+ $this->assertInternalType('resource', $h->getStderr(true));
+ $this->assertInternalType('string', $h->getStderr(false));
+ $r = $h->getStderr(true);
+ fwrite($r, 'test');
+ $this->assertEquals('test', $h->getStderr(false));
+ }
+
+ public function testStoresCurlErrorNumber()
+ {
+ $h = new CurlHandle(curl_init('http://test.com'), array(CURLOPT_URL => 'http://test.com'));
+ $this->assertEquals(CURLE_OK, $h->getErrorNo());
+ $h->setErrorNo(CURLE_OPERATION_TIMEOUTED);
+ $this->assertEquals(CURLE_OPERATION_TIMEOUTED, $h->getErrorNo());
+ }
+
+ public function testAccountsForMissingStdErr()
+ {
+ $handle = curl_init('http://www.test.com/');
+ $h = new CurlHandle($handle, array(
+ CURLOPT_URL => 'http://www.test.com/'
+ ));
+ $this->assertNull($h->getStderr(false));
+ }
+
+ public function testDeterminesIfResourceIsAvailable()
+ {
+ $handle = curl_init($this->getServer()->getUrl());
+ $h = new CurlHandle($handle, array());
+ $this->assertTrue($h->isAvailable());
+
+ // Mess it up by closing the handle
+ curl_close($handle);
+ $this->assertFalse($h->isAvailable());
+
+ // Mess it up by unsetting the handle
+ $handle = null;
+ $this->assertFalse($h->isAvailable());
+ }
+
+ public function testWrapsErrorsAndInfo()
+ {
+ if (!defined('CURLOPT_TIMEOUT_MS')) {
+ $this->markTestSkipped('Update curl');
+ }
+
+ $settings = array(
+ CURLOPT_PORT => 123,
+ CURLOPT_CONNECTTIMEOUT_MS => 1,
+ CURLOPT_TIMEOUT_MS => 1
+ );
+
+ $handle = curl_init($this->getServer()->getUrl());
+ curl_setopt_array($handle, $settings);
+ $h = new CurlHandle($handle, $settings);
+ @curl_exec($handle);
+
+ $errors = array(
+ "couldn't connect to host",
+ 'timeout was reached',
+ 'connection time-out',
+ 'connect() timed out!',
+ 'failed connect to 127.0.0.1:123; connection refused',
+ 'failed to connect to 127.0.0.1 port 123: connection refused'
+ );
+ $this->assertTrue(in_array(strtolower($h->getError()), $errors), $h->getError() . ' was not the error');
+
+ $this->assertTrue($h->getErrorNo() > 0);
+
+ $this->assertEquals($this->getServer()->getUrl(), $h->getInfo(CURLINFO_EFFECTIVE_URL));
+ $this->assertInternalType('array', $h->getInfo());
+
+ curl_close($handle);
+ $this->assertEquals(null, $h->getInfo('url'));
+ }
+
+ public function testGetInfoWithoutDebugMode()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get($this->getServer()->getUrl());
+ $response = $request->send();
+
+ $info = $response->getInfo();
+ $this->assertFalse(empty($info));
+ $this->assertEquals($this->getServer()->getUrl(), $info['url']);
+ }
+
+ public function testWrapsCurlOptions()
+ {
+ $handle = curl_init($this->getServer()->getUrl());
+ $h = new CurlHandle($handle, array(
+ CURLOPT_AUTOREFERER => true,
+ CURLOPT_BUFFERSIZE => 1024
+ ));
+
+ $this->assertEquals(true, $h->getOptions()->get(CURLOPT_AUTOREFERER));
+ $this->assertEquals(1024, $h->getOptions()->get(CURLOPT_BUFFERSIZE));
+ }
+
+ /**
+ * Data provider for factory tests
+ *
+ * @return array
+ */
+ public function dataProvider()
+ {
+ $testFile = __DIR__ . '/../../../../../phpunit.xml.dist';
+
+ $postBody = new QueryString(array('file' => '@' . $testFile));
+ $qs = new QueryString(array(
+ 'x' => 'y',
+ 'z' => 'a'
+ ));
+
+ $client = new Client();
+ $userAgent = $client->getDefaultUserAgent();
+ $auth = base64_encode('michael:123');
+ $testFileSize = filesize($testFile);
+
+ $tests = array(
+ // Send a regular GET
+ array('GET', 'http://www.google.com/', null, null, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_HTTPHEADER => array('Accept:', 'Host: www.google.com', 'User-Agent: ' . $userAgent),
+ )),
+ // Test that custom request methods can be used
+ array('TRACE', 'http://www.google.com/', null, null, array(
+ CURLOPT_CUSTOMREQUEST => 'TRACE'
+ )),
+ // Send a GET using a port
+ array('GET', 'http://127.0.0.1:8080', null, null, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_PORT => 8080,
+ CURLOPT_HTTPHEADER => array('Accept:', 'Host: 127.0.0.1:8080', 'User-Agent: ' . $userAgent),
+ )),
+ // Send a HEAD request
+ array('HEAD', 'http://www.google.com/', null, null, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_HTTPHEADER => array('Accept:', 'Host: www.google.com', 'User-Agent: ' . $userAgent),
+ CURLOPT_NOBODY => 1
+ )),
+ // Send a GET using basic auth
+ array('GET', 'https://michael:123@127.0.0.1/index.html?q=2', null, null, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_HTTPHEADER => array(
+ 'Accept:',
+ 'Host: 127.0.0.1',
+ 'Authorization: Basic ' . $auth,
+ 'User-Agent: ' . $userAgent
+ ),
+ CURLOPT_PORT => 443
+ )),
+ // Send a GET request with custom headers
+ array('GET', 'http://127.0.0.1:8124/', array(
+ 'x-test-data' => 'Guzzle'
+ ), null, array(
+ CURLOPT_PORT => 8124,
+ CURLOPT_HTTPHEADER => array(
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'x-test-data: Guzzle',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'x-test-data' => 'Guzzle'
+ )),
+ // Send a POST using a query string
+ array('POST', 'http://127.0.0.1:8124/post.php', null, $qs, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_POSTFIELDS => 'x=y&z=a',
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Length' => '7',
+ '!Expect' => null,
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
+ '!Transfer-Encoding' => null
+ )),
+ // Send a PUT using raw data
+ array('PUT', 'http://127.0.0.1:8124/put.php', null, EntityBody::factory(fopen($testFile, 'r+')), array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_READFUNCTION => 'callback',
+ CURLOPT_INFILESIZE => filesize($testFile),
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ '!Expect' => null,
+ 'Content-Length' => $testFileSize,
+ '!Transfer-Encoding' => null
+ )),
+ // Send a POST request using an array of fields
+ array('POST', 'http://127.0.0.1:8124/post.php', null, array(
+ 'x' => 'y',
+ 'a' => 'b'
+ ), array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_POST => 1,
+ CURLOPT_POSTFIELDS => 'x=y&a=b',
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Length' => '7',
+ '!Expect' => null,
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
+ '!Transfer-Encoding' => null
+ )),
+ // Send a POST request with raw POST data and a custom content-type
+ array('POST', 'http://127.0.0.1:8124/post.php', array(
+ 'Content-Type' => 'application/json'
+ ), '{"hi":"there"}', array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_CUSTOMREQUEST => 'POST',
+ CURLOPT_UPLOAD => true,
+ CURLOPT_INFILESIZE => 14,
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'Content-Type: application/json',
+ 'User-Agent: ' . $userAgent
+ ),
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Type' => 'application/json',
+ '!Expect' => null,
+ 'Content-Length' => '14',
+ '!Transfer-Encoding' => null
+ )),
+ // Send a POST request with raw POST data, a custom content-type, and use chunked encoding
+ array('POST', 'http://127.0.0.1:8124/post.php', array(
+ 'Content-Type' => 'application/json',
+ 'Transfer-Encoding' => 'chunked'
+ ), '{"hi":"there"}', array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_CUSTOMREQUEST => 'POST',
+ CURLOPT_UPLOAD => true,
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'Transfer-Encoding: chunked',
+ 'Content-Type: application/json',
+ 'User-Agent: ' . $userAgent
+ ),
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Type' => 'application/json',
+ '!Expect' => null,
+ 'Transfer-Encoding' => 'chunked',
+ '!Content-Length' => ''
+ )),
+ // Send a POST request with no body
+ array('POST', 'http://127.0.0.1:8124/post.php', null, '', array(
+ CURLOPT_CUSTOMREQUEST => 'POST',
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Length' => '0',
+ '!Transfer-Encoding' => null
+ )),
+ // Send a POST request with empty post fields
+ array('POST', 'http://127.0.0.1:8124/post.php', null, array(), array(
+ CURLOPT_CUSTOMREQUEST => 'POST',
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Length' => '0',
+ '!Transfer-Encoding' => null
+ )),
+ // Send a PATCH request
+ array('PATCH', 'http://127.0.0.1:8124/patch.php', null, 'body', array(
+ CURLOPT_INFILESIZE => 4,
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'User-Agent: ' . $userAgent
+ )
+ )),
+ // Send a DELETE request with a body
+ array('DELETE', 'http://127.0.0.1:8124/delete.php', null, 'body', array(
+ CURLOPT_CUSTOMREQUEST => 'DELETE',
+ CURLOPT_INFILESIZE => 4,
+ CURLOPT_HTTPHEADER => array (
+ 'Expect:',
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Length' => '4',
+ '!Expect' => null,
+ '!Transfer-Encoding' => null
+ )),
+
+ /**
+ * Send a request with empty path and a fragment - the fragment must be
+ * stripped out before sending it to curl
+ *
+ * @issue 453
+ * @link https://github.com/guzzle/guzzle/issues/453
+ */
+ array('GET', 'http://www.google.com#head', null, null, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_HTTPHEADER => array('Accept:', 'Host: www.google.com', 'User-Agent: ' . $userAgent),
+ )),
+ );
+
+ $postTest = array('POST', 'http://127.0.0.1:8124/post.php', null, $postBody, array(
+ CURLOPT_RETURNTRANSFER => 0,
+ CURLOPT_HEADER => 0,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_WRITEFUNCTION => 'callback',
+ CURLOPT_HEADERFUNCTION => 'callback',
+ CURLOPT_POST => 1,
+ CURLOPT_POSTFIELDS => array(
+ 'file' => '@' . $testFile . ';filename=phpunit.xml.dist;type=application/octet-stream'
+ ),
+ CURLOPT_HTTPHEADER => array (
+ 'Accept:',
+ 'Host: 127.0.0.1:8124',
+ 'Content-Type: multipart/form-data',
+ 'Expect: 100-Continue',
+ 'User-Agent: ' . $userAgent
+ )
+ ), array(
+ 'Host' => '*',
+ 'User-Agent' => '*',
+ 'Content-Length' => '*',
+ 'Expect' => '100-Continue',
+ 'Content-Type' => 'multipart/form-data; boundary=*',
+ '!Transfer-Encoding' => null
+ ));
+
+ if (version_compare(phpversion(), '5.5.0', '>=')) {
+ $postTest[4][CURLOPT_POSTFIELDS] = array(
+ 'file' => new \CurlFile($testFile, 'application/octet-stream', 'phpunit.xml.dist')
+ );
+ }
+
+ $tests[] = $postTest;
+
+ return $tests;
+ }
+
+ /**
+ * @dataProvider dataProvider
+ */
+ public function testFactoryCreatesCurlBasedOnRequest($method, $url, $headers, $body, $options, $expectedHeaders = null)
+ {
+ $client = new Client();
+ $request = $client->createRequest($method, $url, $headers, $body);
+ $request->getCurlOptions()->set('debug', true);
+
+ $originalRequest = clone $request;
+ $curlTest = clone $request;
+ $handle = CurlHandle::factory($curlTest);
+
+ $this->assertInstanceOf('Guzzle\\Http\\Curl\\CurlHandle', $handle);
+ $o = $handle->getOptions()->getAll();
+
+ // Headers are case-insensitive
+ if (isset($o[CURLOPT_HTTPHEADER])) {
+ $o[CURLOPT_HTTPHEADER] = array_map('strtolower', $o[CURLOPT_HTTPHEADER]);
+ }
+ if (isset($options[CURLOPT_HTTPHEADER])) {
+ $options[CURLOPT_HTTPHEADER] = array_map('strtolower', $options[CURLOPT_HTTPHEADER]);
+ }
+
+ $check = 0;
+ foreach ($options as $key => $value) {
+ $check++;
+ $this->assertArrayHasKey($key, $o, '-> Check number ' . $check);
+ if ($key != CURLOPT_HTTPHEADER && $key != CURLOPT_POSTFIELDS && (is_array($o[$key])) || $o[$key] instanceof \Closure) {
+ $this->assertEquals('callback', $value, '-> Check number ' . $check);
+ } else {
+ $this->assertTrue($value == $o[$key], '-> Check number ' . $check . ' - ' . var_export($value, true) . ' != ' . var_export($o[$key], true));
+ }
+ }
+
+ // If we are testing the actual sent headers
+ if ($expectedHeaders) {
+
+ // Send the request to the test server
+ $client = new Client($this->getServer()->getUrl());
+ $request->setClient($client);
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request->send();
+
+ // Get the request that was sent and create a request that we expected
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals($method, $requests[0]->getMethod());
+
+ $test = $this->compareHeaders($expectedHeaders, $requests[0]->getHeaders());
+ $this->assertFalse($test, $test . "\nSent: \n" . $request . "\n\n" . $requests[0]);
+
+ // Ensure only one Content-Length header is sent
+ if ($request->getHeader('Content-Length')) {
+ $this->assertEquals((string) $request->getHeader('Content-Length'), (string) $requests[0]->getHeader('Content-Length'));
+ }
+ }
+ }
+
+ public function testFactoryUsesSpecifiedProtocol()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:8124/');
+ $request->setProtocolVersion('1.1');
+ $handle = CurlHandle::factory($request);
+ $options = $handle->getOptions();
+ $this->assertEquals(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]);
+ }
+
+ public function testUploadsPutData()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/');
+ $request->getCurlOptions()->set('debug', true);
+ $request->setBody(EntityBody::factory('test'), 'text/plain', false);
+ $request->getCurlOptions()->set('progress', true);
+
+ $o = $this->getWildcardObserver($request);
+ $request->send();
+
+ // Make sure that the events were dispatched
+ $this->assertTrue($o->has('curl.callback.progress'));
+
+ // Ensure that the request was received exactly as intended
+ $r = $this->getServer()->getReceivedRequests(true);
+ $this->assertFalse($r[0]->hasHeader('Transfer-Encoding'));
+ $this->assertEquals(4, (string) $r[0]->getHeader('Content-Length'));
+ $sent = strtolower($r[0]);
+ $this->assertContains('put / http/1.1', $sent);
+ $this->assertContains('host: 127.0.0.1', $sent);
+ $this->assertContains('user-agent:', $sent);
+ $this->assertContains('content-type: text/plain', $sent);
+ }
+
+ public function testUploadsPutDataUsingChunkedEncodingWhenLengthCannotBeDetermined()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/');
+ $request->setBody(EntityBody::factory(fopen($this->getServer()->getUrl(), 'r')), 'text/plain');
+ $request->send();
+
+ $r = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('chunked', $r[1]->getHeader('Transfer-Encoding'));
+ $this->assertFalse($r[1]->hasHeader('Content-Length'));
+ }
+
+ public function testUploadsPutDataUsingChunkedEncodingWhenForced()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/', array('Transfer-Encoding' => 'chunked'), 'hi!');
+ $request->send();
+
+ $r = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('chunked', $r[0]->getHeader('Transfer-Encoding'));
+ $this->assertFalse($r[0]->hasHeader('Content-Length'));
+ $this->assertEquals('hi!', $r[0]->getBody(true));
+ }
+
+ public function testSendsPostRequestsWithFields()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+
+ $request = RequestFactory::getInstance()->create('POST', $this->getServer()->getUrl());
+ $request->getCurlOptions()->set('debug', true);
+ $request->setClient(new Client());
+ $request->addPostFields(array(
+ 'a' => 'b',
+ 'c' => 'ay! ~This is a test, isn\'t it?'
+ ));
+ $request->send();
+
+ // Make sure that the request was sent correctly
+ $r = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('a=b&c=ay%21%20~This%20is%20a%20test%2C%20isn%27t%20it%3F', (string) $r[0]->getBody());
+ $this->assertFalse($r[0]->hasHeader('Transfer-Encoding'));
+ $this->assertEquals(56, (string) $r[0]->getHeader('Content-Length'));
+ $sent = strtolower($r[0]);
+ $this->assertContains('post / http/1.1', $sent);
+ $this->assertContains('content-type: application/x-www-form-urlencoded; charset=utf-8', $sent);
+ }
+
+ public function testSendsPostRequestsWithFiles()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+
+ $request = RequestFactory::getInstance()->create('POST', $this->getServer()->getUrl());
+ $request->getCurlOptions()->set('debug', true);
+ $request->setClient(new Client());
+ $request->addPostFiles(array(
+ 'foo' => __FILE__,
+ ));
+ $request->addPostFields(array(
+ 'bar' => 'baz',
+ 'arr' => array('a' => 1, 'b' => 2),
+ ));
+ $this->updateForHandle($request);
+ $request->send();
+
+ // Ensure the CURLOPT_POSTFIELDS option was set properly
+ $options = $this->requestHandle->getOptions()->getAll();
+ if (version_compare(phpversion(), '5.5.0', '<')) {
+ $this->assertContains('@' . __FILE__ . ';filename=CurlHandleTest.php;type=text/x-', $options[CURLOPT_POSTFIELDS]['foo']);
+ } else{
+ $this->assertInstanceOf('CURLFile', $options[CURLOPT_POSTFIELDS]['foo']);
+ }
+ $this->assertEquals('baz', $options[CURLOPT_POSTFIELDS]['bar']);
+ $this->assertEquals('1', $options[CURLOPT_POSTFIELDS]['arr[a]']);
+ $this->assertEquals('2', $options[CURLOPT_POSTFIELDS]['arr[b]']);
+ // Ensure that a Content-Length header was sent by cURL
+ $this->assertTrue($request->hasHeader('Content-Length'));
+ }
+
+ public function testCurlConfigurationOptionsAreSet()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl());
+ $request->setClient(new Client('http://www.example.com'));
+ $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT, 99);
+ $request->getCurlOptions()->set('curl.fake_opt', 99);
+ $request->getCurlOptions()->set(CURLOPT_PORT, 8181);
+ $handle = CurlHandle::factory($request);
+ $this->assertEquals(99, $handle->getOptions()->get(CURLOPT_CONNECTTIMEOUT));
+ $this->assertEquals(8181, $handle->getOptions()->get(CURLOPT_PORT));
+ $this->assertNull($handle->getOptions()->get('curl.fake_opt'));
+ $this->assertNull($handle->getOptions()->get('fake_opt'));
+ }
+
+ public function testEnsuresRequestsHaveResponsesWhenUpdatingFromTransfer()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl());
+ $handle = CurlHandle::factory($request);
+ $handle->updateRequestFromTransfer($request);
+ }
+
+ public function testCanSendBodyAsString()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/', null, 'foo');
+ $request->getCurlOptions()->set('body_as_string', true);
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(false);
+ $this->assertContains('PUT /', $requests[0]);
+ $this->assertContains("\nfoo", $requests[0]);
+ $this->assertContains('content-length: 3', $requests[0]);
+ $this->assertNotContains('content-type', $requests[0]);
+ }
+
+ public function testCanSendPostBodyAsString()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->post('/', null, 'foo');
+ $request->getCurlOptions()->set('body_as_string', true);
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(false);
+ $this->assertContains('POST /', $requests[0]);
+ $this->assertContains("\nfoo", $requests[0]);
+ $this->assertContains('content-length: 3', $requests[0]);
+ $this->assertNotContains('content-type', $requests[0]);
+ }
+
+ public function testAllowsWireTransferInfoToBeEnabled()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl());
+ $request->getCurlOptions()->set('debug', true);
+ $handle = CurlHandle::factory($request);
+ $this->assertNotNull($handle->getOptions()->get(CURLOPT_STDERR));
+ $this->assertNotNull($handle->getOptions()->get(CURLOPT_VERBOSE));
+ }
+
+ public function testAddsCustomCurlOptions()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl());
+ $request->getCurlOptions()->set(CURLOPT_TIMEOUT, 200);
+ $handle = CurlHandle::factory($request);
+ $this->assertEquals(200, $handle->getOptions()->get(CURLOPT_TIMEOUT));
+ }
+
+ public function testSendsPostUploadsWithContentDispositionHeaders()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n");
+
+ $fileToUpload = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'TestData' . DIRECTORY_SEPARATOR . 'test_service.json';
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->post();
+ $request->addPostFile('foo', $fileToUpload, 'application/json');
+ $request->addPostFile('foo', __FILE__);
+
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $body = (string) $requests[0]->getBody();
+
+ $this->assertContains('Content-Disposition: form-data; name="foo[0]"; filename="', $body);
+ $this->assertContains('Content-Type: application/json', $body);
+ $this->assertContains('Content-Type: text/x-', $body);
+ $this->assertContains('Content-Disposition: form-data; name="foo[1]"; filename="', $body);
+ }
+
+ public function requestMethodProvider()
+ {
+ return array(array('POST'), array('PUT'), array('PATCH'));
+ }
+
+ /**
+ * @dataProvider requestMethodProvider
+ */
+ public function testSendsRequestsWithNoBodyUsingContentLengthZero($method)
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $client->createRequest($method)->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertFalse($requests[0]->hasHeader('Transfer-Encoding'));
+ $this->assertTrue($requests[0]->hasHeader('Content-Length'));
+ $this->assertEquals('0', (string) $requests[0]->getHeader('Content-Length'));
+ }
+
+ /**
+ * @dataProvider provideCurlConfig
+ */
+ public function testParseCurlConfigConvertsStringKeysToConstantKeys($options, $expected)
+ {
+ $actual = CurlHandle::parseCurlConfig($options);
+ $this->assertEquals($expected, $actual);
+ }
+
+ /**
+ * Data provider for curl configurations
+ *
+ * @return array
+ */
+ public function provideCurlConfig()
+ {
+ return array(
+ // Conversion of option name to constant value
+ array(
+ array(
+ 'CURLOPT_PORT' => 10,
+ 'CURLOPT_TIMEOUT' => 99
+ ),
+ array(
+ CURLOPT_PORT => 10,
+ CURLOPT_TIMEOUT => 99
+ )
+ ),
+ // Keeps non constant options
+ array(
+ array('debug' => true),
+ array('debug' => true)
+ ),
+ // Conversion of constant names to constant values
+ array(
+ array('debug' => 'CURLPROXY_HTTP'),
+ array('debug' => CURLPROXY_HTTP)
+ )
+ );
+ }
+
+ public function testSeeksToBeginningOfStreamWhenSending()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/', null, 'test');
+ $request->send();
+ $request->send();
+
+ $received = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals(2, count($received));
+ $this->assertEquals('test', (string) $received[0]->getBody());
+ $this->assertEquals('test', (string) $received[1]->getBody());
+ }
+
+ public function testAllowsCurloptEncodingToBeSet()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get('/', null);
+ $request->getCurlOptions()->set(CURLOPT_ENCODING, '');
+ $this->updateForHandle($request);
+ $request->send();
+ $options = $this->requestHandle->getOptions()->getAll();
+ $this->assertSame('', $options[CURLOPT_ENCODING]);
+ $received = $this->getServer()->getReceivedRequests(false);
+ $this->assertContainsIns('accept: */*', $received[0]);
+ $this->assertContainsIns('accept-encoding: ', $received[0]);
+ }
+
+ public function testSendsExpectHeaderWhenSizeIsGreaterThanCutoff()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/', null, 'test');
+ // Start sending the expect header to 2 bytes
+ $this->updateForHandle($request);
+ $request->setExpectHeaderCutoff(2)->send();
+ $options = $this->requestHandle->getOptions()->getAll();
+ $this->assertContains('Expect: 100-Continue', $options[CURLOPT_HTTPHEADER]);
+ $received = $this->getServer()->getReceivedRequests(false);
+ $this->assertContainsIns('expect: 100-continue', $received[0]);
+ }
+
+ public function testSetsCurloptEncodingWhenAcceptEncodingHeaderIsSet()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata");
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get('/', array(
+ 'Accept' => 'application/json',
+ 'Accept-Encoding' => 'gzip, deflate',
+ ));
+ $this->updateForHandle($request);
+ $request->send();
+ $options = $this->requestHandle->getOptions()->getAll();
+ $this->assertSame('gzip, deflate', $options[CURLOPT_ENCODING]);
+ $received = $this->getServer()->getReceivedRequests(false);
+ $this->assertContainsIns('accept: application/json', $received[0]);
+ $this->assertContainsIns('accept-encoding: gzip, deflate', $received[0]);
+ }
+
+ public function testSendsPostFieldsForNonPostRequests()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n");
+
+ $client = new Client();
+ $request = $client->put($this->getServer()->getUrl(), null, array(
+ 'foo' => 'baz',
+ 'baz' => 'bar'
+ ));
+
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('PUT', $requests[0]->getMethod());
+ $this->assertEquals(
+ 'application/x-www-form-urlencoded; charset=utf-8',
+ (string) $requests[0]->getHeader('Content-Type')
+ );
+ $this->assertEquals(15, (string) $requests[0]->getHeader('Content-Length'));
+ $this->assertEquals('foo=baz&baz=bar', (string) $requests[0]->getBody());
+ }
+
+ public function testSendsPostFilesForNonPostRequests()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n");
+
+ $client = new Client();
+ $request = $client->put($this->getServer()->getUrl(), null, array(
+ 'foo' => '@' . __FILE__
+ ));
+
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('PUT', $requests[0]->getMethod());
+ $this->assertContains('multipart/form-data', (string) $requests[0]->getHeader('Content-Type'));
+ $this->assertContains('testSendsPostFilesForNonPostRequests', (string) $requests[0]->getBody());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php
new file mode 100755
index 0000000..e04141c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiProxyTest.php
@@ -0,0 +1,110 @@
+multi = new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT);
+ }
+
+ public function tearDown()
+ {
+ unset($this->multi);
+ }
+
+ public function testConstructorSetsMaxHandles()
+ {
+ $m = new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT);
+ $this->assertEquals(self::MAX_HANDLES, $this->readAttribute($m, 'maxHandles'));
+ }
+
+ public function testConstructorSetsSelectTimeout()
+ {
+ $m = new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT);
+ $this->assertEquals(self::SELECT_TIMEOUT, $this->readAttribute($m, 'selectTimeout'));
+ }
+
+ public function testAddingRequestsAddsToQueue()
+ {
+ $r = new Request('GET', 'http://www.foo.com');
+ $this->assertSame($this->multi, $this->multi->add($r));
+ $this->assertEquals(1, count($this->multi));
+ $this->assertEquals(array($r), $this->multi->all());
+
+ $this->assertTrue($this->multi->remove($r));
+ $this->assertFalse($this->multi->remove($r));
+ $this->assertEquals(0, count($this->multi));
+ }
+
+ public function testResetClearsState()
+ {
+ $r = new Request('GET', 'http://www.foo.com');
+ $this->multi->add($r);
+ $this->multi->reset();
+ $this->assertEquals(0, count($this->multi));
+ }
+
+ public function testSendWillSendQueuedRequestsFirst()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $events = array();
+ $client->getCurlMulti()->getEventDispatcher()->addListener(
+ CurlMultiProxy::ADD_REQUEST,
+ function ($e) use (&$events) {
+ $events[] = $e;
+ }
+ );
+ $request = $client->get();
+ $request->getEventDispatcher()->addListener('request.complete', function () use ($client) {
+ $client->get('/foo')->send();
+ });
+ $request->send();
+ $received = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals(2, count($received));
+ $this->assertEquals($this->getServer()->getUrl(), $received[0]->getUrl());
+ $this->assertEquals($this->getServer()->getUrl() . 'foo', $received[1]->getUrl());
+ $this->assertEquals(2, count($events));
+ }
+
+ public function testTrimsDownMaxHandleCount()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 307 OK\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $client->setCurlMulti(new CurlMultiProxy(self::MAX_HANDLES, self::SELECT_TIMEOUT));
+ $request = $client->get();
+ $request->send();
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+ $handles = $this->readAttribute($client->getCurlMulti(), 'handles');
+ $this->assertEquals(2, count($handles));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php
new file mode 100755
index 0000000..1272281
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlMultiTest.php
@@ -0,0 +1,455 @@
+multi = new MockMulti();
+ }
+
+ public function tearDown()
+ {
+ unset($this->multi);
+ }
+
+ public function testConstructorCreateMultiHandle()
+ {
+ $this->assertInternalType('resource', $this->multi->getHandle());
+ $this->assertEquals('curl_multi', get_resource_type($this->multi->getHandle()));
+ }
+
+ public function testDestructorClosesMultiHandle()
+ {
+ $handle = $this->multi->getHandle();
+ $this->multi->__destruct();
+ $this->assertFalse(is_resource($handle));
+ }
+
+ public function testRequestsCanBeAddedAndCounted()
+ {
+ $multi = new CurlMulti();
+ $request1 = new Request('GET', 'http://www.google.com/');
+ $multi->add($request1);
+ $this->assertEquals(array($request1), $multi->all());
+ $request2 = new Request('POST', 'http://www.google.com/');
+ $multi->add($request2);
+ $this->assertEquals(array($request1, $request2), $multi->all());
+ $this->assertEquals(2, count($multi));
+ }
+
+ public function testRequestsCanBeRemoved()
+ {
+ $request1 = new Request('GET', 'http://www.google.com/');
+ $this->multi->add($request1);
+ $request2 = new Request('PUT', 'http://www.google.com/');
+ $this->multi->add($request2);
+ $this->assertEquals(array($request1, $request2), $this->multi->all());
+ $this->assertTrue($this->multi->remove($request1));
+ $this->assertFalse($this->multi->remove($request1));
+ $this->assertEquals(array($request2), $this->multi->all());
+ }
+
+ public function testsResetRemovesRequestsAndResetsState()
+ {
+ $this->multi->add(new Request('GET', 'http://www.google.com/'));
+ $this->multi->reset();
+ $this->assertEquals(array(), $this->multi->all());
+ }
+
+ public function testSendsRequestsThroughCurl()
+ {
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 204 No content\r\n" .
+ "Content-Length: 0\r\n" .
+ "Server: Jetty(6.1.3)\r\n\r\n",
+ "HTTP/1.1 200 OK\r\n" .
+ "Content-Type: text/html; charset=utf-8\r\n" .
+ "Content-Length: 4\r\n" .
+ "Server: Jetty(6.1.3)\r\n\r\n" .
+ "data"
+ ));
+
+ $request1 = new Request('GET', $this->getServer()->getUrl());
+ $request2 = new Request('GET', $this->getServer()->getUrl());
+ $this->multi->add($request1);
+ $this->multi->add($request2);
+ $this->multi->send();
+
+ $response1 = $request1->getResponse();
+ $response2 = $request2->getResponse();
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2);
+
+ $this->assertTrue($response1->getBody(true) == 'data' || $response2->getBody(true) == 'data');
+ $this->assertTrue($response1->getBody(true) == '' || $response2->getBody(true) == '');
+ $this->assertTrue($response1->getStatusCode() == '204' || $response2->getStatusCode() == '204');
+ $this->assertNotEquals((string) $response1, (string) $response2);
+ }
+
+ public function testSendsThroughCurlAndAggregatesRequestExceptions()
+ {
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\n" .
+ "Content-Type: text/html; charset=utf-8\r\n" .
+ "Content-Length: 4\r\n" .
+ "Server: Jetty(6.1.3)\r\n" .
+ "\r\n" .
+ "data",
+ "HTTP/1.1 204 No content\r\n" .
+ "Content-Length: 0\r\n" .
+ "Server: Jetty(6.1.3)\r\n" .
+ "\r\n",
+ "HTTP/1.1 404 Not Found\r\n" .
+ "Content-Length: 0\r\n" .
+ "\r\n"
+ ));
+
+ $request1 = new Request('GET', $this->getServer()->getUrl());
+ $request2 = new Request('HEAD', $this->getServer()->getUrl());
+ $request3 = new Request('GET', $this->getServer()->getUrl());
+ $this->multi->add($request1);
+ $this->multi->add($request2);
+ $this->multi->add($request3);
+
+ try {
+ $this->multi->send();
+ $this->fail('MultiTransferException not thrown when aggregating request exceptions');
+ } catch (MultiTransferException $e) {
+
+ $this->assertTrue($e->containsRequest($request1));
+ $this->assertTrue($e->containsRequest($request2));
+ $this->assertTrue($e->containsRequest($request3));
+ $this->assertInstanceOf('ArrayIterator', $e->getIterator());
+ $this->assertEquals(1, count($e));
+ $exceptions = $e->getIterator();
+
+ $response1 = $request1->getResponse();
+ $response2 = $request2->getResponse();
+ $response3 = $request3->getResponse();
+
+ $this->assertNotEquals((string) $response1, (string) $response2);
+ $this->assertNotEquals((string) $response3, (string) $response1);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response1);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response2);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response3);
+
+ $failed = $exceptions[0]->getResponse();
+ $this->assertEquals(404, $failed->getStatusCode());
+ $this->assertEquals(1, count($e));
+
+ // Test the IteratorAggregate functionality
+ foreach ($e as $except) {
+ $this->assertEquals($failed, $except->getResponse());
+ }
+
+ $this->assertEquals(1, count($e->getFailedRequests()));
+ $this->assertEquals(2, count($e->getSuccessfulRequests()));
+ $this->assertEquals(3, count($e->getAllRequests()));
+ }
+ }
+
+ public function testCurlErrorsAreCaught()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ try {
+ $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:9876/');
+ $request->setClient(new Client());
+ $request->getCurlOptions()->set(CURLOPT_FRESH_CONNECT, true);
+ $request->getCurlOptions()->set(CURLOPT_FORBID_REUSE, true);
+ $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, 5);
+ $request->send();
+ $this->fail('CurlException not thrown');
+ } catch (CurlException $e) {
+ $m = $e->getMessage();
+ $this->assertContains('[curl] ', $m);
+ $this->assertContains('[url] http://127.0.0.1:9876/', $m);
+ $this->assertInternalType('array', $e->getCurlInfo());
+ }
+ }
+
+ public function testRemovesQueuedRequests()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://127.0.0.1:9876/');
+ $r = new Response(200);
+ $request->setClient(new Client());
+ $request->setResponse($r, true);
+ $this->multi->add($request);
+ $this->multi->send();
+ $this->assertSame($r, $request->getResponse());
+ }
+
+ public function testRemovesQueuedRequestsAddedInTransit()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
+ $client = new Client($this->getServer()->getUrl());
+ $r = $client->get();
+ $r->getEventDispatcher()->addListener('request.receive.status_line', function (Event $event) use ($client) {
+ // Create a request using a queued response
+ $request = $client->get()->setResponse(new Response(200), true);
+ $request->send();
+ });
+ $r->send();
+ $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false)));
+ }
+
+ public function testCatchesExceptionsBeforeSendingSingleRequest()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $multi = new CurlMulti();
+ $client->setCurlMulti($multi);
+ $request = $client->get();
+ $request->getEventDispatcher()->addListener('request.before_send', function() {
+ throw new \RuntimeException('Testing!');
+ });
+ try {
+ $request->send();
+ $this->fail('Did not throw');
+ } catch (\RuntimeException $e) {
+ // Ensure it was removed
+ $this->assertEquals(0, count($multi));
+ }
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\ExceptionCollection
+ * @expectedExceptionMessage Thrown before sending!
+ */
+ public function testCatchesExceptionsBeforeSendingMultipleRequests()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get();
+ $request->getEventDispatcher()->addListener('request.before_send', function() {
+ throw new \RuntimeException('Thrown before sending!');
+ });
+ $client->send(array($request));
+ }
+
+ public function testCatchesExceptionsWhenRemovingQueuedRequests()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $r = $client->get();
+ $r->getEventDispatcher()->addListener('request.sent', function() use ($client) {
+ // Create a request using a queued response
+ $client->get()->setResponse(new Response(404), true)->send();
+ });
+ try {
+ $r->send();
+ $this->fail('Did not throw');
+ } catch (BadResponseException $e) {
+ $this->assertCount(0, $client->getCurlMulti());
+ }
+ }
+
+ public function testCatchesExceptionsWhenRemovingQueuedRequestsBeforeSending()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $client = new Client($this->getServer()->getUrl());
+ $r = $client->get();
+ $r->getEventDispatcher()->addListener('request.before_send', function() use ($client) {
+ // Create a request using a queued response
+ $client->get()->setResponse(new Response(404), true)->send();
+ });
+ try {
+ $r->send();
+ $this->fail('Did not throw');
+ } catch (BadResponseException $e) {
+ $this->assertCount(0, $client->getCurlMulti());
+ }
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage test
+ */
+ public function testDoesNotCatchRandomExceptionsThrownDuringPerform()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $multi = $this->getMock('Guzzle\\Http\\Curl\\CurlMulti', array('perform'));
+ $multi->expects($this->once())
+ ->method('perform')
+ ->will($this->throwException(new \RuntimeException('test')));
+ $multi->add($client->get());
+ $multi->send();
+ }
+
+ public function testDoesNotSendRequestsDecliningToBeSent()
+ {
+ if (!defined('CURLOPT_TIMEOUT_MS')) {
+ $this->markTestSkipped('Update curl');
+ }
+
+ // Create a client that is bound to fail connecting
+ $client = new Client('http://127.0.0.1:123', array(
+ 'curl.CURLOPT_PORT' => 123,
+ 'curl.CURLOPT_CONNECTTIMEOUT_MS' => 1,
+ ));
+
+ $request = $client->get();
+ $multi = new CurlMulti();
+ $multi->add($request);
+
+ // Listen for request exceptions, and when they occur, first change the
+ // state of the request back to transferring, and then just allow it to
+ // exception out
+ $request->getEventDispatcher()->addListener('request.exception', function(Event $event) use ($multi) {
+ $retries = $event['request']->getParams()->get('retries');
+ // Allow the first failure to retry
+ if ($retries == 0) {
+ $event['request']->setState('transfer');
+ $event['request']->getParams()->set('retries', 1);
+ // Remove the request to try again
+ $multi->remove($event['request']);
+ $multi->add($event['request']);
+ }
+ });
+
+ try {
+ $multi->send();
+ $this->fail('Did not throw an exception at all!?!');
+ } catch (\Exception $e) {
+ $this->assertEquals(1, $request->getParams()->get('retries'));
+ }
+ }
+
+ public function testDoesNotThrowExceptionsWhenRequestsRecoverWithRetry()
+ {
+ $this->getServer()->flush();
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get();
+ $request->getEventDispatcher()->addListener('request.before_send', function(Event $event) {
+ $event['request']->setResponse(new Response(200));
+ });
+
+ $multi = new CurlMulti();
+ $multi->add($request);
+ $multi->send();
+ $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false)));
+ }
+
+ public function testDoesNotThrowExceptionsWhenRequestsRecoverWithSuccess()
+ {
+ // Attempt a port that 99.9% is not listening
+ $client = new Client('http://127.0.0.1:123');
+ $request = $client->get();
+ // Ensure it times out quickly if needed
+ $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, 1)->set(CURLOPT_CONNECTTIMEOUT_MS, 1);
+
+ $request->getEventDispatcher()->addListener('request.exception', function(Event $event) use (&$count) {
+ $event['request']->setResponse(new Response(200));
+ });
+
+ $multi = new CurlMulti();
+ $multi->add($request);
+ $multi->send();
+
+ // Ensure that the exception was caught, and the response was set manually
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+ }
+
+ public function testHardResetReopensMultiHandle()
+ {
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+
+ $stream = fopen('php://temp', 'w+');
+ $client = new Client($this->getServer()->getUrl());
+ $client->getConfig()->set('curl.CURLOPT_VERBOSE', true)->set('curl.CURLOPT_STDERR', $stream);
+
+ $request = $client->get();
+ $multi = new CurlMulti();
+ $multi->add($request);
+ $multi->send();
+ $multi->reset(true);
+ $multi->add($request);
+ $multi->send();
+
+ rewind($stream);
+ $this->assertNotContains('Re-using existing connection', stream_get_contents($stream));
+ }
+
+ public function testThrowsMeaningfulExceptionsForCurlMultiErrors()
+ {
+ $multi = new CurlMulti();
+
+ // Set the state of the multi object to sending to trigger the exception
+ $reflector = new \ReflectionMethod('Guzzle\Http\Curl\CurlMulti', 'checkCurlResult');
+ $reflector->setAccessible(true);
+
+ // Successful
+ $reflector->invoke($multi, 0);
+
+ // Known error
+ try {
+ $reflector->invoke($multi, CURLM_BAD_HANDLE);
+ $this->fail('Expected an exception here');
+ } catch (CurlException $e) {
+ $this->assertContains('The passed-in handle is not a valid CURLM handle.', $e->getMessage());
+ $this->assertContains('CURLM_BAD_HANDLE', $e->getMessage());
+ $this->assertContains(strval(CURLM_BAD_HANDLE), $e->getMessage());
+ }
+
+ // Unknown error
+ try {
+ $reflector->invoke($multi, 255);
+ $this->fail('Expected an exception here');
+ } catch (CurlException $e) {
+ $this->assertEquals('Unexpected cURL error: 255', $e->getMessage());
+ }
+ }
+
+ public function testRequestBeforeSendIncludesContentLengthHeaderIfEmptyBody()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request = new Request('PUT', $this->getServer()->getUrl());
+ $that = $this;
+ $request->getEventDispatcher()->addListener('request.before_send', function ($event) use ($that) {
+ $that->assertEquals(0, $event['request']->getHeader('Content-Length'));
+ });
+ $this->multi->add($request);
+ $this->multi->send();
+ }
+
+ public function testRemovesConflictingTransferEncodingHeader()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put('/', null, fopen($this->getServer()->getUrl(), 'r'));
+ $request->setHeader('Content-Length', 4);
+ $request->send();
+ $received = $this->getServer()->getReceivedRequests(true);
+ $this->assertFalse($received[1]->hasHeader('Transfer-Encoding'));
+ $this->assertEquals(4, (string) $received[1]->getHeader('Content-Length'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php
new file mode 100755
index 0000000..c7b5ee6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/CurlVersionTest.php
@@ -0,0 +1,39 @@
+getProperty('version');
+ $refProperty->setAccessible(true);
+ $refProperty->setValue($instance, array());
+
+ $this->assertEquals($info, $instance->getAll());
+ $this->assertEquals($info, $instance->getAll());
+
+ $this->assertEquals($info['version'], $instance->get('version'));
+ $this->assertFalse($instance->get('foo'));
+ }
+
+ public function testIsSingleton()
+ {
+ $refObject = new \ReflectionClass('Guzzle\Http\Curl\CurlVersion');
+ $refProperty = $refObject->getProperty('instance');
+ $refProperty->setAccessible(true);
+ $refProperty->setValue(null, null);
+
+ $this->assertInstanceOf('Guzzle\Http\Curl\CurlVersion', CurlVersion::getInstance());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php
new file mode 100755
index 0000000..c69e0c9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Curl/RequestMediatorTest.php
@@ -0,0 +1,67 @@
+events[] = $event;
+ }
+
+ public function testEmitsEvents()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://www.example.com');
+ $request->setBody('foo');
+ $request->setResponse(new Response(200));
+
+ // Ensure that IO events are emitted
+ $request->getCurlOptions()->set('emit_io', true);
+
+ // Attach listeners for each event type
+ $request->getEventDispatcher()->addListener('curl.callback.progress', array($this, 'event'));
+ $request->getEventDispatcher()->addListener('curl.callback.read', array($this, 'event'));
+ $request->getEventDispatcher()->addListener('curl.callback.write', array($this, 'event'));
+
+ $mediator = new RequestMediator($request, true);
+
+ $mediator->progress('a', 'b', 'c', 'd');
+ $this->assertEquals(1, count($this->events));
+ $this->assertEquals('curl.callback.progress', $this->events[0]->getName());
+
+ $this->assertEquals(3, $mediator->writeResponseBody('foo', 'bar'));
+ $this->assertEquals(2, count($this->events));
+ $this->assertEquals('curl.callback.write', $this->events[1]->getName());
+ $this->assertEquals('bar', $this->events[1]['write']);
+ $this->assertSame($request, $this->events[1]['request']);
+
+ $this->assertEquals('foo', $mediator->readRequestBody('a', 'b', 3));
+ $this->assertEquals(3, count($this->events));
+ $this->assertEquals('curl.callback.read', $this->events[2]->getName());
+ $this->assertEquals('foo', $this->events[2]['read']);
+ $this->assertSame($request, $this->events[2]['request']);
+ }
+
+ public function testDoesNotUseRequestResponseBodyWhenNotCustom()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 307 Foo\r\nLocation: /foo\r\nContent-Length: 2\r\n\r\nHI",
+ "HTTP/1.1 301 Foo\r\nLocation: /foo\r\nContent-Length: 2\r\n\r\nFI",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest",
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $response = $client->get()->send();
+ $this->assertEquals('test', $response->getBody(true));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php
new file mode 100755
index 0000000..124a44d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/EntityBodyTest.php
@@ -0,0 +1,182 @@
+assertEquals('data', (string) $body);
+ $this->assertEquals(4, $body->getContentLength());
+ $this->assertEquals('PHP', $body->getWrapper());
+ $this->assertEquals('TEMP', $body->getStreamType());
+
+ $handle = fopen(__DIR__ . '/../../../../phpunit.xml.dist', 'r');
+ if (!$handle) {
+ $this->fail('Could not open test file');
+ }
+ $body = EntityBody::factory($handle);
+ $this->assertEquals(__DIR__ . '/../../../../phpunit.xml.dist', $body->getUri());
+ $this->assertTrue($body->isLocal());
+ $this->assertEquals(__DIR__ . '/../../../../phpunit.xml.dist', $body->getUri());
+ $this->assertEquals(filesize(__DIR__ . '/../../../../phpunit.xml.dist'), $body->getContentLength());
+
+ // make sure that a body will return as the same object
+ $this->assertTrue($body === EntityBody::factory($body));
+ }
+
+ public function testFactoryCreatesTempStreamByDefault()
+ {
+ $body = EntityBody::factory('');
+ $this->assertEquals('PHP', $body->getWrapper());
+ $this->assertEquals('TEMP', $body->getStreamType());
+ $body = EntityBody::factory();
+ $this->assertEquals('PHP', $body->getWrapper());
+ $this->assertEquals('TEMP', $body->getStreamType());
+ }
+
+ public function testFactoryCanCreateFromObject()
+ {
+ $body = EntityBody::factory(new QueryString(array('foo' => 'bar')));
+ $this->assertEquals('foo=bar', (string) $body);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testFactoryEnsuresObjectsHaveToStringMethod()
+ {
+ EntityBody::factory(new \stdClass('a'));
+ }
+
+ public function testHandlesCompression()
+ {
+ $body = EntityBody::factory('testing 123...testing 123');
+ $this->assertFalse($body->getContentEncoding(), '-> getContentEncoding() must initially return FALSE');
+ $size = $body->getContentLength();
+ $body->compress();
+ $this->assertEquals('gzip', $body->getContentEncoding(), '-> getContentEncoding() must return the correct encoding after compressing');
+ $this->assertEquals(gzdeflate('testing 123...testing 123'), (string) $body);
+ $this->assertTrue($body->getContentLength() < $size);
+ $this->assertTrue($body->uncompress());
+ $this->assertEquals('testing 123...testing 123', (string) $body);
+ $this->assertFalse($body->getContentEncoding(), '-> getContentEncoding() must reset to FALSE');
+
+ if (in_array('bzip2.*', stream_get_filters())) {
+ $this->assertTrue($body->compress('bzip2.compress'));
+ $this->assertEquals('compress', $body->getContentEncoding(), '-> compress() must set \'compress\' as the Content-Encoding');
+ }
+
+ $this->assertFalse($body->compress('non-existent'), '-> compress() must return false when a non-existent stream filter is used');
+
+ // Release the body
+ unset($body);
+
+ // Use gzip compression on the initial content. This will include a
+ // gzip header which will need to be stripped when deflating the stream
+ $body = EntityBody::factory(gzencode('test'));
+ $this->assertSame($body, $body->setStreamFilterContentEncoding('zlib.deflate'));
+ $this->assertTrue($body->uncompress('zlib.inflate'));
+ $this->assertEquals('test', (string) $body);
+ unset($body);
+
+ // Test using a very long string
+ $largeString = '';
+ for ($i = 0; $i < 25000; $i++) {
+ $largeString .= chr(rand(33, 126));
+ }
+ $body = EntityBody::factory($largeString);
+ $this->assertEquals($largeString, (string) $body);
+ $this->assertTrue($body->compress());
+ $this->assertNotEquals($largeString, (string) $body);
+ $compressed = (string) $body;
+ $this->assertTrue($body->uncompress());
+ $this->assertEquals($largeString, (string) $body);
+ $this->assertEquals($compressed, gzdeflate($largeString));
+
+ $body = EntityBody::factory(fopen(__DIR__ . '/../TestData/compress_test', 'w'));
+ $this->assertFalse($body->compress());
+ unset($body);
+
+ unlink(__DIR__ . '/../TestData/compress_test');
+ }
+
+ public function testDeterminesContentType()
+ {
+ // Test using a string/temp stream
+ $body = EntityBody::factory('testing 123...testing 123');
+ $this->assertNull($body->getContentType());
+
+ // Use a local file
+ $body = EntityBody::factory(fopen(__FILE__, 'r'));
+ $this->assertContains('text/x-', $body->getContentType());
+ }
+
+ public function testCreatesMd5Checksum()
+ {
+ $body = EntityBody::factory('testing 123...testing 123');
+ $this->assertEquals(md5('testing 123...testing 123'), $body->getContentMd5());
+
+ $server = $this->getServer()->enqueue(
+ "HTTP/1.1 200 OK" . "\r\n" .
+ "Content-Length: 3" . "\r\n\r\n" .
+ "abc"
+ );
+
+ $body = EntityBody::factory(fopen($this->getServer()->getUrl(), 'r'));
+ $this->assertFalse($body->getContentMd5());
+ }
+
+ public function testSeeksToOriginalPosAfterMd5()
+ {
+ $body = EntityBody::factory('testing 123');
+ $body->seek(4);
+ $this->assertEquals(md5('testing 123'), $body->getContentMd5());
+ $this->assertEquals(4, $body->ftell());
+ $this->assertEquals('ing 123', $body->read(1000));
+ }
+
+ public function testGetTypeFormBodyFactoring()
+ {
+ $body = EntityBody::factory(array('key1' => 'val1', 'key2' => 'val2'));
+ $this->assertEquals('key1=val1&key2=val2', (string) $body);
+ }
+
+ public function testAllowsCustomRewind()
+ {
+ $body = EntityBody::factory('foo');
+ $rewound = false;
+ $body->setRewindFunction(function ($body) use (&$rewound) {
+ $rewound = true;
+ return $body->seek(0);
+ });
+ $body->seek(2);
+ $this->assertTrue($body->rewind());
+ $this->assertTrue($rewound);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testCustomRewindFunctionMustBeCallable()
+ {
+ $body = EntityBody::factory();
+ $body->setRewindFunction('foo');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php
new file mode 100755
index 0000000..df3e4b7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/CurlExceptionTest.php
@@ -0,0 +1,27 @@
+assertNull($e->getError());
+ $this->assertNull($e->getErrorNo());
+ $this->assertSame($e, $e->setError('test', 12));
+ $this->assertEquals('test', $e->getError());
+ $this->assertEquals(12, $e->getErrorNo());
+
+ $handle = new CurlHandle(curl_init(), array());
+ $e->setCurlHandle($handle);
+ $this->assertSame($handle, $e->getCurlHandle());
+ $handle->close();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php
new file mode 100755
index 0000000..12cfd36
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/ExceptionTest.php
@@ -0,0 +1,66 @@
+setRequest($request);
+ $this->assertEquals($request, $e->getRequest());
+ }
+
+ /**
+ * @covers Guzzle\Http\Exception\BadResponseException
+ */
+ public function testBadResponseException()
+ {
+ $e = new BadResponseException('Message');
+ $response = new Response(200);
+ $e->setResponse($response);
+ $this->assertEquals($response, $e->getResponse());
+ }
+
+ /**
+ * @covers Guzzle\Http\Exception\BadResponseException::factory
+ */
+ public function testCreatesGenericErrorExceptionOnError()
+ {
+ $request = new Request('GET', 'http://www.example.com');
+ $response = new Response(307);
+ $e = BadResponseException::factory($request, $response);
+ $this->assertInstanceOf('Guzzle\Http\Exception\BadResponseException', $e);
+ }
+
+ /**
+ * @covers Guzzle\Http\Exception\BadResponseException::factory
+ */
+ public function testCreatesClientErrorExceptionOnClientError()
+ {
+ $request = new Request('GET', 'http://www.example.com');
+ $response = new Response(404);
+ $e = BadResponseException::factory($request, $response);
+ $this->assertInstanceOf('Guzzle\Http\Exception\ClientErrorResponseException', $e);
+ }
+
+ /**
+ * @covers Guzzle\Http\Exception\BadResponseException::factory
+ */
+ public function testCreatesServerErrorExceptionOnServerError()
+ {
+ $request = new Request('GET', 'http://www.example.com');
+ $response = new Response(503);
+ $e = BadResponseException::factory($request, $response);
+ $this->assertInstanceOf('Guzzle\Http\Exception\ServerErrorResponseException', $e);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php
new file mode 100755
index 0000000..fa4ec26
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Exception/MultiTransferExceptionTest.php
@@ -0,0 +1,51 @@
+addSuccessfulRequest($r1);
+ $e->addFailedRequest($r2);
+ $this->assertEquals(array($r1), $e->getSuccessfulRequests());
+ $this->assertEquals(array($r2), $e->getSuccessfulRequests());
+ $this->assertEquals(array($r1, $r2), $e->getAllRequests());
+ $this->assertTrue($e->containsRequest($r1));
+ $this->assertTrue($e->containsRequest($r2));
+ $this->assertFalse($e->containsRequest(new Request('POST', '/foo')));
+ }
+
+ public function testCanSetRequests()
+ {
+ $s = array($r1 = new Request('GET', 'http://www.foo.com'));
+ $f = array($r2 = new Request('GET', 'http://www.foo.com'));
+ $e = new MultiTransferException();
+ $e->setSuccessfulRequests($s);
+ $e->setFailedRequests($f);
+ $this->assertEquals(array($r1), $e->getSuccessfulRequests());
+ $this->assertEquals(array($r2), $e->getSuccessfulRequests());
+ }
+
+ public function testAssociatesExceptionsWithRequests()
+ {
+ $r1 = new Request('GET', 'http://www.foo.com');
+ $re1 = new \Exception('foo');
+ $re2 = new \Exception('bar');
+ $e = new MultiTransferException();
+ $e->add($re2);
+ $e->addFailedRequestWithException($r1, $re1);
+ $this->assertSame($re1, $e->getExceptionForFailedRequest($r1));
+ $this->assertNull($e->getExceptionForFailedRequest(new Request('POST', '/foo')));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php
new file mode 100755
index 0000000..cd6355f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/IoEmittingEntityBodyTest.php
@@ -0,0 +1,47 @@
+decorated = EntityBody::factory('hello');
+ $this->body = new IoEmittingEntityBody($this->decorated);
+ }
+
+ public function testEmitsReadEvents()
+ {
+ $e = null;
+ $this->body->getEventDispatcher()->addListener('body.read', function ($event) use (&$e) {
+ $e = $event;
+ });
+ $this->assertEquals('hel', $this->body->read(3));
+ $this->assertEquals('hel', $e['read']);
+ $this->assertEquals(3, $e['length']);
+ $this->assertSame($this->body, $e['body']);
+ }
+
+ public function testEmitsWriteEvents()
+ {
+ $e = null;
+ $this->body->getEventDispatcher()->addListener('body.write', function ($event) use (&$e) {
+ $e = $event;
+ });
+ $this->body->seek(0, SEEK_END);
+ $this->assertEquals(5, $this->body->write('there'));
+ $this->assertEquals('there', $e['write']);
+ $this->assertEquals(5, $e['result']);
+ $this->assertSame($this->body, $e['body']);
+ $this->assertEquals('hellothere', (string) $this->body);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php
new file mode 100755
index 0000000..9447d8c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/AbstractMessageTest.php
@@ -0,0 +1,136 @@
+mock = $this->getMockForAbstractClass('Guzzle\Http\Message\AbstractMessage');
+ }
+
+ public function tearDown()
+ {
+ $this->mock = $this->request = null;
+ }
+
+ public function testGetParams()
+ {
+ $request = new Request('GET', 'http://example.com');
+ $this->assertInstanceOf('Guzzle\\Common\\Collection', $request->getParams());
+ }
+
+ public function testAddHeaders()
+ {
+ $this->mock->setHeader('A', 'B');
+
+ $this->assertEquals($this->mock, $this->mock->addHeaders(array(
+ 'X-Data' => '123'
+ )));
+
+ $this->assertTrue($this->mock->hasHeader('X-Data') !== false);
+ $this->assertTrue($this->mock->hasHeader('A') !== false);
+ }
+
+ public function testAllowsHeaderToSetAsHeader()
+ {
+ $h = new Header('A', 'B');
+ $this->mock->setHeader('A', $h);
+ $this->assertSame($h, $this->mock->getHeader('A'));
+ }
+
+ public function testGetHeader()
+ {
+ $this->mock->setHeader('Test', '123');
+ $this->assertEquals('123', $this->mock->getHeader('Test'));
+ }
+
+ public function testGetHeaders()
+ {
+ $this->assertSame($this->mock, $this->mock->setHeaders(array('a' => 'b', 'c' => 'd')));
+ $h = $this->mock->getHeaders();
+ $this->assertArrayHasKey('a', $h->toArray());
+ $this->assertArrayHasKey('c', $h->toArray());
+ $this->assertInstanceOf('Guzzle\Http\Message\Header\HeaderInterface', $h->get('a'));
+ $this->assertInstanceOf('Guzzle\Http\Message\Header\HeaderInterface', $h->get('c'));
+ }
+
+ public function testGetHeaderLinesUsesGlue()
+ {
+ $this->mock->setHeaders(array('a' => 'b', 'c' => 'd'));
+ $this->mock->addHeader('a', 'e');
+ $this->mock->getHeader('a')->setGlue('!');
+ $this->assertEquals(array(
+ 'a: b! e',
+ 'c: d'
+ ), $this->mock->getHeaderLines());
+ }
+
+ public function testHasHeader()
+ {
+ $this->assertFalse($this->mock->hasHeader('Foo'));
+ $this->mock->setHeader('Foo', 'Bar');
+ $this->assertEquals(true, $this->mock->hasHeader('Foo'));
+ $this->mock->setHeader('foo', 'yoo');
+ $this->assertEquals(true, $this->mock->hasHeader('Foo'));
+ $this->assertEquals(true, $this->mock->hasHeader('foo'));
+ $this->assertEquals(false, $this->mock->hasHeader('bar'));
+ }
+
+ public function testRemoveHeader()
+ {
+ $this->mock->setHeader('Foo', 'Bar');
+ $this->assertEquals(true, $this->mock->hasHeader('Foo'));
+ $this->mock->removeHeader('Foo');
+ $this->assertFalse($this->mock->hasHeader('Foo'));
+ }
+
+ public function testReturnsNullWhenHeaderIsNotFound()
+ {
+ $this->assertNull($this->mock->getHeader('foo'));
+ }
+
+ public function testAddingHeadersPreservesOriginalHeaderCase()
+ {
+ $this->mock->addHeaders(array(
+ 'test' => '123',
+ 'Test' => 'abc'
+ ));
+ $this->mock->addHeader('test', '456');
+ $this->mock->addHeader('test', '789');
+
+ $header = $this->mock->getHeader('test');
+ $this->assertContains('123', $header->toArray());
+ $this->assertContains('456', $header->toArray());
+ $this->assertContains('789', $header->toArray());
+ $this->assertContains('abc', $header->toArray());
+ }
+
+ public function testCanStoreEmptyHeaders()
+ {
+ $this->mock->setHeader('Content-Length', 0);
+ $this->assertTrue($this->mock->hasHeader('Content-Length'));
+ $this->assertEquals(0, (string) $this->mock->getHeader('Content-Length'));
+ }
+
+ public function testCanSetCustomHeaderFactory()
+ {
+ $f = new Header\HeaderFactory();
+ $this->mock->setHeaderFactory($f);
+ $this->assertSame($f, $this->readAttribute($this->mock, 'headerFactory'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php
new file mode 100755
index 0000000..191b022
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/EntityEnclosingRequestTest.php
@@ -0,0 +1,434 @@
+client = new Client();
+ }
+
+ public function tearDown()
+ {
+ $this->client = null;
+ }
+
+ public function testConstructorConfiguresRequest()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com', array(
+ 'X-Test' => '123'
+ ));
+ $request->setBody('Test');
+ $this->assertEquals('123', $request->getHeader('X-Test'));
+ $this->assertNull($request->getHeader('Expect'));
+ }
+
+ public function testCanSetBodyWithoutOverridingContentType()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com', array('Content-Type' => 'foooooo'));
+ $request->setBody('{"a":"b"}');
+ $this->assertEquals('foooooo', $request->getHeader('Content-Type'));
+ }
+
+ public function testRequestIncludesBodyInMessage()
+ {
+
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.guzzle-project.com/', null, 'data');
+ $this->assertEquals("PUT / HTTP/1.1\r\n"
+ . "Host: www.guzzle-project.com\r\n"
+ . "Content-Length: 4\r\n\r\n"
+ . "data", (string) $request);
+ }
+
+ public function testRequestIncludesPostBodyInMessageOnlyWhenNoPostFiles()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/', null, array(
+ 'foo' => 'bar'
+ ));
+ $this->assertEquals("POST / HTTP/1.1\r\n"
+ . "Host: www.guzzle-project.com\r\n"
+ . "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n\r\n"
+ . "foo=bar", (string) $request);
+
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/', null, array(
+ 'foo' => '@' . __FILE__
+ ));
+ $this->assertEquals("POST / HTTP/1.1\r\n"
+ . "Host: www.guzzle-project.com\r\n"
+ . "Content-Type: multipart/form-data\r\n"
+ . "Expect: 100-Continue\r\n\r\n", (string) $request);
+ }
+
+ public function testAddsPostFieldsAndSetsContentLength()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/', null, array(
+ 'data' => '123'
+ ));
+ $this->assertEquals("POST / HTTP/1.1\r\n"
+ . "Host: www.guzzle-project.com\r\n"
+ . "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n\r\n"
+ . "data=123", (string) $request);
+ }
+
+ public function testAddsPostFilesAndSetsContentType()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.test.com/')
+ ->addPostFiles(array(
+ 'file' => __FILE__
+ ))->addPostFields(array(
+ 'a' => 'b'
+ ));
+ $message = (string) $request;
+ $this->assertEquals('multipart/form-data', $request->getHeader('Content-Type'));
+ $this->assertEquals('100-Continue', $request->getHeader('Expect'));
+ }
+
+ public function testRequestBodyContainsPostFiles()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.test.com/');
+ $request->addPostFields(array(
+ 'test' => '123'
+ ));
+ $this->assertContains("\r\n\r\ntest=123", (string) $request);
+ }
+
+ public function testRequestBodyAddsContentLength()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.test.com/');
+ $request->setBody(EntityBody::factory('test'));
+ $this->assertEquals(4, (string) $request->getHeader('Content-Length'));
+ $this->assertFalse($request->hasHeader('Transfer-Encoding'));
+ }
+
+ public function testRequestBodyDoesNotUseContentLengthWhenChunked()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.test.com/', array(
+ 'Transfer-Encoding' => 'chunked'
+ ), 'test');
+ $this->assertNull($request->getHeader('Content-Length'));
+ $this->assertTrue($request->hasHeader('Transfer-Encoding'));
+ }
+
+ public function testRequestHasMutableBody()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.guzzle-project.com/', null, 'data');
+ $body = $request->getBody();
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $body);
+ $this->assertSame($body, $request->getBody());
+
+ $newBody = EntityBody::factory('foobar');
+ $request->setBody($newBody);
+ $this->assertEquals('foobar', (string) $request->getBody());
+ $this->assertSame($newBody, $request->getBody());
+ }
+
+ public function testSetPostFields()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/');
+ $this->assertInstanceOf('Guzzle\\Http\\QueryString', $request->getPostFields());
+
+ $fields = new QueryString(array(
+ 'a' => 'b'
+ ));
+ $request->addPostFields($fields);
+ $this->assertEquals($fields->getAll(), $request->getPostFields()->getAll());
+ $this->assertEquals(array(), $request->getPostFiles());
+ }
+
+ public function testSetPostFiles()
+ {
+ $request = RequestFactory::getInstance()->create('POST', $this->getServer()->getUrl())
+ ->setClient(new Client())
+ ->addPostFiles(array(__FILE__))
+ ->addPostFields(array(
+ 'test' => 'abc'
+ ));
+
+ $request->getCurlOptions()->set('debug', true);
+
+ $this->assertEquals(array(
+ 'test' => 'abc'
+ ), $request->getPostFields()->getAll());
+
+ $files = $request->getPostFiles();
+ $post = $files['file'][0];
+ $this->assertEquals('file', $post->getFieldName());
+ $this->assertContains('text/x-', $post->getContentType());
+ $this->assertEquals(__FILE__, $post->getFilename());
+
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request->send();
+
+ $this->assertNotNull($request->getHeader('Content-Length'));
+ $this->assertContains('multipart/form-data; boundary=', (string) $request->getHeader('Content-Type'), '-> cURL must add the boundary');
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testSetPostFilesThrowsExceptionWhenFileIsNotFound()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/')
+ ->addPostFiles(array(
+ 'file' => 'filenotfound.ini'
+ ));
+ }
+
+ /**
+ * @expectedException Guzzle\Http\Exception\RequestException
+ */
+ public function testThrowsExceptionWhenNonStringsAreAddedToPost()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/')
+ ->addPostFile('foo', new \stdClass());
+ }
+
+ public function testAllowsContentTypeInPostUploads()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/')
+ ->addPostFile('foo', __FILE__, 'text/plain');
+
+ $this->assertEquals(array(
+ new PostFile('foo', __FILE__, 'text/plain')
+ ), $request->getPostFile('foo'));
+ }
+
+ public function testGuessesContentTypeOfPostUpload()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/')
+ ->addPostFile('foo', __FILE__);
+ $file = $request->getPostFile('foo');
+ $this->assertContains('text/x-', $file[0]->getContentType());
+ }
+
+ public function testAllowsContentDispositionFieldsInPostUploadsWhenSettingInBulk()
+ {
+ $postFile = new PostFile('foo', __FILE__, 'text/x-php');
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/')
+ ->addPostFiles(array('foo' => $postFile));
+
+ $this->assertEquals(array($postFile), $request->getPostFile('foo'));
+ }
+
+ public function testPostRequestsUseApplicationXwwwForUrlEncodedForArrays()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/');
+ $request->setPostField('a', 'b');
+ $this->assertContains("\r\n\r\na=b", (string) $request);
+ $this->assertEquals('application/x-www-form-urlencoded; charset=utf-8', $request->getHeader('Content-Type'));
+ }
+
+ public function testProcessMethodAddsContentType()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/');
+ $request->setPostField('a', 'b');
+ $this->assertEquals('application/x-www-form-urlencoded; charset=utf-8', $request->getHeader('Content-Type'));
+ }
+
+ public function testPostRequestsUseMultipartFormDataWithFiles()
+ {
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.guzzle-project.com/');
+ $request->addPostFiles(array('file' => __FILE__));
+ $this->assertEquals('multipart/form-data', $request->getHeader('Content-Type'));
+ }
+
+ public function testCanSendMultipleRequestsUsingASingleRequestObject()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 201 Created\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ // Send the first request
+ $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl())
+ ->setBody('test')
+ ->setClient(new Client());
+ $request->send();
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+
+ // Send the second request
+ $request->setBody('abcdefg', 'application/json', false);
+ $request->send();
+ $this->assertEquals(201, $request->getResponse()->getStatusCode());
+
+ // Ensure that the same request was sent twice with different bodies
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals(2, count($requests));
+ $this->assertEquals(4, (string) $requests[0]->getHeader('Content-Length'));
+ $this->assertEquals(7, (string) $requests[1]->getHeader('Content-Length'));
+ }
+
+ public function testRemovingPostFieldRebuildsPostFields()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com');
+ $request->setPostField('test', 'value');
+ $request->removePostField('test');
+ $this->assertNull($request->getPostField('test'));
+ }
+
+ public function testUsesChunkedTransferWhenBodyLengthCannotBeDetermined()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/');
+ $request->setBody(fopen($this->getServer()->getUrl(), 'r'));
+ $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding'));
+ $this->assertFalse($request->hasHeader('Content-Length'));
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\RequestException
+ */
+ public function testThrowsExceptionWhenContentLengthCannotBeDeterminedAndUsingHttp1()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/');
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request->setProtocolVersion('1.0');
+ $request->setBody(fopen($this->getServer()->getUrl(), 'r'));
+ }
+
+ public function testAllowsNestedPostData()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->addPostFields(array(
+ 'a' => array('b', 'c')
+ ));
+ $this->assertEquals(array(
+ 'a' => array('b', 'c')
+ ), $request->getPostFields()->getAll());
+ }
+
+ public function testAllowsEmptyFields()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->addPostFields(array(
+ 'a' => ''
+ ));
+ $this->assertEquals(array(
+ 'a' => ''
+ ), $request->getPostFields()->getAll());
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\RequestException
+ */
+ public function testFailsOnInvalidFiles()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->addPostFiles(array(
+ 'a' => new \stdClass()
+ ));
+ }
+
+ public function testHandlesEmptyStrings()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->addPostFields(array(
+ 'a' => '',
+ 'b' => null,
+ 'c' => 'Foo'
+ ));
+ $this->assertEquals(array(
+ 'a' => '',
+ 'b' => null,
+ 'c' => 'Foo'
+ ), $request->getPostFields()->getAll());
+ }
+
+ public function testHoldsPostFiles()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->addPostFile('foo', __FILE__);
+ $request->addPostFile(new PostFile('foo', __FILE__));
+
+ $this->assertArrayHasKey('foo', $request->getPostFiles());
+ $foo = $request->getPostFile('foo');
+ $this->assertEquals(2, count($foo));
+ $this->assertEquals(__FILE__, $foo[0]->getFilename());
+ $this->assertEquals(__FILE__, $foo[1]->getFilename());
+
+ $request->removePostFile('foo');
+ $this->assertEquals(array(), $request->getPostFiles());
+ }
+
+ public function testAllowsAtPrefixWhenAddingPostFiles()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->addPostFiles(array(
+ 'foo' => '@' . __FILE__
+ ));
+ $foo = $request->getPostFile('foo');
+ $this->assertEquals(__FILE__, $foo[0]->getFilename());
+ }
+
+ public function testSetStateToTransferWithEmptyBodySetsContentLengthToZero()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://test.com/');
+ $request->setState($request::STATE_TRANSFER);
+ $this->assertEquals('0', (string) $request->getHeader('Content-Length'));
+ }
+
+ public function testSettingExpectHeaderCutoffChangesRequest()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/');
+ $request->setHeader('Expect', '100-Continue');
+ $request->setExpectHeaderCutoff(false);
+ $this->assertNull($request->getHeader('Expect'));
+ // There is not body, so remove the expect header
+ $request->setHeader('Expect', '100-Continue');
+ $request->setExpectHeaderCutoff(10);
+ $this->assertNull($request->getHeader('Expect'));
+ // The size is less than the cutoff
+ $request->setBody('foo');
+ $this->assertNull($request->getHeader('Expect'));
+ // The size is greater than the cutoff
+ $request->setBody('foobazbarbamboo');
+ $this->assertNotNull($request->getHeader('Expect'));
+ }
+
+ public function testStrictRedirectsCanBeSpecifiedOnEntityEnclosingRequests()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/');
+ $request->configureRedirects(true);
+ $this->assertTrue($request->getParams()->get(RedirectPlugin::STRICT_REDIRECTS));
+ }
+
+ public function testCanDisableRedirects()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/');
+ $request->configureRedirects(false, false);
+ $this->assertTrue($request->getParams()->get(RedirectPlugin::DISABLE));
+ }
+
+ public function testSetsContentTypeWhenSettingBodyByGuessingFromEntityBody()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/foo');
+ $request->setBody(EntityBody::factory(fopen(__FILE__, 'r')));
+ $this->assertEquals('text/x-php', (string) $request->getHeader('Content-Type'));
+ }
+
+ public function testDoesNotCloneBody()
+ {
+ $request = new EntityEnclosingRequest('PUT', 'http://test.com/foo');
+ $request->setBody('test');
+ $newRequest = clone $request;
+ $newRequest->setBody('foo');
+ $this->assertInternalType('string', (string) $request->getBody());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php
new file mode 100755
index 0000000..62ca555
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/HeaderFactoryTest.php
@@ -0,0 +1,29 @@
+createHeader('Foo', 'Bar');
+ $this->assertInstanceOf('Guzzle\Http\Message\Header', $h);
+ $this->assertEquals('Foo', $h->getName());
+ $this->assertEquals('Bar', (string) $h);
+ }
+
+ public function testCreatesSpecificHeaders()
+ {
+ $f = new HeaderFactory();
+ $h = $f->createHeader('Link', '; rel="test"');
+ $this->assertInstanceOf('Guzzle\Http\Message\Header\Link', $h);
+ $this->assertEquals('Link', $h->getName());
+ $this->assertEquals('; rel="test"', (string) $h);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php
new file mode 100755
index 0000000..c834d10
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/Header/LinkTest.php
@@ -0,0 +1,63 @@
+; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg", ; rel=side; type="image/jpeg"');
+ $links = $link->getLinks();
+ $this->assertEquals(array(
+ array(
+ 'rel' => 'front',
+ 'type' => 'image/jpeg',
+ 'url' => 'http:/.../front.jpeg',
+ ),
+ array(
+ 'rel' => 'back',
+ 'type' => 'image/jpeg',
+ 'url' => 'http://.../back.jpeg',
+ ),
+ array(
+ 'rel' => 'side',
+ 'type' => 'image/jpeg',
+ 'url' => 'http://.../side.jpeg?test=1'
+ )
+ ), $links);
+
+ $this->assertEquals(array(
+ 'rel' => 'back',
+ 'type' => 'image/jpeg',
+ 'url' => 'http://.../back.jpeg',
+ ), $link->getLink('back'));
+
+ $this->assertTrue($link->hasLink('front'));
+ $this->assertFalse($link->hasLink('foo'));
+ }
+
+ public function testCanAddLink()
+ {
+ $link = new Link('Link', '; rel=a; type="image/jpeg"');
+ $link->addLink('http://test.com', 'test', array('foo' => 'bar'));
+ $this->assertEquals(
+ '; rel=a; type="image/jpeg", ; rel="test"; foo="bar"',
+ (string) $link
+ );
+ }
+
+ public function testCanParseLinksWithCommas()
+ {
+ $link = new Link('Link', '; rel="previous"; title="start, index"');
+ $this->assertEquals(array(
+ array(
+ 'rel' => 'previous',
+ 'title' => 'start, index',
+ 'url' => 'http://example.com/TheBook/chapter1',
+ )
+ ), $link->getLinks());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php
new file mode 100755
index 0000000..a3f511b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparison.php
@@ -0,0 +1,135 @@
+toArray();
+ }
+
+ foreach ($filteredHeaders as $k => $v) {
+ if ($k[0] == '_') {
+ // This header should be ignored
+ $ignore[] = str_replace('_', '', $k);
+ } elseif ($k[0] == '!') {
+ // This header must not be present
+ $absent[] = str_replace('!', '', $k);
+ } else {
+ $expected[$k] = $v;
+ }
+ }
+
+ return $this->compareArray($expected, $actualHeaders, $ignore, $absent);
+ }
+
+ /**
+ * Check if an array of HTTP headers matches another array of HTTP headers while taking * into account as a wildcard
+ *
+ * @param array $expected Expected HTTP headers (allows wildcard values)
+ * @param array|Collection $actual Actual HTTP header array
+ * @param array $ignore Headers to ignore from the comparison
+ * @param array $absent Array of headers that must not be present
+ *
+ * @return array|bool Returns an array of the differences or FALSE if none
+ */
+ public function compareArray(array $expected, $actual, array $ignore = array(), array $absent = array())
+ {
+ $differences = array();
+
+ // Add information about headers that were present but weren't supposed to be
+ foreach ($absent as $header) {
+ if ($this->hasKey($header, $actual)) {
+ $differences["++ {$header}"] = $actual[$header];
+ unset($actual[$header]);
+ }
+ }
+
+ // Check if expected headers are missing
+ foreach ($expected as $header => $value) {
+ if (!$this->hasKey($header, $actual)) {
+ $differences["- {$header}"] = $value;
+ }
+ }
+
+ // Flip the ignore array so it works with the case insensitive helper
+ $ignore = array_flip($ignore);
+ // Allow case-insensitive comparisons in wildcards
+ $expected = array_change_key_case($expected);
+
+ // Compare the expected and actual HTTP headers in no particular order
+ foreach ($actual as $key => $value) {
+
+ // If this is to be ignored, the skip it
+ if ($this->hasKey($key, $ignore)) {
+ continue;
+ }
+
+ // If the header was not expected
+ if (!$this->hasKey($key, $expected)) {
+ $differences["+ {$key}"] = $value;
+ continue;
+ }
+
+ // Check values and take wildcards into account
+ $lkey = strtolower($key);
+ $pos = is_string($expected[$lkey]) ? strpos($expected[$lkey], '*') : false;
+
+ foreach ((array) $actual[$key] as $v) {
+ if (($pos === false && $v != $expected[$lkey]) || $pos > 0 && substr($v, 0, $pos) != substr($expected[$lkey], 0, $pos)) {
+ $differences[$key] = "{$value} != {$expected[$lkey]}";
+ }
+ }
+ }
+
+ return empty($differences) ? false : $differences;
+ }
+
+ /**
+ * Case insensitive check if an array have a key
+ *
+ * @param string $key Key to check
+ * @param array $array Array to check
+ *
+ * @return bool
+ */
+ protected function hasKey($key, $array)
+ {
+ if ($array instanceof Collection) {
+ $keys = $array->getKeys();
+ } else {
+ $keys = array_keys($array);
+ }
+
+ foreach ($keys as $k) {
+ if (!strcasecmp($k, $key)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php
new file mode 100755
index 0000000..86c4fe8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderComparisonTest.php
@@ -0,0 +1,115 @@
+ 'Foo'
+ ), array(
+ 'Content-Length' => 'Foo'
+ ), false),
+
+ // Missing header
+ array(array(
+ 'X-Foo' => 'Bar'
+ ), array(), array(
+ '- X-Foo' => 'Bar'
+ )),
+
+ // Extra headers is present
+ array(array(
+ 'X-Foo' => 'Bar'
+ ), array(
+ 'X-Foo' => 'Bar',
+ 'X-Baz' => 'Jar'
+ ), array(
+ '+ X-Baz' => 'Jar'
+ )),
+
+ // Header is present but must be absent
+ array(array(
+ '!X-Foo' => '*'
+ ), array(
+ 'X-Foo' => 'Bar'
+ ), array(
+ '++ X-Foo' => 'Bar'
+ )),
+
+ // Different values
+ array(array(
+ 'X-Foo' => 'Bar'
+ ), array(
+ 'X-Foo' => 'Baz'
+ ), array(
+ 'X-Foo' => 'Baz != Bar'
+ )),
+
+ // Wildcard search passes
+ array(array(
+ 'X-Foo' => '*'
+ ), array(
+ 'X-Foo' => 'Bar'
+ ), false),
+
+ // Wildcard search fails
+ array(array(
+ 'X-Foo' => '*'
+ ), array(), array(
+ '- X-Foo' => '*'
+ )),
+
+ // Ignore extra header if present
+ array(array(
+ 'X-Foo' => '*',
+ '_X-Bar' => '*',
+ ), array(
+ 'X-Foo' => 'Baz',
+ 'X-Bar' => 'Jar'
+ ), false),
+
+ // Ignore extra header if present and is not
+ array(array(
+ 'X-Foo' => '*',
+ '_X-Bar' => '*',
+ ), array(
+ 'X-Foo' => 'Baz'
+ ), false),
+
+ // Case insensitive
+ array(array(
+ 'X-Foo' => '*',
+ '_X-Bar' => '*',
+ ), array(
+ 'x-foo' => 'Baz',
+ 'x-BAR' => 'baz'
+ ), false),
+
+ // Case insensitive with collection
+ array(array(
+ 'X-Foo' => '*',
+ '_X-Bar' => '*',
+ ), new Collection(array(
+ 'x-foo' => 'Baz',
+ 'x-BAR' => 'baz'
+ )), false),
+ );
+ }
+
+ /**
+ * @dataProvider filterProvider
+ */
+ public function testComparesHeaders($filters, $headers, $result)
+ {
+ $compare = new HeaderComparison();
+ $this->assertEquals($result, $compare->compare($filters, $headers));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php
new file mode 100755
index 0000000..c750234
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/HeaderTest.php
@@ -0,0 +1,162 @@
+ array('foo', 'Foo'),
+ 'Zoo' => 'bar',
+ );
+
+ public function testStoresHeaderName()
+ {
+ $i = new Header('Zoo', $this->test);
+ $this->assertEquals('Zoo', $i->getName());
+ }
+
+ public function testConvertsToString()
+ {
+ $i = new Header('Zoo', $this->test);
+ $this->assertEquals('foo, Foo, bar', (string) $i);
+ $i->setGlue(';');
+ $this->assertEquals('foo; Foo; bar', (string) $i);
+ }
+
+ public function testNormalizesGluedHeaders()
+ {
+ $h = new Header('Zoo', array('foo, Faz', 'bar'));
+ $result = $h->normalize(true)->toArray();
+ natsort($result);
+ $this->assertEquals(array('bar', 'foo', 'Faz'), $result);
+ }
+
+ public function testCanSearchForValues()
+ {
+ $h = new Header('Zoo', $this->test);
+ $this->assertTrue($h->hasValue('foo'));
+ $this->assertTrue($h->hasValue('Foo'));
+ $this->assertTrue($h->hasValue('bar'));
+ $this->assertFalse($h->hasValue('moo'));
+ $this->assertFalse($h->hasValue('FoO'));
+ }
+
+ public function testIsCountable()
+ {
+ $h = new Header('Zoo', $this->test);
+ $this->assertEquals(3, count($h));
+ }
+
+ public function testCanBeIterated()
+ {
+ $h = new Header('Zoo', $this->test);
+ $results = array();
+ foreach ($h as $key => $value) {
+ $results[$key] = $value;
+ }
+ $this->assertEquals(array(
+ 'foo', 'Foo', 'bar'
+ ), $results);
+ }
+
+ public function testAllowsFalseyValues()
+ {
+ // Allows 0
+ $h = new Header('Foo', 0, ';');
+ $this->assertEquals('0', (string) $h);
+ $this->assertEquals(1, count($h));
+ $this->assertEquals(';', $h->getGlue());
+
+ // Does not add a null header by default
+ $h = new Header('Foo');
+ $this->assertEquals('', (string) $h);
+ $this->assertEquals(0, count($h));
+
+ // Allows null array for a single null header
+ $h = new Header('Foo', array(null));
+ $this->assertEquals('', (string) $h);
+
+ // Allows empty string
+ $h = new Header('Foo', '');
+ $this->assertEquals('', (string) $h);
+ $this->assertEquals(1, count($h));
+ $this->assertEquals(1, count($h->normalize()->toArray()));
+ }
+
+ public function testCanRemoveValues()
+ {
+ $h = new Header('Foo', array('Foo', 'baz', 'bar'));
+ $h->removeValue('bar');
+ $this->assertTrue($h->hasValue('Foo'));
+ $this->assertFalse($h->hasValue('bar'));
+ $this->assertTrue($h->hasValue('baz'));
+ }
+
+ public function testAllowsArrayInConstructor()
+ {
+ $h = new Header('Foo', array('Testing', '123', 'Foo=baz'));
+ $this->assertEquals(array('Testing', '123', 'Foo=baz'), $h->toArray());
+ }
+
+ public function parseParamsProvider()
+ {
+ $res1 = array(
+ array(
+ '' => '',
+ 'rel' => 'front',
+ 'type' => 'image/jpeg',
+ ),
+ array(
+ '' => '',
+ 'rel' => 'back',
+ 'type' => 'image/jpeg',
+ ),
+ );
+
+ return array(
+ array(
+ '; rel="front"; type="image/jpeg", ; rel=back; type="image/jpeg"',
+ $res1
+ ),
+ array(
+ '; rel="front"; type="image/jpeg",; rel=back; type="image/jpeg"',
+ $res1
+ ),
+ array(
+ 'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"',
+ array(
+ array('foo' => 'baz', 'bar' => '123'),
+ array('boo' => ''),
+ array('test' => '123'),
+ array('foobar' => 'foo;bar')
+ )
+ ),
+ array(
+ '; rel="side"; type="image/jpeg",; rel=side; type="image/jpeg"',
+ array(
+ array('' => '', 'rel' => 'side', 'type' => 'image/jpeg'),
+ array('' => '', 'rel' => 'side', 'type' => 'image/jpeg')
+ )
+ ),
+ array(
+ '',
+ array()
+ )
+ );
+ }
+
+ /**
+ * @dataProvider parseParamsProvider
+ */
+ public function testParseParams($header, $result)
+ {
+ $response = new Response(200, array('Link' => $header));
+ $this->assertEquals($result, $response->getHeader('Link')->parseParams());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php
new file mode 100755
index 0000000..be048cb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/PostFileTest.php
@@ -0,0 +1,88 @@
+assertEquals('foo', $file->getFieldName());
+ $this->assertEquals(__FILE__, $file->getFilename());
+ $this->assertEquals('boo', $file->getPostName());
+ $this->assertEquals('x-foo', $file->getContentType());
+ }
+
+ public function testRemovesLeadingAtSymbolFromPath()
+ {
+ $file = new PostFile('foo', '@' . __FILE__);
+ $this->assertEquals(__FILE__, $file->getFilename());
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testEnsuresFileIsReadable()
+ {
+ $file = new PostFile('foo', '/foo/baz/bar');
+ }
+
+ public function testCanChangeContentType()
+ {
+ $file = new PostFile('foo', '@' . __FILE__);
+ $file->setContentType('Boo');
+ $this->assertEquals('Boo', $file->getContentType());
+ }
+
+ public function testCanChangeFieldName()
+ {
+ $file = new PostFile('foo', '@' . __FILE__);
+ $file->setFieldName('Boo');
+ $this->assertEquals('Boo', $file->getFieldName());
+ }
+
+ public function testReturnsCurlValueString()
+ {
+ $file = new PostFile('foo', __FILE__);
+ if (version_compare(phpversion(), '5.5.0', '<')) {
+ $this->assertContains('@' . __FILE__ . ';filename=PostFileTest.php;type=text/x-', $file->getCurlValue());
+ } else {
+ $c = $file->getCurlValue();
+ $this->assertEquals(__FILE__, $c->getFilename());
+ $this->assertEquals('PostFileTest.php', $c->getPostFilename());
+ $this->assertContains('text/x-', $c->getMimeType());
+ }
+ }
+
+ public function testReturnsCurlValueStringAndPostname()
+ {
+ $file = new PostFile('foo', __FILE__, null, 'NewPostFileTest.php');
+ if (version_compare(phpversion(), '5.5.0', '<')) {
+ $this->assertContains('@' . __FILE__ . ';filename=NewPostFileTest.php;type=text/x-', $file->getCurlValue());
+ } else {
+ $c = $file->getCurlValue();
+ $this->assertEquals(__FILE__, $c->getFilename());
+ $this->assertEquals('NewPostFileTest.php', $c->getPostFilename());
+ $this->assertContains('text/x-', $c->getMimeType());
+ }
+ }
+
+ public function testContentDispositionFilePathIsStripped()
+ {
+ $this->getServer()->flush();
+ $client = new Client($this->getServer()->getUrl());
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request = $client->post()->addPostFile('file', __FILE__);
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(false);
+ $this->assertContains('POST / HTTP/1.1', $requests[0]);
+ $this->assertContains('Content-Disposition: form-data; name="file"; filename="PostFileTest.php"', $requests[0]);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php
new file mode 100755
index 0000000..80b8d54
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestFactoryTest.php
@@ -0,0 +1,616 @@
+assertSame($factory, RequestFactory::getInstance());
+ }
+
+ public function testCreatesNewGetRequests()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://www.google.com/');
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\MessageInterface', $request);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\RequestInterface', $request);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $request);
+ $this->assertEquals('GET', $request->getMethod());
+ $this->assertEquals('http', $request->getScheme());
+ $this->assertEquals('http://www.google.com/', $request->getUrl());
+ $this->assertEquals('www.google.com', $request->getHost());
+ $this->assertEquals('/', $request->getPath());
+ $this->assertEquals('/', $request->getResource());
+
+ // Create a GET request with a custom receiving body
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $b = EntityBody::factory();
+ $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl(), null, $b);
+ $request->setClient(new Client());
+ $response = $request->send();
+ $this->assertSame($b, $response->getBody());
+ }
+
+ public function testCreatesPutRequests()
+ {
+ // Test using a string
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, 'Data');
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('PUT', $request->getMethod());
+ $this->assertEquals('http', $request->getScheme());
+ $this->assertEquals('http://www.google.com/path?q=1&v=2', $request->getUrl());
+ $this->assertEquals('www.google.com', $request->getHost());
+ $this->assertEquals('/path', $request->getPath());
+ $this->assertEquals('/path?q=1&v=2', $request->getResource());
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody());
+ $this->assertEquals('Data', (string) $request->getBody());
+ unset($request);
+
+ // Test using an EntityBody
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, EntityBody::factory('Data'));
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('Data', (string) $request->getBody());
+
+ // Test using a resource
+ $resource = fopen('php://temp', 'w+');
+ fwrite($resource, 'Data');
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, $resource);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('Data', (string) $request->getBody());
+
+ // Test using an object that can be cast as a string
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, Url::factory('http://www.example.com/'));
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('http://www.example.com/', (string) $request->getBody());
+ }
+
+ public function testCreatesHeadAndDeleteRequests()
+ {
+ $request = RequestFactory::getInstance()->create('DELETE', 'http://www.test.com/');
+ $this->assertEquals('DELETE', $request->getMethod());
+ $request = RequestFactory::getInstance()->create('HEAD', 'http://www.test.com/');
+ $this->assertEquals('HEAD', $request->getMethod());
+ }
+
+ public function testCreatesOptionsRequests()
+ {
+ $request = RequestFactory::getInstance()->create('OPTIONS', 'http://www.example.com/');
+ $this->assertEquals('OPTIONS', $request->getMethod());
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ }
+
+ public function testCreatesNewPutRequestWithBody()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', null, 'Data');
+ $this->assertEquals('Data', (string) $request->getBody());
+ }
+
+ public function testCreatesNewPostRequestWithFields()
+ {
+ // Use an array
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.google.com/path?q=1&v=2', null, array(
+ 'a' => 'b'
+ ));
+ $this->assertEquals(array('a' => 'b'), $request->getPostFields()->getAll());
+ unset($request);
+
+ // Use a collection
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.google.com/path?q=1&v=2', null, new Collection(array(
+ 'a' => 'b'
+ )));
+ $this->assertEquals(array('a' => 'b'), $request->getPostFields()->getAll());
+
+ // Use a QueryString
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.google.com/path?q=1&v=2', null, new QueryString(array(
+ 'a' => 'b'
+ )));
+ $this->assertEquals(array('a' => 'b'), $request->getPostFields()->getAll());
+
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.test.com/', null, array(
+ 'a' => 'b',
+ 'file' => '@' . __FILE__
+ ));
+
+ $this->assertEquals(array(
+ 'a' => 'b'
+ ), $request->getPostFields()->getAll());
+
+ $files = $request->getPostFiles();
+ $this->assertInstanceOf('Guzzle\Http\Message\PostFile', $files['file'][0]);
+ }
+
+ public function testCreatesFromParts()
+ {
+ $parts = parse_url('http://michael:123@www.google.com:8080/path?q=1&v=2');
+
+ $request = RequestFactory::getInstance()->fromParts('PUT', $parts, null, 'Data');
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('PUT', $request->getMethod());
+ $this->assertEquals('http', $request->getScheme());
+ $this->assertEquals('http://www.google.com:8080/path?q=1&v=2', $request->getUrl());
+ $this->assertEquals('www.google.com', $request->getHost());
+ $this->assertEquals('www.google.com:8080', $request->getHeader('Host'));
+ $this->assertEquals('/path', $request->getPath());
+ $this->assertEquals('/path?q=1&v=2', $request->getResource());
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody());
+ $this->assertEquals('Data', (string) $request->getBody());
+ $this->assertEquals('michael', $request->getUsername());
+ $this->assertEquals('123', $request->getPassword());
+ $this->assertEquals('8080', $request->getPort());
+ $this->assertEquals(array(
+ 'scheme' => 'http',
+ 'host' => 'www.google.com',
+ 'port' => 8080,
+ 'path' => '/path',
+ 'query' => 'q=1&v=2',
+ ), parse_url($request->getUrl()));
+ }
+
+ public function testCreatesFromMessage()
+ {
+ $auth = base64_encode('michael:123');
+ $message = "PUT /path?q=1&v=2 HTTP/1.1\r\nHost: www.google.com:8080\r\nContent-Length: 4\r\nAuthorization: Basic {$auth}\r\n\r\nData";
+ $request = RequestFactory::getInstance()->fromMessage($message);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('PUT', $request->getMethod());
+ $this->assertEquals('http', $request->getScheme());
+ $this->assertEquals('http://www.google.com:8080/path?q=1&v=2', $request->getUrl());
+ $this->assertEquals('www.google.com', $request->getHost());
+ $this->assertEquals('www.google.com:8080', $request->getHeader('Host'));
+ $this->assertEquals('/path', $request->getPath());
+ $this->assertEquals('/path?q=1&v=2', $request->getResource());
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody());
+ $this->assertEquals('Data', (string) $request->getBody());
+ $this->assertEquals("Basic {$auth}", (string) $request->getHeader('Authorization'));
+ $this->assertEquals('8080', $request->getPort());
+
+ // Test passing a blank message returns false
+ $this->assertFalse($request = RequestFactory::getInstance()->fromMessage(''));
+
+ // Test passing a url with no port
+ $message = "PUT /path?q=1&v=2 HTTP/1.1\r\nHost: www.google.com\r\nContent-Length: 4\r\nAuthorization: Basic {$auth}\r\n\r\nData";
+ $request = RequestFactory::getInstance()->fromMessage($message);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\EntityEnclosingRequest', $request);
+ $this->assertEquals('PUT', $request->getMethod());
+ $this->assertEquals('http', $request->getScheme());
+ $this->assertEquals('http://www.google.com/path?q=1&v=2', $request->getUrl());
+ $this->assertEquals('www.google.com', $request->getHost());
+ $this->assertEquals('/path', $request->getPath());
+ $this->assertEquals('/path?q=1&v=2', $request->getResource());
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $request->getBody());
+ $this->assertEquals('Data', (string) $request->getBody());
+ $this->assertEquals("Basic {$auth}", (string) $request->getHeader('Authorization'));
+ $this->assertEquals(80, $request->getPort());
+ }
+
+ public function testCreatesNewTraceRequest()
+ {
+ $request = RequestFactory::getInstance()->create('TRACE', 'http://www.google.com/');
+ $this->assertFalse($request instanceof \Guzzle\Http\Message\EntityEnclosingRequest);
+ $this->assertEquals('TRACE', $request->getMethod());
+ }
+
+ public function testCreatesProperTransferEncodingRequests()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/', array(
+ 'Transfer-Encoding' => 'chunked'
+ ), 'hello');
+ $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding'));
+ $this->assertFalse($request->hasHeader('Content-Length'));
+ }
+
+ public function testProperlyDealsWithDuplicateHeaders()
+ {
+ $parser = new MessageParser();
+
+ $message = "POST / http/1.1\r\n"
+ . "DATE:Mon, 09 Sep 2011 23:36:00 GMT\r\n"
+ . "host:host.foo.com\r\n"
+ . "ZOO:abc\r\n"
+ . "ZOO:123\r\n"
+ . "ZOO:HI\r\n"
+ . "zoo:456\r\n\r\n";
+
+ $parts = $parser->parseRequest($message);
+ $this->assertEquals(array (
+ 'DATE' => 'Mon, 09 Sep 2011 23:36:00 GMT',
+ 'host' => 'host.foo.com',
+ 'ZOO' => array('abc', '123', 'HI'),
+ 'zoo' => '456',
+ ), $parts['headers']);
+
+ $request = RequestFactory::getInstance()->fromMessage($message);
+
+ $this->assertEquals(array(
+ 'abc', '123', 'HI', '456'
+ ), $request->getHeader('zoo')->toArray());
+ }
+
+ public function testCreatesHttpMessagesWithBodiesAndNormalizesLineEndings()
+ {
+ $message = "POST / http/1.1\r\n"
+ . "Content-Type:application/x-www-form-urlencoded; charset=utf8\r\n"
+ . "Date:Mon, 09 Sep 2011 23:36:00 GMT\r\n"
+ . "Host:host.foo.com\r\n\r\n"
+ . "foo=bar";
+
+ $request = RequestFactory::getInstance()->fromMessage($message);
+ $this->assertEquals('application/x-www-form-urlencoded; charset=utf8', (string) $request->getHeader('Content-Type'));
+ $this->assertEquals('foo=bar', (string) $request->getBody());
+
+ $message = "POST / http/1.1\n"
+ . "Content-Type:application/x-www-form-urlencoded; charset=utf8\n"
+ . "Date:Mon, 09 Sep 2011 23:36:00 GMT\n"
+ . "Host:host.foo.com\n\n"
+ . "foo=bar";
+ $request = RequestFactory::getInstance()->fromMessage($message);
+ $this->assertEquals('foo=bar', (string) $request->getBody());
+
+ $message = "PUT / HTTP/1.1\r\nContent-Length: 0\r\n\r\n";
+ $request = RequestFactory::getInstance()->fromMessage($message);
+ $this->assertTrue($request->hasHeader('Content-Length'));
+ $this->assertEquals(0, (string) $request->getHeader('Content-Length'));
+ }
+
+ public function testBugPathIncorrectlyHandled()
+ {
+ $message = "POST /foo\r\n\r\nBODY";
+ $request = RequestFactory::getInstance()->fromMessage($message);
+ $this->assertSame('POST', $request->getMethod());
+ $this->assertSame('/foo', $request->getPath());
+ $this->assertSame('BODY', (string) $request->getBody());
+ }
+
+ public function testHandlesChunkedTransferEncoding()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.foo.com/', array(
+ 'Transfer-Encoding' => 'chunked'
+ ), 'Test');
+ $this->assertFalse($request->hasHeader('Content-Length'));
+ $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding'));
+
+ $request = RequestFactory::getInstance()->create('POST', 'http://www.foo.com/', array(
+ 'transfer-encoding' => 'chunked'
+ ), array(
+ 'foo' => 'bar'
+ ));
+
+ $this->assertFalse($request->hasHeader('Content-Length'));
+ $this->assertEquals('chunked', $request->getHeader('Transfer-Encoding'));
+ }
+
+ public function testClonesRequestsWithMethodWithoutClient()
+ {
+ $f = RequestFactory::getInstance();
+ $request = $f->create('GET', 'http://www.test.com', array('X-Foo' => 'Bar'));
+ $request->getParams()->replace(array('test' => '123'));
+ $request->getCurlOptions()->set('foo', 'bar');
+ $cloned = $f->cloneRequestWithMethod($request, 'PUT');
+ $this->assertEquals('PUT', $cloned->getMethod());
+ $this->assertEquals('Bar', (string) $cloned->getHeader('X-Foo'));
+ $this->assertEquals('http://www.test.com', $cloned->getUrl());
+ // Ensure params are cloned and cleaned up
+ $this->assertEquals(1, count($cloned->getParams()->getAll()));
+ $this->assertEquals('123', $cloned->getParams()->get('test'));
+ // Ensure curl options are cloned
+ $this->assertEquals('bar', $cloned->getCurlOptions()->get('foo'));
+ // Ensure event dispatcher is cloned
+ $this->assertNotSame($request->getEventDispatcher(), $cloned->getEventDispatcher());
+ }
+
+ public function testClonesRequestsWithMethodWithClient()
+ {
+ $f = RequestFactory::getInstance();
+ $client = new Client();
+ $request = $client->put('http://www.test.com', array('Content-Length' => 4), 'test');
+ $cloned = $f->cloneRequestWithMethod($request, 'GET');
+ $this->assertEquals('GET', $cloned->getMethod());
+ $this->assertNull($cloned->getHeader('Content-Length'));
+ $this->assertEquals('http://www.test.com', $cloned->getUrl());
+ $this->assertSame($request->getClient(), $cloned->getClient());
+ }
+
+ public function testClonesRequestsWithMethodWithClientWithEntityEnclosingChange()
+ {
+ $f = RequestFactory::getInstance();
+ $client = new Client();
+ $request = $client->put('http://www.test.com', array('Content-Length' => 4), 'test');
+ $cloned = $f->cloneRequestWithMethod($request, 'POST');
+ $this->assertEquals('POST', $cloned->getMethod());
+ $this->assertEquals('test', (string) $cloned->getBody());
+ }
+
+ public function testCanDisableRedirects()
+ {
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 307\r\nLocation: " . $this->getServer()->getUrl() . "\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $response = $client->get('/', array(), array('allow_redirects' => false))->send();
+ $this->assertEquals(307, $response->getStatusCode());
+ }
+
+ public function testCanAddCookies()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get('/', array(), array('cookies' => array('Foo' => 'Bar')));
+ $this->assertEquals('Bar', $request->getCookie('Foo'));
+ }
+
+ public function testCanAddQueryString()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://foo.com', array(), null, array(
+ 'query' => array('Foo' => 'Bar')
+ ));
+ $this->assertEquals('Bar', $request->getQuery()->get('Foo'));
+ }
+
+ public function testCanSetDefaultQueryString()
+ {
+ $request = new Request('GET', 'http://www.foo.com?test=abc');
+ RequestFactory::getInstance()->applyOptions($request, array(
+ 'query' => array('test' => '123', 'other' => 't123')
+ ), RequestFactory::OPTIONS_AS_DEFAULTS);
+ $this->assertEquals('abc', $request->getQuery()->get('test'));
+ $this->assertEquals('t123', $request->getQuery()->get('other'));
+ }
+
+ public function testCanAddBasicAuth()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://foo.com', array(), null, array(
+ 'auth' => array('michael', 'test')
+ ));
+ $this->assertEquals('michael', $request->getUsername());
+ $this->assertEquals('test', $request->getPassword());
+ }
+
+ public function testCanAddDigestAuth()
+ {
+ $request = RequestFactory::getInstance()->create('GET', 'http://foo.com', array(), null, array(
+ 'auth' => array('michael', 'test', 'digest')
+ ));
+ $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH));
+ $this->assertEquals('michael', $request->getUsername());
+ $this->assertEquals('test', $request->getPassword());
+ }
+
+ public function testCanAddEvents()
+ {
+ $foo = null;
+ $client = new Client();
+ $client->addSubscriber(new MockPlugin(array(new Response(200))));
+ $request = $client->get($this->getServer()->getUrl(), array(), array(
+ 'events' => array(
+ 'request.before_send' => function () use (&$foo) { $foo = true; }
+ )
+ ));
+ $request->send();
+ $this->assertTrue($foo);
+ }
+
+ public function testCanAddEventsWithPriority()
+ {
+ $foo = null;
+ $client = new Client();
+ $client->addSubscriber(new MockPlugin(array(new Response(200))));
+ $request = $client->get($this->getServer()->getUrl(), array(), array(
+ 'events' => array(
+ 'request.before_send' => array(function () use (&$foo) { $foo = true; }, 100)
+ )
+ ));
+ $request->send();
+ $this->assertTrue($foo);
+ }
+
+ public function testCanAddPlugins()
+ {
+ $mock = new MockPlugin(array(
+ new Response(200),
+ new Response(200)
+ ));
+ $client = new Client();
+ $client->addSubscriber($mock);
+ $request = $client->get('/', array(), array(
+ 'plugins' => array($mock)
+ ));
+ $request->send();
+ }
+
+ public function testCanDisableExceptions()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array(
+ 'plugins' => array(new MockPlugin(array(new Response(500)))),
+ 'exceptions' => false
+ ));
+ $this->assertEquals(500, $request->send()->getStatusCode());
+ }
+
+ public function testCanDisableExceptionsWithErrorListener()
+ {
+ $client = new Client();
+ $client->getEventDispatcher()->addListener('request.error', function () {});
+ $request = $client->get('/', array(), array(
+ 'plugins' => array(new MockPlugin(array(new Response(500)))),
+ 'exceptions' => false
+ ));
+ $this->assertEquals(500, $request->send()->getStatusCode());
+ }
+
+ public function testCanChangeSaveToLocation()
+ {
+ $r = EntityBody::factory();
+ $client = new Client();
+ $request = $client->get('/', array(), array(
+ 'plugins' => array(new MockPlugin(array(new Response(200, array(), 'testing')))),
+ 'save_to' => $r
+ ));
+ $request->send();
+ $this->assertEquals('testing', (string) $r);
+ }
+
+ public function testCanSetProxy()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('proxy' => '192.168.16.121'));
+ $this->assertEquals('192.168.16.121', $request->getCurlOptions()->get(CURLOPT_PROXY));
+ }
+
+ public function testCanSetHeadersOption()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('headers' => array('Foo' => 'Bar')));
+ $this->assertEquals('Bar', (string) $request->getHeader('Foo'));
+ }
+
+ public function testCanSetDefaultHeadersOptions()
+ {
+ $request = new Request('GET', 'http://www.foo.com', array('Foo' => 'Bar'));
+ RequestFactory::getInstance()->applyOptions($request, array(
+ 'headers' => array('Foo' => 'Baz', 'Bam' => 't123')
+ ), RequestFactory::OPTIONS_AS_DEFAULTS);
+ $this->assertEquals('Bar', (string) $request->getHeader('Foo'));
+ $this->assertEquals('t123', (string) $request->getHeader('Bam'));
+ }
+
+ public function testCanSetBodyOption()
+ {
+ $client = new Client();
+ $request = $client->put('/', array(), null, array('body' => 'test'));
+ $this->assertEquals('test', (string) $request->getBody());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testValidatesBodyOption()
+ {
+ $client = new Client();
+ $client->get('/', array(), array('body' => 'test'));
+ }
+
+ public function testCanSetTimeoutOption()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('timeout' => 1.5));
+ $this->assertEquals(1500, $request->getCurlOptions()->get(CURLOPT_TIMEOUT_MS));
+ }
+
+ public function testCanSetConnectTimeoutOption()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('connect_timeout' => 1.5));
+ $this->assertEquals(1500, $request->getCurlOptions()->get(CURLOPT_CONNECTTIMEOUT_MS));
+ }
+
+ public function testCanSetDebug()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('debug' => true));
+ $this->assertTrue($request->getCurlOptions()->get(CURLOPT_VERBOSE));
+ }
+
+ public function testCanSetVerifyToOff()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('verify' => false));
+ $this->assertNull($request->getCurlOptions()->get(CURLOPT_CAINFO));
+ $this->assertSame(0, $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYHOST));
+ $this->assertFalse($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER));
+ }
+
+ public function testCanSetVerifyToOn()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('verify' => true));
+ $this->assertNotNull($request->getCurlOptions()->get(CURLOPT_CAINFO));
+ $this->assertSame(2, $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYHOST));
+ $this->assertTrue($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER));
+ }
+
+ public function testCanSetVerifyToPath()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('verify' => '/foo.pem'));
+ $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_CAINFO));
+ $this->assertSame(2, $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYHOST));
+ $this->assertTrue($request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER));
+ }
+
+ public function inputValidation()
+ {
+ return array_map(function ($option) { return array($option); }, array(
+ 'headers', 'query', 'cookies', 'auth', 'events', 'plugins', 'params'
+ ));
+ }
+
+ /**
+ * @dataProvider inputValidation
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testValidatesInput($option)
+ {
+ $client = new Client();
+ $client->get('/', array(), array($option => 'foo'));
+ }
+
+ public function testCanAddRequestParams()
+ {
+ $client = new Client();
+ $request = $client->put('/', array(), null, array('params' => array('foo' => 'test')));
+ $this->assertEquals('test', $request->getParams()->get('foo'));
+ }
+
+ public function testCanAddSslKey()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('ssl_key' => '/foo.pem'));
+ $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLKEY));
+ }
+
+ public function testCanAddSslKeyPassword()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('ssl_key' => array('/foo.pem', 'bar')));
+ $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLKEY));
+ $this->assertEquals('bar', $request->getCurlOptions()->get(CURLOPT_SSLKEYPASSWD));
+ }
+
+ public function testCanAddSslCert()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('cert' => '/foo.pem'));
+ $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLCERT));
+ }
+
+ public function testCanAddSslCertPassword()
+ {
+ $client = new Client();
+ $request = $client->get('/', array(), array('cert' => array('/foo.pem', 'bar')));
+ $this->assertEquals('/foo.pem', $request->getCurlOptions()->get(CURLOPT_SSLCERT));
+ $this->assertEquals('bar', $request->getCurlOptions()->get(CURLOPT_SSLCERTPASSWD));
+ }
+
+ public function testCreatesBodyWithoutZeroString()
+ {
+ $request = RequestFactory::getInstance()->create('PUT', 'http://test.com', array(), '0');
+ $this->assertSame('0', (string) $request->getBody());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php
new file mode 100755
index 0000000..5bf6248
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/RequestTest.php
@@ -0,0 +1,639 @@
+client = new Client($this->getServer()->getUrl());
+ $this->request = $this->client->get();
+ }
+
+ public function tearDown()
+ {
+ unset($this->request);
+ unset($this->client);
+ }
+
+ public function testConstructorBuildsRequestWithArrayHeaders()
+ {
+ // Test passing an array of headers
+ $request = new Request('GET', 'http://www.guzzle-project.com/', array(
+ 'foo' => 'bar'
+ ));
+
+ $this->assertEquals('GET', $request->getMethod());
+ $this->assertEquals('http://www.guzzle-project.com/', $request->getUrl());
+ $this->assertEquals('bar', $request->getHeader('foo'));
+ }
+
+ public function testDescribesEvents()
+ {
+ $this->assertInternalType('array', Request::getAllEvents());
+ }
+
+ public function testConstructorBuildsRequestWithCollectionHeaders()
+ {
+ $request = new Request('GET', 'http://www.guzzle-project.com/', new Collection(array(
+ 'foo' => 'bar'
+ )));
+ $this->assertEquals('bar', $request->getHeader('foo'));
+ }
+
+ public function testConstructorBuildsRequestWithNoHeaders()
+ {
+ $request = new Request('GET', 'http://www.guzzle-project.com/', null);
+ $this->assertFalse($request->hasHeader('foo'));
+ }
+
+ public function testConstructorHandlesNonBasicAuth()
+ {
+ $request = new Request('GET', 'http://www.guzzle-project.com/', array(
+ 'Authorization' => 'Foo bar'
+ ));
+ $this->assertNull($request->getUserName());
+ $this->assertNull($request->getPassword());
+ $this->assertEquals('Foo bar', (string) $request->getHeader('Authorization'));
+ }
+
+ public function testRequestsCanBeConvertedToRawMessageStrings()
+ {
+ $auth = base64_encode('michael:123');
+ $message = "PUT /path?q=1&v=2 HTTP/1.1\r\n"
+ . "Host: www.google.com\r\n"
+ . "Authorization: Basic {$auth}\r\n"
+ . "Content-Length: 4\r\n\r\nData";
+
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.google.com/path?q=1&v=2', array(
+ 'Authorization' => 'Basic ' . $auth
+ ), 'Data');
+
+ $this->assertEquals($message, $request->__toString());
+ }
+
+ /**
+ * Add authorization after the fact and see that it was put in the message
+ */
+ public function testRequestStringsIncludeAuth()
+ {
+ $auth = base64_encode('michael:123');
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request = RequestFactory::getInstance()->create('PUT', $this->getServer()->getUrl(), null, 'Data')
+ ->setClient($this->client)
+ ->setAuth('michael', '123', CURLAUTH_BASIC);
+ $request->send();
+
+ $this->assertContains('Authorization: Basic ' . $auth, (string) $request);
+ }
+
+ public function testGetEventDispatcher()
+ {
+ $d = $this->request->getEventDispatcher();
+ $this->assertInstanceOf('Symfony\\Component\\EventDispatcher\\EventDispatcherInterface', $d);
+ $this->assertEquals($d, $this->request->getEventDispatcher());
+ }
+
+ public function testRequestsManageClients()
+ {
+ $request = new Request('GET', 'http://test.com');
+ $this->assertNull($request->getClient());
+ $request->setClient($this->client);
+ $this->assertSame($this->client, $request->getClient());
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage A client must be set on the request
+ */
+ public function testRequestsRequireClients()
+ {
+ $request = new Request('GET', 'http://test.com');
+ $request->send();
+ }
+
+ public function testSend()
+ {
+ $response = new Response(200, array(
+ 'Content-Length' => 3
+ ), 'abc');
+ $this->request->setResponse($response, true);
+ $r = $this->request->send();
+
+ $this->assertSame($response, $r);
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $this->request->getResponse());
+ $this->assertSame($r, $this->request->getResponse());
+ $this->assertEquals('complete', $this->request->getState());
+ }
+
+ public function testGetResponse()
+ {
+ $this->assertNull($this->request->getResponse());
+ $response = new Response(200, array('Content-Length' => 3), 'abc');
+
+ $this->request->setResponse($response);
+ $this->assertEquals($response, $this->request->getResponse());
+
+ $client = new Client('http://www.google.com');
+ $request = $client->get('http://www.google.com/');
+ $request->setResponse($response, true);
+ $request->send();
+ $requestResponse = $request->getResponse();
+ $this->assertSame($response, $requestResponse);
+
+ // Try again, making sure it's still the same response
+ $this->assertSame($requestResponse, $request->getResponse());
+
+ $response = new Response(204);
+ $request = $client->get();
+ $request->setResponse($response, true);
+ $request->send();
+ $requestResponse = $request->getResponse();
+ $this->assertSame($response, $requestResponse);
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody());
+ }
+
+ public function testRequestThrowsExceptionOnBadResponse()
+ {
+ try {
+ $this->request->setResponse(new Response(404, array('Content-Length' => 3), 'abc'), true);
+ $this->request->send();
+ $this->fail('Expected exception not thrown');
+ } catch (BadResponseException $e) {
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\RequestInterface', $e->getRequest());
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $e->getResponse());
+ $this->assertContains('Client error response', $e->getMessage());
+ }
+ }
+
+ public function testManagesQuery()
+ {
+ $this->assertInstanceOf('Guzzle\\Http\\QueryString', $this->request->getQuery());
+ $this->request->getQuery()->set('test', '123');
+ $this->assertEquals('test=123', $this->request->getQuery(true));
+ }
+
+ public function testRequestHasMethod()
+ {
+ $this->assertEquals('GET', $this->request->getMethod());
+ }
+
+ public function testRequestHasScheme()
+ {
+ $this->assertEquals('http', $this->request->getScheme());
+ $this->assertEquals($this->request, $this->request->setScheme('https'));
+ $this->assertEquals('https', $this->request->getScheme());
+ }
+
+ public function testRequestHasHost()
+ {
+ $this->assertEquals('127.0.0.1', $this->request->getHost());
+ $this->assertEquals('127.0.0.1:8124', (string) $this->request->getHeader('Host'));
+
+ $this->assertSame($this->request, $this->request->setHost('www2.google.com'));
+ $this->assertEquals('www2.google.com', $this->request->getHost());
+ $this->assertEquals('www2.google.com:8124', (string) $this->request->getHeader('Host'));
+
+ $this->assertSame($this->request, $this->request->setHost('www.test.com:8081'));
+ $this->assertEquals('www.test.com', $this->request->getHost());
+ $this->assertEquals(8081, $this->request->getPort());
+ }
+
+ public function testRequestHasProtocol()
+ {
+ $this->assertEquals('1.1', $this->request->getProtocolVersion());
+ $this->assertEquals($this->request, $this->request->setProtocolVersion('1.1'));
+ $this->assertEquals('1.1', $this->request->getProtocolVersion());
+ $this->assertEquals($this->request, $this->request->setProtocolVersion('1.0'));
+ $this->assertEquals('1.0', $this->request->getProtocolVersion());
+ }
+
+ public function testRequestHasPath()
+ {
+ $this->assertEquals('/', $this->request->getPath());
+ $this->assertEquals($this->request, $this->request->setPath('/index.html'));
+ $this->assertEquals('/index.html', $this->request->getPath());
+ $this->assertEquals($this->request, $this->request->setPath('index.html'));
+ $this->assertEquals('/index.html', $this->request->getPath());
+ }
+
+ public function testPermitsFalsyComponents()
+ {
+ $request = new Request('GET', 'http://0/0?0');
+ $this->assertSame('0', $request->getHost());
+ $this->assertSame('/0', $request->getPath());
+ $this->assertSame('0', $request->getQuery(true));
+
+ $request = new Request('GET', '0');
+ $this->assertEquals('/0', $request->getPath());
+ }
+
+ public function testRequestHasPort()
+ {
+ $this->assertEquals(8124, $this->request->getPort());
+ $this->assertEquals('127.0.0.1:8124', $this->request->getHeader('Host'));
+
+ $this->assertEquals($this->request, $this->request->setPort('8080'));
+ $this->assertEquals('8080', $this->request->getPort());
+ $this->assertEquals('127.0.0.1:8080', $this->request->getHeader('Host'));
+
+ $this->request->setPort(80);
+ $this->assertEquals('127.0.0.1', $this->request->getHeader('Host'));
+ }
+
+ public function testRequestHandlesAuthorization()
+ {
+ // Uninitialized auth
+ $this->assertEquals(null, $this->request->getUsername());
+ $this->assertEquals(null, $this->request->getPassword());
+
+ // Set an auth
+ $this->assertSame($this->request, $this->request->setAuth('michael', '123'));
+ $this->assertEquals('michael', $this->request->getUsername());
+ $this->assertEquals('123', $this->request->getPassword());
+
+ // Set an auth with blank password
+ $this->assertSame($this->request, $this->request->setAuth('michael', ''));
+ $this->assertEquals('michael', $this->request->getUsername());
+ $this->assertEquals('', $this->request->getPassword());
+
+ // Remove the auth
+ $this->request->setAuth(false);
+ $this->assertEquals(null, $this->request->getUsername());
+ $this->assertEquals(null, $this->request->getPassword());
+
+ // Make sure that the cURL based auth works too
+ $request = new Request('GET', $this->getServer()->getUrl());
+ $request->setAuth('michael', 'password', CURLAUTH_DIGEST);
+ $this->assertEquals('michael:password', $request->getCurlOptions()->get(CURLOPT_USERPWD));
+ $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH));
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testValidatesAuth()
+ {
+ $this->request->setAuth('foo', 'bar', 'bam');
+ }
+
+ public function testGetResourceUri()
+ {
+ $this->assertEquals('/', $this->request->getResource());
+ $this->request->setPath('/index.html');
+ $this->assertEquals('/index.html', $this->request->getResource());
+ $this->request->getQuery()->add('v', '1');
+ $this->assertEquals('/index.html?v=1', $this->request->getResource());
+ }
+
+ public function testRequestHasMutableUrl()
+ {
+ $url = 'http://www.test.com:8081/path?q=123#fragment';
+ $u = Url::factory($url);
+ $this->assertSame($this->request, $this->request->setUrl($url));
+ $this->assertEquals($url, $this->request->getUrl());
+
+ $this->assertSame($this->request, $this->request->setUrl($u));
+ $this->assertEquals($url, $this->request->getUrl());
+ }
+
+ public function testRequestHasState()
+ {
+ $this->assertEquals(RequestInterface::STATE_NEW, $this->request->getState());
+ $this->request->setState(RequestInterface::STATE_TRANSFER);
+ $this->assertEquals(RequestInterface::STATE_TRANSFER, $this->request->getState());
+ }
+
+ public function testSetManualResponse()
+ {
+ $response = new Response(200, array(
+ 'Date' => 'Sat, 16 Oct 2010 17:27:14 GMT',
+ 'Expires' => '-1',
+ 'Cache-Control' => 'private, max-age=0',
+ 'Content-Type' => 'text/html; charset=ISO-8859-1',
+ ), 'response body');
+
+ $this->assertSame($this->request, $this->request->setResponse($response), '-> setResponse() must use a fluent interface');
+ $this->assertEquals('complete', $this->request->getState(), '-> setResponse() must change the state of the request to complete');
+ $this->assertSame($response, $this->request->getResponse(), '-> setResponse() must set the exact same response that was passed in to it');
+ }
+
+ public function testRequestCanHaveManuallySetResponseBody()
+ {
+ $file = __DIR__ . '/../../TestData/temp.out';
+ if (file_exists($file)) {
+ unlink($file);
+ }
+
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata");
+ $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl());
+ $request->setClient($this->client);
+ $entityBody = EntityBody::factory(fopen($file, 'w+'));
+ $request->setResponseBody($entityBody);
+ $response = $request->send();
+ $this->assertSame($entityBody, $response->getBody());
+
+ $this->assertTrue(file_exists($file));
+ $this->assertEquals('data', file_get_contents($file));
+ unlink($file);
+
+ $this->assertEquals('data', $response->getBody(true));
+ }
+
+ public function testHoldsCookies()
+ {
+ $this->assertNull($this->request->getCookie('test'));
+
+ // Set a cookie
+ $this->assertSame($this->request, $this->request->addCookie('test', 'abc'));
+ $this->assertEquals('abc', $this->request->getCookie('test'));
+
+ // Multiple cookies by setting the Cookie header
+ $this->request->setHeader('Cookie', '__utma=1.638370270.1344367610.1374365610.1944450276.2; __utmz=1.1346368610.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); hl=de; PHPSESSID=ak93pqashi5uubuoq8fjv60897');
+ $this->assertEquals('1.638370270.1344367610.1374365610.1944450276.2', $this->request->getCookie('__utma'));
+ $this->assertEquals('1.1346368610.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)', $this->request->getCookie('__utmz'));
+ $this->assertEquals('de', $this->request->getCookie('hl'));
+ $this->assertEquals('ak93pqashi5uubuoq8fjv60897', $this->request->getCookie('PHPSESSID'));
+
+ // Unset the cookies by setting the Cookie header to null
+ $this->request->setHeader('Cookie', null);
+ $this->assertNull($this->request->getCookie('test'));
+ $this->request->removeHeader('Cookie');
+
+ // Set and remove a cookie
+ $this->assertSame($this->request, $this->request->addCookie('test', 'abc'));
+ $this->assertEquals('abc', $this->request->getCookie('test'));
+ $this->assertSame($this->request, $this->request->removeCookie('test'));
+ $this->assertNull($this->request->getCookie('test'));
+
+ // Remove the cookie header
+ $this->assertSame($this->request, $this->request->addCookie('test', 'abc'));
+ $this->request->removeHeader('Cookie');
+ $this->assertEquals('', (string) $this->request->getHeader('Cookie'));
+
+ // Remove a cookie value
+ $this->request->addCookie('foo', 'bar')->addCookie('baz', 'boo');
+ $this->request->removeCookie('foo');
+ $this->assertEquals(array(
+ 'baz' => 'boo'
+ ), $this->request->getCookies());
+
+ $this->request->addCookie('foo', 'bar');
+ $this->assertEquals('baz=boo; foo=bar', (string) $this->request->getHeader('Cookie'));
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\RequestException
+ * @expectedExceptionMessage Error completing request
+ */
+ public function testRequestThrowsExceptionWhenSetToCompleteWithNoResponse()
+ {
+ $this->request->setState(RequestInterface::STATE_COMPLETE);
+ }
+
+ public function testClonedRequestsUseNewInternalState()
+ {
+ $p = new AsyncPlugin();
+ $this->request->getEventDispatcher()->addSubscriber($p);
+ $h = $this->request->getHeader('Host');
+
+ $r = clone $this->request;
+ $this->assertEquals(RequestInterface::STATE_NEW, $r->getState());
+ $this->assertNotSame($r->getQuery(), $this->request->getQuery());
+ $this->assertNotSame($r->getCurlOptions(), $this->request->getCurlOptions());
+ $this->assertNotSame($r->getEventDispatcher(), $this->request->getEventDispatcher());
+ $this->assertEquals($r->getHeaders(), $this->request->getHeaders());
+ $this->assertNotSame($h, $r->getHeader('Host'));
+ $this->assertNotSame($r->getParams(), $this->request->getParams());
+ $this->assertTrue($this->request->getEventDispatcher()->hasListeners('request.sent'));
+ }
+
+ public function testRecognizesBasicAuthCredentialsInUrls()
+ {
+ $this->request->setUrl('http://michael:test@test.com/');
+ $this->assertEquals('michael', $this->request->getUsername());
+ $this->assertEquals('test', $this->request->getPassword());
+ }
+
+ public function testRequestCanBeSentUsingCurl()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\nConnection: close\r\n\r\ndata",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\nConnection: close\r\n\r\ndata",
+ "HTTP/1.1 404 Not Found\r\nContent-Encoding: application/xml\r\nContent-Length: 48\r\n\r\nFile not found "
+ ));
+
+ $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl());
+ $request->setClient($this->client);
+ $response = $request->send();
+
+ $this->assertEquals('data', $response->getBody(true));
+ $this->assertEquals(200, (int) $response->getStatusCode());
+ $this->assertEquals('OK', $response->getReasonPhrase());
+ $this->assertEquals(4, $response->getContentLength());
+ $this->assertEquals('Thu, 01 Dec 1994 16:00:00 GMT', $response->getExpires());
+
+ // Test that the same handle can be sent twice without setting state to new
+ $response2 = $request->send();
+ $this->assertNotSame($response, $response2);
+
+ try {
+ $request = RequestFactory::getInstance()->create('GET', $this->getServer()->getUrl() . 'index.html');
+ $request->setClient($this->client);
+ $response = $request->send();
+ $this->fail('Request did not receive a 404 response');
+ } catch (BadResponseException $e) {
+ }
+
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $messages = $this->getServer()->getReceivedRequests(false);
+ $port = $this->getServer()->getPort();
+
+ $userAgent = $this->client->getDefaultUserAgent();
+
+ $this->assertEquals('127.0.0.1:' . $port, $requests[0]->getHeader('Host'));
+ $this->assertEquals('127.0.0.1:' . $port, $requests[1]->getHeader('Host'));
+ $this->assertEquals('127.0.0.1:' . $port, $requests[2]->getHeader('Host'));
+
+ $this->assertEquals('/', $requests[0]->getPath());
+ $this->assertEquals('/', $requests[1]->getPath());
+ $this->assertEquals('/index.html', $requests[2]->getPath());
+
+ $parts = explode("\r\n", $messages[0]);
+ $this->assertEquals('GET / HTTP/1.1', $parts[0]);
+
+ $parts = explode("\r\n", $messages[1]);
+ $this->assertEquals('GET / HTTP/1.1', $parts[0]);
+
+ $parts = explode("\r\n", $messages[2]);
+ $this->assertEquals('GET /index.html HTTP/1.1', $parts[0]);
+ }
+
+ public function testThrowsExceptionsWhenUnsuccessfulResponseIsReceivedByDefault()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n");
+
+ try {
+ $request = $this->client->get('/index.html');
+ $response = $request->send();
+ $this->fail('Request did not receive a 404 response');
+ } catch (BadResponseException $e) {
+ $this->assertContains('Client error response', $e->getMessage());
+ $this->assertContains('[status code] 404', $e->getMessage());
+ $this->assertContains('[reason phrase] Not found', $e->getMessage());
+ }
+ }
+
+ public function testCanShortCircuitErrorHandling()
+ {
+ $request = $this->request;
+ $response = new Response(404);
+ $request->setResponse($response, true);
+ $out = '';
+ $that = $this;
+ $request->getEventDispatcher()->addListener('request.error', function($event) use (&$out, $that) {
+ $out .= $event['request'] . "\n" . $event['response'] . "\n";
+ $event->stopPropagation();
+ });
+ $request->send();
+ $this->assertContains((string) $request, $out);
+ $this->assertContains((string) $request->getResponse(), $out);
+ $this->assertSame($response, $request->getResponse());
+ }
+
+ public function testCanOverrideUnsuccessfulResponses()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 404 NOT FOUND\r\n" .
+ "Content-Length: 0\r\n" .
+ "\r\n",
+ "HTTP/1.1 200 OK\r\n" .
+ "Content-Length: 0\r\n" .
+ "\r\n"
+ ));
+
+ $newResponse = null;
+
+ $request = $this->request;
+ $request->getEventDispatcher()->addListener('request.error', function($event) use (&$newResponse) {
+ if ($event['response']->getStatusCode() == 404) {
+ $newRequest = clone $event['request'];
+ $newResponse = $newRequest->send();
+ // Override the original response and bypass additional response processing
+ $event['response'] = $newResponse;
+ // Call $event['request']->setResponse($newResponse); to re-apply events
+ $event->stopPropagation();
+ }
+ });
+
+ $request->send();
+
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+ $this->assertSame($newResponse, $request->getResponse());
+ $this->assertEquals(2, count($this->getServer()->getReceivedRequests()));
+ }
+
+ public function testCanRetrieveUrlObject()
+ {
+ $request = new Request('GET', 'http://www.example.com/foo?abc=d');
+ $this->assertInstanceOf('Guzzle\Http\Url', $request->getUrl(true));
+ $this->assertEquals('http://www.example.com/foo?abc=d', $request->getUrl());
+ $this->assertEquals('http://www.example.com/foo?abc=d', (string) $request->getUrl(true));
+ }
+
+ public function testUnresolvedRedirectsReturnResponse()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 303 SEE OTHER\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Foo\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $request = $this->request;
+ $this->assertEquals(303, $request->send()->getStatusCode());
+ $request->getParams()->set(RedirectPlugin::DISABLE, true);
+ $this->assertEquals(301, $request->send()->getStatusCode());
+ }
+
+ public function testCanSendCustomRequests()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $request = $this->client->createRequest('PROPFIND', $this->getServer()->getUrl(), array(
+ 'Content-Type' => 'text/plain'
+ ), 'foo');
+ $response = $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('PROPFIND', $requests[0]->getMethod());
+ $this->assertEquals(3, (string) $requests[0]->getHeader('Content-Length'));
+ $this->assertEquals('foo', (string) $requests[0]->getBody());
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_Error_Warning
+ */
+ public function testEnsuresFileCanBeCreated()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest");
+ $this->client->get('/')->setResponseBody('/wefwefefefefwewefwe/wefwefwefefwe/wefwefewfw.txt')->send();
+ }
+
+ public function testAllowsFilenameForDownloadingContent()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest");
+ $name = sys_get_temp_dir() . '/foo.txt';
+ $this->client->get('/')->setResponseBody($name)->send();
+ $this->assertEquals('test', file_get_contents($name));
+ unlink($name);
+ }
+
+ public function testUsesCustomResponseBodyWhenItIsCustom()
+ {
+ $en = EntityBody::factory();
+ $request = $this->client->get();
+ $request->setResponseBody($en);
+ $request->setResponse(new Response(200, array(), 'foo'));
+ $this->assertEquals('foo', (string) $en);
+ }
+
+ public function testCanChangePortThroughScheme()
+ {
+ $request = new Request('GET', 'http://foo.com');
+ $request->setScheme('https');
+ $this->assertEquals('https://foo.com', (string) $request->getUrl());
+ $this->assertEquals('foo.com', $request->getHost());
+ $request->setScheme('http');
+ $this->assertEquals('http://foo.com', (string) $request->getUrl());
+ $this->assertEquals('foo.com', $request->getHost());
+ $request->setPort(null);
+ $this->assertEquals('http://foo.com', (string) $request->getUrl());
+ $this->assertEquals('foo.com', $request->getHost());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php
new file mode 100755
index 0000000..08b4df8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Message/ResponseTest.php
@@ -0,0 +1,677 @@
+response = new Response(200, new Collection(array(
+ 'Accept-Ranges' => 'bytes',
+ 'Age' => '12',
+ 'Allow' => 'GET, HEAD',
+ 'Cache-Control' => 'no-cache',
+ 'Content-Encoding' => 'gzip',
+ 'Content-Language' => 'da',
+ 'Content-Length' => '348',
+ 'Content-Location' => '/index.htm',
+ 'Content-Disposition' => 'attachment; filename=fname.ext',
+ 'Content-MD5' => 'Q2hlY2sgSW50ZWdyaXR5IQ==',
+ 'Content-Range' => 'bytes 21010-47021/47022',
+ 'Content-Type' => 'text/html; charset=utf-8',
+ 'Date' => 'Tue, 15 Nov 1994 08:12:31 GMT',
+ 'ETag' => '737060cd8c284d8af7ad3082f209582d',
+ 'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT',
+ 'Last-Modified' => 'Tue, 15 Nov 1994 12:45:26 GMT',
+ 'Location' => 'http://www.w3.org/pub/WWW/People.html',
+ 'Pragma' => 'no-cache',
+ 'Proxy-Authenticate' => 'Basic',
+ 'Retry-After' => '120',
+ 'Server' => 'Apache/1.3.27 (Unix) (Red-Hat/Linux)',
+ 'Set-Cookie' => 'UserID=JohnDoe; Max-Age=3600; Version=1',
+ 'Trailer' => 'Max-Forwards',
+ 'Transfer-Encoding' => 'chunked',
+ 'Vary' => '*',
+ 'Via' => '1.0 fred, 1.1 nowhere.com (Apache/1.1)',
+ 'Warning' => '199 Miscellaneous warning',
+ 'WWW-Authenticate' => 'Basic'
+ )), 'body');
+ }
+
+ public function tearDown()
+ {
+ unset($this->response);
+ }
+
+ public function testConstructor()
+ {
+ $params = new Collection();
+ $body = EntityBody::factory('');
+ $response = new Response(200, $params, $body);
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertEquals($body, $response->getBody());
+ $this->assertEquals('OK', $response->getReasonPhrase());
+ $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", $response->getRawHeaders());
+
+ // Make sure Content-Length is set automatically
+ $response = new Response(200, $params);
+ $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", $response->getRawHeaders());
+
+ // Pass bodies to the response
+ $response = new Response(200, null, 'data');
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody());
+ $response = new Response(200, null, EntityBody::factory('data'));
+ $this->assertInstanceOf('Guzzle\\Http\\EntityBody', $response->getBody());
+ $this->assertEquals('data', $response->getBody(true));
+ $response = new Response(200, null, '0');
+ $this->assertSame('0', $response->getBody(true), 'getBody(true) should return "0" if response body is "0".');
+
+ // Make sure the proper exception is thrown
+ try {
+ //$response = new Response(200, null, array('foo' => 'bar'));
+ //$this->fail('Response did not throw exception when passing invalid body');
+ } catch (HttpException $e) {
+ }
+
+ // Ensure custom codes can be set
+ $response = new Response(2);
+ $this->assertEquals(2, $response->getStatusCode());
+ $this->assertEquals('', $response->getReasonPhrase());
+
+ // Make sure the proper exception is thrown when sending invalid headers
+ try {
+ $response = new Response(200, 'adidas');
+ $this->fail('Response did not throw exception when passing invalid $headers');
+ } catch (BadResponseException $e) {
+ }
+ }
+
+ public function test__toString()
+ {
+ $response = new Response(200);
+ $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", (string) $response);
+
+ // Add another header
+ $response = new Response(200, array(
+ 'X-Test' => 'Guzzle'
+ ));
+ $this->assertEquals("HTTP/1.1 200 OK\r\nX-Test: Guzzle\r\n\r\n", (string) $response);
+
+ $response = new Response(200, array(
+ 'Content-Length' => 4
+ ), 'test');
+ $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", (string) $response);
+ }
+
+ public function testFactory()
+ {
+ $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest");
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertEquals('OK', $response->getReasonPhrase());
+ $this->assertEquals(4, (string) $response->getContentLength());
+ $this->assertEquals('test', $response->getBody(true));
+
+ // Make sure that automatic Content-Length works
+ $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest");
+ $this->assertEquals(4, (string) $response->getContentLength());
+ $this->assertEquals('test', $response->getBody(true));
+ }
+
+ public function testFactoryCanCreateHeadResponses()
+ {
+ $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n");
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertEquals('OK', $response->getReasonPhrase());
+ $this->assertEquals(4, (string) $response->getContentLength());
+ $this->assertEquals('', $response->getBody(true));
+ }
+
+ public function testFactoryRequiresMessage()
+ {
+ $this->assertFalse(Response::fromMessage(''));
+ }
+
+ public function testGetBody()
+ {
+ $body = EntityBody::factory('');
+ $response = new Response(403, new Collection(), $body);
+ $this->assertEquals($body, $response->getBody());
+ $response->setBody('foo');
+ $this->assertEquals('foo', $response->getBody(true));
+ }
+
+ public function testManagesStatusCode()
+ {
+ $response = new Response(403);
+ $this->assertEquals(403, $response->getStatusCode());
+ }
+
+ public function testGetMessage()
+ {
+ $response = new Response(200, new Collection(array(
+ 'Content-Length' => 4
+ )), 'body');
+
+ $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nbody", $response->getMessage());
+ }
+
+ public function testGetRawHeaders()
+ {
+ $response = new Response(200, new Collection(array(
+ 'Keep-Alive' => 155,
+ 'User-Agent' => 'Guzzle',
+ 'Content-Length' => 4
+ )), 'body');
+
+ $this->assertEquals("HTTP/1.1 200 OK\r\nKeep-Alive: 155\r\nUser-Agent: Guzzle\r\nContent-Length: 4\r\n\r\n", $response->getRawHeaders());
+ }
+
+ public function testHandlesStatusAndStatusCodes()
+ {
+ $response = new Response(200, new Collection(), 'body');
+ $this->assertEquals('OK', $response->getReasonPhrase());
+
+ $this->assertSame($response, $response->setStatus(204));
+ $this->assertEquals('No Content', $response->getReasonPhrase());
+ $this->assertEquals(204, $response->getStatusCode());
+
+ $this->assertSame($response, $response->setStatus(204, 'Testing!'));
+ $this->assertEquals('Testing!', $response->getReasonPhrase());
+ $this->assertEquals(204, $response->getStatusCode());
+
+ $response->setStatus(2000);
+ $this->assertEquals(2000, $response->getStatusCode());
+ $this->assertEquals('', $response->getReasonPhrase());
+
+ $response->setStatus(200, 'Foo');
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertEquals('Foo', $response->getReasonPhrase());
+ }
+
+ public function testIsClientError()
+ {
+ $response = new Response(403);
+ $this->assertTrue($response->isClientError());
+ $response = new Response(200);
+ $this->assertFalse($response->isClientError());
+ }
+
+ public function testIsError()
+ {
+ $response = new Response(403);
+ $this->assertTrue($response->isError());
+ $response = new Response(200);
+ $this->assertFalse($response->isError());
+ $response = new Response(500);
+ $this->assertTrue($response->isError());
+ }
+
+ public function testIsInformational()
+ {
+ $response = new Response(100);
+ $this->assertTrue($response->isInformational());
+ $response = new Response(200);
+ $this->assertFalse($response->isInformational());
+ }
+
+ public function testIsRedirect()
+ {
+ $response = new Response(301);
+ $this->assertTrue($response->isRedirect());
+ $response = new Response(200);
+ $this->assertFalse($response->isRedirect());
+ }
+
+ public function testIsServerError()
+ {
+ $response = new Response(500);
+ $this->assertTrue($response->isServerError());
+ $response = new Response(400);
+ $this->assertFalse($response->isServerError());
+ }
+
+ public function testIsSuccessful()
+ {
+ $response = new Response(200);
+ $this->assertTrue($response->isSuccessful());
+ $response = new Response(403);
+ $this->assertFalse($response->isSuccessful());
+ }
+
+ public function testGetAcceptRanges()
+ {
+ $this->assertEquals('bytes', $this->response->getAcceptRanges());
+ }
+
+ public function testCalculatesAge()
+ {
+ $this->assertEquals(12, $this->response->calculateAge());
+
+ $this->response->removeHeader('Age');
+ $this->response->removeHeader('Date');
+ $this->assertNull($this->response->calculateAge());
+
+ $this->response->setHeader('Date', gmdate(ClientInterface::HTTP_DATE, strtotime('-1 minute')));
+ // If the test runs slowly, still pass with a +5 second allowance
+ $this->assertTrue($this->response->getAge() - 60 <= 5);
+ }
+
+ public function testGetAllow()
+ {
+ $this->assertEquals('GET, HEAD', $this->response->getAllow());
+ }
+
+ public function testGetCacheControl()
+ {
+ $this->assertEquals('no-cache', $this->response->getCacheControl());
+ }
+
+ public function testGetContentEncoding()
+ {
+ $this->assertEquals('gzip', $this->response->getContentEncoding());
+ }
+
+ public function testGetContentLanguage()
+ {
+ $this->assertEquals('da', $this->response->getContentLanguage());
+ }
+
+ public function testGetContentLength()
+ {
+ $this->assertEquals('348', $this->response->getContentLength());
+ }
+
+ public function testGetContentLocation()
+ {
+ $this->assertEquals('/index.htm', $this->response->getContentLocation());
+ }
+
+ public function testGetContentDisposition()
+ {
+ $this->assertEquals('attachment; filename=fname.ext', $this->response->getContentDisposition());
+ }
+
+ public function testGetContentMd5()
+ {
+ $this->assertEquals('Q2hlY2sgSW50ZWdyaXR5IQ==', $this->response->getContentMd5());
+ }
+
+ public function testGetContentRange()
+ {
+ $this->assertEquals('bytes 21010-47021/47022', $this->response->getContentRange());
+ }
+
+ public function testGetContentType()
+ {
+ $this->assertEquals('text/html; charset=utf-8', $this->response->getContentType());
+ }
+
+ public function testGetDate()
+ {
+ $this->assertEquals('Tue, 15 Nov 1994 08:12:31 GMT', $this->response->getDate());
+ }
+
+ public function testGetEtag()
+ {
+ $this->assertEquals('737060cd8c284d8af7ad3082f209582d', $this->response->getEtag());
+ }
+
+ public function testGetExpires()
+ {
+ $this->assertEquals('Thu, 01 Dec 1994 16:00:00 GMT', $this->response->getExpires());
+ }
+
+ public function testGetLastModified()
+ {
+ $this->assertEquals('Tue, 15 Nov 1994 12:45:26 GMT', $this->response->getLastModified());
+ }
+
+ public function testGetLocation()
+ {
+ $this->assertEquals('http://www.w3.org/pub/WWW/People.html', $this->response->getLocation());
+ }
+
+ public function testGetPragma()
+ {
+ $this->assertEquals('no-cache', $this->response->getPragma());
+ }
+
+ public function testGetProxyAuthenticate()
+ {
+ $this->assertEquals('Basic', $this->response->getProxyAuthenticate());
+ }
+
+ public function testGetServer()
+ {
+ $this->assertEquals('Apache/1.3.27 (Unix) (Red-Hat/Linux)', $this->response->getServer());
+ }
+
+ public function testGetSetCookie()
+ {
+ $this->assertEquals('UserID=JohnDoe; Max-Age=3600; Version=1', $this->response->getSetCookie());
+ }
+
+ public function testGetMultipleSetCookie()
+ {
+ $this->response->addHeader('Set-Cookie', 'UserID=Mike; Max-Age=200');
+ $this->assertEquals(array(
+ 'UserID=JohnDoe; Max-Age=3600; Version=1',
+ 'UserID=Mike; Max-Age=200',
+ ), $this->response->getHeader('Set-Cookie')->toArray());
+ }
+
+ public function testGetSetCookieNormalizesHeaders()
+ {
+ $this->response->addHeaders(array(
+ 'Set-Cooke' => 'boo',
+ 'set-cookie' => 'foo'
+ ));
+
+ $this->assertEquals(array(
+ 'UserID=JohnDoe; Max-Age=3600; Version=1',
+ 'foo'
+ ), $this->response->getHeader('Set-Cookie')->toArray());
+
+ $this->response->addHeaders(array(
+ 'set-cookie' => 'fubu'
+ ));
+ $this->assertEquals(
+ array('UserID=JohnDoe; Max-Age=3600; Version=1', 'foo', 'fubu'),
+ $this->response->getHeader('Set-Cookie')->toArray()
+ );
+ }
+
+ public function testGetTrailer()
+ {
+ $this->assertEquals('Max-Forwards', $this->response->getTrailer());
+ }
+
+ public function testGetTransferEncoding()
+ {
+ $this->assertEquals('chunked', $this->response->getTransferEncoding());
+ }
+
+ public function testGetVary()
+ {
+ $this->assertEquals('*', $this->response->getVary());
+ }
+
+ public function testReturnsViaHeader()
+ {
+ $this->assertEquals('1.0 fred, 1.1 nowhere.com (Apache/1.1)', $this->response->getVia());
+ }
+ public function testGetWarning()
+ {
+ $this->assertEquals('199 Miscellaneous warning', $this->response->getWarning());
+ }
+
+ public function testReturnsWwwAuthenticateHeader()
+ {
+ $this->assertEquals('Basic', $this->response->getWwwAuthenticate());
+ }
+
+ public function testReturnsConnectionHeader()
+ {
+ $this->assertEquals(null, $this->response->getConnection());
+ $this->response->setHeader('Connection', 'close');
+ $this->assertEquals('close', $this->response->getConnection());
+ }
+
+ public function testReturnsHeaders()
+ {
+ $this->assertEquals('Basic', $this->response->getHeader('WWW-Authenticate', null, true));
+ $this->assertEquals('chunked', $this->response->getHeader('Transfer-Encoding', null, false));
+ }
+
+ public function testHasTransferInfo()
+ {
+ $stats = array (
+ 'url' => 'http://www.google.com/',
+ 'content_type' => 'text/html; charset=ISO-8859-1',
+ 'http_code' => 200,
+ 'header_size' => 606,
+ 'request_size' => 53,
+ 'filetime' => -1,
+ 'ssl_verify_result' => 0,
+ 'redirect_count' => 0,
+ 'total_time' => 0.093284,
+ 'namelookup_time' => 0.001349,
+ 'connect_time' => 0.01635,
+ 'pretransfer_time' => 0.016358,
+ 'size_upload' => 0,
+ 'size_download' => 10330,
+ 'speed_download' => 110737,
+ 'speed_upload' => 0,
+ 'download_content_length' => -1,
+ 'upload_content_length' => 0,
+ 'starttransfer_time' => 0.07066,
+ 'redirect_time' => 0,
+ );
+
+ // Uninitialized state
+ $this->assertNull($this->response->getInfo('url'));
+ $this->assertEquals(array(), $this->response->getInfo());
+
+ // Set the stats
+ $this->response->setInfo($stats);
+ $this->assertEquals($stats, $this->response->getInfo());
+ $this->assertEquals(606, $this->response->getInfo('header_size'));
+ $this->assertNull($this->response->getInfo('does_not_exist'));
+ }
+
+ /**
+ * @return Response
+ */
+ private function getResponse($code, array $headers = null, EntityBody $body = null)
+ {
+ return new Response($code, $headers, $body);
+ }
+
+ public function testDeterminesIfItCanBeCached()
+ {
+ $this->assertTrue($this->getResponse(200)->canCache());
+ $this->assertTrue($this->getResponse(410)->canCache());
+ $this->assertFalse($this->getResponse(404)->canCache());
+ $this->assertTrue($this->getResponse(200, array(
+ 'Cache-Control' => 'public'
+ ))->canCache());
+
+ // This has the no-store directive
+ $this->assertFalse($this->getResponse(200, array(
+ 'Cache-Control' => 'private, no-store'
+ ))->canCache());
+
+ // The body cannot be read, so it cannot be cached
+ $tmp = tempnam('/tmp', 'not-readable');
+ $resource = fopen($tmp, 'w');
+ $this->assertFalse($this->getResponse(200, array(
+ 'Transfer-Encoding' => 'chunked'
+ ), EntityBody::factory($resource, 10))->canCache());
+ unlink($tmp);
+
+ // The body is 0 length, cannot be read, so it can be cached
+ $tmp = tempnam('/tmp', 'not-readable');
+ $resource = fopen($tmp, 'w');
+ $this->assertTrue($this->getResponse(200, array(array(
+ 'Content-Length' => 0
+ )), EntityBody::factory($resource, 0))->canCache());
+ unlink($tmp);
+ }
+
+ public function testDeterminesResponseMaxAge()
+ {
+ $this->assertEquals(null, $this->getResponse(200)->getMaxAge());
+
+ // Uses the response's s-maxage
+ $this->assertEquals(140, $this->getResponse(200, array(
+ 'Cache-Control' => 's-maxage=140'
+ ))->getMaxAge());
+
+ // Uses the response's max-age
+ $this->assertEquals(120, $this->getResponse(200, array(
+ 'Cache-Control' => 'max-age=120'
+ ))->getMaxAge());
+
+ // Uses the response's max-age
+ $this->assertEquals(120, $this->getResponse(200, array(
+ 'Cache-Control' => 'max-age=120',
+ 'Expires' => gmdate(ClientInterface::HTTP_DATE, strtotime('+1 day'))
+ ))->getMaxAge());
+
+ // Uses the Expires date
+ $this->assertGreaterThanOrEqual(82400, $this->getResponse(200, array(
+ 'Expires' => gmdate(ClientInterface::HTTP_DATE, strtotime('+1 day'))
+ ))->getMaxAge());
+
+ // Uses the Expires date
+ $this->assertGreaterThanOrEqual(82400, $this->getResponse(200, array(
+ 'Expires' => gmdate(ClientInterface::HTTP_DATE, strtotime('+1 day'))
+ ))->getMaxAge());
+ }
+
+ public function testDeterminesIfItCanValidate()
+ {
+ $response = new Response(200);
+ $this->assertFalse($response->canValidate());
+ $response->setHeader('ETag', '123');
+ $this->assertTrue($response->canValidate());
+ $response->removeHeader('ETag');
+ $this->assertFalse($response->canValidate());
+ $response->setHeader('Last-Modified', '123');
+ $this->assertTrue($response->canValidate());
+ }
+
+ public function testCalculatesFreshness()
+ {
+ $response = new Response(200);
+ $this->assertNull($response->isFresh());
+ $this->assertNull($response->getFreshness());
+
+ $response->setHeader('Cache-Control', 'max-age=120');
+ $response->setHeader('Age', 100);
+ $this->assertEquals(20, $response->getFreshness());
+ $this->assertTrue($response->isFresh());
+
+ $response->setHeader('Age', 120);
+ $this->assertEquals(0, $response->getFreshness());
+ $this->assertTrue($response->isFresh());
+
+ $response->setHeader('Age', 150);
+ $this->assertEquals(-30, $response->getFreshness());
+ $this->assertFalse($response->isFresh());
+ }
+
+ public function testHandlesProtocols()
+ {
+ $this->assertSame($this->response, $this->response->setProtocol('HTTP', '1.0'));
+ $this->assertEquals('HTTP', $this->response->getProtocol());
+ $this->assertEquals('1.0', $this->response->getProtocolVersion());
+ }
+
+ public function testComparesContentType()
+ {
+ $response = new Response(200, array(
+ 'Content-Type' => 'text/html; charset=ISO-8859-4'
+ ));
+
+ $this->assertTrue($response->isContentType('text/html'));
+ $this->assertTrue($response->isContentType('TExT/html'));
+ $this->assertTrue($response->isContentType('charset=ISO-8859-4'));
+ $this->assertFalse($response->isContentType('application/xml'));
+ }
+
+ public function testResponseDeterminesIfMethodIsAllowedBaseOnAllowHeader()
+ {
+ $response = new Response(200, array(
+ 'Allow' => 'OPTIONS, POST, deletE,GET'
+ ));
+
+ $this->assertTrue($response->isMethodAllowed('get'));
+ $this->assertTrue($response->isMethodAllowed('GET'));
+ $this->assertTrue($response->isMethodAllowed('options'));
+ $this->assertTrue($response->isMethodAllowed('post'));
+ $this->assertTrue($response->isMethodAllowed('Delete'));
+ $this->assertFalse($response->isMethodAllowed('put'));
+ $this->assertFalse($response->isMethodAllowed('PUT'));
+
+ $response = new Response(200);
+ $this->assertFalse($response->isMethodAllowed('get'));
+ }
+
+ public function testParsesJsonResponses()
+ {
+ $response = new Response(200, array(), '{"foo": "bar"}');
+ $this->assertEquals(array('foo' => 'bar'), $response->json());
+ // Return array when null is a service response
+ $response = new Response(200);
+ $this->assertEquals(array(), $response->json());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ * @expectedExceptionMessage Unable to parse response body into JSON: 4
+ */
+ public function testThrowsExceptionWhenFailsToParseJsonResponse()
+ {
+ $response = new Response(200, array(), '{"foo": "');
+ $response->json();
+ }
+
+ public function testParsesXmlResponses()
+ {
+ $response = new Response(200, array(), 'bar ');
+ $this->assertEquals('bar', (string) $response->xml()->foo);
+ // Always return a SimpleXMLElement from the xml method
+ $response = new Response(200);
+ $this->assertEmpty((string) $response->xml()->foo);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ * @expectedExceptionMessage Unable to parse response body into XML: String could not be parsed as XML
+ */
+ public function testThrowsExceptionWhenFailsToParseXmlResponse()
+ {
+ $response = new Response(200, array(), 'xml();
+ }
+
+ public function testResponseIsSerializable()
+ {
+ $response = new Response(200, array('Foo' => 'bar'), 'test');
+ $r = unserialize(serialize($response));
+ $this->assertEquals(200, $r->getStatusCode());
+ $this->assertEquals('bar', (string) $r->getHeader('Foo'));
+ $this->assertEquals('test', (string) $r->getBody());
+ }
+
+ public function testPreventsComplexExternalEntities()
+ {
+ $xml = ']>&test; ';
+ $response = new Response(200, array(), $xml);
+
+ $oldCwd = getcwd();
+ chdir(__DIR__);
+ try {
+ $xml = $response->xml();
+ chdir($oldCwd);
+ $this->markTestIncomplete('Did not throw the expected exception! XML resolved as: ' . $xml->asXML());
+ } catch (\Exception $e) {
+ chdir($oldCwd);
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php
new file mode 100755
index 0000000..7228453
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/MimetypesTest.php
@@ -0,0 +1,31 @@
+assertEquals('text/x-php', Mimetypes::getInstance()->fromExtension('php'));
+ }
+
+ public function testGetsFromFilename()
+ {
+ $this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(__FILE__));
+ }
+
+ public function testGetsFromCaseInsensitiveFilename()
+ {
+ $this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(strtoupper(__FILE__)));
+ }
+
+ public function testReturnsNullWhenNoMatchFound()
+ {
+ $this->assertNull(Mimetypes::getInstance()->fromExtension('foobar'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php
new file mode 100755
index 0000000..549d3ed
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/CommaAggregatorTest.php
@@ -0,0 +1,30 @@
+aggregate($key, $value, $query);
+ $this->assertEquals(array('test%20123' => 'foo%20123,baz,bar'), $result);
+ }
+
+ public function testEncodes()
+ {
+ $query = new QueryString();
+ $query->useUrlEncoding(false);
+ $a = new Ag();
+ $key = 'test 123';
+ $value = array('foo 123', 'baz', 'bar');
+ $result = $a->aggregate($key, $value, $query);
+ $this->assertEquals(array('test 123' => 'foo 123,baz,bar'), $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php
new file mode 100755
index 0000000..6a4d9d9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/DuplicateAggregatorTest.php
@@ -0,0 +1,30 @@
+aggregate($key, $value, $query);
+ $this->assertEquals(array('facet%201' => array('size%20a', 'width%20b')), $result);
+ }
+
+ public function testEncodes()
+ {
+ $query = new QueryString();
+ $query->useUrlEncoding(false);
+ $a = new Ag();
+ $key = 'facet 1';
+ $value = array('size a', 'width b');
+ $result = $a->aggregate($key, $value, $query);
+ $this->assertEquals(array('facet 1' => array('size a', 'width b')), $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php
new file mode 100755
index 0000000..1e7f0c2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryAggregator/PhpAggregatorTest.php
@@ -0,0 +1,32 @@
+useUrlEncoding(false);
+ $a = new Ag();
+ $key = 't';
+ $value = array(
+ 'v1' => 'a',
+ 'v2' => 'b',
+ 'v3' => array(
+ 'v4' => 'c',
+ 'v5' => 'd',
+ )
+ );
+ $result = $a->aggregate($key, $value, $query);
+ $this->assertEquals(array(
+ 't[v1]' => 'a',
+ 't[v2]' => 'b',
+ 't[v3][v4]' => 'c',
+ 't[v3][v5]' => 'd',
+ ), $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php
new file mode 100755
index 0000000..948db44
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/QueryStringTest.php
@@ -0,0 +1,233 @@
+q = new QueryString();
+ }
+
+ public function testGetFieldSeparator()
+ {
+ $this->assertEquals('&', $this->q->getFieldSeparator());
+ }
+
+ public function testGetValueSeparator()
+ {
+ $this->assertEquals('=', $this->q->getValueSeparator());
+ }
+
+ public function testIsUrlEncoding()
+ {
+ $this->assertEquals('RFC 3986', $this->q->getUrlEncoding());
+ $this->assertTrue($this->q->isUrlEncoding());
+ $this->assertEquals('foo%20bar', $this->q->encodeValue('foo bar'));
+
+ $this->q->useUrlEncoding(QueryString::FORM_URLENCODED);
+ $this->assertTrue($this->q->isUrlEncoding());
+ $this->assertEquals(QueryString::FORM_URLENCODED, $this->q->getUrlEncoding());
+ $this->assertEquals('foo+bar', $this->q->encodeValue('foo bar'));
+
+ $this->assertSame($this->q, $this->q->useUrlEncoding(false));
+ $this->assertFalse($this->q->isUrlEncoding());
+ $this->assertFalse($this->q->isUrlEncoding());
+ }
+
+ public function testSetFieldSeparator()
+ {
+ $this->assertEquals($this->q, $this->q->setFieldSeparator('/'));
+ $this->assertEquals('/', $this->q->getFieldSeparator());
+ }
+
+ public function testSetValueSeparator()
+ {
+ $this->assertEquals($this->q, $this->q->setValueSeparator('/'));
+ $this->assertEquals('/', $this->q->getValueSeparator());
+ }
+
+ public function testUrlEncode()
+ {
+ $params = array(
+ 'test' => 'value',
+ 'test 2' => 'this is a test?',
+ 'test3' => array('v1', 'v2', 'v3'),
+ 'ሴ' => 'bar'
+ );
+ $encoded = array(
+ 'test' => 'value',
+ 'test%202' => rawurlencode('this is a test?'),
+ 'test3%5B0%5D' => 'v1',
+ 'test3%5B1%5D' => 'v2',
+ 'test3%5B2%5D' => 'v3',
+ '%E1%88%B4' => 'bar'
+ );
+ $this->q->replace($params);
+ $this->assertEquals($encoded, $this->q->urlEncode());
+
+ // Disable encoding
+ $testData = array('test 2' => 'this is a test');
+ $this->q->replace($testData);
+ $this->q->useUrlEncoding(false);
+ $this->assertEquals($testData, $this->q->urlEncode());
+ }
+
+ public function testToString()
+ {
+ // Check with no parameters
+ $this->assertEquals('', $this->q->__toString());
+
+ $params = array(
+ 'test' => 'value',
+ 'test 2' => 'this is a test?',
+ 'test3' => array('v1', 'v2', 'v3'),
+ 'test4' => null,
+ );
+ $this->q->replace($params);
+ $this->assertEquals('test=value&test%202=this%20is%20a%20test%3F&test3%5B0%5D=v1&test3%5B1%5D=v2&test3%5B2%5D=v3&test4', $this->q->__toString());
+ $this->q->useUrlEncoding(false);
+ $this->assertEquals('test=value&test 2=this is a test?&test3[0]=v1&test3[1]=v2&test3[2]=v3&test4', $this->q->__toString());
+
+ // Use an alternative aggregator
+ $this->q->setAggregator(new CommaAggregator());
+ $this->assertEquals('test=value&test 2=this is a test?&test3=v1,v2,v3&test4', $this->q->__toString());
+ }
+
+ public function testAllowsMultipleValuesPerKey()
+ {
+ $q = new QueryString();
+ $q->add('facet', 'size');
+ $q->add('facet', 'width');
+ $q->add('facet.field', 'foo');
+ // Use the duplicate aggregator
+ $q->setAggregator(new DuplicateAggregator());
+ $this->assertEquals('facet=size&facet=width&facet.field=foo', $q->__toString());
+ }
+
+ public function testAllowsNestedQueryData()
+ {
+ $this->q->replace(array(
+ 'test' => 'value',
+ 't' => array(
+ 'v1' => 'a',
+ 'v2' => 'b',
+ 'v3' => array(
+ 'v4' => 'c',
+ 'v5' => 'd',
+ )
+ )
+ ));
+
+ $this->q->useUrlEncoding(false);
+ $this->assertEquals('test=value&t[v1]=a&t[v2]=b&t[v3][v4]=c&t[v3][v5]=d', $this->q->__toString());
+ }
+
+ public function parseQueryProvider()
+ {
+ return array(
+ // Ensure that multiple query string values are allowed per value
+ array('q=a&q=b', array('q' => array('a', 'b'))),
+ // Ensure that PHP array style query string values are parsed
+ array('q[]=a&q[]=b', array('q' => array('a', 'b'))),
+ // Ensure that a single PHP array style query string value is parsed into an array
+ array('q[]=a', array('q' => array('a'))),
+ // Ensure that decimals are allowed in query strings
+ array('q.a=a&q.b=b', array(
+ 'q.a' => 'a',
+ 'q.b' => 'b'
+ )),
+ // Ensure that query string values are percent decoded
+ array('q%20a=a%20b', array('q a' => 'a b')),
+ // Ensure null values can be added
+ array('q&a', array('q' => false, 'a' => false)),
+ );
+ }
+
+ /**
+ * @dataProvider parseQueryProvider
+ */
+ public function testParsesQueryStrings($query, $data)
+ {
+ $query = QueryString::fromString($query);
+ $this->assertEquals($data, $query->getAll());
+ }
+
+ public function testProperlyDealsWithDuplicateQueryStringValues()
+ {
+ $query = QueryString::fromString('foo=a&foo=b&?µ=c');
+ $this->assertEquals(array('a', 'b'), $query->get('foo'));
+ $this->assertEquals('c', $query->get('?µ'));
+ }
+
+ public function testAllowsBlankQueryStringValues()
+ {
+ $query = QueryString::fromString('foo');
+ $this->assertEquals('foo', (string) $query);
+ $query->set('foo', QueryString::BLANK);
+ $this->assertEquals('foo', (string) $query);
+ }
+
+ public function testAllowsFalsyQueryStringValues()
+ {
+ $query = QueryString::fromString('0');
+ $this->assertEquals('0', (string) $query);
+ $query->set('0', QueryString::BLANK);
+ $this->assertSame('0', (string) $query);
+ }
+
+ public function testFromStringIgnoresQuestionMark()
+ {
+ $query = QueryString::fromString('foo=baz&bar=boo');
+ $this->assertEquals('foo=baz&bar=boo', (string) $query);
+ }
+
+ public function testConvertsPlusSymbolsToSpaces()
+ {
+ $query = QueryString::fromString('var=foo+bar');
+ $this->assertEquals('foo bar', $query->get('var'));
+ }
+
+ public function testFromStringDoesntMangleZeroes()
+ {
+ $query = QueryString::fromString('var=0');
+ $this->assertSame('0', $query->get('var'));
+ }
+
+ public function testAllowsZeroValues()
+ {
+ $query = new QueryString(array(
+ 'foo' => 0,
+ 'baz' => '0',
+ 'bar' => null,
+ 'boo' => false,
+ 'bam' => ''
+ ));
+ $this->assertEquals('foo=0&baz=0&bar&boo&bam=', (string) $query);
+ }
+
+ public function testFromStringDoesntStripTrailingEquals()
+ {
+ $query = QueryString::fromString('data=mF0b3IiLCJUZWFtIERldiJdfX0=');
+ $this->assertEquals('mF0b3IiLCJUZWFtIERldiJdfX0=', $query->get('data'));
+ }
+
+ public function testGuessesIfDuplicateAggregatorShouldBeUsed()
+ {
+ $query = QueryString::fromString('test=a&test=b');
+ $this->assertEquals('test=a&test=b', (string) $query);
+ }
+
+ public function testGuessesIfDuplicateAggregatorShouldBeUsedAndChecksForPhpStyle()
+ {
+ $query = QueryString::fromString('test[]=a&test[]=b');
+ $this->assertEquals('test%5B0%5D=a&test%5B1%5D=b', (string) $query);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php
new file mode 100755
index 0000000..6bb3fed
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/ReadLimitEntityBodyTest.php
@@ -0,0 +1,81 @@
+decorated = EntityBody::factory(fopen(__FILE__, 'r'));
+ $this->body = new ReadLimitEntityBody($this->decorated, 10, 3);
+ }
+
+ public function testReturnsSubsetWhenCastToString()
+ {
+ $body = EntityBody::factory('foo_baz_bar');
+ $limited = new ReadLimitEntityBody($body, 3, 4);
+ $this->assertEquals('baz', (string) $limited);
+ }
+
+ public function testReturnsSubsetOfEmptyBodyWhenCastToString()
+ {
+ $body = EntityBody::factory('');
+ $limited = new ReadLimitEntityBody($body, 0, 10);
+ $this->assertEquals('', (string) $limited);
+ }
+
+ public function testSeeksWhenConstructed()
+ {
+ $this->assertEquals(3, $this->body->ftell());
+ }
+
+ public function testAllowsBoundedSeek()
+ {
+ $this->body->seek(100);
+ $this->assertEquals(13, $this->body->ftell());
+ $this->body->seek(0);
+ $this->assertEquals(3, $this->body->ftell());
+ $this->assertEquals(false, $this->body->seek(1000, SEEK_END));
+ }
+
+ public function testReadsOnlySubsetOfData()
+ {
+ $data = $this->body->read(100);
+ $this->assertEquals(10, strlen($data));
+ $this->assertFalse($this->body->read(1000));
+
+ $this->body->setOffset(10);
+ $newData = $this->body->read(100);
+ $this->assertEquals(10, strlen($newData));
+ $this->assertNotSame($data, $newData);
+ }
+
+ public function testClaimsConsumedWhenReadLimitIsReached()
+ {
+ $this->assertFalse($this->body->isConsumed());
+ $this->body->read(1000);
+ $this->assertTrue($this->body->isConsumed());
+ }
+
+ public function testContentLengthIsBounded()
+ {
+ $this->assertEquals(10, $this->body->getContentLength());
+ }
+
+ public function testContentMd5IsBasedOnSubsection()
+ {
+ $this->assertNotSame($this->body->getContentMd5(), $this->decorated->getContentMd5());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php
new file mode 100755
index 0000000..886236d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/RedirectPluginTest.php
@@ -0,0 +1,277 @@
+getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ // Create a client that uses the default redirect behavior
+ $client = new Client($this->getServer()->getUrl());
+ $history = new HistoryPlugin();
+ $client->addSubscriber($history);
+
+ $request = $client->get('/foo');
+ $response = $request->send();
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertContains('/redirect2', $response->getEffectiveUrl());
+
+ // Ensure that two requests were sent
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('/foo', $requests[0]->getResource());
+ $this->assertEquals('GET', $requests[0]->getMethod());
+ $this->assertEquals('/redirect1', $requests[1]->getResource());
+ $this->assertEquals('GET', $requests[1]->getMethod());
+ $this->assertEquals('/redirect2', $requests[2]->getResource());
+ $this->assertEquals('GET', $requests[2]->getMethod());
+
+ // Ensure that the redirect count was incremented
+ $this->assertEquals(2, $request->getParams()->get(RedirectPlugin::REDIRECT_COUNT));
+ $this->assertCount(3, $history);
+ $requestHistory = $history->getAll();
+
+ $this->assertEquals(301, $requestHistory[0]['response']->getStatusCode());
+ $this->assertEquals('/redirect1', (string) $requestHistory[0]['response']->getHeader('Location'));
+ $this->assertEquals(301, $requestHistory[1]['response']->getStatusCode());
+ $this->assertEquals('/redirect2', (string) $requestHistory[1]['response']->getHeader('Location'));
+ $this->assertEquals(200, $requestHistory[2]['response']->getStatusCode());
+ }
+
+ public function testCanLimitNumberOfRedirects()
+ {
+ // Flush the server and queue up a redirect followed by a successful response
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect3\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect4\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect5\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect6\r\nContent-Length: 0\r\n\r\n"
+ ));
+
+ try {
+ $client = new Client($this->getServer()->getUrl());
+ $client->get('/foo')->send();
+ $this->fail('Did not throw expected exception');
+ } catch (TooManyRedirectsException $e) {
+ $this->assertContains(
+ "5 redirects were issued for this request:\nGET /foo HTTP/1.1\r\n",
+ $e->getMessage()
+ );
+ }
+ }
+
+ public function testDefaultBehaviorIsToRedirectWithGetForEntityEnclosingRequests()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $client->post('/foo', array('X-Baz' => 'bar'), 'testing')->send();
+
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('POST', $requests[0]->getMethod());
+ $this->assertEquals('GET', $requests[1]->getMethod());
+ $this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz'));
+ $this->assertEquals('GET', $requests[2]->getMethod());
+ }
+
+ public function testCanRedirectWithStrictRfcCompliance()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->post('/foo', array('X-Baz' => 'bar'), 'testing');
+ $request->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, true);
+ $request->send();
+
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('POST', $requests[0]->getMethod());
+ $this->assertEquals('POST', $requests[1]->getMethod());
+ $this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz'));
+ $this->assertEquals('POST', $requests[2]->getMethod());
+ }
+
+ public function testRedirect303WithGet()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 303 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->post('/foo');
+ $request->send();
+
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('POST', $requests[0]->getMethod());
+ $this->assertEquals('GET', $requests[1]->getMethod());
+ }
+
+ public function testRedirect303WithGetWithStrictRfcCompliance()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 303 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->post('/foo');
+ $request->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, true);
+ $request->send();
+
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('POST', $requests[0]->getMethod());
+ $this->assertEquals('GET', $requests[1]->getMethod());
+ }
+
+ public function testRewindsStreamWhenRedirectingIfNeeded()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put();
+ $request->configureRedirects(true);
+ $body = EntityBody::factory('foo');
+ $body->read(1);
+ $request->setBody($body);
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('foo', (string) $requests[0]->getBody());
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\CouldNotRewindStreamException
+ */
+ public function testThrowsExceptionWhenStreamCannotBeRewound()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n"
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put();
+ $request->configureRedirects(true);
+ $body = EntityBody::factory(fopen($this->getServer()->getUrl(), 'r'));
+ $body->read(1);
+ $request->setBody($body)->send();
+ }
+
+ public function testRedirectsCanBeDisabledPerRequest()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array("HTTP/1.1 301 Foo\r\nLocation: /foo\r\nContent-Length: 0\r\n\r\n"));
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->put();
+ $request->configureRedirects(false, 0);
+ $this->assertEquals(301, $request->send()->getStatusCode());
+ }
+
+ public function testCanRedirectWithNoLeadingSlashAndQuery()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: redirect?foo=bar\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get('?foo=bar');
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals($this->getServer()->getUrl() . '?foo=bar', $requests[0]->getUrl());
+ $this->assertEquals($this->getServer()->getUrl() . 'redirect?foo=bar', $requests[1]->getUrl());
+ // Ensure that the history on the actual request is correct
+ $this->assertEquals($this->getServer()->getUrl() . '?foo=bar', $request->getUrl());
+ }
+
+ public function testRedirectWithStrictRfc386Compliance()
+ {
+ // Flush the server and queue up a redirect followed by a successful response
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: redirect\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get('/foo');
+ $request->send();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('/redirect', $requests[1]->getResource());
+ }
+
+ public function testResetsHistoryEachSend()
+ {
+ // Flush the server and queue up a redirect followed by a successful response
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+
+ // Create a client that uses the default redirect behavior
+ $client = new Client($this->getServer()->getUrl());
+ $history = new HistoryPlugin();
+ $client->addSubscriber($history);
+
+ $request = $client->get('/foo');
+ $response = $request->send();
+ $this->assertEquals(3, count($history));
+ $this->assertTrue($request->getParams()->hasKey('redirect.count'));
+ $this->assertContains('/redirect2', $response->getEffectiveUrl());
+
+ $request->send();
+ $this->assertFalse($request->getParams()->hasKey('redirect.count'));
+ }
+
+ public function testHandlesRedirectsWithSpacesProperly()
+ {
+ // Flush the server and queue up a redirect followed by a successful response
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect 1\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->get('/foo');
+ $request->send();
+ $reqs = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('/redirect%201', $reqs[1]->getResource());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php
new file mode 100755
index 0000000..94eb59a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/Server.php
@@ -0,0 +1,191 @@
+port = $port ?: self::DEFAULT_PORT;
+ $this->client = new Client($this->getUrl());
+ register_shutdown_function(array($this, 'stop'));
+ }
+
+ /**
+ * Flush the received requests from the server
+ * @throws RuntimeException
+ */
+ public function flush()
+ {
+ $this->client->delete('guzzle-server/requests')->send();
+ }
+
+ /**
+ * Queue an array of responses or a single response on the server.
+ *
+ * Any currently queued responses will be overwritten. Subsequent requests
+ * on the server will return queued responses in FIFO order.
+ *
+ * @param array|Response $responses A single or array of Responses to queue
+ * @throws BadResponseException
+ */
+ public function enqueue($responses)
+ {
+ $data = array();
+ foreach ((array) $responses as $response) {
+
+ // Create the response object from a string
+ if (is_string($response)) {
+ $response = Response::fromMessage($response);
+ } elseif (!($response instanceof Response)) {
+ throw new BadResponseException('Responses must be strings or implement Response');
+ }
+
+ $data[] = array(
+ 'statusCode' => $response->getStatusCode(),
+ 'reasonPhrase' => $response->getReasonPhrase(),
+ 'headers' => $response->getHeaders()->toArray(),
+ 'body' => $response->getBody(true)
+ );
+ }
+
+ $request = $this->client->put('guzzle-server/responses', null, json_encode($data));
+ $request->send();
+ }
+
+ /**
+ * Check if the server is running
+ *
+ * @return bool
+ */
+ public function isRunning()
+ {
+ if ($this->running) {
+ return true;
+ }
+
+ try {
+ $this->client->get('guzzle-server/perf', array(), array('timeout' => 5))->send();
+ $this->running = true;
+ return true;
+ } catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Get the URL to the server
+ *
+ * @return string
+ */
+ public function getUrl()
+ {
+ return 'http://127.0.0.1:' . $this->getPort() . '/';
+ }
+
+ /**
+ * Get the port that the server is listening on
+ *
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * Get all of the received requests
+ *
+ * @param bool $hydrate Set to TRUE to turn the messages into
+ * actual {@see RequestInterface} objects. If $hydrate is FALSE,
+ * requests will be returned as strings.
+ *
+ * @return array
+ * @throws RuntimeException
+ */
+ public function getReceivedRequests($hydrate = false)
+ {
+ $response = $this->client->get('guzzle-server/requests')->send();
+ $data = array_filter(explode(self::REQUEST_DELIMITER, $response->getBody(true)));
+ if ($hydrate) {
+ $data = array_map(function($message) {
+ return RequestFactory::getInstance()->fromMessage($message);
+ }, $data);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Start running the node.js server in the background
+ */
+ public function start()
+ {
+ if (!$this->isRunning()) {
+ exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR
+ . 'server.js ' . $this->port
+ . ' >> /tmp/server.log 2>&1 &');
+ // Wait at most 5 seconds for the server the setup before
+ // proceeding.
+ $start = time();
+ while (!$this->isRunning() && time() - $start < 5);
+ if (!$this->running) {
+ throw new RuntimeException(
+ 'Unable to contact server.js. Have you installed node.js v0.5.0+? node must be in your path.'
+ );
+ }
+ }
+ }
+
+ /**
+ * Stop running the node.js server
+ */
+ public function stop()
+ {
+ if (!$this->isRunning()) {
+ return false;
+ }
+
+ $this->running = false;
+ $this->client->delete('guzzle-server')->send();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php
new file mode 100755
index 0000000..091314b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/StaticClientTest.php
@@ -0,0 +1,67 @@
+assertTrue(class_exists('FooBazBar'));
+ $this->assertSame($client, $this->readAttribute('Guzzle\Http\StaticClient', 'client'));
+ }
+
+ public function requestProvider()
+ {
+ return array_map(
+ function ($m) { return array($m); },
+ array('GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS')
+ );
+ }
+
+ /**
+ * @dataProvider requestProvider
+ */
+ public function testSendsRequests($method)
+ {
+ $mock = new MockPlugin(array(new Response(200)));
+ call_user_func('Guzzle\Http\StaticClient::' . $method, 'http://foo.com', array(
+ 'plugins' => array($mock)
+ ));
+ $requests = $mock->getReceivedRequests();
+ $this->assertCount(1, $requests);
+ $this->assertEquals($method, $requests[0]->getMethod());
+ }
+
+ public function testCanCreateStreamsUsingDefaultFactory()
+ {
+ $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"));
+ $stream = StaticClient::get($this->getServer()->getUrl(), array('stream' => true));
+ $this->assertInstanceOf('Guzzle\Stream\StreamInterface', $stream);
+ $this->assertEquals('test', (string) $stream);
+ }
+
+ public function testCanCreateStreamsUsingCustomFactory()
+ {
+ $stream = $this->getMockBuilder('Guzzle\Stream\StreamRequestFactoryInterface')
+ ->setMethods(array('fromRequest'))
+ ->getMockForAbstractClass();
+ $resource = new Stream(fopen('php://temp', 'r+'));
+ $stream->expects($this->once())
+ ->method('fromRequest')
+ ->will($this->returnValue($resource));
+ $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"));
+ $result = StaticClient::get($this->getServer()->getUrl(), array('stream' => $stream));
+ $this->assertSame($resource, $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php
new file mode 100755
index 0000000..28f2671
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/UrlTest.php
@@ -0,0 +1,303 @@
+assertEquals('', (string) $url);
+ }
+
+ public function testPortIsDeterminedFromScheme()
+ {
+ $this->assertEquals(80, Url::factory('http://www.test.com/')->getPort());
+ $this->assertEquals(443, Url::factory('https://www.test.com/')->getPort());
+ $this->assertEquals(null, Url::factory('ftp://www.test.com/')->getPort());
+ $this->assertEquals(8192, Url::factory('http://www.test.com:8192/')->getPort());
+ }
+
+ public function testCloneCreatesNewInternalObjects()
+ {
+ $u1 = Url::factory('http://www.test.com/');
+ $u2 = clone $u1;
+ $this->assertNotSame($u1->getQuery(), $u2->getQuery());
+ }
+
+ public function testValidatesUrlPartsInFactory()
+ {
+ $url = Url::factory('/index.php');
+ $this->assertEquals('/index.php', (string) $url);
+ $this->assertFalse($url->isAbsolute());
+
+ $url = 'http://michael:test@test.com:80/path/123?q=abc#test';
+ $u = Url::factory($url);
+ $this->assertEquals('http://michael:test@test.com/path/123?q=abc#test', (string) $u);
+ $this->assertTrue($u->isAbsolute());
+ }
+
+ public function testAllowsFalsyUrlParts()
+ {
+ $url = Url::factory('http://0:50/0?0#0');
+ $this->assertSame('0', $url->getHost());
+ $this->assertEquals(50, $url->getPort());
+ $this->assertSame('/0', $url->getPath());
+ $this->assertEquals('0', (string) $url->getQuery());
+ $this->assertSame('0', $url->getFragment());
+ $this->assertEquals('http://0:50/0?0#0', (string) $url);
+
+ $url = Url::factory('');
+ $this->assertSame('', (string) $url);
+
+ $url = Url::factory('0');
+ $this->assertSame('0', (string) $url);
+ }
+
+ public function testBuildsRelativeUrlsWithFalsyParts()
+ {
+ $url = Url::buildUrl(array(
+ 'host' => '0',
+ 'path' => '0',
+ ));
+
+ $this->assertSame('//0/0', $url);
+
+ $url = Url::buildUrl(array(
+ 'path' => '0',
+ ));
+ $this->assertSame('0', $url);
+ }
+
+ public function testUrlStoresParts()
+ {
+ $url = Url::factory('http://test:pass@www.test.com:8081/path/path2/?a=1&b=2#fragment');
+ $this->assertEquals('http', $url->getScheme());
+ $this->assertEquals('test', $url->getUsername());
+ $this->assertEquals('pass', $url->getPassword());
+ $this->assertEquals('www.test.com', $url->getHost());
+ $this->assertEquals(8081, $url->getPort());
+ $this->assertEquals('/path/path2/', $url->getPath());
+ $this->assertEquals('fragment', $url->getFragment());
+ $this->assertEquals('a=1&b=2', (string) $url->getQuery());
+
+ $this->assertEquals(array(
+ 'fragment' => 'fragment',
+ 'host' => 'www.test.com',
+ 'pass' => 'pass',
+ 'path' => '/path/path2/',
+ 'port' => 8081,
+ 'query' => 'a=1&b=2',
+ 'scheme' => 'http',
+ 'user' => 'test'
+ ), $url->getParts());
+ }
+
+ public function testHandlesPathsCorrectly()
+ {
+ $url = Url::factory('http://www.test.com');
+ $this->assertEquals('', $url->getPath());
+ $url->setPath('test');
+ $this->assertEquals('test', $url->getPath());
+
+ $url->setPath('/test/123/abc');
+ $this->assertEquals(array('test', '123', 'abc'), $url->getPathSegments());
+
+ $parts = parse_url('http://www.test.com/test');
+ $parts['path'] = '';
+ $this->assertEquals('http://www.test.com', Url::buildUrl($parts));
+ $parts['path'] = 'test';
+ $this->assertEquals('http://www.test.com/test', Url::buildUrl($parts));
+ }
+
+ public function testAddsQueryStringIfPresent()
+ {
+ $this->assertEquals('?foo=bar', Url::buildUrl(array(
+ 'query' => 'foo=bar'
+ )));
+ }
+
+ public function testAddsToPath()
+ {
+ // Does nothing here
+ $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(false));
+ $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(null));
+ $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(array()));
+ $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(new \stdClass()));
+ $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath(''));
+ $this->assertEquals('http://e.com/base?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('/'));
+ $this->assertEquals('http://e.com/baz/foo', (string) Url::factory('http://e.com/baz/')->addPath('foo'));
+ $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('relative'));
+ $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::factory('http://e.com/base?a=1')->addPath('/relative'));
+ $this->assertEquals('http://e.com/base/0', (string) Url::factory('http://e.com/base')->addPath('0'));
+ $this->assertEquals('http://e.com/base/0/1', (string) Url::factory('http://e.com/base')->addPath('0')->addPath('1'));
+ }
+
+ /**
+ * URL combination data provider
+ *
+ * @return array
+ */
+ public function urlCombineDataProvider()
+ {
+ return array(
+ array('http://www.example.com/', 'http://www.example.com/', 'http://www.example.com/'),
+ array('http://www.example.com/path', '/absolute', 'http://www.example.com/absolute'),
+ array('http://www.example.com/path', '/absolute?q=2', 'http://www.example.com/absolute?q=2'),
+ array('http://www.example.com/path', 'more', 'http://www.example.com/path/more'),
+ array('http://www.example.com/path', 'more?q=1', 'http://www.example.com/path/more?q=1'),
+ array('http://www.example.com/', '?q=1', 'http://www.example.com/?q=1'),
+ array('http://www.example.com/path', 'http://test.com', 'http://test.com'),
+ array('http://www.example.com:8080/path', 'http://test.com', 'http://test.com'),
+ array('http://www.example.com:8080/path', '?q=2#abc', 'http://www.example.com:8080/path?q=2#abc'),
+ array('http://u:a@www.example.com/path', 'test', 'http://u:a@www.example.com/path/test'),
+ array('http://www.example.com/path', 'http://u:a@www.example.com/', 'http://u:a@www.example.com/'),
+ array('/path?q=2', 'http://www.test.com/', 'http://www.test.com/path?q=2'),
+ array('http://api.flickr.com/services/', 'http://www.flickr.com/services/oauth/access_token', 'http://www.flickr.com/services/oauth/access_token'),
+ array('http://www.example.com/?foo=bar', 'some/path', 'http://www.example.com/some/path?foo=bar'),
+ array('http://www.example.com/?foo=bar', 'some/path?boo=moo', 'http://www.example.com/some/path?boo=moo&foo=bar'),
+ array('http://www.example.com/some/', 'path?foo=bar&foo=baz', 'http://www.example.com/some/path?foo=bar&foo=baz'),
+ );
+ }
+
+ /**
+ * @dataProvider urlCombineDataProvider
+ */
+ public function testCombinesUrls($a, $b, $c)
+ {
+ $this->assertEquals($c, (string) Url::factory($a)->combine($b));
+ }
+
+ public function testHasGettersAndSetters()
+ {
+ $url = Url::factory('http://www.test.com/');
+ $this->assertEquals('example.com', $url->setHost('example.com')->getHost());
+ $this->assertEquals('8080', $url->setPort(8080)->getPort());
+ $this->assertEquals('/foo/bar', $url->setPath(array('foo', 'bar'))->getPath());
+ $this->assertEquals('a', $url->setPassword('a')->getPassword());
+ $this->assertEquals('b', $url->setUsername('b')->getUsername());
+ $this->assertEquals('abc', $url->setFragment('abc')->getFragment());
+ $this->assertEquals('https', $url->setScheme('https')->getScheme());
+ $this->assertEquals('a=123', (string) $url->setQuery('a=123')->getQuery());
+ $this->assertEquals('https://b:a@example.com:8080/foo/bar?a=123#abc', (string) $url);
+ $this->assertEquals('b=boo', (string) $url->setQuery(new QueryString(array(
+ 'b' => 'boo'
+ )))->getQuery());
+ $this->assertEquals('https://b:a@example.com:8080/foo/bar?b=boo#abc', (string) $url);
+ }
+
+ public function testSetQueryAcceptsArray()
+ {
+ $url = Url::factory('http://www.test.com');
+ $url->setQuery(array('a' => 'b'));
+ $this->assertEquals('http://www.test.com?a=b', (string) $url);
+ }
+
+ public function urlProvider()
+ {
+ return array(
+ array('/foo/..', '/'),
+ array('//foo//..', '/'),
+ array('/foo/../..', '/'),
+ array('/foo/../.', '/'),
+ array('/./foo/..', '/'),
+ array('/./foo', '/foo'),
+ array('/./foo/', '/foo/'),
+ array('/./foo/bar/baz/pho/../..', '/foo/bar'),
+ array('*', '*'),
+ array('/foo', '/foo'),
+ array('/abc/123/../foo/', '/abc/foo/'),
+ array('/a/b/c/./../../g', '/a/g'),
+ array('/b/c/./../../g', '/g'),
+ array('/b/c/./../../g', '/g'),
+ array('/c/./../../g', '/g'),
+ array('/./../../g', '/g'),
+ );
+ }
+
+ /**
+ * @dataProvider urlProvider
+ */
+ public function testNormalizesPaths($path, $result)
+ {
+ $url = Url::factory('http://www.example.com/');
+ $url->setPath($path)->normalizePath();
+ $this->assertEquals($result, $url->getPath());
+ }
+
+ public function testSettingHostWithPortModifiesPort()
+ {
+ $url = Url::factory('http://www.example.com');
+ $url->setHost('foo:8983');
+ $this->assertEquals('foo', $url->getHost());
+ $this->assertEquals(8983, $url->getPort());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testValidatesUrlCanBeParsed()
+ {
+ Url::factory('foo:////');
+ }
+
+ public function testConvertsSpecialCharsInPathWhenCastingToString()
+ {
+ $url = Url::factory('http://foo.com/baz bar?a=b');
+ $url->addPath('?');
+ $this->assertEquals('http://foo.com/baz%20bar/%3F?a=b', (string) $url);
+ }
+
+ /**
+ * @link http://tools.ietf.org/html/rfc3986#section-5.4.1
+ */
+ public function rfc3986UrlProvider()
+ {
+ $result = array(
+ array('g', 'http://a/b/c/g'),
+ array('./g', 'http://a/b/c/g'),
+ array('g/', 'http://a/b/c/g/'),
+ array('/g', 'http://a/g'),
+ array('?y', 'http://a/b/c/d;p?y'),
+ array('g?y', 'http://a/b/c/g?y'),
+ array('#s', 'http://a/b/c/d;p?q#s'),
+ array('g#s', 'http://a/b/c/g#s'),
+ array('g?y#s', 'http://a/b/c/g?y#s'),
+ array(';x', 'http://a/b/c/;x'),
+ array('g;x', 'http://a/b/c/g;x'),
+ array('g;x?y#s', 'http://a/b/c/g;x?y#s'),
+ array('', 'http://a/b/c/d;p?q'),
+ array('.', 'http://a/b/c'),
+ array('./', 'http://a/b/c/'),
+ array('..', 'http://a/b'),
+ array('../', 'http://a/b/'),
+ array('../g', 'http://a/b/g'),
+ array('../..', 'http://a/'),
+ array('../../', 'http://a/'),
+ array('../../g', 'http://a/g')
+ );
+
+ // This support was added in PHP 5.4.7: https://bugs.php.net/bug.php?id=62844
+ if (version_compare(PHP_VERSION, '5.4.7', '>=')) {
+ $result[] = array('//g', 'http://g');
+ }
+
+ return $result;
+ }
+
+ /**
+ * @dataProvider rfc3986UrlProvider
+ */
+ public function testCombinesUrlsUsingRfc3986($relative, $result)
+ {
+ $a = Url::factory('http://a/b/c/d;p?q');
+ $b = Url::factory($relative);
+ $this->assertEquals($result, trim((string) $a->combine($b, true), '='));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js
new file mode 100755
index 0000000..4156f1a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Http/server.js
@@ -0,0 +1,146 @@
+/**
+ * Guzzle node.js test server to return queued responses to HTTP requests and
+ * expose a RESTful API for enqueueing responses and retrieving the requests
+ * that have been received.
+ *
+ * - Delete all requests that have been received:
+ * DELETE /guzzle-server/requests
+ * Host: 127.0.0.1:8124
+ *
+ * - Enqueue responses
+ * PUT /guzzle-server/responses
+ * Host: 127.0.0.1:8124
+ *
+ * [{ "statusCode": 200, "reasonPhrase": "OK", "headers": {}, "body": "" }]
+ *
+ * - Get the received requests
+ * GET /guzzle-server/requests
+ * Host: 127.0.0.1:8124
+ *
+ * - Shutdown the server
+ * DELETE /guzzle-server
+ * Host: 127.0.0.1:8124
+ *
+ * @package Guzzle PHP
+ * @license See the LICENSE file that was distributed with this source code.
+ */
+
+var http = require("http");
+
+/**
+ * Guzzle node.js server
+ * @class
+ */
+var GuzzleServer = function(port, log) {
+
+ this.port = port;
+ this.log = log;
+ this.responses = [];
+ this.requests = [];
+ var that = this;
+
+ var controlRequest = function(request, req, res) {
+ if (req.url == '/guzzle-server/perf') {
+ res.writeHead(200, "OK", {"Content-Length": 16});
+ res.end("Body of response");
+ } else if (req.method == "DELETE") {
+ if (req.url == "/guzzle-server/requests") {
+ // Clear the received requests
+ that.requests = [];
+ res.writeHead(200, "OK", { "Content-Length": 0 });
+ res.end();
+ if (this.log) {
+ console.log("Flushing requests");
+ }
+ } else if (req.url == "/guzzle-server") {
+ // Shutdown the server
+ res.writeHead(200, "OK", { "Content-Length": 0, "Connection": "close" });
+ res.end();
+ if (this.log) {
+ console.log("Shutting down");
+ }
+ that.server.close();
+ }
+ } else if (req.method == "GET") {
+ if (req.url === "/guzzle-server/requests") {
+ // Get received requests
+ var data = that.requests.join("\n----[request]\n");
+ res.writeHead(200, "OK", { "Content-Length": data.length });
+ res.end(data);
+ if (that.log) {
+ console.log("Sending receiving requests");
+ }
+ }
+ } else if (req.method == "PUT") {
+ if (req.url == "/guzzle-server/responses") {
+ if (that.log) {
+ console.log("Adding responses...");
+ }
+ // Received response to queue
+ var data = request.split("\r\n\r\n")[1];
+ if (!data) {
+ if (that.log) {
+ console.log("No response data was provided");
+ }
+ res.writeHead(400, "NO RESPONSES IN REQUEST", { "Content-Length": 0 });
+ } else {
+ that.responses = eval("(" + data + ")");
+ if (that.log) {
+ console.log(that.responses);
+ }
+ res.writeHead(200, "OK", { "Content-Length": 0 });
+ }
+ res.end();
+ }
+ }
+ };
+
+ var receivedRequest = function(request, req, res) {
+ if (req.url.indexOf("/guzzle-server") === 0) {
+ controlRequest(request, req, res);
+ } else if (req.url.indexOf("/guzzle-server") == -1 && !that.responses.length) {
+ res.writeHead(500);
+ res.end("No responses in queue");
+ } else {
+ var response = that.responses.shift();
+ res.writeHead(response.statusCode, response.reasonPhrase, response.headers);
+ res.end(response.body);
+ that.requests.push(request);
+ }
+ };
+
+ this.start = function() {
+
+ that.server = http.createServer(function(req, res) {
+
+ var request = req.method + " " + req.url + " HTTP/" + req.httpVersion + "\r\n";
+ for (var i in req.headers) {
+ request += i + ": " + req.headers[i] + "\r\n";
+ }
+ request += "\r\n";
+
+ // Receive each chunk of the request body
+ req.addListener("data", function(chunk) {
+ request += chunk;
+ });
+
+ // Called when the request completes
+ req.addListener("end", function() {
+ receivedRequest(request, req, res);
+ });
+ });
+ that.server.listen(port, "127.0.0.1");
+
+ if (this.log) {
+ console.log("Server running at http://127.0.0.1:8124/");
+ }
+ };
+};
+
+// Get the port from the arguments
+port = process.argv.length >= 3 ? process.argv[2] : 8124;
+log = process.argv.length >= 4 ? process.argv[3] : false;
+
+// Start the server
+server = new GuzzleServer(port, log);
+server.start();
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php
new file mode 100755
index 0000000..990c0af
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/InflectorTest.php
@@ -0,0 +1,37 @@
+assertSame(Inflector::getDefault(), Inflector::getDefault());
+ }
+
+ public function testSnake()
+ {
+ $this->assertEquals('camel_case', Inflector::getDefault()->snake('camelCase'));
+ $this->assertEquals('camel_case', Inflector::getDefault()->snake('CamelCase'));
+ $this->assertEquals('camel_case_words', Inflector::getDefault()->snake('CamelCaseWords'));
+ $this->assertEquals('camel_case_words', Inflector::getDefault()->snake('CamelCase_words'));
+ $this->assertEquals('test', Inflector::getDefault()->snake('test'));
+ $this->assertEquals('test', Inflector::getDefault()->snake('test'));
+ $this->assertEquals('expect100_continue', Inflector::getDefault()->snake('Expect100Continue'));
+ }
+
+ public function testCamel()
+ {
+ $this->assertEquals('CamelCase', Inflector::getDefault()->camel('camel_case'));
+ $this->assertEquals('CamelCaseWords', Inflector::getDefault()->camel('camel_case_words'));
+ $this->assertEquals('Test', Inflector::getDefault()->camel('test'));
+ $this->assertEquals('Expect100Continue', ucfirst(Inflector::getDefault()->camel('expect100_continue')));
+ // Get from cache
+ $this->assertEquals('Test', Inflector::getDefault()->camel('test', false));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php
new file mode 100755
index 0000000..f00b7fa
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/MemoizingInflectorTest.php
@@ -0,0 +1,46 @@
+getMock('Guzzle\Inflection\Inflector', array('snake', 'camel'));
+ $mock->expects($this->once())->method('snake')->will($this->returnValue('foo_bar'));
+ $mock->expects($this->once())->method('camel')->will($this->returnValue('FooBar'));
+
+ $inflector = new MemoizingInflector($mock);
+ $this->assertEquals('foo_bar', $inflector->snake('FooBar'));
+ $this->assertEquals('foo_bar', $inflector->snake('FooBar'));
+ $this->assertEquals('FooBar', $inflector->camel('foo_bar'));
+ $this->assertEquals('FooBar', $inflector->camel('foo_bar'));
+ }
+
+ public function testProtectsAgainstCacheOverflow()
+ {
+ $inflector = new MemoizingInflector(new Inflector(), 10);
+ for ($i = 1; $i < 11; $i++) {
+ $inflector->camel('foo_' . $i);
+ $inflector->snake('Foo' . $i);
+ }
+
+ $cache = $this->readAttribute($inflector, 'cache');
+ $this->assertEquals(10, count($cache['snake']));
+ $this->assertEquals(10, count($cache['camel']));
+
+ $inflector->camel('baz!');
+ $inflector->snake('baz!');
+
+ // Now ensure that 20% of the cache was removed (2), then the item was added
+ $cache = $this->readAttribute($inflector, 'cache');
+ $this->assertEquals(9, count($cache['snake']));
+ $this->assertEquals(9, count($cache['camel']));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php
new file mode 100755
index 0000000..ff2654c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Inflection/PreComputedInflectorTest.php
@@ -0,0 +1,45 @@
+getMock('Guzzle\Inflection\Inflector', array('snake', 'camel'));
+ $mock->expects($this->once())->method('snake')->with('Test')->will($this->returnValue('test'));
+ $mock->expects($this->once())->method('camel')->with('Test')->will($this->returnValue('Test'));
+ $inflector = new PreComputedInflector($mock, array('FooBar' => 'foo_bar'), array('foo_bar' => 'FooBar'));
+ $this->assertEquals('FooBar', $inflector->camel('foo_bar'));
+ $this->assertEquals('foo_bar', $inflector->snake('FooBar'));
+ $this->assertEquals('Test', $inflector->camel('Test'));
+ $this->assertEquals('test', $inflector->snake('Test'));
+ }
+
+ public function testMirrorsPrecomputedValues()
+ {
+ $mock = $this->getMock('Guzzle\Inflection\Inflector', array('snake', 'camel'));
+ $mock->expects($this->never())->method('snake');
+ $mock->expects($this->never())->method('camel');
+ $inflector = new PreComputedInflector($mock, array('Zeep' => 'zeep'), array(), true);
+ $this->assertEquals('Zeep', $inflector->camel('zeep'));
+ $this->assertEquals('zeep', $inflector->snake('Zeep'));
+ }
+
+ public function testMirrorsPrecomputedValuesByMerging()
+ {
+ $mock = $this->getMock('Guzzle\Inflection\Inflector', array('snake', 'camel'));
+ $mock->expects($this->never())->method('snake');
+ $mock->expects($this->never())->method('camel');
+ $inflector = new PreComputedInflector($mock, array('Zeep' => 'zeep'), array('foo' => 'Foo'), true);
+ $this->assertEquals('Zeep', $inflector->camel('zeep'));
+ $this->assertEquals('zeep', $inflector->snake('Zeep'));
+ $this->assertEquals('Foo', $inflector->camel('foo'));
+ $this->assertEquals('foo', $inflector->snake('Foo'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php
new file mode 100755
index 0000000..8d6ae84
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/AppendIteratorTest.php
@@ -0,0 +1,29 @@
+ 1,
+ 'b' => 2
+ ));
+ $b = new \ArrayIterator(array());
+ $c = new \ArrayIterator(array(
+ 'c' => 3,
+ 'd' => 4
+ ));
+ $i = new AppendIterator();
+ $i->append($a);
+ $i->append($b);
+ $i->append($c);
+ $this->assertEquals(array(1, 2, 3, 4), iterator_to_array($i, false));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php
new file mode 100755
index 0000000..ec4c129
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/ChunkedIteratorTest.php
@@ -0,0 +1,52 @@
+assertEquals(11, count($chunks));
+ foreach ($chunks as $j => $chunk) {
+ $this->assertEquals(range($j * 10, min(100, $j * 10 + 9)), $chunk);
+ }
+ }
+
+ public function testChunksIteratorWithOddValues()
+ {
+ $chunked = new ChunkedIterator(new \ArrayIterator(array(1, 2, 3, 4, 5)), 2);
+ $chunks = iterator_to_array($chunked, false);
+ $this->assertEquals(3, count($chunks));
+ $this->assertEquals(array(1, 2), $chunks[0]);
+ $this->assertEquals(array(3, 4), $chunks[1]);
+ $this->assertEquals(array(5), $chunks[2]);
+ }
+
+ public function testMustNotTerminateWithTraversable()
+ {
+ $traversable = simplexml_load_string(' ')->foo;
+ $chunked = new ChunkedIterator($traversable, 2);
+ $actual = iterator_to_array($chunked, false);
+ $this->assertCount(2, $actual);
+ }
+
+ public function testSizeOfZeroMakesIteratorInvalid() {
+ $chunked = new ChunkedIterator(new \ArrayIterator(range(1, 5)), 0);
+ $chunked->rewind();
+ $this->assertFalse($chunked->valid());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testSizeLowerZeroThrowsException() {
+ new ChunkedIterator(new \ArrayIterator(range(1, 5)), -1);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php
new file mode 100755
index 0000000..73b4f69
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/FilterIteratorTest.php
@@ -0,0 +1,28 @@
+assertEquals(range(1, 99, 2), iterator_to_array($i, false));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testValidatesCallable()
+ {
+ $i = new FilterIterator(new \ArrayIterator(), new \stdClass());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php
new file mode 100755
index 0000000..4de4a6b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MapIteratorTest.php
@@ -0,0 +1,28 @@
+assertEquals(range(0, 1000, 10), iterator_to_array($i, false));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testValidatesCallable()
+ {
+ $i = new MapIterator(new \ArrayIterator(), new \stdClass());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php
new file mode 100755
index 0000000..5bcf06f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Iterator/MethodProxyIteratorTest.php
@@ -0,0 +1,28 @@
+append('a');
+ $proxy->append('b');
+ $this->assertEquals(array('a', 'b'), $i->getArrayCopy());
+ $this->assertEquals(array('a', 'b'), $proxy->getArrayCopy());
+ }
+
+ public function testUsesInnerIterator()
+ {
+ $i = new MethodProxyIterator(new ChunkedIterator(new \ArrayIterator(array(1, 2, 3, 4, 5)), 2));
+ $this->assertEquals(3, count(iterator_to_array($i, false)));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php
new file mode 100755
index 0000000..a66882f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ArrayLogAdapterTest.php
@@ -0,0 +1,23 @@
+log('test', \LOG_NOTICE, '127.0.0.1');
+ $this->assertEquals(array(array('message' => 'test', 'priority' => \LOG_NOTICE, 'extras' => '127.0.0.1')), $adapter->getLogs());
+ }
+
+ public function testClearLog()
+ {
+ $adapter = new ArrayLogAdapter();
+ $adapter->log('test', \LOG_NOTICE, '127.0.0.1');
+ $adapter->clearLogs();
+ $this->assertEquals(array(), $adapter->getLogs());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php
new file mode 100755
index 0000000..0177dc0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/ClosureLogAdapterTest.php
@@ -0,0 +1,30 @@
+adapter = new ClosureLogAdapter(function($message, $priority, $extras = null) use ($that, &$modified) {
+ $modified = array($message, $priority, $extras);
+ });
+ $this->adapter->log('test', LOG_NOTICE, '127.0.0.1');
+ $this->assertEquals(array('test', LOG_NOTICE, '127.0.0.1'), $modified);
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testThrowsExceptionWhenNotCallable()
+ {
+ $this->adapter = new ClosureLogAdapter(123);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php
new file mode 100755
index 0000000..3ff4b07
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/MessageFormatterTest.php
@@ -0,0 +1,143 @@
+request = new EntityEnclosingRequest('POST', 'http://foo.com?q=test', array(
+ 'X-Foo' => 'bar',
+ 'Authorization' => 'Baz'
+ ));
+ $this->request->setBody(EntityBody::factory('Hello'));
+
+ $this->response = new Response(200, array(
+ 'X-Test' => 'Abc'
+ ), 'Foo');
+
+ $this->handle = $this->getMockBuilder('Guzzle\Http\Curl\CurlHandle')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getError', 'getErrorNo', 'getStderr', 'getInfo'))
+ ->getMock();
+
+ $this->handle->expects($this->any())
+ ->method('getError')
+ ->will($this->returnValue('e'));
+
+ $this->handle->expects($this->any())
+ ->method('getErrorNo')
+ ->will($this->returnValue('123'));
+
+ $this->handle->expects($this->any())
+ ->method('getStderr')
+ ->will($this->returnValue('testing'));
+
+ $this->handle->expects($this->any())
+ ->method('getInfo')
+ ->will($this->returnValueMap(array(
+ array(CURLINFO_CONNECT_TIME, '123'),
+ array(CURLINFO_TOTAL_TIME, '456')
+ )));
+ }
+
+ public function logProvider()
+ {
+ return array(
+ // Uses the cache for the second time
+ array('{method} - {method}', 'POST - POST'),
+ array('{url}', 'http://foo.com?q=test'),
+ array('{port}', '80'),
+ array('{resource}', '/?q=test'),
+ array('{host}', 'foo.com'),
+ array('{hostname}', gethostname()),
+ array('{protocol}/{version}', 'HTTP/1.1'),
+ array('{code} {phrase}', '200 OK'),
+ array('{req_header_Foo}', ''),
+ array('{req_header_X-Foo}', 'bar'),
+ array('{req_header_Authorization}', 'Baz'),
+ array('{res_header_foo}', ''),
+ array('{res_header_X-Test}', 'Abc'),
+ array('{req_body}', 'Hello'),
+ array('{res_body}', 'Foo'),
+ array('{curl_stderr}', 'testing'),
+ array('{curl_error}', 'e'),
+ array('{curl_code}', '123'),
+ array('{connect_time}', '123'),
+ array('{total_time}', '456')
+ );
+ }
+
+ /**
+ * @dataProvider logProvider
+ */
+ public function testFormatsMessages($template, $output)
+ {
+ $formatter = new MessageFormatter($template);
+ $this->assertEquals($output, $formatter->format($this->request, $this->response, $this->handle));
+ }
+
+ public function testFormatsRequestsAndResponses()
+ {
+ $formatter = new MessageFormatter();
+ $formatter->setTemplate('{request}{response}');
+ $this->assertEquals($this->request . $this->response, $formatter->format($this->request, $this->response));
+ }
+
+ public function testAddsTimestamp()
+ {
+ $formatter = new MessageFormatter('{ts}');
+ $this->assertNotEmpty($formatter->format($this->request, $this->response));
+ }
+
+ public function testUsesResponseWhenNoHandleAndGettingCurlInformation()
+ {
+ $formatter = new MessageFormatter('{connect_time}/{total_time}');
+ $response = $this->getMockBuilder('Guzzle\Http\Message\Response')
+ ->setConstructorArgs(array(200))
+ ->setMethods(array('getInfo'))
+ ->getMock();
+ $response->expects($this->exactly(2))
+ ->method('getInfo')
+ ->will($this->returnValueMap(array(
+ array('connect_time', '1'),
+ array('total_time', '2'),
+ )));
+ $this->assertEquals('1/2', $formatter->format($this->request, $response));
+ }
+
+ public function testUsesEmptyStringWhenNoHandleAndNoResponse()
+ {
+ $formatter = new MessageFormatter('{connect_time}/{total_time}');
+ $this->assertEquals('/', $formatter->format($this->request));
+ }
+
+ public function testInjectsTotalTime()
+ {
+ $out = '';
+ $formatter = new MessageFormatter('{connect_time}/{total_time}');
+ $adapter = new ClosureLogAdapter(function ($m) use (&$out) { $out .= $m; });
+ $log = new LogPlugin($adapter, $formatter);
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHI");
+ $client = new Client($this->getServer()->getUrl());
+ $client->addSubscriber($log);
+ $client->get('/')->send();
+ $this->assertNotEquals('/', $out);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php
new file mode 100755
index 0000000..7b72dd6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/PsrLogAdapterTest.php
@@ -0,0 +1,25 @@
+pushHandler($handler);
+ $adapter = new PsrLogAdapter($log);
+ $adapter->log('test!', LOG_INFO);
+ $this->assertTrue($handler->hasInfoRecords());
+ $this->assertSame($log, $adapter->getLogObject());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php
new file mode 100755
index 0000000..1b61283
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Log/Zf2LogAdapterTest.php
@@ -0,0 +1,51 @@
+stream = fopen('php://temp', 'r+');
+ $this->log = new Logger();
+ $this->log->addWriter(new Stream($this->stream));
+ $this->adapter = new Zf2LogAdapter($this->log);
+
+ }
+
+ public function testLogsMessagesToAdaptedObject()
+ {
+ // Test without a priority
+ $this->adapter->log('Zend_Test!', \LOG_NOTICE);
+ rewind($this->stream);
+ $contents = stream_get_contents($this->stream);
+ $this->assertEquals(1, substr_count($contents, 'Zend_Test!'));
+
+ // Test with a priority
+ $this->adapter->log('Zend_Test!', \LOG_ALERT);
+ rewind($this->stream);
+ $contents = stream_get_contents($this->stream);
+ $this->assertEquals(2, substr_count($contents, 'Zend_Test!'));
+ }
+
+ public function testExposesAdaptedLogObject()
+ {
+ $this->assertEquals($this->log, $this->adapter->getLogObject());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php
new file mode 100755
index 0000000..3fb6527
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/CustomResponseModel.php
@@ -0,0 +1,21 @@
+command = $command;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php
new file mode 100755
index 0000000..aabb15f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ErrorResponseMock.php
@@ -0,0 +1,25 @@
+command = $command;
+ $this->response = $response;
+ $this->message = 'Error from ' . $response;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php
new file mode 100755
index 0000000..97a1974
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/ExceptionMock.php
@@ -0,0 +1,11 @@
+multiHandle;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php
new file mode 100755
index 0000000..11e22eb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockObserver.php
@@ -0,0 +1,65 @@
+events as $event) {
+ if ($event->getName() == $eventName) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function getLastEvent()
+ {
+ return end($this->events);
+ }
+
+ public function count()
+ {
+ return count($this->events);
+ }
+
+ public function getGrouped()
+ {
+ $events = array();
+ foreach ($this->events as $event) {
+ if (!isset($events[$event->getName()])) {
+ $events[$event->getName()] = array();
+ }
+ $events[$event->getName()][] = $event;
+ }
+
+ return $events;
+ }
+
+ public function getData($event, $key, $occurrence = 0)
+ {
+ $grouped = $this->getGrouped();
+ if (isset($grouped[$event])) {
+ return $grouped[$event][$occurrence][$key];
+ }
+
+ return null;
+ }
+
+ public function update(Event $event)
+ {
+ $this->events[] = $event;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php
new file mode 100755
index 0000000..e011959
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Mock/MockSubject.php
@@ -0,0 +1,7 @@
+ 'allseeing-i.com',
+ 'path' => '/',
+ 'data' => array(
+ 'PHPSESSID' => '6c951590e7a9359bcedde25cda73e43c'
+ ),
+ 'max_age' => NULL,
+ 'expires' => 'Sat, 26-Jul-2008 17:00:42 GMT',
+ 'version' => NULL,
+ 'secure' => NULL,
+ 'discard' => NULL,
+ 'port' => NULL,
+ 'cookies' => array(
+ 'ASIHTTPRequestTestCookie' => 'This+is+the+value'
+ ),
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ array('', false),
+ array('foo', false),
+ // Test setting a blank value for a cookie
+ array(array(
+ 'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '),
+ array(
+ 'cookies' => array(
+ 'foo' => ''
+ ),
+ 'data' => array(),
+ 'discard' => null,
+ 'domain' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ // Test setting a value and removing quotes
+ array(array(
+ 'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;', 'foo="1"', 'foo="1";', 'foo= "1";'),
+ array(
+ 'cookies' => array(
+ 'foo' => '1'
+ ),
+ 'data' => array(),
+ 'discard' => null,
+ 'domain' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ // Test setting multiple values
+ array(array(
+ 'foo=1; bar=2;', 'foo =1; bar = "2"', 'foo=1; bar=2'),
+ array(
+ 'cookies' => array(
+ 'foo' => '1',
+ 'bar' => '2',
+ ),
+ 'data' => array(),
+ 'discard' => null,
+ 'domain' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ // Tests getting the domain and path from a reference request
+ array(array(
+ 'foo=1; port="80,8081"; httponly', 'foo=1; port="80,8081"; domain=www.test.com; HttpOnly;', 'foo=1; ; domain=www.test.com; path=/path; port="80,8081"; HttpOnly;'),
+ array(
+ 'cookies' => array(
+ 'foo' => 1
+ ),
+ 'data' => array(),
+ 'discard' => null,
+ 'domain' => 'www.test.com',
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/path',
+ 'port' => array('80', '8081'),
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => true
+ ),
+ 'http://www.test.com/path/'
+ ),
+ // Some of the following tests are based on http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Http/CookieTest.php
+ array(
+ 'justacookie=foo; domain=example.com',
+ array(
+ 'cookies' => array(
+ 'justacookie' => 'foo'
+ ),
+ 'domain' => 'example.com',
+ 'data' => array(),
+ 'discard' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ array(
+ 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
+ array(
+ 'cookies' => array(
+ 'expires' => 'tomorrow'
+ ),
+ 'domain' => '.example.com',
+ 'path' => '/Space Out/',
+ 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
+ 'data' => array(),
+ 'discard' => null,
+ 'port' => null,
+ 'secure' => true,
+ 'version' => null,
+ 'max_age' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ array(
+ 'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/',
+ array(
+ 'cookies' => array(
+ 'domain' => 'unittests'
+ ),
+ 'domain' => 'example.com',
+ 'path' => '/some value/',
+ 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
+ 'secure' => false,
+ 'data' => array(),
+ 'discard' => null,
+ 'max_age' => null,
+ 'port' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ array(
+ 'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT',
+ array(
+ 'cookies' => array(
+ 'path' => 'indexAction'
+ ),
+ 'domain' => '.foo.com',
+ 'path' => '/',
+ 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
+ 'secure' => false,
+ 'data' => array(),
+ 'discard' => null,
+ 'max_age' => null,
+ 'port' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ array(
+ 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400',
+ array(
+ 'cookies' => array(
+ 'secure' => 'sha1'
+ ),
+ 'domain' => 'some.really.deep.domain.com',
+ 'path' => '/',
+ 'secure' => true,
+ 'data' => array(),
+ 'discard' => null,
+ 'expires' => time() + 86400,
+ 'max_age' => 86400,
+ 'port' => null,
+ 'version' => 1,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ array(
+ 'PHPSESSID=123456789+abcd%2Cef; secure; discard; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
+ array(
+ 'cookies' => array(
+ 'PHPSESSID' => '123456789+abcd%2Cef'
+ ),
+ 'domain' => '.localdomain',
+ 'path' => '/foo/baz',
+ 'expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
+ 'secure' => true,
+ 'data' => array(),
+ 'discard' => true,
+ 'max_age' => null,
+ 'port' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ )
+ ),
+ // rfc6265#section-5.1.4
+ array(
+ 'cookie=value',
+ array(
+ 'cookies' => array(
+ 'cookie' => 'value'
+ ),
+ 'domain' => 'example.com',
+ 'data' => array(),
+ 'discard' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/some/path',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ ),
+ 'http://example.com/some/path/test.html'
+ ),
+ array(
+ 'empty=path',
+ array(
+ 'cookies' => array(
+ 'empty' => 'path'
+ ),
+ 'domain' => 'example.com',
+ 'data' => array(),
+ 'discard' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ ),
+ 'http://example.com/test.html'
+ ),
+ array(
+ 'baz=qux',
+ array(
+ 'cookies' => array(
+ 'baz' => 'qux'
+ ),
+ 'domain' => 'example.com',
+ 'data' => array(),
+ 'discard' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ ),
+ 'http://example.com?query=here'
+ ),
+ array(
+ 'test=noSlashPath; path=someString',
+ array(
+ 'cookies' => array(
+ 'test' => 'noSlashPath'
+ ),
+ 'domain' => 'example.com',
+ 'data' => array(),
+ 'discard' => null,
+ 'expires' => null,
+ 'max_age' => null,
+ 'path' => '/real/path',
+ 'port' => null,
+ 'secure' => null,
+ 'version' => null,
+ 'comment' => null,
+ 'comment_url' => null,
+ 'http_only' => false
+ ),
+ 'http://example.com/real/path/'
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider cookieParserDataProvider
+ */
+ public function testParseCookie($cookie, $parsed, $url = null)
+ {
+ $c = $this->cookieParserClass;
+ $parser = new $c();
+
+ $request = null;
+ if ($url) {
+ $url = Url::factory($url);
+ $host = $url->getHost();
+ $path = $url->getPath();
+ } else {
+ $host = '';
+ $path = '';
+ }
+
+ foreach ((array) $cookie as $c) {
+ $p = $parser->parseCookie($c, $host, $path);
+
+ // Remove expires values from the assertion if they are relatively equal by allowing a 5 minute difference
+ if ($p['expires'] != $parsed['expires']) {
+ if (abs($p['expires'] - $parsed['expires']) < 300) {
+ unset($p['expires']);
+ unset($parsed['expires']);
+ }
+ }
+
+ if (is_array($parsed)) {
+ foreach ($parsed as $key => $value) {
+ $this->assertEquals($parsed[$key], $p[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true));
+ }
+
+ foreach ($p as $key => $value) {
+ $this->assertEquals($p[$key], $parsed[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true));
+ }
+ } else {
+ $this->assertEquals($parsed, $p);
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php
new file mode 100755
index 0000000..75d336f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Cookie/CookieParserTest.php
@@ -0,0 +1,22 @@
+parseCookie('foo=baz+bar', null, null, true);
+ $this->assertEquals(array(
+ 'foo' => 'baz bar'
+ ), $result['cookies']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php
new file mode 100755
index 0000000..da58bb4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserProvider.php
@@ -0,0 +1,225 @@
+ 'GET',
+ 'protocol' => 'HTTP',
+ 'version' => '1.1',
+ 'request_url' => array(
+ 'scheme' => 'http',
+ 'host' => '',
+ 'port' => '',
+ 'path' => '/',
+ 'query' => ''
+ ),
+ 'headers' => array(),
+ 'body' => ''
+ )),
+ // Path and query string, multiple header values per header and case sensitive storage
+ array("HEAD /path?query=foo HTTP/1.0\r\nHost: example.com\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\nX-Foo: Baz\r\n\r\n", array(
+ 'method' => 'HEAD',
+ 'protocol' => 'HTTP',
+ 'version' => '1.0',
+ 'request_url' => array(
+ 'scheme' => 'http',
+ 'host' => 'example.com',
+ 'port' => '',
+ 'path' => '/path',
+ 'query' => 'query=foo'
+ ),
+ 'headers' => array(
+ 'Host' => 'example.com',
+ 'X-Foo' => array('foo', 'foo', 'Baz'),
+ 'x-foo' => 'Bar'
+ ),
+ 'body' => ''
+ )),
+ // Includes a body
+ array("PUT / HTTP/1.0\r\nhost: example.com:443\r\nContent-Length: 4\r\n\r\ntest", array(
+ 'method' => 'PUT',
+ 'protocol' => 'HTTP',
+ 'version' => '1.0',
+ 'request_url' => array(
+ 'scheme' => 'https',
+ 'host' => 'example.com',
+ 'port' => '443',
+ 'path' => '/',
+ 'query' => ''
+ ),
+ 'headers' => array(
+ 'host' => 'example.com:443',
+ 'Content-Length' => '4'
+ ),
+ 'body' => 'test'
+ )),
+ // Includes Authorization headers
+ array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nAuthorization: Basic {$auth}\r\n\r\n", array(
+ 'method' => 'GET',
+ 'protocol' => 'HTTP',
+ 'version' => '1.1',
+ 'request_url' => array(
+ 'scheme' => 'http',
+ 'host' => 'example.com',
+ 'port' => '8080',
+ 'path' => '/',
+ 'query' => ''
+ ),
+ 'headers' => array(
+ 'Host' => 'example.com:8080',
+ 'Authorization' => "Basic {$auth}"
+ ),
+ 'body' => ''
+ )),
+ // Include authorization header
+ array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nauthorization: Basic {$auth}\r\n\r\n", array(
+ 'method' => 'GET',
+ 'protocol' => 'HTTP',
+ 'version' => '1.1',
+ 'request_url' => array(
+ 'scheme' => 'http',
+ 'host' => 'example.com',
+ 'port' => '8080',
+ 'path' => '/',
+ 'query' => ''
+ ),
+ 'headers' => array(
+ 'Host' => 'example.com:8080',
+ 'authorization' => "Basic {$auth}"
+ ),
+ 'body' => ''
+ )),
+ );
+ }
+
+ public function responseProvider()
+ {
+ return array(
+ // Empty request
+ array('', false),
+
+ array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", array(
+ 'protocol' => 'HTTP',
+ 'version' => '1.1',
+ 'code' => '200',
+ 'reason_phrase' => 'OK',
+ 'headers' => array(
+ 'Content-Length' => 0
+ ),
+ 'body' => ''
+ )),
+ array("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n", array(
+ 'protocol' => 'HTTP',
+ 'version' => '1.0',
+ 'code' => '400',
+ 'reason_phrase' => 'Bad Request',
+ 'headers' => array(
+ 'Content-Length' => 0
+ ),
+ 'body' => ''
+ )),
+ array("HTTP/1.0 100 Continue\r\n\r\n", array(
+ 'protocol' => 'HTTP',
+ 'version' => '1.0',
+ 'code' => '100',
+ 'reason_phrase' => 'Continue',
+ 'headers' => array(),
+ 'body' => ''
+ )),
+ array("HTTP/1.1 204 No Content\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\n\r\n", array(
+ 'protocol' => 'HTTP',
+ 'version' => '1.1',
+ 'code' => '204',
+ 'reason_phrase' => 'No Content',
+ 'headers' => array(
+ 'X-Foo' => array('foo', 'foo'),
+ 'x-foo' => 'Bar'
+ ),
+ 'body' => ''
+ )),
+ array("HTTP/1.1 200 Ok that is great!\r\nContent-Length: 4\r\n\r\nTest", array(
+ 'protocol' => 'HTTP',
+ 'version' => '1.1',
+ 'code' => '200',
+ 'reason_phrase' => 'Ok that is great!',
+ 'headers' => array(
+ 'Content-Length' => 4
+ ),
+ 'body' => 'Test'
+ )),
+ );
+ }
+
+ public function compareRequestResults($result, $expected)
+ {
+ if (!$result) {
+ $this->assertFalse($expected);
+ return;
+ }
+
+ $this->assertEquals($result['method'], $expected['method']);
+ $this->assertEquals($result['protocol'], $expected['protocol']);
+ $this->assertEquals($result['version'], $expected['version']);
+ $this->assertEquals($result['request_url'], $expected['request_url']);
+ $this->assertEquals($result['body'], $expected['body']);
+ $this->compareHttpHeaders($result['headers'], $expected['headers']);
+ }
+
+ public function compareResponseResults($result, $expected)
+ {
+ if (!$result) {
+ $this->assertFalse($expected);
+ return;
+ }
+
+ $this->assertEquals($result['protocol'], $expected['protocol']);
+ $this->assertEquals($result['version'], $expected['version']);
+ $this->assertEquals($result['code'], $expected['code']);
+ $this->assertEquals($result['reason_phrase'], $expected['reason_phrase']);
+ $this->assertEquals($result['body'], $expected['body']);
+ $this->compareHttpHeaders($result['headers'], $expected['headers']);
+ }
+
+ protected function normalizeHeaders($headers)
+ {
+ $normalized = array();
+ foreach ($headers as $key => $value) {
+ $key = strtolower($key);
+ if (!isset($normalized[$key])) {
+ $normalized[$key] = $value;
+ } elseif (!is_array($normalized[$key])) {
+ $normalized[$key] = array($value);
+ } else {
+ $normalized[$key][] = $value;
+ }
+ }
+
+ foreach ($normalized as $key => &$value) {
+ if (is_array($value)) {
+ sort($value);
+ }
+ }
+
+ return $normalized;
+ }
+
+ public function compareHttpHeaders($result, $expected)
+ {
+ // Aggregate all headers case-insensitively
+ $result = $this->normalizeHeaders($result);
+ $expected = $this->normalizeHeaders($expected);
+ $this->assertEquals($result, $expected);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php
new file mode 100755
index 0000000..2f52228
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/MessageParserTest.php
@@ -0,0 +1,58 @@
+compareRequestResults($parts, $parser->parseRequest($message));
+ }
+
+ /**
+ * @dataProvider responseProvider
+ */
+ public function testParsesResponses($message, $parts)
+ {
+ $parser = new MessageParser();
+ $this->compareResponseResults($parts, $parser->parseResponse($message));
+ }
+
+ public function testParsesRequestsWithMissingProtocol()
+ {
+ $parser = new MessageParser();
+ $parts = $parser->parseRequest("GET /\r\nHost: Foo.com\r\n\r\n");
+ $this->assertEquals('GET', $parts['method']);
+ $this->assertEquals('HTTP', $parts['protocol']);
+ $this->assertEquals('1.1', $parts['version']);
+ }
+
+ public function testParsesRequestsWithMissingVersion()
+ {
+ $parser = new MessageParser();
+ $parts = $parser->parseRequest("GET / HTTP\r\nHost: Foo.com\r\n\r\n");
+ $this->assertEquals('GET', $parts['method']);
+ $this->assertEquals('HTTP', $parts['protocol']);
+ $this->assertEquals('1.1', $parts['version']);
+ }
+
+ public function testParsesResponsesWithMissingReasonPhrase()
+ {
+ $parser = new MessageParser();
+ $parts = $parser->parseResponse("HTTP/1.1 200\r\n\r\n");
+ $this->assertEquals('200', $parts['code']);
+ $this->assertEquals('', $parts['reason_phrase']);
+ $this->assertEquals('HTTP', $parts['protocol']);
+ $this->assertEquals('1.1', $parts['version']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php
new file mode 100755
index 0000000..6706e20
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/Message/PeclHttpMessageParserTest.php
@@ -0,0 +1,36 @@
+markTestSkipped('pecl_http is not available.');
+ }
+ }
+
+ /**
+ * @dataProvider requestProvider
+ */
+ public function testParsesRequests($message, $parts)
+ {
+ $parser = new PeclHttpMessageParser();
+ $this->compareRequestResults($parts, $parser->parseRequest($message));
+ }
+
+ /**
+ * @dataProvider responseProvider
+ */
+ public function testParsesResponses($message, $parts)
+ {
+ $parser = new PeclHttpMessageParser();
+ $this->compareResponseResults($parts, $parser->parseResponse($message));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php
new file mode 100755
index 0000000..7675efb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/ParserRegistryTest.php
@@ -0,0 +1,33 @@
+registerParser('foo', $c);
+ $this->assertSame($c, $r->getParser('foo'));
+ }
+
+ public function testReturnsNullWhenNotFound()
+ {
+ $r = new ParserRegistry();
+ $this->assertNull($r->getParser('FOO'));
+ }
+
+ public function testReturnsLazyLoadedDefault()
+ {
+ $r = new ParserRegistry();
+ $c = $r->getParser('cookie');
+ $this->assertInstanceOf('Guzzle\Parser\Cookie\CookieParser', $c);
+ $this->assertSame($c, $r->getParser('cookie'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php
new file mode 100755
index 0000000..a05fc2e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/AbstractUriTemplateTest.php
@@ -0,0 +1,113 @@
+ 'value',
+ 'hello' => 'Hello World!',
+ 'empty' => '',
+ 'path' => '/foo/bar',
+ 'x' => '1024',
+ 'y' => '768',
+ 'null' => null,
+ 'list' => array('red', 'green', 'blue'),
+ 'keys' => array(
+ "semi" => ';',
+ "dot" => '.',
+ "comma" => ','
+ ),
+ 'empty_keys' => array(),
+ );
+
+ return array_map(function($t) use ($params) {
+ $t[] = $params;
+ return $t;
+ }, array(
+ array('foo', 'foo'),
+ array('{var}', 'value'),
+ array('{hello}', 'Hello%20World%21'),
+ array('{+var}', 'value'),
+ array('{+hello}', 'Hello%20World!'),
+ array('{+path}/here', '/foo/bar/here'),
+ array('here?ref={+path}', 'here?ref=/foo/bar'),
+ array('X{#var}', 'X#value'),
+ array('X{#hello}', 'X#Hello%20World!'),
+ array('map?{x,y}', 'map?1024,768'),
+ array('{x,hello,y}', '1024,Hello%20World%21,768'),
+ array('{+x,hello,y}', '1024,Hello%20World!,768'),
+ array('{+path,x}/here', '/foo/bar,1024/here'),
+ array('{#x,hello,y}', '#1024,Hello%20World!,768'),
+ array('{#path,x}/here', '#/foo/bar,1024/here'),
+ array('X{.var}', 'X.value'),
+ array('X{.x,y}', 'X.1024.768'),
+ array('{/var}', '/value'),
+ array('{/var,x}/here', '/value/1024/here'),
+ array('{;x,y}', ';x=1024;y=768'),
+ array('{;x,y,empty}', ';x=1024;y=768;empty'),
+ array('{?x,y}', '?x=1024&y=768'),
+ array('{?x,y,empty}', '?x=1024&y=768&empty='),
+ array('?fixed=yes{&x}', '?fixed=yes&x=1024'),
+ array('{&x,y,empty}', '&x=1024&y=768&empty='),
+ array('{var:3}', 'val'),
+ array('{var:30}', 'value'),
+ array('{list}', 'red,green,blue'),
+ array('{list*}', 'red,green,blue'),
+ array('{keys}', 'semi,%3B,dot,.,comma,%2C'),
+ array('{keys*}', 'semi=%3B,dot=.,comma=%2C'),
+ array('{+path:6}/here', '/foo/b/here'),
+ array('{+list}', 'red,green,blue'),
+ array('{+list*}', 'red,green,blue'),
+ array('{+keys}', 'semi,;,dot,.,comma,,'),
+ array('{+keys*}', 'semi=;,dot=.,comma=,'),
+ array('{#path:6}/here', '#/foo/b/here'),
+ array('{#list}', '#red,green,blue'),
+ array('{#list*}', '#red,green,blue'),
+ array('{#keys}', '#semi,;,dot,.,comma,,'),
+ array('{#keys*}', '#semi=;,dot=.,comma=,'),
+ array('X{.var:3}', 'X.val'),
+ array('X{.list}', 'X.red,green,blue'),
+ array('X{.list*}', 'X.red.green.blue'),
+ array('X{.keys}', 'X.semi,%3B,dot,.,comma,%2C'),
+ array('X{.keys*}', 'X.semi=%3B.dot=..comma=%2C'),
+ array('{/var:1,var}', '/v/value'),
+ array('{/list}', '/red,green,blue'),
+ array('{/list*}', '/red/green/blue'),
+ array('{/list*,path:4}', '/red/green/blue/%2Ffoo'),
+ array('{/keys}', '/semi,%3B,dot,.,comma,%2C'),
+ array('{/keys*}', '/semi=%3B/dot=./comma=%2C'),
+ array('{;hello:5}', ';hello=Hello'),
+ array('{;list}', ';list=red,green,blue'),
+ array('{;list*}', ';list=red;list=green;list=blue'),
+ array('{;keys}', ';keys=semi,%3B,dot,.,comma,%2C'),
+ array('{;keys*}', ';semi=%3B;dot=.;comma=%2C'),
+ array('{?var:3}', '?var=val'),
+ array('{?list}', '?list=red,green,blue'),
+ array('{?list*}', '?list=red&list=green&list=blue'),
+ array('{?keys}', '?keys=semi,%3B,dot,.,comma,%2C'),
+ array('{?keys*}', '?semi=%3B&dot=.&comma=%2C'),
+ array('{&var:3}', '&var=val'),
+ array('{&list}', '&list=red,green,blue'),
+ array('{&list*}', '&list=red&list=green&list=blue'),
+ array('{&keys}', '&keys=semi,%3B,dot,.,comma,%2C'),
+ array('{&keys*}', '&semi=%3B&dot=.&comma=%2C'),
+ array('{.null}', ''),
+ array('{.null,var}', '.value'),
+ array('X{.empty_keys*}', 'X'),
+ array('X{.empty_keys}', 'X'),
+ // Test that missing expansions are skipped
+ array('test{&missing*}', 'test'),
+ // Test that multiple expansions can be set
+ array('http://{var}/{var:2}{?keys*}', 'http://value/va?semi=%3B&dot=.&comma=%2C'),
+ // Test more complex query string stuff
+ array('http://www.test.com{+path}{?var,keys*}', 'http://www.test.com/foo/bar?var=value&semi=%3B&dot=.&comma=%2C')
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php
new file mode 100755
index 0000000..633c5d5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/PeclUriTemplateTest.php
@@ -0,0 +1,27 @@
+markTestSkipped('uri_template PECL extension must be installed to test PeclUriTemplate');
+ }
+ }
+
+ /**
+ * @dataProvider templateProvider
+ */
+ public function testExpandsUriTemplates($template, $expansion, $params)
+ {
+ $uri = new PeclUriTemplate($template);
+ $this->assertEquals($expansion, $uri->expand($template, $params));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php
new file mode 100755
index 0000000..5130d6f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Parser/UriTemplate/UriTemplateTest.php
@@ -0,0 +1,106 @@
+assertEquals($expansion, $uri->expand($template, $params));
+ }
+
+ public function expressionProvider()
+ {
+ return array(
+ array(
+ '{+var*}', array(
+ 'operator' => '+',
+ 'values' => array(
+ array('value' => 'var', 'modifier' => '*')
+ )
+ ),
+ ),
+ array(
+ '{?keys,var,val}', array(
+ 'operator' => '?',
+ 'values' => array(
+ array('value' => 'keys', 'modifier' => ''),
+ array('value' => 'var', 'modifier' => ''),
+ array('value' => 'val', 'modifier' => '')
+ )
+ ),
+ ),
+ array(
+ '{+x,hello,y}', array(
+ 'operator' => '+',
+ 'values' => array(
+ array('value' => 'x', 'modifier' => ''),
+ array('value' => 'hello', 'modifier' => ''),
+ array('value' => 'y', 'modifier' => '')
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider expressionProvider
+ */
+ public function testParsesExpressions($exp, $data)
+ {
+ $template = new UriTemplate($exp);
+
+ // Access the config object
+ $class = new \ReflectionClass($template);
+ $method = $class->getMethod('parseExpression');
+ $method->setAccessible(true);
+
+ $exp = substr($exp, 1, -1);
+ $this->assertEquals($data, $method->invokeArgs($template, array($exp)));
+ }
+
+ /**
+ * @ticket https://github.com/guzzle/guzzle/issues/90
+ */
+ public function testAllowsNestedArrayExpansion()
+ {
+ $template = new UriTemplate();
+
+ $result = $template->expand('http://example.com{+path}{/segments}{?query,data*,foo*}', array(
+ 'path' => '/foo/bar',
+ 'segments' => array('one', 'two'),
+ 'query' => 'test',
+ 'data' => array(
+ 'more' => array('fun', 'ice cream')
+ ),
+ 'foo' => array(
+ 'baz' => array(
+ 'bar' => 'fizz',
+ 'test' => 'buzz'
+ ),
+ 'bam' => 'boo'
+ )
+ ));
+
+ $this->assertEquals('http://example.com/foo/bar/one,two?query=test&more%5B0%5D=fun&more%5B1%5D=ice%20cream&baz%5Bbar%5D=fizz&baz%5Btest%5D=buzz&bam=boo', $result);
+ }
+
+ /**
+ * @ticket https://github.com/guzzle/guzzle/issues/426
+ */
+ public function testSetRegex()
+ {
+ $template = new UriTemplate();
+ $template->setRegex('/\<\$(.+)\>/');
+ $this->assertSame('/foo', $template->expand('/<$a>', array('a' => 'foo')));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php
new file mode 100755
index 0000000..16990a5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Async/AsyncPluginTest.php
@@ -0,0 +1,93 @@
+assertArrayHasKey('request.before_send', $events);
+ $this->assertArrayHasKey('request.exception', $events);
+ $this->assertArrayHasKey('curl.callback.progress', $events);
+ }
+
+ public function testEnablesProgressCallbacks()
+ {
+ $p = new AsyncPlugin();
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com');
+ $event = new Event(array(
+ 'request' => $request
+ ));
+ $p->onBeforeSend($event);
+ $this->assertEquals(true, $request->getCurlOptions()->get('progress'));
+ }
+
+ public function testAddsTimesOutAfterSending()
+ {
+ $p = new AsyncPlugin();
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com');
+ $handle = CurlHandle::factory($request);
+ $event = new Event(array(
+ 'request' => $request,
+ 'handle' => $handle->getHandle(),
+ 'uploaded' => 10,
+ 'upload_size' => 10,
+ 'downloaded' => 0
+ ));
+ $p->onCurlProgress($event);
+ }
+
+ public function testEnsuresRequestIsSet()
+ {
+ $p = new AsyncPlugin();
+ $event = new Event(array(
+ 'uploaded' => 10,
+ 'upload_size' => 10,
+ 'downloaded' => 0
+ ));
+ $p->onCurlProgress($event);
+ }
+
+ public function testMasksCurlExceptions()
+ {
+ $p = new AsyncPlugin();
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com');
+ $e = new CurlException('Error');
+ $event = new Event(array(
+ 'request' => $request,
+ 'exception' => $e
+ ));
+ $p->onRequestTimeout($event);
+ $this->assertEquals(RequestInterface::STATE_COMPLETE, $request->getState());
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+ $this->assertTrue($request->getResponse()->hasHeader('X-Guzzle-Async'));
+ }
+
+ public function testEnsuresIntegration()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 204 FOO\r\nContent-Length: 4\r\n\r\ntest");
+ $client = new Client($this->getServer()->getUrl());
+ $request = $client->post('/', null, array(
+ 'foo' => 'bar'
+ ));
+ $request->getEventDispatcher()->addSubscriber(new AsyncPlugin());
+ $request->send();
+ $this->assertEquals('', $request->getResponse()->getBody(true));
+ $this->assertTrue($request->getResponse()->hasHeader('X-Guzzle-Async'));
+ $received = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals('POST', $received[0]->getMethod());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php
new file mode 100755
index 0000000..72af263
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/AbstractBackoffStrategyTest.php
@@ -0,0 +1,86 @@
+getMockBuilder('Guzzle\Plugin\Backoff\AbstractBackoffStrategy')
+ ->setMethods(array('getDelay', 'makesDecision'))
+ ->getMockForAbstractClass();
+ }
+
+ public function testReturnsZeroWhenNoNextAndGotNull()
+ {
+ $request = new Request('GET', 'http://www.foo.com');
+ $mock = $this->getMockStrategy();
+ $mock->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(null));
+ $this->assertEquals(0, $mock->getBackoffPeriod(0, $request));
+ }
+
+ public function testReturnsFalse()
+ {
+ $request = new Request('GET', 'http://www.foo.com');
+ $mock = $this->getMockStrategy();
+ $mock->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(false));
+ $this->assertEquals(false, $mock->getBackoffPeriod(0, $request));
+ }
+
+ public function testReturnsNextValueWhenNullOrTrue()
+ {
+ $request = new Request('GET', 'http://www.foo.com');
+ $mock = $this->getMockStrategy();
+ $mock->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(null));
+ $mock->expects($this->any())->method('makesDecision')->will($this->returnValue(false));
+
+ $mock2 = $this->getMockStrategy();
+ $mock2->expects($this->atLeastOnce())->method('getDelay')->will($this->returnValue(10));
+ $mock2->expects($this->atLeastOnce())->method('makesDecision')->will($this->returnValue(true));
+ $mock->setNext($mock2);
+
+ $this->assertEquals(10, $mock->getBackoffPeriod(0, $request));
+ }
+
+ public function testReturnsFalseWhenNullAndNoNext()
+ {
+ $request = new Request('GET', 'http://www.foo.com');
+ $s = new TruncatedBackoffStrategy(2);
+ $this->assertFalse($s->getBackoffPeriod(0, $request));
+ }
+
+ public function testHasNext()
+ {
+ $a = new TruncatedBackoffStrategy(2);
+ $b = new TruncatedBackoffStrategy(2);
+ $a->setNext($b);
+ $this->assertSame($b, $a->getNext());
+ }
+
+ public function testSkipsOtherDecisionsInChainWhenOneReturnsTrue()
+ {
+ $a = new CallbackBackoffStrategy(function () { return null; }, true);
+ $b = new CallbackBackoffStrategy(function () { return true; }, true);
+ $c = new CallbackBackoffStrategy(function () { return null; }, true);
+ $d = new CallbackBackoffStrategy(function () { return 10; }, false);
+ $a->setNext($b);
+ $b->setNext($c);
+ $c->setNext($d);
+ $this->assertEquals(10, $a->getBackoffPeriod(2, new Request('GET', 'http://www.foo.com')));
+ }
+
+ public function testReturnsZeroWhenDecisionMakerReturnsTrueButNoFurtherStrategiesAreInTheChain()
+ {
+ $a = new CallbackBackoffStrategy(function () { return null; }, true);
+ $b = new CallbackBackoffStrategy(function () { return true; }, true);
+ $a->setNext($b);
+ $this->assertSame(0, $a->getBackoffPeriod(2, new Request('GET', 'http://www.foo.com')));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php
new file mode 100755
index 0000000..a64dd82
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffLoggerTest.php
@@ -0,0 +1,110 @@
+message = '';
+ }
+
+ public function testHasEventList()
+ {
+ $this->assertEquals(1, count(BackoffLogger::getSubscribedEvents()));
+ }
+
+ public function testLogsEvents()
+ {
+ list($logPlugin, $request, $response) = $this->getMocks();
+
+ $response = $this->getMockBuilder('Guzzle\Http\Message\Response')
+ ->setConstructorArgs(array(503))
+ ->setMethods(array('getInfo'))
+ ->getMock();
+
+ $response->expects($this->any())
+ ->method('getInfo')
+ ->will($this->returnValue(2));
+
+ $handle = $this->getMockHandle();
+
+ $event = new Event(array(
+ 'request' => $request,
+ 'response' => $response,
+ 'retries' => 1,
+ 'delay' => 3,
+ 'handle' => $handle
+ ));
+
+ $logPlugin->onRequestRetry($event);
+ $this->assertContains(
+ '] PUT http://www.example.com - 503 Service Unavailable - Retries: 1, Delay: 3, Time: 2, 2, cURL: 30 Foo',
+ $this->message
+ );
+ }
+
+ public function testCanSetTemplate()
+ {
+ $l = new BackoffLogger(new ClosureLogAdapter(function () {}));
+ $l->setTemplate('foo');
+ $t = $this->readAttribute($l, 'formatter');
+ $this->assertEquals('foo', $this->readAttribute($t, 'template'));
+ }
+
+ /**
+ * @return array
+ */
+ protected function getMocks()
+ {
+ $that = $this;
+ $logger = new ClosureLogAdapter(function ($message) use ($that) {
+ $that->message .= $message . "\n";
+ });
+ $logPlugin = new BackoffLogger($logger);
+ $response = new Response(503);
+ $request = RequestFactory::getInstance()->create('PUT', 'http://www.example.com', array(
+ 'Content-Length' => 3,
+ 'Foo' => 'Bar'
+ ));
+
+ return array($logPlugin, $request, $response);
+ }
+
+ /**
+ * @return CurlHandle
+ */
+ protected function getMockHandle()
+ {
+ $handle = $this->getMockBuilder('Guzzle\Http\Curl\CurlHandle')
+ ->disableOriginalConstructor()
+ ->setMethods(array('getError', 'getErrorNo', 'getInfo'))
+ ->getMock();
+
+ $handle->expects($this->once())
+ ->method('getError')
+ ->will($this->returnValue('Foo'));
+
+ $handle->expects($this->once())
+ ->method('getErrorNo')
+ ->will($this->returnValue(30));
+
+ $handle->expects($this->any())
+ ->method('getInfo')
+ ->will($this->returnValue(2));
+
+ return $handle;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php
new file mode 100755
index 0000000..496e49e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/BackoffPluginTest.php
@@ -0,0 +1,297 @@
+retried = false;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(BackoffPlugin::RETRY_EVENT => 'onRequestRetry');
+ }
+
+ public function onRequestRetry(Event $event)
+ {
+ $this->retried = $event;
+ }
+
+ public function testHasEventList()
+ {
+ $this->assertEquals(1, count(BackoffPlugin::getAllEvents()));
+ }
+
+ public function testCreatesDefaultExponentialBackoffPlugin()
+ {
+ $plugin = BackoffPlugin::getExponentialBackoff(3, array(204), array(10));
+ $this->assertInstanceOf('Guzzle\Plugin\Backoff\BackoffPlugin', $plugin);
+ $strategy = $this->readAttribute($plugin, 'strategy');
+ $this->assertInstanceOf('Guzzle\Plugin\Backoff\TruncatedBackoffStrategy', $strategy);
+ $this->assertEquals(3, $this->readAttribute($strategy, 'max'));
+ $strategy = $this->readAttribute($strategy, 'next');
+ $this->assertInstanceOf('Guzzle\Plugin\Backoff\HttpBackoffStrategy', $strategy);
+ $this->assertEquals(array(204 => true), $this->readAttribute($strategy, 'errorCodes'));
+ $strategy = $this->readAttribute($strategy, 'next');
+ $this->assertInstanceOf('Guzzle\Plugin\Backoff\CurlBackoffStrategy', $strategy);
+ $this->assertEquals(array(10 => true), $this->readAttribute($strategy, 'errorCodes'));
+ $strategy = $this->readAttribute($strategy, 'next');
+ $this->assertInstanceOf('Guzzle\Plugin\Backoff\ExponentialBackoffStrategy', $strategy);
+ }
+
+ public function testDoesNotRetryUnlessStrategyReturnsNumber()
+ {
+ $request = new Request('GET', 'http://www.example.com');
+ $request->setState('transfer');
+
+ $mock = $this->getMockBuilder('Guzzle\Plugin\Backoff\BackoffStrategyInterface')
+ ->setMethods(array('getBackoffPeriod'))
+ ->getMockForAbstractClass();
+
+ $mock->expects($this->once())
+ ->method('getBackoffPeriod')
+ ->will($this->returnValue(false));
+
+ $plugin = new BackoffPlugin($mock);
+ $plugin->addSubscriber($this);
+ $plugin->onRequestSent(new Event(array('request' => $request)));
+ $this->assertFalse($this->retried);
+ }
+
+ public function testUpdatesRequestForRetry()
+ {
+ $request = new Request('GET', 'http://www.example.com');
+ $request->setState('transfer');
+ $response = new Response(500);
+ $handle = $this->getMockBuilder('Guzzle\Http\Curl\CurlHandle')->disableOriginalConstructor()->getMock();
+ $e = new CurlException();
+ $e->setCurlHandle($handle);
+
+ $plugin = new BackoffPlugin(new ConstantBackoffStrategy(10));
+ $plugin->addSubscriber($this);
+
+ $event = new Event(array(
+ 'request' => $request,
+ 'response' => $response,
+ 'exception' => $e
+ ));
+
+ $plugin->onRequestSent($event);
+ $this->assertEquals(array(
+ 'request' => $request,
+ 'response' => $response,
+ 'handle' => $handle,
+ 'retries' => 1,
+ 'delay' => 10
+ ), $this->readAttribute($this->retried, 'context'));
+
+ $plugin->onRequestSent($event);
+ $this->assertEquals(array(
+ 'request' => $request,
+ 'response' => $response,
+ 'handle' => $handle,
+ 'retries' => 2,
+ 'delay' => 10
+ ), $this->readAttribute($this->retried, 'context'));
+ }
+
+ public function testDoesNothingWhenNotRetryingAndPollingRequest()
+ {
+ $request = new Request('GET', 'http://www.foo.com');
+ $plugin = new BackoffPlugin(new ConstantBackoffStrategy(10));
+ $plugin->onRequestPoll(new Event(array('request' => $request)));
+ }
+
+ public function testRetriesRequests()
+ {
+ // Create a script to return several 500 and 503 response codes
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"
+ ));
+
+ $plugin = new BackoffPlugin(
+ new TruncatedBackoffStrategy(3,
+ new HttpBackoffStrategy(null,
+ new CurlBackoffStrategy(null,
+ new ConstantBackoffStrategy(0.05)
+ )
+ )
+ )
+ );
+
+ $client = new Client($this->getServer()->getUrl());
+ $client->getEventDispatcher()->addSubscriber($plugin);
+ $request = $client->get();
+ $request->send();
+
+ // Make sure it eventually completed successfully
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+ $this->assertEquals('data', $request->getResponse()->getBody(true));
+
+ // Check that three requests were made to retry this request
+ $this->assertEquals(3, count($this->getServer()->getReceivedRequests(false)));
+ $this->assertEquals(2, $request->getParams()->get(BackoffPlugin::RETRY_PARAM));
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\ServerErrorResponseException
+ */
+ public function testFailsOnTruncation()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n"
+ ));
+
+ $plugin = new BackoffPlugin(
+ new TruncatedBackoffStrategy(2,
+ new HttpBackoffStrategy(null,
+ new ConstantBackoffStrategy(0.05)
+ )
+ )
+ );
+
+ $client = new Client($this->getServer()->getUrl());
+ $client->addSubscriber($plugin);
+ $client->get()->send();
+ }
+
+ public function testRetriesRequestsWhenInParallel()
+ {
+ // Create a script to return several 500 and 503 response codes
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"
+ ));
+
+ $plugin = new BackoffPlugin(
+ new HttpBackoffStrategy(null,
+ new TruncatedBackoffStrategy(3,
+ new CurlBackoffStrategy(null,
+ new ConstantBackoffStrategy(0.1)
+ )
+ )
+ )
+ );
+ $client = new Client($this->getServer()->getUrl());
+ $client->getEventDispatcher()->addSubscriber($plugin);
+ $requests = array();
+ for ($i = 0; $i < 5; $i++) {
+ $requests[] = $client->get();
+ }
+ $client->send($requests);
+
+ $this->assertEquals(15, count($this->getServer()->getReceivedRequests(false)));
+ }
+
+ /**
+ * @covers Guzzle\Plugin\Backoff\BackoffPlugin
+ * @covers Guzzle\Http\Curl\CurlMulti
+ */
+ public function testRetriesPooledRequestsUsingDelayAndPollingEvent()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ndata"
+ ));
+ // Need to sleep for some time ensure that the polling works correctly in the observer
+ $plugin = new BackoffPlugin(new HttpBackoffStrategy(null,
+ new TruncatedBackoffStrategy(1,
+ new ConstantBackoffStrategy(0.5))));
+
+ $client = new Client($this->getServer()->getUrl());
+ $client->getEventDispatcher()->addSubscriber($plugin);
+ $request = $client->get();
+ $request->send();
+ // Make sure it eventually completed successfully
+ $this->assertEquals('data', $request->getResponse()->getBody(true));
+ // Check that two requests were made to retry this request
+ $this->assertEquals(2, count($this->getServer()->getReceivedRequests(false)));
+ }
+
+ public function testSeeksToBeginningOfRequestBodyWhenRetrying()
+ {
+ // Create a request with a body
+ $request = new EntityEnclosingRequest('PUT', 'http://www.example.com');
+ $request->setBody('abc');
+ // Set the retry time to be something that will be retried always
+ $request->getParams()->set(BackoffPlugin::DELAY_PARAM, 2);
+ // Seek to the end of the stream
+ $request->getBody()->seek(3);
+ $this->assertEquals('', $request->getBody()->read(1));
+ // Create a plugin that does not delay when retrying
+ $plugin = new BackoffPlugin(new ConstantBackoffStrategy(0));
+ $plugin->onRequestPoll($this->getMockEvent($request));
+ // Ensure that the stream was seeked to 0
+ $this->assertEquals('a', $request->getBody()->read(1));
+ }
+
+ public function testDoesNotSeekOnRequestsWithNoBodyWhenRetrying()
+ {
+ // Create a request with a body
+ $request = new EntityEnclosingRequest('PUT', 'http://www.example.com');
+ $request->getParams()->set(BackoffPlugin::DELAY_PARAM, 2);
+ $plugin = new BackoffPlugin(new ConstantBackoffStrategy(0));
+ $plugin->onRequestPoll($this->getMockEvent($request));
+ }
+
+ protected function getMockEvent(RequestInterface $request)
+ {
+ // Create a mock curl multi object
+ $multi = $this->getMockBuilder('Guzzle\Http\Curl\CurlMulti')
+ ->setMethods(array('remove', 'add'))
+ ->getMock();
+
+ // Create an event that is expected for the Poll event
+ $event = new Event(array(
+ 'request' => $request,
+ 'curl_multi' => $multi
+ ));
+ $event->setName(CurlMultiInterface::POLLING_REQUEST);
+
+ return $event;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php
new file mode 100755
index 0000000..c0ce10d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CallbackBackoffStrategyTest.php
@@ -0,0 +1,31 @@
+getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $strategy = new CallbackBackoffStrategy(function () { return 10; }, true);
+ $this->assertTrue($strategy->makesDecision());
+ $this->assertEquals(10, $strategy->getBackoffPeriod(0, $request));
+ // Ensure it chains correctly when null is returned
+ $strategy = new CallbackBackoffStrategy(function () { return null; }, false);
+ $this->assertFalse($strategy->makesDecision());
+ $this->assertFalse($strategy->getBackoffPeriod(0, $request));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php
new file mode 100755
index 0000000..703eb4a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ConstantBackoffStrategyTest.php
@@ -0,0 +1,20 @@
+assertFalse($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertEquals(3.5, $strategy->getBackoffPeriod(0, $request));
+ $this->assertEquals(3.5, $strategy->getBackoffPeriod(1, $request));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php
new file mode 100755
index 0000000..0a5c3e2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/CurlBackoffStrategyTest.php
@@ -0,0 +1,36 @@
+assertNotEmpty(CurlBackoffStrategy::getDefaultFailureCodes());
+ $strategy = new CurlBackoffStrategy();
+ $this->assertTrue($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $e = new CurlException();
+ $e->setError('foo', CURLE_BAD_CALLING_ORDER);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, null, $e));
+
+ foreach (CurlBackoffStrategy::getDefaultFailureCodes() as $code) {
+ $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, null, $e->setError('foo', $code)));
+ }
+ }
+
+ public function testIgnoresNonErrors()
+ {
+ $strategy = new CurlBackoffStrategy();
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, new Response(200)));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php
new file mode 100755
index 0000000..09965bc
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ExponentialBackoffStrategyTest.php
@@ -0,0 +1,23 @@
+assertFalse($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertEquals(1, $strategy->getBackoffPeriod(0, $request));
+ $this->assertEquals(2, $strategy->getBackoffPeriod(1, $request));
+ $this->assertEquals(4, $strategy->getBackoffPeriod(2, $request));
+ $this->assertEquals(8, $strategy->getBackoffPeriod(3, $request));
+ $this->assertEquals(16, $strategy->getBackoffPeriod(4, $request));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php
new file mode 100755
index 0000000..ae68a4e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/HttpBackoffStrategyTest.php
@@ -0,0 +1,47 @@
+assertNotEmpty(HttpBackoffStrategy::getDefaultFailureCodes());
+ $strategy = new HttpBackoffStrategy();
+ $this->assertTrue($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+
+ $response = new Response(200);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response));
+ $response->setStatus(400);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response));
+
+ foreach (HttpBackoffStrategy::getDefaultFailureCodes() as $code) {
+ $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, $response->setStatus($code)));
+ }
+ }
+
+ public function testAllowsCustomCodes()
+ {
+ $strategy = new HttpBackoffStrategy(array(204));
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $response = new Response(204);
+ $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, $response));
+ $response->setStatus(500);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response));
+ }
+
+ public function testIgnoresNonErrors()
+ {
+ $strategy = new HttpBackoffStrategy();
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php
new file mode 100755
index 0000000..b4ce8e4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/LinearBackoffStrategyTest.php
@@ -0,0 +1,21 @@
+assertFalse($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request));
+ $this->assertEquals(5, $strategy->getBackoffPeriod(1, $request));
+ $this->assertEquals(10, $strategy->getBackoffPeriod(2, $request));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php
new file mode 100755
index 0000000..dea5a68
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/ReasonPhraseBackoffStrategyTest.php
@@ -0,0 +1,32 @@
+assertEmpty(ReasonPhraseBackoffStrategy::getDefaultFailureCodes());
+ $strategy = new ReasonPhraseBackoffStrategy(array('Foo', 'Internal Server Error'));
+ $this->assertTrue($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $response = new Response(200);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request, $response));
+ $response->setStatus(200, 'Foo');
+ $this->assertEquals(0, $strategy->getBackoffPeriod(0, $request, $response));
+ }
+
+ public function testIgnoresNonErrors()
+ {
+ $strategy = new ReasonPhraseBackoffStrategy();
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertEquals(false, $strategy->getBackoffPeriod(0, $request));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php
new file mode 100755
index 0000000..5590dfb
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Backoff/TruncatedBackoffStrategyTest.php
@@ -0,0 +1,30 @@
+assertTrue($strategy->makesDecision());
+ $request = $this->getMock('Guzzle\Http\Message\Request', array(), array(), '', false);
+ $this->assertFalse($strategy->getBackoffPeriod(0, $request));
+ $this->assertFalse($strategy->getBackoffPeriod(1, $request));
+ $this->assertFalse($strategy->getBackoffPeriod(2, $request));
+
+ $response = new Response(500);
+ $strategy->setNext(new HttpBackoffStrategy(null, new ConstantBackoffStrategy(10)));
+ $this->assertEquals(10, $strategy->getBackoffPeriod(0, $request, $response));
+ $this->assertEquals(10, $strategy->getBackoffPeriod(1, $request, $response));
+ $this->assertFalse($strategy->getBackoffPeriod(2, $request, $response));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php
new file mode 100755
index 0000000..69da60a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CachePluginTest.php
@@ -0,0 +1,441 @@
+assertInstanceOf('Guzzle\Plugin\Cache\CacheStorageInterface', $this->readAttribute($plugin, 'storage'));
+ }
+
+ public function testAddsDefaultCollaborators()
+ {
+ $this->assertNotEmpty(CachePlugin::getSubscribedEvents());
+ $plugin = new CachePlugin(array(
+ 'storage' => $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')->getMockForAbstractClass()
+ ));
+ $this->assertInstanceOf('Guzzle\Plugin\Cache\CacheStorageInterface', $this->readAttribute($plugin, 'storage'));
+ $this->assertInstanceOf(
+ 'Guzzle\Plugin\Cache\CanCacheStrategyInterface',
+ $this->readAttribute($plugin, 'canCache')
+ );
+ $this->assertInstanceOf(
+ 'Guzzle\Plugin\Cache\RevalidationInterface',
+ $this->readAttribute($plugin, 'revalidation')
+ );
+ }
+
+ public function testAddsCallbackCollaborators()
+ {
+ $this->assertNotEmpty(CachePlugin::getSubscribedEvents());
+ $plugin = new CachePlugin(array('can_cache' => function () {}));
+ $this->assertInstanceOf(
+ 'Guzzle\Plugin\Cache\CallbackCanCacheStrategy',
+ $this->readAttribute($plugin, 'canCache')
+ );
+ }
+
+ public function testCanPassCacheAsOnlyArgumentToConstructor()
+ {
+ $p = new CachePlugin(new DoctrineCacheAdapter(new ArrayCache()));
+ $p = new CachePlugin(new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache())));
+ }
+
+ public function testUsesCreatedCacheStorage()
+ {
+ $plugin = new CachePlugin(array(
+ 'adapter' => $this->getMockBuilder('Guzzle\Cache\CacheAdapterInterface')->getMockForAbstractClass()
+ ));
+ $this->assertInstanceOf('Guzzle\Plugin\Cache\CacheStorageInterface', $this->readAttribute($plugin, 'storage'));
+ }
+
+ public function testUsesProvidedOptions()
+ {
+ $can = $this->getMockBuilder('Guzzle\Plugin\Cache\CanCacheStrategyInterface')->getMockForAbstractClass();
+ $revalidate = $this->getMockBuilder('Guzzle\Plugin\Cache\RevalidationInterface')->getMockForAbstractClass();
+ $plugin = new CachePlugin(array(
+ 'storage' => $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')->getMockForAbstractClass(),
+ 'can_cache' => $can,
+ 'revalidation' => $revalidate
+ ));
+ $this->assertSame($can, $this->readAttribute($plugin, 'canCache'));
+ $this->assertSame($revalidate, $this->readAttribute($plugin, 'revalidation'));
+ }
+
+ public function satisfyProvider()
+ {
+ $req1 = new Request('GET', 'http://foo.com', array('Cache-Control' => 'no-cache'));
+
+ return array(
+ // The response is too old to satisfy the request
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-age=20')), new Response(200, array('Age' => 100)), false, false),
+ // The response cannot satisfy the request because it is stale
+ array(new Request('GET', 'http://foo.com'), new Response(200, array('Cache-Control' => 'max-age=10', 'Age' => 100)), false, false),
+ // Allows the expired response to satisfy the request because of the max-stale
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale=15')), new Response(200, array('Cache-Control' => 'max-age=90', 'Age' => 100)), true, false),
+ // Max stale is > than the allowed staleness
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale=5')), new Response(200, array('Cache-Control' => 'max-age=90', 'Age' => 100)), false, false),
+ // Performs cache revalidation
+ array($req1, new Response(200), true, true),
+ // Performs revalidation due to ETag on the response and no cache-control on the request
+ array(new Request('GET', 'http://foo.com'), new Response(200, array(
+ 'ETag' => 'ABC',
+ 'Expires' => date('c', strtotime('+1 year'))
+ )), true, true),
+ );
+ }
+
+ /**
+ * @dataProvider satisfyProvider
+ */
+ public function testChecksIfResponseCanSatisfyRequest($request, $response, $can, $revalidates)
+ {
+ $didRevalidate = false;
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')->getMockForAbstractClass();
+ $revalidate = $this->getMockBuilder('Guzzle\Plugin\Cache\DefaultRevalidation')
+ ->setMethods(array('revalidate'))
+ ->setConstructorArgs(array($storage))
+ ->getMockForAbstractClass();
+
+ $revalidate->expects($this->any())
+ ->method('revalidate')
+ ->will($this->returnCallback(function () use (&$didRevalidate) {
+ $didRevalidate = true;
+ return true;
+ }));
+
+ $plugin = new CachePlugin(array(
+ 'storage' => $storage,
+ 'revalidation' => $revalidate
+ ));
+
+ $this->assertEquals($can, $plugin->canResponseSatisfyRequest($request, $response));
+ $this->assertEquals($didRevalidate, $revalidates);
+ }
+
+ public function satisfyFailedProvider()
+ {
+ return array(
+ // Neither has stale-if-error
+ array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100)), false),
+ // Request has stale-if-error
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50')), true),
+ // Request has valid stale-if-error
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=50')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50')), true),
+ // Request has expired stale-if-error
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=20')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50')), false),
+ // Response has permanent stale-if-error
+ array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error', )), true),
+ // Response has valid stale-if-error
+ array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=50')), true),
+ // Response has expired stale-if-error
+ array(new Request('GET', 'http://foo.com', array()), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=20')), false),
+ // Request has valid stale-if-error but response does not
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=50')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=20')), false),
+ // Response has valid stale-if-error but request does not
+ array(new Request('GET', 'http://foo.com', array('Cache-Control' => 'stale-if-error=20')), new Response(200, array('Age' => 100, 'Cache-Control' => 'max-age=50, stale-if-error=50')), false),
+ );
+ }
+
+ /**
+ * @dataProvider satisfyFailedProvider
+ */
+ public function testChecksIfResponseCanSatisfyFailedRequest($request, $response, $can)
+ {
+ $plugin = new CachePlugin();
+
+ $this->assertEquals($can, $plugin->canResponseSatisfyFailedRequest($request, $response));
+ }
+
+ public function testDoesNothingWhenRequestIsNotCacheable()
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->never())->method('fetch');
+
+ $plugin = new CachePlugin(array(
+ 'storage' => $storage,
+ 'can_cache' => new CallbackCanCacheStrategy(function () { return false; })
+ ));
+
+ $plugin->onRequestBeforeSend(new Event(array(
+ 'request' => new Request('GET', 'http://foo.com')
+ )));
+ }
+
+ public function satisfiableProvider()
+ {
+ $date = new \DateTime('-10 seconds');
+
+ return array(
+ // Fresh response
+ array(new Response(200, array(), 'foo')),
+ // Stale response
+ array(new Response(200, array('Date' => $date->format('c'), 'Cache-Control' => 'max-age=5'), 'foo'))
+ );
+ }
+
+ /**
+ * @dataProvider satisfiableProvider
+ */
+ public function testInjectsSatisfiableResponses($response)
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+
+ $storage->expects($this->once())->method('fetch')->will($this->returnValue($response));
+ $plugin = new CachePlugin(array('storage' => $storage));
+ $request = new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale'));
+ $plugin->onRequestBeforeSend(new Event(array('request' => $request)));
+ $plugin->onRequestSent(new Event(array('request' => $request, 'response' => $request->getResponse())));
+ $this->assertEquals($response->getStatusCode(), $request->getResponse()->getStatusCode());
+ $this->assertEquals((string) $response->getBody(), (string) $request->getResponse()->getBody());
+ $this->assertTrue($request->getResponse()->hasHeader('Age'));
+ if ($request->getResponse()->isFresh() === false) {
+ $this->assertContains('110', (string) $request->getResponse()->getHeader('Warning'));
+ }
+ $this->assertSame(
+ sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION),
+ (string) $request->getHeader('Via')
+ );
+ $this->assertSame(
+ sprintf('%s GuzzleCache/%s',$request->getProtocolVersion(), Version::VERSION),
+ (string) $request->getResponse()->getHeader('Via')
+ );
+ $this->assertTrue($request->getParams()->get('cache.lookup'));
+ $this->assertTrue($request->getParams()->get('cache.hit'));
+ $this->assertTrue($request->getResponse()->hasHeader('X-Cache-Lookup'));
+ $this->assertTrue($request->getResponse()->hasHeader('X-Cache'));
+ $this->assertEquals('HIT from GuzzleCache', (string) $request->getResponse()->getHeader('X-Cache'));
+ $this->assertEquals('HIT from GuzzleCache', (string) $request->getResponse()->getHeader('X-Cache-Lookup'));
+ }
+
+ public function satisfiableOnErrorProvider()
+ {
+ $date = new \DateTime('-10 seconds');
+ return array(
+ array(
+ new Response(200, array(
+ 'Date' => $date->format('c'),
+ 'Cache-Control' => 'max-age=5, stale-if-error'
+ ), 'foo'),
+ )
+ );
+ }
+
+ /**
+ * @dataProvider satisfiableOnErrorProvider
+ */
+ public function testInjectsSatisfiableResponsesOnError($cacheResponse)
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->exactly(2))->method('fetch')->will($this->returnValue($cacheResponse));
+ $plugin = new CachePlugin(array('storage' => $storage));
+ $request = new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale'));
+ $plugin->onRequestBeforeSend(new Event(array('request' => $request)));
+ $plugin->onRequestError(
+ $event = new Event(array(
+ 'request' => $request,
+ 'response' => $request->getResponse(),
+ ))
+ );
+ $response = $event['response'];
+ $this->assertEquals($cacheResponse->getStatusCode(), $response->getStatusCode());
+ $this->assertEquals((string) $cacheResponse->getBody(), (string) $response->getBody());
+ $this->assertTrue($response->hasHeader('Age'));
+ if ($response->isFresh() === false) {
+ $this->assertContains('110', (string) $response->getHeader('Warning'));
+ }
+ $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $request->getHeader('Via'));
+ $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $response->getHeader('Via'));
+ $this->assertTrue($request->getParams()->get('cache.lookup'));
+ $this->assertSame('error', $request->getParams()->get('cache.hit'));
+ $this->assertTrue($response->hasHeader('X-Cache-Lookup'));
+ $this->assertTrue($response->hasHeader('X-Cache'));
+ $this->assertEquals('HIT from GuzzleCache', (string) $response->getHeader('X-Cache-Lookup'));
+ $this->assertEquals('HIT_ERROR from GuzzleCache', (string) $response->getHeader('X-Cache'));
+ }
+
+ /**
+ * @dataProvider satisfiableOnErrorProvider
+ */
+ public function testInjectsSatisfiableResponsesOnException($cacheResponse)
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->exactly(2))->method('fetch')->will($this->returnValue($cacheResponse));
+ $plugin = new CachePlugin(array('storage' => $storage));
+ $request = new Request('GET', 'http://foo.com', array('Cache-Control' => 'max-stale'));
+ $plugin->onRequestBeforeSend(new Event(array(
+ 'request' => $request
+ )));
+ $plugin->onRequestException(
+ new Event(array(
+ 'request' => $request,
+ 'response' => $request->getResponse(),
+ 'exception' => $this->getMock('Guzzle\Http\Exception\CurlException'),
+ ))
+ );
+ $plugin->onRequestSent(
+ new Event(array(
+ 'request' => $request,
+ 'response' => $response = $request->getResponse(),
+ ))
+ );
+ $this->assertEquals($cacheResponse->getStatusCode(), $response->getStatusCode());
+ $this->assertEquals((string) $cacheResponse->getBody(), (string) $response->getBody());
+ $this->assertTrue($response->hasHeader('Age'));
+ if ($response->isFresh() === false) {
+ $this->assertContains('110', (string) $response->getHeader('Warning'));
+ }
+ $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $request->getHeader('Via'));
+ $this->assertSame(sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION), (string) $response->getHeader('Via'));
+ $this->assertTrue($request->getParams()->get('cache.lookup'));
+ $this->assertSame('error', $request->getParams()->get('cache.hit'));
+ $this->assertTrue($response->hasHeader('X-Cache-Lookup'));
+ $this->assertTrue($response->hasHeader('X-Cache'));
+ $this->assertEquals('HIT from GuzzleCache', (string) $response->getHeader('X-Cache-Lookup'));
+ $this->assertEquals('HIT_ERROR from GuzzleCache', (string) $response->getHeader('X-Cache'));
+ }
+
+ public function unsatisfiableOnErrorProvider()
+ {
+ $date = new \DateTime('-10 seconds');
+
+ return array(
+ // no-store on request
+ array(
+ false,
+ array('Cache-Control' => 'no-store'),
+ new Response(200, array('Date' => $date->format('D, d M Y H:i:s T'), 'Cache-Control' => 'max-age=5, stale-if-error'), 'foo'),
+ ),
+ // request expired
+ array(
+ true,
+ array('Cache-Control' => 'stale-if-error=4'),
+ new Response(200, array('Date' => $date->format('D, d M Y H:i:s T'), 'Cache-Control' => 'max-age=5, stale-if-error'), 'foo'),
+ ),
+ // response expired
+ array(
+ true,
+ array('Cache-Control' => 'stale-if-error'),
+ new Response(200, array('Date' => $date->format('D, d M Y H:i:s T'), 'Cache-Control' => 'max-age=5, stale-if-error=4'), 'foo'),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider unsatisfiableOnErrorProvider
+ */
+ public function testDoesNotInjectUnsatisfiableResponsesOnError($requestCanCache, $requestHeaders, $cacheResponse)
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->exactly($requestCanCache ? 2 : 0))->method('fetch')->will($this->returnValue($cacheResponse));
+ $plugin = new CachePlugin(array('storage' => $storage));
+ $request = new Request('GET', 'http://foo.com', $requestHeaders);
+ $plugin->onRequestBeforeSend(new Event(array(
+ 'request' => $request
+ )));
+ $plugin->onRequestError(
+ $event = new Event(array(
+ 'request' => $request,
+ 'response' => $response = $request->getResponse(),
+ ))
+ );
+
+ $this->assertSame($response, $event['response']);
+ }
+
+ /**
+ * @dataProvider unsatisfiableOnErrorProvider
+ */
+ public function testDoesNotInjectUnsatisfiableResponsesOnException($requestCanCache, $requestHeaders, $responseParts)
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->exactly($requestCanCache ? 2 : 0))->method('fetch')->will($this->returnValue($responseParts));
+ $plugin = new CachePlugin(array('storage' => $storage));
+ $request = new Request('GET', 'http://foo.com', $requestHeaders);
+ $plugin->onRequestBeforeSend(new Event(array(
+ 'request' => $request
+ )));
+ $plugin->onRequestException(
+ $event = new Event(array(
+ 'request' => $request,
+ 'response' => $response = $request->getResponse(),
+ 'exception' => $this->getMock('Guzzle\Http\Exception\CurlException'),
+ ))
+ );
+
+ $this->assertSame($response, $request->getResponse());
+ }
+
+ public function testCachesResponsesWhenCacheable()
+ {
+ $cache = new ArrayCache();
+ $plugin = new CachePlugin($cache);
+
+ $request = new Request('GET', 'http://foo.com');
+ $response = new Response(200, array(), 'Foo');
+ $plugin->onRequestBeforeSend(new Event(array(
+ 'request' => $request
+ )));
+ $plugin->onRequestSent(new Event(array(
+ 'request' => $request,
+ 'response' => $response
+ )));
+ $data = $this->readAttribute($cache, 'data');
+ $this->assertNotEmpty($data);
+ }
+
+ public function testPurgesRequests()
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('purge'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->atLeastOnce())->method('purge');
+ $plugin = new CachePlugin(array('storage' => $storage));
+ $request = new Request('GET', 'http://foo.com', array('X-Foo' => 'Bar'));
+ $plugin->purge($request);
+ }
+
+ public function testAutoPurgesRequests()
+ {
+ $storage = $this->getMockBuilder('Guzzle\Plugin\Cache\CacheStorageInterface')
+ ->setMethods(array('purge'))
+ ->getMockForAbstractClass();
+ $storage->expects($this->atLeastOnce())->method('purge');
+ $plugin = new CachePlugin(array('storage' => $storage, 'auto_purge' => true));
+ $client = new Client();
+ $request = $client->put('http://foo.com', array('X-Foo' => 'Bar'));
+ $request->addSubscriber($plugin);
+ $request->setResponse(new Response(200), true);
+ $request->send();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php
new file mode 100755
index 0000000..f3d9baf
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/CallbackCanCacheStrategyTest.php
@@ -0,0 +1,72 @@
+assertTrue($c->canCacheRequest(new Request('DELETE', 'http://www.foo.com')));
+ }
+
+ /**
+ * The following is a bit of an integration test to ensure that the CachePlugin honors a
+ * custom can cache strategy.
+ */
+ public function testIntegrationWithCachePlugin()
+ {
+ $c = new CallbackCanCacheStrategy(
+ function ($request) { return true; },
+ function ($response) { return true; }
+ );
+
+ // Make a request and response that have no business being cached
+ $request = new Request('DELETE', 'http://www.foo.com');
+ $response = Response::fromMessage(
+ "HTTP/1.1 200 OK\r\n"
+ . "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
+ . "Last-Modified: Wed, 09 Jan 2013 08:48:53 GMT\r\n"
+ . "Content-Length: 2\r\n"
+ . "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n\r\n"
+ . "hi"
+ );
+
+ $this->assertTrue($c->canCacheRequest($request));
+ $this->assertTrue($c->canCacheResponse($response));
+
+ $s = $this->getMockBuilder('Guzzle\Plugin\Cache\DefaultCacheStorage')
+ ->setConstructorArgs(array(new DoctrineCacheAdapter(new ArrayCache())))
+ ->setMethods(array('fetch'))
+ ->getMockForAbstractClass();
+
+ $s->expects($this->once())
+ ->method('fetch')
+ ->will($this->returnValue($response));
+
+ $plugin = new CachePlugin(array('can_cache' => $c, 'storage' => $s));
+ $plugin->onRequestBeforeSend(new Event(array('request' => $request)));
+
+ $this->assertEquals(200, $request->getResponse()->getStatusCode());
+ $this->assertEquals('hi', $request->getResponse()->getBody(true));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php
new file mode 100755
index 0000000..701a015
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCacheStorageTest.php
@@ -0,0 +1,193 @@
+ 'application/json'));
+ $response = new Response(200, array(
+ 'Content-Type' => 'application/json',
+ 'Connection' => 'close',
+ 'X-Foo' => 'Bar',
+ 'Vary' => 'Accept'
+ ), 'test');
+ $s->cache($request, $response);
+ $data = $this->readAttribute($a, 'data');
+
+ return array(
+ 'cache' => $a,
+ 'adapter' => $c,
+ 'storage' => $s,
+ 'request' => $request,
+ 'response' => $response,
+ 'serialized' => end($data)
+ );
+ }
+
+ public function testReturnsNullForCacheMiss()
+ {
+ $cache = $this->getCache();
+ $this->assertNull($cache['storage']->fetch(new Request('GET', 'http://test.com')));
+ }
+
+ public function testCachesRequests()
+ {
+ $cache = $this->getCache();
+ $foundRequest = $foundBody = $bodyKey = false;
+ foreach ($this->readAttribute($cache['cache'], 'data') as $key => $v) {
+ if (strpos($v, 'foo.com')) {
+ $foundRequest = true;
+ $data = unserialize($v);
+ $bodyKey = $data[0][3];
+ $this->assertInternalType('integer', $data[0][4]);
+ $this->assertFalse(isset($data[0][0]['connection']));
+ $this->assertEquals('foo.com', $data[0][0]['host']);
+ } elseif ($v == 'test') {
+ $foundBody = $key;
+ }
+ }
+ $this->assertContains($bodyKey, $foundBody);
+ $this->assertTrue($foundRequest);
+ }
+
+ public function testFetchesResponse()
+ {
+ $cache = $this->getCache();
+ $response = $cache['storage']->fetch($cache['request']);
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertFalse($response->hasHeader('Connection'));
+ $this->assertEquals('Bar', (string) $response->getHeader('X-Foo'));
+ $this->assertEquals('test', (string) $response->getBody());
+ $this->assertTrue(in_array($cache['serialized'], $this->readAttribute($cache['cache'], 'data')));
+ }
+
+ public function testDeletesRequestItemsAndBody()
+ {
+ $cache = $this->getCache();
+ $cache['storage']->delete($cache['request']);
+ $this->assertFalse(in_array('test', $this->readAttribute($cache['cache'], 'data')));
+ $this->assertFalse(in_array($cache['serialized'], $this->readAttribute($cache['cache'], 'data')));
+ }
+
+ public function testCachesMultipleRequestsWithVary()
+ {
+ $cache = $this->getCache();
+ $cache['request']->setHeader('Accept', 'application/xml');
+ $response = $cache['response']->setHeader('Content-Type', 'application/xml');
+ $response->setBody('123');
+ $cache['storage']->cache($cache['request'], $response);
+ $data = $this->readAttribute($cache['cache'], 'data');
+ foreach ($data as $v) {
+ if (strpos($v, 'foo.com')) {
+ $u = unserialize($v);
+ $this->assertEquals(2, count($u));
+ $this->assertEquals($u[0][0]['accept'], 'application/xml');
+ $this->assertEquals($u[0][1]['content-type'], 'application/xml');
+ $this->assertEquals($u[1][0]['accept'], 'application/json');
+ $this->assertEquals($u[1][1]['content-type'], 'application/json');
+ $this->assertNotSame($u[0][3], $u[1][3]);
+ break;
+ }
+ }
+ }
+
+ public function testPurgeRemovesAllMethodCaches()
+ {
+ $cache = $this->getCache();
+ foreach (array('HEAD', 'POST', 'PUT', 'DELETE') as $method) {
+ $request = RequestFactory::getInstance()->cloneRequestWithMethod($cache['request'], $method);
+ $cache['storage']->cache($request, $cache['response']);
+ }
+ $cache['storage']->purge('http://foo.com');
+ $this->assertFalse(in_array('test', $this->readAttribute($cache['cache'], 'data')));
+ $this->assertFalse(in_array($cache['serialized'], $this->readAttribute($cache['cache'], 'data')));
+ $this->assertEquals(
+ array('DoctrineNamespaceCacheKey[]'),
+ array_keys($this->readAttribute($cache['cache'], 'data'))
+ );
+ }
+
+ public function testRemovesExpiredResponses()
+ {
+ $cache = $this->getCache();
+ $request = new Request('GET', 'http://xyz.com');
+ $response = new Response(200, array('Age' => 1000, 'Cache-Control' => 'max-age=-10000'));
+ $cache['storage']->cache($request, $response);
+ $this->assertNull($cache['storage']->fetch($request));
+ $data = $this->readAttribute($cache['cache'], 'data');
+ $this->assertFalse(in_array('xyz.com', $data));
+ $this->assertTrue(in_array($cache['serialized'], $data));
+ }
+
+ public function testUsesVaryToDetermineResult()
+ {
+ $cache = $this->getCache();
+ $this->assertInstanceOf('Guzzle\Http\Message\Response', $cache['storage']->fetch($cache['request']));
+ $request = new Request('GET', 'http://foo.com', array('Accept' => 'application/xml'));
+ $this->assertNull($cache['storage']->fetch($request));
+ }
+
+ public function testEnsuresResponseIsStillPresent()
+ {
+ $cache = $this->getCache();
+ $data = $this->readAttribute($cache['cache'], 'data');
+ $key = array_search('test', $data);
+ $cache['cache']->delete(substr($key, 1, -4));
+ $this->assertNull($cache['storage']->fetch($cache['request']));
+ }
+
+ public function staleProvider()
+ {
+ return array(
+ array(
+ new Request('GET', 'http://foo.com', array('Accept' => 'foo')),
+ new Response(200, array('Cache-Control' => 'stale-if-error=100', 'Vary' => 'Accept'))
+ ),
+ array(
+ new Request('GET', 'http://foo.com', array('Accept' => 'foo')),
+ new Response(200, array('Cache-Control' => 'stale-if-error', 'Vary' => 'Accept'))
+ )
+ );
+ }
+
+ /**
+ * @dataProvider staleProvider
+ */
+ public function testUsesStaleTimeDirectiveForTtd($request, $response)
+ {
+ $cache = $this->getCache();
+ $cache['storage']->cache($request, $response);
+ $data = $this->readAttribute($cache['cache'], 'data');
+ foreach ($data as $v) {
+ if (strpos($v, 'foo.com')) {
+ $u = unserialize($v);
+ $this->assertGreaterThan($u[1][4], $u[0][4]);
+ break;
+ }
+ }
+ }
+
+ public function testCanFilterCacheKeys()
+ {
+ $cache = $this->getCache();
+ $cache['request']->getQuery()->set('auth', 'foo');
+ $this->assertNull($cache['storage']->fetch($cache['request']));
+ $cache['request']->getParams()->set('cache.key_filter', 'auth');
+ $this->assertNotNull($cache['storage']->fetch($cache['request']));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php
new file mode 100755
index 0000000..de4d182
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultCanCacheStrategyTest.php
@@ -0,0 +1,40 @@
+assertTrue($strategy->canCacheRequest($request));
+ }
+
+ public function testDoesNotCacheNoStore()
+ {
+ $strategy = new DefaultCanCacheStrategy();
+ $request = new Request('GET', 'http://foo.com', array('cache-control' => 'no-store'));
+ $this->assertFalse($strategy->canCacheRequest($request));
+ }
+
+ public function testCanCacheResponse()
+ {
+ $response = $this->getMockBuilder('Guzzle\Http\Message\Response')
+ ->setMethods(array('canCache'))
+ ->setConstructorArgs(array(200))
+ ->getMock();
+ $response->expects($this->once())
+ ->method('canCache')
+ ->will($this->returnValue(true));
+ $strategy = new DefaultCanCacheStrategy();
+ $this->assertTrue($strategy->canCacheResponse($response));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php
new file mode 100755
index 0000000..0699cb2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DefaultRevalidationTest.php
@@ -0,0 +1,248 @@
+getHttpDate('-100 hours') . "\r\nContent-Length: 4\r\n\r\nData",
+ "HTTP/1.1 304 NOT MODIFIED\r\nCache-Control: max-age=2000000\r\nContent-Length: 0\r\n\r\n",
+ ),
+ // Forces revalidation that overwrites what is in cache
+ array(
+ false,
+ "\r\n",
+ "HTTP/1.1 200 OK\r\nCache-Control: must-revalidate, no-cache\r\nDate: " . $this->getHttpDate('-10 hours') . "\r\nContent-Length: 4\r\n\r\nData",
+ "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nDatas",
+ "HTTP/1.1 200 OK\r\nContent-Length: 5\r\nDate: " . $this->getHttpDate('now') . "\r\n\r\nDatas"
+ ),
+ // Throws an exception during revalidation
+ array(
+ false,
+ "\r\n",
+ "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nDate: " . $this->getHttpDate('-3 hours') . "\r\n\r\nData",
+ "HTTP/1.1 500 INTERNAL SERVER ERROR\r\nContent-Length: 0\r\n\r\n"
+ ),
+ // ETag mismatch
+ array(
+ false,
+ "\r\n",
+ "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nETag: \"123\"\r\nDate: " . $this->getHttpDate('-10 hours') . "\r\n\r\nData",
+ "HTTP/1.1 304 NOT MODIFIED\r\nETag: \"123456\"\r\n\r\n",
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider cacheRevalidationDataProvider
+ */
+ public function testRevalidatesResponsesAgainstOriginServer($can, $request, $response, $validate = null, $result = null)
+ {
+ // Send some responses to the test server for cache validation
+ $server = $this->getServer();
+ $server->flush();
+
+ if ($validate) {
+ $server->enqueue($validate);
+ }
+
+ $request = RequestFactory::getInstance()->fromMessage("GET / HTTP/1.1\r\nHost: 127.0.0.1:" . $server->getPort() . "\r\n" . $request);
+ $response = Response::fromMessage($response);
+ $request->setClient(new Client());
+
+ $plugin = new CachePlugin(new DoctrineCacheAdapter(new ArrayCache()));
+ $this->assertEquals(
+ $can,
+ $plugin->canResponseSatisfyRequest($request, $response),
+ '-> ' . $request . "\n" . $response
+ );
+
+ if ($result) {
+ $result = Response::fromMessage($result);
+ $result->removeHeader('Date');
+ $request->getResponse()->removeHeader('Date');
+ $request->getResponse()->removeHeader('Connection');
+ // Get rid of dates
+ $this->assertEquals((string) $result, (string) $request->getResponse());
+ }
+
+ if ($validate) {
+ $this->assertEquals(1, count($server->getReceivedRequests()));
+ }
+ }
+
+ public function testHandles404RevalidationResponses()
+ {
+ $request = new Request('GET', 'http://foo.com');
+ $request->setClient(new Client());
+ $badResponse = new Response(404, array(), 'Oh no!');
+ $badRequest = clone $request;
+ $badRequest->setResponse($badResponse, true);
+ $response = new Response(200, array(), 'foo');
+
+ // Seed the cache
+ $s = new DefaultCacheStorage(new DoctrineCacheAdapter(new ArrayCache()));
+ $s->cache($request, $response);
+ $this->assertNotNull($s->fetch($request));
+
+ $rev = $this->getMockBuilder('Guzzle\Plugin\Cache\DefaultRevalidation')
+ ->setConstructorArgs(array($s))
+ ->setMethods(array('createRevalidationRequest'))
+ ->getMock();
+
+ $rev->expects($this->once())
+ ->method('createRevalidationRequest')
+ ->will($this->returnValue($badRequest));
+
+ try {
+ $rev->revalidate($request, $response);
+ $this->fail('Should have thrown an exception');
+ } catch (BadResponseException $e) {
+ $this->assertSame($badResponse, $e->getResponse());
+ $this->assertNull($s->fetch($request));
+ }
+ }
+
+ public function testCanRevalidateWithPlugin()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\n" .
+ "Date: Mon, 12 Nov 2012 03:06:37 GMT\r\n" .
+ "Cache-Control: private, s-maxage=0, max-age=0, must-revalidate\r\n" .
+ "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" .
+ "Content-Length: 2\r\n\r\nhi",
+ "HTTP/1.0 304 Not Modified\r\n" .
+ "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" .
+ "Content-Type: text/html; charset=UTF-8\r\n" .
+ "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" .
+ "Age: 6302\r\n\r\n",
+ "HTTP/1.0 304 Not Modified\r\n" .
+ "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" .
+ "Content-Type: text/html; charset=UTF-8\r\n" .
+ "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" .
+ "Age: 6302\r\n\r\n",
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $client->addSubscriber(new CachePlugin());
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ $this->assertEquals(3, count($this->getServer()->getReceivedRequests()));
+ }
+
+ public function testCanHandleRevalidationFailures()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $lm = gmdate('c', time() - 60);
+ $mock = new MockPlugin(array(
+ new Response(200, array(
+ 'Date' => $lm,
+ 'Cache-Control' => 'max-age=100, must-revalidate, stale-if-error=9999',
+ 'Last-Modified' => $lm,
+ 'Content-Length' => 2
+ ), 'hi'),
+ new CurlException('Bleh'),
+ new CurlException('Bleh')
+ ));
+ $client->addSubscriber(new CachePlugin());
+ $client->addSubscriber($mock);
+ $client->get()->send();
+ $response = $client->get()->send();
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertEquals('hi', $response->getBody(true));
+ $this->assertEquals(3, count($mock->getReceivedRequests()));
+ $this->assertEquals(0, count($mock->getQueue()));
+ }
+
+ public function testCanHandleStaleIfErrorWhenRevalidating()
+ {
+ $lm = gmdate('c', time() - 60);
+ $mock = new MockPlugin(array(
+ new Response(200, array(
+ 'Date' => $lm,
+ 'Cache-Control' => 'must-revalidate, max-age=0, stale-if-error=1200',
+ 'Last-Modified' => $lm,
+ 'Content-Length' => 2
+ ), 'hi'),
+ new CurlException('Oh no!'),
+ new CurlException('Oh no!')
+ ));
+ $cache = new CachePlugin();
+ $client = new Client('http://www.example.com');
+ $client->addSubscriber($cache);
+ $client->addSubscriber($mock);
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ $response = $client->get()->send();
+ $this->assertEquals(200, $response->getStatusCode());
+ $this->assertCount(0, $mock);
+ $this->assertEquals('HIT from GuzzleCache', (string) $response->getHeader('X-Cache-Lookup'));
+ $this->assertEquals('HIT_ERROR from GuzzleCache', (string) $response->getHeader('X-Cache'));
+ }
+
+ /**
+ * @group issue-437
+ */
+ public function testDoesNotTouchClosureListeners()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\n" .
+ "Date: Mon, 12 Nov 2012 03:06:37 GMT\r\n" .
+ "Cache-Control: private, s-maxage=0, max-age=0, must-revalidate\r\n" .
+ "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" .
+ "Content-Length: 2\r\n\r\nhi",
+ "HTTP/1.0 304 Not Modified\r\n" .
+ "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" .
+ "Content-Type: text/html; charset=UTF-8\r\n" .
+ "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" .
+ "Age: 6302\r\n\r\n",
+ "HTTP/1.0 304 Not Modified\r\n" .
+ "Date: Mon, 12 Nov 2012 03:06:38 GMT\r\n" .
+ "Content-Type: text/html; charset=UTF-8\r\n" .
+ "Last-Modified: Mon, 12 Nov 2012 02:53:38 GMT\r\n" .
+ "Age: 6302\r\n\r\n",
+ ));
+ $client = new Client($this->getServer()->getUrl());
+ $client->addSubscriber(new CachePlugin());
+ $client->getEventDispatcher()->addListener('command.after_send', function(){});
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ $this->assertEquals(200, $client->get()->send()->getStatusCode());
+ }
+
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php
new file mode 100755
index 0000000..9af80f2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/DenyRevalidationTest.php
@@ -0,0 +1,19 @@
+assertFalse($deny->revalidate(new Request('GET', 'http://foo.com'), new Response(200)));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php
new file mode 100755
index 0000000..4bcc04b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cache/SkipRevalidationTest.php
@@ -0,0 +1,19 @@
+assertTrue($skip->revalidate(new Request('GET', 'http://foo.com'), new Response(200)));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php
new file mode 100755
index 0000000..5d0f668
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/ArrayCookieJarTest.php
@@ -0,0 +1,385 @@
+jar = new ArrayCookieJar();
+ }
+
+ protected function getTestCookies()
+ {
+ return array(
+ new Cookie(array('name' => 'foo', 'value' => 'bar', 'domain' => 'foo.com', 'path' => '/', 'discard' => true)),
+ new Cookie(array('name' => 'test', 'value' => '123', 'domain' => 'baz.com', 'path' => '/foo', 'expires' => 2)),
+ new Cookie(array('name' => 'you', 'value' => '123', 'domain' => 'bar.com', 'path' => '/boo', 'expires' => time() + 1000))
+ );
+ }
+
+ /**
+ * Provides test data for cookie cookieJar retrieval
+ */
+ public function getCookiesDataProvider()
+ {
+ return array(
+ array(array('foo', 'baz', 'test', 'muppet', 'googoo'), '', '', '', false),
+ array(array('foo', 'baz', 'muppet', 'googoo'), '', '', '', true),
+ array(array('googoo'), 'www.example.com', '', '', false),
+ array(array('muppet', 'googoo'), 'test.y.example.com', '', '', false),
+ array(array('foo', 'baz'), 'example.com', '', '', false),
+ array(array('muppet'), 'x.y.example.com', '/acme/', '', false),
+ array(array('muppet'), 'x.y.example.com', '/acme/test/', '', false),
+ array(array('googoo'), 'x.y.example.com', '/test/acme/test/', '', false),
+ array(array('foo', 'baz'), 'example.com', '', '', false),
+ array(array('baz'), 'example.com', '', 'baz', false),
+ );
+ }
+
+ public function testStoresAndRetrievesCookies()
+ {
+ $cookies = $this->getTestCookies();
+ foreach ($cookies as $cookie) {
+ $this->assertTrue($this->jar->add($cookie));
+ }
+
+ $this->assertEquals(3, count($this->jar));
+ $this->assertEquals(3, count($this->jar->getIterator()));
+ $this->assertEquals($cookies, $this->jar->all(null, null, null, false, false));
+ }
+
+ public function testRemovesExpiredCookies()
+ {
+ $cookies = $this->getTestCookies();
+ foreach ($this->getTestCookies() as $cookie) {
+ $this->jar->add($cookie);
+ }
+ $this->jar->removeExpired();
+ $this->assertEquals(array($cookies[0], $cookies[2]), $this->jar->all());
+ }
+
+ public function testRemovesTemporaryCookies()
+ {
+ $cookies = $this->getTestCookies();
+ foreach ($this->getTestCookies() as $cookie) {
+ $this->jar->add($cookie);
+ }
+ $this->jar->removeTemporary();
+ $this->assertEquals(array($cookies[2]), $this->jar->all());
+ }
+
+ public function testIsSerializable()
+ {
+ $this->assertEquals('[]', $this->jar->serialize());
+ $this->jar->unserialize('[]');
+ $this->assertEquals(array(), $this->jar->all());
+
+ $cookies = $this->getTestCookies();
+ foreach ($this->getTestCookies() as $cookie) {
+ $this->jar->add($cookie);
+ }
+
+ // Remove discard and expired cookies
+ $serialized = $this->jar->serialize();
+ $data = json_decode($serialized, true);
+ $this->assertEquals(1, count($data));
+
+ $a = new ArrayCookieJar();
+ $a->unserialize($serialized);
+ $this->assertEquals(1, count($a));
+ }
+
+ public function testRemovesSelectively()
+ {
+ $cookies = $this->getTestCookies();
+ foreach ($this->getTestCookies() as $cookie) {
+ $this->jar->add($cookie);
+ }
+
+ // Remove foo.com cookies
+ $this->jar->remove('foo.com');
+ $this->assertEquals(2, count($this->jar));
+ // Try again, removing no further cookies
+ $this->jar->remove('foo.com');
+ $this->assertEquals(2, count($this->jar));
+
+ // Remove bar.com cookies with path of /boo
+ $this->jar->remove('bar.com', '/boo');
+ $this->assertEquals(1, count($this->jar));
+
+ // Remove cookie by name
+ $this->jar->remove(null, null, 'test');
+ $this->assertEquals(0, count($this->jar));
+ }
+
+ public function testDoesNotAddIncompleteCookies()
+ {
+ $this->assertEquals(false, $this->jar->add(new Cookie()));
+ $this->assertFalse($this->jar->add(new Cookie(array(
+ 'name' => 'foo'
+ ))));
+ $this->assertFalse($this->jar->add(new Cookie(array(
+ 'name' => false
+ ))));
+ $this->assertFalse($this->jar->add(new Cookie(array(
+ 'name' => true
+ ))));
+ $this->assertFalse($this->jar->add(new Cookie(array(
+ 'name' => 'foo',
+ 'domain' => 'foo.com'
+ ))));
+ }
+
+ public function testDoesAddValidCookies()
+ {
+ $this->assertTrue($this->jar->add(new Cookie(array(
+ 'name' => 'foo',
+ 'domain' => 'foo.com',
+ 'value' => 0
+ ))));
+ $this->assertTrue($this->jar->add(new Cookie(array(
+ 'name' => 'foo',
+ 'domain' => 'foo.com',
+ 'value' => 0.0
+ ))));
+ $this->assertTrue($this->jar->add(new Cookie(array(
+ 'name' => 'foo',
+ 'domain' => 'foo.com',
+ 'value' => '0'
+ ))));
+ }
+
+ public function testOverwritesCookiesThatAreOlderOrDiscardable()
+ {
+ $t = time() + 1000;
+ $data = array(
+ 'name' => 'foo',
+ 'value' => 'bar',
+ 'domain' => '.example.com',
+ 'path' => '/',
+ 'max_age' => '86400',
+ 'port' => array(80, 8080),
+ 'version' => '1',
+ 'secure' => true,
+ 'discard' => true,
+ 'expires' => $t
+ );
+
+ // Make sure that the discard cookie is overridden with the non-discard
+ $this->assertTrue($this->jar->add(new Cookie($data)));
+
+ unset($data['discard']);
+ $this->assertTrue($this->jar->add(new Cookie($data)));
+ $this->assertEquals(1, count($this->jar));
+
+ $c = $this->jar->all();
+ $this->assertEquals(false, $c[0]->getDiscard());
+
+ // Make sure it doesn't duplicate the cookie
+ $this->jar->add(new Cookie($data));
+ $this->assertEquals(1, count($this->jar));
+
+ // Make sure the more future-ful expiration date supersede the other
+ $data['expires'] = time() + 2000;
+ $this->assertTrue($this->jar->add(new Cookie($data)));
+ $this->assertEquals(1, count($this->jar));
+ $c = $this->jar->all();
+ $this->assertNotEquals($t, $c[0]->getExpires());
+ }
+
+ public function testOverwritesCookiesThatHaveChanged()
+ {
+ $t = time() + 1000;
+ $data = array(
+ 'name' => 'foo',
+ 'value' => 'bar',
+ 'domain' => '.example.com',
+ 'path' => '/',
+ 'max_age' => '86400',
+ 'port' => array(80, 8080),
+ 'version' => '1',
+ 'secure' => true,
+ 'discard' => true,
+ 'expires' => $t
+ );
+
+ // Make sure that the discard cookie is overridden with the non-discard
+ $this->assertTrue($this->jar->add(new Cookie($data)));
+
+ $data['value'] = 'boo';
+ $this->assertTrue($this->jar->add(new Cookie($data)));
+ $this->assertEquals(1, count($this->jar));
+
+ // Changing the value plus a parameter also must overwrite the existing one
+ $data['value'] = 'zoo';
+ $data['secure'] = false;
+ $this->assertTrue($this->jar->add(new Cookie($data)));
+ $this->assertEquals(1, count($this->jar));
+
+ $c = $this->jar->all();
+ $this->assertEquals('zoo', $c[0]->getValue());
+ }
+
+ public function testAddsCookiesFromResponseWithNoRequest()
+ {
+ $response = new Response(200, array(
+ 'Set-Cookie' => array(
+ "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT; path=/; domain=127.0.0.1",
+ "FPCK3=AgBNbvoQAGpGEABZLRAAbFsQAF1tEABkDhAAeO0=; expires=Sat, 02-Apr-2019 02:17:40 GMT; path=/; domain=127.0.0.1",
+ "CH=deleted; expires=Wed, 03-Mar-2010 02:17:39 GMT; path=/; domain=127.0.0.1",
+ "CH=AgBNbvoQAAEcEAApuhAAMJcQADQvEAAvGxAALe0QAD6uEAATwhAAC1AQAC8t; expires=Sat, 02-Apr-2019 02:17:40 GMT; path=/; domain=127.0.0.1"
+ )
+ ));
+
+ $this->jar->addCookiesFromResponse($response);
+ $this->assertEquals(3, count($this->jar));
+ $this->assertEquals(1, count($this->jar->all(null, null, 'fpc')));
+ $this->assertEquals(1, count($this->jar->all(null, null, 'FPCK3')));
+ $this->assertEquals(1, count($this->jar->all(null, null, 'CH')));
+ }
+
+ public function testAddsCookiesFromResponseWithRequest()
+ {
+ $response = new Response(200, array(
+ 'Set-Cookie' => "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT;"
+ ));
+ $request = new Request('GET', 'http://www.example.com');
+ $this->jar->addCookiesFromResponse($response, $request);
+ $this->assertEquals(1, count($this->jar));
+ }
+
+ public function getMatchingCookiesDataProvider()
+ {
+ return array(
+ array('https://example.com', array(0)),
+ array('http://example.com', array()),
+ array('https://example.com:8912', array()),
+ array('https://foo.example.com', array(0)),
+ array('http://foo.example.com/test/acme/', array(4))
+ );
+ }
+
+ /**
+ * @dataProvider getMatchingCookiesDataProvider
+ */
+ public function testReturnsCookiesMatchingRequests($url, $cookies)
+ {
+ $bag = array(
+ new Cookie(array(
+ 'name' => 'foo',
+ 'value' => 'bar',
+ 'domain' => 'example.com',
+ 'path' => '/',
+ 'max_age' => '86400',
+ 'port' => array(443, 8080),
+ 'version' => '1',
+ 'secure' => true
+ )),
+ new Cookie(array(
+ 'name' => 'baz',
+ 'value' => 'foobar',
+ 'domain' => 'example.com',
+ 'path' => '/',
+ 'max_age' => '86400',
+ 'port' => array(80, 8080),
+ 'version' => '1',
+ 'secure' => true
+ )),
+ new Cookie(array(
+ 'name' => 'test',
+ 'value' => '123',
+ 'domain' => 'www.foobar.com',
+ 'path' => '/path/',
+ 'discard' => true
+ )),
+ new Cookie(array(
+ 'name' => 'muppet',
+ 'value' => 'cookie_monster',
+ 'domain' => '.y.example.com',
+ 'path' => '/acme/',
+ 'comment' => 'Comment goes here...',
+ 'expires' => time() + 86400
+ )),
+ new Cookie(array(
+ 'name' => 'googoo',
+ 'value' => 'gaga',
+ 'domain' => '.example.com',
+ 'path' => '/test/acme/',
+ 'max_age' => 1500,
+ 'version' => 2
+ ))
+ );
+
+ foreach ($bag as $cookie) {
+ $this->jar->add($cookie);
+ }
+
+ $request = new Request('GET', $url);
+ $results = $this->jar->getMatchingCookies($request);
+ $this->assertEquals(count($cookies), count($results));
+ foreach ($cookies as $i) {
+ $this->assertContains($bag[$i], $results);
+ }
+ }
+
+ /**
+ * @expectedException \Guzzle\Plugin\Cookie\Exception\InvalidCookieException
+ * @expectedExceptionMessage The cookie name must not contain invalid characters: abc:@123
+ */
+ public function testThrowsExceptionWithStrictMode()
+ {
+ $a = new ArrayCookieJar();
+ $a->setStrictMode(true);
+ $a->add(new Cookie(array(
+ 'name' => 'abc:@123',
+ 'value' => 'foo',
+ 'domain' => 'bar'
+ )));
+ }
+
+ public function testRemoveExistingCookieIfEmpty()
+ {
+ // Add a cookie that should not be affected
+ $a = new Cookie(array(
+ 'name' => 'foo',
+ 'value' => 'nope',
+ 'domain' => 'foo.com',
+ 'path' => '/abc'
+ ));
+ $this->jar->add($a);
+
+ $data = array(
+ 'name' => 'foo',
+ 'value' => 'bar',
+ 'domain' => 'foo.com',
+ 'path' => '/'
+ );
+
+ $b = new Cookie($data);
+ $this->assertTrue($this->jar->add($b));
+ $this->assertEquals(2, count($this->jar));
+
+ // Try to re-set the same cookie with no value: assert that cookie is not added
+ $data['value'] = null;
+ $this->assertFalse($this->jar->add(new Cookie($data)));
+ // assert that original cookie has been deleted
+ $cookies = $this->jar->all('foo.com');
+ $this->assertTrue(in_array($a, $cookies, true));
+ $this->assertFalse(in_array($b, $cookies, true));
+ $this->assertEquals(1, count($this->jar));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php
new file mode 100755
index 0000000..ac9471f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieJar/FileCookieJarTest.php
@@ -0,0 +1,63 @@
+file = tempnam('/tmp', 'file-cookies');
+ }
+
+ public function testLoadsFromFileFile()
+ {
+ $jar = new FileCookieJar($this->file);
+ $this->assertEquals(array(), $jar->all());
+ unlink($this->file);
+ }
+
+ public function testPersistsToFileFile()
+ {
+ $jar = new FileCookieJar($this->file);
+ $jar->add(new Cookie(array(
+ 'name' => 'foo',
+ 'value' => 'bar',
+ 'domain' => 'foo.com',
+ 'expires' => time() + 1000
+ )));
+ $jar->add(new Cookie(array(
+ 'name' => 'baz',
+ 'value' => 'bar',
+ 'domain' => 'foo.com',
+ 'expires' => time() + 1000
+ )));
+ $jar->add(new Cookie(array(
+ 'name' => 'boo',
+ 'value' => 'bar',
+ 'domain' => 'foo.com',
+ )));
+
+ $this->assertEquals(3, count($jar));
+ unset($jar);
+
+ // Make sure it wrote to the file
+ $contents = file_get_contents($this->file);
+ $this->assertNotEmpty($contents);
+
+ // Load the cookieJar from the file
+ $jar = new FileCookieJar($this->file);
+
+ // Weeds out temporary and session cookies
+ $this->assertEquals(2, count($jar));
+ unset($jar);
+ unlink($this->file);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php
new file mode 100755
index 0000000..f8c175c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookiePluginTest.php
@@ -0,0 +1,134 @@
+getMockBuilder('Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar')
+ ->setMethods(array('addCookiesFromResponse'))
+ ->getMock();
+
+ $mock->expects($this->exactly(1))
+ ->method('addCookiesFromResponse')
+ ->with($response);
+
+ $plugin = new CookiePlugin($mock);
+ $plugin->onRequestSent(new Event(array(
+ 'response' => $response
+ )));
+ }
+
+ public function testAddsCookiesToRequests()
+ {
+ $cookie = new Cookie(array(
+ 'name' => 'foo',
+ 'value' => 'bar'
+ ));
+
+ $mock = $this->getMockBuilder('Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar')
+ ->setMethods(array('getMatchingCookies'))
+ ->getMock();
+
+ $mock->expects($this->once())
+ ->method('getMatchingCookies')
+ ->will($this->returnValue(array($cookie)));
+
+ $plugin = new CookiePlugin($mock);
+
+ $client = new Client();
+ $client->getEventDispatcher()->addSubscriber($plugin);
+
+ $request = $client->get('http://www.example.com');
+ $plugin->onRequestBeforeSend(new Event(array(
+ 'request' => $request
+ )));
+
+ $this->assertEquals('bar', $request->getCookie('foo'));
+ }
+
+ public function testCookiesAreExtractedFromRedirectResponses()
+ {
+ $plugin = new CookiePlugin(new ArrayCookieJar());
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 302 Moved Temporarily\r\n" .
+ "Set-Cookie: test=583551; expires=Wednesday, 23-Mar-2050 19:49:45 GMT; path=/\r\n" .
+ "Location: /redirect\r\n\r\n",
+ "HTTP/1.1 200 OK\r\n" .
+ "Content-Length: 0\r\n\r\n",
+ "HTTP/1.1 200 OK\r\n" .
+ "Content-Length: 0\r\n\r\n"
+ ));
+
+ $client = new Client($this->getServer()->getUrl());
+ $client->getEventDispatcher()->addSubscriber($plugin);
+
+ $client->get()->send();
+ $request = $client->get();
+ $request->send();
+ $this->assertEquals('test=583551', $request->getHeader('Cookie'));
+
+ $requests = $this->getServer()->getReceivedRequests(true);
+ // Confirm subsequent requests have the cookie.
+ $this->assertEquals('test=583551', $requests[2]->getHeader('Cookie'));
+ // Confirm the redirected request has the cookie.
+ $this->assertEquals('test=583551', $requests[1]->getHeader('Cookie'));
+ }
+
+ public function testCookiesAreNotAddedWhenParamIsSet()
+ {
+ $jar = new ArrayCookieJar();
+ $plugin = new CookiePlugin($jar);
+
+ $jar->add(new Cookie(array(
+ 'domain' => 'example.com',
+ 'path' => '/',
+ 'name' => 'test',
+ 'value' => 'hi',
+ 'expires' => time() + 3600
+ )));
+
+ $client = new Client('http://example.com');
+ $client->getEventDispatcher()->addSubscriber($plugin);
+
+ // Ensure that it is normally added
+ $request = $client->get();
+ $request->setResponse(new Response(200), true);
+ $request->send();
+ $this->assertEquals('hi', $request->getCookie('test'));
+
+ // Now ensure that it is not added
+ $request = $client->get();
+ $request->getParams()->set('cookies.disable', true);
+ $request->setResponse(new Response(200), true);
+ $request->send();
+ $this->assertNull($request->getCookie('test'));
+ }
+
+ public function testProvidesCookieJar()
+ {
+ $jar = new ArrayCookieJar();
+ $plugin = new CookiePlugin($jar);
+ $this->assertSame($jar, $plugin->getCookieJar());
+ }
+
+ public function testEscapesCookieDomains()
+ {
+ $cookie = new Cookie(array('domain' => '/foo/^$[A-Z]+/'));
+ $this->assertFalse($cookie->matchesDomain('foo'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php
new file mode 100755
index 0000000..9fb0b43
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Cookie/CookieTest.php
@@ -0,0 +1,223 @@
+assertEquals('/', $cookie->getPath());
+ $this->assertEquals(array(), $cookie->getPorts());
+ }
+
+ public function testConvertsDateTimeMaxAgeToUnixTimestamp()
+ {
+ $cookie = new Cookie(array(
+ 'expires' => 'November 20, 1984'
+ ));
+ $this->assertTrue(is_numeric($cookie->getExpires()));
+ }
+
+ public function testAddsExpiresBasedOnMaxAge()
+ {
+ $t = time();
+ $cookie = new Cookie(array(
+ 'max_age' => 100
+ ));
+ $this->assertEquals($t + 100, $cookie->getExpires());
+ }
+
+ public function testHoldsValues()
+ {
+ $t = time();
+ $data = array(
+ 'name' => 'foo',
+ 'value' => 'baz',
+ 'path' => '/bar',
+ 'domain' => 'baz.com',
+ 'expires' => $t,
+ 'max_age' => 100,
+ 'comment' => 'Hi',
+ 'comment_url' => 'foo.com',
+ 'port' => array(1, 2),
+ 'version' => 2,
+ 'secure' => true,
+ 'discard' => true,
+ 'http_only' => true,
+ 'data' => array(
+ 'foo' => 'baz',
+ 'bar' => 'bam'
+ )
+ );
+
+ $cookie = new Cookie($data);
+ $this->assertEquals($data, $cookie->toArray());
+
+ $this->assertEquals('foo', $cookie->getName());
+ $this->assertEquals('baz', $cookie->getValue());
+ $this->assertEquals('baz.com', $cookie->getDomain());
+ $this->assertEquals('/bar', $cookie->getPath());
+ $this->assertEquals($t, $cookie->getExpires());
+ $this->assertEquals(100, $cookie->getMaxAge());
+ $this->assertEquals('Hi', $cookie->getComment());
+ $this->assertEquals('foo.com', $cookie->getCommentUrl());
+ $this->assertEquals(array(1, 2), $cookie->getPorts());
+ $this->assertEquals(2, $cookie->getVersion());
+ $this->assertTrue($cookie->getSecure());
+ $this->assertTrue($cookie->getDiscard());
+ $this->assertTrue($cookie->getHttpOnly());
+ $this->assertEquals('baz', $cookie->getAttribute('foo'));
+ $this->assertEquals('bam', $cookie->getAttribute('bar'));
+ $this->assertEquals(array(
+ 'foo' => 'baz',
+ 'bar' => 'bam'
+ ), $cookie->getAttributes());
+
+ $cookie->setName('a')
+ ->setValue('b')
+ ->setPath('c')
+ ->setDomain('bar.com')
+ ->setExpires(10)
+ ->setMaxAge(200)
+ ->setComment('e')
+ ->setCommentUrl('f')
+ ->setPorts(array(80))
+ ->setVersion(3)
+ ->setSecure(false)
+ ->setHttpOnly(false)
+ ->setDiscard(false)
+ ->setAttribute('snoop', 'dog');
+
+ $this->assertEquals('a', $cookie->getName());
+ $this->assertEquals('b', $cookie->getValue());
+ $this->assertEquals('c', $cookie->getPath());
+ $this->assertEquals('bar.com', $cookie->getDomain());
+ $this->assertEquals(10, $cookie->getExpires());
+ $this->assertEquals(200, $cookie->getMaxAge());
+ $this->assertEquals('e', $cookie->getComment());
+ $this->assertEquals('f', $cookie->getCommentUrl());
+ $this->assertEquals(array(80), $cookie->getPorts());
+ $this->assertEquals(3, $cookie->getVersion());
+ $this->assertFalse($cookie->getSecure());
+ $this->assertFalse($cookie->getDiscard());
+ $this->assertFalse($cookie->getHttpOnly());
+ $this->assertEquals('dog', $cookie->getAttribute('snoop'));
+ }
+
+ public function testDeterminesIfExpired()
+ {
+ $c = new Cookie();
+ $c->setExpires(10);
+ $this->assertTrue($c->isExpired());
+ $c->setExpires(time() + 10000);
+ $this->assertFalse($c->isExpired());
+ }
+
+ public function testMatchesPorts()
+ {
+ $cookie = new Cookie();
+ // Always matches when nothing is set
+ $this->assertTrue($cookie->matchesPort(2));
+
+ $cookie->setPorts(array(1, 2));
+ $this->assertTrue($cookie->matchesPort(2));
+ $this->assertFalse($cookie->matchesPort(100));
+ }
+
+ public function testMatchesDomain()
+ {
+ $cookie = new Cookie();
+ $this->assertTrue($cookie->matchesDomain('baz.com'));
+
+ $cookie->setDomain('baz.com');
+ $this->assertTrue($cookie->matchesDomain('baz.com'));
+ $this->assertFalse($cookie->matchesDomain('bar.com'));
+
+ $cookie->setDomain('.baz.com');
+ $this->assertTrue($cookie->matchesDomain('.baz.com'));
+ $this->assertTrue($cookie->matchesDomain('foo.baz.com'));
+ $this->assertFalse($cookie->matchesDomain('baz.bar.com'));
+ $this->assertTrue($cookie->matchesDomain('baz.com'));
+
+ $cookie->setDomain('.127.0.0.1');
+ $this->assertTrue($cookie->matchesDomain('127.0.0.1'));
+
+ $cookie->setDomain('127.0.0.1');
+ $this->assertTrue($cookie->matchesDomain('127.0.0.1'));
+
+ $cookie->setDomain('.com.');
+ $this->assertFalse($cookie->matchesDomain('baz.com'));
+
+ $cookie->setDomain('.local');
+ $this->assertTrue($cookie->matchesDomain('example.local'));
+ }
+
+ public function testMatchesPath()
+ {
+ $cookie = new Cookie();
+ $this->assertTrue($cookie->matchesPath('/foo'));
+
+ $cookie->setPath('/foo');
+
+ // o The cookie-path and the request-path are identical.
+ $this->assertTrue($cookie->matchesPath('/foo'));
+ $this->assertFalse($cookie->matchesPath('/bar'));
+
+ // o The cookie-path is a prefix of the request-path, and the first
+ // character of the request-path that is not included in the cookie-
+ // path is a %x2F ("/") character.
+ $this->assertTrue($cookie->matchesPath('/foo/bar'));
+ $this->assertFalse($cookie->matchesPath('/fooBar'));
+
+ // o The cookie-path is a prefix of the request-path, and the last
+ // character of the cookie-path is %x2F ("/").
+ $cookie->setPath('/foo/');
+ $this->assertTrue($cookie->matchesPath('/foo/bar'));
+ $this->assertFalse($cookie->matchesPath('/fooBaz'));
+ $this->assertFalse($cookie->matchesPath('/foo'));
+
+ }
+
+ public function cookieValidateProvider()
+ {
+ return array(
+ array('foo', 'baz', 'bar', true),
+ array('0', '0', '0', true),
+ array('', 'baz', 'bar', 'The cookie name must not be empty'),
+ array('foo', '', 'bar', 'The cookie value must not be empty'),
+ array('foo', 'baz', '', 'The cookie domain must not be empty'),
+ array('foo\\', 'baz', '0', 'The cookie name must not contain invalid characters: foo\\'),
+ );
+ }
+
+ /**
+ * @dataProvider cookieValidateProvider
+ */
+ public function testValidatesCookies($name, $value, $domain, $result)
+ {
+ $cookie = new Cookie(array(
+ 'name' => $name,
+ 'value' => $value,
+ 'domain' => $domain
+ ));
+ $this->assertSame($result, $cookie->validate());
+ }
+
+ public function testCreatesInvalidCharacterString()
+ {
+ $m = new \ReflectionMethod('Guzzle\Plugin\Cookie\Cookie', 'getInvalidCharacters');
+ $m->setAccessible(true);
+ $p = new \ReflectionProperty('Guzzle\Plugin\Cookie\Cookie', 'invalidCharString');
+ $p->setAccessible(true);
+ $p->setValue('');
+ // Expects a string containing 51 invalid characters
+ $this->assertEquals(51, strlen($m->invoke($m)));
+ $this->assertContains('@', $m->invoke($m));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php
new file mode 100755
index 0000000..2a4b49e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/CurlAuth/CurlAuthPluginTest.php
@@ -0,0 +1,39 @@
+getEventDispatcher()->addSubscriber($plugin);
+ $request = $client->get('/');
+ $this->assertEquals('michael', $request->getUsername());
+ $this->assertEquals('test', $request->getPassword());
+ Version::$emitWarnings = true;
+ }
+
+ public function testAddsDigestAuthentication()
+ {
+ Version::$emitWarnings = false;
+ $plugin = new CurlAuthPlugin('julian', 'test', CURLAUTH_DIGEST);
+ $client = new Client('http://www.test.com/');
+ $client->getEventDispatcher()->addSubscriber($plugin);
+ $request = $client->get('/');
+ $this->assertEquals('julian', $request->getUsername());
+ $this->assertEquals('test', $request->getPassword());
+ $this->assertEquals('julian:test', $request->getCurlOptions()->get(CURLOPT_USERPWD));
+ $this->assertEquals(CURLAUTH_DIGEST, $request->getCurlOptions()->get(CURLOPT_HTTPAUTH));
+ Version::$emitWarnings = true;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php
new file mode 100755
index 0000000..6f94186
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/ErrorResponse/ErrorResponsePluginTest.php
@@ -0,0 +1,137 @@
+flush();
+ }
+
+ public function setUp()
+ {
+ $mockError = 'Guzzle\Tests\Mock\ErrorResponseMock';
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'works' => array(
+ 'httpMethod' => 'GET',
+ 'errorResponses' => array(
+ array('code' => 500, 'class' => $mockError),
+ array('code' => 503, 'reason' => 'foo', 'class' => $mockError),
+ array('code' => 200, 'reason' => 'Error!', 'class' => $mockError)
+ )
+ ),
+ 'bad_class' => array(
+ 'httpMethod' => 'GET',
+ 'errorResponses' => array(
+ array('code' => 500, 'class' => 'Does\\Not\\Exist')
+ )
+ ),
+ 'does_not_implement' => array(
+ 'httpMethod' => 'GET',
+ 'errorResponses' => array(
+ array('code' => 500, 'class' => __CLASS__)
+ )
+ ),
+ 'no_errors' => array('httpMethod' => 'GET'),
+ 'no_class' => array(
+ 'httpMethod' => 'GET',
+ 'errorResponses' => array(
+ array('code' => 500)
+ )
+ ),
+ )
+ ));
+ $this->client = new Client($this->getServer()->getUrl());
+ $this->client->setDescription($description);
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\ServerErrorResponseException
+ */
+ public function testSkipsWhenErrorResponsesIsNotSet()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('no_errors')->execute();
+ }
+
+ public function testSkipsWhenErrorResponsesIsNotSetAndAllowsSuccess()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('no_errors')->execute();
+ }
+
+ /**
+ * @expectedException \Guzzle\Plugin\ErrorResponse\Exception\ErrorResponseException
+ * @expectedExceptionMessage Does\Not\Exist does not exist
+ */
+ public function testEnsuresErrorResponseExists()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('bad_class')->execute();
+ }
+
+ /**
+ * @expectedException \Guzzle\Plugin\ErrorResponse\Exception\ErrorResponseException
+ * @expectedExceptionMessage must implement Guzzle\Plugin\ErrorResponse\ErrorResponseExceptionInterface
+ */
+ public function testEnsuresErrorResponseImplementsInterface()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('does_not_implement')->execute();
+ }
+
+ public function testThrowsSpecificErrorResponseOnMatch()
+ {
+ try {
+ $this->getServer()->enqueue("HTTP/1.1 500 Foo\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $command = $this->client->getCommand('works');
+ $command->execute();
+ $this->fail('Exception not thrown');
+ } catch (ErrorResponseMock $e) {
+ $this->assertSame($command, $e->command);
+ $this->assertEquals(500, $e->response->getStatusCode());
+ }
+ }
+
+ /**
+ * @expectedException \Guzzle\Tests\Mock\ErrorResponseMock
+ */
+ public function testThrowsWhenCodeAndPhraseMatch()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 Error!\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('works')->execute();
+ }
+
+ public function testSkipsWhenReasonDoesNotMatch()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('works')->execute();
+ }
+
+ public function testSkipsWhenNoClassIsSet()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $this->client->addSubscriber(new ErrorResponsePlugin());
+ $this->client->getCommand('no_class')->execute();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php
new file mode 100755
index 0000000..41aa673
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/History/HistoryPluginTest.php
@@ -0,0 +1,140 @@
+get();
+ $requests[$i]->setResponse(new Response(200), true);
+ $requests[$i]->send();
+ $h->add($requests[$i]);
+ }
+
+ return $requests;
+ }
+
+ public function testDescribesSubscribedEvents()
+ {
+ $this->assertInternalType('array', HistoryPlugin::getSubscribedEvents());
+ }
+
+ public function testMaintainsLimitValue()
+ {
+ $h = new HistoryPlugin();
+ $this->assertSame($h, $h->setLimit(10));
+ $this->assertEquals(10, $h->getLimit());
+ }
+
+ public function testAddsRequests()
+ {
+ $h = new HistoryPlugin();
+ $requests = $this->addRequests($h, 1);
+ $this->assertEquals(1, count($h));
+ $i = $h->getIterator();
+ $this->assertEquals(1, count($i));
+ $this->assertEquals($requests[0], $i[0]);
+ }
+
+ /**
+ * @depends testAddsRequests
+ */
+ public function testMaintainsLimit()
+ {
+ $h = new HistoryPlugin();
+ $h->setLimit(2);
+ $requests = $this->addRequests($h, 3);
+ $this->assertEquals(2, count($h));
+ $i = 0;
+ foreach ($h as $request) {
+ if ($i > 0) {
+ $this->assertSame($requests[$i], $request);
+ }
+ }
+ }
+
+ public function testReturnsLastRequest()
+ {
+ $h = new HistoryPlugin();
+ $requests = $this->addRequests($h, 5);
+ $this->assertSame(end($requests), $h->getLastRequest());
+ }
+
+ public function testReturnsLastResponse()
+ {
+ $h = new HistoryPlugin();
+ $requests = $this->addRequests($h, 5);
+ $this->assertSame(end($requests)->getResponse(), $h->getLastResponse());
+ }
+
+ public function testClearsHistory()
+ {
+ $h = new HistoryPlugin();
+ $requests = $this->addRequests($h, 5);
+ $this->assertEquals(5, count($h));
+ $h->clear();
+ $this->assertEquals(0, count($h));
+ }
+
+ /**
+ * @depends testAddsRequests
+ */
+ public function testUpdatesAddRequests()
+ {
+ $h = new HistoryPlugin();
+ $client = new Client('http://127.0.0.1/');
+ $client->getEventDispatcher()->addSubscriber($h);
+
+ $request = $client->get();
+ $request->setResponse(new Response(200), true);
+ $request->send();
+
+ $this->assertSame($request, $h->getLastRequest());
+ }
+
+ public function testCanCastToString()
+ {
+ $client = new Client('http://127.0.0.1/');
+ $h = new HistoryPlugin();
+ $client->getEventDispatcher()->addSubscriber($h);
+
+ $mock = new MockPlugin(array(
+ new Response(301, array('Location' => '/redirect1', 'Content-Length' => 0)),
+ new Response(307, array('Location' => '/redirect2', 'Content-Length' => 0)),
+ new Response(200, array('Content-Length' => '2'), 'HI')
+ ));
+
+ $client->getEventDispatcher()->addSubscriber($mock);
+ $request = $client->get();
+ $request->send();
+ $this->assertEquals(3, count($h));
+ $this->assertEquals(3, count($mock->getReceivedRequests()));
+
+ $h = str_replace("\r", '', $h);
+ $this->assertContains("> GET / HTTP/1.1\nHost: 127.0.0.1\nUser-Agent:", $h);
+ $this->assertContains("< HTTP/1.1 301 Moved Permanently\nLocation: /redirect1", $h);
+ $this->assertContains("< HTTP/1.1 307 Temporary Redirect\nLocation: /redirect2", $h);
+ $this->assertContains("< HTTP/1.1 200 OK\nContent-Length: 2\n\nHI", $h);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php
new file mode 100755
index 0000000..ad663a5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Log/LogPluginTest.php
@@ -0,0 +1,95 @@
+adapter = new ClosureLogAdapter(function ($message) {
+ echo $message;
+ });
+ }
+
+ public function testIgnoresCurlEventsWhenNotWiringBodies()
+ {
+ $p = new LogPlugin($this->adapter);
+ $this->assertNotEmpty($p->getSubscribedEvents());
+ $event = new Event(array('request' => new Request('GET', 'http://foo.com')));
+ $p->onCurlRead($event);
+ $p->onCurlWrite($event);
+ $p->onRequestBeforeSend($event);
+ }
+
+ public function testLogsWhenComplete()
+ {
+ $output = '';
+ $p = new LogPlugin(new ClosureLogAdapter(function ($message) use (&$output) {
+ $output = $message;
+ }), '{method} {resource} | {code} {res_body}');
+
+ $p->onRequestSent(new Event(array(
+ 'request' => new Request('GET', 'http://foo.com'),
+ 'response' => new Response(200, array(), 'Foo')
+ )));
+
+ $this->assertEquals('GET / | 200 Foo', $output);
+ }
+
+ public function testWiresBodiesWhenNeeded()
+ {
+ $client = new Client($this->getServer()->getUrl());
+ $plugin = new LogPlugin($this->adapter, '{req_body} | {res_body}', true);
+ $client->getEventDispatcher()->addSubscriber($plugin);
+ $request = $client->put();
+
+ // Send the response from the dummy server as the request body
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\nsend");
+ $stream = fopen($this->getServer()->getUrl(), 'r');
+ $request->setBody(EntityBody::factory($stream, 4));
+
+ $tmpFile = tempnam(sys_get_temp_dir(), 'non_repeatable');
+ $request->setResponseBody(EntityBody::factory(fopen($tmpFile, 'w')));
+
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 8\r\n\r\nresponse");
+
+ ob_start();
+ $request->send();
+ $message = ob_get_clean();
+
+ unlink($tmpFile);
+ $this->assertContains("send", $message);
+ $this->assertContains("response", $message);
+ }
+
+ public function testHasHelpfulStaticFactoryMethod()
+ {
+ $s = fopen('php://temp', 'r+');
+ $client = new Client();
+ $client->addSubscriber(LogPlugin::getDebugPlugin(true, $s));
+ $request = $client->put('http://foo.com', array('Content-Type' => 'Foo'), 'Bar');
+ $request->setresponse(new Response(200), true);
+ $request->send();
+ rewind($s);
+ $contents = stream_get_contents($s);
+ $this->assertContains('# Request:', $contents);
+ $this->assertContainsIns('PUT / HTTP/1.1', $contents);
+ $this->assertContains('# Response:', $contents);
+ $this->assertContainsIns('HTTP/1.1 200 OK', $contents);
+ $this->assertContains('# Errors:', $contents);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php
new file mode 100755
index 0000000..4bd4111
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/CommandContentMd5PluginTest.php
@@ -0,0 +1,97 @@
+ array(
+ 'test' => array(
+ 'httpMethod' => 'PUT',
+ 'parameters' => array(
+ 'ContentMD5' => array(),
+ 'Body' => array(
+ 'location' => 'body'
+ )
+ )
+ )
+ )
+ ));
+
+ $client = new Client();
+ $client->setDescription($description);
+
+ return $client;
+ }
+
+ public function testHasEvents()
+ {
+ $this->assertNotEmpty(CommandContentMd5Plugin::getSubscribedEvents());
+ }
+
+ public function testValidatesMd5WhenParamExists()
+ {
+ $client = $this->getClient();
+ $command = $client->getCommand('test', array(
+ 'Body' => 'Foo',
+ 'ContentMD5' => true
+ ));
+ $event = new Event(array('command' => $command));
+ $request = $command->prepare();
+ $plugin = new CommandContentMd5Plugin();
+ $plugin->onCommandBeforeSend($event);
+ $this->assertEquals('E1bGfXrRY42Ba/uCLdLCXQ==', (string) $request->getHeader('Content-MD5'));
+ }
+
+ public function testDoesNothingWhenNoPayloadExists()
+ {
+ $client = $this->getClient();
+ $client->getDescription()->getOperation('test')->setHttpMethod('GET');
+ $command = $client->getCommand('test');
+ $event = new Event(array('command' => $command));
+ $request = $command->prepare();
+ $plugin = new CommandContentMd5Plugin();
+ $plugin->onCommandBeforeSend($event);
+ $this->assertNull($request->getHeader('Content-MD5'));
+ }
+
+ public function testAddsValidationToResponsesOfContentMd5()
+ {
+ $client = $this->getClient();
+ $client->getDescription()->getOperation('test')->setHttpMethod('GET');
+ $command = $client->getCommand('test', array(
+ 'ValidateMD5' => true
+ ));
+ $event = new Event(array('command' => $command));
+ $request = $command->prepare();
+ $plugin = new CommandContentMd5Plugin();
+ $plugin->onCommandBeforeSend($event);
+ $listeners = $request->getEventDispatcher()->getListeners('request.complete');
+ $this->assertNotEmpty($listeners);
+ }
+
+ public function testIgnoresValidationWhenDisabled()
+ {
+ $client = $this->getClient();
+ $client->getDescription()->getOperation('test')->setHttpMethod('GET');
+ $command = $client->getCommand('test', array(
+ 'ValidateMD5' => false
+ ));
+ $event = new Event(array('command' => $command));
+ $request = $command->prepare();
+ $plugin = new CommandContentMd5Plugin();
+ $plugin->onCommandBeforeSend($event);
+ $listeners = $request->getEventDispatcher()->getListeners('request.complete');
+ $this->assertEmpty($listeners);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php
new file mode 100755
index 0000000..482e92b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Md5/Md5ValidatorPluginTest.php
@@ -0,0 +1,120 @@
+create('GET', 'http://www.test.com/');
+ $request->getEventDispatcher()->addSubscriber($plugin);
+
+ $body = 'abc';
+ $hash = md5($body);
+ $response = new Response(200, array(
+ 'Content-MD5' => $hash,
+ 'Content-Length' => 3
+ ), 'abc');
+
+ $request->dispatch('request.complete', array(
+ 'response' => $response
+ ));
+
+ // Try again with no Content-MD5
+ $response->removeHeader('Content-MD5');
+ $request->dispatch('request.complete', array(
+ 'response' => $response
+ ));
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ */
+ public function testThrowsExceptionOnInvalidMd5()
+ {
+ $plugin = new Md5ValidatorPlugin();
+ $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/');
+ $request->getEventDispatcher()->addSubscriber($plugin);
+
+ $request->dispatch('request.complete', array(
+ 'response' => new Response(200, array(
+ 'Content-MD5' => 'foobar',
+ 'Content-Length' => 3
+ ), 'abc')
+ ));
+ }
+
+ public function testSkipsWhenContentLengthIsTooLarge()
+ {
+ $plugin = new Md5ValidatorPlugin(false, 1);
+ $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/');
+ $request->getEventDispatcher()->addSubscriber($plugin);
+
+ $request->dispatch('request.complete', array(
+ 'response' => new Response(200, array(
+ 'Content-MD5' => 'foobar',
+ 'Content-Length' => 3
+ ), 'abc')
+ ));
+ }
+
+ public function testProperlyValidatesWhenUsingContentEncoding()
+ {
+ $plugin = new Md5ValidatorPlugin(true);
+ $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/');
+ $request->getEventDispatcher()->addSubscriber($plugin);
+
+ // Content-MD5 is the MD5 hash of the canonical content after all
+ // content-encoding has been applied. Because cURL will automatically
+ // decompress entity bodies, we need to re-compress it to calculate.
+ $body = EntityBody::factory('abc');
+ $body->compress();
+ $hash = $body->getContentMd5();
+ $body->uncompress();
+
+ $response = new Response(200, array(
+ 'Content-MD5' => $hash,
+ 'Content-Encoding' => 'gzip'
+ ), 'abc');
+ $request->dispatch('request.complete', array(
+ 'response' => $response
+ ));
+ $this->assertEquals('abc', $response->getBody(true));
+
+ // Try again with an unknown encoding
+ $response = new Response(200, array(
+ 'Content-MD5' => $hash,
+ 'Content-Encoding' => 'foobar'
+ ), 'abc');
+ $request->dispatch('request.complete', array(
+ 'response' => $response
+ ));
+
+ // Try again with compress
+ $body->compress('bzip2.compress');
+ $response = new Response(200, array(
+ 'Content-MD5' => $body->getContentMd5(),
+ 'Content-Encoding' => 'compress'
+ ), 'abc');
+ $request->dispatch('request.complete', array(
+ 'response' => $response
+ ));
+
+ // Try again with encoding and disabled content-encoding checks
+ $request->getEventDispatcher()->removeSubscriber($plugin);
+ $plugin = new Md5ValidatorPlugin(false);
+ $request->getEventDispatcher()->addSubscriber($plugin);
+ $request->dispatch('request.complete', array(
+ 'response' => $response
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php
new file mode 100755
index 0000000..3af8fef
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Mock/MockPluginTest.php
@@ -0,0 +1,199 @@
+assertInternalType('array', MockPlugin::getSubscribedEvents());
+ }
+
+ public function testDescribesEvents()
+ {
+ $this->assertInternalType('array', MockPlugin::getAllEvents());
+ }
+
+ public function testCanBeTemporary()
+ {
+ $plugin = new MockPlugin();
+ $this->assertFalse($plugin->isTemporary());
+ $plugin = new MockPlugin(null, true);
+ $this->assertTrue($plugin->isTemporary());
+ }
+
+ public function testIsCountable()
+ {
+ $plugin = new MockPlugin();
+ $plugin->addResponse(Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
+ $this->assertEquals(1, count($plugin));
+ }
+
+ /**
+ * @depends testIsCountable
+ */
+ public function testCanClearQueue()
+ {
+ $plugin = new MockPlugin();
+ $plugin->addResponse(Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
+ $plugin->clearQueue();
+ $this->assertEquals(0, count($plugin));
+ }
+
+ public function testCanInspectQueue()
+ {
+ $plugin = new MockPlugin();
+ $this->assertInternalType('array', $plugin->getQueue());
+ $plugin->addResponse(Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
+ $queue = $plugin->getQueue();
+ $this->assertInternalType('array', $queue);
+ $this->assertEquals(1, count($queue));
+ }
+
+ public function testRetrievesResponsesFromFiles()
+ {
+ $response = MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response');
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $response);
+ $this->assertEquals(200, $response->getStatusCode());
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testThrowsExceptionWhenResponseFileIsNotFound()
+ {
+ MockPlugin::getMockFile('missing/filename');
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testInvalidResponsesThrowAnException()
+ {
+ $p = new MockPlugin();
+ $p->addResponse($this);
+ }
+
+ public function testAddsResponseObjectsToQueue()
+ {
+ $p = new MockPlugin();
+ $response = Response::fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $p->addResponse($response);
+ $this->assertEquals(array($response), $p->getQueue());
+ }
+
+ public function testAddsResponseFilesToQueue()
+ {
+ $p = new MockPlugin();
+ $p->addResponse(__DIR__ . '/../../TestData/mock_response');
+ $this->assertEquals(1, count($p));
+ }
+
+ /**
+ * @depends testAddsResponseFilesToQueue
+ */
+ public function testAddsMockResponseToRequestFromClient()
+ {
+ $p = new MockPlugin();
+ $response = MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response');
+ $p->addResponse($response);
+
+ $client = new Client('http://127.0.0.1:123/');
+ $client->getEventDispatcher()->addSubscriber($p, 9999);
+ $request = $client->get();
+ $request->send();
+
+ $this->assertSame($response, $request->getResponse());
+ $this->assertEquals(0, count($p));
+ }
+
+ /**
+ * @depends testAddsResponseFilesToQueue
+ * @expectedException \OutOfBoundsException
+ */
+ public function testUpdateThrowsExceptionWhenEmpty()
+ {
+ $p = new MockPlugin();
+ $p->onRequestBeforeSend(new Event());
+ }
+
+ /**
+ * @depends testAddsMockResponseToRequestFromClient
+ */
+ public function testDetachesTemporaryWhenEmpty()
+ {
+ $p = new MockPlugin(null, true);
+ $p->addResponse(MockPlugin::getMockFile(__DIR__ . '/../../TestData/mock_response'));
+ $client = new Client('http://127.0.0.1:123/');
+ $client->getEventDispatcher()->addSubscriber($p, 9999);
+ $request = $client->get();
+ $request->send();
+
+ $this->assertFalse($this->hasSubscriber($client, $p));
+ }
+
+ public function testLoadsResponsesFromConstructor()
+ {
+ $p = new MockPlugin(array(new Response(200)));
+ $this->assertEquals(1, $p->count());
+ }
+
+ public function testStoresMockedRequests()
+ {
+ $p = new MockPlugin(array(new Response(200), new Response(200)));
+ $client = new Client('http://127.0.0.1:123/');
+ $client->getEventDispatcher()->addSubscriber($p, 9999);
+
+ $request1 = $client->get();
+ $request1->send();
+ $this->assertEquals(array($request1), $p->getReceivedRequests());
+
+ $request2 = $client->get();
+ $request2->send();
+ $this->assertEquals(array($request1, $request2), $p->getReceivedRequests());
+
+ $p->flush();
+ $this->assertEquals(array(), $p->getReceivedRequests());
+ }
+
+ public function testReadsBodiesFromMockedRequests()
+ {
+ $p = new MockPlugin(array(new Response(200)));
+ $p->readBodies(true);
+ $client = new Client('http://127.0.0.1:123/');
+ $client->getEventDispatcher()->addSubscriber($p, 9999);
+
+ $body = EntityBody::factory('foo');
+ $request = $client->put();
+ $request->setBody($body);
+ $request->send();
+ $this->assertEquals(3, $body->ftell());
+ }
+
+ public function testCanMockBadRequestExceptions()
+ {
+ $client = new Client('http://127.0.0.1:123/');
+ $ex = new CurlException('Foo');
+ $mock = new MockPlugin(array($ex));
+ $client->addSubscriber($mock);
+ $request = $client->get('foo');
+
+ try {
+ $request->send();
+ $this->fail('Did not dequeue an exception');
+ } catch (CurlException $e) {
+ $this->assertSame($e, $ex);
+ $this->assertSame($request, $ex->getRequest());
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php
new file mode 100755
index 0000000..3892fb6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Plugin/Oauth/OauthPluginTest.php
@@ -0,0 +1,345 @@
+ 'foo',
+ 'consumer_secret' => 'bar',
+ 'token' => 'count',
+ 'token_secret' => 'dracula'
+ );
+
+ protected function getRequest()
+ {
+ return RequestFactory::getInstance()->create('POST', 'http://www.test.com/path?a=b&c=d', null, array(
+ 'e' => 'f'
+ ));
+ }
+
+ public function testSubscribesToEvents()
+ {
+ $events = OauthPlugin::getSubscribedEvents();
+ $this->assertArrayHasKey('request.before_send', $events);
+ }
+
+ public function testAcceptsConfigurationData()
+ {
+ $p = new OauthPlugin($this->config);
+
+ // Access the config object
+ $class = new \ReflectionClass($p);
+ $property = $class->getProperty('config');
+ $property->setAccessible(true);
+ $config = $property->getValue($p);
+
+ $this->assertEquals('foo', $config['consumer_key']);
+ $this->assertEquals('bar', $config['consumer_secret']);
+ $this->assertEquals('count', $config['token']);
+ $this->assertEquals('dracula', $config['token_secret']);
+ $this->assertEquals('1.0', $config['version']);
+ $this->assertEquals('HMAC-SHA1', $config['signature_method']);
+ $this->assertEquals('header', $config['request_method']);
+ }
+
+ public function testCreatesStringToSignFromPostRequest()
+ {
+ $p = new OauthPlugin($this->config);
+ $request = $this->getRequest();
+ $signString = $p->getStringToSign($request, self::TIMESTAMP, self::NONCE);
+
+ $this->assertContains('&e=f', rawurldecode($signString));
+
+ $expectedSignString =
+ // Method and URL
+ 'POST&http%3A%2F%2Fwww.test.com%2Fpath' .
+ // Sorted parameters from query string and body
+ '&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' .
+ '%26oauth_nonce%3De7aa11195ca58349bec8b5ebe351d3497eb9e603%26' .
+ 'oauth_signature_method%3DHMAC-SHA1' .
+ '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0';
+
+ $this->assertEquals($expectedSignString, $signString);
+ }
+
+ public function testCreatesStringToSignIgnoringPostFields()
+ {
+ $config = $this->config;
+ $config['disable_post_params'] = true;
+ $p = new OauthPlugin($config);
+ $request = $this->getRequest();
+ $sts = rawurldecode($p->getStringToSign($request, self::TIMESTAMP, self::NONCE));
+ $this->assertNotContains('&e=f', $sts);
+ }
+
+ public function testCreatesStringToSignFromPostRequestWithCustomContentType()
+ {
+ $p = new OauthPlugin($this->config);
+ $request = $this->getRequest();
+ $request->setHeader('Content-Type', 'Foo');
+ $this->assertEquals(
+ // Method and URL
+ 'POST&http%3A%2F%2Fwww.test.com%2Fpath' .
+ // Sorted parameters from query string and body
+ '&a%3Db%26c%3Dd%26oauth_consumer_key%3Dfoo' .
+ '%26oauth_nonce%3D'. self::NONCE .'%26' .
+ 'oauth_signature_method%3DHMAC-SHA1' .
+ '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0',
+ $p->getStringToSign($request, self::TIMESTAMP, self::NONCE)
+ );
+ }
+
+ /**
+ * @depends testCreatesStringToSignFromPostRequest
+ */
+ public function testConvertsBooleansToStrings()
+ {
+ $p = new OauthPlugin($this->config);
+ $request = $this->getRequest();
+ $request->getQuery()->set('a', true);
+ $request->getQuery()->set('c', false);
+ $this->assertContains('&a%3Dtrue%26c%3Dfalse', $p->getStringToSign($request, self::TIMESTAMP, self::NONCE));
+ }
+
+ public function testCreatesStringToSignFromPostRequestWithNullValues()
+ {
+ $config = array(
+ 'consumer_key' => 'foo',
+ 'consumer_secret' => 'bar',
+ 'token' => null,
+ 'token_secret' => 'dracula'
+ );
+
+ $p = new OauthPlugin($config);
+ $request = $this->getRequest();
+ $signString = $p->getStringToSign($request, self::TIMESTAMP, self::NONCE);
+
+ $this->assertContains('&e=f', rawurldecode($signString));
+
+ $expectedSignString = // Method and URL
+ 'POST&http%3A%2F%2Fwww.test.com%2Fpath' .
+ // Sorted parameters from query string and body
+ '&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' .
+ '%26oauth_nonce%3De7aa11195ca58349bec8b5ebe351d3497eb9e603%26' .
+ 'oauth_signature_method%3DHMAC-SHA1' .
+ '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_version%3D1.0';
+
+ $this->assertEquals($expectedSignString, $signString);
+ }
+
+ /**
+ * @depends testCreatesStringToSignFromPostRequest
+ */
+ public function testMultiDimensionalArray()
+ {
+ $p = new OauthPlugin($this->config);
+ $request = $this->getRequest();
+ $request->getQuery()->set('a', array('b' => array('e' => 'f', 'c' => 'd')));
+ $this->assertContains('a%255Bb%255D%255Bc%255D%3Dd%26a%255Bb%255D%255Be%255D%3Df%26c%3Dd%26e%3Df%26', $p->getStringToSign($request, self::TIMESTAMP, self::NONCE));
+ }
+
+ /**
+ * @depends testMultiDimensionalArray
+ */
+ public function testMultiDimensionalArrayWithNonDefaultQueryAggregator()
+ {
+ $p = new OauthPlugin($this->config);
+ $request = $this->getRequest();
+ $aggregator = new CommaAggregator();
+ $query = $request->getQuery()->setAggregator($aggregator)
+ ->set('g', array('h', 'i', 'j'))
+ ->set('k', array('l'))
+ ->set('m', array('n', 'o'));
+ $this->assertContains('a%3Db%26c%3Dd%26e%3Df%26g%3Dh%2Ci%2Cj%26k%3Dl%26m%3Dn%2Co', $p->getStringToSign($request, self::TIMESTAMP, self::NONCE));
+ }
+
+ /**
+ * @depends testCreatesStringToSignFromPostRequest
+ */
+ public function testSignsStrings()
+ {
+ $p = new OauthPlugin(array_merge($this->config, array(
+ 'signature_callback' => function($string, $key) {
+ return "_{$string}|{$key}_";
+ }
+ )));
+ $request = $this->getRequest();
+ $sig = $p->getSignature($request, self::TIMESTAMP, self::NONCE);
+ $this->assertEquals(
+ '_POST&http%3A%2F%2Fwww.test.com%2Fpath&a%3Db%26c%3Dd%26e%3Df%26oauth_consumer_key%3Dfoo' .
+ '%26oauth_nonce%3D'. self::NONCE .'%26oauth_signature_method%3DHMAC-SHA1' .
+ '%26oauth_timestamp%3D' . self::TIMESTAMP . '%26oauth_token%3Dcount%26oauth_version%3D1.0|' .
+ 'bar&dracula_',
+ base64_decode($sig)
+ );
+ }
+
+ /**
+ * Test that the Oauth is signed correctly and that extra strings haven't been added
+ * to the authorization header.
+ */
+ public function testSignsOauthRequests()
+ {
+ $p = new OauthPlugin($this->config);
+ $event = new Event(array(
+ 'request' => $this->getRequest(),
+ 'timestamp' => self::TIMESTAMP
+ ));
+ $params = $p->onRequestBeforeSend($event);
+
+ $this->assertTrue($event['request']->hasHeader('Authorization'));
+
+ $authorizationHeader = (string)$event['request']->getHeader('Authorization');
+
+ $this->assertStringStartsWith('OAuth ', $authorizationHeader);
+
+ $stringsToCheck = array(
+ 'oauth_consumer_key="foo"',
+ 'oauth_nonce="'.urlencode($params['oauth_nonce']).'"',
+ 'oauth_signature="'.urlencode($params['oauth_signature']).'"',
+ 'oauth_signature_method="HMAC-SHA1"',
+ 'oauth_timestamp="' . self::TIMESTAMP . '"',
+ 'oauth_token="count"',
+ 'oauth_version="1.0"',
+ );
+
+ $totalLength = strlen('OAuth ');
+
+ //Separator is not used before first parameter.
+ $separator = '';
+
+ foreach ($stringsToCheck as $stringToCheck) {
+ $this->assertContains($stringToCheck, $authorizationHeader);
+ $totalLength += strlen($separator);
+ $totalLength += strlen($stringToCheck);
+ $separator = ', ';
+ }
+
+ // Technically this test is not universally valid. It would be allowable to have extra \n characters
+ // in the Authorization header. However Guzzle does not do this, so we just perform a simple check
+ // on length to validate the Authorization header is composed of only the strings above.
+ $this->assertEquals($totalLength, strlen($authorizationHeader), 'Authorization has extra characters i.e. contains extra elements compared to stringsToCheck.');
+ }
+
+ public function testSignsOauthQueryStringRequest()
+ {
+ $config = array_merge(
+ $this->config,
+ array('request_method' => OauthPlugin::REQUEST_METHOD_QUERY)
+ );
+
+ $p = new OauthPlugin($config);
+ $event = new Event(array(
+ 'request' => $this->getRequest(),
+ 'timestamp' => self::TIMESTAMP
+ ));
+ $params = $p->onRequestBeforeSend($event);
+
+ $this->assertFalse($event['request']->hasHeader('Authorization'));
+
+ $stringsToCheck = array(
+ 'a=b',
+ 'c=d',
+ 'oauth_consumer_key=foo',
+ 'oauth_nonce='.urlencode($params['oauth_nonce']),
+ 'oauth_signature='.urlencode($params['oauth_signature']),
+ 'oauth_signature_method=HMAC-SHA1',
+ 'oauth_timestamp='.self::TIMESTAMP,
+ 'oauth_token=count',
+ 'oauth_version=1.0',
+ );
+
+ $queryString = (string) $event['request']->getQuery();
+
+ $totalLength = strlen('?');
+
+ //Separator is not used before first parameter.
+ $separator = '';
+
+ foreach ($stringsToCheck as $stringToCheck) {
+ $this->assertContains($stringToCheck, $queryString);
+ $totalLength += strlen($separator);
+ $totalLength += strlen($stringToCheck);
+ $separator = '&';
+ }
+
+ // Removes the last query string separator '&'
+ $totalLength -= 1;
+
+ $this->assertEquals($totalLength, strlen($queryString), 'Query string has extra characters i.e. contains extra elements compared to stringsToCheck.');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testInvalidArgumentExceptionOnMethodError()
+ {
+ $config = array_merge(
+ $this->config,
+ array('request_method' => 'FakeMethod')
+ );
+
+ $p = new OauthPlugin($config);
+ $event = new Event(array(
+ 'request' => $this->getRequest(),
+ 'timestamp' => self::TIMESTAMP
+ ));
+
+ $p->onRequestBeforeSend($event);
+ }
+
+ public function testDoesNotAddFalseyValuesToAuthorization()
+ {
+ unset($this->config['token']);
+ $p = new OauthPlugin($this->config);
+ $event = new Event(array('request' => $this->getRequest(), 'timestamp' => self::TIMESTAMP));
+ $p->onRequestBeforeSend($event);
+ $this->assertTrue($event['request']->hasHeader('Authorization'));
+ $this->assertNotContains('oauth_token=', (string) $event['request']->getHeader('Authorization'));
+ }
+
+ public function testOptionalOauthParametersAreNotAutomaticallyAdded()
+ {
+ // The only required Oauth parameters are the consumer key and secret. That is enough credentials
+ // for signing oauth requests.
+ $config = array(
+ 'consumer_key' => 'foo',
+ 'consumer_secret' => 'bar',
+ );
+
+ $plugin = new OauthPlugin($config);
+ $event = new Event(array(
+ 'request' => $this->getRequest(),
+ 'timestamp' => self::TIMESTAMP
+ ));
+
+ $timestamp = $plugin->getTimestamp($event);
+ $request = $event['request'];
+ $nonce = $plugin->generateNonce($request);
+
+ $paramsToSign = $plugin->getParamsToSign($request, $timestamp, $nonce);
+
+ $optionalParams = array(
+ 'callback' => 'oauth_callback',
+ 'token' => 'oauth_token',
+ 'verifier' => 'oauth_verifier',
+ 'token_secret' => 'token_secret'
+ );
+
+ foreach ($optionalParams as $optionName => $oauthName) {
+ $this->assertArrayNotHasKey($oauthName, $paramsToSign, "Optional Oauth param '$oauthName' was not set via config variable '$optionName', but it is listed in getParamsToSign().");
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php
new file mode 100755
index 0000000..8b42fb8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/AbstractConfigLoaderTest.php
@@ -0,0 +1,149 @@
+loader = $this->getMockBuilder('Guzzle\Service\AbstractConfigLoader')
+ ->setMethods(array('build'))
+ ->getMockForAbstractClass();
+ }
+
+ public function tearDown()
+ {
+ foreach ($this->cleanup as $file) {
+ unlink($file);
+ }
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testOnlyLoadsSupportedTypes()
+ {
+ $this->loader->load(new \stdClass());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Unable to open fooooooo.json
+ */
+ public function testFileMustBeReadable()
+ {
+ $this->loader->load('fooooooo.json');
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Unknown file extension
+ */
+ public function testMustBeSupportedExtension()
+ {
+ $this->loader->load(dirname(__DIR__) . '/TestData/FileBody.txt');
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ * @expectedExceptionMessage Error loading JSON data from
+ */
+ public function testJsonMustBeValue()
+ {
+ $filename = tempnam(sys_get_temp_dir(), 'json') . '.json';
+ file_put_contents($filename, '{/{./{}foo');
+ $this->cleanup[] = $filename;
+ $this->loader->load($filename);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ * @expectedExceptionMessage PHP files must return an array
+ */
+ public function testPhpFilesMustReturnAnArray()
+ {
+ $filename = tempnam(sys_get_temp_dir(), 'php') . '.php';
+ file_put_contents($filename, 'cleanup[] = $filename;
+ $this->loader->load($filename);
+ }
+
+ public function testLoadsPhpFileIncludes()
+ {
+ $filename = tempnam(sys_get_temp_dir(), 'php') . '.php';
+ file_put_contents($filename, ' "bar");');
+ $this->cleanup[] = $filename;
+ $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0));
+ $config = $this->loader->load($filename);
+ $this->assertEquals(array('foo' => 'bar'), $config);
+ }
+
+ public function testCanCreateFromJson()
+ {
+ $file = dirname(__DIR__) . '/TestData/services/json1.json';
+ // The build method will just return the config data
+ $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0));
+ $data = $this->loader->load($file);
+ // Ensure that the config files were merged using the includes directives
+ $this->assertArrayHasKey('includes', $data);
+ $this->assertArrayHasKey('services', $data);
+ $this->assertInternalType('array', $data['services']['foo']);
+ $this->assertInternalType('array', $data['services']['abstract']);
+ $this->assertInternalType('array', $data['services']['mock']);
+ $this->assertEquals('bar', $data['services']['foo']['params']['baz']);
+ }
+
+ public function testUsesAliases()
+ {
+ $file = dirname(__DIR__) . '/TestData/services/json1.json';
+ $this->loader->addAlias('foo', $file);
+ // The build method will just return the config data
+ $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0));
+ $data = $this->loader->load('foo');
+ $this->assertEquals('bar', $data['services']['foo']['params']['baz']);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Unable to open foo.json
+ */
+ public function testCanRemoveAliases()
+ {
+ $file = dirname(__DIR__) . '/TestData/services/json1.json';
+ $this->loader->addAlias('foo.json', $file);
+ $this->loader->removeAlias('foo.json');
+ $this->loader->load('foo.json');
+ }
+
+ public function testCanLoadArraysWithIncludes()
+ {
+ $file = dirname(__DIR__) . '/TestData/services/json1.json';
+ $config = array('includes' => array($file));
+ // The build method will just return the config data
+ $this->loader->expects($this->exactly(1))->method('build')->will($this->returnArgument(0));
+ $data = $this->loader->load($config);
+ $this->assertEquals('bar', $data['services']['foo']['params']['baz']);
+ }
+
+ public function testDoesNotEnterInfiniteLoop()
+ {
+ $prefix = $file = dirname(__DIR__) . '/TestData/description';
+ $this->loader->load("{$prefix}/baz.json");
+ $this->assertCount(4, $this->readAttribute($this->loader, 'loadedFiles'));
+ // Ensure that the internal list of loaded files is reset
+ $this->loader->load("{$prefix}/../test_service2.json");
+ $this->assertCount(1, $this->readAttribute($this->loader, 'loadedFiles'));
+ // Ensure that previously loaded files will be reloaded when starting fresh
+ $this->loader->load("{$prefix}/baz.json");
+ $this->assertCount(4, $this->readAttribute($this->loader, 'loadedFiles'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php
new file mode 100755
index 0000000..f63070e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderLoaderTest.php
@@ -0,0 +1,177 @@
+ array(
+ 'abstract' => array(
+ 'params' => array(
+ 'access_key' => 'xyz',
+ 'secret' => 'abc',
+ ),
+ ),
+ 'foo' => array(
+ 'extends' => 'abstract',
+ 'params' => array(
+ 'baz' => 'bar',
+ ),
+ ),
+ 'mock' => array(
+ 'extends' => 'abstract',
+ 'params' => array(
+ 'username' => 'foo',
+ 'password' => 'baz',
+ 'subdomain' => 'bar',
+ )
+ )
+ )
+ );
+
+ $builder = $arrayFactory->load($data);
+
+ // Ensure that services were parsed
+ $this->assertTrue(isset($builder['mock']));
+ $this->assertTrue(isset($builder['abstract']));
+ $this->assertTrue(isset($builder['foo']));
+ $this->assertFalse(isset($builder['jimmy']));
+ }
+
+ /**
+ * @expectedException Guzzle\Service\Exception\ServiceNotFoundException
+ * @expectedExceptionMessage foo is trying to extend a non-existent service: abstract
+ */
+ public function testThrowsExceptionWhenExtendingNonExistentService()
+ {
+ $arrayFactory = new ServiceBuilderLoader();
+
+ $data = array(
+ 'services' => array(
+ 'foo' => array(
+ 'extends' => 'abstract'
+ )
+ )
+ );
+
+ $builder = $arrayFactory->load($data);
+ }
+
+ public function testAllowsGlobalParameterOverrides()
+ {
+ $arrayFactory = new ServiceBuilderLoader();
+
+ $data = array(
+ 'services' => array(
+ 'foo' => array(
+ 'params' => array(
+ 'foo' => 'baz',
+ 'bar' => 'boo'
+ )
+ )
+ )
+ );
+
+ $builder = $arrayFactory->load($data, array(
+ 'bar' => 'jar',
+ 'far' => 'car'
+ ));
+
+ $compiled = json_decode($builder->serialize(), true);
+ $this->assertEquals(array(
+ 'foo' => 'baz',
+ 'bar' => 'jar',
+ 'far' => 'car'
+ ), $compiled['foo']['params']);
+ }
+
+ public function tstDoesNotErrorOnCircularReferences()
+ {
+ $arrayFactory = new ServiceBuilderLoader();
+ $arrayFactory->load(array(
+ 'services' => array(
+ 'too' => array('extends' => 'ball'),
+ 'ball' => array('extends' => 'too'),
+ )
+ ));
+ }
+
+ public function configProvider()
+ {
+ $foo = array(
+ 'extends' => 'bar',
+ 'class' => 'stdClass',
+ 'params' => array('a' => 'test', 'b' => '456')
+ );
+
+ return array(
+ array(
+ // Does not extend the existing `foo` service but overwrites it
+ array(
+ 'services' => array(
+ 'foo' => $foo,
+ 'bar' => array('params' => array('baz' => '123'))
+ )
+ ),
+ array(
+ 'services' => array(
+ 'foo' => array('class' => 'Baz')
+ )
+ ),
+ array(
+ 'services' => array(
+ 'foo' => array('class' => 'Baz'),
+ 'bar' => array('params' => array('baz' => '123'))
+ )
+ )
+ ),
+ array(
+ // Extends the existing `foo` service
+ array(
+ 'services' => array(
+ 'foo' => $foo,
+ 'bar' => array('params' => array('baz' => '123'))
+ )
+ ),
+ array(
+ 'services' => array(
+ 'foo' => array(
+ 'extends' => 'foo',
+ 'params' => array('b' => '123', 'c' => 'def')
+ )
+ )
+ ),
+ array(
+ 'services' => array(
+ 'foo' => array(
+ 'extends' => 'bar',
+ 'class' => 'stdClass',
+ 'params' => array('a' => 'test', 'b' => '123', 'c' => 'def')
+ ),
+ 'bar' => array('params' => array('baz' => '123'))
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider configProvider
+ */
+ public function testCombinesConfigs($a, $b, $c)
+ {
+ $l = new ServiceBuilderLoader();
+ $m = new \ReflectionMethod($l, 'mergeData');
+ $m->setAccessible(true);
+ $this->assertEquals($c, $m->invoke($l, $a, $b));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php
new file mode 100755
index 0000000..e1b3a1d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Builder/ServiceBuilderTest.php
@@ -0,0 +1,317 @@
+ array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'username' => 'michael',
+ 'password' => 'testing123',
+ 'subdomain' => 'michael',
+ ),
+ ),
+ 'billy.mock' => array(
+ 'alias' => 'Hello!',
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'username' => 'billy',
+ 'password' => 'passw0rd',
+ 'subdomain' => 'billy',
+ ),
+ ),
+ 'billy.testing' => array(
+ 'extends' => 'billy.mock',
+ 'params' => array(
+ 'subdomain' => 'test.billy',
+ ),
+ ),
+ 'missing_params' => array(
+ 'extends' => 'billy.mock'
+ )
+ );
+
+ public function testAllowsSerialization()
+ {
+ $builder = ServiceBuilder::factory($this->arrayData);
+ $cached = unserialize(serialize($builder));
+ $this->assertEquals($cached, $builder);
+ }
+
+ public function testDelegatesFactoryMethodToAbstractFactory()
+ {
+ $builder = ServiceBuilder::factory($this->arrayData);
+ $c = $builder->get('michael.mock');
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $c);
+ }
+
+ /**
+ * @expectedException Guzzle\Service\Exception\ServiceNotFoundException
+ * @expectedExceptionMessage No service is registered as foobar
+ */
+ public function testThrowsExceptionWhenGettingInvalidClient()
+ {
+ ServiceBuilder::factory($this->arrayData)->get('foobar');
+ }
+
+ public function testStoresClientCopy()
+ {
+ $builder = ServiceBuilder::factory($this->arrayData);
+ $client = $builder->get('michael.mock');
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $client);
+ $this->assertEquals('http://127.0.0.1:8124/v1/michael', $client->getBaseUrl());
+ $this->assertEquals($client, $builder->get('michael.mock'));
+
+ // Get another client but throw this one away
+ $client2 = $builder->get('billy.mock', true);
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $client2);
+ $this->assertEquals('http://127.0.0.1:8124/v1/billy', $client2->getBaseUrl());
+
+ // Make sure the original client is still there and set
+ $this->assertTrue($client === $builder->get('michael.mock'));
+
+ // Create a new billy.mock client that is stored
+ $client3 = $builder->get('billy.mock');
+
+ // Make sure that the stored billy.mock client is equal to the other stored client
+ $this->assertTrue($client3 === $builder->get('billy.mock'));
+
+ // Make sure that this client is not equal to the previous throwaway client
+ $this->assertFalse($client2 === $builder->get('billy.mock'));
+ }
+
+ public function testBuildersPassOptionsThroughToClients()
+ {
+ $s = new ServiceBuilder(array(
+ 'michael.mock' => array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'base_url' => 'http://www.test.com/',
+ 'subdomain' => 'michael',
+ 'password' => 'test',
+ 'username' => 'michael',
+ 'curl.curlopt_proxyport' => 8080
+ )
+ )
+ ));
+
+ $c = $s->get('michael.mock');
+ $this->assertEquals(8080, $c->getConfig('curl.curlopt_proxyport'));
+ }
+
+ public function testUsesTheDefaultBuilderWhenNoBuilderIsSpecified()
+ {
+ $s = new ServiceBuilder(array(
+ 'michael.mock' => array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'base_url' => 'http://www.test.com/',
+ 'subdomain' => 'michael',
+ 'password' => 'test',
+ 'username' => 'michael',
+ 'curl.curlopt_proxyport' => 8080
+ )
+ )
+ ));
+
+ $c = $s->get('michael.mock');
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $c);
+ }
+
+ public function testUsedAsArray()
+ {
+ $b = ServiceBuilder::factory($this->arrayData);
+ $this->assertTrue($b->offsetExists('michael.mock'));
+ $this->assertFalse($b->offsetExists('not_there'));
+ $this->assertInstanceOf('Guzzle\Service\Client', $b['michael.mock']);
+
+ unset($b['michael.mock']);
+ $this->assertFalse($b->offsetExists('michael.mock'));
+
+ $b['michael.mock'] = new Client('http://www.test.com/');
+ $this->assertInstanceOf('Guzzle\Service\Client', $b['michael.mock']);
+ }
+
+ public function testFactoryCanCreateFromJson()
+ {
+ $tmp = sys_get_temp_dir() . '/test.js';
+ file_put_contents($tmp, json_encode($this->arrayData));
+ $b = ServiceBuilder::factory($tmp);
+ unlink($tmp);
+ $s = $b->get('billy.testing');
+ $this->assertEquals('test.billy', $s->getConfig('subdomain'));
+ $this->assertEquals('billy', $s->getConfig('username'));
+ }
+
+ public function testFactoryCanCreateFromArray()
+ {
+ $b = ServiceBuilder::factory($this->arrayData);
+ $s = $b->get('billy.testing');
+ $this->assertEquals('test.billy', $s->getConfig('subdomain'));
+ $this->assertEquals('billy', $s->getConfig('username'));
+ }
+
+ public function testFactoryDoesNotRequireParams()
+ {
+ $b = ServiceBuilder::factory($this->arrayData);
+ $s = $b->get('missing_params');
+ $this->assertEquals('billy', $s->getConfig('username'));
+ }
+
+ public function testBuilderAllowsReferencesBetweenClients()
+ {
+ $builder = ServiceBuilder::factory(array(
+ 'a' => array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'other_client' => '{b}',
+ 'username' => 'x',
+ 'password' => 'y',
+ 'subdomain' => 'z'
+ )
+ ),
+ 'b' => array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'username' => '1',
+ 'password' => '2',
+ 'subdomain' => '3'
+ )
+ )
+ ));
+
+ $client = $builder['a'];
+ $this->assertEquals('x', $client->getConfig('username'));
+ $this->assertSame($builder['b'], $client->getConfig('other_client'));
+ $this->assertEquals('1', $builder['b']->getConfig('username'));
+ }
+
+ public function testEmitsEventsWhenClientsAreCreated()
+ {
+ // Ensure that the client signals that it emits an event
+ $this->assertEquals(array('service_builder.create_client'), ServiceBuilder::getAllEvents());
+
+ // Create a test service builder
+ $builder = ServiceBuilder::factory(array(
+ 'a' => array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'username' => 'test',
+ 'password' => '123',
+ 'subdomain' => 'z'
+ )
+ )
+ ));
+
+ // Add an event listener to pick up client creation events
+ $emits = 0;
+ $builder->getEventDispatcher()->addListener('service_builder.create_client', function($event) use (&$emits) {
+ $emits++;
+ });
+
+ // Get the 'a' client by name
+ $client = $builder->get('a');
+
+ // Ensure that the event was emitted once, and that the client was present
+ $this->assertEquals(1, $emits);
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $client);
+ }
+
+ public function testCanAddGlobalParametersToServicesOnLoad()
+ {
+ $builder = ServiceBuilder::factory($this->arrayData, array(
+ 'username' => 'fred',
+ 'new_value' => 'test'
+ ));
+
+ $data = json_decode($builder->serialize(), true);
+
+ foreach ($data as $service) {
+ $this->assertEquals('fred', $service['params']['username']);
+ $this->assertEquals('test', $service['params']['new_value']);
+ }
+ }
+
+ public function testAddsGlobalPlugins()
+ {
+ $b = new ServiceBuilder($this->arrayData);
+ $b->addGlobalPlugin(new HistoryPlugin());
+ $s = $b->get('michael.mock');
+ $this->assertTrue($s->getEventDispatcher()->hasListeners('request.sent'));
+ }
+
+ public function testCanGetData()
+ {
+ $b = new ServiceBuilder($this->arrayData);
+ $this->assertEquals($this->arrayData['michael.mock'], $b->getData('michael.mock'));
+ $this->assertNull($b->getData('ewofweoweofe'));
+ }
+
+ public function testCanGetByAlias()
+ {
+ $b = new ServiceBuilder($this->arrayData);
+ $this->assertSame($b->get('billy.mock'), $b->get('Hello!'));
+ }
+
+ public function testCanOverwriteParametersForThrowawayClients()
+ {
+ $b = new ServiceBuilder($this->arrayData);
+
+ $c1 = $b->get('michael.mock');
+ $this->assertEquals('michael', $c1->getConfig('username'));
+
+ $c2 = $b->get('michael.mock', array('username' => 'jeremy'));
+ $this->assertEquals('jeremy', $c2->getConfig('username'));
+ }
+
+ public function testGettingAThrowawayClientWithParametersDoesNotAffectGettingOtherClients()
+ {
+ $b = new ServiceBuilder($this->arrayData);
+
+ $c1 = $b->get('michael.mock', array('username' => 'jeremy'));
+ $this->assertEquals('jeremy', $c1->getConfig('username'));
+
+ $c2 = $b->get('michael.mock');
+ $this->assertEquals('michael', $c2->getConfig('username'));
+ }
+
+ public function testCanUseArbitraryData()
+ {
+ $b = new ServiceBuilder();
+ $b['a'] = 'foo';
+ $this->assertTrue(isset($b['a']));
+ $this->assertEquals('foo', $b['a']);
+ unset($b['a']);
+ $this->assertFalse(isset($b['a']));
+ }
+
+ public function testCanRegisterServiceData()
+ {
+ $b = new ServiceBuilder();
+ $b['a'] = array(
+ 'class' => 'Guzzle\Tests\Service\Mock\MockClient',
+ 'params' => array(
+ 'username' => 'billy',
+ 'password' => 'passw0rd',
+ 'subdomain' => 'billy',
+ )
+ );
+ $this->assertTrue(isset($b['a']));
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\MockClient', $b['a']);
+ $client = $b['a'];
+ unset($b['a']);
+ $this->assertFalse(isset($b['a']));
+ // Ensure that instantiated clients can be registered
+ $b['mock'] = $client;
+ $this->assertSame($client, $b['mock']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php
new file mode 100755
index 0000000..b8245ad
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/CachingConfigLoaderTest.php
@@ -0,0 +1,43 @@
+getMockBuilder('Guzzle\Service\ConfigLoaderInterface')
+ ->setMethods(array('load'))
+ ->getMockForAbstractClass();
+ $data = array('foo' => 'bar');
+ $loader->expects($this->once())
+ ->method('load')
+ ->will($this->returnValue($data));
+ $cache = new CachingConfigLoader($loader, $cache);
+ $this->assertEquals($data, $cache->load('foo'));
+ $this->assertEquals($data, $cache->load('foo'));
+ }
+
+ public function testDoesNotCacheArrays()
+ {
+ $cache = new DoctrineCacheAdapter(new ArrayCache());
+ $loader = $this->getMockBuilder('Guzzle\Service\ConfigLoaderInterface')
+ ->setMethods(array('load'))
+ ->getMockForAbstractClass();
+ $data = array('foo' => 'bar');
+ $loader->expects($this->exactly(2))
+ ->method('load')
+ ->will($this->returnValue($data));
+ $cache = new CachingConfigLoader($loader, $cache);
+ $this->assertEquals($data, $cache->load(array()));
+ $this->assertEquals($data, $cache->load(array()));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php
new file mode 100755
index 0000000..aee29ed
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/ClientTest.php
@@ -0,0 +1,320 @@
+serviceTest = new ServiceDescription(array(
+ 'test_command' => new Operation(array(
+ 'doc' => 'documentationForCommand',
+ 'method' => 'DELETE',
+ 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand',
+ 'args' => array(
+ 'bucket' => array(
+ 'required' => true
+ ),
+ 'key' => array(
+ 'required' => true
+ )
+ )
+ ))
+ ));
+
+ $this->service = ServiceDescription::factory(__DIR__ . '/../TestData/test_service.json');
+ }
+
+ public function testAllowsCustomClientParameters()
+ {
+ $client = new Mock\MockClient(null, array(
+ Client::COMMAND_PARAMS => array(AbstractCommand::RESPONSE_PROCESSING => 'foo')
+ ));
+ $command = $client->getCommand('mock_command');
+ $this->assertEquals('foo', $command->get(AbstractCommand::RESPONSE_PROCESSING));
+ }
+
+ public function testFactoryCreatesClient()
+ {
+ $client = Client::factory(array(
+ 'base_url' => 'http://www.test.com/',
+ 'test' => '123'
+ ));
+
+ $this->assertEquals('http://www.test.com/', $client->getBaseUrl());
+ $this->assertEquals('123', $client->getConfig('test'));
+ }
+
+ public function testFactoryDoesNotRequireBaseUrl()
+ {
+ $client = Client::factory();
+ }
+
+ public function testDescribesEvents()
+ {
+ $this->assertInternalType('array', Client::getAllEvents());
+ }
+
+ public function testExecutesCommands()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+
+ $client = new Client($this->getServer()->getUrl());
+ $cmd = new MockCommand();
+ $client->execute($cmd);
+
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $cmd->getResponse());
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Response', $cmd->getResult());
+ $this->assertEquals(1, count($this->getServer()->getReceivedRequests(false)));
+ }
+
+ public function testExecutesCommandsWithArray()
+ {
+ $client = new Client('http://www.test.com/');
+ $client->getEventDispatcher()->addSubscriber(new MockPlugin(array(
+ new Response(200),
+ new Response(200)
+ )));
+
+ // Create a command set and a command
+ $set = array(new MockCommand(), new MockCommand());
+ $client->execute($set);
+
+ // Make sure it sent
+ $this->assertTrue($set[0]->isExecuted());
+ $this->assertTrue($set[1]->isExecuted());
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testThrowsExceptionWhenInvalidCommandIsExecuted()
+ {
+ $client = new Client();
+ $client->execute(new \stdClass());
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testThrowsExceptionWhenMissingCommand()
+ {
+ $client = new Client();
+
+ $mock = $this->getMock('Guzzle\\Service\\Command\\Factory\\FactoryInterface');
+ $mock->expects($this->any())
+ ->method('factory')
+ ->with($this->equalTo('test'))
+ ->will($this->returnValue(null));
+
+ $client->setCommandFactory($mock);
+ $client->getCommand('test');
+ }
+
+ public function testCreatesCommandsUsingCommandFactory()
+ {
+ $mockCommand = new MockCommand();
+
+ $client = new Mock\MockClient();
+ $mock = $this->getMock('Guzzle\\Service\\Command\\Factory\\FactoryInterface');
+ $mock->expects($this->any())
+ ->method('factory')
+ ->with($this->equalTo('foo'))
+ ->will($this->returnValue($mockCommand));
+
+ $client->setCommandFactory($mock);
+
+ $command = $client->getCommand('foo', array('acl' => '123'));
+ $this->assertSame($mockCommand, $command);
+ $command = $client->getCommand('foo', array('acl' => '123'));
+ $this->assertSame($mockCommand, $command);
+ $this->assertSame($client, $command->getClient());
+ }
+
+ public function testOwnsServiceDescription()
+ {
+ $client = new Mock\MockClient();
+ $this->assertNull($client->getDescription());
+
+ $description = $this->getMock('Guzzle\\Service\\Description\\ServiceDescription');
+ $this->assertSame($client, $client->setDescription($description));
+ $this->assertSame($description, $client->getDescription());
+ }
+
+ public function testOwnsResourceIteratorFactory()
+ {
+ $client = new Mock\MockClient();
+
+ $method = new \ReflectionMethod($client, 'getResourceIteratorFactory');
+ $method->setAccessible(TRUE);
+ $rf1 = $method->invoke($client);
+
+ $rf = $this->readAttribute($client, 'resourceIteratorFactory');
+ $this->assertInstanceOf('Guzzle\\Service\\Resource\\ResourceIteratorClassFactory', $rf);
+ $this->assertSame($rf1, $rf);
+
+ $rf = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock');
+ $client->setResourceIteratorFactory($rf);
+ $this->assertNotSame($rf1, $rf);
+ }
+
+ public function testClientResetsRequestsBeforeExecutingCommands()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHi",
+ "HTTP/1.1 200 OK\r\nContent-Length: 1\r\n\r\nI"
+ ));
+
+ $client = new Mock\MockClient($this->getServer()->getUrl());
+
+ $command = $client->getCommand('mock_command');
+ $client->execute($command);
+ $client->execute($command);
+ $this->assertEquals('I', $command->getResponse()->getBody(true));
+ }
+
+ public function testClientCreatesIterators()
+ {
+ $client = new Mock\MockClient();
+
+ $iterator = $client->getIterator('mock_command', array(
+ 'foo' => 'bar'
+ ), array(
+ 'limit' => 10
+ ));
+
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ $this->assertEquals(10, $this->readAttribute($iterator, 'limit'));
+
+ $command = $this->readAttribute($iterator, 'originalCommand');
+ $this->assertEquals('bar', $command->get('foo'));
+ }
+
+ public function testClientCreatesIteratorsWithNoOptions()
+ {
+ $client = new Mock\MockClient();
+ $iterator = $client->getIterator('mock_command');
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ }
+
+ public function testClientCreatesIteratorsWithCommands()
+ {
+ $client = new Mock\MockClient();
+ $command = new MockCommand();
+ $iterator = $client->getIterator($command);
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ $iteratorCommand = $this->readAttribute($iterator, 'originalCommand');
+ $this->assertSame($command, $iteratorCommand);
+ }
+
+ public function testClientHoldsInflector()
+ {
+ $client = new Mock\MockClient();
+ $this->assertInstanceOf('Guzzle\Inflection\MemoizingInflector', $client->getInflector());
+
+ $inflector = new Inflector();
+ $client->setInflector($inflector);
+ $this->assertSame($inflector, $client->getInflector());
+ }
+
+ public function testClientAddsGlobalCommandOptions()
+ {
+ $client = new Mock\MockClient('http://www.foo.com', array(
+ Client::COMMAND_PARAMS => array(
+ 'mesa' => 'bar'
+ )
+ ));
+ $command = $client->getCommand('mock_command');
+ $this->assertEquals('bar', $command->get('mesa'));
+ }
+
+ public function testSupportsServiceDescriptionBaseUrls()
+ {
+ $description = new ServiceDescription(array('baseUrl' => 'http://foo.com'));
+ $client = new Client();
+ $client->setDescription($description);
+ $this->assertEquals('http://foo.com', $client->getBaseUrl());
+ }
+
+ public function testMergesDefaultCommandParamsCorrectly()
+ {
+ $client = new Mock\MockClient('http://www.foo.com', array(
+ Client::COMMAND_PARAMS => array(
+ 'mesa' => 'bar',
+ 'jar' => 'jar'
+ )
+ ));
+ $command = $client->getCommand('mock_command', array('jar' => 'test'));
+ $this->assertEquals('bar', $command->get('mesa'));
+ $this->assertEquals('test', $command->get('jar'));
+ }
+
+ /**
+ * @expectedException \Guzzle\Http\Exception\BadResponseException
+ */
+ public function testWrapsSingleCommandExceptions()
+ {
+ $client = new Mock\MockClient('http://foobaz.com');
+ $mock = new MockPlugin(array(new Response(401)));
+ $client->addSubscriber($mock);
+ $client->execute(new MockCommand());
+ }
+
+ public function testWrapsMultipleCommandExceptions()
+ {
+ $client = new Mock\MockClient('http://foobaz.com');
+ $mock = new MockPlugin(array(new Response(200), new Response(200), new Response(404), new Response(500)));
+ $client->addSubscriber($mock);
+
+ $cmds = array(new MockCommand(), new MockCommand(), new MockCommand(), new MockCommand());
+ try {
+ $client->execute($cmds);
+ } catch (CommandTransferException $e) {
+ $this->assertEquals(2, count($e->getFailedRequests()));
+ $this->assertEquals(2, count($e->getSuccessfulRequests()));
+ $this->assertEquals(2, count($e->getFailedCommands()));
+ $this->assertEquals(2, count($e->getSuccessfulCommands()));
+
+ foreach ($e->getSuccessfulCommands() as $c) {
+ $this->assertTrue($c->getResponse()->isSuccessful());
+ }
+
+ foreach ($e->getFailedCommands() as $c) {
+ $this->assertFalse($c->getRequest()->getResponse()->isSuccessful());
+ }
+ }
+ }
+
+ public function testGetCommandAfterTwoSetDescriptions()
+ {
+ $service1 = ServiceDescription::factory(__DIR__ . '/../TestData/test_service.json');
+ $service2 = ServiceDescription::factory(__DIR__ . '/../TestData/test_service_3.json');
+
+ $client = new Mock\MockClient();
+
+ $client->setDescription($service1);
+ $client->getCommand('foo_bar');
+ $client->setDescription($service2);
+ $client->getCommand('baz_qux');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php
new file mode 100755
index 0000000..1004fae
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/AbstractCommandTest.php
@@ -0,0 +1,16 @@
+setDescription(ServiceDescription::factory(__DIR__ . '/../../TestData/test_service.json'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php
new file mode 100755
index 0000000..d762246
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/ClosureCommandTest.php
@@ -0,0 +1,54 @@
+ function($command, $api) {
+ $command->set('testing', '123');
+ $request = RequestFactory::getInstance()->create('GET', 'http://www.test.com/');
+ return $request;
+ }
+ ));
+
+ $client = $this->getServiceBuilder()->get('mock');
+ $c->setClient($client)->prepare();
+ $this->assertEquals('123', $c->get('testing'));
+ $this->assertEquals('http://www.test.com/', $c->getRequest()->getUrl());
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ * @expectedExceptionMessage Closure command did not return a RequestInterface object
+ */
+ public function testMustReturnRequest()
+ {
+ $c = new ClosureCommand(array(
+ 'closure' => function($command, $api) {
+ return false;
+ }
+ ));
+
+ $client = $this->getServiceBuilder()->get('mock');
+ $c->setClient($client)->prepare();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php
new file mode 100755
index 0000000..b7173d4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/CommandTest.php
@@ -0,0 +1,445 @@
+assertEquals('123', $command->get('test'));
+ $this->assertFalse($command->isPrepared());
+ $this->assertFalse($command->isExecuted());
+ }
+
+ public function testDeterminesShortName()
+ {
+ $api = new Operation(array('name' => 'foobar'));
+ $command = new MockCommand(array(), $api);
+ $this->assertEquals('foobar', $command->getName());
+
+ $command = new MockCommand();
+ $this->assertEquals('mock_command', $command->getName());
+
+ $command = new Sub();
+ $this->assertEquals('sub.sub', $command->getName());
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testGetRequestThrowsExceptionBeforePreparation()
+ {
+ $command = new MockCommand();
+ $command->getRequest();
+ }
+
+ public function testGetResponseExecutesCommandsWhenNeeded()
+ {
+ $response = new Response(200);
+ $client = $this->getClient();
+ $this->setMockResponse($client, array($response));
+ $command = new MockCommand();
+ $command->setClient($client);
+ $this->assertSame($response, $command->getResponse());
+ $this->assertSame($response, $command->getResponse());
+ }
+
+ public function testGetResultExecutesCommandsWhenNeeded()
+ {
+ $response = new Response(200);
+ $client = $this->getClient();
+ $this->setMockResponse($client, array($response));
+ $command = new MockCommand();
+ $command->setClient($client);
+ $this->assertSame($response, $command->getResult());
+ $this->assertSame($response, $command->getResult());
+ }
+
+ public function testSetClient()
+ {
+ $command = new MockCommand();
+ $client = $this->getClient();
+
+ $command->setClient($client);
+ $this->assertEquals($client, $command->getClient());
+
+ unset($client);
+ unset($command);
+
+ $command = new MockCommand();
+ $client = $this->getClient();
+
+ $command->setClient($client)->prepare();
+ $this->assertEquals($client, $command->getClient());
+ $this->assertTrue($command->isPrepared());
+ }
+
+ public function testExecute()
+ {
+ $client = $this->getClient();
+ $response = new Response(200, array(
+ 'Content-Type' => 'application/xml'
+ ), '123 ');
+ $this->setMockResponse($client, array($response));
+ $command = new MockCommand();
+ $this->assertSame($command, $command->setClient($client));
+
+ // Returns the result of the command
+ $this->assertInstanceOf('SimpleXMLElement', $command->execute());
+
+ $this->assertTrue($command->isPrepared());
+ $this->assertTrue($command->isExecuted());
+ $this->assertSame($response, $command->getResponse());
+ $this->assertInstanceOf('Guzzle\\Http\\Message\\Request', $command->getRequest());
+ // Make sure that the result was automatically set to a SimpleXMLElement
+ $this->assertInstanceOf('SimpleXMLElement', $command->getResult());
+ $this->assertEquals('123', (string) $command->getResult()->data);
+ }
+
+ public function testConvertsJsonResponsesToArray()
+ {
+ $client = $this->getClient();
+ $this->setMockResponse($client, array(
+ new \Guzzle\Http\Message\Response(200, array(
+ 'Content-Type' => 'application/json'
+ ), '{ "key": "Hi!" }'
+ )
+ ));
+ $command = new MockCommand();
+ $command->setClient($client);
+ $command->execute();
+ $this->assertEquals(array(
+ 'key' => 'Hi!'
+ ), $command->getResult());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ */
+ public function testConvertsInvalidJsonResponsesToArray()
+ {
+ $json = '{ "key": "Hi!" }invalid';
+ // Some implementations of php-json extension are not strict enough
+ // and allow to parse invalid json ignoring invalid parts
+ // See https://github.com/remicollet/pecl-json-c/issues/5
+ if (json_decode($json) && JSON_ERROR_NONE === json_last_error()) {
+ $this->markTestSkipped('php-pecl-json library regression issues');
+ }
+
+ $client = $this->getClient();
+ $this->setMockResponse($client, array(
+ new \Guzzle\Http\Message\Response(200, array(
+ 'Content-Type' => 'application/json'
+ ), $json
+ )
+ ));
+ $command = new MockCommand();
+ $command->setClient($client);
+ $command->execute();
+ }
+
+ public function testProcessResponseIsNotXml()
+ {
+ $client = $this->getClient();
+ $this->setMockResponse($client, array(
+ new Response(200, array(
+ 'Content-Type' => 'application/octet-stream'
+ ), 'abc,def,ghi')
+ ));
+ $command = new MockCommand();
+ $client->execute($command);
+
+ // Make sure that the result was not converted to XML
+ $this->assertFalse($command->getResult() instanceof \SimpleXMLElement);
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testExecuteThrowsExceptionWhenNoClientIsSet()
+ {
+ $command = new MockCommand();
+ $command->execute();
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testPrepareThrowsExceptionWhenNoClientIsSet()
+ {
+ $command = new MockCommand();
+ $command->prepare();
+ }
+
+ public function testCommandsAllowsCustomRequestHeaders()
+ {
+ $command = new MockCommand();
+ $command->getRequestHeaders()->set('test', '123');
+ $this->assertInstanceOf('Guzzle\Common\Collection', $command->getRequestHeaders());
+ $this->assertEquals('123', $command->getRequestHeaders()->get('test'));
+
+ $command->setClient($this->getClient())->prepare();
+ $this->assertEquals('123', (string) $command->getRequest()->getHeader('test'));
+ }
+
+ public function testCommandsAllowsCustomRequestHeadersAsArray()
+ {
+ $command = new MockCommand(array(AbstractCommand::HEADERS_OPTION => array('Foo' => 'Bar')));
+ $this->assertInstanceOf('Guzzle\Common\Collection', $command->getRequestHeaders());
+ $this->assertEquals('Bar', $command->getRequestHeaders()->get('Foo'));
+ }
+
+ private function getOperation()
+ {
+ return new Operation(array(
+ 'name' => 'foobar',
+ 'httpMethod' => 'POST',
+ 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand',
+ 'parameters' => array(
+ 'test' => array(
+ 'default' => '123',
+ 'type' => 'string'
+ )
+ )));
+ }
+
+ public function testCommandsUsesOperation()
+ {
+ $api = $this->getOperation();
+ $command = new MockCommand(array(), $api);
+ $this->assertSame($api, $command->getOperation());
+ $command->setClient($this->getClient())->prepare();
+ $this->assertEquals('123', $command->get('test'));
+ $this->assertSame($api, $command->getOperation($api));
+ }
+
+ public function testCloneMakesNewRequest()
+ {
+ $client = $this->getClient();
+ $command = new MockCommand(array(), $this->getOperation());
+ $command->setClient($client);
+
+ $command->prepare();
+ $this->assertTrue($command->isPrepared());
+
+ $command2 = clone $command;
+ $this->assertFalse($command2->isPrepared());
+ }
+
+ public function testHasOnCompleteMethod()
+ {
+ $that = $this;
+ $called = 0;
+
+ $testFunction = function($command) use (&$called, $that) {
+ $called++;
+ $that->assertInstanceOf('Guzzle\Service\Command\CommandInterface', $command);
+ };
+
+ $client = $this->getClient();
+ $command = new MockCommand(array(
+ 'command.on_complete' => $testFunction
+ ), $this->getOperation());
+ $command->setClient($client);
+
+ $command->prepare()->setResponse(new Response(200), true);
+ $command->execute();
+ $this->assertEquals(1, $called);
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testOnCompleteMustBeCallable()
+ {
+ $client = $this->getClient();
+ $command = new MockCommand();
+ $command->setOnComplete('foo');
+ }
+
+ public function testCanSetResultManually()
+ {
+ $client = $this->getClient();
+ $client->getEventDispatcher()->addSubscriber(new MockPlugin(array(
+ new Response(200)
+ )));
+ $command = new MockCommand();
+ $client->execute($command);
+ $command->setResult('foo!');
+ $this->assertEquals('foo!', $command->getResult());
+ }
+
+ public function testCanInitConfig()
+ {
+ $command = $this->getMockBuilder('Guzzle\\Service\\Command\\AbstractCommand')
+ ->setConstructorArgs(array(array(
+ 'foo' => 'bar'
+ ), new Operation(array(
+ 'parameters' => array(
+ 'baz' => new Parameter(array(
+ 'default' => 'baaar'
+ ))
+ )
+ ))))
+ ->getMockForAbstractClass();
+
+ $this->assertEquals('bar', $command['foo']);
+ $this->assertEquals('baaar', $command['baz']);
+ }
+
+ public function testAddsCurlOptionsToRequestsWhenPreparing()
+ {
+ $command = new MockCommand(array(
+ 'foo' => 'bar',
+ 'curl.options' => array('CURLOPT_PROXYPORT' => 8080)
+ ));
+ $client = new Client();
+ $command->setClient($client);
+ $request = $command->prepare();
+ $this->assertEquals(8080, $request->getCurlOptions()->get(CURLOPT_PROXYPORT));
+ }
+
+ public function testIsInvokable()
+ {
+ $client = $this->getClient();
+ $response = new Response(200);
+ $this->setMockResponse($client, array($response));
+ $command = new MockCommand();
+ $command->setClient($client);
+ // Returns the result of the command
+ $this->assertSame($response, $command());
+ }
+
+ public function testCreatesDefaultOperation()
+ {
+ $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')->getMockForAbstractClass();
+ $this->assertInstanceOf('Guzzle\Service\Description\Operation', $command->getOperation());
+ }
+
+ public function testAllowsValidatorToBeInjected()
+ {
+ $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')->getMockForAbstractClass();
+ $v = new SchemaValidator();
+ $command->setValidator($v);
+ $this->assertSame($v, $this->readAttribute($command, 'validator'));
+ }
+
+ public function testCanDisableValidation()
+ {
+ $command = new MockCommand();
+ $command->setClient(new \Guzzle\Service\Client());
+ $v = $this->getMockBuilder('Guzzle\Service\Description\SchemaValidator')
+ ->setMethods(array('validate'))
+ ->getMock();
+ $v->expects($this->never())->method('validate');
+ $command->setValidator($v);
+ $command->set(AbstractCommand::DISABLE_VALIDATION, true);
+ $command->prepare();
+ }
+
+ public function testValidatorDoesNotUpdateNonDefaultValues()
+ {
+ $command = new MockCommand(array('test' => 123, 'foo' => 'bar'));
+ $command->setClient(new \Guzzle\Service\Client());
+ $command->prepare();
+ $this->assertEquals(123, $command->get('test'));
+ $this->assertEquals('bar', $command->get('foo'));
+ }
+
+ public function testValidatorUpdatesDefaultValues()
+ {
+ $command = new MockCommand();
+ $command->setClient(new \Guzzle\Service\Client());
+ $command->prepare();
+ $this->assertEquals(123, $command->get('test'));
+ $this->assertEquals('abc', $command->get('_internal'));
+ }
+
+ /**
+ * @expectedException \Guzzle\Service\Exception\ValidationException
+ * @expectedExceptionMessage [Foo] Baz
+ */
+ public function testValidatesCommandBeforeSending()
+ {
+ $command = new MockCommand();
+ $command->setClient(new \Guzzle\Service\Client());
+ $v = $this->getMockBuilder('Guzzle\Service\Description\SchemaValidator')
+ ->setMethods(array('validate', 'getErrors'))
+ ->getMock();
+ $v->expects($this->any())->method('validate')->will($this->returnValue(false));
+ $v->expects($this->any())->method('getErrors')->will($this->returnValue(array('[Foo] Baz', '[Bar] Boo')));
+ $command->setValidator($v);
+ $command->prepare();
+ }
+
+ /**
+ * @expectedException \Guzzle\Service\Exception\ValidationException
+ * @expectedExceptionMessage Validation errors: [abc] must be of type string
+ */
+ public function testValidatesAdditionalParameters()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'foo' => array(
+ 'parameters' => array(
+ 'baz' => array('type' => 'integer')
+ ),
+ 'additionalParameters' => array(
+ 'type' => 'string'
+ )
+ )
+ )
+ ));
+
+ $client = new Client();
+ $client->setDescription($description);
+ $command = $client->getCommand('foo', array(
+ 'abc' => false,
+ 'command.headers' => array('foo' => 'bar')
+ ));
+ $command->prepare();
+ }
+
+ public function testCanAccessValidationErrorsFromCommand()
+ {
+ $validationErrors = array('[Foo] Baz', '[Bar] Boo');
+ $command = new MockCommand();
+ $command->setClient(new \Guzzle\Service\Client());
+
+ $this->assertFalse($command->getValidationErrors());
+
+ $v = $this->getMockBuilder('Guzzle\Service\Description\SchemaValidator')
+ ->setMethods(array('validate', 'getErrors'))
+ ->getMock();
+ $v->expects($this->any())->method('getErrors')->will($this->returnValue($validationErrors));
+ $command->setValidator($v);
+
+ $this->assertEquals($validationErrors, $command->getValidationErrors());
+ }
+
+ public function testCanChangeResponseBody()
+ {
+ $body = EntityBody::factory();
+ $command = new MockCommand();
+ $command->setClient(new \Guzzle\Service\Client());
+ $command->set(AbstractCommand::RESPONSE_BODY, $body);
+ $request = $command->prepare();
+ $this->assertSame($body, $this->readAttribute($request, 'responseBody'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php
new file mode 100755
index 0000000..b7a4682
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultRequestSerializerTest.php
@@ -0,0 +1,122 @@
+serializer = DefaultRequestSerializer::getInstance();
+ $this->client = new Client('http://foo.com/baz');
+ $this->operation = new Operation(array('httpMethod' => 'POST'));
+ $this->command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')
+ ->setConstructorArgs(array(array(), $this->operation))
+ ->getMockForAbstractClass();
+ $this->command->setClient($this->client);
+ }
+
+ public function testAllowsCustomVisitor()
+ {
+ $this->serializer->addVisitor('custom', new HeaderVisitor());
+ $this->command['test'] = '123';
+ $this->operation->addParam(new Parameter(array('name' => 'test', 'location' => 'custom')));
+ $request = $this->serializer->prepare($this->command);
+ $this->assertEquals('123', (string) $request->getHeader('test'));
+ }
+
+ public function testUsesRelativePath()
+ {
+ $this->operation->setUri('bar');
+ $request = $this->serializer->prepare($this->command);
+ $this->assertEquals('http://foo.com/baz/bar', (string) $request->getUrl());
+ }
+
+ public function testUsesRelativePathWithUriLocations()
+ {
+ $this->command['test'] = '123';
+ $this->operation->setUri('bar/{test}');
+ $this->operation->addParam(new Parameter(array('name' => 'test', 'location' => 'uri')));
+ $request = $this->serializer->prepare($this->command);
+ $this->assertEquals('http://foo.com/baz/bar/123', (string) $request->getUrl());
+ }
+
+ public function testAllowsCustomFactory()
+ {
+ $f = new VisitorFlyweight();
+ $serializer = new DefaultRequestSerializer($f);
+ $this->assertSame($f, $this->readAttribute($serializer, 'factory'));
+ }
+
+ public function testMixedParams()
+ {
+ $this->operation->setUri('bar{?limit,fields}');
+ $this->operation->addParam(new Parameter(array(
+ 'name' => 'limit',
+ 'location' => 'uri',
+ 'required' => false,
+ )));
+ $this->operation->addParam(new Parameter(array(
+ 'name' => 'fields',
+ 'location' => 'uri',
+ 'required' => true,
+ )));
+
+ $this->command['fields'] = array('id', 'name');
+
+ $request = $this->serializer->prepare($this->command);
+ $this->assertEquals('http://foo.com/baz/bar?fields='.urlencode('id,name'), (string) $request->getUrl());
+ }
+
+ public function testValidatesAdditionalParameters()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'foo' => array(
+ 'httpMethod' => 'PUT',
+ 'parameters' => array(
+ 'bar' => array('location' => 'header')
+ ),
+ 'additionalParameters' => array(
+ 'location' => 'json'
+ )
+ )
+ )
+ ));
+
+ $client = new Client();
+ $client->setDescription($description);
+ $command = $client->getCommand('foo');
+ $command['bar'] = 'test';
+ $command['hello'] = 'abc';
+ $request = $command->prepare();
+ $this->assertEquals('test', (string) $request->getHeader('bar'));
+ $this->assertEquals('{"hello":"abc"}', (string) $request->getBody());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php
new file mode 100755
index 0000000..a6a02f9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/DefaultResponseParserTest.php
@@ -0,0 +1,59 @@
+setClient(new Client());
+ $request = $op->prepare();
+ $request->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/xml'
+ ), 'Bar '), true);
+ $this->assertInstanceOf('SimpleXMLElement', $op->execute());
+ }
+
+ public function testParsesJsonResponses()
+ {
+ $op = new OperationCommand(array(), new Operation());
+ $op->setClient(new Client());
+ $request = $op->prepare();
+ $request->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/json'
+ ), '{"Baz":"Bar"}'), true);
+ $this->assertEquals(array('Baz' => 'Bar'), $op->execute());
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\RuntimeException
+ */
+ public function testThrowsExceptionWhenParsingJsonFails()
+ {
+ $op = new OperationCommand(array(), new Operation());
+ $op->setClient(new Client());
+ $request = $op->prepare();
+ $request->setResponse(new Response(200, array('Content-Type' => 'application/json'), '{"Baz":ddw}'), true);
+ $op->execute();
+ }
+
+ public function testAddsContentTypeWhenExpectsIsSetOnCommand()
+ {
+ $op = new OperationCommand(array(), new Operation());
+ $op['command.expects'] = 'application/json';
+ $op->setClient(new Client());
+ $request = $op->prepare();
+ $request->setResponse(new Response(200, null, '{"Baz":"Bar"}'), true);
+ $this->assertEquals(array('Baz' => 'Bar'), $op->execute());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php
new file mode 100755
index 0000000..ab1041a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/AliasFactoryTest.php
@@ -0,0 +1,76 @@
+client = new Client();
+
+ $map = new MapFactory(array(
+ 'test' => 'Guzzle\Tests\Service\Mock\Command\MockCommand',
+ 'test1' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand'
+ ));
+
+ $this->factory = new AliasFactory($this->client, array(
+ 'foo' => 'test',
+ 'bar' => 'sub',
+ 'sub' => 'test1',
+ 'krull' => 'test3',
+ 'krull_2' => 'krull',
+ 'sub_2' => 'bar',
+ 'bad_link' => 'jarjar'
+ ));
+
+ $map2 = new MapFactory(array(
+ 'test3' => 'Guzzle\Tests\Service\Mock\Command\Sub\Sub'
+ ));
+
+ $this->client->setCommandFactory(new CompositeFactory(array($map, $this->factory, $map2)));
+ }
+
+ public function aliasProvider()
+ {
+ return array(
+ array('foo', 'Guzzle\Tests\Service\Mock\Command\MockCommand', false),
+ array('bar', 'Guzzle\Tests\Service\Mock\Command\OtherCommand', false),
+ array('sub', 'Guzzle\Tests\Service\Mock\Command\OtherCommand', false),
+ array('sub_2', 'Guzzle\Tests\Service\Mock\Command\OtherCommand', false),
+ array('krull', 'Guzzle\Tests\Service\Mock\Command\Sub\Sub', false),
+ array('krull_2', 'Guzzle\Tests\Service\Mock\Command\Sub\Sub', false),
+ array('missing', null, true),
+ array('bad_link', null, true)
+ );
+ }
+
+ /**
+ * @dataProvider aliasProvider
+ */
+ public function testAliasesCommands($key, $result, $exception)
+ {
+ try {
+ $command = $this->client->getCommand($key);
+ if (is_null($result)) {
+ $this->assertNull($command);
+ } else {
+ $this->assertInstanceof($result, $command);
+ }
+ } catch (\Exception $e) {
+ if (!$exception) {
+ $this->fail('Got exception when it was not expected');
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php
new file mode 100755
index 0000000..b896dcf
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/CompositeFactoryTest.php
@@ -0,0 +1,124 @@
+getMockBuilder($class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function testIsIterable()
+ {
+ $factory = new CompositeFactory(array($this->getFactory(), $this->getFactory()));
+ $this->assertEquals(2, count($factory));
+ $this->assertEquals(2, count(iterator_to_array($factory->getIterator())));
+ }
+
+ public function testFindsFactories()
+ {
+ $f1 = $this->getFactory();
+ $f2 = $this->getFactory('Guzzle\\Service\\Command\\Factory\\CompositeFactory');
+ $factory = new CompositeFactory(array($f1, $f2));
+ $this->assertNull($factory->find('foo'));
+ $this->assertNull($factory->find($this->getFactory()));
+ $this->assertSame($f1, $factory->find('Guzzle\\Service\\Command\\Factory\\MapFactory'));
+ $this->assertSame($f2, $factory->find('Guzzle\\Service\\Command\\Factory\\CompositeFactory'));
+ $this->assertSame($f1, $factory->find($f1));
+ $this->assertSame($f2, $factory->find($f2));
+
+ $this->assertFalse($factory->has('foo'));
+ $this->assertTrue($factory->has('Guzzle\\Service\\Command\\Factory\\MapFactory'));
+ $this->assertTrue($factory->has('Guzzle\\Service\\Command\\Factory\\CompositeFactory'));
+ }
+
+ public function testCreatesCommands()
+ {
+ $factory = new CompositeFactory();
+ $this->assertNull($factory->factory('foo'));
+
+ $f1 = $this->getFactory();
+ $mockCommand1 = $this->getMockForAbstractClass('Guzzle\\Service\\Command\\AbstractCommand');
+
+ $f1->expects($this->once())
+ ->method('factory')
+ ->with($this->equalTo('foo'))
+ ->will($this->returnValue($mockCommand1));
+
+ $factory = new CompositeFactory(array($f1));
+ $this->assertSame($mockCommand1, $factory->factory('foo'));
+ }
+
+ public function testAllowsRemovalOfFactories()
+ {
+ $f1 = $this->getFactory();
+ $f2 = $this->getFactory();
+ $f3 = $this->getFactory('Guzzle\\Service\\Command\\Factory\\CompositeFactory');
+ $factories = array($f1, $f2, $f3);
+ $factory = new CompositeFactory($factories);
+
+ $factory->remove('foo');
+ $this->assertEquals($factories, $factory->getIterator()->getArrayCopy());
+
+ $factory->remove($f1);
+ $this->assertEquals(array($f2, $f3), $factory->getIterator()->getArrayCopy());
+
+ $factory->remove('Guzzle\\Service\\Command\\Factory\\MapFactory');
+ $this->assertEquals(array($f3), $factory->getIterator()->getArrayCopy());
+
+ $factory->remove('Guzzle\\Service\\Command\\Factory\\CompositeFactory');
+ $this->assertEquals(array(), $factory->getIterator()->getArrayCopy());
+
+ $factory->remove('foo');
+ $this->assertEquals(array(), $factory->getIterator()->getArrayCopy());
+ }
+
+ public function testAddsFactoriesBeforeAndAtEnd()
+ {
+ $f1 = $this->getFactory();
+ $f2 = $this->getFactory();
+ $f3 = $this->getFactory('Guzzle\\Service\\Command\\Factory\\CompositeFactory');
+ $f4 = $this->getFactory();
+
+ $factory = new CompositeFactory();
+
+ $factory->add($f1);
+ $this->assertEquals(array($f1), $factory->getIterator()->getArrayCopy());
+
+ $factory->add($f2);
+ $this->assertEquals(array($f1, $f2), $factory->getIterator()->getArrayCopy());
+
+ $factory->add($f3, $f2);
+ $this->assertEquals(array($f1, $f3, $f2), $factory->getIterator()->getArrayCopy());
+
+ $factory->add($f4, 'Guzzle\\Service\\Command\\Factory\\CompositeFactory');
+ $this->assertEquals(array($f1, $f4, $f3, $f2), $factory->getIterator()->getArrayCopy());
+ }
+
+ public function testProvidesDefaultChainForClients()
+ {
+ $client = $this->getMock('Guzzle\\Service\\Client');
+ $chain = CompositeFactory::getDefaultChain($client);
+ $a = $chain->getIterator()->getArrayCopy();
+ $this->assertEquals(1, count($a));
+ $this->assertInstanceOf('Guzzle\\Service\\Command\\Factory\\ConcreteClassFactory', $a[0]);
+
+ $description = $this->getMock('Guzzle\\Service\\Description\\ServiceDescription');
+ $client->expects($this->once())
+ ->method('getDescription')
+ ->will($this->returnValue($description));
+ $chain = CompositeFactory::getDefaultChain($client);
+ $a = $chain->getIterator()->getArrayCopy();
+ $this->assertEquals(2, count($a));
+ $this->assertInstanceOf('Guzzle\\Service\\Command\\Factory\\ServiceDescriptionFactory', $a[0]);
+ $this->assertInstanceOf('Guzzle\\Service\\Command\\Factory\\ConcreteClassFactory', $a[1]);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php
new file mode 100755
index 0000000..7664718
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ConcreteClassFactoryTest.php
@@ -0,0 +1,49 @@
+ $prefix
+ ));
+ }
+
+ $factory = new ConcreteClassFactory($client);
+
+ if (is_null($result)) {
+ $this->assertNull($factory->factory($key));
+ } else {
+ $this->assertInstanceof($result, $factory->factory($key));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php
new file mode 100755
index 0000000..ee720d1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/MapFactoryTest.php
@@ -0,0 +1,37 @@
+ 'Guzzle\Tests\Service\Mock\Command\MockCommand',
+ 'test1' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand'
+ ));
+
+ if (is_null($result)) {
+ $this->assertNull($factory->factory($key));
+ } else {
+ $this->assertInstanceof($result, $factory->factory($key));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php
new file mode 100755
index 0000000..3372634
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/Factory/ServiceDescriptionFactoryTest.php
@@ -0,0 +1,68 @@
+getDescription();
+
+ $factory = new ServiceDescriptionFactory($d);
+ $this->assertSame($d, $factory->getServiceDescription());
+
+ if (is_null($result)) {
+ $this->assertNull($factory->factory($key));
+ } else {
+ $this->assertInstanceof($result, $factory->factory($key));
+ }
+ }
+
+ public function testUsesUcFirstIfNoExactMatch()
+ {
+ $d = $this->getDescription();
+ $factory = new ServiceDescriptionFactory($d, new Inflector());
+ $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('Test'));
+ $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('test'));
+ }
+
+ public function testUsesInflectionIfNoExactMatch()
+ {
+ $d = $this->getDescription();
+ $factory = new ServiceDescriptionFactory($d, new Inflector());
+ $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('Binks'));
+ $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\OtherCommand', $factory->factory('binks'));
+ $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\MockCommand', $factory->factory('JarJar'));
+ $this->assertInstanceof('Guzzle\Tests\Service\Mock\Command\MockCommand', $factory->factory('jar_jar'));
+ }
+
+ protected function getDescription()
+ {
+ return ServiceDescription::factory(array(
+ 'operations' => array(
+ 'jar_jar' => array('class' => 'Guzzle\Tests\Service\Mock\Command\MockCommand'),
+ 'binks' => array('class' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand'),
+ 'Test' => array('class' => 'Guzzle\Tests\Service\Mock\Command\OtherCommand')
+ )
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php
new file mode 100755
index 0000000..46b472e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/AbstractVisitorTestCase.php
@@ -0,0 +1,110 @@
+command = new MockCommand();
+ $this->request = new EntityEnclosingRequest('POST', 'http://www.test.com/some/path.php');
+ $this->validator = new SchemaValidator();
+ }
+
+ protected function getCommand($location)
+ {
+ $command = new OperationCommand(array(), $this->getNestedCommand($location));
+ $command->setClient(new MockClient());
+
+ return $command;
+ }
+
+ protected function getNestedCommand($location)
+ {
+ return new Operation(array(
+ 'httpMethod' => 'POST',
+ 'parameters' => array(
+ 'foo' => new Parameter(array(
+ 'type' => 'object',
+ 'location' => $location,
+ 'sentAs' => 'Foo',
+ 'required' => true,
+ 'properties' => array(
+ 'test' => array(
+ 'type' => 'object',
+ 'required' => true,
+ 'properties' => array(
+ 'baz' => array(
+ 'type' => 'boolean',
+ 'default' => true
+ ),
+ 'jenga' => array(
+ 'type' => 'string',
+ 'default' => 'hello',
+ 'sentAs' => 'Jenga_Yall!',
+ 'filters' => array('strtoupper')
+ )
+ )
+ ),
+ 'bar' => array('default' => 123)
+ ),
+ 'additionalProperties' => array(
+ 'type' => 'string',
+ 'filters' => array('strtoupper'),
+ 'location' => $location
+ )
+ )),
+ 'arr' => new Parameter(array(
+ 'type' => 'array',
+ 'location' => $location,
+ 'items' => array(
+ 'type' => 'string',
+ 'filters' => array('strtoupper')
+ )
+ )),
+ )
+ ));
+ }
+
+ protected function getCommandWithArrayParamAndFilters()
+ {
+ $operation = new Operation(array(
+ 'httpMethod' => 'POST',
+ 'parameters' => array(
+ 'foo' => new Parameter(array(
+ 'type' => 'string',
+ 'location' => 'query',
+ 'sentAs' => 'Foo',
+ 'required' => true,
+ 'default' => 'bar',
+ 'filters' => array('strtoupper')
+ )),
+ 'arr' => new Parameter(array(
+ 'type' => 'array',
+ 'location' => 'query',
+ 'sentAs' => 'Arr',
+ 'required' => true,
+ 'default' => array(123, 456, 789),
+ 'filters' => array(array('method' => 'implode', 'args' => array(',', '@value')))
+ ))
+ )
+ ));
+ $command = new OperationCommand(array(), $operation);
+ $command->setClient(new MockClient());
+
+ return $command;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php
new file mode 100755
index 0000000..2a95c45
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/BodyVisitorTest.php
@@ -0,0 +1,63 @@
+getNestedCommand('body')->getParam('foo')->setSentAs('Foo');
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertEquals('123', (string) $this->request->getBody());
+ $this->assertNull($this->request->getHeader('Expect'));
+ }
+
+ public function testAddsExpectHeaderWhenSetToTrue()
+ {
+ $visitor = new Visitor();
+ $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo');
+ $param->setData('expect_header', true);
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertEquals('123', (string) $this->request->getBody());
+ }
+
+ public function testCanDisableExpectHeader()
+ {
+ $visitor = new Visitor();
+ $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo');
+ $param->setData('expect_header', false);
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertNull($this->request->getHeader('Expect'));
+ }
+
+ public function testCanSetExpectHeaderBasedOnSize()
+ {
+ $visitor = new Visitor();
+ $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo');
+ // The body is less than the cutoff
+ $param->setData('expect_header', 5);
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertNull($this->request->getHeader('Expect'));
+ // Now check when the body is greater than the cutoff
+ $param->setData('expect_header', 2);
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertEquals('100-Continue', (string) $this->request->getHeader('Expect'));
+ }
+
+ public function testAddsContentEncodingWhenSetOnBody()
+ {
+ $visitor = new Visitor();
+ $param = $this->getNestedCommand('body')->getParam('foo')->setSentAs('Foo');
+ $body = EntityBody::factory('foo');
+ $body->compress();
+ $visitor->visit($this->command, $this->request, $param, $body);
+ $this->assertEquals('gzip', (string) $this->request->getHeader('Content-Encoding'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php
new file mode 100755
index 0000000..7ea1ae9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/HeaderVisitorTest.php
@@ -0,0 +1,48 @@
+getNestedCommand('header')->getParam('foo')->setSentAs('test');
+ $param->setAdditionalProperties(new Parameter(array()));
+ $visitor->visit($this->command, $this->request, $param, 'test');
+ }
+
+ public function testVisitsLocation()
+ {
+ $visitor = new Visitor();
+ $param = $this->getNestedCommand('header')->getParam('foo')->setSentAs('test');
+ $param->setAdditionalProperties(false);
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertEquals('123', (string) $this->request->getHeader('test'));
+ }
+
+ public function testVisitsMappedPrefixHeaders()
+ {
+ $visitor = new Visitor();
+ $param = $this->getNestedCommand('header')->getParam('foo')->setSentAs('test');
+ $param->setSentAs('x-foo-');
+ $param->setAdditionalProperties(new Parameter(array(
+ 'type' => 'string'
+ )));
+ $visitor->visit($this->command, $this->request, $param, array(
+ 'bar' => 'test',
+ 'baz' => '123'
+ ));
+ $this->assertEquals('test', (string) $this->request->getHeader('x-foo-bar'));
+ $this->assertEquals('123', (string) $this->request->getHeader('x-foo-baz'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php
new file mode 100755
index 0000000..ea6782f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/JsonVisitorTest.php
@@ -0,0 +1,60 @@
+after($this->command, $this->request);
+
+ $param = $this->getNestedCommand('json')->getParam('foo');
+ $visitor->visit($this->command, $this->request, $param->setSentAs('test'), '123');
+ $visitor->visit($this->command, $this->request, $param->setSentAs('test2'), 'abc');
+ $visitor->after($this->command, $this->request);
+ $this->assertEquals('{"test":"123","test2":"abc"}', (string) $this->request->getBody());
+ }
+
+ public function testAddsJsonHeader()
+ {
+ $visitor = new Visitor();
+ $visitor->setContentTypeHeader('application/json-foo');
+ $param = $this->getNestedCommand('json')->getParam('foo');
+ $visitor->visit($this->command, $this->request, $param->setSentAs('test'), '123');
+ $visitor->after($this->command, $this->request);
+ $this->assertEquals('application/json-foo', (string) $this->request->getHeader('Content-Type'));
+ }
+
+ public function testRecursivelyBuildsJsonBodies()
+ {
+ $command = $this->getCommand('json');
+ $request = $command->prepare();
+ $this->assertEquals('{"Foo":{"test":{"baz":true,"Jenga_Yall!":"HELLO"},"bar":123}}', (string) $request->getBody());
+ }
+
+ public function testAppliesFiltersToAdditionalProperties()
+ {
+ $command = $this->getCommand('json');
+ $command->set('foo', array('not_set' => 'abc'));
+ $request = $command->prepare();
+ $result = json_decode($request->getBody(), true);
+ $this->assertEquals('ABC', $result['Foo']['not_set']);
+ }
+
+ public function testAppliesFiltersToArrayItemValues()
+ {
+ $command = $this->getCommand('json');
+ $command->set('arr', array('a', 'b'));
+ $request = $command->prepare();
+ $result = json_decode($request->getBody(), true);
+ $this->assertEquals(array('A', 'B'), $result['arr']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php
new file mode 100755
index 0000000..540b410
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFieldVisitorTest.php
@@ -0,0 +1,33 @@
+getNestedCommand('postField')->getParam('foo');
+ $visitor->visit($this->command, $this->request, $param->setSentAs('test'), '123');
+ $this->assertEquals('123', (string) $this->request->getPostField('test'));
+ }
+
+ public function testRecursivelyBuildsPostFields()
+ {
+ $command = $this->getCommand('postField');
+ $request = $command->prepare();
+ $visitor = new Visitor();
+ $param = $command->getOperation()->getParam('foo');
+ $visitor->visit($command, $request, $param, $command['foo']);
+ $visitor->after($command, $request);
+ $this->assertEquals(
+ 'Foo[test][baz]=1&Foo[test][Jenga_Yall!]=HELLO&Foo[bar]=123',
+ rawurldecode((string) $request->getPostFields())
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php
new file mode 100755
index 0000000..21e3cec
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/PostFileVisitorTest.php
@@ -0,0 +1,54 @@
+getNestedCommand('postFile')->getParam('foo');
+
+ // Test using a path to a file
+ $visitor->visit($this->command, $this->request, $param->setSentAs('test_3'), __FILE__);
+ $this->assertInternalType('array', $this->request->getPostFile('test_3'));
+
+ // Test with a PostFile
+ $visitor->visit($this->command, $this->request, $param->setSentAs(null), new PostFile('baz', __FILE__));
+ $this->assertInternalType('array', $this->request->getPostFile('baz'));
+ }
+
+ public function testVisitsLocationWithMultipleFiles()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'DoPost' => array(
+ 'httpMethod' => 'POST',
+ 'parameters' => array(
+ 'foo' => array(
+ 'location' => 'postFile',
+ 'type' => array('string', 'array')
+ )
+ )
+ )
+ )
+ ));
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array("HTTP/1.1 200 OK\r\nContent-Length:0\r\n\r\n"));
+ $client = new Client($this->getServer()->getUrl());
+ $client->setDescription($description);
+ $command = $client->getCommand('DoPost', array('foo' => array(__FILE__, __FILE__)));
+ $command->execute();
+ $received = $this->getServer()->getReceivedRequests();
+ $this->assertContains('name="foo[0]";', $received[0]);
+ $this->assertContains('name="foo[1]";', $received[0]);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php
new file mode 100755
index 0000000..607af76
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/QueryVisitorTest.php
@@ -0,0 +1,48 @@
+getNestedCommand('query')->getParam('foo')->setSentAs('test');
+ $visitor->visit($this->command, $this->request, $param, '123');
+ $this->assertEquals('123', $this->request->getQuery()->get('test'));
+ }
+
+ /**
+ * @covers Guzzle\Service\Command\LocationVisitor\Request\QueryVisitor
+ * @covers Guzzle\Service\Command\LocationVisitor\Request\AbstractRequestVisitor::resolveRecursively
+ */
+ public function testRecursivelyBuildsQueryStrings()
+ {
+ $command = $this->getCommand('query');
+ $command->getOperation()->getParam('foo')->setSentAs('Foo');
+ $request = $command->prepare();
+ $this->assertEquals(
+ 'Foo[test][baz]=1&Foo[test][Jenga_Yall!]=HELLO&Foo[bar]=123',
+ rawurldecode($request->getQuery())
+ );
+ }
+
+ /**
+ * @covers Guzzle\Service\Command\LocationVisitor\Request\AbstractRequestVisitor::resolveRecursively
+ */
+ public function testFiltersAreAppliedToArrayParamType()
+ {
+ $command = $this->getCommandWithArrayParamAndFilters();
+ $request = $command->prepare();
+ $query = $request->getQuery();
+ // param type 'string'
+ $this->assertEquals('BAR', $query->get('Foo'));
+ // param type 'array'
+ $this->assertEquals('123,456,789', $query->get('Arr'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php
new file mode 100755
index 0000000..ff8cec5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/ResponseBodyVisitorTest.php
@@ -0,0 +1,20 @@
+getNestedCommand('response_body')->getParam('foo');
+ $visitor->visit($this->command, $this->request, $param, sys_get_temp_dir() . '/foo.txt');
+ $body = $this->readAttribute($this->request, 'responseBody');
+ $this->assertContains('/foo.txt', $body->getUri());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php
new file mode 100755
index 0000000..beb58b0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Request/XmlVisitorTest.php
@@ -0,0 +1,558 @@
+ array(
+ 'xmlRoot' => array(
+ 'name' => 'test',
+ 'namespaces' => 'http://foo.com'
+ )
+ ),
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string'),
+ 'Baz' => array('location' => 'xml', 'type' => 'string')
+ )
+ ),
+ array('Foo' => 'test', 'Baz' => 'bar'),
+ 'test bar '
+ ),
+ // Ensure that the content-type is not added
+ array(array('parameters' => array('Foo' => array('location' => 'xml', 'type' => 'string'))), array(), ''),
+ // Test with adding attributes and no namespace
+ array(
+ array(
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'test'
+ )
+ ),
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string', 'data' => array('xmlAttribute' => true))
+ )
+ ),
+ array('Foo' => 'test', 'Baz' => 'bar'),
+ ' '
+ ),
+ // Test adding with an array
+ array(
+ array(
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string'),
+ 'Baz' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'items' => array(
+ 'type' => 'numeric',
+ 'sentAs' => 'Bar'
+ )
+ )
+ )
+ ),
+ array('Foo' => 'test', 'Baz' => array(1, 2)),
+ 'test 1 2 '
+ ),
+ // Test adding an object
+ array(
+ array(
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string'),
+ 'Baz' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Bar' => array('type' => 'string'),
+ 'Bam' => array()
+ )
+ )
+ )
+ ),
+ array('Foo' => 'test', 'Baz' => array('Bar' => 'abc', 'Bam' => 'foo')),
+ 'test abc foo '
+ ),
+ // Add an array that contains an object
+ array(
+ array(
+ 'parameters' => array(
+ 'Baz' => array(
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'items' => array(
+ 'type' => 'object',
+ 'sentAs' => 'Bar',
+ 'properties' => array('A' => array(), 'B' => array())
+ )
+ )
+ )
+ ),
+ array('Baz' => array(
+ array('A' => '1', 'B' => '2'),
+ array('A' => '3', 'B' => '4')
+ )),
+ '1 2 3 4 '
+ ),
+ // Add an object of attributes
+ array(
+ array(
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string'),
+ 'Baz' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Bar' => array('type' => 'string', 'data' => array('xmlAttribute' => true)),
+ 'Bam' => array()
+ )
+ )
+ )
+ ),
+ array('Foo' => 'test', 'Baz' => array('Bar' => 'abc', 'Bam' => 'foo')),
+ 'test foo '
+ ),
+ // Check order doesn't matter
+ array(
+ array(
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string'),
+ 'Baz' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Bar' => array('type' => 'string', 'data' => array('xmlAttribute' => true)),
+ 'Bam' => array()
+ )
+ )
+ )
+ ),
+ array('Foo' => 'test', 'Baz' => array('Bam' => 'foo', 'Bar' => 'abc')),
+ 'test foo '
+ ),
+ // Add values with custom namespaces
+ array(
+ array(
+ 'parameters' => array(
+ 'Foo' => array(
+ 'location' => 'xml',
+ 'type' => 'string',
+ 'data' => array(
+ 'xmlNamespace' => 'http://foo.com'
+ )
+ )
+ )
+ ),
+ array('Foo' => 'test'),
+ 'test '
+ ),
+ // Add attributes with custom namespace prefix
+ array(
+ array(
+ 'parameters' => array(
+ 'Wrap' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Foo' => array(
+ 'type' => 'string',
+ 'sentAs' => 'xsi:baz',
+ 'data' => array(
+ 'xmlNamespace' => 'http://foo.com',
+ 'xmlAttribute' => true
+ )
+ )
+ )
+ ),
+ )
+ ),
+ array('Wrap' => array(
+ 'Foo' => 'test'
+ )),
+ ' '
+ ),
+ // Add nodes with custom namespace prefix
+ array(
+ array(
+ 'parameters' => array(
+ 'Wrap' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Foo' => array(
+ 'type' => 'string',
+ 'sentAs' => 'xsi:Foo',
+ 'data' => array(
+ 'xmlNamespace' => 'http://foobar.com'
+ )
+ )
+ )
+ ),
+ )
+ ),
+ array('Wrap' => array(
+ 'Foo' => 'test'
+ )),
+ 'test '
+ ),
+ array(
+ array(
+ 'parameters' => array(
+ 'Foo' => array(
+ 'location' => 'xml',
+ 'type' => 'string',
+ 'data' => array(
+ 'xmlNamespace' => 'http://foo.com'
+ )
+ )
+ )
+ ),
+ array('Foo' => 'This is a title '),
+ 'This is a title]]> '
+ ),
+ // Flat array at top level
+ array(
+ array(
+ 'parameters' => array(
+ 'Bars' => array(
+ 'type' => 'array',
+ 'data' => array('xmlFlattened' => true),
+ 'location' => 'xml',
+ 'items' => array(
+ 'type' => 'object',
+ 'sentAs' => 'Bar',
+ 'properties' => array(
+ 'A' => array(),
+ 'B' => array()
+ )
+ )
+ ),
+ 'Boos' => array(
+ 'type' => 'array',
+ 'data' => array('xmlFlattened' => true),
+ 'location' => 'xml',
+ 'items' => array(
+ 'sentAs' => 'Boo',
+ 'type' => 'string'
+ )
+ )
+ )
+ ),
+ array(
+ 'Bars' => array(
+ array('A' => '1', 'B' => '2'),
+ array('A' => '3', 'B' => '4')
+ ),
+ 'Boos' => array('test', '123')
+ ),
+ '1 2 3 4 test 123 '
+ ),
+ // Nested flat arrays
+ array(
+ array(
+ 'parameters' => array(
+ 'Delete' => array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'properties' => array(
+ 'Items' => array(
+ 'type' => 'array',
+ 'data' => array('xmlFlattened' => true),
+ 'items' => array(
+ 'type' => 'object',
+ 'sentAs' => 'Item',
+ 'properties' => array(
+ 'A' => array(),
+ 'B' => array()
+ )
+ )
+ )
+ )
+ )
+ )
+ ),
+ array(
+ 'Delete' => array(
+ 'Items' => array(
+ array('A' => '1', 'B' => '2'),
+ array('A' => '3', 'B' => '4')
+ )
+ )
+ ),
+ '1 2 3 4 '
+ )
+ );
+ }
+
+ /**
+ * @dataProvider xmlProvider
+ */
+ public function testSerializesXml(array $operation, array $input, $xml)
+ {
+ $operation = new Operation($operation);
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array($input, $operation))
+ ->getMockForAbstractClass();
+ $command->setClient(new Client('http://www.test.com/some/path.php'));
+ $request = $command->prepare();
+ if (!empty($input)) {
+ $this->assertEquals('application/xml', (string) $request->getHeader('Content-Type'));
+ } else {
+ $this->assertNull($request->getHeader('Content-Type'));
+ }
+ $body = str_replace(array("\n", ""), '', (string) $request->getBody());
+ $this->assertEquals($xml, $body);
+ }
+
+ public function testAddsContentTypeAndTopLevelValues()
+ {
+ $operation = new Operation(array(
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'test',
+ 'namespaces' => array(
+ 'xsi' => 'http://foo.com'
+ )
+ )
+ ),
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string'),
+ 'Baz' => array('location' => 'xml', 'type' => 'string')
+ )
+ ));
+
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array(array(
+ 'Foo' => 'test',
+ 'Baz' => 'bar'
+ ), $operation))
+ ->getMockForAbstractClass();
+
+ $command->setClient(new Client());
+ $request = $command->prepare();
+ $this->assertEquals('application/xml', (string) $request->getHeader('Content-Type'));
+ $this->assertEquals(
+ '' . "\n"
+ . 'test bar ' . "\n",
+ (string) $request->getBody()
+ );
+ }
+
+ public function testCanChangeContentType()
+ {
+ $visitor = new XmlVisitor();
+ $visitor->setContentTypeHeader('application/foo');
+ $this->assertEquals('application/foo', $this->readAttribute($visitor, 'contentType'));
+ }
+
+ public function testCanAddArrayOfSimpleTypes()
+ {
+ $request = new EntityEnclosingRequest('POST', 'http://foo.com');
+ $visitor = new XmlVisitor();
+ $param = new Parameter(array(
+ 'type' => 'object',
+ 'location' => 'xml',
+ 'name' => 'Out',
+ 'properties' => array(
+ 'Nodes' => array(
+ 'required' => true,
+ 'type' => 'array',
+ 'min' => 1,
+ 'items' => array('type' => 'string', 'sentAs' => 'Node')
+ )
+ )
+ ));
+
+ $param->setParent(new Operation(array(
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'Test',
+ 'namespaces' => array(
+ 'https://foo/'
+ )
+ )
+ )
+ )));
+
+ $value = array('Nodes' => array('foo', 'baz'));
+ $this->assertTrue($this->validator->validate($param, $value));
+ $visitor->visit($this->command, $request, $param, $value);
+ $visitor->after($this->command, $request);
+
+ $this->assertEquals(
+ "\n"
+ . "foo baz \n",
+ (string) $request->getBody()
+ );
+ }
+
+ public function testCanAddMultipleNamespacesToRoot()
+ {
+ $operation = new Operation(array(
+ 'data' => array(
+ 'xmlRoot' => array(
+ 'name' => 'Hi',
+ 'namespaces' => array(
+ 'xsi' => 'http://foo.com',
+ 'foo' => 'http://foobar.com'
+ )
+ )
+ ),
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml', 'type' => 'string')
+ )
+ ));
+
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array(array(
+ 'Foo' => 'test'
+ ), $operation))
+ ->getMockForAbstractClass();
+
+ $command->setClient(new Client());
+ $request = $command->prepare();
+ $this->assertEquals('application/xml', (string) $request->getHeader('Content-Type'));
+ $this->assertEquals(
+ '' . "\n"
+ . 'test ' . "\n",
+ (string) $request->getBody()
+ );
+ }
+
+ public function testValuesAreFiltered()
+ {
+ $operation = new Operation(array(
+ 'parameters' => array(
+ 'Foo' => array(
+ 'location' => 'xml',
+ 'type' => 'string',
+ 'filters' => array('strtoupper')
+ ),
+ 'Bar' => array(
+ 'location' => 'xml',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Baz' => array(
+ 'filters' => array('strtoupper')
+ )
+ )
+ )
+ )
+ ));
+
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array(array(
+ 'Foo' => 'test',
+ 'Bar' => array(
+ 'Baz' => 'abc'
+ )
+ ), $operation))
+ ->getMockForAbstractClass();
+
+ $command->setClient(new Client());
+ $request = $command->prepare();
+ $this->assertEquals(
+ '' . "\n"
+ . 'TEST ABC ' . "\n",
+ (string) $request->getBody()
+ );
+ }
+
+ public function testSkipsNullValues()
+ {
+ $operation = new Operation(array(
+ 'parameters' => array(
+ 'Foo' => array(
+ 'location' => 'xml',
+ 'type' => 'string'
+ ),
+ 'Bar' => array(
+ 'location' => 'xml',
+ 'type' => 'object',
+ 'properties' => array(
+ 'Baz' => array(),
+ 'Bam' => array(),
+ )
+ ),
+ 'Arr' => array(
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'string'
+ )
+ )
+ )
+ ));
+
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array(array(
+ 'Foo' => null,
+ 'Bar' => array(
+ 'Bar' => null,
+ 'Bam' => 'test'
+ ),
+ 'Arr' => array(null)
+ ), $operation))
+ ->getMockForAbstractClass();
+
+ $command->setClient(new Client());
+ $request = $command->prepare();
+ $this->assertEquals(
+ '' . "\n"
+ . 'test ' . "\n",
+ (string) $request->getBody()
+ );
+ }
+
+ public function testAllowsXmlEncoding()
+ {
+ $operation = new Operation(array(
+ 'data' => array(
+ 'xmlEncoding' => 'UTF-8'
+ ),
+ 'parameters' => array(
+ 'Foo' => array('location' => 'xml')
+ )
+ ));
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array(array('Foo' => 'test'), $operation))
+ ->getMockForAbstractClass();
+ $command->setClient(new Client());
+ $request = $command->prepare();
+ $this->assertEquals(
+ '' . "\n"
+ . 'test ' . "\n",
+ (string) $request->getBody()
+ );
+ }
+
+ public function testAllowsSendingXmlPayloadIfNoXmlParamsWereSet()
+ {
+ $operation = new Operation(array(
+ 'httpMethod' => 'POST',
+ 'data' => array('xmlAllowEmpty' => true),
+ 'parameters' => array('Foo' => array('location' => 'xml'))
+ ));
+ $command = $this->getMockBuilder('Guzzle\Service\Command\OperationCommand')
+ ->setConstructorArgs(array(array(), $operation))
+ ->getMockForAbstractClass();
+ $command->setClient(new Client('http://foo.com'));
+ $request = $command->prepare();
+ $this->assertEquals(
+ '' . "\n"
+ . ' ' . "\n",
+ (string) $request->getBody()
+ );
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php
new file mode 100755
index 0000000..7b86003
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/AbstractResponseVisitorTest.php
@@ -0,0 +1,29 @@
+value = array();
+ $this->command = new MockCommand();
+ $this->response = new Response(200, array(
+ 'X-Foo' => 'bar',
+ 'Content-Length' => 3,
+ 'Content-Type' => 'text/plain'
+ ), 'Foo');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php
new file mode 100755
index 0000000..932e39b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/BodyVisitorTest.php
@@ -0,0 +1,21 @@
+ 'body', 'name' => 'foo'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('Foo', (string) $this->value['foo']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php
new file mode 100755
index 0000000..db54b1a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/HeaderVisitorTest.php
@@ -0,0 +1,98 @@
+ 'header',
+ 'name' => 'ContentType',
+ 'sentAs' => 'Content-Type'
+ ));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('text/plain', $this->value['ContentType']);
+ }
+
+ public function testVisitsLocationWithFilters()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'header',
+ 'name' => 'Content-Type',
+ 'filters' => array('strtoupper')
+ ));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('TEXT/PLAIN', $this->value['Content-Type']);
+ }
+
+ public function testVisitsMappedPrefixHeaders()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'header',
+ 'name' => 'Metadata',
+ 'sentAs' => 'X-Baz-',
+ 'type' => 'object',
+ 'additionalProperties' => array(
+ 'type' => 'string'
+ )
+ ));
+ $response = new Response(200, array(
+ 'X-Baz-Test' => 'ABC',
+ 'X-Baz-Bar' => array('123', '456'),
+ 'Content-Length' => 3
+ ), 'Foo');
+ $visitor->visit($this->command, $response, $param, $this->value);
+ $this->assertEquals(array(
+ 'Metadata' => array(
+ 'Test' => 'ABC',
+ 'Bar' => array('123', '456')
+ )
+ ), $this->value);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testDiscardingUnknownHeaders()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'header',
+ 'name' => 'Content-Type',
+ 'additionalParameters' => false
+ ));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('text/plain', $this->value['Content-Type']);
+ $this->assertArrayNotHasKey('X-Foo', $this->value);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testDiscardingUnknownPropertiesWithAliasing()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'header',
+ 'name' => 'ContentType',
+ 'sentAs' => 'Content-Type',
+ 'additionalParameters' => false
+ ));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('text/plain', $this->value['ContentType']);
+ $this->assertArrayNotHasKey('X-Foo', $this->value);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php
new file mode 100755
index 0000000..4f8d30b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/JsonVisitorTest.php
@@ -0,0 +1,157 @@
+getMockBuilder('Guzzle\Service\Command\AbstractCommand')
+ ->setMethods(array('getResponse'))
+ ->getMockForAbstractClass();
+ $command->expects($this->once())
+ ->method('getResponse')
+ ->will($this->returnValue(new Response(200, null, '{"foo":"bar"}')));
+ $result = array();
+ $visitor->before($command, $result);
+ $this->assertEquals(array('foo' => 'bar'), $result);
+ }
+
+ public function testVisitsLocation()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'array',
+ 'items' => array(
+ 'filters' => 'strtoupper',
+ 'type' => 'string'
+ )
+ ));
+ $this->value = array('foo' => array('a', 'b', 'c'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('A', 'B', 'C'), $this->value['foo']);
+ }
+
+ public function testRenamesTopLevelValues()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'sentAs' => 'Baz',
+ 'type' => 'string',
+ ));
+ $this->value = array('Baz' => 'test');
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => 'test'), $this->value);
+ }
+
+ public function testRenamesDoesNotFailForNonExistentKey()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array(
+ 'bar' => array(
+ 'name' => 'bar',
+ 'sentAs' => 'baz',
+ ),
+ ),
+ ));
+ $this->value = array('foo' => array('unknown' => 'Unknown'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => array('unknown' => 'Unknown')), $this->value);
+ }
+
+ public function testTraversesObjectsAndAppliesFilters()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array(
+ 'foo' => array('filters' => 'strtoupper'),
+ 'bar' => array('filters' => 'strtolower')
+ )
+ ));
+ $this->value = array('foo' => array('foo' => 'hello', 'bar' => 'THERE'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => 'HELLO', 'bar' => 'there'), $this->value['foo']);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testDiscardingUnknownProperties()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'additionalProperties' => false,
+ 'properties' => array(
+ 'bar' => array(
+ 'type' => 'string',
+ 'name' => 'bar',
+ ),
+ ),
+ ));
+ $this->value = array('foo' => array('bar' => 15, 'unknown' => 'Unknown'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => array('bar' => 15)), $this->value);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testDiscardingUnknownPropertiesWithAliasing()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'additionalProperties' => false,
+ 'properties' => array(
+ 'bar' => array(
+ 'name' => 'bar',
+ 'sentAs' => 'baz',
+ ),
+ ),
+ ));
+ $this->value = array('foo' => array('baz' => 15, 'unknown' => 'Unknown'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => array('bar' => 15)), $this->value);
+ }
+
+ public function testWalksAdditionalProperties()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'additionalProperties' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'bar' => array(
+ 'type' => 'string',
+ 'filters' => array('base64_decode')
+ )
+ ),
+ ),
+ ));
+ $this->value = array('foo' => array('baz' => array('bar' => 'Zm9v')));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('foo', $this->value['foo']['baz']['bar']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php
new file mode 100755
index 0000000..23cd40f
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/ReasonPhraseVisitorTest.php
@@ -0,0 +1,21 @@
+ 'reasonPhrase', 'name' => 'phrase'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals('OK', $this->value['phrase']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php
new file mode 100755
index 0000000..7211a58
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/StatusCodeVisitorTest.php
@@ -0,0 +1,21 @@
+ 'statusCode', 'name' => 'code'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(200, $this->value['code']);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php
new file mode 100755
index 0000000..f87cec7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/Response/XmlVisitorTest.php
@@ -0,0 +1,431 @@
+getMockBuilder('Guzzle\Service\Command\AbstractCommand')
+ ->setMethods(array('getResponse'))
+ ->getMockForAbstractClass();
+ $command->expects($this->once())
+ ->method('getResponse')
+ ->will($this->returnValue(new Response(200, null, 'test ')));
+ $result = array();
+ $visitor->before($command, $result);
+ $this->assertEquals(array('Bar' => 'test'), $result);
+ }
+
+ public function testBeforeMethodParsesXmlWithNamespace()
+ {
+ $this->markTestSkipped("Response/XmlVisitor cannot accept 'xmlns' in response, see #368 (http://git.io/USa1mA).");
+
+ $visitor = new Visitor();
+ $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')
+ ->setMethods(array('getResponse'))
+ ->getMockForAbstractClass();
+ $command->expects($this->once())
+ ->method('getResponse')
+ ->will($this->returnValue(new Response(200, null, 'test ')));
+ $result = array();
+ $visitor->before($command, $result);
+ $this->assertEquals(array('Bar' => 'test'), $result);
+ }
+
+ public function testBeforeMethodParsesNestedXml()
+ {
+ $visitor = new Visitor();
+ $command = $this->getMockBuilder('Guzzle\Service\Command\AbstractCommand')
+ ->setMethods(array('getResponse'))
+ ->getMockForAbstractClass();
+ $command->expects($this->once())
+ ->method('getResponse')
+ ->will($this->returnValue(new Response(200, null, 'test ')));
+ $result = array();
+ $visitor->before($command, $result);
+ $this->assertEquals(array('Items' => array('Bar' => 'test')), $result);
+ }
+
+ public function testCanExtractAndRenameTopLevelXmlValues()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'xml',
+ 'name' => 'foo',
+ 'sentAs' => 'Bar'
+ ));
+ $value = array('Bar' => 'test');
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertArrayHasKey('foo', $value);
+ $this->assertEquals('test', $value['foo']);
+ }
+
+ public function testEnsuresRepeatedArraysAreInCorrectLocations()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'xml',
+ 'name' => 'foo',
+ 'sentAs' => 'Foo',
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Bar' => array('type' => 'string'),
+ 'Baz' => array('type' => 'string'),
+ 'Bam' => array('type' => 'string')
+ )
+ )
+ ));
+
+ $xml = new \SimpleXMLElement('1 2 ');
+ $value = json_decode(json_encode($xml), true);
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertEquals(array(
+ 'foo' => array(
+ array (
+ 'Bar' => '1',
+ 'Baz' => '2'
+ )
+ )
+ ), $value);
+ }
+
+ public function testEnsuresFlatArraysAreFlat()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'location' => 'xml',
+ 'name' => 'foo',
+ 'type' => 'array',
+ 'items' => array('type' => 'string')
+ ));
+
+ $value = array('foo' => array('bar', 'baz'));
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertEquals(array('foo' => array('bar', 'baz')), $value);
+
+ $value = array('foo' => 'bar');
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertEquals(array('foo' => array('bar')), $value);
+ }
+
+ public function xmlDataProvider()
+ {
+ $param = new Parameter(array(
+ 'location' => 'xml',
+ 'name' => 'Items',
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'object',
+ 'name' => 'Item',
+ 'properties' => array(
+ 'Bar' => array('type' => 'string'),
+ 'Baz' => array('type' => 'string')
+ )
+ )
+ ));
+
+ return array(
+ array($param, '1 2 ', array(
+ 'Items' => array(
+ array('Bar' => 1),
+ array('Bar' => 2)
+ )
+ )),
+ array($param, '1 ', array(
+ 'Items' => array(
+ array('Bar' => 1)
+ )
+ )),
+ array($param, ' ', array(
+ 'Items' => array()
+ ))
+ );
+ }
+
+ /**
+ * @dataProvider xmlDataProvider
+ */
+ public function testEnsuresWrappedArraysAreInCorrectLocations($param, $xml, $result)
+ {
+ $visitor = new Visitor();
+ $xml = new \SimpleXMLElement($xml);
+ $value = json_decode(json_encode($xml), true);
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertEquals($result, $value);
+ }
+
+ public function testCanRenameValues()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'TerminatingInstances',
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'sentAs' => 'instancesSet',
+ 'items' => array(
+ 'name' => 'item',
+ 'type' => 'object',
+ 'sentAs' => 'item',
+ 'properties' => array(
+ 'InstanceId' => array(
+ 'type' => 'string',
+ 'sentAs' => 'instanceId',
+ ),
+ 'CurrentState' => array(
+ 'type' => 'object',
+ 'sentAs' => 'currentState',
+ 'properties' => array(
+ 'Code' => array(
+ 'type' => 'numeric',
+ 'sentAs' => 'code',
+ ),
+ 'Name' => array(
+ 'type' => 'string',
+ 'sentAs' => 'name',
+ ),
+ ),
+ ),
+ 'PreviousState' => array(
+ 'type' => 'object',
+ 'sentAs' => 'previousState',
+ 'properties' => array(
+ 'Code' => array(
+ 'type' => 'numeric',
+ 'sentAs' => 'code',
+ ),
+ 'Name' => array(
+ 'type' => 'string',
+ 'sentAs' => 'name',
+ ),
+ ),
+ ),
+ ),
+ )
+ ));
+
+ $value = array(
+ 'instancesSet' => array (
+ 'item' => array (
+ 'instanceId' => 'i-3ea74257',
+ 'currentState' => array(
+ 'code' => '32',
+ 'name' => 'shutting-down',
+ ),
+ 'previousState' => array(
+ 'code' => '16',
+ 'name' => 'running',
+ ),
+ ),
+ )
+ );
+
+ $visitor->visit($this->command, $this->response, $param, $value);
+
+ $this->assertEquals(array(
+ 'TerminatingInstances' => array(
+ array(
+ 'InstanceId' => 'i-3ea74257',
+ 'CurrentState' => array(
+ 'Code' => '32',
+ 'Name' => 'shutting-down',
+ ),
+ 'PreviousState' => array(
+ 'Code' => '16',
+ 'Name' => 'running',
+ )
+ )
+ )
+ ), $value);
+ }
+
+ public function testCanRenameAttributes()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'RunningQueues',
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'items' => array(
+ 'type' => 'object',
+ 'sentAs' => 'item',
+ 'properties' => array(
+ 'QueueId' => array(
+ 'type' => 'string',
+ 'sentAs' => 'queue_id',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ ),
+ ),
+ 'CurrentState' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Code' => array(
+ 'type' => 'numeric',
+ 'sentAs' => 'code',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ ),
+ ),
+ 'Name' => array(
+ 'sentAs' => 'name',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ ),
+ ),
+ ),
+ ),
+ 'PreviousState' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Code' => array(
+ 'type' => 'numeric',
+ 'sentAs' => 'code',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ ),
+ ),
+ 'Name' => array(
+ 'sentAs' => 'name',
+ 'data' => array(
+ 'xmlAttribute' => true,
+ ),
+ ),
+ ),
+ ),
+ ),
+ )
+ ));
+
+ $xml = ' ';
+ $value = json_decode(json_encode(new \SimpleXMLElement($xml)), true);
+ $visitor->visit($this->command, $this->response, $param, $value);
+
+ $this->assertEquals(array(
+ 'RunningQueues' => array(
+ array(
+ 'QueueId' => 'q-3ea74257',
+ 'CurrentState' => array(
+ 'Code' => '32',
+ 'Name' => 'processing',
+ ),
+ 'PreviousState' => array(
+ 'Code' => '16',
+ 'Name' => 'wait',
+ ),
+ ),
+ )
+ ), $value);
+ }
+
+ public function testAddsEmptyArraysWhenValueIsMissing()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'Foo',
+ 'type' => 'array',
+ 'location' => 'xml',
+ 'items' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Baz' => array('type' => 'array'),
+ 'Bar' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Baz' => array('type' => 'array'),
+ )
+ )
+ )
+ )
+ ));
+
+ $value = array();
+ $visitor->visit($this->command, $this->response, $param, $value);
+
+ $value = array(
+ 'Foo' => array(
+ 'Bar' => array()
+ )
+ );
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertEquals(array(
+ 'Foo' => array(
+ array(
+ 'Bar' => array()
+ )
+ )
+ ), $value);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testDiscardingUnknownProperties()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'additionalProperties' => false,
+ 'properties' => array(
+ 'bar' => array(
+ 'type' => 'string',
+ 'name' => 'bar',
+ ),
+ ),
+ ));
+ $this->value = array('foo' => array('bar' => 15, 'unknown' => 'Unknown'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => array('bar' => 15)), $this->value);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testDiscardingUnknownPropertiesWithAliasing()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'additionalProperties' => false,
+ 'properties' => array(
+ 'bar' => array(
+ 'name' => 'bar',
+ 'sentAs' => 'baz',
+ ),
+ ),
+ ));
+ $this->value = array('foo' => array('baz' => 15, 'unknown' => 'Unknown'));
+ $visitor->visit($this->command, $this->response, $param, $this->value);
+ $this->assertEquals(array('foo' => array('bar' => 15)), $this->value);
+ }
+
+ public function testProperlyHandlesEmptyStringValues()
+ {
+ $visitor = new Visitor();
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array(
+ 'bar' => array('type' => 'string')
+ ),
+ ));
+ $xml = ' ';
+ $value = json_decode(json_encode(new \SimpleXMLElement($xml)), true);
+ $visitor->visit($this->command, $this->response, $param, $value);
+ $this->assertEquals(array('foo' => array('bar' => '')), $value);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php
new file mode 100755
index 0000000..a252ffe
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/LocationVisitor/VisitorFlyweightTest.php
@@ -0,0 +1,53 @@
+assertInstanceOf('Guzzle\Service\Command\LocationVisitor\Request\JsonVisitor', $f->getRequestVisitor('json'));
+ $this->assertInstanceOf('Guzzle\Service\Command\LocationVisitor\Response\JsonVisitor', $f->getResponseVisitor('json'));
+ }
+
+ public function testCanUseCustomMappings()
+ {
+ $f = new VisitorFlyweight(array());
+ $this->assertEquals(array(), $this->readAttribute($f, 'mappings'));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage No request visitor has been mapped for foo
+ */
+ public function testThrowsExceptionWhenRetrievingUnknownVisitor()
+ {
+ VisitorFlyweight::getInstance()->getRequestVisitor('foo');
+ }
+
+ public function testCachesVisitors()
+ {
+ $f = new VisitorFlyweight();
+ $v1 = $f->getRequestVisitor('json');
+ $this->assertSame($v1, $f->getRequestVisitor('json'));
+ }
+
+ public function testAllowsAddingVisitors()
+ {
+ $f = new VisitorFlyweight();
+ $j1 = new JsonRequestVisitor();
+ $j2 = new JsonResponseVisitor();
+ $f->addRequestVisitor('json', $j1);
+ $f->addResponseVisitor('json', $j2);
+ $this->assertSame($j1, $f->getRequestVisitor('json'));
+ $this->assertSame($j2, $f->getResponseVisitor('json'));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php
new file mode 100755
index 0000000..95fb533
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationCommandTest.php
@@ -0,0 +1,102 @@
+getRequestSerializer();
+ $b = new DefaultRequestSerializer(VisitorFlyweight::getInstance());
+ $operation->setRequestSerializer($b);
+ $this->assertNotSame($a, $operation->getRequestSerializer());
+ }
+
+ public function testPreparesRequestUsingSerializer()
+ {
+ $op = new OperationCommand(array(), new Operation());
+ $op->setClient(new Client());
+ $s = $this->getMockBuilder('Guzzle\Service\Command\RequestSerializerInterface')
+ ->setMethods(array('prepare'))
+ ->getMockForAbstractClass();
+ $s->expects($this->once())
+ ->method('prepare')
+ ->will($this->returnValue(new EntityEnclosingRequest('POST', 'http://foo.com')));
+ $op->setRequestSerializer($s);
+ $op->prepare();
+ }
+
+ public function testParsesResponsesWithResponseParser()
+ {
+ $op = new OperationCommand(array(), new Operation());
+ $p = $this->getMockBuilder('Guzzle\Service\Command\ResponseParserInterface')
+ ->setMethods(array('parse'))
+ ->getMockForAbstractClass();
+ $p->expects($this->once())
+ ->method('parse')
+ ->will($this->returnValue(array('foo' => 'bar')));
+ $op->setResponseParser($p);
+ $op->setClient(new Client());
+ $request = $op->prepare();
+ $request->setResponse(new Response(200), true);
+ $this->assertEquals(array('foo' => 'bar'), $op->execute());
+ }
+
+ public function testParsesResponsesUsingModelParserWhenMatchingModelIsFound()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'foo' => array('responseClass' => 'bar', 'responseType' => 'model')
+ ),
+ 'models' => array(
+ 'bar' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Baz' => array('type' => 'string', 'location' => 'xml')
+ )
+ )
+ )
+ ));
+
+ $op = new OperationCommand(array(), $description->getOperation('foo'));
+ $op->setClient(new Client());
+ $request = $op->prepare();
+ $request->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/xml'
+ ), 'Bar '), true);
+ $result = $op->execute();
+ $this->assertEquals(new Model(array('Baz' => 'Bar')), $result);
+ }
+
+ public function testAllowsRawResponses()
+ {
+ $description = new ServiceDescription(array(
+ 'operations' => array('foo' => array('responseClass' => 'bar', 'responseType' => 'model')),
+ 'models' => array('bar' => array())
+ ));
+ $op = new OperationCommand(array(
+ OperationCommand::RESPONSE_PROCESSING => OperationCommand::TYPE_RAW
+ ), $description->getOperation('foo'));
+ $op->setClient(new Client());
+ $request = $op->prepare();
+ $response = new Response(200, array(
+ 'Content-Type' => 'application/xml'
+ ), 'Bar ');
+ $request->setResponse($response, true);
+ $this->assertSame($response, $op->execute());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php
new file mode 100755
index 0000000..69ba1fc
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Command/OperationResponseParserTest.php
@@ -0,0 +1,335 @@
+addVisitor('foo', $visitor);
+ $this->assertSame($visitor, $this->readAttribute($p, 'factory')->getResponseVisitor('foo'));
+ }
+
+ public function testUsesParentParser()
+ {
+ $p = new OperationResponseParser(new VisitorFlyweight());
+ $operation = new Operation();
+ $operation->setServiceDescription(new ServiceDescription());
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($p)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/xml'), 'C '), true);
+ $this->assertInstanceOf('SimpleXMLElement', $op->execute());
+ }
+
+ public function testVisitsLocations()
+ {
+ $parser = new OperationResponseParser(new VisitorFlyweight(array()));
+ $parser->addVisitor('statusCode', new StatusCodeVisitor());
+ $parser->addVisitor('reasonPhrase', new ReasonPhraseVisitor());
+ $parser->addVisitor('json', new JsonVisitor());
+ $op = new OperationCommand(array(), $this->getDescription()->getOperation('test'));
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(201), true);
+ $result = $op->execute();
+ $this->assertEquals(201, $result['code']);
+ $this->assertEquals('Created', $result['phrase']);
+ }
+
+ public function testVisitsLocationsForJsonResponse()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $operation = $this->getDescription()->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/json'
+ ), '{"baz":"bar","enigma":"123"}'), true);
+ $result = $op->execute();
+ $this->assertEquals(array(
+ 'baz' => 'bar',
+ 'enigma' => '123',
+ 'code' => 200,
+ 'phrase' => 'OK'
+ ), $result->toArray());
+ }
+
+ public function testSkipsUnkownModels()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $operation = $this->getDescription()->getOperation('test');
+ $operation->setResponseClass('Baz')->setResponseType('model');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(201), true);
+ $this->assertInstanceOf('Guzzle\Http\Message\Response', $op->execute());
+ }
+
+ public function testAllowsModelProcessingToBeDisabled()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $operation = $this->getDescription()->getOperation('test');
+ $op = new OperationCommand(array('command.response_processing' => 'native'), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/json'
+ ), '{"baz":"bar","enigma":"123"}'), true);
+ $result = $op->execute();
+ $this->assertInstanceOf('Guzzle\Service\Resource\Model', $result);
+ $this->assertEquals(array(
+ 'baz' => 'bar',
+ 'enigma' => '123'
+ ), $result->toArray());
+ }
+
+ public function testCanInjectModelSchemaIntoModels()
+ {
+ $parser = new OperationResponseParser(VisitorFlyweight::getInstance(), true);
+ $desc = $this->getDescription();
+ $operation = $desc->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/json'
+ ), '{"baz":"bar","enigma":"123"}'), true);
+ $result = $op->execute();
+ $this->assertSame($result->getStructure(), $desc->getModel('Foo'));
+ }
+
+ public function testDoesNotParseXmlWhenNotUsingXmlVisitor()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Foo')),
+ 'models' => array(
+ 'Foo' => array(
+ 'type' => 'object',
+ 'properties' => array('baz' => array('location' => 'body'))
+ )
+ )
+ ));
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $brokenXml = '<><><>>>>';
+ $op->prepare()->setResponse(new Response(200, array(
+ 'Content-Type' => 'application/xml'
+ ), $brokenXml), true);
+ $result = $op->execute();
+ $this->assertEquals(array('baz'), $result->getKeys());
+ $this->assertEquals($brokenXml, (string) $result['baz']);
+ }
+
+ public function testVisitsAdditionalProperties()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Foo')),
+ 'models' => array(
+ 'Foo' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'code' => array('location' => 'statusCode')
+ ),
+ 'additionalProperties' => array(
+ 'location' => 'json',
+ 'type' => 'object',
+ 'properties' => array(
+ 'a' => array(
+ 'type' => 'string',
+ 'filters' => 'strtoupper'
+ )
+ )
+ )
+ )
+ )
+ ));
+
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $json = '[{"a":"test"},{"a":"baz"}]';
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), $json), true);
+ $result = $op->execute()->toArray();
+ $this->assertEquals(array(
+ 'code' => 200,
+ array('a' => 'TEST'),
+ array('a' => 'BAZ')
+ ), $result);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/399
+ */
+ public function testAdditionalPropertiesDisabledDiscardsData()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Foo')),
+ 'models' => array(
+ 'Foo' => array(
+ 'type' => 'object',
+ 'additionalProperties' => false,
+ 'properties' => array(
+ 'name' => array(
+ 'location' => 'json',
+ 'type' => 'string',
+ ),
+ 'nested' => array(
+ 'location' => 'json',
+ 'type' => 'object',
+ 'additionalProperties' => false,
+ 'properties' => array(
+ 'width' => array(
+ 'type' => 'integer'
+ )
+ ),
+ ),
+ 'code' => array('location' => 'statusCode')
+ ),
+
+ )
+ )
+ ));
+
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $json = '{"name":"test", "volume":2.0, "nested":{"width":10,"bogus":1}}';
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), $json), true);
+ $result = $op->execute()->toArray();
+ $this->assertEquals(array(
+ 'name' => 'test',
+ 'nested' => array(
+ 'width' => 10,
+ ),
+ 'code' => 200
+ ), $result);
+ }
+
+ public function testCreatesCustomResponseClassInterface()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Guzzle\Tests\Mock\CustomResponseModel'))
+ ));
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), 'hi!'), true);
+ $result = $op->execute();
+ $this->assertInstanceOf('Guzzle\Tests\Mock\CustomResponseModel', $result);
+ $this->assertSame($op, $result->command);
+ }
+
+ /**
+ * @expectedException \Guzzle\Service\Exception\ResponseClassException
+ * @expectedExceptionMessage must exist
+ */
+ public function testEnsuresResponseClassExists()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Foo\Baz\Bar'))
+ ));
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), 'hi!'), true);
+ $op->execute();
+ }
+
+ /**
+ * @expectedException \Guzzle\Service\Exception\ResponseClassException
+ * @expectedExceptionMessage and implement
+ */
+ public function testEnsuresResponseClassImplementsResponseClassInterface()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => __CLASS__))
+ ));
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), 'hi!'), true);
+ $op->execute();
+ }
+
+ protected function getDescription()
+ {
+ return ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Foo')),
+ 'models' => array(
+ 'Foo' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'baz' => array('type' => 'string', 'location' => 'json'),
+ 'code' => array('location' => 'statusCode'),
+ 'phrase' => array('location' => 'reasonPhrase'),
+ )
+ )
+ )
+ ));
+ }
+
+ public function testCanAddListenerToParseDomainObjects()
+ {
+ $client = new Client();
+ $client->setDescription(ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'FooBazBar'))
+ )));
+ $foo = new \stdClass();
+ $client->getEventDispatcher()->addListener('command.parse_response', function ($e) use ($foo) {
+ $e['result'] = $foo;
+ });
+ $command = $client->getCommand('test');
+ $command->prepare()->setResponse(new Response(200), true);
+ $result = $command->execute();
+ $this->assertSame($result, $foo);
+ }
+
+ /**
+ * @group issue-399
+ * @link https://github.com/guzzle/guzzle/issues/501
+ */
+ public function testAdditionalPropertiesWithRefAreResolved()
+ {
+ $parser = OperationResponseParser::getInstance();
+ $description = ServiceDescription::factory(array(
+ 'operations' => array('test' => array('responseClass' => 'Foo')),
+ 'models' => array(
+ 'Baz' => array('type' => 'string'),
+ 'Foo' => array(
+ 'type' => 'object',
+ 'additionalProperties' => array('$ref' => 'Baz', 'location' => 'json')
+ )
+ )
+ ));
+ $operation = $description->getOperation('test');
+ $op = new OperationCommand(array(), $operation);
+ $op->setResponseParser($parser)->setClient(new Client());
+ $json = '{"a":"a","b":"b","c":"c"}';
+ $op->prepare()->setResponse(new Response(200, array('Content-Type' => 'application/json'), $json), true);
+ $result = $op->execute()->toArray();
+ $this->assertEquals(array('a' => 'a', 'b' => 'b', 'c' => 'c'), $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php
new file mode 100755
index 0000000..ae33b69
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/OperationTest.php
@@ -0,0 +1,308 @@
+ 'test',
+ 'summary' => 'doc',
+ 'notes' => 'notes',
+ 'documentationUrl' => 'http://www.example.com',
+ 'httpMethod' => 'POST',
+ 'uri' => '/api/v1',
+ 'responseClass' => 'array',
+ 'responseNotes' => 'returns the json_decoded response',
+ 'deprecated' => true,
+ 'parameters' => array(
+ 'key' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'maxLength' => 10
+ ),
+ 'key_2' => array(
+ 'required' => true,
+ 'type' => 'integer',
+ 'default' => 10
+ )
+ )
+ ));
+
+ $this->assertEquals('test', $c->getName());
+ $this->assertEquals('doc', $c->getSummary());
+ $this->assertEquals('http://www.example.com', $c->getDocumentationUrl());
+ $this->assertEquals('POST', $c->getHttpMethod());
+ $this->assertEquals('/api/v1', $c->getUri());
+ $this->assertEquals('array', $c->getResponseClass());
+ $this->assertEquals('returns the json_decoded response', $c->getResponseNotes());
+ $this->assertTrue($c->getDeprecated());
+ $this->assertEquals('Guzzle\\Service\\Command\\OperationCommand', $c->getClass());
+ $this->assertEquals(array(
+ 'key' => new Parameter(array(
+ 'name' => 'key',
+ 'required' => true,
+ 'type' => 'string',
+ 'maxLength' => 10,
+ 'parent' => $c
+ )),
+ 'key_2' => new Parameter(array(
+ 'name' => 'key_2',
+ 'required' => true,
+ 'type' => 'integer',
+ 'default' => 10,
+ 'parent' => $c
+ ))
+ ), $c->getParams());
+
+ $this->assertEquals(new Parameter(array(
+ 'name' => 'key_2',
+ 'required' => true,
+ 'type' => 'integer',
+ 'default' => 10,
+ 'parent' => $c
+ )), $c->getParam('key_2'));
+
+ $this->assertNull($c->getParam('afefwef'));
+ $this->assertArrayNotHasKey('parent', $c->getParam('key_2')->toArray());
+ }
+
+ public function testAllowsConcreteCommands()
+ {
+ $c = new Operation(array(
+ 'name' => 'test',
+ 'class' => 'Guzzle\\Service\\Command\ClosureCommand',
+ 'parameters' => array(
+ 'p' => new Parameter(array(
+ 'name' => 'foo'
+ ))
+ )
+ ));
+ $this->assertEquals('Guzzle\\Service\\Command\ClosureCommand', $c->getClass());
+ }
+
+ public function testConvertsToArray()
+ {
+ $data = array(
+ 'name' => 'test',
+ 'class' => 'Guzzle\\Service\\Command\ClosureCommand',
+ 'summary' => 'test',
+ 'documentationUrl' => 'http://www.example.com',
+ 'httpMethod' => 'PUT',
+ 'uri' => '/',
+ 'parameters' => array('p' => array('name' => 'foo'))
+ );
+ $c = new Operation($data);
+ $toArray = $c->toArray();
+ unset($data['name']);
+ $this->assertArrayHasKey('parameters', $toArray);
+ $this->assertInternalType('array', $toArray['parameters']);
+
+ // Normalize the array
+ unset($data['parameters']);
+ unset($toArray['parameters']);
+
+ $data['responseType'] = 'primitive';
+ $data['responseClass'] = 'array';
+ $this->assertEquals($data, $toArray);
+ }
+
+ public function testDeterminesIfHasParam()
+ {
+ $command = $this->getTestCommand();
+ $this->assertTrue($command->hasParam('data'));
+ $this->assertFalse($command->hasParam('baz'));
+ }
+
+ public function testReturnsParamNames()
+ {
+ $command = $this->getTestCommand();
+ $this->assertEquals(array('data'), $command->getParamNames());
+ }
+
+ protected function getTestCommand()
+ {
+ return new Operation(array(
+ 'parameters' => array(
+ 'data' => new Parameter(array(
+ 'type' => 'string'
+ ))
+ )
+ ));
+ }
+
+ public function testCanBuildUpCommands()
+ {
+ $c = new Operation(array());
+ $c->setName('foo')
+ ->setClass('Baz')
+ ->setDeprecated(false)
+ ->setSummary('summary')
+ ->setDocumentationUrl('http://www.foo.com')
+ ->setHttpMethod('PUT')
+ ->setResponseNotes('oh')
+ ->setResponseClass('string')
+ ->setUri('/foo/bar')
+ ->addParam(new Parameter(array(
+ 'name' => 'test'
+ )));
+
+ $this->assertEquals('foo', $c->getName());
+ $this->assertEquals('Baz', $c->getClass());
+ $this->assertEquals(false, $c->getDeprecated());
+ $this->assertEquals('summary', $c->getSummary());
+ $this->assertEquals('http://www.foo.com', $c->getDocumentationUrl());
+ $this->assertEquals('PUT', $c->getHttpMethod());
+ $this->assertEquals('oh', $c->getResponseNotes());
+ $this->assertEquals('string', $c->getResponseClass());
+ $this->assertEquals('/foo/bar', $c->getUri());
+ $this->assertEquals(array('test'), $c->getParamNames());
+ }
+
+ public function testCanRemoveParams()
+ {
+ $c = new Operation(array());
+ $c->addParam(new Parameter(array('name' => 'foo')));
+ $this->assertTrue($c->hasParam('foo'));
+ $c->removeParam('foo');
+ $this->assertFalse($c->hasParam('foo'));
+ }
+
+ public function testAddsNameToParametersIfNeeded()
+ {
+ $command = new Operation(array('parameters' => array('foo' => new Parameter(array()))));
+ $this->assertEquals('foo', $command->getParam('foo')->getName());
+ }
+
+ public function testContainsApiErrorInformation()
+ {
+ $command = $this->getOperation();
+ $this->assertEquals(1, count($command->getErrorResponses()));
+ $arr = $command->toArray();
+ $this->assertEquals(1, count($arr['errorResponses']));
+ $command->addErrorResponse(400, 'Foo', 'Baz\\Bar');
+ $this->assertEquals(2, count($command->getErrorResponses()));
+ $command->setErrorResponses(array());
+ $this->assertEquals(0, count($command->getErrorResponses()));
+ }
+
+ public function testHasNotes()
+ {
+ $o = new Operation(array('notes' => 'foo'));
+ $this->assertEquals('foo', $o->getNotes());
+ $o->setNotes('bar');
+ $this->assertEquals('bar', $o->getNotes());
+ }
+
+ public function testHasData()
+ {
+ $o = new Operation(array('data' => array('foo' => 'baz', 'bar' => 123)));
+ $o->setData('test', false);
+ $this->assertEquals('baz', $o->getData('foo'));
+ $this->assertEquals(123, $o->getData('bar'));
+ $this->assertNull($o->getData('wfefwe'));
+ $this->assertEquals(array(
+ 'parameters' => array(),
+ 'class' => 'Guzzle\Service\Command\OperationCommand',
+ 'data' => array('foo' => 'baz', 'bar' => 123, 'test' => false),
+ 'responseClass' => 'array',
+ 'responseType' => 'primitive'
+ ), $o->toArray());
+ }
+
+ public function testHasServiceDescription()
+ {
+ $s = new ServiceDescription();
+ $o = new Operation(array(), $s);
+ $this->assertSame($s, $o->getServiceDescription());
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testValidatesResponseType()
+ {
+ $o = new Operation(array('responseClass' => 'array', 'responseType' => 'foo'));
+ }
+
+ public function testInfersResponseType()
+ {
+ $o = $this->getOperation();
+ $o->setServiceDescription(new ServiceDescription(array('models' => array('Foo' => array()))));
+ $this->assertEquals('primitive', $o->getResponseType());
+ $this->assertEquals('primitive', $o->setResponseClass('boolean')->getResponseType());
+ $this->assertEquals('primitive', $o->setResponseClass('array')->getResponseType());
+ $this->assertEquals('primitive', $o->setResponseClass('integer')->getResponseType());
+ $this->assertEquals('primitive', $o->setResponseClass('string')->getResponseType());
+ $this->assertEquals('class', $o->setResponseClass('foo')->getResponseType());
+ $this->assertEquals('class', $o->setResponseClass(__CLASS__)->getResponseType());
+ $this->assertEquals('model', $o->setResponseClass('Foo')->getResponseType());
+ }
+
+ public function testHasResponseType()
+ {
+ // infers in the constructor
+ $o = new Operation(array('responseClass' => 'array'));
+ $this->assertEquals('primitive', $o->getResponseType());
+ // Infers when set
+ $o = new Operation();
+ $this->assertEquals('primitive', $o->getResponseType());
+ $this->assertEquals('model', $o->setResponseType('model')->getResponseType());
+ }
+
+ public function testHasAdditionalParameters()
+ {
+ $o = new Operation(array(
+ 'additionalParameters' => array(
+ 'type' => 'string', 'name' => 'binks'
+ ),
+ 'parameters' => array(
+ 'foo' => array('type' => 'integer')
+ )
+ ));
+ $this->assertEquals('string', $o->getAdditionalParameters()->getType());
+ $arr = $o->toArray();
+ $this->assertEquals(array(
+ 'type' => 'string'
+ ), $arr['additionalParameters']);
+ }
+
+ /**
+ * @return Operation
+ */
+ protected function getOperation()
+ {
+ return new Operation(array(
+ 'name' => 'OperationTest',
+ 'class' => get_class($this),
+ 'parameters' => array(
+ 'test' => array('type' => 'object'),
+ 'bool_1' => array('default' => true, 'type' => 'boolean'),
+ 'bool_2' => array('default' => false),
+ 'float' => array('type' => 'numeric'),
+ 'int' => array('type' => 'integer'),
+ 'date' => array('type' => 'string'),
+ 'timestamp' => array('type' => 'string'),
+ 'string' => array('type' => 'string'),
+ 'username' => array('type' => 'string', 'required' => true, 'filters' => 'strtolower'),
+ 'test_function' => array('type' => 'string', 'filters' => __CLASS__ . '::strtoupper')
+ ),
+ 'errorResponses' => array(
+ array('code' => 503, 'reason' => 'InsufficientCapacity', 'class' => 'Guzzle\\Exception\\RuntimeException')
+ )
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php
new file mode 100755
index 0000000..b9c162a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ParameterTest.php
@@ -0,0 +1,411 @@
+ 'foo',
+ 'type' => 'bar',
+ 'required' => true,
+ 'default' => '123',
+ 'description' => '456',
+ 'minLength' => 2,
+ 'maxLength' => 5,
+ 'location' => 'body',
+ 'static' => 'static!',
+ 'filters' => array('trim', 'json_encode')
+ );
+
+ public function testCreatesParamFromArray()
+ {
+ $p = new Parameter($this->data);
+ $this->assertEquals('foo', $p->getName());
+ $this->assertEquals('bar', $p->getType());
+ $this->assertEquals(true, $p->getRequired());
+ $this->assertEquals('123', $p->getDefault());
+ $this->assertEquals('456', $p->getDescription());
+ $this->assertEquals(2, $p->getMinLength());
+ $this->assertEquals(5, $p->getMaxLength());
+ $this->assertEquals('body', $p->getLocation());
+ $this->assertEquals('static!', $p->getStatic());
+ $this->assertEquals(array('trim', 'json_encode'), $p->getFilters());
+ }
+
+ public function testCanConvertToArray()
+ {
+ $p = new Parameter($this->data);
+ unset($this->data['name']);
+ $this->assertEquals($this->data, $p->toArray());
+ }
+
+ public function testUsesStatic()
+ {
+ $d = $this->data;
+ $d['default'] = 'booboo';
+ $d['static'] = true;
+ $p = new Parameter($d);
+ $this->assertEquals('booboo', $p->getValue('bar'));
+ }
+
+ public function testUsesDefault()
+ {
+ $d = $this->data;
+ $d['default'] = 'foo';
+ $d['static'] = null;
+ $p = new Parameter($d);
+ $this->assertEquals('foo', $p->getValue(null));
+ }
+
+ public function testReturnsYourValue()
+ {
+ $d = $this->data;
+ $d['static'] = null;
+ $p = new Parameter($d);
+ $this->assertEquals('foo', $p->getValue('foo'));
+ }
+
+ public function testZeroValueDoesNotCauseDefaultToBeReturned()
+ {
+ $d = $this->data;
+ $d['default'] = '1';
+ $d['static'] = null;
+ $p = new Parameter($d);
+ $this->assertEquals('0', $p->getValue('0'));
+ }
+
+ public function testFiltersValues()
+ {
+ $d = $this->data;
+ $d['static'] = null;
+ $d['filters'] = 'strtoupper';
+ $p = new Parameter($d);
+ $this->assertEquals('FOO', $p->filter('foo'));
+ }
+
+ public function testConvertsBooleans()
+ {
+ $p = new Parameter(array('type' => 'boolean'));
+ $this->assertEquals(true, $p->filter('true'));
+ $this->assertEquals(false, $p->filter('false'));
+ }
+
+ public function testUsesArrayByDefaultForFilters()
+ {
+ $d = $this->data;
+ $d['filters'] = null;
+ $p = new Parameter($d);
+ $this->assertEquals(array(), $p->getFilters());
+ }
+
+ public function testAllowsSimpleLocationValue()
+ {
+ $p = new Parameter(array('name' => 'myname', 'location' => 'foo', 'sentAs' => 'Hello'));
+ $this->assertEquals('foo', $p->getLocation());
+ $this->assertEquals('Hello', $p->getSentAs());
+ }
+
+ public function testParsesTypeValues()
+ {
+ $p = new Parameter(array('type' => 'foo'));
+ $this->assertEquals('foo', $p->getType());
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage A [method] value must be specified for each complex filter
+ */
+ public function testValidatesComplexFilters()
+ {
+ $p = new Parameter(array('filters' => array(array('args' => 'foo'))));
+ }
+
+ public function testCanBuildUpParams()
+ {
+ $p = new Parameter(array());
+ $p->setName('foo')
+ ->setDescription('c')
+ ->setFilters(array('d'))
+ ->setLocation('e')
+ ->setSentAs('f')
+ ->setMaxLength(1)
+ ->setMinLength(1)
+ ->setMinimum(2)
+ ->setMaximum(2)
+ ->setMinItems(3)
+ ->setMaxItems(3)
+ ->setRequired(true)
+ ->setStatic(true)
+ ->setDefault('h')
+ ->setType('i');
+
+ $p->addFilter('foo');
+
+ $this->assertEquals('foo', $p->getName());
+ $this->assertEquals('h', $p->getDefault());
+ $this->assertEquals('c', $p->getDescription());
+ $this->assertEquals(array('d', 'foo'), $p->getFilters());
+ $this->assertEquals('e', $p->getLocation());
+ $this->assertEquals('f', $p->getSentAs());
+ $this->assertEquals(1, $p->getMaxLength());
+ $this->assertEquals(1, $p->getMinLength());
+ $this->assertEquals(2, $p->getMaximum());
+ $this->assertEquals(2, $p->getMinimum());
+ $this->assertEquals(3, $p->getMaxItems());
+ $this->assertEquals(3, $p->getMinItems());
+ $this->assertEquals(true, $p->getRequired());
+ $this->assertEquals(true, $p->getStatic());
+ $this->assertEquals('i', $p->getType());
+ }
+
+ public function testAllowsNestedShape()
+ {
+ $command = $this->getServiceBuilder()->get('mock')->getCommand('mock_command')->getOperation();
+ $param = new Parameter(array(
+ 'parent' => $command,
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'location' => 'query',
+ 'properties' => array(
+ 'foo' => array(
+ 'type' => 'object',
+ 'required' => true,
+ 'properties' => array(
+ 'baz' => array(
+ 'name' => 'baz',
+ 'type' => 'bool',
+ )
+ )
+ ),
+ 'bar' => array(
+ 'name' => 'bar',
+ 'default' => '123'
+ )
+ )
+ ));
+
+ $this->assertSame($command, $param->getParent());
+ $this->assertNotEmpty($param->getProperties());
+ $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $param->getProperty('foo'));
+ $this->assertSame($param, $param->getProperty('foo')->getParent());
+ $this->assertSame($param->getProperty('foo'), $param->getProperty('foo')->getProperty('baz')->getParent());
+ $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $param->getProperty('bar'));
+ $this->assertSame($param, $param->getProperty('bar')->getParent());
+
+ $array = $param->toArray();
+ $this->assertInternalType('array', $array['properties']);
+ $this->assertArrayHasKey('foo', $array['properties']);
+ $this->assertArrayHasKey('bar', $array['properties']);
+ }
+
+ public function testAllowsComplexFilters()
+ {
+ $that = $this;
+ $param = new Parameter(array());
+ $param->setFilters(array(array('method' => function ($a, $b, $c, $d) use ($that, $param) {
+ $that->assertEquals('test', $a);
+ $that->assertEquals('my_value!', $b);
+ $that->assertEquals('bar', $c);
+ $that->assertSame($param, $d);
+ return 'abc' . $b;
+ }, 'args' => array('test', '@value', 'bar', '@api'))));
+ $this->assertEquals('abcmy_value!', $param->filter('my_value!'));
+ }
+
+ public function testCanChangeParentOfNestedParameter()
+ {
+ $param1 = new Parameter(array('name' => 'parent'));
+ $param2 = new Parameter(array('name' => 'child'));
+ $param2->setParent($param1);
+ $this->assertSame($param1, $param2->getParent());
+ }
+
+ public function testCanRemoveFromNestedStructure()
+ {
+ $param1 = new Parameter(array('name' => 'parent'));
+ $param2 = new Parameter(array('name' => 'child'));
+ $param1->addProperty($param2);
+ $this->assertSame($param1, $param2->getParent());
+ $this->assertSame($param2, $param1->getProperty('child'));
+
+ // Remove a single child from the structure
+ $param1->removeProperty('child');
+ $this->assertNull($param1->getProperty('child'));
+ // Remove the entire structure
+ $param1->addProperty($param2);
+ $param1->removeProperty('child');
+ $this->assertNull($param1->getProperty('child'));
+ }
+
+ public function testAddsAdditionalProperties()
+ {
+ $p = new Parameter(array(
+ 'type' => 'object',
+ 'additionalProperties' => array('type' => 'string')
+ ));
+ $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $p->getAdditionalProperties());
+ $this->assertNull($p->getAdditionalProperties()->getAdditionalProperties());
+ $p = new Parameter(array('type' => 'object'));
+ $this->assertTrue($p->getAdditionalProperties());
+ }
+
+ public function testAddsItems()
+ {
+ $p = new Parameter(array(
+ 'type' => 'array',
+ 'items' => array('type' => 'string')
+ ));
+ $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $p->getItems());
+ $out = $p->toArray();
+ $this->assertEquals('array', $out['type']);
+ $this->assertInternalType('array', $out['items']);
+ }
+
+ public function testHasExtraProperties()
+ {
+ $p = new Parameter();
+ $this->assertEquals(array(), $p->getData());
+ $p->setData(array('foo' => 'bar'));
+ $this->assertEquals('bar', $p->getData('foo'));
+ $p->setData('baz', 'boo');
+ $this->assertEquals(array('foo' => 'bar', 'baz' => 'boo'), $p->getData());
+ }
+
+ public function testCanRetrieveKnownPropertiesUsingDataMethod()
+ {
+ $p = new Parameter();
+ $this->assertEquals(null, $p->getData('foo'));
+ $p->setName('test');
+ $this->assertEquals('test', $p->getData('name'));
+ }
+
+ public function testHasInstanceOf()
+ {
+ $p = new Parameter();
+ $this->assertNull($p->getInstanceOf());
+ $p->setInstanceOf('Foo');
+ $this->assertEquals('Foo', $p->getInstanceOf());
+ }
+
+ public function testHasPattern()
+ {
+ $p = new Parameter();
+ $this->assertNull($p->getPattern());
+ $p->setPattern('/[0-9]+/');
+ $this->assertEquals('/[0-9]+/', $p->getPattern());
+ }
+
+ public function testHasEnum()
+ {
+ $p = new Parameter();
+ $this->assertNull($p->getEnum());
+ $p->setEnum(array('foo', 'bar'));
+ $this->assertEquals(array('foo', 'bar'), $p->getEnum());
+ }
+
+ public function testSerializesItems()
+ {
+ $p = new Parameter(array(
+ 'type' => 'object',
+ 'additionalProperties' => array('type' => 'string')
+ ));
+ $this->assertEquals(array(
+ 'type' => 'object',
+ 'additionalProperties' => array('type' => 'string')
+ ), $p->toArray());
+ }
+
+ public function testResolvesRefKeysRecursively()
+ {
+ $description = new ServiceDescription(array(
+ 'models' => array(
+ 'JarJar' => array('type' => 'string', 'default' => 'Mesa address tha senate!'),
+ 'Anakin' => array('type' => 'array', 'items' => array('$ref' => 'JarJar'))
+ )
+ ));
+ $p = new Parameter(array('$ref' => 'Anakin', 'description' => 'added'), $description);
+ $this->assertEquals(array(
+ 'type' => 'array',
+ 'items' => array('type' => 'string', 'default' => 'Mesa address tha senate!'),
+ 'description' => 'added'
+ ), $p->toArray());
+ }
+
+ public function testResolvesExtendsRecursively()
+ {
+ $jarJar = array('type' => 'string', 'default' => 'Mesa address tha senate!', 'description' => 'a');
+ $anakin = array('type' => 'array', 'items' => array('extends' => 'JarJar', 'description' => 'b'));
+ $description = new ServiceDescription(array(
+ 'models' => array('JarJar' => $jarJar, 'Anakin' => $anakin)
+ ));
+ // Description attribute will be updated, and format added
+ $p = new Parameter(array('extends' => 'Anakin', 'format' => 'date'), $description);
+ $this->assertEquals(array(
+ 'type' => 'array',
+ 'format' => 'date',
+ 'items' => array(
+ 'type' => 'string',
+ 'default' => 'Mesa address tha senate!',
+ 'description' => 'b'
+ )
+ ), $p->toArray());
+ }
+
+ public function testHasKeyMethod()
+ {
+ $p = new Parameter(array('name' => 'foo', 'sentAs' => 'bar'));
+ $this->assertEquals('bar', $p->getWireName());
+ $p->setSentAs(null);
+ $this->assertEquals('foo', $p->getWireName());
+ }
+
+ public function testIncludesNameInToArrayWhenItemsAttributeHasName()
+ {
+ $p = new Parameter(array(
+ 'type' => 'array',
+ 'name' => 'Abc',
+ 'items' => array(
+ 'name' => 'Foo',
+ 'type' => 'object'
+ )
+ ));
+ $result = $p->toArray();
+ $this->assertEquals(array(
+ 'type' => 'array',
+ 'items' => array(
+ 'name' => 'Foo',
+ 'type' => 'object',
+ 'additionalProperties' => true
+ )
+ ), $result);
+ }
+
+ public function dateTimeProvider()
+ {
+ $d = 'October 13, 2012 16:15:46 UTC';
+
+ return array(
+ array($d, 'date-time', '2012-10-13T16:15:46Z'),
+ array($d, 'date', '2012-10-13'),
+ array($d, 'timestamp', strtotime($d)),
+ array(new \DateTime($d), 'timestamp', strtotime($d))
+ );
+ }
+
+ /**
+ * @dataProvider dateTimeProvider
+ */
+ public function testAppliesFormat($d, $format, $result)
+ {
+ $p = new Parameter();
+ $p->setFormat($format);
+ $this->assertEquals($format, $p->getFormat());
+ $this->assertEquals($result, $p->filter($d));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php
new file mode 100755
index 0000000..eb3619b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaFormatterTest.php
@@ -0,0 +1,61 @@
+assertEquals($result, SchemaFormatter::format($format, $value));
+ }
+
+ /**
+ * @expectedException \Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testValidatesDateTimeInput()
+ {
+ SchemaFormatter::format('date-time', false);
+ }
+
+ public function testEnsuresTimestampsAreIntegers()
+ {
+ $t = time();
+ $result = SchemaFormatter::format('timestamp', $t);
+ $this->assertSame($t, $result);
+ $this->assertInternalType('int', $result);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php
new file mode 100755
index 0000000..4d6cc87
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/SchemaValidatorTest.php
@@ -0,0 +1,326 @@
+validator = new SchemaValidator();
+ }
+
+ public function testValidatesArrayListsAreNumericallyIndexed()
+ {
+ $value = array(array(1));
+ $this->assertFalse($this->validator->validate($this->getComplexParam(), $value));
+ $this->assertEquals(
+ array('[Foo][0] must be an array of properties. Got a numerically indexed array.'),
+ $this->validator->getErrors()
+ );
+ }
+
+ public function testValidatesArrayListsContainProperItems()
+ {
+ $value = array(true);
+ $this->assertFalse($this->validator->validate($this->getComplexParam(), $value));
+ $this->assertEquals(
+ array('[Foo][0] must be of type object'),
+ $this->validator->getErrors()
+ );
+ }
+
+ public function testAddsDefaultValuesInLists()
+ {
+ $value = array(array());
+ $this->assertTrue($this->validator->validate($this->getComplexParam(), $value));
+ $this->assertEquals(array(array('Bar' => true)), $value);
+ }
+
+ public function testMergesDefaultValuesInLists()
+ {
+ $value = array(
+ array('Baz' => 'hello!'),
+ array('Bar' => false)
+ );
+ $this->assertTrue($this->validator->validate($this->getComplexParam(), $value));
+ $this->assertEquals(array(
+ array(
+ 'Baz' => 'hello!',
+ 'Bar' => true
+ ),
+ array('Bar' => false)
+ ), $value);
+ }
+
+ public function testCorrectlyConvertsParametersToArrayWhenArraysArePresent()
+ {
+ $param = $this->getComplexParam();
+ $result = $param->toArray();
+ $this->assertInternalType('array', $result['items']);
+ $this->assertEquals('array', $result['type']);
+ $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $param->getItems());
+ }
+
+ public function testAllowsInstanceOf()
+ {
+ $p = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'instanceOf' => get_class($this)
+ ));
+ $this->assertTrue($this->validator->validate($p, $this));
+ $this->assertFalse($this->validator->validate($p, $p));
+ $this->assertEquals(array('[foo] must be an instance of ' . __CLASS__), $this->validator->getErrors());
+ }
+
+ public function testEnforcesInstanceOfOnlyWhenObject()
+ {
+ $p = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => array('object', 'string'),
+ 'instanceOf' => get_class($this)
+ ));
+ $this->assertTrue($this->validator->validate($p, $this));
+ $s = 'test';
+ $this->assertTrue($this->validator->validate($p, $s));
+ }
+
+ public function testConvertsObjectsToArraysWhenToArrayInterface()
+ {
+ $o = $this->getMockBuilder('Guzzle\Common\ToArrayInterface')
+ ->setMethods(array('toArray'))
+ ->getMockForAbstractClass();
+ $o->expects($this->once())
+ ->method('toArray')
+ ->will($this->returnValue(array(
+ 'foo' => 'bar'
+ )));
+ $p = new Parameter(array(
+ 'name' => 'test',
+ 'type' => 'object',
+ 'properties' => array(
+ 'foo' => array('required' => 'true')
+ )
+ ));
+ $this->assertTrue($this->validator->validate($p, $o));
+ }
+
+ public function testMergesValidationErrorsInPropertiesWithParent()
+ {
+ $p = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array(
+ 'bar' => array('type' => 'string', 'required' => true, 'description' => 'This is what it does'),
+ 'test' => array('type' => 'string', 'minLength' => 2, 'maxLength' => 5),
+ 'test2' => array('type' => 'string', 'minLength' => 2, 'maxLength' => 2),
+ 'test3' => array('type' => 'integer', 'minimum' => 100),
+ 'test4' => array('type' => 'integer', 'maximum' => 10),
+ 'test5' => array('type' => 'array', 'maxItems' => 2),
+ 'test6' => array('type' => 'string', 'enum' => array('a', 'bc')),
+ 'test7' => array('type' => 'string', 'pattern' => '/[0-9]+/'),
+ 'test8' => array('type' => 'number'),
+ 'baz' => array(
+ 'type' => 'array',
+ 'minItems' => 2,
+ 'required' => true,
+ "items" => array("type" => "string")
+ )
+ )
+ ));
+
+ $value = array(
+ 'test' => 'a',
+ 'test2' => 'abc',
+ 'baz' => array(false),
+ 'test3' => 10,
+ 'test4' => 100,
+ 'test5' => array(1, 3, 4),
+ 'test6' => 'Foo',
+ 'test7' => 'abc',
+ 'test8' => 'abc'
+ );
+
+ $this->assertFalse($this->validator->validate($p, $value));
+ $this->assertEquals(array (
+ '[foo][bar] is a required string: This is what it does',
+ '[foo][baz] must contain 2 or more elements',
+ '[foo][baz][0] must be of type string',
+ '[foo][test2] length must be less than or equal to 2',
+ '[foo][test3] must be greater than or equal to 100',
+ '[foo][test4] must be less than or equal to 10',
+ '[foo][test5] must contain 2 or fewer elements',
+ '[foo][test6] must be one of "a" or "bc"',
+ '[foo][test7] must match the following regular expression: /[0-9]+/',
+ '[foo][test8] must be of type number',
+ '[foo][test] length must be greater than or equal to 2',
+ ), $this->validator->getErrors());
+ }
+
+ public function testHandlesNullValuesInArraysWithDefaults()
+ {
+ $p = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'required' => true,
+ 'properties' => array(
+ 'bar' => array(
+ 'type' => 'object',
+ 'required' => true,
+ 'properties' => array(
+ 'foo' => array('default' => 'hi')
+ )
+ )
+ )
+ ));
+ $value = array();
+ $this->assertTrue($this->validator->validate($p, $value));
+ $this->assertEquals(array('bar' => array('foo' => 'hi')), $value);
+ }
+
+ public function testFailsWhenNullValuesInArraysWithNoDefaults()
+ {
+ $p = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'required' => true,
+ 'properties' => array(
+ 'bar' => array(
+ 'type' => 'object',
+ 'required' => true,
+ 'properties' => array('foo' => array('type' => 'string'))
+ )
+ )
+ ));
+ $value = array();
+ $this->assertFalse($this->validator->validate($p, $value));
+ $this->assertEquals(array('[foo][bar] is a required object'), $this->validator->getErrors());
+ }
+
+ public function testChecksTypes()
+ {
+ $p = new SchemaValidator();
+ $r = new \ReflectionMethod($p, 'determineType');
+ $r->setAccessible(true);
+ $this->assertEquals('any', $r->invoke($p, 'any', 'hello'));
+ $this->assertEquals(false, $r->invoke($p, 'foo', 'foo'));
+ $this->assertEquals('string', $r->invoke($p, 'string', 'hello'));
+ $this->assertEquals(false, $r->invoke($p, 'string', false));
+ $this->assertEquals('integer', $r->invoke($p, 'integer', 1));
+ $this->assertEquals(false, $r->invoke($p, 'integer', 'abc'));
+ $this->assertEquals('numeric', $r->invoke($p, 'numeric', 1));
+ $this->assertEquals('numeric', $r->invoke($p, 'numeric', '1'));
+ $this->assertEquals('number', $r->invoke($p, 'number', 1));
+ $this->assertEquals('number', $r->invoke($p, 'number', '1'));
+ $this->assertEquals(false, $r->invoke($p, 'numeric', 'a'));
+ $this->assertEquals('boolean', $r->invoke($p, 'boolean', true));
+ $this->assertEquals('boolean', $r->invoke($p, 'boolean', false));
+ $this->assertEquals(false, $r->invoke($p, 'boolean', 'false'));
+ $this->assertEquals('null', $r->invoke($p, 'null', null));
+ $this->assertEquals(false, $r->invoke($p, 'null', 'abc'));
+ $this->assertEquals('array', $r->invoke($p, 'array', array()));
+ $this->assertEquals(false, $r->invoke($p, 'array', 'foo'));
+ }
+
+ public function testValidatesFalseAdditionalProperties()
+ {
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array('bar' => array('type' => 'string')),
+ 'additionalProperties' => false
+ ));
+ $value = array('test' => '123');
+ $this->assertFalse($this->validator->validate($param, $value));
+ $this->assertEquals(array('[foo][test] is not an allowed property'), $this->validator->getErrors());
+ $value = array('bar' => '123');
+ $this->assertTrue($this->validator->validate($param, $value));
+ }
+
+ public function testAllowsUndefinedAdditionalProperties()
+ {
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array('bar' => array('type' => 'string'))
+ ));
+ $value = array('test' => '123');
+ $this->assertTrue($this->validator->validate($param, $value));
+ }
+
+ public function testValidatesAdditionalProperties()
+ {
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'properties' => array('bar' => array('type' => 'string')),
+ 'additionalProperties' => array('type' => 'integer')
+ ));
+ $value = array('test' => 'foo');
+ $this->assertFalse($this->validator->validate($param, $value));
+ $this->assertEquals(array('[foo][test] must be of type integer'), $this->validator->getErrors());
+ }
+
+ public function testValidatesAdditionalPropertiesThatArrayArrays()
+ {
+ $param = new Parameter(array(
+ 'name' => 'foo',
+ 'type' => 'object',
+ 'additionalProperties' => array(
+ 'type' => 'array',
+ 'items' => array('type' => 'string')
+ )
+ ));
+ $value = array('test' => array(true));
+ $this->assertFalse($this->validator->validate($param, $value));
+ $this->assertEquals(array('[foo][test][0] must be of type string'), $this->validator->getErrors());
+ }
+
+ public function testIntegersCastToStringWhenTypeMismatch()
+ {
+ $param = new Parameter(array('name' => 'test', 'type' => 'string'));
+ $value = 12;
+ $this->assertTrue($this->validator->validate($param, $value));
+ $this->assertEquals('12', $value);
+ }
+
+ public function testRequiredMessageIncludesType()
+ {
+ $param = new Parameter(array('name' => 'test', 'type' => array('string', 'boolean'), 'required' => true));
+ $value = null;
+ $this->assertFalse($this->validator->validate($param, $value));
+ $this->assertEquals(array('[test] is a required string or boolean'), $this->validator->getErrors());
+ }
+
+ protected function getComplexParam()
+ {
+ return new Parameter(array(
+ 'name' => 'Foo',
+ 'type' => 'array',
+ 'required' => true,
+ 'min' => 1,
+ 'items' => array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'Baz' => array(
+ 'type' => 'string',
+ ),
+ 'Bar' => array(
+ 'required' => true,
+ 'type' => 'boolean',
+ 'default' => true
+ )
+ )
+ )
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php
new file mode 100755
index 0000000..bbfd1d6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionLoaderTest.php
@@ -0,0 +1,177 @@
+ true,
+ 'baz' => array('bar'),
+ 'apiVersion' => '123',
+ 'operations' => array()
+ ));
+
+ $this->assertEquals(true, $d->getData('foo'));
+ $this->assertEquals(array('bar'), $d->getData('baz'));
+ $this->assertEquals('123', $d->getApiVersion());
+ }
+
+ public function testAllowsDeepNestedInheritance()
+ {
+ $d = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'abstract' => array(
+ 'httpMethod' => 'HEAD',
+ 'parameters' => array(
+ 'test' => array('type' => 'string', 'required' => true)
+ )
+ ),
+ 'abstract2' => array('uri' => '/test', 'extends' => 'abstract'),
+ 'concrete' => array('extends' => 'abstract2'),
+ 'override' => array('extends' => 'abstract', 'httpMethod' => 'PUT'),
+ 'override2' => array('extends' => 'override', 'httpMethod' => 'POST', 'uri' => '/')
+ )
+ ));
+
+ $c = $d->getOperation('concrete');
+ $this->assertEquals('/test', $c->getUri());
+ $this->assertEquals('HEAD', $c->getHttpMethod());
+ $params = $c->getParams();
+ $param = $params['test'];
+ $this->assertEquals('string', $param->getType());
+ $this->assertTrue($param->getRequired());
+
+ // Ensure that merging HTTP method does not make an array
+ $this->assertEquals('PUT', $d->getOperation('override')->getHttpMethod());
+ $this->assertEquals('POST', $d->getOperation('override2')->getHttpMethod());
+ $this->assertEquals('/', $d->getOperation('override2')->getUri());
+ }
+
+ /**
+ * @expectedException RuntimeException
+ */
+ public function testThrowsExceptionWhenExtendingMissingCommand()
+ {
+ ServiceDescription::factory(array(
+ 'operations' => array(
+ 'concrete' => array(
+ 'extends' => 'missing'
+ )
+ )
+ ));
+ }
+
+ public function testAllowsMultipleInheritance()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'a' => array(
+ 'httpMethod' => 'GET',
+ 'parameters' => array(
+ 'a1' => array(
+ 'default' => 'foo',
+ 'required' => true,
+ 'prepend' => 'hi'
+ )
+ )
+ ),
+ 'b' => array(
+ 'extends' => 'a',
+ 'parameters' => array(
+ 'b2' => array()
+ )
+ ),
+ 'c' => array(
+ 'parameters' => array(
+ 'a1' => array(
+ 'default' => 'bar',
+ 'required' => true,
+ 'description' => 'test'
+ ),
+ 'c3' => array()
+ )
+ ),
+ 'd' => array(
+ 'httpMethod' => 'DELETE',
+ 'extends' => array('b', 'c'),
+ 'parameters' => array(
+ 'test' => array()
+ )
+ )
+ )
+ ));
+
+ $command = $description->getOperation('d');
+ $this->assertEquals('DELETE', $command->getHttpMethod());
+ $this->assertContains('a1', $command->getParamNames());
+ $this->assertContains('b2', $command->getParamNames());
+ $this->assertContains('c3', $command->getParamNames());
+ $this->assertContains('test', $command->getParamNames());
+
+ $this->assertTrue($command->getParam('a1')->getRequired());
+ $this->assertEquals('bar', $command->getParam('a1')->getDefault());
+ $this->assertEquals('test', $command->getParam('a1')->getDescription());
+ }
+
+ public function testAddsOtherFields()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(),
+ 'description' => 'Foo',
+ 'apiVersion' => 'bar'
+ ));
+ $this->assertEquals('Foo', $description->getDescription());
+ $this->assertEquals('bar', $description->getApiVersion());
+ }
+
+ public function testCanLoadNestedExtends()
+ {
+ $description = ServiceDescription::factory(array(
+ 'operations' => array(
+ 'root' => array(
+ 'class' => 'foo'
+ ),
+ 'foo' => array(
+ 'extends' => 'root',
+ 'parameters' => array(
+ 'baz' => array('type' => 'string')
+ )
+ ),
+ 'foo_2' => array(
+ 'extends' => 'foo',
+ 'parameters' => array(
+ 'bar' => array('type' => 'string')
+ )
+ ),
+ 'foo_3' => array(
+ 'class' => 'bar',
+ 'parameters' => array(
+ 'bar2' => array('type' => 'string')
+ )
+ ),
+ 'foo_4' => array(
+ 'extends' => array('foo_2', 'foo_3'),
+ 'parameters' => array(
+ 'bar3' => array('type' => 'string')
+ )
+ )
+ )
+ ));
+
+ $this->assertTrue($description->hasOperation('foo_4'));
+ $foo4 = $description->getOperation('foo_4');
+ $this->assertTrue($foo4->hasParam('baz'));
+ $this->assertTrue($foo4->hasParam('bar'));
+ $this->assertTrue($foo4->hasParam('bar2'));
+ $this->assertTrue($foo4->hasParam('bar3'));
+ $this->assertEquals('bar', $foo4->getClass());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php
new file mode 100755
index 0000000..ff25452
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Description/ServiceDescriptionTest.php
@@ -0,0 +1,240 @@
+serviceData = array(
+ 'test_command' => new Operation(array(
+ 'name' => 'test_command',
+ 'description' => 'documentationForCommand',
+ 'httpMethod' => 'DELETE',
+ 'class' => 'Guzzle\\Tests\\Service\\Mock\\Command\\MockCommand',
+ 'parameters' => array(
+ 'bucket' => array('required' => true),
+ 'key' => array('required' => true)
+ )
+ ))
+ );
+ }
+
+ /**
+ * @covers Guzzle\Service\Description\ServiceDescription::factory
+ * @covers Guzzle\Service\Description\ServiceDescriptionLoader::build
+ */
+ public function testFactoryDelegatesToConcreteFactories()
+ {
+ $jsonFile = __DIR__ . '/../../TestData/test_service.json';
+ $this->assertInstanceOf('Guzzle\Service\Description\ServiceDescription', ServiceDescription::factory($jsonFile));
+ }
+
+ public function testConstructor()
+ {
+ $service = new ServiceDescription(array('operations' => $this->serviceData));
+ $this->assertEquals(1, count($service->getOperations()));
+ $this->assertFalse($service->hasOperation('foobar'));
+ $this->assertTrue($service->hasOperation('test_command'));
+ }
+
+ public function testIsSerializable()
+ {
+ $service = new ServiceDescription(array('operations' => $this->serviceData));
+ $data = serialize($service);
+ $d2 = unserialize($data);
+ $this->assertEquals(serialize($service), serialize($d2));
+ }
+
+ public function testSerializesParameters()
+ {
+ $service = new ServiceDescription(array(
+ 'operations' => array(
+ 'foo' => new Operation(array('parameters' => array('foo' => array('type' => 'string'))))
+ )
+ ));
+ $serialized = serialize($service);
+ $this->assertContains('"parameters":{"foo":', $serialized);
+ $service = unserialize($serialized);
+ $this->assertTrue($service->getOperation('foo')->hasParam('foo'));
+ }
+
+ public function testAllowsForJsonBasedArrayParamsFunctionalTest()
+ {
+ $description = new ServiceDescription(array(
+ 'operations' => array(
+ 'test' => new Operation(array(
+ 'httpMethod' => 'PUT',
+ 'parameters' => array(
+ 'data' => array(
+ 'required' => true,
+ 'filters' => 'json_encode',
+ 'location' => 'body'
+ )
+ )
+ ))
+ )
+ ));
+ $client = new Client();
+ $client->setDescription($description);
+ $command = $client->getCommand('test', array(
+ 'data' => array(
+ 'foo' => 'bar'
+ )
+ ));
+
+ $request = $command->prepare();
+ $this->assertEquals('{"foo":"bar"}', (string) $request->getBody());
+ }
+
+ public function testContainsModels()
+ {
+ $d = new ServiceDescription(array(
+ 'operations' => array('foo' => array()),
+ 'models' => array(
+ 'Tag' => array('type' => 'object'),
+ 'Person' => array('type' => 'object')
+ )
+ ));
+ $this->assertTrue($d->hasModel('Tag'));
+ $this->assertTrue($d->hasModel('Person'));
+ $this->assertFalse($d->hasModel('Foo'));
+ $this->assertInstanceOf('Guzzle\Service\Description\Parameter', $d->getModel('Tag'));
+ $this->assertNull($d->getModel('Foo'));
+ $this->assertContains('"models":{', serialize($d));
+ $this->assertEquals(array('Tag', 'Person'), array_keys($d->getModels()));
+ }
+
+ public function testCanAddModels()
+ {
+ $d = new ServiceDescription(array());
+ $this->assertFalse($d->hasModel('Foo'));
+ $d->addModel(new Parameter(array('name' => 'Foo')));
+ $this->assertTrue($d->hasModel('Foo'));
+ }
+
+ public function testHasAttributes()
+ {
+ $d = new ServiceDescription(array(
+ 'operations' => array(),
+ 'name' => 'Name',
+ 'description' => 'Description',
+ 'apiVersion' => '1.24'
+ ));
+
+ $this->assertEquals('Name', $d->getName());
+ $this->assertEquals('Description', $d->getDescription());
+ $this->assertEquals('1.24', $d->getApiVersion());
+
+ $s = serialize($d);
+ $this->assertContains('"name":"Name"', $s);
+ $this->assertContains('"description":"Description"', $s);
+ $this->assertContains('"apiVersion":"1.24"', $s);
+
+ $d = unserialize($s);
+ $this->assertEquals('Name', $d->getName());
+ $this->assertEquals('Description', $d->getDescription());
+ $this->assertEquals('1.24', $d->getApiVersion());
+ }
+
+ public function testPersistsCustomAttributes()
+ {
+ $data = array(
+ 'operations' => array('foo' => array('class' => 'foo', 'parameters' => array())),
+ 'name' => 'Name',
+ 'description' => 'Test',
+ 'apiVersion' => '1.24',
+ 'auth' => 'foo',
+ 'keyParam' => 'bar'
+ );
+ $d = new ServiceDescription($data);
+ $d->setData('hello', 'baz');
+ $this->assertEquals('foo', $d->getData('auth'));
+ $this->assertEquals('baz', $d->getData('hello'));
+ $this->assertEquals('bar', $d->getData('keyParam'));
+ // responseClass and responseType are added by default
+ $data['operations']['foo']['responseClass'] = 'array';
+ $data['operations']['foo']['responseType'] = 'primitive';
+ $this->assertEquals($data + array('hello' => 'baz'), json_decode($d->serialize(), true));
+ }
+
+ public function testHasToArray()
+ {
+ $data = array(
+ 'operations' => array(),
+ 'name' => 'Name',
+ 'description' => 'Test'
+ );
+ $d = new ServiceDescription($data);
+ $arr = $d->toArray();
+ $this->assertEquals('Name', $arr['name']);
+ $this->assertEquals('Test', $arr['description']);
+ }
+
+ public function testReturnsNullWhenRetrievingMissingOperation()
+ {
+ $s = new ServiceDescription(array());
+ $this->assertNull($s->getOperation('foo'));
+ }
+
+ public function testCanAddOperations()
+ {
+ $s = new ServiceDescription(array());
+ $this->assertFalse($s->hasOperation('Foo'));
+ $s->addOperation(new Operation(array('name' => 'Foo')));
+ $this->assertTrue($s->hasOperation('Foo'));
+ }
+
+ /**
+ * @expectedException Guzzle\Common\Exception\InvalidArgumentException
+ */
+ public function testValidatesOperationTypes()
+ {
+ $s = new ServiceDescription(array(
+ 'operations' => array('foo' => new \stdClass())
+ ));
+ }
+
+ public function testHasBaseUrl()
+ {
+ $description = new ServiceDescription(array('baseUrl' => 'http://foo.com'));
+ $this->assertEquals('http://foo.com', $description->getBaseUrl());
+ $description->setBaseUrl('http://foobar.com');
+ $this->assertEquals('http://foobar.com', $description->getBaseUrl());
+ }
+
+ public function testCanUseBasePath()
+ {
+ $description = new ServiceDescription(array('basePath' => 'http://foo.com'));
+ $this->assertEquals('http://foo.com', $description->getBaseUrl());
+ }
+
+ public function testModelsHaveNames()
+ {
+ $desc = array(
+ 'models' => array(
+ 'date' => array('type' => 'string'),
+ 'user'=> array(
+ 'type' => 'object',
+ 'properties' => array(
+ 'dob' => array('$ref' => 'date')
+ )
+ )
+ )
+ );
+
+ $s = ServiceDescription::factory($desc);
+ $this->assertEquals('date', $s->getModel('date')->getName());
+ $this->assertEquals('dob', $s->getModel('user')->getProperty('dob')->getName());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php
new file mode 100755
index 0000000..be0d4ac
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/CommandTransferExceptionTest.php
@@ -0,0 +1,66 @@
+addSuccessfulCommand($c1)->addFailedCommand($c2);
+ $this->assertSame(array($c1), $e->getSuccessfulCommands());
+ $this->assertSame(array($c2), $e->getFailedCommands());
+ $this->assertSame(array($c1, $c2), $e->getAllCommands());
+ }
+
+ public function testConvertsMultiExceptionIntoCommandTransfer()
+ {
+ $r1 = new Request('GET', 'http://foo.com');
+ $r2 = new Request('GET', 'http://foobaz.com');
+ $e = new MultiTransferException('Test', 123);
+ $e->addSuccessfulRequest($r1)->addFailedRequest($r2);
+ $ce = CommandTransferException::fromMultiTransferException($e);
+
+ $this->assertInstanceOf('Guzzle\Service\Exception\CommandTransferException', $ce);
+ $this->assertEquals('Test', $ce->getMessage());
+ $this->assertEquals(123, $ce->getCode());
+ $this->assertSame(array($r1), $ce->getSuccessfulRequests());
+ $this->assertSame(array($r2), $ce->getFailedRequests());
+ }
+
+ public function testCanRetrieveExceptionForCommand()
+ {
+ $r1 = new Request('GET', 'http://foo.com');
+ $e1 = new \Exception('foo');
+ $c1 = $this->getMockBuilder('Guzzle\Tests\Service\Mock\Command\MockCommand')
+ ->setMethods(array('getRequest'))
+ ->getMock();
+ $c1->expects($this->once())->method('getRequest')->will($this->returnValue($r1));
+
+ $e = new MultiTransferException('Test', 123);
+ $e->addFailedRequestWithException($r1, $e1);
+ $ce = CommandTransferException::fromMultiTransferException($e);
+ $ce->addFailedCommand($c1);
+
+ $this->assertSame($e1, $ce->getExceptionForFailedCommand($c1));
+ }
+
+ public function testAddsNonRequestExceptions()
+ {
+ $e = new MultiTransferException();
+ $e->add(new \Exception('bar'));
+ $e->addFailedRequestWithException(new Request('GET', 'http://www.foo.com'), new \Exception('foo'));
+ $ce = CommandTransferException::fromMultiTransferException($e);
+ $this->assertEquals(2, count($ce));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php
new file mode 100755
index 0000000..6455295
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/InconsistentClientTransferExceptionTest.php
@@ -0,0 +1,15 @@
+assertEquals($items, $e->getCommands());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php
new file mode 100755
index 0000000..ef789d8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Exception/ValidationExceptionTest.php
@@ -0,0 +1,17 @@
+setErrors($errors);
+ $this->assertEquals($errors, $e->getErrors());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php
new file mode 100755
index 0000000..4ab423e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/IterableCommand.php
@@ -0,0 +1,31 @@
+ 'iterable_command',
+ 'parameters' => array(
+ 'page_size' => array('type' => 'integer'),
+ 'next_token' => array('type' => 'string')
+ )
+ ));
+ }
+
+ protected function build()
+ {
+ $this->request = $this->client->createRequest('GET');
+
+ // Add the next token and page size query string values
+ $this->request->getQuery()->set('next_token', $this->get('next_token'));
+
+ if ($this->get('page_size')) {
+ $this->request->getQuery()->set('page_size', $this->get('page_size'));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php
new file mode 100755
index 0000000..831a7e7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/MockCommand.php
@@ -0,0 +1,32 @@
+ get_called_class() == __CLASS__ ? 'mock_command' : 'sub.sub',
+ 'httpMethod' => 'POST',
+ 'parameters' => array(
+ 'test' => array(
+ 'default' => 123,
+ 'required' => true,
+ 'doc' => 'Test argument'
+ ),
+ '_internal' => array(
+ 'default' => 'abc'
+ ),
+ 'foo' => array('filters' => array('strtoupper'))
+ )
+ ));
+ }
+
+ protected function build()
+ {
+ $this->request = $this->client->createRequest();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php
new file mode 100755
index 0000000..72ae1f6
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/OtherCommand.php
@@ -0,0 +1,30 @@
+ 'other_command',
+ 'parameters' => array(
+ 'test' => array(
+ 'default' => '123',
+ 'required' => true,
+ 'doc' => 'Test argument'
+ ),
+ 'other' => array(),
+ 'arg' => array('type' => 'string'),
+ 'static' => array('static' => true, 'default' => 'this is static')
+ )
+ ));
+ }
+
+ protected function build()
+ {
+ $this->request = $this->client->getRequest('HEAD');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php
new file mode 100755
index 0000000..d348480
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Command/Sub/Sub.php
@@ -0,0 +1,7 @@
+ '{scheme}://127.0.0.1:8124/{api_version}/{subdomain}',
+ 'scheme' => 'http',
+ 'api_version' => 'v1'
+ ), array('username', 'password', 'subdomain'));
+
+ return new self($config->get('base_url'), $config);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php
new file mode 100755
index 0000000..8faf412
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Mock/Model/MockCommandIterator.php
@@ -0,0 +1,42 @@
+nextToken) {
+ $this->command->set('next_token', $this->nextToken);
+ }
+
+ $this->command->set('page_size', (int) $this->calculatePageSize());
+ $this->command->execute();
+
+ $data = json_decode($this->command->getResponse()->getBody(true), true);
+
+ $this->nextToken = $data['next_token'];
+
+ return $data['resources'];
+ }
+
+ public function next()
+ {
+ $this->calledNext++;
+ parent::next();
+ }
+
+ public function getResources()
+ {
+ return $this->resources;
+ }
+
+ public function getIteratedCount()
+ {
+ return $this->iteratedCount;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php
new file mode 100755
index 0000000..41c2073
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/CompositeResourceIteratorFactoryTest.php
@@ -0,0 +1,37 @@
+assertFalse($factory->canBuild($cmd));
+ $factory->build($cmd);
+ }
+
+ public function testBuildsResourceIterators()
+ {
+ $f1 = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock\Model');
+ $factory = new CompositeResourceIteratorFactory(array());
+ $factory->addFactory($f1);
+ $command = new MockCommand();
+ $iterator = $factory->build($command, array('client.namespace' => 'Guzzle\Tests\Service\Mock'));
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php
new file mode 100755
index 0000000..d166e92
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/MapResourceIteratorFactoryTest.php
@@ -0,0 +1,40 @@
+build(new MockCommand());
+ }
+
+ public function testBuildsResourceIterators()
+ {
+ $factory = new MapResourceIteratorFactory(array(
+ 'mock_command' => 'Guzzle\Tests\Service\Mock\Model\MockCommandIterator'
+ ));
+ $iterator = $factory->build(new MockCommand());
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ }
+
+ public function testUsesWildcardMappings()
+ {
+ $factory = new MapResourceIteratorFactory(array(
+ '*' => 'Guzzle\Tests\Service\Mock\Model\MockCommandIterator'
+ ));
+ $iterator = $factory->build(new MockCommand());
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php
new file mode 100755
index 0000000..7214133
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ModelTest.php
@@ -0,0 +1,65 @@
+ 'object'));
+ $model = new Model(array('foo' => 'bar'), $param);
+ $this->assertSame($param, $model->getStructure());
+ $this->assertEquals('bar', $model->get('foo'));
+ $this->assertEquals('bar', $model['foo']);
+ }
+
+ public function testCanBeUsedWithoutStructure()
+ {
+ $model = new Model(array(
+ 'Foo' => 'baz',
+ 'Bar' => array(
+ 'Boo' => 'Bam'
+ )
+ ));
+ $transform = function ($key, $value) {
+ return ($value && is_array($value)) ? new Collection($value) : $value;
+ };
+ $model = $model->map($transform);
+ $this->assertInstanceOf('Guzzle\Common\Collection', $model->getPath('Bar'));
+ }
+
+ public function testAllowsFiltering()
+ {
+ $model = new Model(array(
+ 'Foo' => 'baz',
+ 'Bar' => 'a'
+ ));
+ $model = $model->filter(function ($i, $v) {
+ return $v[0] == 'a';
+ });
+ $this->assertEquals(array('Bar' => 'a'), $model->toArray());
+ }
+
+ public function testDoesNotIncludeEmptyStructureInString()
+ {
+ $model = new Model(array('Foo' => 'baz'));
+ $str = (string) $model;
+ $this->assertContains('Debug output of model', $str);
+ $this->assertNotContains('Model structure', $str);
+ }
+
+ public function testDoesIncludeModelStructureInString()
+ {
+ $model = new Model(array('Foo' => 'baz'), new Parameter(array('name' => 'Foo')));
+ $str = (string) $model;
+ $this->assertContains('Debug output of Foo model', $str);
+ $this->assertContains('Model structure', $str);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php
new file mode 100755
index 0000000..7b061b5
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorClassFactoryTest.php
@@ -0,0 +1,41 @@
+registerNamespace('Baz');
+ $command = new MockCommand();
+ $factory->build($command);
+ }
+
+ public function testBuildsResourceIterators()
+ {
+ $factory = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock\Model');
+ $command = new MockCommand();
+ $iterator = $factory->build($command, array('client.namespace' => 'Guzzle\Tests\Service\Mock'));
+ $this->assertInstanceOf('Guzzle\Tests\Service\Mock\Model\MockCommandIterator', $iterator);
+ }
+
+ public function testChecksIfCanBuild()
+ {
+ $factory = new ResourceIteratorClassFactory('Guzzle\Tests\Service');
+ $this->assertFalse($factory->canBuild(new MockCommand()));
+ $factory = new ResourceIteratorClassFactory('Guzzle\Tests\Service\Mock\Model');
+ $this->assertTrue($factory->canBuild(new MockCommand()));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php
new file mode 100755
index 0000000..573fb6d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Service/Resource/ResourceIteratorTest.php
@@ -0,0 +1,184 @@
+assertInternalType('array', ResourceIterator::getAllEvents());
+ }
+
+ public function testConstructorConfiguresDefaults()
+ {
+ $ri = $this->getMockForAbstractClass('Guzzle\\Service\\Resource\\ResourceIterator', array(
+ $this->getServiceBuilder()->get('mock')->getCommand('iterable_command'),
+ array(
+ 'limit' => 10,
+ 'page_size' => 3
+ )
+ ), 'MockIterator');
+
+ $this->assertEquals(false, $ri->getNextToken());
+ $this->assertEquals(false, $ri->current());
+ }
+
+ public function testSendsRequestsForNextSetOfResources()
+ {
+ // Queue up an array of responses for iterating
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }"
+ ));
+
+ // Create a new resource iterator using the IterableCommand mock
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'), array(
+ 'page_size' => 3
+ ));
+
+ // Ensure that no requests have been sent yet
+ $this->assertEquals(0, count($this->getServer()->getReceivedRequests(false)));
+
+ //$this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i', 'j'), $ri->toArray());
+ $ri->toArray();
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals(3, count($requests));
+
+ $this->assertEquals(3, $requests[0]->getQuery()->get('page_size'));
+ $this->assertEquals(3, $requests[1]->getQuery()->get('page_size'));
+ $this->assertEquals(3, $requests[2]->getQuery()->get('page_size'));
+
+ // Reset and resend
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 41\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"j\"] }",
+ ));
+
+ $d = array();
+ foreach ($ri as $data) {
+ $d[] = $data;
+ }
+ $this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i', 'j'), $d);
+ }
+
+ public function testCalculatesPageSize()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"g\", \"h\", \"i\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"j\", \"resources\": [\"j\", \"k\"] }"
+ ));
+
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'), array(
+ 'page_size' => 3,
+ 'limit' => 7
+ ));
+
+ $this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i', 'j'), $ri->toArray());
+ $requests = $this->getServer()->getReceivedRequests(true);
+ $this->assertEquals(3, count($requests));
+ $this->assertEquals(3, $requests[0]->getQuery()->get('page_size'));
+ $this->assertEquals(3, $requests[1]->getQuery()->get('page_size'));
+ $this->assertEquals(1, $requests[2]->getQuery()->get('page_size'));
+ }
+
+ public function testUseAsArray()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\nContent-Length: 52\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"g\", \"h\", \"i\"] }"
+ ));
+
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'));
+
+ // Ensure that the key is never < 0
+ $this->assertEquals(0, $ri->key());
+ $this->assertEquals(0, count($ri));
+
+ // Ensure that the iterator can be used as KVP array
+ $data = array();
+ foreach ($ri as $key => $value) {
+ $data[$key] = $value;
+ }
+
+ // Ensure that the iterate is countable
+ $this->assertEquals(6, count($ri));
+ $this->assertEquals(array('d', 'e', 'f', 'g', 'h', 'i'), $data);
+ }
+
+ public function testBailsWhenSendReturnsNoResults()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"g\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [] }"
+ ));
+
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'));
+
+ // Ensure that the iterator can be used as KVP array
+ $data = $ri->toArray();
+
+ // Ensure that the iterate is countable
+ $this->assertEquals(3, count($ri));
+ $this->assertEquals(array('d', 'e', 'f'), $data);
+
+ $this->assertEquals(2, $ri->getRequestCount());
+ }
+
+ public function testHoldsDataOptions()
+ {
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'));
+ $this->assertNull($ri->get('foo'));
+ $this->assertSame($ri, $ri->set('foo', 'bar'));
+ $this->assertEquals('bar', $ri->get('foo'));
+ }
+
+ public function testSettingLimitOrPageSizeClearsData()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }",
+ "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }"
+ ));
+
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'));
+ $ri->toArray();
+ $this->assertNotEmpty($this->readAttribute($ri, 'resources'));
+
+ $ri->setLimit(10);
+ $this->assertEmpty($this->readAttribute($ri, 'resources'));
+
+ $ri->toArray();
+ $this->assertNotEmpty($this->readAttribute($ri, 'resources'));
+ $ri->setPageSize(10);
+ $this->assertEmpty($this->readAttribute($ri, 'resources'));
+ }
+
+ public function testWorksWithCustomAppendIterator()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue(array(
+ "HTTP/1.1 200 OK\r\n\r\n{ \"next_token\": \"\", \"resources\": [\"d\", \"e\", \"f\"] }"
+ ));
+ $ri = new MockCommandIterator($this->getServiceBuilder()->get('mock')->getCommand('iterable_command'));
+ $a = new \Guzzle\Iterator\AppendIterator();
+ $a->append($ri);
+ $results = iterator_to_array($a, false);
+ $this->assertEquals(4, $ri->calledNext);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php
new file mode 100755
index 0000000..083aaa0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/PhpStreamRequestFactoryTest.php
@@ -0,0 +1,172 @@
+client = new Client($this->getServer()->getUrl());
+ $this->factory = new PhpStreamRequestFactory();
+ }
+
+ public function testOpensValidStreamByCreatingContext()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+ $request = $this->client->get('/');
+ $stream = $this->factory->fromRequest($request);
+ $this->assertEquals('hi', (string) $stream);
+ $headers = $this->factory->getLastResponseHeaders();
+ $this->assertContains('HTTP/1.1 200 OK', $headers);
+ $this->assertContains('Content-Length: 2', $headers);
+ $this->assertSame($headers, $stream->getCustomData('response_headers'));
+ $this->assertEquals(2, $stream->getSize());
+ }
+
+ public function testOpensValidStreamByPassingContextAndMerging()
+ {
+ $request = $this->client->get('/');
+ $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory')
+ ->setMethods(array('createContext', 'createStream'))
+ ->getMock();
+ $this->factory->expects($this->never())
+ ->method('createContext');
+ $this->factory->expects($this->once())
+ ->method('createStream')
+ ->will($this->returnValue(new Stream(fopen('php://temp', 'r'))));
+
+ $context = array('http' => array('method' => 'HEAD', 'ignore_errors' => false));
+ $this->factory->fromRequest($request, stream_context_create($context));
+ $options = stream_context_get_options($this->readAttribute($this->factory, 'context'));
+ $this->assertEquals('HEAD', $options['http']['method']);
+ $this->assertFalse($options['http']['ignore_errors']);
+ $this->assertEquals('1.1', $options['http']['protocol_version']);
+ }
+
+ public function testAppliesProxySettings()
+ {
+ $request = $this->client->get('/');
+ $request->getCurlOptions()->set(CURLOPT_PROXY, 'tcp://foo.com');
+ $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory')
+ ->setMethods(array('createStream'))
+ ->getMock();
+ $this->factory->expects($this->once())
+ ->method('createStream')
+ ->will($this->returnValue(new Stream(fopen('php://temp', 'r'))));
+ $this->factory->fromRequest($request);
+ $options = stream_context_get_options($this->readAttribute($this->factory, 'context'));
+ $this->assertEquals('tcp://foo.com', $options['http']['proxy']);
+ }
+
+ public function testAddsPostFields()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+ $request = $this->client->post('/', array('Foo' => 'Bar'), array('foo' => 'baz bar'));
+ $stream = $this->factory->fromRequest($request);
+ $this->assertEquals('hi', (string) $stream);
+
+ $headers = $this->factory->getLastResponseHeaders();
+ $this->assertContains('HTTP/1.1 200 OK', $headers);
+ $this->assertContains('Content-Length: 2', $headers);
+ $this->assertSame($headers, $stream->getCustomData('response_headers'));
+
+ $received = $this->getServer()->getReceivedRequests();
+ $this->assertEquals(1, count($received));
+ $this->assertContains('POST / HTTP/1.1', $received[0]);
+ $this->assertContains('host: ', $received[0]);
+ $this->assertContains('user-agent: Guzzle/', $received[0]);
+ $this->assertContains('foo: Bar', $received[0]);
+ $this->assertContains('content-length: 13', $received[0]);
+ $this->assertContains('foo=baz%20bar', $received[0]);
+ }
+
+ public function testAddsBody()
+ {
+ $this->getServer()->flush();
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+ $request = $this->client->put('/', array('Foo' => 'Bar'), 'Testing...123');
+ $stream = $this->factory->fromRequest($request);
+ $this->assertEquals('hi', (string) $stream);
+
+ $headers = $this->factory->getLastResponseHeaders();
+ $this->assertContains('HTTP/1.1 200 OK', $headers);
+ $this->assertContains('Content-Length: 2', $headers);
+ $this->assertSame($headers, $stream->getCustomData('response_headers'));
+
+ $received = $this->getServer()->getReceivedRequests();
+ $this->assertEquals(1, count($received));
+ $this->assertContains('PUT / HTTP/1.1', $received[0]);
+ $this->assertContains('host: ', $received[0]);
+ $this->assertContains('user-agent: Guzzle/', $received[0]);
+ $this->assertContains('foo: Bar', $received[0]);
+ $this->assertContains('content-length: 13', $received[0]);
+ $this->assertContains('Testing...123', $received[0]);
+ }
+
+ public function testCanDisableSslValidation()
+ {
+ $request = $this->client->get('/');
+ $request->getCurlOptions()->set(CURLOPT_SSL_VERIFYPEER, false);
+ $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory')
+ ->setMethods(array('createStream'))
+ ->getMock();
+ $this->factory->expects($this->once())
+ ->method('createStream')
+ ->will($this->returnValue(new Stream(fopen('php://temp', 'r'))));
+ $this->factory->fromRequest($request);
+ $options = stream_context_get_options($this->readAttribute($this->factory, 'context'));
+ $this->assertFalse($options['ssl']['verify_peer']);
+ }
+
+ public function testUsesSslValidationByDefault()
+ {
+ $request = $this->client->get('/');
+ $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory')
+ ->setMethods(array('createStream'))
+ ->getMock();
+ $this->factory->expects($this->once())
+ ->method('createStream')
+ ->will($this->returnValue(new Stream(fopen('php://temp', 'r'))));
+ $this->factory->fromRequest($request);
+ $options = stream_context_get_options($this->readAttribute($this->factory, 'context'));
+ $this->assertTrue($options['ssl']['verify_peer']);
+ $this->assertSame($request->getCurlOptions()->get(CURLOPT_CAINFO), $options['ssl']['cafile']);
+ }
+
+ public function testBasicAuthAddsUserAndPassToUrl()
+ {
+ $request = $this->client->get('/');
+ $request->setAuth('Foo', 'Bar');
+ $this->factory = $this->getMockBuilder('Guzzle\Stream\PhpStreamRequestFactory')
+ ->setMethods(array('createStream'))
+ ->getMock();
+ $this->factory->expects($this->once())
+ ->method('createStream')
+ ->will($this->returnValue(new Stream(fopen('php://temp', 'r'))));
+ $this->factory->fromRequest($request);
+ $this->assertContains('Foo:Bar@', (string) $this->readAttribute($this->factory, 'url'));
+ }
+
+ public function testCanCreateCustomStreamClass()
+ {
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nhi");
+ $request = $this->client->get('/');
+ $stream = $this->factory->fromRequest($request, array(), array('stream_class' => 'Guzzle\Http\EntityBody'));
+ $this->assertInstanceOf('Guzzle\Http\EntityBody', $stream);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php
new file mode 100755
index 0000000..4973f25
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/Stream/StreamTest.php
@@ -0,0 +1,189 @@
+assertEquals($handle, $stream->getStream());
+ $this->assertTrue($stream->isReadable());
+ $this->assertTrue($stream->isWritable());
+ $this->assertTrue($stream->isLocal());
+ $this->assertTrue($stream->isSeekable());
+ $this->assertEquals('PHP', $stream->getWrapper());
+ $this->assertEquals('TEMP', $stream->getStreamType());
+ $this->assertEquals(4, $stream->getSize());
+ $this->assertEquals('php://temp', $stream->getUri());
+ $this->assertEquals(array(), $stream->getWrapperData());
+ $this->assertFalse($stream->isConsumed());
+ unset($stream);
+ }
+
+ public function testCanModifyStream()
+ {
+ $handle1 = fopen('php://temp', 'r+');
+ $handle2 = fopen('php://temp', 'r+');
+ $stream = new Stream($handle1);
+ $this->assertSame($handle1, $stream->getStream());
+ $stream->setStream($handle2, 10);
+ $this->assertEquals(10, $stream->getSize());
+ $this->assertSame($handle2, $stream->getStream());
+ }
+
+ public function testStreamClosesHandleOnDestruct()
+ {
+ $handle = fopen('php://temp', 'r');
+ $stream = new Stream($handle);
+ unset($stream);
+ $this->assertFalse(is_resource($handle));
+ }
+
+ public function testConvertsToString()
+ {
+ $handle = fopen('php://temp', 'w+');
+ fwrite($handle, 'data');
+ $stream = new Stream($handle);
+ $this->assertEquals('data', (string) $stream);
+ unset($stream);
+
+ $handle = fopen(__DIR__ . '/../TestData/FileBody.txt', 'r');
+ $stream = new Stream($handle);
+ $this->assertEquals('', (string) $stream);
+ unset($stream);
+ }
+
+ public function testConvertsToStringAndRestoresCursorPos()
+ {
+ $handle = fopen('php://temp', 'w+');
+ $stream = new Stream($handle);
+ $stream->write('foobazbar');
+ $stream->seek(3);
+ $this->assertEquals('foobazbar', (string) $stream);
+ $this->assertEquals(3, $stream->ftell());
+ }
+
+ public function testIsConsumed()
+ {
+ $handle = fopen('php://temp', 'w+');
+ fwrite($handle, 'data');
+ $stream = new Stream($handle);
+ $this->assertFalse($stream->isConsumed());
+ $stream->read(4);
+ $this->assertTrue($stream->isConsumed());
+ }
+
+ public function testAllowsSettingManualSize()
+ {
+ $handle = fopen('php://temp', 'w+');
+ fwrite($handle, 'data');
+ $stream = new Stream($handle);
+ $stream->setSize(10);
+ $this->assertEquals(10, $stream->getSize());
+ unset($stream);
+ }
+
+ public function testWrapsStream()
+ {
+ $handle = fopen('php://temp', 'w+');
+ fwrite($handle, 'data');
+ $stream = new Stream($handle);
+ $this->assertTrue($stream->isSeekable());
+ $this->assertTrue($stream->isReadable());
+ $this->assertTrue($stream->seek(0));
+ $this->assertEquals('da', $stream->read(2));
+ $this->assertEquals('ta', $stream->read(2));
+ $this->assertTrue($stream->seek(0));
+ $this->assertEquals('data', $stream->read(4));
+ $stream->write('_appended');
+ $stream->seek(0);
+ $this->assertEquals('data_appended', $stream->read(13));
+ }
+
+ public function testGetSize()
+ {
+ $size = filesize(__DIR__ . '/../../../bootstrap.php');
+ $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r');
+ $stream = new Stream($handle);
+ $this->assertEquals($handle, $stream->getStream());
+ $this->assertEquals($size, $stream->getSize());
+ $this->assertEquals($size, $stream->getSize());
+ unset($stream);
+
+ // Make sure that false is returned when the size cannot be determined
+ $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
+ $handle = fopen('http://127.0.0.1:' . $this->getServer()->getPort(), 'r');
+ $stream = new Stream($handle);
+ $this->assertEquals(false, $stream->getSize());
+ unset($stream);
+ }
+
+ public function testEnsuresSizeIsConsistent()
+ {
+ $h = fopen('php://temp', 'r+');
+ fwrite($h, 'foo');
+ $stream = new Stream($h);
+ $this->assertEquals(3, $stream->getSize());
+ $stream->write('test');
+ $this->assertEquals(7, $stream->getSize());
+ fclose($h);
+ }
+
+ public function testAbstractsMetaData()
+ {
+ $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r');
+ $stream = new Stream($handle);
+ $this->assertEquals('plainfile', $stream->getMetaData('wrapper_type'));
+ $this->assertEquals(null, $stream->getMetaData('wrapper_data'));
+ $this->assertInternalType('array', $stream->getMetaData());
+ }
+
+ public function testDoesNotAttemptToWriteToReadonlyStream()
+ {
+ $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r');
+ $stream = new Stream($handle);
+ $this->assertEquals(0, $stream->write('foo'));
+ }
+
+ public function testProvidesStreamPosition()
+ {
+ $handle = fopen(__DIR__ . '/../../../bootstrap.php', 'r');
+ $stream = new Stream($handle);
+ $stream->read(2);
+ $this->assertSame(ftell($handle), $stream->ftell());
+ $this->assertEquals(2, $stream->ftell());
+ }
+
+ public function testRewindIsSeekZero()
+ {
+ $stream = new Stream(fopen('php://temp', 'w+'));
+ $stream->write('foobazbar');
+ $this->assertTrue($stream->rewind());
+ $this->assertEquals('foobazbar', $stream->read(9));
+ }
+
+ public function testCanDetachStream()
+ {
+ $r = fopen('php://temp', 'w+');
+ $stream = new Stream($r);
+ $stream->detachStream();
+ $this->assertNull($stream->getStream());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/FileBody.txt b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/FileBody.txt
new file mode 100755
index 0000000..e69de29
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json
new file mode 100755
index 0000000..c354ed7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/bar.json
@@ -0,0 +1,3 @@
+{
+ "includes": ["foo.json"]
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json
new file mode 100755
index 0000000..765237b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/baz.json
@@ -0,0 +1,3 @@
+{
+ "includes": ["foo.json", "bar.json"]
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json
new file mode 100755
index 0000000..cee5005
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/foo.json
@@ -0,0 +1,8 @@
+{
+ "includes": ["recursive.json"],
+ "operations": {
+ "abstract": {
+ "httpMethod": "POST"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json
new file mode 100755
index 0000000..c354ed7
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/description/recursive.json
@@ -0,0 +1,3 @@
+{
+ "includes": ["foo.json"]
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response
new file mode 100755
index 0000000..b6938a2
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/mock_response
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Content-Length: 0
+
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json
new file mode 100755
index 0000000..7b2a9da
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json1.json
@@ -0,0 +1,18 @@
+{
+ "includes": [ "json2.json" ],
+ "services": {
+ "abstract": {
+ "access_key": "xyz",
+ "secret": "abc"
+ },
+ "mock": {
+ "class": "Guzzle\\Tests\\Service\\Mock\\MockClient",
+ "extends": "abstract",
+ "params": {
+ "username": "foo",
+ "password": "baz",
+ "subdomain": "bar"
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json
new file mode 100755
index 0000000..08e5566
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/json2.json
@@ -0,0 +1,11 @@
+{
+ "services": {
+ "foo": {
+ "class": "Guzzle\\Tests\\Service\\Mock\\MockClient",
+ "extends": "abstract",
+ "params": {
+ "baz": "bar"
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json
new file mode 100755
index 0000000..25452e4
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/services/services.json
@@ -0,0 +1,71 @@
+{
+ "abstract": {
+ "access_key": "xyz",
+ "secret": "abc"
+ },
+ "mock": {
+ "class": "Guzzle\\Tests\\Service\\Mock\\MockClient",
+ "extends": "abstract",
+ "params": {
+ "username": "foo",
+ "password": "baz",
+ "subdomain": "bar"
+ }
+ },
+
+ "test.abstract.aws": {
+ "params": {
+ "access_key": "12345",
+ "secret_key": "abcd"
+ }
+ },
+
+ "test.s3": {
+ "class": "Guzzle\\Service\\Aws\\S3Client",
+ "extends": "test.abstract.aws",
+ "params": {
+ "devpay_product_token": "",
+ "devpay_user_token": ""
+ }
+ },
+
+ "test.simple_db": {
+ "class": "Guzzle\\Service\\Aws\\SimpleDb\\SimpleDbClient",
+ "extends": "test.abstract.aws"
+ },
+
+ "test.sqs": {
+ "class": "Guzzle\\Service\\Aws\\Sqs\\SqsClient",
+ "extends": "test.abstract.aws"
+ },
+
+ "test.centinel": {
+ "class": "Guzzle\\Service\\CardinalCommerce\\Centinel.CentinelClient",
+ "params": {
+ "password": "test",
+ "processor_id": "123",
+ "merchant_id": "456"
+ }
+ },
+
+ "test.mws": {
+ "class": "Guzzle\\Service\\Mws\\MwsClient",
+ "extends": "test.abstract.aws",
+ "params": {
+ "merchant_id": "ABCDE",
+ "marketplace_id": "FGHIJ",
+ "application_name": "GuzzleTest",
+ "application_version": "0.1",
+ "base_url": "https://mws.amazonservices.com"
+ }
+ },
+
+ "mock": {
+ "class": "Guzzle\\Tests\\Service\\Mock\\MockClient",
+ "params": {
+ "username": "test_user",
+ "password": "****",
+ "subdomain": "test"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json
new file mode 100755
index 0000000..01557ca
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service.json
@@ -0,0 +1,40 @@
+{
+ "includes": [ "test_service2.json" ],
+ "operations": {
+ "test": {
+ "uri": "/path"
+ },
+ "concrete": {
+ "extends": "abstract"
+ },
+ "foo_bar": {
+ "uri": "/testing",
+ "parameters": {
+ "other": {
+ "location": "json",
+ "location_key": "Other"
+ },
+ "test": {
+ "type": "object",
+ "location": "json",
+ "properties": {
+ "baz": {
+ "type": "boolean",
+ "default": true
+ },
+ "bar": {
+ "type": "string",
+ "filters": [
+ {
+ "method": "strtolower",
+ "args": ["test", "@value"]
+ },
+ "strtoupper"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json
new file mode 100755
index 0000000..66dd9ef
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service2.json
@@ -0,0 +1,7 @@
+{
+ "operations": {
+ "abstract": {
+ "uri": "/abstract"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json
new file mode 100755
index 0000000..ae2ae0b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/Guzzle/Tests/TestData/test_service_3.json
@@ -0,0 +1,40 @@
+{
+ "includes": [ "test_service2.json" ],
+ "operations": {
+ "test": {
+ "uri": "/path"
+ },
+ "concrete": {
+ "extends": "abstract"
+ },
+ "baz_qux": {
+ "uri": "/testing",
+ "parameters": {
+ "other": {
+ "location": "json",
+ "location_key": "Other"
+ },
+ "test": {
+ "type": "object",
+ "location": "json",
+ "properties": {
+ "baz": {
+ "type": "boolean",
+ "default": true
+ },
+ "bar": {
+ "type": "string",
+ "filters": [
+ {
+ "method": "strtolower",
+ "args": ["test", "@value"]
+ },
+ "strtoupper"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/bootstrap.php b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/bootstrap.php
new file mode 100755
index 0000000..28908d3
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/guzzle/guzzle/tests/bootstrap.php
@@ -0,0 +1,10 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Lazily loads listeners and subscribers from the dependency injection
+ * container.
+ *
+ * @author Fabien Potencier
+ * @author Bernhard Schussek
+ * @author Jordan Alliot
+ */
+class ContainerAwareEventDispatcher extends EventDispatcher
+{
+ private $container;
+
+ /**
+ * The service IDs of the event listeners and subscribers.
+ */
+ private $listenerIds = array();
+
+ /**
+ * The services registered as listeners.
+ */
+ private $listeners = array();
+
+ public function __construct(ContainerInterface $container)
+ {
+ $this->container = $container;
+ }
+
+ /**
+ * Adds a service as event listener.
+ *
+ * @param string $eventName Event for which the listener is added
+ * @param array $callback The service ID of the listener service & the method
+ * name that has to be called
+ * @param int $priority The higher this value, the earlier an event listener
+ * will be triggered in the chain.
+ * Defaults to 0.
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addListenerService($eventName, $callback, $priority = 0)
+ {
+ if (!\is_array($callback) || 2 !== \count($callback)) {
+ throw new \InvalidArgumentException('Expected an array("service", "method") argument');
+ }
+
+ $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority);
+ }
+
+ public function removeListener($eventName, $listener)
+ {
+ $this->lazyLoad($eventName);
+
+ if (isset($this->listenerIds[$eventName])) {
+ foreach ($this->listenerIds[$eventName] as $i => $args) {
+ list($serviceId, $method) = $args;
+ $key = $serviceId.'.'.$method;
+ if (isset($this->listeners[$eventName][$key]) && $listener === array($this->listeners[$eventName][$key], $method)) {
+ unset($this->listeners[$eventName][$key]);
+ if (empty($this->listeners[$eventName])) {
+ unset($this->listeners[$eventName]);
+ }
+ unset($this->listenerIds[$eventName][$i]);
+ if (empty($this->listenerIds[$eventName])) {
+ unset($this->listenerIds[$eventName]);
+ }
+ }
+ }
+ }
+
+ parent::removeListener($eventName, $listener);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasListeners($eventName = null)
+ {
+ if (null === $eventName) {
+ return $this->listenerIds || $this->listeners || parent::hasListeners();
+ }
+
+ if (isset($this->listenerIds[$eventName])) {
+ return true;
+ }
+
+ return parent::hasListeners($eventName);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListeners($eventName = null)
+ {
+ if (null === $eventName) {
+ foreach ($this->listenerIds as $serviceEventName => $args) {
+ $this->lazyLoad($serviceEventName);
+ }
+ } else {
+ $this->lazyLoad($eventName);
+ }
+
+ return parent::getListeners($eventName);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListenerPriority($eventName, $listener)
+ {
+ $this->lazyLoad($eventName);
+
+ return parent::getListenerPriority($eventName, $listener);
+ }
+
+ /**
+ * Adds a service as event subscriber.
+ *
+ * @param string $serviceId The service ID of the subscriber service
+ * @param string $class The service's class name (which must implement EventSubscriberInterface)
+ */
+ public function addSubscriberService($serviceId, $class)
+ {
+ foreach ($class::getSubscribedEvents() as $eventName => $params) {
+ if (\is_string($params)) {
+ $this->listenerIds[$eventName][] = array($serviceId, $params, 0);
+ } elseif (\is_string($params[0])) {
+ $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0);
+ } else {
+ foreach ($params as $listener) {
+ $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0);
+ }
+ }
+ }
+ }
+
+ public function getContainer()
+ {
+ return $this->container;
+ }
+
+ /**
+ * Lazily loads listeners for this event from the dependency injection
+ * container.
+ *
+ * @param string $eventName The name of the event to dispatch. The name of
+ * the event is the name of the method that is
+ * invoked on listeners.
+ */
+ protected function lazyLoad($eventName)
+ {
+ if (isset($this->listenerIds[$eventName])) {
+ foreach ($this->listenerIds[$eventName] as $args) {
+ list($serviceId, $method, $priority) = $args;
+ $listener = $this->container->get($serviceId);
+
+ $key = $serviceId.'.'.$method;
+ if (!isset($this->listeners[$eventName][$key])) {
+ $this->addListener($eventName, array($listener, $method), $priority);
+ } elseif ($this->listeners[$eventName][$key] !== $listener) {
+ parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method));
+ $this->addListener($eventName, array($listener, $method), $priority);
+ }
+
+ $this->listeners[$eventName][$key] = $listener;
+ }
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php
new file mode 100755
index 0000000..53d7c5d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php
@@ -0,0 +1,375 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Debug;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Stopwatch\Stopwatch;
+
+/**
+ * Collects some data about event listeners.
+ *
+ * This event dispatcher delegates the dispatching to another one.
+ *
+ * @author Fabien Potencier
+ */
+class TraceableEventDispatcher implements TraceableEventDispatcherInterface
+{
+ protected $logger;
+ protected $stopwatch;
+
+ private $called;
+ private $dispatcher;
+ private $wrappedListeners;
+
+ public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null)
+ {
+ $this->dispatcher = $dispatcher;
+ $this->stopwatch = $stopwatch;
+ $this->logger = $logger;
+ $this->called = array();
+ $this->wrappedListeners = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addListener($eventName, $listener, $priority = 0)
+ {
+ $this->dispatcher->addListener($eventName, $listener, $priority);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ $this->dispatcher->addSubscriber($subscriber);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeListener($eventName, $listener)
+ {
+ if (isset($this->wrappedListeners[$eventName])) {
+ foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) {
+ if ($wrappedListener->getWrappedListener() === $listener) {
+ $listener = $wrappedListener;
+ unset($this->wrappedListeners[$eventName][$index]);
+ break;
+ }
+ }
+ }
+
+ return $this->dispatcher->removeListener($eventName, $listener);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeSubscriber(EventSubscriberInterface $subscriber)
+ {
+ return $this->dispatcher->removeSubscriber($subscriber);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListeners($eventName = null)
+ {
+ return $this->dispatcher->getListeners($eventName);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListenerPriority($eventName, $listener)
+ {
+ if (!method_exists($this->dispatcher, 'getListenerPriority')) {
+ return 0;
+ }
+
+ return $this->dispatcher->getListenerPriority($eventName, $listener);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasListeners($eventName = null)
+ {
+ return $this->dispatcher->hasListeners($eventName);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dispatch($eventName, Event $event = null)
+ {
+ if (null === $event) {
+ $event = new Event();
+ }
+
+ if (null !== $this->logger && $event->isPropagationStopped()) {
+ $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName));
+ }
+
+ $this->preProcess($eventName);
+ $this->preDispatch($eventName, $event);
+
+ $e = $this->stopwatch->start($eventName, 'section');
+
+ $this->dispatcher->dispatch($eventName, $event);
+
+ if ($e->isStarted()) {
+ $e->stop();
+ }
+
+ $this->postDispatch($eventName, $event);
+ $this->postProcess($eventName);
+
+ return $event;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCalledListeners()
+ {
+ $called = array();
+ foreach ($this->called as $eventName => $listeners) {
+ foreach ($listeners as $listener) {
+ $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
+ $called[$eventName.'.'.$info['pretty']] = $info;
+ }
+ }
+
+ return $called;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNotCalledListeners()
+ {
+ try {
+ $allListeners = $this->getListeners();
+ } catch (\Exception $e) {
+ if (null !== $this->logger) {
+ $this->logger->info('An exception was thrown while getting the uncalled listeners.', array('exception' => $e));
+ }
+
+ // unable to retrieve the uncalled listeners
+ return array();
+ }
+
+ $notCalled = array();
+ foreach ($allListeners as $eventName => $listeners) {
+ foreach ($listeners as $listener) {
+ $called = false;
+ if (isset($this->called[$eventName])) {
+ foreach ($this->called[$eventName] as $l) {
+ if ($l->getWrappedListener() === $listener) {
+ $called = true;
+
+ break;
+ }
+ }
+ }
+
+ if (!$called) {
+ $info = $this->getListenerInfo($listener, $eventName);
+ $notCalled[$eventName.'.'.$info['pretty']] = $info;
+ }
+ }
+ }
+
+ uasort($notCalled, array($this, 'sortListenersByPriority'));
+
+ return $notCalled;
+ }
+
+ /**
+ * Proxies all method calls to the original event dispatcher.
+ *
+ * @param string $method The method name
+ * @param array $arguments The method arguments
+ *
+ * @return mixed
+ */
+ public function __call($method, $arguments)
+ {
+ return \call_user_func_array(array($this->dispatcher, $method), $arguments);
+ }
+
+ /**
+ * Called before dispatching the event.
+ *
+ * @param string $eventName The event name
+ * @param Event $event The event
+ */
+ protected function preDispatch($eventName, Event $event)
+ {
+ }
+
+ /**
+ * Called after dispatching the event.
+ *
+ * @param string $eventName The event name
+ * @param Event $event The event
+ */
+ protected function postDispatch($eventName, Event $event)
+ {
+ }
+
+ private function preProcess($eventName)
+ {
+ foreach ($this->dispatcher->getListeners($eventName) as $listener) {
+ $info = $this->getListenerInfo($listener, $eventName);
+ $name = isset($info['class']) ? $info['class'] : $info['type'];
+ $wrappedListener = new WrappedListener($listener, $name, $this->stopwatch, $this);
+ $this->wrappedListeners[$eventName][] = $wrappedListener;
+ $this->dispatcher->removeListener($eventName, $listener);
+ $this->dispatcher->addListener($eventName, $wrappedListener, $info['priority']);
+ }
+ }
+
+ private function postProcess($eventName)
+ {
+ unset($this->wrappedListeners[$eventName]);
+ $skipped = false;
+ foreach ($this->dispatcher->getListeners($eventName) as $listener) {
+ if (!$listener instanceof WrappedListener) { // #12845: a new listener was added during dispatch.
+ continue;
+ }
+ // Unwrap listener
+ $priority = $this->getListenerPriority($eventName, $listener);
+ $this->dispatcher->removeListener($eventName, $listener);
+ $this->dispatcher->addListener($eventName, $listener->getWrappedListener(), $priority);
+
+ $info = $this->getListenerInfo($listener->getWrappedListener(), $eventName);
+ if ($listener->wasCalled()) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Notified event "%s" to listener "%s".', $eventName, $info['pretty']));
+ }
+
+ if (!isset($this->called[$eventName])) {
+ $this->called[$eventName] = new \SplObjectStorage();
+ }
+
+ $this->called[$eventName]->attach($listener);
+ }
+
+ if (null !== $this->logger && $skipped) {
+ $this->logger->debug(sprintf('Listener "%s" was not called for event "%s".', $info['pretty'], $eventName));
+ }
+
+ if ($listener->stoppedPropagation()) {
+ if (null !== $this->logger) {
+ $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName));
+ }
+
+ $skipped = true;
+ }
+ }
+ }
+
+ /**
+ * Returns information about the listener.
+ *
+ * @param object $listener The listener
+ * @param string $eventName The event name
+ *
+ * @return array Information about the listener
+ */
+ private function getListenerInfo($listener, $eventName)
+ {
+ $info = array(
+ 'event' => $eventName,
+ 'priority' => $this->getListenerPriority($eventName, $listener),
+ );
+
+ // unwrap for correct listener info
+ if ($listener instanceof WrappedListener) {
+ $listener = $listener->getWrappedListener();
+ }
+
+ if ($listener instanceof \Closure) {
+ $info += array(
+ 'type' => 'Closure',
+ 'pretty' => 'closure',
+ );
+ } elseif (\is_string($listener)) {
+ try {
+ $r = new \ReflectionFunction($listener);
+ $file = $r->getFileName();
+ $line = $r->getStartLine();
+ } catch (\ReflectionException $e) {
+ $file = null;
+ $line = null;
+ }
+ $info += array(
+ 'type' => 'Function',
+ 'function' => $listener,
+ 'file' => $file,
+ 'line' => $line,
+ 'pretty' => $listener,
+ );
+ } elseif (\is_array($listener) || (\is_object($listener) && \is_callable($listener))) {
+ if (!\is_array($listener)) {
+ $listener = array($listener, '__invoke');
+ }
+ $class = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0];
+ try {
+ $r = new \ReflectionMethod($class, $listener[1]);
+ $file = $r->getFileName();
+ $line = $r->getStartLine();
+ } catch (\ReflectionException $e) {
+ $file = null;
+ $line = null;
+ }
+ $info += array(
+ 'type' => 'Method',
+ 'class' => $class,
+ 'method' => $listener[1],
+ 'file' => $file,
+ 'line' => $line,
+ 'pretty' => $class.'::'.$listener[1],
+ );
+ }
+
+ return $info;
+ }
+
+ private function sortListenersByPriority($a, $b)
+ {
+ if (\is_int($a['priority']) && !\is_int($b['priority'])) {
+ return 1;
+ }
+
+ if (!\is_int($a['priority']) && \is_int($b['priority'])) {
+ return -1;
+ }
+
+ if ($a['priority'] === $b['priority']) {
+ return 0;
+ }
+
+ if ($a['priority'] > $b['priority']) {
+ return -1;
+ }
+
+ return 1;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php
new file mode 100755
index 0000000..5483e81
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Debug;
+
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+
+/**
+ * @author Fabien Potencier
+ */
+interface TraceableEventDispatcherInterface extends EventDispatcherInterface
+{
+ /**
+ * Gets the called listeners.
+ *
+ * @return array An array of called listeners
+ */
+ public function getCalledListeners();
+
+ /**
+ * Gets the not called listeners.
+ *
+ * @return array An array of not called listeners
+ */
+ public function getNotCalledListeners();
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/WrappedListener.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/WrappedListener.php
new file mode 100755
index 0000000..1552af0
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Debug/WrappedListener.php
@@ -0,0 +1,71 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Debug;
+
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\Stopwatch\Stopwatch;
+
+/**
+ * @author Fabien Potencier
+ */
+class WrappedListener
+{
+ private $listener;
+ private $name;
+ private $called;
+ private $stoppedPropagation;
+ private $stopwatch;
+ private $dispatcher;
+
+ public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null)
+ {
+ $this->listener = $listener;
+ $this->name = $name;
+ $this->stopwatch = $stopwatch;
+ $this->dispatcher = $dispatcher;
+ $this->called = false;
+ $this->stoppedPropagation = false;
+ }
+
+ public function getWrappedListener()
+ {
+ return $this->listener;
+ }
+
+ public function wasCalled()
+ {
+ return $this->called;
+ }
+
+ public function stoppedPropagation()
+ {
+ return $this->stoppedPropagation;
+ }
+
+ public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher)
+ {
+ $this->called = true;
+
+ $e = $this->stopwatch->start($this->name, 'event_listener');
+
+ \call_user_func($this->listener, $event, $eventName, $this->dispatcher ?: $dispatcher);
+
+ if ($e->isStarted()) {
+ $e->stop();
+ }
+
+ if ($event->isPropagationStopped()) {
+ $this->stoppedPropagation = true;
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php
new file mode 100755
index 0000000..5a94ae8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php
@@ -0,0 +1,100 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * Compiler pass to register tagged services for an event dispatcher.
+ */
+class RegisterListenersPass implements CompilerPassInterface
+{
+ protected $dispatcherService;
+ protected $listenerTag;
+ protected $subscriberTag;
+
+ /**
+ * @param string $dispatcherService Service name of the event dispatcher in processed container
+ * @param string $listenerTag Tag name used for listener
+ * @param string $subscriberTag Tag name used for subscribers
+ */
+ public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber')
+ {
+ $this->dispatcherService = $dispatcherService;
+ $this->listenerTag = $listenerTag;
+ $this->subscriberTag = $subscriberTag;
+ }
+
+ public function process(ContainerBuilder $container)
+ {
+ if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
+ return;
+ }
+
+ $definition = $container->findDefinition($this->dispatcherService);
+
+ foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) {
+ $def = $container->getDefinition($id);
+ if (!$def->isPublic()) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id));
+ }
+
+ if ($def->isAbstract()) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event listeners are lazy-loaded.', $id));
+ }
+
+ foreach ($events as $event) {
+ $priority = isset($event['priority']) ? $event['priority'] : 0;
+
+ if (!isset($event['event'])) {
+ throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
+ }
+
+ if (!isset($event['method'])) {
+ $event['method'] = 'on'.preg_replace_callback(array(
+ '/(?<=\b)[a-z]/i',
+ '/[^a-z0-9]/i',
+ ), function ($matches) { return strtoupper($matches[0]); }, $event['event']);
+ $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);
+ }
+
+ $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
+ }
+ }
+
+ foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) {
+ $def = $container->getDefinition($id);
+ if (!$def->isPublic()) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id));
+ }
+
+ if ($def->isAbstract()) {
+ throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event subscribers are lazy-loaded.', $id));
+ }
+
+ // We must assume that the class value has been correctly filled, even if the service is created by a factory
+ $class = $container->getParameterBag()->resolveValue($def->getClass());
+ $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
+
+ if (!is_subclass_of($class, $interface)) {
+ if (!class_exists($class, false)) {
+ throw new \InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
+ }
+
+ throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
+ }
+
+ $definition->addMethodCall('addSubscriberService', array($id, $class));
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Event.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Event.php
new file mode 100755
index 0000000..320919a
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Event.php
@@ -0,0 +1,120 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * Event is the base class for classes containing event data.
+ *
+ * This class contains no event data. It is used by events that do not pass
+ * state information to an event handler when an event is raised.
+ *
+ * You can call the method stopPropagation() to abort the execution of
+ * further listeners in your event listener.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ */
+class Event
+{
+ /**
+ * @var bool Whether no further event listeners should be triggered
+ */
+ private $propagationStopped = false;
+
+ /**
+ * @var EventDispatcherInterface Dispatcher that dispatched this event
+ */
+ private $dispatcher;
+
+ /**
+ * @var string This event's name
+ */
+ private $name;
+
+ /**
+ * Returns whether further event listeners should be triggered.
+ *
+ * @see Event::stopPropagation()
+ *
+ * @return bool Whether propagation was already stopped for this event
+ */
+ public function isPropagationStopped()
+ {
+ return $this->propagationStopped;
+ }
+
+ /**
+ * Stops the propagation of the event to further event listeners.
+ *
+ * If multiple event listeners are connected to the same event, no
+ * further event listener will be triggered once any trigger calls
+ * stopPropagation().
+ */
+ public function stopPropagation()
+ {
+ $this->propagationStopped = true;
+ }
+
+ /**
+ * Stores the EventDispatcher that dispatches this Event.
+ *
+ * @param EventDispatcherInterface $dispatcher
+ *
+ * @deprecated since version 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call.
+ */
+ public function setDispatcher(EventDispatcherInterface $dispatcher)
+ {
+ $this->dispatcher = $dispatcher;
+ }
+
+ /**
+ * Returns the EventDispatcher that dispatches this Event.
+ *
+ * @return EventDispatcherInterface
+ *
+ * @deprecated since version 2.4, to be removed in 3.0. The event dispatcher is passed to the listener call.
+ */
+ public function getDispatcher()
+ {
+ @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.4 and will be removed in 3.0. The event dispatcher instance can be received in the listener call instead.', E_USER_DEPRECATED);
+
+ return $this->dispatcher;
+ }
+
+ /**
+ * Gets the event's name.
+ *
+ * @return string
+ *
+ * @deprecated since version 2.4, to be removed in 3.0. The event name is passed to the listener call.
+ */
+ public function getName()
+ {
+ @trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.4 and will be removed in 3.0. The event name can be received in the listener call instead.', E_USER_DEPRECATED);
+
+ return $this->name;
+ }
+
+ /**
+ * Sets the event's name property.
+ *
+ * @param string $name The event name
+ *
+ * @deprecated since version 2.4, to be removed in 3.0. The event name is passed to the listener call.
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventDispatcher.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventDispatcher.php
new file mode 100755
index 0000000..b41b98e
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventDispatcher.php
@@ -0,0 +1,198 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * The EventDispatcherInterface is the central point of Symfony's event listener system.
+ *
+ * Listeners are registered on the manager and events are dispatched through the
+ * manager.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ * @author Jordan Alliot
+ */
+class EventDispatcher implements EventDispatcherInterface
+{
+ private $listeners = array();
+ private $sorted = array();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dispatch($eventName, Event $event = null)
+ {
+ if (null === $event) {
+ $event = new Event();
+ }
+
+ $event->setDispatcher($this);
+ $event->setName($eventName);
+
+ if ($listeners = $this->getListeners($eventName)) {
+ $this->doDispatch($listeners, $eventName, $event);
+ }
+
+ return $event;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListeners($eventName = null)
+ {
+ if (null !== $eventName) {
+ if (!isset($this->listeners[$eventName])) {
+ return array();
+ }
+
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+
+ return $this->sorted[$eventName];
+ }
+
+ foreach ($this->listeners as $eventName => $eventListeners) {
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+ }
+
+ return array_filter($this->sorted);
+ }
+
+ /**
+ * Gets the listener priority for a specific event.
+ *
+ * Returns null if the event or the listener does not exist.
+ *
+ * @param string $eventName The name of the event
+ * @param callable $listener The listener
+ *
+ * @return int|null The event listener priority
+ */
+ public function getListenerPriority($eventName, $listener)
+ {
+ if (!isset($this->listeners[$eventName])) {
+ return;
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ if (false !== \in_array($listener, $listeners, true)) {
+ return $priority;
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasListeners($eventName = null)
+ {
+ return (bool) $this->getListeners($eventName);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addListener($eventName, $listener, $priority = 0)
+ {
+ $this->listeners[$eventName][$priority][] = $listener;
+ unset($this->sorted[$eventName]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeListener($eventName, $listener)
+ {
+ if (!isset($this->listeners[$eventName])) {
+ return;
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ if (false !== ($key = array_search($listener, $listeners, true))) {
+ unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (\is_string($params)) {
+ $this->addListener($eventName, array($subscriber, $params));
+ } elseif (\is_string($params[0])) {
+ $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
+ } else {
+ foreach ($params as $listener) {
+ $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeSubscriber(EventSubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (\is_array($params) && \is_array($params[0])) {
+ foreach ($params as $listener) {
+ $this->removeListener($eventName, array($subscriber, $listener[0]));
+ }
+ } else {
+ $this->removeListener($eventName, array($subscriber, \is_string($params) ? $params : $params[0]));
+ }
+ }
+ }
+
+ /**
+ * Triggers the listeners of an event.
+ *
+ * This method can be overridden to add functionality that is executed
+ * for each listener.
+ *
+ * @param callable[] $listeners The event listeners
+ * @param string $eventName The name of the event to dispatch
+ * @param Event $event The event object to pass to the event handlers/listeners
+ */
+ protected function doDispatch($listeners, $eventName, Event $event)
+ {
+ foreach ($listeners as $listener) {
+ if ($event->isPropagationStopped()) {
+ break;
+ }
+ \call_user_func($listener, $event, $eventName, $this);
+ }
+ }
+
+ /**
+ * Sorts the internal list of listeners for the given event by priority.
+ *
+ * @param string $eventName The name of the event
+ */
+ private function sortListeners($eventName)
+ {
+ krsort($this->listeners[$eventName]);
+ $this->sorted[$eventName] = \call_user_func_array('array_merge', $this->listeners[$eventName]);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventDispatcherInterface.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
new file mode 100755
index 0000000..60160a9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * The EventDispatcherInterface is the central point of Symfony's event listener system.
+ * Listeners are registered on the manager and events are dispatched through the
+ * manager.
+ *
+ * @author Bernhard Schussek
+ */
+interface EventDispatcherInterface
+{
+ /**
+ * Dispatches an event to all registered listeners.
+ *
+ * @param string $eventName The name of the event to dispatch. The name of
+ * the event is the name of the method that is
+ * invoked on listeners.
+ * @param Event $event The event to pass to the event handlers/listeners
+ * If not supplied, an empty Event instance is created
+ *
+ * @return Event
+ */
+ public function dispatch($eventName, Event $event = null);
+
+ /**
+ * Adds an event listener that listens on the specified events.
+ *
+ * @param string $eventName The event to listen on
+ * @param callable $listener The listener
+ * @param int $priority The higher this value, the earlier an event
+ * listener will be triggered in the chain (defaults to 0)
+ */
+ public function addListener($eventName, $listener, $priority = 0);
+
+ /**
+ * Adds an event subscriber.
+ *
+ * The subscriber is asked for all the events he is
+ * interested in and added as a listener for these events.
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber);
+
+ /**
+ * Removes an event listener from the specified events.
+ *
+ * @param string $eventName The event to remove a listener from
+ * @param callable $listener The listener to remove
+ */
+ public function removeListener($eventName, $listener);
+
+ public function removeSubscriber(EventSubscriberInterface $subscriber);
+
+ /**
+ * Gets the listeners of a specific event or all listeners sorted by descending priority.
+ *
+ * @param string $eventName The name of the event
+ *
+ * @return array The event listeners for the specified event, or all event listeners by event name
+ */
+ public function getListeners($eventName = null);
+
+ /**
+ * Checks whether an event has any registered listeners.
+ *
+ * @param string $eventName The name of the event
+ *
+ * @return bool true if the specified event has any listeners, false otherwise
+ */
+ public function hasListeners($eventName = null);
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventSubscriberInterface.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventSubscriberInterface.php
new file mode 100755
index 0000000..8af7789
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/EventSubscriberInterface.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * An EventSubscriber knows himself what events he is interested in.
+ * If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
+ * {@link getSubscribedEvents} and registers the subscriber as a listener for all
+ * returned events.
+ *
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ * @author Bernhard Schussek
+ */
+interface EventSubscriberInterface
+{
+ /**
+ * Returns an array of event names this subscriber wants to listen to.
+ *
+ * The array keys are event names and the value can be:
+ *
+ * * The method name to call (priority defaults to 0)
+ * * An array composed of the method name to call and the priority
+ * * An array of arrays composed of the method names to call and respective
+ * priorities, or 0 if unset
+ *
+ * For instance:
+ *
+ * * array('eventName' => 'methodName')
+ * * array('eventName' => array('methodName', $priority))
+ * * array('eventName' => array(array('methodName1', $priority), array('methodName2')))
+ *
+ * @return array The event names to listen to
+ */
+ public static function getSubscribedEvents();
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/GenericEvent.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/GenericEvent.php
new file mode 100755
index 0000000..f0be7e1
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/GenericEvent.php
@@ -0,0 +1,175 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * Event encapsulation class.
+ *
+ * Encapsulates events thus decoupling the observer from the subject they encapsulate.
+ *
+ * @author Drak
+ */
+class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate
+{
+ protected $subject;
+ protected $arguments;
+
+ /**
+ * Encapsulate an event with $subject and $args.
+ *
+ * @param mixed $subject The subject of the event, usually an object or a callable
+ * @param array $arguments Arguments to store in the event
+ */
+ public function __construct($subject = null, array $arguments = array())
+ {
+ $this->subject = $subject;
+ $this->arguments = $arguments;
+ }
+
+ /**
+ * Getter for subject property.
+ *
+ * @return mixed The observer subject
+ */
+ public function getSubject()
+ {
+ return $this->subject;
+ }
+
+ /**
+ * Get argument by key.
+ *
+ * @param string $key Key
+ *
+ * @return mixed Contents of array key
+ *
+ * @throws \InvalidArgumentException if key is not found
+ */
+ public function getArgument($key)
+ {
+ if ($this->hasArgument($key)) {
+ return $this->arguments[$key];
+ }
+
+ throw new \InvalidArgumentException(sprintf('Argument "%s" not found.', $key));
+ }
+
+ /**
+ * Add argument to event.
+ *
+ * @param string $key Argument name
+ * @param mixed $value Value
+ *
+ * @return $this
+ */
+ public function setArgument($key, $value)
+ {
+ $this->arguments[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Getter for all arguments.
+ *
+ * @return array
+ */
+ public function getArguments()
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * Set args property.
+ *
+ * @param array $args Arguments
+ *
+ * @return $this
+ */
+ public function setArguments(array $args = array())
+ {
+ $this->arguments = $args;
+
+ return $this;
+ }
+
+ /**
+ * Has argument.
+ *
+ * @param string $key Key of arguments array
+ *
+ * @return bool
+ */
+ public function hasArgument($key)
+ {
+ return array_key_exists($key, $this->arguments);
+ }
+
+ /**
+ * ArrayAccess for argument getter.
+ *
+ * @param string $key Array key
+ *
+ * @return mixed
+ *
+ * @throws \InvalidArgumentException if key does not exist in $this->args
+ */
+ public function offsetGet($key)
+ {
+ return $this->getArgument($key);
+ }
+
+ /**
+ * ArrayAccess for argument setter.
+ *
+ * @param string $key Array key to set
+ * @param mixed $value Value
+ */
+ public function offsetSet($key, $value)
+ {
+ $this->setArgument($key, $value);
+ }
+
+ /**
+ * ArrayAccess for unset argument.
+ *
+ * @param string $key Array key
+ */
+ public function offsetUnset($key)
+ {
+ if ($this->hasArgument($key)) {
+ unset($this->arguments[$key]);
+ }
+ }
+
+ /**
+ * ArrayAccess has argument.
+ *
+ * @param string $key Array key
+ *
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ return $this->hasArgument($key);
+ }
+
+ /**
+ * IteratorAggregate for iterating over the object like an array.
+ *
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->arguments);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php
new file mode 100755
index 0000000..b3cf56c
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php
@@ -0,0 +1,91 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * A read-only proxy for an event dispatcher.
+ *
+ * @author Bernhard Schussek
+ */
+class ImmutableEventDispatcher implements EventDispatcherInterface
+{
+ private $dispatcher;
+
+ public function __construct(EventDispatcherInterface $dispatcher)
+ {
+ $this->dispatcher = $dispatcher;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dispatch($eventName, Event $event = null)
+ {
+ return $this->dispatcher->dispatch($eventName, $event);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addListener($eventName, $listener, $priority = 0)
+ {
+ throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeListener($eventName, $listener)
+ {
+ throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeSubscriber(EventSubscriberInterface $subscriber)
+ {
+ throw new \BadMethodCallException('Unmodifiable event dispatchers must not be modified.');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListeners($eventName = null)
+ {
+ return $this->dispatcher->getListeners($eventName);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListenerPriority($eventName, $listener)
+ {
+ return $this->dispatcher->getListenerPriority($eventName, $listener);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasListeners($eventName = null)
+ {
+ return $this->dispatcher->hasListeners($eventName);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/LICENSE b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/LICENSE
new file mode 100755
index 0000000..21d7fb9
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2018 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/README.md b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/README.md
new file mode 100755
index 0000000..185c3fe
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/README.md
@@ -0,0 +1,15 @@
+EventDispatcher Component
+=========================
+
+The EventDispatcher component provides tools that allow your application
+components to communicate with each other by dispatching events and listening to
+them.
+
+Resources
+---------
+
+ * [Documentation](https://symfony.com/doc/current/components/event_dispatcher/index.html)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php
new file mode 100755
index 0000000..48de632
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php
@@ -0,0 +1,398 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+abstract class AbstractEventDispatcherTest extends TestCase
+{
+ /* Some pseudo events */
+ const preFoo = 'pre.foo';
+ const postFoo = 'post.foo';
+ const preBar = 'pre.bar';
+ const postBar = 'post.bar';
+
+ /**
+ * @var EventDispatcher
+ */
+ private $dispatcher;
+
+ private $listener;
+
+ protected function setUp()
+ {
+ $this->dispatcher = $this->createEventDispatcher();
+ $this->listener = new TestEventListener();
+ }
+
+ protected function tearDown()
+ {
+ $this->dispatcher = null;
+ $this->listener = null;
+ }
+
+ abstract protected function createEventDispatcher();
+
+ public function testInitialState()
+ {
+ $this->assertEquals(array(), $this->dispatcher->getListeners());
+ $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
+ }
+
+ public function testAddListener()
+ {
+ $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));
+ $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'));
+ $this->assertTrue($this->dispatcher->hasListeners());
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
+ $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo));
+ $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo));
+ $this->assertCount(2, $this->dispatcher->getListeners());
+ }
+
+ public function testGetListenersSortsByPriority()
+ {
+ $listener1 = new TestEventListener();
+ $listener2 = new TestEventListener();
+ $listener3 = new TestEventListener();
+ $listener1->name = '1';
+ $listener2->name = '2';
+ $listener3->name = '3';
+
+ $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10);
+ $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10);
+ $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo'));
+
+ $expected = array(
+ array($listener2, 'preFoo'),
+ array($listener3, 'preFoo'),
+ array($listener1, 'preFoo'),
+ );
+
+ $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo'));
+ }
+
+ public function testGetAllListenersSortsByPriority()
+ {
+ $listener1 = new TestEventListener();
+ $listener2 = new TestEventListener();
+ $listener3 = new TestEventListener();
+ $listener4 = new TestEventListener();
+ $listener5 = new TestEventListener();
+ $listener6 = new TestEventListener();
+
+ $this->dispatcher->addListener('pre.foo', $listener1, -10);
+ $this->dispatcher->addListener('pre.foo', $listener2);
+ $this->dispatcher->addListener('pre.foo', $listener3, 10);
+ $this->dispatcher->addListener('post.foo', $listener4, -10);
+ $this->dispatcher->addListener('post.foo', $listener5);
+ $this->dispatcher->addListener('post.foo', $listener6, 10);
+
+ $expected = array(
+ 'pre.foo' => array($listener3, $listener2, $listener1),
+ 'post.foo' => array($listener6, $listener5, $listener4),
+ );
+
+ $this->assertSame($expected, $this->dispatcher->getListeners());
+ }
+
+ public function testGetListenerPriority()
+ {
+ $listener1 = new TestEventListener();
+ $listener2 = new TestEventListener();
+
+ $this->dispatcher->addListener('pre.foo', $listener1, -10);
+ $this->dispatcher->addListener('pre.foo', $listener2);
+
+ $this->assertSame(-10, $this->dispatcher->getListenerPriority('pre.foo', $listener1));
+ $this->assertSame(0, $this->dispatcher->getListenerPriority('pre.foo', $listener2));
+ $this->assertNull($this->dispatcher->getListenerPriority('pre.bar', $listener2));
+ $this->assertNull($this->dispatcher->getListenerPriority('pre.foo', function () {}));
+ }
+
+ public function testDispatch()
+ {
+ $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo'));
+ $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'));
+ $this->dispatcher->dispatch(self::preFoo);
+ $this->assertTrue($this->listener->preFooInvoked);
+ $this->assertFalse($this->listener->postFooInvoked);
+ $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent'));
+ $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo));
+ $event = new Event();
+ $return = $this->dispatcher->dispatch(self::preFoo, $event);
+ $this->assertSame($event, $return);
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testLegacyDispatch()
+ {
+ $event = new Event();
+ $this->dispatcher->dispatch(self::preFoo, $event);
+ $this->assertEquals('pre.foo', $event->getName());
+ }
+
+ public function testDispatchForClosure()
+ {
+ $invoked = 0;
+ $listener = function () use (&$invoked) {
+ ++$invoked;
+ };
+ $this->dispatcher->addListener('pre.foo', $listener);
+ $this->dispatcher->addListener('post.foo', $listener);
+ $this->dispatcher->dispatch(self::preFoo);
+ $this->assertEquals(1, $invoked);
+ }
+
+ public function testStopEventPropagation()
+ {
+ $otherListener = new TestEventListener();
+
+ // postFoo() stops the propagation, so only one listener should
+ // be executed
+ // Manually set priority to enforce $this->listener to be called first
+ $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10);
+ $this->dispatcher->addListener('post.foo', array($otherListener, 'postFoo'));
+ $this->dispatcher->dispatch(self::postFoo);
+ $this->assertTrue($this->listener->postFooInvoked);
+ $this->assertFalse($otherListener->postFooInvoked);
+ }
+
+ public function testDispatchByPriority()
+ {
+ $invoked = array();
+ $listener1 = function () use (&$invoked) {
+ $invoked[] = '1';
+ };
+ $listener2 = function () use (&$invoked) {
+ $invoked[] = '2';
+ };
+ $listener3 = function () use (&$invoked) {
+ $invoked[] = '3';
+ };
+ $this->dispatcher->addListener('pre.foo', $listener1, -10);
+ $this->dispatcher->addListener('pre.foo', $listener2);
+ $this->dispatcher->addListener('pre.foo', $listener3, 10);
+ $this->dispatcher->dispatch(self::preFoo);
+ $this->assertEquals(array('3', '2', '1'), $invoked);
+ }
+
+ public function testRemoveListener()
+ {
+ $this->dispatcher->addListener('pre.bar', $this->listener);
+ $this->assertTrue($this->dispatcher->hasListeners(self::preBar));
+ $this->dispatcher->removeListener('pre.bar', $this->listener);
+ $this->assertFalse($this->dispatcher->hasListeners(self::preBar));
+ $this->dispatcher->removeListener('notExists', $this->listener);
+ }
+
+ public function testAddSubscriber()
+ {
+ $eventSubscriber = new TestEventSubscriber();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
+ }
+
+ public function testAddSubscriberWithPriorities()
+ {
+ $eventSubscriber = new TestEventSubscriber();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+
+ $eventSubscriber = new TestEventSubscriberWithPriorities();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+
+ $listeners = $this->dispatcher->getListeners('pre.foo');
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertCount(2, $listeners);
+ $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]);
+ }
+
+ public function testAddSubscriberWithMultipleListeners()
+ {
+ $eventSubscriber = new TestEventSubscriberWithMultipleListeners();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+
+ $listeners = $this->dispatcher->getListeners('pre.foo');
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertCount(2, $listeners);
+ $this->assertEquals('preFoo2', $listeners[0][1]);
+ }
+
+ public function testRemoveSubscriber()
+ {
+ $eventSubscriber = new TestEventSubscriber();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
+ $this->dispatcher->removeSubscriber($eventSubscriber);
+ $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
+ }
+
+ public function testRemoveSubscriberWithPriorities()
+ {
+ $eventSubscriber = new TestEventSubscriberWithPriorities();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->dispatcher->removeSubscriber($eventSubscriber);
+ $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
+ }
+
+ public function testRemoveSubscriberWithMultipleListeners()
+ {
+ $eventSubscriber = new TestEventSubscriberWithMultipleListeners();
+ $this->dispatcher->addSubscriber($eventSubscriber);
+ $this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
+ $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo));
+ $this->dispatcher->removeSubscriber($eventSubscriber);
+ $this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testLegacyEventReceivesTheDispatcherInstance()
+ {
+ $dispatcher = null;
+ $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) {
+ $dispatcher = $event->getDispatcher();
+ });
+ $this->dispatcher->dispatch('test');
+ $this->assertSame($this->dispatcher, $dispatcher);
+ }
+
+ public function testEventReceivesTheDispatcherInstanceAsArgument()
+ {
+ $listener = new TestWithDispatcher();
+ $this->dispatcher->addListener('test', array($listener, 'foo'));
+ $this->assertNull($listener->name);
+ $this->assertNull($listener->dispatcher);
+ $this->dispatcher->dispatch('test');
+ $this->assertEquals('test', $listener->name);
+ $this->assertSame($this->dispatcher, $listener->dispatcher);
+ }
+
+ /**
+ * @see https://bugs.php.net/bug.php?id=62976
+ *
+ * This bug affects:
+ * - The PHP 5.3 branch for versions < 5.3.18
+ * - The PHP 5.4 branch for versions < 5.4.8
+ * - The PHP 5.5 branch is not affected
+ */
+ public function testWorkaroundForPhpBug62976()
+ {
+ $dispatcher = $this->createEventDispatcher();
+ $dispatcher->addListener('bug.62976', new CallableClass());
+ $dispatcher->removeListener('bug.62976', function () {});
+ $this->assertTrue($dispatcher->hasListeners('bug.62976'));
+ }
+
+ public function testHasListenersWhenAddedCallbackListenerIsRemoved()
+ {
+ $listener = function () {};
+ $this->dispatcher->addListener('foo', $listener);
+ $this->dispatcher->removeListener('foo', $listener);
+ $this->assertFalse($this->dispatcher->hasListeners());
+ }
+
+ public function testGetListenersWhenAddedCallbackListenerIsRemoved()
+ {
+ $listener = function () {};
+ $this->dispatcher->addListener('foo', $listener);
+ $this->dispatcher->removeListener('foo', $listener);
+ $this->assertSame(array(), $this->dispatcher->getListeners());
+ }
+
+ public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled()
+ {
+ $this->assertFalse($this->dispatcher->hasListeners('foo'));
+ $this->assertFalse($this->dispatcher->hasListeners());
+ }
+}
+
+class CallableClass
+{
+ public function __invoke()
+ {
+ }
+}
+
+class TestEventListener
+{
+ public $preFooInvoked = false;
+ public $postFooInvoked = false;
+
+ /* Listener methods */
+
+ public function preFoo(Event $e)
+ {
+ $this->preFooInvoked = true;
+ }
+
+ public function postFoo(Event $e)
+ {
+ $this->postFooInvoked = true;
+
+ $e->stopPropagation();
+ }
+}
+
+class TestWithDispatcher
+{
+ public $name;
+ public $dispatcher;
+
+ public function foo(Event $e, $name, $dispatcher)
+ {
+ $this->name = $name;
+ $this->dispatcher = $dispatcher;
+ }
+}
+
+class TestEventSubscriber implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo');
+ }
+}
+
+class TestEventSubscriberWithPriorities implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'pre.foo' => array('preFoo', 10),
+ 'post.foo' => array('postFoo'),
+ );
+ }
+}
+
+class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array('pre.foo' => array(
+ array('preFoo1'),
+ array('preFoo2', 10),
+ ));
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php
new file mode 100755
index 0000000..224a292
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php
@@ -0,0 +1,277 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests;
+
+use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\DependencyInjection\Scope;
+use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest
+{
+ protected function createEventDispatcher()
+ {
+ $container = new Container();
+
+ return new ContainerAwareEventDispatcher($container);
+ }
+
+ public function testAddAListenerService()
+ {
+ $event = new Event();
+
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $service
+ ->expects($this->once())
+ ->method('onEvent')
+ ->with($event)
+ ;
+
+ $container = new Container();
+ $container->set('service.listener', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+
+ $dispatcher->dispatch('onEvent', $event);
+ }
+
+ public function testAddASubscriberService()
+ {
+ $event = new Event();
+
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\SubscriberService')->getMock();
+
+ $service
+ ->expects($this->once())
+ ->method('onEvent')
+ ->with($event)
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('onEventWithPriority')
+ ->with($event)
+ ;
+
+ $service
+ ->expects($this->once())
+ ->method('onEventNested')
+ ->with($event)
+ ;
+
+ $container = new Container();
+ $container->set('service.subscriber', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService');
+
+ $dispatcher->dispatch('onEvent', $event);
+ $dispatcher->dispatch('onEventWithPriority', $event);
+ $dispatcher->dispatch('onEventNested', $event);
+ }
+
+ public function testPreventDuplicateListenerService()
+ {
+ $event = new Event();
+
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $service
+ ->expects($this->once())
+ ->method('onEvent')
+ ->with($event)
+ ;
+
+ $container = new Container();
+ $container->set('service.listener', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10);
+
+ $dispatcher->dispatch('onEvent', $event);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @group legacy
+ */
+ public function testTriggerAListenerServiceOutOfScope()
+ {
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $scope = new Scope('scope');
+ $container = new Container();
+ $container->addScope($scope);
+ $container->enterScope('scope');
+
+ $container->set('service.listener', $service, 'scope');
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+
+ $container->leaveScope('scope');
+ $dispatcher->dispatch('onEvent');
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testReEnteringAScope()
+ {
+ $event = new Event();
+
+ $service1 = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $service1
+ ->expects($this->exactly(2))
+ ->method('onEvent')
+ ->with($event)
+ ;
+
+ $scope = new Scope('scope');
+ $container = new Container();
+ $container->addScope($scope);
+ $container->enterScope('scope');
+
+ $container->set('service.listener', $service1, 'scope');
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+ $dispatcher->dispatch('onEvent', $event);
+
+ $service2 = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $service2
+ ->expects($this->once())
+ ->method('onEvent')
+ ->with($event)
+ ;
+
+ $container->enterScope('scope');
+ $container->set('service.listener', $service2, 'scope');
+
+ $dispatcher->dispatch('onEvent', $event);
+
+ $container->leaveScope('scope');
+
+ $dispatcher->dispatch('onEvent');
+ }
+
+ public function testHasListenersOnLazyLoad()
+ {
+ $event = new Event();
+
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $container = new Container();
+ $container->set('service.listener', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+
+ $event->setDispatcher($dispatcher);
+ $event->setName('onEvent');
+
+ $service
+ ->expects($this->once())
+ ->method('onEvent')
+ ->with($event)
+ ;
+
+ $this->assertTrue($dispatcher->hasListeners());
+
+ if ($dispatcher->hasListeners('onEvent')) {
+ $dispatcher->dispatch('onEvent');
+ }
+ }
+
+ public function testGetListenersOnLazyLoad()
+ {
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $container = new Container();
+ $container->set('service.listener', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+
+ $listeners = $dispatcher->getListeners();
+
+ $this->assertArrayHasKey('onEvent', $listeners);
+
+ $this->assertCount(1, $dispatcher->getListeners('onEvent'));
+ }
+
+ public function testRemoveAfterDispatch()
+ {
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $container = new Container();
+ $container->set('service.listener', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+
+ $dispatcher->dispatch('onEvent', new Event());
+ $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent'));
+ $this->assertFalse($dispatcher->hasListeners('onEvent'));
+ }
+
+ public function testRemoveBeforeDispatch()
+ {
+ $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock();
+
+ $container = new Container();
+ $container->set('service.listener', $service);
+
+ $dispatcher = new ContainerAwareEventDispatcher($container);
+ $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'));
+
+ $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent'));
+ $this->assertFalse($dispatcher->hasListeners('onEvent'));
+ }
+}
+
+class Service
+{
+ public function onEvent(Event $e)
+ {
+ }
+}
+
+class SubscriberService implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array(
+ 'onEvent' => 'onEvent',
+ 'onEventWithPriority' => array('onEventWithPriority', 10),
+ 'onEventNested' => array(array('onEventNested')),
+ );
+ }
+
+ public function onEvent(Event $e)
+ {
+ }
+
+ public function onEventWithPriority(Event $e)
+ {
+ }
+
+ public function onEventNested(Event $e)
+ {
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php
new file mode 100755
index 0000000..ffdda38
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php
@@ -0,0 +1,254 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests\Debug;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher;
+use Symfony\Component\EventDispatcher\Debug\WrappedListener;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\Stopwatch\Stopwatch;
+
+class TraceableEventDispatcherTest extends TestCase
+{
+ public function testAddRemoveListener()
+ {
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+
+ $tdispatcher->addListener('foo', $listener = function () {});
+ $listeners = $dispatcher->getListeners('foo');
+ $this->assertCount(1, $listeners);
+ $this->assertSame($listener, $listeners[0]);
+
+ $tdispatcher->removeListener('foo', $listener);
+ $this->assertCount(0, $dispatcher->getListeners('foo'));
+ }
+
+ public function testGetListeners()
+ {
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+
+ $tdispatcher->addListener('foo', $listener = function () {});
+ $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo'));
+ }
+
+ public function testHasListeners()
+ {
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+
+ $this->assertFalse($dispatcher->hasListeners('foo'));
+ $this->assertFalse($tdispatcher->hasListeners('foo'));
+
+ $tdispatcher->addListener('foo', $listener = function () {});
+ $this->assertTrue($dispatcher->hasListeners('foo'));
+ $this->assertTrue($tdispatcher->hasListeners('foo'));
+ }
+
+ public function testGetListenerPriority()
+ {
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+
+ $tdispatcher->addListener('foo', function () {}, 123);
+
+ $listeners = $dispatcher->getListeners('foo');
+ $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
+
+ // Verify that priority is preserved when listener is removed and re-added
+ // in preProcess() and postProcess().
+ $tdispatcher->dispatch('foo', new Event());
+ $listeners = $dispatcher->getListeners('foo');
+ $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0]));
+ }
+
+ public function testGetListenerPriorityReturnsZeroWhenWrappedMethodDoesNotExist()
+ {
+ $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
+ $traceableEventDispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+ $traceableEventDispatcher->addListener('foo', function () {}, 123);
+ $listeners = $traceableEventDispatcher->getListeners('foo');
+
+ $this->assertSame(0, $traceableEventDispatcher->getListenerPriority('foo', $listeners[0]));
+ }
+
+ public function testAddRemoveSubscriber()
+ {
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+
+ $subscriber = new EventSubscriber();
+
+ $tdispatcher->addSubscriber($subscriber);
+ $listeners = $dispatcher->getListeners('foo');
+ $this->assertCount(1, $listeners);
+ $this->assertSame(array($subscriber, 'call'), $listeners[0]);
+
+ $tdispatcher->removeSubscriber($subscriber);
+ $this->assertCount(0, $dispatcher->getListeners('foo'));
+ }
+
+ /**
+ * @dataProvider isWrappedDataProvider
+ *
+ * @param bool $isWrapped
+ */
+ public function testGetCalledListeners($isWrapped)
+ {
+ $dispatcher = new EventDispatcher();
+ $stopWatch = new Stopwatch();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, $stopWatch);
+
+ $listener = function () {};
+ if ($isWrapped) {
+ $listener = new WrappedListener($listener, 'foo', $stopWatch, $dispatcher);
+ }
+
+ $tdispatcher->addListener('foo', $listener, 5);
+
+ $this->assertEquals(array(), $tdispatcher->getCalledListeners());
+ $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => 5)), $tdispatcher->getNotCalledListeners());
+
+ $tdispatcher->dispatch('foo');
+
+ $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure', 'priority' => 5)), $tdispatcher->getCalledListeners());
+ $this->assertEquals(array(), $tdispatcher->getNotCalledListeners());
+ }
+
+ public function isWrappedDataProvider()
+ {
+ return array(
+ array(false),
+ array(true),
+ );
+ }
+
+ public function testGetCalledListenersNested()
+ {
+ $tdispatcher = null;
+ $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) {
+ $tdispatcher = $dispatcher;
+ $dispatcher->dispatch('bar');
+ });
+ $dispatcher->addListener('bar', function (Event $event) {});
+ $dispatcher->dispatch('foo');
+ $this->assertSame($dispatcher, $tdispatcher);
+ $this->assertCount(2, $dispatcher->getCalledListeners());
+ }
+
+ public function testLogger()
+ {
+ $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
+
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
+ $tdispatcher->addListener('foo', $listener1 = function () {});
+ $tdispatcher->addListener('foo', $listener2 = function () {});
+
+ $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".');
+ $logger->expects($this->at(1))->method('debug')->with('Notified event "foo" to listener "closure".');
+
+ $tdispatcher->dispatch('foo');
+ }
+
+ public function testLoggerWithStoppedEvent()
+ {
+ $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
+
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger);
+ $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); });
+ $tdispatcher->addListener('foo', $listener2 = function () {});
+
+ $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".');
+ $logger->expects($this->at(1))->method('debug')->with('Listener "closure" stopped propagation of the event "foo".');
+ $logger->expects($this->at(2))->method('debug')->with('Listener "closure" was not called for event "foo".');
+
+ $tdispatcher->dispatch('foo');
+ }
+
+ public function testDispatchCallListeners()
+ {
+ $called = array();
+
+ $dispatcher = new EventDispatcher();
+ $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch());
+ $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10);
+ $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20);
+
+ $tdispatcher->dispatch('foo');
+
+ $this->assertSame(array('foo2', 'foo1'), $called);
+ }
+
+ public function testDispatchNested()
+ {
+ $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $loop = 1;
+ $dispatchedEvents = 0;
+ $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) {
+ ++$loop;
+ if (2 == $loop) {
+ $dispatcher->dispatch('foo');
+ }
+ });
+ $dispatcher->addListener('foo', function () use (&$dispatchedEvents) {
+ ++$dispatchedEvents;
+ });
+
+ $dispatcher->dispatch('foo');
+
+ $this->assertSame(2, $dispatchedEvents);
+ }
+
+ public function testDispatchReusedEventNested()
+ {
+ $nestedCall = false;
+ $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) {
+ $dispatcher->dispatch('bar', $e);
+ });
+ $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) {
+ $nestedCall = true;
+ });
+
+ $this->assertFalse($nestedCall);
+ $dispatcher->dispatch('foo');
+ $this->assertTrue($nestedCall);
+ }
+
+ public function testListenerCanRemoveItselfWhenExecuted()
+ {
+ $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) {
+ $dispatcher->removeListener('foo', $listener1);
+ };
+ $eventDispatcher->addListener('foo', $listener1);
+ $eventDispatcher->addListener('foo', function () {});
+ $eventDispatcher->dispatch('foo');
+
+ $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
+ }
+}
+
+class EventSubscriber implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array('foo' => 'call');
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php
new file mode 100755
index 0000000..7490d0d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php
@@ -0,0 +1,154 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
+
+class RegisterListenersPassTest extends TestCase
+{
+ /**
+ * Tests that event subscribers not implementing EventSubscriberInterface
+ * trigger an exception.
+ *
+ * @expectedException \InvalidArgumentException
+ */
+ public function testEventSubscriberWithoutInterface()
+ {
+ $builder = new ContainerBuilder();
+ $builder->register('event_dispatcher');
+ $builder->register('my_event_subscriber', 'stdClass')
+ ->addTag('kernel.event_subscriber');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($builder);
+ }
+
+ public function testValidEventSubscriber()
+ {
+ $services = array(
+ 'my_event_subscriber' => array(0 => array()),
+ );
+
+ $builder = new ContainerBuilder();
+ $eventDispatcherDefinition = $builder->register('event_dispatcher');
+ $builder->register('my_event_subscriber', 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService')
+ ->addTag('kernel.event_subscriber');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($builder);
+
+ $this->assertEquals(array(array('addSubscriberService', array('my_event_subscriber', 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService'))), $eventDispatcherDefinition->getMethodCalls());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The service "foo" must be public as event listeners are lazy-loaded.
+ */
+ public function testPrivateEventListener()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_listener', array());
+ $container->register('event_dispatcher', 'stdClass');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($container);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The service "foo" must be public as event subscribers are lazy-loaded.
+ */
+ public function testPrivateEventSubscriber()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_subscriber', array());
+ $container->register('event_dispatcher', 'stdClass');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($container);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The service "foo" must not be abstract as event listeners are lazy-loaded.
+ */
+ public function testAbstractEventListener()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_listener', array());
+ $container->register('event_dispatcher', 'stdClass');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($container);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The service "foo" must not be abstract as event subscribers are lazy-loaded.
+ */
+ public function testAbstractEventSubscriber()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_subscriber', array());
+ $container->register('event_dispatcher', 'stdClass');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($container);
+ }
+
+ public function testEventSubscriberResolvableClassName()
+ {
+ $container = new ContainerBuilder();
+
+ $container->setParameter('subscriber.class', 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService');
+ $container->register('foo', '%subscriber.class%')->addTag('kernel.event_subscriber', array());
+ $container->register('event_dispatcher', 'stdClass');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($container);
+
+ $definition = $container->getDefinition('event_dispatcher');
+ $expected_calls = array(
+ array(
+ 'addSubscriberService',
+ array(
+ 'foo',
+ 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService',
+ ),
+ ),
+ );
+ $this->assertSame($expected_calls, $definition->getMethodCalls());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage You have requested a non-existent parameter "subscriber.class"
+ */
+ public function testEventSubscriberUnresolvableClassName()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', '%subscriber.class%')->addTag('kernel.event_subscriber', array());
+ $container->register('event_dispatcher', 'stdClass');
+
+ $registerListenersPass = new RegisterListenersPass();
+ $registerListenersPass->process($container);
+ }
+}
+
+class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php
new file mode 100755
index 0000000..5faa5c8
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests;
+
+use Symfony\Component\EventDispatcher\EventDispatcher;
+
+class EventDispatcherTest extends AbstractEventDispatcherTest
+{
+ protected function createEventDispatcher()
+ {
+ return new EventDispatcher();
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/EventTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/EventTest.php
new file mode 100755
index 0000000..bdc14ab
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/EventTest.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+
+/**
+ * Test class for Event.
+ */
+class EventTest extends TestCase
+{
+ /**
+ * @var \Symfony\Component\EventDispatcher\Event
+ */
+ protected $event;
+
+ /**
+ * @var \Symfony\Component\EventDispatcher\EventDispatcher
+ */
+ protected $dispatcher;
+
+ /**
+ * Sets up the fixture, for example, opens a network connection.
+ * This method is called before a test is executed.
+ */
+ protected function setUp()
+ {
+ $this->event = new Event();
+ $this->dispatcher = new EventDispatcher();
+ }
+
+ /**
+ * Tears down the fixture, for example, closes a network connection.
+ * This method is called after a test is executed.
+ */
+ protected function tearDown()
+ {
+ $this->event = null;
+ $this->dispatcher = null;
+ }
+
+ public function testIsPropagationStopped()
+ {
+ $this->assertFalse($this->event->isPropagationStopped());
+ }
+
+ public function testStopPropagationAndIsPropagationStopped()
+ {
+ $this->event->stopPropagation();
+ $this->assertTrue($this->event->isPropagationStopped());
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testLegacySetDispatcher()
+ {
+ $this->event->setDispatcher($this->dispatcher);
+ $this->assertSame($this->dispatcher, $this->event->getDispatcher());
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testLegacyGetDispatcher()
+ {
+ $this->assertNull($this->event->getDispatcher());
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testLegacyGetName()
+ {
+ $this->assertNull($this->event->getName());
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testLegacySetName()
+ {
+ $this->event->setName('foo');
+ $this->assertEquals('foo', $this->event->getName());
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php
new file mode 100755
index 0000000..b63f69d
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php
@@ -0,0 +1,136 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+/**
+ * Test class for Event.
+ */
+class GenericEventTest extends TestCase
+{
+ /**
+ * @var GenericEvent
+ */
+ private $event;
+
+ private $subject;
+
+ /**
+ * Prepares the environment before running a test.
+ */
+ protected function setUp()
+ {
+ $this->subject = new \stdClass();
+ $this->event = new GenericEvent($this->subject, array('name' => 'Event'));
+ }
+
+ /**
+ * Cleans up the environment after running a test.
+ */
+ protected function tearDown()
+ {
+ $this->subject = null;
+ $this->event = null;
+ }
+
+ public function testConstruct()
+ {
+ $this->assertEquals($this->event, new GenericEvent($this->subject, array('name' => 'Event')));
+ }
+
+ /**
+ * Tests Event->getArgs().
+ */
+ public function testGetArguments()
+ {
+ // test getting all
+ $this->assertSame(array('name' => 'Event'), $this->event->getArguments());
+ }
+
+ public function testSetArguments()
+ {
+ $result = $this->event->setArguments(array('foo' => 'bar'));
+ $this->assertAttributeSame(array('foo' => 'bar'), 'arguments', $this->event);
+ $this->assertSame($this->event, $result);
+ }
+
+ public function testSetArgument()
+ {
+ $result = $this->event->setArgument('foo2', 'bar2');
+ $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event);
+ $this->assertEquals($this->event, $result);
+ }
+
+ public function testGetArgument()
+ {
+ // test getting key
+ $this->assertEquals('Event', $this->event->getArgument('name'));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testGetArgException()
+ {
+ $this->event->getArgument('nameNotExist');
+ }
+
+ public function testOffsetGet()
+ {
+ // test getting key
+ $this->assertEquals('Event', $this->event['name']);
+
+ // test getting invalid arg
+ $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException');
+ $this->assertFalse($this->event['nameNotExist']);
+ }
+
+ public function testOffsetSet()
+ {
+ $this->event['foo2'] = 'bar2';
+ $this->assertAttributeSame(array('name' => 'Event', 'foo2' => 'bar2'), 'arguments', $this->event);
+ }
+
+ public function testOffsetUnset()
+ {
+ unset($this->event['name']);
+ $this->assertAttributeSame(array(), 'arguments', $this->event);
+ }
+
+ public function testOffsetIsset()
+ {
+ $this->assertArrayHasKey('name', $this->event);
+ $this->assertArrayNotHasKey('nameNotExist', $this->event);
+ }
+
+ public function testHasArgument()
+ {
+ $this->assertTrue($this->event->hasArgument('name'));
+ $this->assertFalse($this->event->hasArgument('nameNotExist'));
+ }
+
+ public function testGetSubject()
+ {
+ $this->assertSame($this->subject, $this->event->getSubject());
+ }
+
+ public function testHasIterator()
+ {
+ $data = array();
+ foreach ($this->event as $key => $value) {
+ $data[$key] = $value;
+ }
+ $this->assertEquals(array('name' => 'Event'), $data);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php
new file mode 100755
index 0000000..04f2861
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\Event;
+use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
+
+/**
+ * @author Bernhard Schussek
+ */
+class ImmutableEventDispatcherTest extends TestCase
+{
+ /**
+ * @var \PHPUnit_Framework_MockObject_MockObject
+ */
+ private $innerDispatcher;
+
+ /**
+ * @var ImmutableEventDispatcher
+ */
+ private $dispatcher;
+
+ protected function setUp()
+ {
+ $this->innerDispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
+ $this->dispatcher = new ImmutableEventDispatcher($this->innerDispatcher);
+ }
+
+ public function testDispatchDelegates()
+ {
+ $event = new Event();
+
+ $this->innerDispatcher->expects($this->once())
+ ->method('dispatch')
+ ->with('event', $event)
+ ->will($this->returnValue('result'));
+
+ $this->assertSame('result', $this->dispatcher->dispatch('event', $event));
+ }
+
+ public function testGetListenersDelegates()
+ {
+ $this->innerDispatcher->expects($this->once())
+ ->method('getListeners')
+ ->with('event')
+ ->will($this->returnValue('result'));
+
+ $this->assertSame('result', $this->dispatcher->getListeners('event'));
+ }
+
+ public function testHasListenersDelegates()
+ {
+ $this->innerDispatcher->expects($this->once())
+ ->method('hasListeners')
+ ->with('event')
+ ->will($this->returnValue('result'));
+
+ $this->assertSame('result', $this->dispatcher->hasListeners('event'));
+ }
+
+ /**
+ * @expectedException \BadMethodCallException
+ */
+ public function testAddListenerDisallowed()
+ {
+ $this->dispatcher->addListener('event', function () { return 'foo'; });
+ }
+
+ /**
+ * @expectedException \BadMethodCallException
+ */
+ public function testAddSubscriberDisallowed()
+ {
+ $subscriber = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventSubscriberInterface')->getMock();
+
+ $this->dispatcher->addSubscriber($subscriber);
+ }
+
+ /**
+ * @expectedException \BadMethodCallException
+ */
+ public function testRemoveListenerDisallowed()
+ {
+ $this->dispatcher->removeListener('event', function () { return 'foo'; });
+ }
+
+ /**
+ * @expectedException \BadMethodCallException
+ */
+ public function testRemoveSubscriberDisallowed()
+ {
+ $subscriber = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventSubscriberInterface')->getMock();
+
+ $this->dispatcher->removeSubscriber($subscriber);
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/composer.json b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/composer.json
new file mode 100755
index 0000000..14fc24b
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/composer.json
@@ -0,0 +1,44 @@
+{
+ "name": "symfony/event-dispatcher",
+ "type": "library",
+ "description": "Symfony EventDispatcher Component",
+ "keywords": [],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "symfony/dependency-injection": "~2.6|~3.0.0",
+ "symfony/expression-language": "~2.6|~3.0.0",
+ "symfony/config": "^2.0.5|~3.0.0",
+ "symfony/stopwatch": "~2.3|~3.0.0",
+ "psr/log": "~1.0"
+ },
+ "suggest": {
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ }
+}
diff --git a/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/phpunit.xml.dist b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/phpunit.xml.dist
new file mode 100755
index 0000000..f2eb169
--- /dev/null
+++ b/app/Common/extend/tencentcloud/vendor/symfony/event-dispatcher/phpunit.xml.dist
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Resources
+ ./Tests
+ ./vendor
+
+
+
+
diff --git a/app/Common/extend/tenxunyunimage/.gitignore b/app/Common/extend/tenxunyunimage/.gitignore
new file mode 100755
index 0000000..380c6f5
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/.gitignore
@@ -0,0 +1,7 @@
+# Mac
+.DS_Store
+Icon?
+
+# PhpStorm
+*.iml
+.idea/
diff --git a/app/Common/extend/tenxunyunimage/QcloudImage/Auth.php b/app/Common/extend/tenxunyunimage/QcloudImage/Auth.php
new file mode 100755
index 0000000..ae7f6a4
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/QcloudImage/Auth.php
@@ -0,0 +1,48 @@
+appId = $appId;
+ $this->secretId = $secretId;
+ $this->secretKey = $secretKey;
+ }
+ /**
+ * Return the appId
+ */
+ public function getAppId() {
+ return $this->appId;
+ }
+
+ /**
+ * Create reusable signature.
+ * This signature will expire at time()+$howlong timestamp.
+ * Return the signature on success.
+ * Return false on fail.
+ */
+ public function getSign($bucket, $howlong = 30) {
+ if ($howlong <= 0) {
+ return false;
+ }
+
+ $now = time();
+ $expiration = $now + $howlong;
+ $random = rand();
+
+ $plainText = "a=".$this->appId."&b=$bucket&k=".$this->secretId."&e=$expiration&t=$now&r=$random&f=";
+ $bin = hash_hmac('SHA1', $plainText, $this->secretKey, true);
+
+ return base64_encode($bin.$plainText);
+ }
+
+ private $appId = "";
+ private $secretId = "";
+ private $secretKey = "";
+}
diff --git a/app/Common/extend/tenxunyunimage/QcloudImage/CIClient.php b/app/Common/extend/tenxunyunimage/QcloudImage/CIClient.php
new file mode 100755
index 0000000..5113656
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/QcloudImage/CIClient.php
@@ -0,0 +1,1780 @@
+bucket = $bucket;
+ $this->auth = new Auth($appid, $secretId, $secretKey);
+ $this->http = new HttpClient();
+ $this->conf = new Conf();
+ }
+
+ public function useHttp()
+ {
+ $this->conf->useHttp();
+ }
+
+ public function useHttps()
+ {
+ $this->conf->useHttps();
+ }
+
+ public function setTimeout($timeout)
+ {
+ $this->conf->setTimeout($timeout);
+ }
+
+ /**
+ * 使用新服务器域名 recognition.image.myqcloud.com
+ *
+ * 如果你:
+ * 1.正在使用人脸识别系列功能( https://cloud.tencent.com/product/FaceRecognition/developer )
+ * 2.并且是通过旧域名访问的
+ * 那么: 请继续使用旧域名
+ */
+ public function useNewDomain()
+ {
+ $this->conf->useNewDomain();
+ }
+
+ /**
+ * 使用旧服务器域名 recognition.image.myqcloud.com
+ *
+ * 如果你:
+ * 1.正在使用人脸识别系列功能( https://cloud.tencent.com/product/FaceRecognition/developer )
+ * 2.并且是通过旧域名访问的
+ * 那么: 请继续使用旧域名
+ */
+ public function useOldDomain()
+ {
+ $this->conf->useOldDomain();
+ }
+
+ public function setProxy($proxy)
+ {
+ $this->http->setProxy($proxy);
+ }
+
+ /**
+ * 黄图识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures Person的人脸图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * 以上两种指定其一即可,如果指定多个,则优先使用urls,其次 files
+ *
+ * @return array http请求响应
+ */
+ public function pornDetect($picture) {
+
+ if (!$picture || !is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/detection/pornDetect');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+
+ if (isset($picture['urls'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url_list'] = $picture['urls'];
+
+ $data = json_encode($files);
+ } else if (isset($picture['files'])){
+ $index = 0;
+
+ foreach ($picture['files'] as $file) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$file);
+ } else {
+ $path = $file;
+ }
+
+ $path = realpath($path);
+ if (!file_exists($path)) {
+ return Error::json(Error::$FilePath, 'file '.$file.' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files["image[$index]"] = curl_file_create($path);
+ } else {
+ $files["image[$index]"] = '@'.($path);
+ }
+ $index++;
+ }
+
+ $data = $files;
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 标签识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $picture
+ * url array: 指定图片的url数组
+ * file array: 指定图片的路径数组
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ *
+ * @return array http请求响应
+ */
+ public function tagDetect($picture) {
+
+ if (!$picture || !is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/v1/detection/imagetag_detect');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+
+ if (isset($picture['url'])) {
+ $files['url'] = $picture['url'];
+ } else if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';') { // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ $files['image'] = base64_encode(file_get_contents($filePath));
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = base64_encode($picture['buffer']);
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+
+ $data = json_encode($files);
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 身份证识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures Person的人脸图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * buffers array: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files,最后buffers
+ * @param $cardType int 0为身份证有照片的一面,1为身份证有国徽的一面
+ * @return array http请求响应
+ */
+ public function idcardDetect($picture, $cardType=0) {
+
+ if (!$picture || !is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ if ($cardType !== 0 && $cardType !== 1) {
+ return Error::json(Error::$Param, 'param cardType error');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/idcard');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['card_type'] = $cardType;
+ if (isset($picture['urls'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url_list'] = $picture['urls'];
+
+ $data = json_encode($files);
+ } else if (isset($picture['files'])){
+ $index = 0;
+
+ foreach ($picture['files'] as $file) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$file);
+ } else {
+ $path = $file;
+ }
+
+ $path = realpath($path);
+ if (!file_exists($path)) {
+ return Error::json(Error::$FilePath, 'file '.$file.' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files["image[$index]"] = curl_file_create($path);
+ } else {
+ $files["image[$index]"] = '@'.($path);
+ }
+ $index++;
+ }
+
+ $data = $files;
+ } else if (isset($picture['buffers'])){
+ $index = 0;
+
+ foreach ($picture['buffers'] as $buffer) {
+ $files["image[$index]"] = $buffer;
+
+ $index++;
+ }
+
+ $data = $files;
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 名片识别v2
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures Person的人脸图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * buffers array: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files,最后buffers
+ * @return array http请求响应
+ */
+ public function namecardV2Detect($picture) {
+
+ if (!$picture || !is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+ $reqUrl = $this->conf->buildUrl('/ocr/businesscard');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['urls'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url_list'] = $picture['urls'];
+
+ $data = json_encode($files);
+ } else if (isset($picture['files'])){
+ $index = 0;
+
+ foreach ($picture['files'] as $file) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$file);
+ } else {
+ $path = $file;
+ }
+
+ $path = realpath($path);
+ if (!file_exists($path)) {
+ return Error::json(Error::$FilePath, 'file '.$file.' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files["image[$index]"] = curl_file_create($path);
+ } else {
+ $files["image[$index]"] = '@'.($path);
+ }
+ $index++;
+ }
+
+ $data = $files;
+ } else if (isset($picture['buffers'])){
+ $index = 0;
+
+ foreach ($picture['buffers'] as $buffer) {
+ $files["image[$index]"] = $buffer;
+
+ $index++;
+ }
+
+ $data = $files;
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 行驶证驾驶证识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures 证件的图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * buffers array: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files,最后buffers
+ * @param type int 表示识别类型,0表示行驶证,1表示驾驶证
+ * @return array http请求响应
+ */
+ public function drivingLicence($picture, $type=0){
+
+ if (!is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ if ($type !== 0 && $type !== 1) {
+ return Error::json(Error::$Param, 'param type error');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/drivinglicence');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $files['type'] = $type;
+ $data = json_encode($files);
+ } else {
+ $files['type'] = strval($type);
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 车牌号识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures 车牌号的图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * buffers array: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files,最后buffers
+ * @return array http请求响应
+ */
+ public function plate($picture){
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/plate');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 银行卡识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures 车牌号的图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * buffers array: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files,最后buffers
+ * @return array http请求响应
+ */
+ public function bankcard ($picture){
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/bankcard');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 营业执照识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures 车牌号的图片
+ * urls array: 指定图片的url数组
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files
+ * @return array http请求响应
+ */
+ public function bizlicense ($picture){
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/bizlicense');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 通用印刷体识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures 车牌号的图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files
+ * @return array http请求响应
+ */
+ public function general ($picture){
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/general');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 手写体识别
+ * @param array(associative) $picture 识别的图片
+ * * @param array(associative) $pictures 车牌号的图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files
+ * @return array http请求响应
+ */
+ public function handwriting ($picture){
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/ocr/handwriting');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 创建Person
+ * @param string $personId 创建的Person的ID
+ * @param array $groupIds 创建的Person需要加入的Group
+ * @param array(associative) $picture 创建的Person的人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ * @param string $personName 创建的Person的名字
+ * @param string $tag 为创建的Person打标签
+ *
+ * @return array http请求响应
+ */
+ public function faceNewPerson($personId, $groupIds, $picture, $personName=NULL, $tag=NULL) {
+
+ if (! is_array($groupIds)) {
+ return Error::json(Error::$Param, 'param groupIds must be array');
+ }
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/newperson');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+ if ($personName) {
+ $files['person_name'] = strval($personName);
+ }
+ if ($tag) {
+ $files['tag'] = strval($tag);
+ }
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['group_ids'] = $groupIds;
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ $index = 0;
+ foreach ($groupIds as $groupId) {
+ $files["group_ids[".strval($index++)."]"] = strval($groupId);
+ }
+
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 删除Person
+ * @param string $personId 删除的Person的ID
+ *
+ * @return array http请求响应
+ */
+ public function faceDelPerson($personId) {
+ $reqUrl = $this->conf->buildUrl('/face/delperson');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 为Person 添加人脸
+ * @param string $personId 创建的Person的ID
+ * @param array(associative) $pictures Person的人脸图片
+ * urls array: 指定图片的url数组
+ * files array: 指定图片的路径数组
+ * buffers array: 指定图片的内容数组
+ * 以上三种指定其一即可,如果指定多个,则优先使用urls,其次 files,再次 buffers。
+ * @param string $tag 为face打标签
+ *
+ * @return array http请求响应
+ */
+ public function faceAddFace($personId, $pictures, $tag=NULL) {
+ if (! is_array($pictures)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/addface');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+ if ($tag) {
+ $files['tag'] = strval($tag);
+ }
+ if (isset($pictures['urls']) && is_array($pictures['urls'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['urls'] = $pictures['urls'];
+ $data = json_encode($files);
+ } else {
+ if (isset($pictures['files']) && is_array($pictures['files'])) {
+ $index = 0;
+ foreach ($pictures['files'] as $picture) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture);
+ } else {
+ $path = $picture;
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture.' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files["images[$index]"] = curl_file_create($filePath);
+ } else {
+ $files["images[$index]"] = '@' . $filePath;
+ }
+ $index ++;
+ }
+ } else if (isset($pictures['buffers']) && is_array($pictures['buffers'])) {
+ $index = 0;
+ foreach ($pictures['buffers'] as $buffer) {
+ $files["images[".$index++."]"] = $buffer;
+ }
+ } else {
+ return Error::json(Error::$Param, 'param pictures is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 删除face
+ * @param string $personId 操作的Person的ID
+ * @param array $faceIds 删除的face的ID数组
+ *
+ * @return array http请求响应
+ */
+ public function faceDelFace($personId, $faceIds) {
+
+ if (! is_array($faceIds)) {
+ return Error::json(Error::$Param, 'param faceIds must be array');
+ }
+ $reqUrl = $this->conf->buildUrl('/face/delface');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+ $files['face_ids'] = $faceIds;
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 设置信息
+ * @param string $personId 操作的Person的ID
+ * @param string $personName Person的名字
+ * @param string $tag 为Person打标签
+ *
+ * @return array http请求响应
+ */
+ public function faceSetInfo($personId, $personName=NULL, $tag=NULL) {
+ $reqUrl = $this->conf->buildUrl('/face/setinfo');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+ if ($personName) {
+ $files['person_name'] = strval($personName);
+ }
+ if ($tag) {
+ $files['tag'] = strval($tag);
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 获取信息
+ * @param string $personId 操作的Person的ID
+ *
+ * @return array http请求响应
+ */
+ public function faceGetInfo($personId) {
+ $reqUrl = $this->conf->buildUrl('/face/getinfo');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 获取app下的组列表
+ *
+ * @return array http请求响应
+ */
+ public function faceGetGroupIds() {
+ $reqUrl = $this->conf->buildUrl('/face/getgroupids');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 获取group下的person列表
+ * @param string $groupId 操作的GroupID
+ *
+ * @return array http请求响应
+ */
+ public function faceGetPersonIds($groupId) {
+ $reqUrl = $this->conf->buildUrl('/face/getpersonids');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['group_id'] = strval($groupId);
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 获取person的face列表
+ * @param string $personId 操作的Person的ID
+ *
+ * @return array http请求响应
+ */
+ public function faceGetFaceIds($personId) {
+ $reqUrl = $this->conf->buildUrl('/face/getfaceids');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 获取face的信息
+ * @param string $faceId 操作的FaceID
+ *
+ * @return array http请求响应
+ */
+ public function faceGetFaceInfo($faceId) {
+ $reqUrl = $this->conf->buildUrl('/face/getfaceinfo');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ $files['face_id'] = strval($faceId);
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 识别指定的图片属于哪个人
+ * @param array $groupId 需要对比的GroupId
+ * @param array(associative) $picture Person的人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ *
+ * @return array http请求响应
+ */
+ public function faceIdentify($groupId, $picture) {
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/identify');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['group_id'] = strval($groupId);
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 识别指定的图片是不是指定的person
+ * @param array $personId 需要对比的person
+ * @param array(associative) $picture 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ *
+ * @return array http请求响应
+ */
+ public function faceVerify($personId, $picture) {
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/verify');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['person_id'] = strval($personId);
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 对比两张图片是否是同一个人
+ * @param array(associative) $pictureA 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ * @param array(associative) $pictureB 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ *
+ * @return array http请求响应
+ */
+ public function faceCompare($pictureA, $pictureB) {
+ if (! is_array($pictureA)) {
+ return Error::json(Error::$Param, 'param pictureA must be array');
+ }
+ if (! is_array($pictureB)) {
+ return Error::json(Error::$Param, 'param pictureB must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/compare');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+
+ if (isset($pictureA['url'])) {
+ $files['urlA'] = $pictureA['url'];
+ } else if (isset($pictureA['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$pictureA['file']);
+ } else {
+ $path = $pictureA['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$pictureA['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['imageA'] = curl_file_create($filePath);
+ } else {
+ $files['imageA'] = '@' . $filePath;
+ }
+ } else if (isset($pictureA['buffer'])) {
+ $files['imageA'] = $pictureA['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param pictureA is illegal');
+ }
+
+ if (isset($pictureB['url'])) {
+ $files['urlB'] = $pictureB['url'];
+ } else if (isset($pictureB['file'])) {
+ $filePath = realpath($pictureB['file']);
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$pictureB['file']);
+ } else {
+ $path = $pictureB['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$pictureB['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['imageB'] = curl_file_create($filePath);
+ } else {
+ $files['imageB'] = '@' . $filePath;
+ }
+ } else if (isset($pictureB['buffer'])) {
+ $files['imageB'] = $pictureB['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param pictureB is illegal');
+ }
+
+ if (isset($pictureA['url']) && isset($pictureB['ur'])) {
+ $headers[] = 'Content-Type:application/json';
+ $data = json_encode($files);
+ } else {
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 检测图中的人脸
+ * @param array(associative) $picture 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ * @param int $mode 检测模式,0为检测所有人脸,1为检测最大的人脸
+ *
+ * @return array http请求响应
+ */
+ public function faceDetect($picture, $mode=0) {
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+ if ($mode !== 0 && $mode !== 1) {
+ return Error::json(Error::$Param, 'param mode error');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/detect');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['mode'] = $mode;
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ $files['mode'] = strval($mode);
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 定位图中人脸的五官信息
+ * @param array(associative) $picture 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ * @param int $mode 检测模式,0为检测所有人脸,1为检测最大的人脸
+ *
+ * @return array http请求响应
+ */
+ public function faceShape($picture, $mode=0) {
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+ if ($mode !== 0 && $mode !== 1) {
+ return Error::json(Error::$Param, 'param mode error');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/shape');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['mode'] = $mode;
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ $files['mode'] = strval($mode);
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 多脸检索
+ * @param array(associative) $picture 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file
+ * @param array $idtype group_id:单个id,group_ids:多个id
+ *
+ * @return array http请求响应
+ */
+ public function multidentify($picture, $idtype){
+
+ if (!$picture || !is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/multidentify');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+
+ if (isset($picture['url'])) { //url
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+
+ if (isset($idtype['group_id'])) {
+ $files['group_id'] = $idtype['group_id'];
+ } else if (isset($idtype['group_ids'])) {
+ $files['group_ids'] = $idtype['group_ids'];
+ } else {
+ return Error::json(Error::$Param, 'param idtype is illegal');
+ }
+ } else if (isset($picture['file'])) {
+ $headers[] = 'Content-Type:multipart/form-data';
+ if(PATH_SEPARATOR==';') { // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files["image"] = curl_file_create($filePath);
+ } else {
+ $files["image"] = '@'.($filePath);
+ }
+
+ if (isset($idtype['group_id'])) {
+ $files['group_id'] = $idtype['group_id'];
+ } else if (isset($idtype['group_ids'])) {
+ if(!isset($picture['url'])){
+ $index = 0;
+
+ foreach ($idtype['group_ids'] as $id) {
+ $files["group_ids[$index]"] = $id;
+ $index++;
+ }
+ }
+
+ } else {
+ return Error::json(Error::$Param, 'param idtype is illegal');
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+
+
+ if(isset($picture['url'])){
+ $data = json_encode($files);
+ }else if(isset($picture['file'])){
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 人脸静态活体检测
+ * @param array(associative) $picture 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ * @param int $mode 检测模式,0为检测所有人脸,1为检测最大的人脸
+ *
+ * @return array http请求响应
+ */
+ public function liveDetectPicture ($picture, $sign) {
+
+ if (!$picture || !is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/livedetectpicture');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+
+ if (isset($picture['url'])) {
+ $files['url'] = $picture['url'];
+ $files['sign'] = $sign;
+ } else if (isset($picture['file'])) {
+ $files['sign'] = $sign;
+ if(PATH_SEPARATOR==';') { // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ $files['image'] = base64_encode(file_get_contents($filePath));
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = base64_encode($picture['buffer']);
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+
+ $data = json_encode($files);
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 检测图片中的人和给定的信息是否匹配
+ * @param string $idcardNumber 身份证号
+ * @param string $idcardName 姓名
+ * @param array(associative) $picture 人脸图片
+ * url string: 指定图片的url
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上三种指定其一即可,如果指定多个,则优先使用url,其次 file,再次 buffer。
+ *
+ * @return array http请求响应
+ */
+ public function faceIdCardCompare($idcardNumber, $idcardName, $picture) {
+
+ if (! is_array($picture)) {
+ return Error::json(Error::$Param, 'param picture must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/idcardcompare');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['idcard_number'] = strval($idcardNumber);
+ $files['idcard_name'] = strval($idcardName);
+
+ if (isset($picture['url'])) {
+ $headers[] = 'Content-Type:application/json';
+ $files['url'] = $picture['url'];
+ $data = json_encode($files);
+ } else {
+ if (isset($picture['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$picture['file']);
+ } else {
+ $path = $picture['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$picture['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['image'] = curl_file_create($filePath);
+ } else {
+ $files['image'] = '@' . $filePath;
+ }
+ } else if (isset($picture['buffer'])) {
+ $files['image'] = $picture['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param picture is illegal');
+ }
+ $data = $files;
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $data,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 活体检测第一步:获取唇语(验证码)
+ * @param string $seq 指定一个sessionId,若使用,请确保id唯一。
+ *
+ * @return array http请求响应
+ */
+ public function faceLiveGetFour($seq=NULL) {
+ $reqUrl = $this->conf->buildUrl('/face/livegetfour');
+ $headers = $this->baseHeaders();
+ $headers[] = 'Content-Type:application/json';
+ $files = $this->baseParams();
+ if ($seq) {
+ $files['seq'] = strval($seq);
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => json_encode($files),
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 活体检测第二步:检测
+ * @param string $validate faceLiveGetFour获取的验证码
+ * @param array(associative) $video 拍摄的视频
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上二种指定其一即可,如果指定多个,则优先使用 file,其次 buffer。
+ * @param bool $compareFlag 是否将视频中的人和card图片比对
+ * @param array(associative) $card 人脸图片
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上二种指定其一即可,如果指定多个,则优先使用 file,其次 buffer。
+ * @param string $seq 指定一个sessionId,若使用,请确保id唯一。
+ *
+ * @return array http请求响应
+ */
+ public function faceLiveDetectFour($validate, $video, $compareFlag, $card=NULL, $seq=NULL) {
+ if (! is_array($video)) {
+ return Error::json(Error::$Param, 'param video must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/livedetectfour');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['validate_data'] = strval($validate);
+
+ if (isset($video['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$video['file']);
+ } else {
+ $path = $video['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$video['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['video'] = curl_file_create($filePath);
+ } else {
+ $files['video'] = '@' . $filePath;
+ }
+ } else if (isset($video['buffer'])) {
+ $files['video'] = $video['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param video is illegal');
+ }
+
+ if ($compareFlag) {
+ if (! is_array($card)) {
+ return Error::json(Error::$Param, 'param card must be array');
+ }
+ if (isset($card['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$card['file']);
+ } else {
+ $path = $card['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$card['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['card'] = curl_file_create($filePath);
+ } else {
+ $files['card'] = '@' . $filePath;
+ }
+ } else if (isset($card['buffer'])) {
+ $files['card'] = $card['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param card is illegal');
+ }
+ $files['compare_flag'] = 'true';
+ } else {
+ $files['compare_flag'] = 'false';
+ }
+ if ($seq) {
+ $files['seq'] = strval($seq);
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $files,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+ /**
+ * 活体检测第二步:检测--对比指定身份信息
+ * @param string $validate faceLiveGetFour获取的验证码
+ * @param array(associative) $video 拍摄的视频
+ * file string: 指定图片的路径
+ * buffer string: 指定图片的内容
+ * 以上二种指定其一即可,如果指定多个,则优先使用 file,其次 buffer。
+ * @param string $idcardNumber 身份证号
+ * @param string $idcardName 姓名
+ * @param string $seq 指定一个sessionId,若使用,请确保id唯一。
+ *
+ * @return array http请求响应
+ */
+ public function faceIdCardLiveDetectFour($validate, $video, $idcardNumber, $idcardName, $seq=NULL) {
+ if (! is_array($video)) {
+ return Error::json(Error::$Param, 'param video must be array');
+ }
+
+ $reqUrl = $this->conf->buildUrl('/face/idcardlivedetectfour');
+ $headers = $this->baseHeaders();
+ $files = $this->baseParams();
+ $files['validate_data'] = strval($validate);
+ $files['idcard_number'] = strval($idcardNumber);
+ $files['idcard_name'] = strval($idcardName);
+
+ if (isset($video['file'])) {
+ if(PATH_SEPARATOR==';'){ // WIN OS
+ $path = iconv("UTF-8","gb2312//IGNORE",$video['file']);
+ } else {
+ $path = $video['file'];
+ }
+
+ $filePath = realpath($path);
+ if (! file_exists($filePath)) {
+ return Error::json(Error::$FilePath, 'file '.$video['file'].' not exist');
+ }
+
+ if (function_exists('curl_file_create')) {
+ $files['video'] = curl_file_create($filePath);
+ } else {
+ $files['video'] = '@' . $filePath;
+ }
+ } else if (isset($video['buffer'])) {
+ $files['video'] = $video['buffer'];
+ } else {
+ return Error::json(Error::$Param, 'param video is illegal');
+ }
+
+ if ($seq) {
+ $files['seq'] = strval($seq);
+ }
+
+ return $this->doRequest(array(
+ 'url' => $reqUrl,
+ 'method' => 'POST',
+ 'data' => $files,
+ 'header' => $headers,
+ 'timeout' => $this->conf->timeout()
+ ));
+ }
+
+
+ /**
+ * send http request
+ * @param array $request http请求信息
+ * url : 请求的url地址
+ * method : 请求方法,'get', 'post', 'put', 'delete', 'head'
+ * data : 请求数据,如有设置,则method为post
+ * header : 需要设置的http头部
+ * host : 请求头部host
+ * timeout : 请求超时时间
+ * cert : ca文件路径
+ * ssl_version: SSL版本号
+ * @return string http请求响应
+ */
+ private function doRequest($request) {
+ $result = $this->http->sendRequest($request);
+ $json = json_decode($result, true);
+ if ($json) {
+ $json['http_code'] = $this->http->statusCode();
+ return json_encode($json);
+ }
+
+ return Error::json(Error::$Network, "response is not json: ".$result, $this->http->statusCode());
+ }
+
+ private function baseHeaders() {
+ return array (
+ 'Authorization:'.$this->auth->getSign($this->bucket),
+ 'User-Agent:'.Conf::getUa($this->auth->getAppId()),
+ );
+ }
+ private function baseParams() {
+ return array (
+ 'appid' => $this->auth->getAppId(),
+ 'bucket' => $this->bucket,
+ );
+ }
+
+ private $bucket;
+ private $auth;
+ private $http;
+ private $conf;
+}
diff --git a/app/Common/extend/tenxunyunimage/QcloudImage/Conf.php b/app/Common/extend/tenxunyunimage/QcloudImage/Conf.php
new file mode 100755
index 0000000..465402b
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/QcloudImage/Conf.php
@@ -0,0 +1,55 @@
+SCHEME = 'http';
+ }
+ public function useHttps() {
+ $this->SCHEME = 'https';
+ }
+ public function setTimeout($timeout) {
+ if ($timeout > 0) {
+ $this->REQ_TIMEOUT = $timeout;
+ }
+ }
+
+ public function useNewDomain()
+ {
+ $this->HOST = self::SERVER_ADDR2;
+ }
+
+ public function useOldDomain()
+ {
+ $this->HOST = self::SERVER_ADDR;
+ }
+ public function timeout() {
+ return $this->REQ_TIMEOUT;
+ }
+
+ public function buildUrl($uri) {
+ return $this->SCHEME . '://' . $this->HOST . '/' . ltrim($uri, "/");
+ }
+
+ public static function getUa($appid = null) {
+ $ua = 'CIPhpSDK/'.self::VERSION.' ('.php_uname().')';
+ if ($appid) {
+ $ua .= " User($appid)";
+ }
+ return $ua;
+ }
+}
diff --git a/app/Common/extend/tenxunyunimage/QcloudImage/Error.php b/app/Common/extend/tenxunyunimage/QcloudImage/Error.php
new file mode 100755
index 0000000..2477d51
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/QcloudImage/Error.php
@@ -0,0 +1,28 @@
+ $code,
+ 'message' => $message,
+ 'httpcode' => $httpcode,
+ 'data' => json_decode('{}',true)
+ ));
+ }
+
+ public static $Param = -1;
+ public static $Network = -2;
+ public static $FilePath = -3;
+ public static $Unknown = -4;
+}
diff --git a/app/Common/extend/tenxunyunimage/QcloudImage/HttpClient.php b/app/Common/extend/tenxunyunimage/QcloudImage/HttpClient.php
new file mode 100755
index 0000000..63ee910
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/QcloudImage/HttpClient.php
@@ -0,0 +1,122 @@
+proxy = $proxy;
+ }
+
+ public function __destory() {
+ if ($this->curlHandler) {
+ curl_close($this->curlHandler);
+ }
+ }
+
+ /**
+ * send http request
+ * @param array $request http请求信息
+ * url : 请求的url地址
+ * method : 请求方法,'get', 'post', 'put', 'delete', 'head'
+ * data : 请求数据,如有设置,则method为post
+ * header : 需要设置的http头部
+ * host : 请求头部host
+ * timeout : 请求超时时间
+ * cert : ca文件路径
+ * ssl_version: SSL版本号
+ * @return string http请求响应
+ */
+ public function sendRequest($request) {
+ if (!is_array($request) || !isset($request["url"])) {
+ return false;
+ }
+ if ($this->curlHandler) {
+ if (function_exists('curl_reset')) {
+ curl_reset($this->curlHandler);
+ } else {
+ my_curl_reset($this->curlHandler);
+ }
+ } else {
+ $this->curlHandler = curl_init();
+ }
+
+ curl_setopt($this->curlHandler, CURLOPT_URL, $request['url']);
+
+ $method = 'GET';
+ if (isset($request['method']) &&
+ in_array(strtolower($request['method']), array('get', 'post', 'put', 'delete', 'head'))) {
+ $method = strtoupper($request['method']);
+ } else if (isset($request['data'])) {
+ $method = 'POST';
+ }
+
+ $header = isset($request['header']) ? $request['header'] : array();
+ $header[] = 'Connection: keep-alive';
+ if ('POST' == $method) {
+ $header[] = 'Expect: ';
+ }
+
+ isset($request['host']) && $header[] = 'Host:' . $request['host'];
+ curl_setopt($this->curlHandler, CURLOPT_HTTPHEADER, $header);
+
+ if (empty($this->proxy)) {
+ curl_setopt($this->curlHandler, CURLOPT_PROXY, null);
+ } else {
+ curl_setopt($this->curlHandler, CURLOPT_PROXY, $this->proxy);
+ }
+
+ curl_setopt($this->curlHandler, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($this->curlHandler, CURLOPT_CUSTOMREQUEST, $method);
+ isset($request['timeout']) && curl_setopt($this->curlHandler, CURLOPT_TIMEOUT, $request['timeout']);
+ isset($request['data']) && in_array($method, array('POST', 'PUT')) &&
+ curl_setopt($this->curlHandler, CURLOPT_POSTFIELDS, $request['data']);
+ $ssl = substr($request['url'], 0, 8) == "https://" ? true : false;
+ if (isset($request['cert'])) {
+ curl_setopt($this->curlHandler, CURLOPT_SSL_VERIFYPEER,true);
+ curl_setopt($this->curlHandler, CURLOPT_CAINFO, $request['cert']);
+ curl_setopt($this->curlHandler, CURLOPT_SSL_VERIFYHOST,2);
+ if (isset($request['ssl_version'])) {
+ curl_setopt($this->curlHandler, CURLOPT_SSLVERSION, $request['ssl_version']);
+ } else {
+ curl_setopt($this->curlHandler, CURLOPT_SSLVERSION, 4);
+ }
+ } else if ($ssl) {
+ curl_setopt($this->curlHandler, CURLOPT_SSL_VERIFYPEER,true); //true any ca
+ curl_setopt($this->curlHandler, CURLOPT_SSL_VERIFYHOST,2);
+ if (isset($request['ssl_version'])) {
+ curl_setopt($this->curlHandler, CURLOPT_SSLVERSION, $request['ssl_version']);
+ } else {
+ curl_setopt($this->curlHandler, CURLOPT_SSLVERSION, 4);
+ }
+ }
+ $ret = curl_exec($this->curlHandler);
+ $this->httpInfo = curl_getinfo($this->curlHandler);
+ return $ret;
+ }
+
+ public function statusCode() {
+ if ($this->httpInfo) {
+ return $this->httpInfo['http_code'];
+ }
+ return 0;
+ }
+
+ private $httpInfo;
+ private $curlHandler;
+}
diff --git a/app/Common/extend/tenxunyunimage/README.md b/app/Common/extend/tenxunyunimage/README.md
new file mode 100755
index 0000000..bd2aeaa
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/README.md
@@ -0,0 +1,224 @@
+# tencentyun/image-php-sdk-v2.0
+[腾讯云](https://cloud.tencent.com) 云智AI应用服务智能图像 SDK for PHP
+
+## 安装(直接下载源码集成)
+### 直接下载源码集成
+从github下载源码,并加载image-php-sdk-v2.0/index.php就可以了。
+调用请参考sample.php
+
+### 1. 在腾讯云申请业务的授权
+授权包括:
+
+ APP_ID
+ SECRET_ID
+ SECRET_KEY
+ BUCKET
+
+### 2. 创建对应操作类的对象
+如果要使用图片,需要创建图片操作类对象
+
+ require_once __DIR__ . '/index.php';
+ use QcloudImage\CIClient;
+
+ $client = new CIClient('APP_ID', 'SECRET_ID', 'SECRET_KEY', 'BUCKET');
+ $client->setTimeout(30);
+
+### 3. 调用对应的方法
+在创建完对象后,根据实际需求,调用对应的操作方法就可以了。sdk提供的方法包括:图片识别、人脸识别及人脸核身等。
+
+#### 3.1 图片识别
+图片识别包括:图片鉴黄、图片标签、OCR-身份证识别及OCR-名片识别。
+
+##### 图片鉴黄
+
+```php
+ //单个或多个图片Url
+ var_dump ($client->pornDetect(array('urls'=>array('YOUR URL A',
+ 'YOUR URL B'))));
+ //单个或多个图片File
+ var_dump ($client->pornDetect(array('files'=>array('F:\pic\你好.jpg','G:\pic\test2.jpg'))));
+```
+
+##### 图片标签
+
+```php
+ //单个图片url
+ var_dump ($client->tagDetect(array('url'=>'YOUR URL')));
+ //单个图片file
+ var_dump ($client->tagDetect(array('file'=>'G:\pic\hot1.jpg')));
+ //单个图片内容
+ var_dump ($client->tagDetect(array('buffer'=>file_get_contents('G:\pic\hot1.jpg'))));
+```
+
+##### OCR-身份证识别
+
+```php
+ //单个或多个图片Url,识别身份证正面
+ var_dump ($client->idcardDetect(array('urls'=>array('YOUR URL A',
+ 'YOUR URL B')), 0));
+ //单个或多个图片file,识别身份证正面
+ var_dump ($client->idcardDetect(array('files'=>array('F:\pic\id6_zheng.jpg', 'F:\pic\id2_zheng.jpg')), 0));
+ //单个或多个图片内容,识别身份证正面
+ var_dump ($client->idcardDetect(array('buffers'=>array(file_get_contents('F:\pic\id6_zheng.jpg'),
+ file_get_contents('F:\pic\id2_zheng.jpg'))), 0));
+
+ //单个或多个图片Url,识别身份证反面
+ var_dump ($client->idcardDetect(array('urls'=>array('YOUR URL C',
+ 'YOUR URL D')), 1));
+ //单个或多个图片file,识别身份证反面
+ var_dump ($client->idcardDetect(array('files'=>array('F:\pic\id5_fan.jpg', 'F:\pic\id7_fan.png')), 1));
+ //单个或多个图片内容,识别身份证反面
+ var_dump ($client->idcardDetect(array('buffers'=>array(file_get_contents('F:\pic\id5_fan.jpg'),
+ file_get_contents('F:\pic\id7_fan.jpg'))), 1));
+```
+
+##### OCR-名片识别
+```php
+ //单个或多个图片Url
+ var_dump ($client->namecardDetect(array('urls'=>array('YOUR URL A',
+ 'YOUR URL B')), 0));
+ //单个或多个图片file,
+ var_dump ($client->namecardDetect(array('files'=>array('F:\pic\r.jpg', 'F:\pic\name2.jpg')), 1));
+ //单个或多个图片内容
+ var_dump ($client->namecardDetect(array('buffers'=>array(file_get_contents('F:\pic\name1.jpg'),
+ file_get_contents('F:\pic\name2.jpg'))), 0));
+```
+
+#### 3.2 人脸识别
+人脸识别包括:人脸检测、五官定位、个体信息管理、人脸验证、人脸对比及人脸检索。
+
+#### 人脸检测
+
+```php
+ //单个图片Url, mode:1为检测最大的人脸 , 0为检测所有人脸
+ var_dump ($client->faceDetect(array('url'=>'YOUR URL'), 1));
+ //单个图片file,mode:1为检测最大的人脸 , 0为检测所有人脸
+ var_dump ($client->faceDetect(array('file'=>'F:\pic\face1.jpg'),0));
+ //单个图片内容,mode:1为检测最大的人脸 , 0为检测所有人脸
+ var_dump ($client->faceDetect(array('buffer'=>file_get_contents('F:\pic\face1.jpg')), 1));
+```
+
+##### 五官定位
+
+```php
+ //单个图片Url,mode:1为检测最大的人脸 , 0为检测所有人脸
+ var_dump ($client->faceShape(array('url'=>'YOUR URL'),1));
+ //单个图片file,mode:1为检测最大的人脸 , 0为检测所有人脸
+ var_dump ($client->faceShape(array('file'=>'F:\pic\face1.jpg'),0));
+ //单个图片内容,mode:1为检测最大的人脸 , 0为检测所有人脸
+ var_dump ($client->faceShape(array('buffer'=>file_get_contents('F:\pic\face1.jpg')), 1));
+```
+
+##### 个体信息管理
+```php
+ //个体创建,创建一个Person,并将Person放置到group_ids指定的组当中,不存在的group_id会自动创建。
+ //创建一个Person, 使用图片url
+ var_dump ($client->faceNewPerson('person1111', array('group11',), array('url'=>'YOUR URL'), 'xiaoxin'));
+ //创建一个Person, 使用图片file
+ var_dump ($client->faceNewPerson('person2111', array('group11',), array('file'=>'F:\pic\hot1.jpg')));
+ //创建一个Person, 使用图片内容
+ var_dump ($client->faceNewPerson('person3111', array('group11',), array('buffer'=>file_get_contents('F:\pic\zhao1.jpg'))));
+
+ //增加人脸,将一组Face加入到一个Person中。
+ //将单个或者多个Face的url加入到一个Person中
+ var_dump ($client->faceAddFace('person1111', array('urls'=>array('YOUR URL A',
+ 'YOUR URL B'))));
+ //将单个或者多个Face的file加入到一个Person中
+ var_dump ($client->faceAddFace('person2111', array('files'=>array('F:\pic\yang.jpg','F:\pic\yang2.jpg'))));
+ //将单个或者多个Face的文件内容加入到一个Person中
+ var_dump ($client->faceAddFace('person3111', array('buffers'=>array(file_get_contents('F:\pic\yang.jpg'),file_get_contents('F:\pic\yang2.jpg')))));
+
+ // 删除人脸,删除一个person下的face
+ var_dump ($client->faceDelFace('person1', array('12346',)));
+
+ //设置信息
+ var_dump ($client->faceSetInfo('person1', 'fanbing'));
+
+ //获取信息
+ var_dump ($client->faceGetInfo('person1'));
+
+ //获取组列表
+ var_dump ($client->faceGetGroupIds());
+
+ //获取人列表
+ var_dump ($client->faceGetPersonIds('group1'));
+
+ //获取人脸列表
+ var_dump ($client->faceGetFaceIds('person1'));
+
+ //获取人脸信息
+ var_dump ($client->faceGetFaceInfo('1704147773393235686'));
+
+ //删除个人
+ var_dump ($client->faceDelPerson('person11'));
+```
+
+##### 人脸验证
+给定一个Face和一个Person,返回是否是同一个人的判断以及置信度
+
+```php
+ //单个图片Url
+ var_dump ($client->faceVerify('person1', array('url'=>'YOUR URL')));
+ //单个图片file
+ var_dump ($client->faceVerify('person3111', array('file'=>'F:\pic\yang3.jpg')));
+ //单个图片内容
+ var_dump ($client->faceVerify('person3111', array('buffer'=>file_get_contents('F:\pic\yang3.jpg'))));
+```
+
+##### 人脸检索
+对于一个待识别的人脸图片,在一个Group中识别出最相似的Top5 Person作为其身份返回,返回的Top5中按照相似度从大到小排列。
+
+```php
+ //单个文件url
+ var_dump ($client->faceIdentify('group1', array('url'=>'YOUR URL')));
+ //单个文件file
+ var_dump ($client->faceIdentify('group11', array('file'=>'F:\pic\yang3.jpg')));
+ //单个文件内容
+ var_dump ($client->faceIdentify('group11', array('buffer'=>file_get_contents('F:\pic\yang3.jpg'))));
+```
+
+##### 人脸对比
+
+```php
+ //两个对比图片的文件url
+ var_dump ($client->faceCompare(array('url'=>"YOUR URL A"),
+ array('url'=>'YOUR URL B')));
+ //两个对比图片的文件file
+ var_dump ($client->faceCompare(array('file'=>'F:\pic\yang.jpg'), array('file'=>'F:\pic\yang2.jpg')));
+ //两个对比图片的文件内容
+ var_dump ($client->faceCompare(array('file'=>'F:\pic\yang.jpg'), array('file'=>'F:\pic\yang2.jpg')));
+```
+
+
+#### 3.3 人脸核身
+
+##### 身份证识别对比
+
+```php
+ //身份证url
+ var_dump ($client->faceIdCardCompare('xxxxxxxxxxx', 'xxxxxxxxxxx', array('url'=>'YOUR URL')));
+ //身份证文件file
+ var_dump ($client->faceIdCardCompare('xxxxxxxxxxx', 'xxxxxxxxxxx', array('file'=>'F:\pic\idcard.jpg')));
+ //身份证文件内容
+ var_dump ($client->faceIdCardCompare('xxxxxxxxxxx', 'xxxxxxxxxxx', array('buffer'=>file_get_contents('F:\pic\idcard.jpg'))));
+```
+
+##### 活体检测—获取唇语验证码
+
+```php
+ $obj = $client->faceLiveGetFour();
+ var_dump ($obj);
+ $validate_data = $obj['data']['validate_data'];
+```
+
+##### 活体检测-视频与用户照片的比对
+
+```php
+ var_dump ($client->faceLiveDetectFour($validate_data, array('file'=>'F:\pic\ZOE_0171.mp4'), False, array('F:\pic\idcard.jpg')));
+```
+
+##### 活体检测-视频与身份证高清照片的比对
+
+```php
+ var_dump ($client->faceIdCardLiveDetectFour($validate_data, array('file'=>'F:\pic\ZOE_0171.mp4'), 'xxxxxxxxxxx', 'xxxxxxxxxxx'));
+```
diff --git a/app/Common/extend/tenxunyunimage/assets/face_02.jpg b/app/Common/extend/tenxunyunimage/assets/face_02.jpg
new file mode 100755
index 0000000..8dbee7a
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/face_02.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/face_05.jpg b/app/Common/extend/tenxunyunimage/assets/face_05.jpg
new file mode 100755
index 0000000..6a5fa53
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/face_05.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_face_01.jpg b/app/Common/extend/tenxunyunimage/assets/icon_face_01.jpg
new file mode 100755
index 0000000..f5005fc
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_face_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_id_01.jpg b/app/Common/extend/tenxunyunimage/assets/icon_id_01.jpg
new file mode 100755
index 0000000..d158022
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_id_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_id_02.jpg b/app/Common/extend/tenxunyunimage/assets/icon_id_02.jpg
new file mode 100755
index 0000000..3d38ab0
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_id_02.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_id_03.jpg b/app/Common/extend/tenxunyunimage/assets/icon_id_03.jpg
new file mode 100755
index 0000000..c381250
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_id_03.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_id_04.jpg b/app/Common/extend/tenxunyunimage/assets/icon_id_04.jpg
new file mode 100755
index 0000000..bb6aa49
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_id_04.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_imag_01.jpg b/app/Common/extend/tenxunyunimage/assets/icon_imag_01.jpg
new file mode 100755
index 0000000..773dec2
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_imag_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_ocr_card_1.jpg b/app/Common/extend/tenxunyunimage/assets/icon_ocr_card_1.jpg
new file mode 100755
index 0000000..d12a292
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_ocr_card_1.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_ocr_jsz_01.jpg b/app/Common/extend/tenxunyunimage/assets/icon_ocr_jsz_01.jpg
new file mode 100755
index 0000000..a932e09
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_ocr_jsz_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_ocr_license_3.jpg b/app/Common/extend/tenxunyunimage/assets/icon_ocr_license_3.jpg
new file mode 100755
index 0000000..9d3a462
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_ocr_license_3.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_ocr_xsz_01.jpg b/app/Common/extend/tenxunyunimage/assets/icon_ocr_xsz_01.jpg
new file mode 100755
index 0000000..c08762f
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_ocr_xsz_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_porn04.jpg b/app/Common/extend/tenxunyunimage/assets/icon_porn04.jpg
new file mode 100755
index 0000000..e62cb24
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_porn04.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_porn05.jpg b/app/Common/extend/tenxunyunimage/assets/icon_porn05.jpg
new file mode 100755
index 0000000..377c1b0
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_porn05.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/icon_porn06.jpg b/app/Common/extend/tenxunyunimage/assets/icon_porn06.jpg
new file mode 100755
index 0000000..e419c7e
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/icon_porn06.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/livedetectpicture.jpg b/app/Common/extend/tenxunyunimage/assets/livedetectpicture.jpg
new file mode 100755
index 0000000..f96cbdc
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/livedetectpicture.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/ocr_card_01.jpg b/app/Common/extend/tenxunyunimage/assets/ocr_card_01.jpg
new file mode 100755
index 0000000..449b447
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/ocr_card_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/ocr_common09.jpg b/app/Common/extend/tenxunyunimage/assets/ocr_common09.jpg
new file mode 100755
index 0000000..5cf75dc
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/ocr_common09.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/ocr_hw_03.png b/app/Common/extend/tenxunyunimage/assets/ocr_hw_03.png
new file mode 100755
index 0000000..9dbbf75
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/ocr_hw_03.png differ
diff --git a/app/Common/extend/tenxunyunimage/assets/ocr_namecard_01.jpg b/app/Common/extend/tenxunyunimage/assets/ocr_namecard_01.jpg
new file mode 100755
index 0000000..de25c0b
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/ocr_namecard_01.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/ocr_namecard_02.jpg b/app/Common/extend/tenxunyunimage/assets/ocr_namecard_02.jpg
new file mode 100755
index 0000000..5a665a7
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/ocr_namecard_02.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/assets/ocr_yyzz_02.jpg b/app/Common/extend/tenxunyunimage/assets/ocr_yyzz_02.jpg
new file mode 100755
index 0000000..45158dd
Binary files /dev/null and b/app/Common/extend/tenxunyunimage/assets/ocr_yyzz_02.jpg differ
diff --git a/app/Common/extend/tenxunyunimage/autoload.php b/app/Common/extend/tenxunyunimage/autoload.php
new file mode 100755
index 0000000..898bf32
--- /dev/null
+++ b/app/Common/extend/tenxunyunimage/autoload.php
@@ -0,0 +1,11 @@
+useHttps();
+
+// 设置超时
+$client->setTimeout(30);
+
+// 选择服务器域名, 推荐使用新域名 useNewDomain ( recognition.image.myqcloud.com )
+//
+// 如果你:
+// 1.正在使用人脸识别系列功能( https://cloud.tencent.com/product/FaceRecognition/developer )
+// 2.并且是通过旧域名访问的
+// 那么: 请继续使用旧域名
+$client->useNewDomain();
+
+//根据你的网络环境, 可能需要设置代理
+//$client->setProxy('127.0.0.1:12759');
+
+//图片鉴黄
+//单个或多个图片Url
+var_dump ($client->pornDetect(array('urls'=>array('http://open.youtu.qq.com./static/img/image_porn04.87591fe.jpg'))));
+//单个或多个图片File
+var_dump ($client->pornDetect(array('files'=>array('assets/icon_porn04.jpg'))));
+
+//图片标签
+//单个图片url
+var_dump ($client->tagDetect(array('url'=>'http://open.youtu.qq.com./static/img/imag_02.f43527f.jpg')));
+//单个图片file
+var_dump ($client->tagDetect(array('file'=>'assets/icon_imag_01.jpg')));
+//单个图片内容
+var_dump ($client->tagDetect(array('buffer'=>file_get_contents('assets/icon_imag_01.jpg'))));
+
+//身份证识别
+//单个或多个图片Url,识别身份证正面
+var_dump ($client->idcardDetect(array('urls'=>array('http://open.youtu.qq.com./static/img/ocr_id_01.883a2df.jpg')), 0/*0为正面,1为反面*/));
+//单个或多个图片file,识别身份证正面
+var_dump ($client->idcardDetect(array('files'=>array('assets/icon_id_01.jpg')), 0/*0为正面,1为反面*/));
+//单个或多个图片内容,识别身份证正面
+var_dump ($client->idcardDetect(array('buffers'=>array(file_get_contents('assets/icon_id_01.jpg'))), 0/*0为正面,1为反面*/));
+
+//名片识别v2
+//单个或多个图片Url
+var_dump ($client->namecardV2Detect(array('urls'=>array('http://open.youtu.qq.com/app/img/experience/char_general/ocr_namecard_01.jpg'))));
+//单个或多个图片file
+var_dump ($client->namecardV2Detect(array('files'=>array('assets/ocr_namecard_01.jpg'))));
+//单个或多个图片内容
+var_dump ($client->namecardV2Detect(array('buffers'=>array(file_get_contents('assets/ocr_namecard_01.jpg')))));
+
+//行驶证驾驶证识别
+//单个或多个图片file
+var_dump ($client->drivingLicence(array('file'=>'assets/icon_ocr_jsz_01.jpg'),1/*0表示行驶证,1表示驾驶证*/));
+//使用buffer
+var_dump ($client->drivingLicence(array('buffer'=>file_get_contents('assets/icon_ocr_jsz_01.jpg')),1/*0表示行驶证,1表示驾驶证*/));
+//单个或多个图片Url
+var_dump ($client->drivingLicence(array('url'=>'http://open.youtu.qq.com./static/img/ocr_jsz_01.53c2885.jpg'), 1/*0表示行驶证,1表示驾驶证*/));
+
+//车牌号识别
+//单个图片file
+var_dump ($client->plate(array('file'=>'assets/icon_ocr_license_3.jpg')));
+//单个图片的URL
+var_dump ($client->plate(array('url'=>'http://open.youtu.qq.com./static/img/ocr_license_01.d7ac40a.jpg')));
+
+//银行卡识别
+//单个图片file
+var_dump ($client->bankcard(array('file'=>'assets/ocr_card_01.jpg')));
+//使用buffer
+var_dump ($client->bankcard(array('buffer'=>file_get_contents('assets/ocr_card_01.jpg'))));
+//单个图片的URL
+var_dump ($client->bankcard(array('url'=>'http://open.youtu.qq.com./static/img/ocr_card_01.dd4aada.jpg')));
+
+//营业执照识别
+//单个图片识别
+var_dump ($client->bizlicense(array('file'=>'assets/ocr_yyzz_02.jpg')));
+//使用buffer
+var_dump ($client->bizlicense(array('buffer'=>file_get_contents('assets/ocr_yyzz_02.jpg'))));
+//单个图片的URL
+var_dump ($client->bizlicense(array('url'=>'http://open.youtu.qq.com./static/img/ocr_yyzz_01.1d874f9.jpg')));
+
+//通用印刷体的识别
+//单个图片的识别
+var_dump ($client->general(array('file'=>'assets/ocr_common09.jpg')));
+//单个图片的URL
+var_dump ($client->general(array('url'=>'http://open.youtu.qq.com/static/img/ocr_common05.df60ecc.jpg')));
+
+//手写体识别
+//单个图片的识别
+var_dump ($client->handwriting(array('file'=>'assets/ocr_hw_03.png')));
+//单个图片的URL
+var_dump ($client->handwriting(array('url'=>'http://open.youtu.qq.com./static/img/ocr_hw_03.2174a0a.jpg')));
+
+//人脸检测
+//单个图片Url, mode:1为检测最大的人脸 , 0为检测所有人脸
+var_dump ($client->faceDetect(array('url'=>'https://open.youtu.qq.com/static/img/face_05.b64219d.jpg'), 0));
+//单个图片file,mode:1为检测最大的人脸 , 0为检测所有人脸
+var_dump ($client->faceDetect(array('file'=>'assets/face_05.jpg'),0));
+//单个图片内容,mode:1为检测最大的人脸 , 0为检测所有人脸
+var_dump ($client->faceDetect(array('buffer'=>file_get_contents('assets/face_05.jpg')), 0));
+
+//五官定位
+//单个图片Url,mode:1为检测最大的人脸 , 0为检测所有人脸
+var_dump ($client->faceShape(array('url'=>'https://open.youtu.qq.com/static/img/face_05.b64219d.jpg'),0));
+//单个图片Url,mode:1为检测最大的人脸 , 0为检测所有人脸
+var_dump ($client->faceShape(array('file'=>'assets/face_05.jpg'),0));
+//单个图片Url,mode:1为检测最大的人脸 , 0为检测所有人脸
+var_dump ($client->faceShape(array('buffer'=>file_get_contents('assets/face_05.jpg')), 0));
+
+
+//创建一个Person,并将Person放置到group_ids指定的组当中, 使用图片url
+var_dump ($client->faceNewPerson('personId0', array('groupId0'), array('url'=>'http://open.youtu.qq.com./static/img/face_01.f0c4a0c.jpg'), 'personName0','personTag0'));
+//创建一个Person,并将Person放置到group_ids指定的组当中, 使用图片file
+var_dump ($client->faceNewPerson('personId1', array('groupId0'), array('file'=>'assets/face_02.jpg'), 'personName1', 'personTag1'));
+//创建一个Person,并将Person放置到group_ids指定的组当中, 使用图片内容
+var_dump ($client->faceNewPerson('personId2', array('groupId0'), array('buffer'=>file_get_contents('assets/icon_id_01.jpg')), 'personName2', 'personTag2'));
+
+
+//增加人脸,将单个或者多个Face的url加入到一个Person中.注意,一个Face只能被加入到一个Person中。 一个Person最多允许包含20个Face
+var_dump ($client->faceAddFace('person_one', array('urls'=>array('YOUR URL A','YOUR URL B'))));
+//增加人脸,将单个或者多个Face的file加入到一个Person中.注意,一个Face只能被加入到一个Person中。 一个Person最多允许包含20个Face
+var_dump ($client->faceAddFace('person_two', array('files'=>array('F:\pic\yang.jpg','F:\pic\yang2.jpg'))));
+//增加人脸,将单个或者多个Face的文件内容加入到一个Person中.注意,一个Face只能被加入到一个Person中。 一个Person最多允许包含20个Face
+var_dump ($client->faceAddFace('person_three', array('buffers'=>array(file_get_contents('F:\pic\yang.jpg'),file_get_contents('F:\pic\yang2.jpg')))));
+
+//删除人脸
+var_dump ($client->faceDelFace('person_one', array('one',)));
+//设置信息
+var_dump ($client->faceSetInfo('person_one', 'fanbing'));
+//获取信息
+var_dump ($client->faceGetInfo('person_one'));
+//获取组列表
+var_dump ($client->faceGetGroupIds());
+//获取人列表
+var_dump ($client->faceGetPersonIds('group1'));
+//获取人脸列表
+var_dump ($client->faceGetFaceIds('person_one'));
+//获取人脸信息
+var_dump ($client->faceGetFaceInfo('1704147773393235686'));
+//删除个人
+var_dump ($client->faceDelPerson('person_one'));
+
+//人脸验证
+//单个图片Url
+var_dump ($client->faceVerify('person1', array('url'=>'YOUR URL')));
+//单个图片file
+var_dump ($client->faceVerify('person3111', array('file'=>'F:\pic\yang3.jpg')));
+//单个图片内容
+var_dump ($client->faceVerify('person3111', array('buffer'=>file_get_contents('F:\pic\yang3.jpg'))));
+
+//人脸检索
+//单个文件url
+var_dump ($client->faceIdentify('group1', array('url'=>'YOUR URL')));
+//单个文件file
+var_dump ($client->faceIdentify('group11', array('file'=>'F:\pic\yang3.jpg')));
+//单个文件内容
+var_dump ($client->faceIdentify('group11', array('buffer'=>file_get_contents('F:\pic\yang3.jpg'))));
+
+//人脸对比
+//两个对比图片的文件url
+var_dump ($client->faceCompare(array('url'=>"YOUR URL A"), array('url'=>'YOUR URL B')));
+//两个对比图片的文件file
+var_dump ($client->faceCompare(array('file'=>'F:\pic\yang.jpg'), array('file'=>'F:\pic\yang2.jpg')));
+//两个对比图片的文件内容
+var_dump ($client->faceCompare( array('buffer'=>file_get_contents('F:\pic\yang.jpg')), array('buffer'=>file_get_contents('F:\pic\yang3.jpg'))));
+
+
+//身份证识别对比
+//身份证url
+var_dump ($client->faceIdCardCompare('ID CARD NUM', 'NAME', array('url'=>'YOUR URL')));
+//身份证文件file
+var_dump ($client->faceIdCardCompare('ID CARD NUM', 'NAME', array('file'=>'F:\pic\idcard.jpg')));
+//身份证文件内容
+var_dump ($client->faceIdCardCompare('ID CARD NUM', 'NAME', array('buffer'=>file_get_contents('F:\pic\idcard.jpg'))));
+
+
+//人脸核身
+//活体检测第一步:获取唇语(验证码)
+$obj = $client->faceLiveGetFour();
+var_dump ($obj);
+$faceObj = json_decode($obj, true);
+var_dump ($faceObj);
+$validate_data = '';
+if ($faceObj && isset($faceObj['data']['validate_data'])) {
+ $validate_data = $faceObj['data']['validate_data'];
+}
+var_dump ($validate_data);
+
+//活体检测第二步:检测
+var_dump ($client->faceLiveDetectFour($validate_data, array('file'=>'F:\pic\ZOE_0171.mp4'), False, array('F:\pic\idcard.jpg')));
+//活体检测第二步:检测--对比指定身份信息
+var_dump ($client->faceIdCardLiveDetectFour($validate_data, array('file'=>'F:\pic\ZOE_0171.mp4'), '330782198802084329', '季锦锦'));
+
+//人脸静态活体检测
+//使用image的检测
+var_dump ($client->liveDetectPicture(array('file'=>'F:\pic\face1.jpg'),'123456'));
+//使用buffer
+var_dump ($client->liveDetectPicture(array('buffer'=>file_get_contents('F:\pic\face1.jpg')),'123456'));
+//单个图片的URL
+var_dump ($client->liveDetectPicture(array('url'=>'YOUR URL'),'123456'));
+
+//多脸检索
+//使用 image 和 group_id 的请求
+var_dump ($client->multidentify(array('file'=>'F:\pic\r2.jpg'), array('group_id'=>'tencent')));
+//使用 image 和 group_ids 的请求
+var_dump ($client->multidentify(array('file'=>'F:\pic\face1.jpg'), array('group_ids'=>array("tencent","qq"))));
+//使用 url 和 group_id 的请求
+var_dump ($client->multidentify(array('url'=>'YOUR URL'), array('group_id'=>'tencent')));
+//使用 url 和 group_ids 的请求
+var_dump ($client->multidentify(array('url'=>'YOUR URL') , array('group_ids'=>array("tencent","qq"))));
diff --git a/app/Common/extend/timg.jpg b/app/Common/extend/timg.jpg
new file mode 100755
index 0000000..029e917
Binary files /dev/null and b/app/Common/extend/timg.jpg differ
diff --git a/app/Common/extend/vista.ttf b/app/Common/extend/vista.ttf
new file mode 100755
index 0000000..aa23ae1
Binary files /dev/null and b/app/Common/extend/vista.ttf differ
diff --git a/app/Common/extend/wxBizDataCrypt/errorCode.php b/app/Common/extend/wxBizDataCrypt/errorCode.php
new file mode 100755
index 0000000..d2e2976
--- /dev/null
+++ b/app/Common/extend/wxBizDataCrypt/errorCode.php
@@ -0,0 +1,23 @@
+
+
+ * -41001: encodingAesKey 非法
+ * -41003: aes 解密失败
+ * -41004: 解密后得到的buffer非法
+ * -41005: base64加密失败
+ * -41016: base64解密失败
+ *
+ */
+class ErrorCode
+{
+ public static $OK = 0;
+ public static $IllegalAesKey = -41001;
+ public static $IllegalIv = -41002;
+ public static $IllegalBuffer = -41003;
+ public static $DecodeBase64Error = -41004;
+}
+
+?>
\ No newline at end of file
diff --git a/app/Common/extend/wxBizDataCrypt/wxBizDataCrypt.php b/app/Common/extend/wxBizDataCrypt/wxBizDataCrypt.php
new file mode 100755
index 0000000..4b26368
--- /dev/null
+++ b/app/Common/extend/wxBizDataCrypt/wxBizDataCrypt.php
@@ -0,0 +1,69 @@
+sessionKey = $sessionKey;
+ $this->appid = $appid;
+ }
+
+
+ /**
+ * 检验数据的真实性,并且获取解密后的明文.
+ * @param $encryptedData string 加密的用户数据
+ * @param $iv string 与用户数据一同返回的初始向量
+ * @param $data string 解密后的原文
+ *
+ * @return int 成功0,失败返回对应的错误码
+ */
+ public function decryptData( $encryptedData, $iv, &$data )
+ {
+ if (strlen($this->sessionKey) != 24) {
+ return ErrorCode::$IllegalAesKey;
+ }
+ $aesKey=base64_decode($this->sessionKey);
+
+
+ if (strlen($iv) != 24) {
+ return ErrorCode::$IllegalIv;
+ }
+ $aesIV=base64_decode($iv);
+
+ $aesCipher=base64_decode($encryptedData);
+
+ $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
+
+ $dataObj=json_decode( $result );
+ if( $dataObj == NULL )
+ {
+ return ErrorCode::$IllegalBuffer;
+ }
+ if( $dataObj->watermark->appid != $this->appid )
+ {
+ return ErrorCode::$IllegalBuffer;
+ }
+ $data = $result;
+ return ErrorCode::$OK;
+ }
+
+}
+
diff --git a/app/Common/extend/wxWork/work.php b/app/Common/extend/wxWork/work.php
new file mode 100755
index 0000000..b21c6ea
--- /dev/null
+++ b/app/Common/extend/wxWork/work.php
@@ -0,0 +1,241 @@
+appid = $appid;
+ $this->appsecret = $appsecret;
+ $path = ROOT_PATH;
+ if (!is_dir($path . 'runtime/data')) {
+ mkdir($path . 'runtime/data',0777,true);
+ }
+ if (!is_dir($path . 'runtime/data/tpl')) {
+ mkdir($path . 'runtime/data/tpl',0777,true);
+ }
+ if (!is_dir($path . 'runtime/data/tpl/web')) {
+ mkdir($path . 'runtime/data/tpl/web',0777,true);
+ }
+
+ }
+
+ /*
+ * 给员工推送应用消息
+ * array $data 发送数据
+ */
+ public function send(array $data)
+ {
+ if (is_array($data)) {
+ $data = json_encode($data, JSON_UNESCAPED_UNICODE);
+ }
+ $accessTokenWW = $this->getAccessTokenWW();
+
+ if (is_array($accessTokenWW)) {
+ return $accessTokenWW;
+ }
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={$accessTokenWW}";
+
+ $res = $this->curlPost($url, $data);
+ return $res;
+ }
+ /*
+ * 给员工推送应用消息
+ * array $data 发送数据
+ */
+ public function send_multi(array $data)
+ {
+ $accessTokenWW = $this->getAccessTokenWW();
+ if (is_array($accessTokenWW)) {
+ return $accessTokenWW;
+ }
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={$accessTokenWW}";
+ foreach ($data as $index => $item)
+ {
+ $data[$index]['url'] = $url;
+ }
+ $res = $this->curl_multi($data);
+ return $res;
+ }
+
+ /*
+ * 获取AccessToken
+ */
+ protected function getAccessTokenWW()
+ {
+ $appidMd5 = md5($this->appid);
+ if (!is_file(ROOT_PATH . 'runtime/data/tpl/web/' . $appidMd5 . '.txt')) {
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->appid}&corpsecret={$this->appsecret}";
+ $data = $this->curlPost($url);
+ $data = json_decode($data, true);
+ if (!isset($data['access_token'])) {
+ return $data;
+ }
+ $access_token = $data['access_token'];
+
+
+ file_put_contents(ROOT_PATH . 'runtime/data/tpl/web/' . $appidMd5 . '.txt', json_encode(['at' => $access_token, 'time' => time() + 6200]));
+ return $access_token;
+ }
+ if (is_file(ROOT_PATH . 'runtime/data/tpl/web/' . $appidMd5 . '.txt')) {
+ $fileInfo = file_get_contents(ROOT_PATH . 'runtime/data/tpl/web/' . $appidMd5 . '.txt');
+ if (!$fileInfo) {
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->appid}&corpsecret={$this->appsecret}";
+ $data = $this->curlPost($url);
+ $data = json_decode($data, true);
+ if (!isset($data['access_token'])) {
+ return $data;
+ }
+ $access_token = $data['access_token'];
+
+ file_put_contents(ROOT_PATH . '/data/tpl/web/' . $appidMd5 . '.txt', json_encode(['at' => $access_token, 'time' => time() + 6200]));
+ return $access_token;
+ } else {
+ $fileInfo = json_decode($fileInfo, true);
+ if ($fileInfo['time'] < time()) {
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->appid}&corpsecret={$this->appsecret}";
+ $data = $this->curlPost($url);
+ $data = json_decode($data, true);
+ if (!isset($data['access_token'])) {
+ return $data;
+ }
+ $access_token = $data['access_token'];
+
+ file_put_contents(ROOT_PATH . 'runtime/data/tpl/web/' . $appidMd5 . '.txt', json_encode(['at' => $access_token, 'time' => time() + 6200]));
+ return $access_token;
+ }
+ return $fileInfo['at'];
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ * 发送http请求
+ * string $url 请求链接
+ * string(json) $data 请求数据
+ * number $time 请求超时时间
+ */
+ protected function curlPost($url, $data = '', $time = 20)
+ {
+// if (!empty($data))
+// $data = $this->arr2xml($data);
+
+ //初使化init方法
+ $ch = curl_init();
+
+ //指定URL
+ curl_setopt($ch, CURLOPT_URL, $url);
+
+ //设定请求后返回结果
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+
+ //声明使用POST方式来进行发送
+ curl_setopt($ch, CURLOPT_POST, 1);
+
+ //发送什么数据呢
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+
+
+ //忽略证书
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+
+ //忽略header头信息
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+
+ //设置超时时间
+ curl_setopt($ch, CURLOPT_TIMEOUT, $time);
+
+ //发送请求
+ $output = curl_exec($ch);
+
+ //关闭curl
+ curl_close($ch);
+
+ //返回数据
+// $output = (array)\simplexml_load_string($output, null, LIBXML_NOCDATA | LIBXML_COMPACT);
+ return $output;
+ }
+
+ /*
+ * 批量发送http请求
+ * string $url 请求链接
+ * string(json) $data 请求数据
+ * number $time 请求超时时间
+ */
+ protected function curl_multi ($array)
+ {
+ global $_GPC, $_W;
+ $mh = curl_multi_init();
+ $curls = array();
+
+ foreach ($array as $index => $item)
+ {
+ $tmp = curl_init();
+
+ curl_setopt($tmp, CURLOPT_URL, $item['url']);
+ curl_setopt($tmp, CURLOPT_HEADER, 0);
+
+
+
+ //设定请求后返回结果
+ curl_setopt($tmp, CURLOPT_RETURNTRANSFER, 1);
+
+ //声明使用POST方式来进行发送
+ curl_setopt($tmp, CURLOPT_POST, 1);
+
+ //发送什么数据呢
+ curl_setopt($tmp, CURLOPT_POSTFIELDS, $item['data']);
+
+
+ //忽略证书
+ curl_setopt($tmp, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($tmp, CURLOPT_SSL_VERIFYHOST, false);
+
+ //忽略header头信息
+ curl_setopt($tmp, CURLOPT_HEADER, 0);
+
+ //设置超时时间
+ curl_setopt($tmp, CURLOPT_TIMEOUT, 100);
+
+
+ array_push($curls, $tmp);
+ curl_multi_add_handle($mh, $tmp);
+ }
+
+ $running=null;
+
+ do {
+ $mrc = curl_multi_exec($mh, $running);
+ } while ($mrc == CURLM_CALL_MULTI_PERFORM);
+
+ while ($running && $mrc == CURLM_OK) {
+ if (curl_multi_select($mh) != -1) {
+ do {
+ $mrc = curl_multi_exec($mh, $running);
+ } while ($mrc == CURLM_CALL_MULTI_PERFORM);
+ }
+ }
+
+ foreach ($curls as $index => $item)
+ {
+ curl_multi_remove_handle($mh, $item);
+ }
+ curl_multi_close($mh);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/extend/wxWork/work.weixin.class.php b/app/Common/extend/wxWork/work.weixin.class.php
new file mode 100755
index 0000000..5c4bf86
--- /dev/null
+++ b/app/Common/extend/wxWork/work.weixin.class.php
@@ -0,0 +1,234 @@
+appid = $appid;
+ $this->appsecret = $appsecret;
+ $path = IA_ROOT;
+ if (!is_dir($path . '/data')) {
+ mkdir($path . '/data');
+ }
+ if (!is_dir($path . '/data/tpl')) {
+ mkdir($path . '/data/tpl');
+ }
+ if (!is_dir($path . '/data/tpl/web')) {
+ mkdir($path . '/data/tpl/web');
+ }
+
+ }
+
+ /*
+ * 给员工推送应用消息
+ * array $data 发送数据
+ */
+ public function send(array $data)
+ {
+ if (is_array($data)) {
+ $data = json_encode($data, JSON_UNESCAPED_UNICODE);
+ }
+ $accessTokenWW = $this->getAccessTokenWW();
+ if (is_array($accessTokenWW)) {
+ return $accessTokenWW;
+ }
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={$accessTokenWW}";
+ $res = $this->curlPost($url, $data);
+ return $res;
+ }
+ /*
+ * 给员工推送应用消息
+ * array $data 发送数据
+ */
+ public function send_multi(array $data)
+ {
+ $accessTokenWW = $this->getAccessTokenWW();
+ if (is_array($accessTokenWW)) {
+ return $accessTokenWW;
+ }
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={$accessTokenWW}";
+ foreach ($data as $index => $item)
+ {
+ $data[$index]['url'] = $url;
+ }
+ $res = $this->curl_multi($data);
+ return $res;
+ }
+
+ /*
+ * 获取AccessToken
+ */
+ protected function getAccessTokenWW()
+ {
+ $appidMd5 = md5($this->appid);
+ if (!is_file(IA_ROOT . '/data/tpl/web/' . $appidMd5 . '.txt')) {
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->appid}&corpsecret={$this->appsecret}";
+ $data = $this->curlPost($url);
+ $data = json_decode($data, true);
+ if (!isset($data['access_token'])) {
+ return $data;
+ }
+ $access_token = $data['access_token'];
+ file_put_contents(IA_ROOT . '/data/tpl/web/' . $appidMd5 . '.txt', json_encode(['at' => $access_token, 'time' => time() + 6200]));
+ return $access_token;
+ }
+ if (is_file(IA_ROOT . '/data/tpl/web/' . $appidMd5 . '.txt')) {
+ $fileInfo = file_get_contents(IA_ROOT . '/data/tpl/web/' . $appidMd5 . '.txt');
+ if (!$fileInfo) {
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->appid}&corpsecret={$this->appsecret}";
+ $data = $this->curlPost($url);
+ $data = json_decode($data, true);
+ if (!isset($data['access_token'])) {
+ return $data;
+ }
+ $access_token = $data['access_token'];
+ file_put_contents(IA_ROOT . '/data/tpl/web/' . $appidMd5 . '.txt', json_encode(['at' => $access_token, 'time' => time() + 6200]));
+ return $access_token;
+ } else {
+ $fileInfo = json_decode($fileInfo, true);
+ if ($fileInfo['time'] < time()) {
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->appid}&corpsecret={$this->appsecret}";
+ $data = $this->curlPost($url);
+ $data = json_decode($data, true);
+ if (!isset($data['access_token'])) {
+ return $data;
+ }
+ $access_token = $data['access_token'];
+ file_put_contents(IA_ROOT . '/data/tpl/web/' . $appidMd5 . '.txt', json_encode(['at' => $access_token, 'time' => time() + 6200]));
+ return $access_token;
+ }
+ return $fileInfo['at'];
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ * 发送http请求
+ * string $url 请求链接
+ * string(json) $data 请求数据
+ * number $time 请求超时时间
+ */
+ protected function curlPost($url, $data = '', $time = 20)
+ {
+// if (!empty($data))
+// $data = $this->arr2xml($data);
+
+ //初使化init方法
+ $ch = curl_init();
+
+ //指定URL
+ curl_setopt($ch, CURLOPT_URL, $url);
+
+ //设定请求后返回结果
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+
+ //声明使用POST方式来进行发送
+ curl_setopt($ch, CURLOPT_POST, 1);
+
+ //发送什么数据呢
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+
+
+ //忽略证书
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+
+ //忽略header头信息
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+
+ //设置超时时间
+ curl_setopt($ch, CURLOPT_TIMEOUT, $time);
+
+ //发送请求
+ $output = curl_exec($ch);
+
+ //关闭curl
+ curl_close($ch);
+
+ //返回数据
+// $output = (array)\simplexml_load_string($output, null, LIBXML_NOCDATA | LIBXML_COMPACT);
+ return $output;
+ }
+
+ /*
+ * 批量发送http请求
+ * string $url 请求链接
+ * string(json) $data 请求数据
+ * number $time 请求超时时间
+ */
+ protected function curl_multi ($array)
+ {
+ global $_GPC, $_W;
+ $mh = curl_multi_init();
+ $curls = array();
+
+ foreach ($array as $index => $item)
+ {
+ $tmp = curl_init();
+
+ curl_setopt($tmp, CURLOPT_URL, $item['url']);
+ curl_setopt($tmp, CURLOPT_HEADER, 0);
+
+
+
+ //设定请求后返回结果
+ curl_setopt($tmp, CURLOPT_RETURNTRANSFER, 1);
+
+ //声明使用POST方式来进行发送
+ curl_setopt($tmp, CURLOPT_POST, 1);
+
+ //发送什么数据呢
+ curl_setopt($tmp, CURLOPT_POSTFIELDS, $item['data']);
+
+
+ //忽略证书
+ curl_setopt($tmp, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($tmp, CURLOPT_SSL_VERIFYHOST, false);
+
+ //忽略header头信息
+ curl_setopt($tmp, CURLOPT_HEADER, 0);
+
+ //设置超时时间
+ curl_setopt($tmp, CURLOPT_TIMEOUT, 100);
+
+
+ array_push($curls, $tmp);
+ curl_multi_add_handle($mh, $tmp);
+ }
+
+ $running=null;
+
+ do {
+ $mrc = curl_multi_exec($mh, $running);
+ } while ($mrc == CURLM_CALL_MULTI_PERFORM);
+
+ while ($running && $mrc == CURLM_OK) {
+ if (curl_multi_select($mh) != -1) {
+ do {
+ $mrc = curl_multi_exec($mh, $running);
+ } while ($mrc == CURLM_CALL_MULTI_PERFORM);
+ }
+ }
+
+ foreach ($curls as $index => $item)
+ {
+ curl_multi_remove_handle($mh, $item);
+ }
+ curl_multi_close($mh);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/listener/AppInit.php b/app/Common/listener/AppInit.php
new file mode 100755
index 0000000..b30ee2b
--- /dev/null
+++ b/app/Common/listener/AppInit.php
@@ -0,0 +1,97 @@
+initConst();
+
+ }
+
+ /**
+ * 初始化系统常量
+ * @author shuixian
+ * @DataTime: 2019/12/516:52
+ */
+ private function initConst()
+ {
+
+ $appDebug = Env::get('APP_DEBUG',false);
+ defined('APP_DEBUG') or define('APP_DEBUG',$appDebug) ;
+
+ defined('DS') or define('DS', DIRECTORY_SEPARATOR);
+
+ //获取当前应用目录
+ defined('APP_PATH') or define('APP_PATH', app_path());
+ //获取当前系统根目录
+ defined('LONGBING_ROOT_PATH') or define('LONGBING_ROOT_PATH', APP_PATH . '..' . DS);
+
+ defined('ROOT_PATH') or define('ROOT_PATH', LONGBING_ROOT_PATH);
+
+
+ //系统扩展目录
+ defined('EXTEND_PATH') or define('EXTEND_PATH', LONGBING_ROOT_PATH . 'extend/');
+ //app\Common里的扩展目录
+ defined('LONGBING_EXTEND_PATH') or define('LONGBING_EXTEND_PATH', APP_PATH . 'Common/extend' . DS);//文件上传目录
+
+ //微擎先删除 在处理
+ //defined( 'IA_PATH' ) or define('IA_PATH', ROOT_PATH);
+ //defined( 'IA_ROOT' ) or define('IA_ROOT', ROOT_PATH);
+
+
+ defined('PAY_PATH') or define('PAY_PATH', LONGBING_ROOT_PATH);
+
+ //微擎
+ if (longbingIsWeiqin()) {
+ global $_W;
+ defined('APP_MODEL_NAME') or define('APP_MODEL_NAME', $_W['current_module']['name']);
+
+ //发现没有使用
+ //defined('UPLOAD_OBPATH') or define('UPLOAD_OBPATH', 'https://' . $_SERVER['HTTP_HOST'] . '/attachment/upload' . DS); // 配置文件目录
+ //defined('APP_PUBLIC_OBPATH') or define('APP_PUBLIC_OBPATH', 'https://' . $_SERVER['HTTP_HOST'] . '/addons/longbing_shequpintuan/core/public' . DS); // 配置文件目录
+ //defined('APP_HOST_PUBLIC') or define('APP_HOST_PUBLIC', 'https://' . $_SERVER['HTTP_HOST'] . '/addons/longbing_shequpintuan/core/public/init_image' . DS); // 配置文件目录
+
+ defined('UPLOAD_PATH') or define('UPLOAD_PATH', $_SERVER['DOCUMENT_ROOT'] . '/attachment/upload/' . DS); // 配置文件目录
+ defined('PUBLIC_PATH') or define('PUBLIC_PATH', ADDON_PATH . '/core/public' . DS); // 配置文件目录
+ defined('FILE_UPLOAD_PATH') or define('FILE_UPLOAD_PATH', LONGBING_ROOT_PATH . '../../../attachment' . DS);//文件上传目录
+
+ } //独立版
+ else {
+
+ defined('APP_MODEL_NAME') or define('APP_MODEL_NAME', Config::get('app.AdminModelList.app_model_name','longbing_card') );
+ defined('UPLOAD_PATH') or define('UPLOAD_PATH', $_SERVER['DOCUMENT_ROOT'] . '/uploads' . DS); // 配置文件目录
+ defined('PUBLIC_PATH') or define('PUBLIC_PATH', ROOT_PATH . 'public' . DS); // 配置文件目录
+ defined('FILE_UPLOAD_PATH') or define('FILE_UPLOAD_PATH', ROOT_PATH . 'public/attachment' . DS); //文件上传目录
+ }
+
+ //修改文件存储配置信息
+ $filesystemConfig = Config::get('filesystem') ;
+ $filesystemConfig['disks']['longbing']['root'] = FILE_UPLOAD_PATH ;
+ Config::set( $filesystemConfig, 'filesystem');
+
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Common/listener/HttpEndLog.php b/app/Common/listener/HttpEndLog.php
new file mode 100755
index 0000000..9892876
--- /dev/null
+++ b/app/Common/listener/HttpEndLog.php
@@ -0,0 +1,96 @@
+isDebug()) {
+
+ try {
+
+
+ //获取请求地址
+ $data['url'] = $request->url(true);
+
+ //获取请求参数
+ $data['param'] = json_encode($request->param());
+
+ //获取IP
+ $data['ip'] = $request->ip();
+
+ //获取返回值
+ $data['content'] = $response->getContent();
+
+ //消耗内存
+ $data['mem'] = getRangeMem(App::getInstance()->getBeginMem());
+ //耗时
+ $data['execution_time'] = getRangeTime(App::getInstance()->getBeginTime());
+
+ //平台ID
+ $uniacid = $request->param('uniacid');
+ $uniacid = empty($uniacid) ? $request->param('i') : $uniacid;
+ $data['uniacid'] = $uniacid ? $uniacid : 0;
+
+ //获取用户信息
+ //独立版管理后台
+ $token = $request->header('token');
+ $user = getUserForToken($token);
+ if (empty($data['uniacid']) && !empty($user)) {
+
+ $data['uniacid'] = $user['uniacid'];
+ $data['uid'] = $user['account'];
+ $data['username'] = $user['account'];
+ }
+
+ //微擎版本管理后台
+ //小程序前端接口
+
+
+ //保存到数据库 ims_longbing_action_log
+
+ $actionLogModel = new LongbingActionLog();
+
+ $actionLogModel->addActionLog($data);
+ }catch (Exception $e){
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingActionLog.php b/app/Common/model/LongbingActionLog.php
new file mode 100755
index 0000000..c11094d
--- /dev/null
+++ b/app/Common/model/LongbingActionLog.php
@@ -0,0 +1,32 @@
+save($data);
+ return $result;
+ }
+}
diff --git a/app/Common/model/LongbingCardCollection.php b/app/Common/model/LongbingCardCollection.php
new file mode 100755
index 0000000..a74e0ef
--- /dev/null
+++ b/app/Common/model/LongbingCardCollection.php
@@ -0,0 +1,44 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function createCollection($data)
+ {
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ return !empty($result);
+ }
+
+ public function listCollection($filter)
+ {
+ $result = $this->where($filter)->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function updateCollection($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ public function delCollection($filter)
+ {
+ $result = $this->where($filter)->delete();
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingCardCommonModel.php b/app/Common/model/LongbingCardCommonModel.php
new file mode 100755
index 0000000..8446e61
--- /dev/null
+++ b/app/Common/model/LongbingCardCommonModel.php
@@ -0,0 +1,35 @@
+name = $table_name;
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function getCount($table_name ,$filter)
+ {
+ $this->name = $table_name;
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+
+ public function listRows($table_name ,$filter ,$field)
+ {
+ $this->name = $table_name;
+ $result = $this->where($filter);
+ if(!empty($field)) $result->field($field);
+ $result = $result->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingCardCount.php b/app/Common/model/LongbingCardCount.php
new file mode 100755
index 0000000..3e8b449
--- /dev/null
+++ b/app/Common/model/LongbingCardCount.php
@@ -0,0 +1,41 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function getCountNum($filter)
+ {
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+ //查询当天的数据
+ public function getTodaylist($where){
+ return $this->where($where)->whereDay('create_time')->count();
+ }
+ public function getCreateTimeAttr($value){
+ return date('Y-m-d H:i:s',$value['create_time']);
+ }
+ public function getYesterdaylist($where){
+ $data = $this->alias('a')
+ ->join( 'longbing_card_collection b', 'a.to_uid = b.to_uid && a.uniacid = b.uniacid','left')
+ ->field('a.to_uid,count(a.to_uid) as number,a.create_time')
+ ->where($where)
+ ->group('a.to_uid')
+ ->whereDay('a.create_time')
+ ->select()->toArray();print_r($this->getLastSql());exit;
+ return $data;
+ }
+
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingCardFromId.php b/app/Common/model/LongbingCardFromId.php
new file mode 100755
index 0000000..8d7de2f
--- /dev/null
+++ b/app/Common/model/LongbingCardFromId.php
@@ -0,0 +1,39 @@
+where($filter)->order('id asc')->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //删除7天前的fromid
+ public function autoDelFromId()
+ {
+ $filter = [['create_time' ,'<' ,mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - 6, date( 'Y' ) )]];
+ $result = $this->delFromId($filter);
+ return !empty($result);
+ }
+ //删除id
+ public function delFromId($filter)
+ {
+ $result = $this->destoryFromId($filter);
+ return !empty($result);
+ }
+
+ //删除fromId(真删除)
+ public function destoryFromId($filter)
+ {
+ $result = $this->where($filter)->delete();
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingCardRate.php b/app/Common/model/LongbingCardRate.php
new file mode 100755
index 0000000..8be519a
--- /dev/null
+++ b/app/Common/model/LongbingCardRate.php
@@ -0,0 +1,42 @@
+save($data);
+ return !empty($result);
+ }
+
+
+ //获取单条数据
+ public function getRate($filter)
+ {
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //更新
+ public function updateRate($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ //删除
+ public function deleRate($filter)
+ {
+ $result = $this->where($filter)->delete();
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingCardUserMark.php b/app/Common/model/LongbingCardUserMark.php
new file mode 100755
index 0000000..5f2d753
--- /dev/null
+++ b/app/Common/model/LongbingCardUserMark.php
@@ -0,0 +1,67 @@
+save($data);
+ return !empty($result);
+ }
+ //修改
+ public function updateMark($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+ //获取总数
+ public function getMarkCount($filter)
+ {
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+
+ public function listMarkData($filter ,$field = null)
+ {
+ $result = $this->where($filter);
+ if(empty($field) && is_array($field)) $result = $result->field($field);
+ $result = $result->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function getMarkData($filter ,$field = null)
+ {
+ $result = $this->where($filter);
+ if(empty($field) && is_array($field)) $result = $result->field($field);
+ $result = $result->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-07 10:18
+ * @功能说明:获取跟进的用户
+ */
+ public function getMarkUser($dis){
+
+
+ $data = $this->alias('a')
+ ->join('longbing_card_user b','a.user_id = b.id')
+ ->where($dis)
+ ->column('a.id');
+
+ return $data;
+
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingCardWechatCode.php b/app/Common/model/LongbingCardWechatCode.php
new file mode 100755
index 0000000..72515a4
--- /dev/null
+++ b/app/Common/model/LongbingCardWechatCode.php
@@ -0,0 +1,60 @@
+createRow($data);
+ return !empty($result);
+ }
+ //获取
+ public function getCode($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->getRow($filter);
+ return $result;
+ }
+ //列表
+ public function listCode($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->listRow($filter);
+ return $result;
+ }
+ //总数
+ public function getCodeCount($filter)
+ {
+ $filter['deleted'] = 0;
+ $count = $this->where($filter)->count();
+ return $count;
+ }
+ //修改
+ public function updateCode($filter ,$data)
+ {
+ $filter['deleted'] = 0;
+ $data['update_time'] = time();
+ $result = $this->updateRow($filter ,$data);
+ return !empty($result);
+ }
+ //删除
+ public function delCode($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->deleteRow($filter);
+ return !empty($result);
+ }
+ //删除(真删除)
+ public function destoryCode($filter)
+ {
+ $result = $this->destoryRow($filter);
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingClientInfo.php b/app/Common/model/LongbingClientInfo.php
new file mode 100755
index 0000000..96dfef6
--- /dev/null
+++ b/app/Common/model/LongbingClientInfo.php
@@ -0,0 +1,41 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function listClientData($filter ,$field = null)
+ {
+ $result = $this->where($filter);
+ if(empty($field) && is_array($field)) $result = $result->field($field);
+ $result = $result->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function getClientData($filter ,$field = null)
+ {
+ $result = $this->where($filter);
+ if(empty($field) && is_array($field)) $result = $result->field($field);
+ $result = $result->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ public function updateClientInfo($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingTabbar.php b/app/Common/model/LongbingTabbar.php
new file mode 100755
index 0000000..6860011
--- /dev/null
+++ b/app/Common/model/LongbingTabbar.php
@@ -0,0 +1,17 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingUser.php b/app/Common/model/LongbingUser.php
new file mode 100755
index 0000000..a6a7804
--- /dev/null
+++ b/app/Common/model/LongbingUser.php
@@ -0,0 +1,750 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function listCustomerData($filter ,$page_config)
+ {
+ $uniacid = $filter['uniacid'];
+ //设置查询条件
+ $where = [
+ ['user.uniacid' ,'=' , $uniacid],
+ ['user.is_staff' ,'=' , 0]
+ ];
+ //判断是否根据昵称查询
+// if(isset($filter['nickName']))
+// {
+// $where[] = ['nickName' ,'like' ,'%' . $filter['nickName'] . '%'];
+// }
+ //判断是否查询电话号码授权
+ if(isset($filter['is_phone']) && !empty($filter['is_phone'])) $where[] = ['phone.phone' ,'<>' ,'null'];
+
+ //判断是否授权头像/登陆信息
+ if(isset($filter['avatarUrl']) && !empty($filter['avatarUrl'])) $where[] = ['user.avatarUrl' ,'<>' ,''];
+
+ //设置转换参数
+
+ $mark_arr = array(
+ 0 => array(
+ 'id' => 3,
+ 'value' => '未跟进'
+ ),
+ 1 => array(
+ 'id' => 1,
+ 'value' => '跟进中'
+ ),
+ 2 => array(
+ 'id' => 2,
+ 'value' => '已成交'
+ ),
+ );
+
+ $deal_arr = array(
+ 0 => array(
+ 'id' => 1,
+ 'value' => '未成交'
+ ),
+ 1 => array(
+ 'id' => 2,
+ 'value' => '已成交'
+ ),
+ );
+ $count = 0;
+ $users = [];
+ $mark_value = '';
+ $deal_value = '';
+// var_dump(isset($filter['mark']) || isset($filter['deal']) || isset($filter['nickName']));
+ if (isset($filter['mark']) || isset($filter['deal']) || isset($filter['nickName']))
+ {
+ $user_ids = array();
+ if (isset($filter['mark']))
+ {
+ $mark_value = $filter['mark'];
+ //未跟进
+ if ($filter['mark'] == 3)
+ {
+ //$list_mark = pdo_getall('longbing_card_user_mark', ['uniacid' => $uniacid]);
+ //获取已经跟进的客户数据
+ $mark_model = new MarkModel();
+
+ $list_mark = $mark_model->listMarkData(['uniacid' => $uniacid ,'status' => 1] ,['user_id']);
+
+ $tmp_arr = array();
+ foreach ($list_mark as $k => $v)
+ {
+ array_push($tmp_arr, $v['user_id']);
+ }
+ //查询为跟进的数据
+ if (count($tmp_arr) > 1)
+ {
+ $tmp_arr = '(' . implode(',', $tmp_arr) . ')';
+ $list_mark = $this->where([['uniacid' , '=' ,$uniacid] , ['id' ,'not in' , $tmp_arr] , ['is_staff' ,'=' , 0]])->field(['id'])->select();
+ }
+ else if (count($tmp_arr) == 1)
+ {
+ $tmp_arr = implode(',', $tmp_arr);
+ $list_mark = $this->where([['uniacid' , '=' ,$uniacid] , ['id' ,'!=' , $tmp_arr] , ['is_staff' ,'=' , 0]])->field(['id'])->select();
+ }
+ else
+ {
+ $list_mark = $this->where([['uniacid' , '=' ,$uniacid] , ['is_staff' ,'=' , 0]])->field(['id'])->select();;
+ }
+ //判断数据是否为空
+ if(empty($list_mark)) $list_mark = [];
+ //获取未跟进用户id列表
+ foreach ($list_mark as $k => $v)
+ {
+ array_push($user_ids, $v['id']);
+ }
+ }
+ //已跟进数据
+ else
+ {
+ $mark_model = new MarkModel();
+ $list_mark = $mark_model->listMarkData(['uniacid' => $uniacid ,'status' => 1] ,['user_id']);
+ foreach ($list_mark as $k => $v)
+ {
+ array_push($user_ids, $v['user_id']);
+ }
+ }
+ }
+ //成交
+ if (isset($filter['deal']))
+ {
+ $deal_value = $filter['deal'];
+ //未成交
+ if ($filter['deal'] == 1)
+ {
+ //获取已成交的数据
+ $mark_model = new MarkModel();
+ $list_mark = $mark_model->listMarkData(['uniacid' => $uniacid ,'mark' => 2 ,'status' => 1] ,['user_id']);
+ if(empty($list_mark)) $list_mark = [];
+ //跟进状态查询
+ if (isset($filter['mark']))
+ {
+ //获取用户id数据
+ $tmp1 = array();
+ foreach($list_mark as $v)
+ {
+ if(!in_array($v['user_id'], $tmp1)) $tmp1[] = $v['user_id'];
+ }
+ $tmp2 = [];
+ foreach($user_ids as $v)
+ {
+ if(!in_array($v, $tmp1)) $tmp2[] = $v;
+ }
+ $user_ids = $tmp2;
+ }
+ else
+ {
+
+ $tmp_arr = array();
+ foreach ($list_mark as $k => $v)
+ {
+ array_push($tmp_arr, $v['user_id']);
+ }
+
+ if (count($tmp_arr) > 1)
+ {
+ $tmp_arr = '(' . implode(',', $tmp_arr) . ')';
+ $list_mark = $this->where([['uniacid' , '=' ,$uniacid] , ['id' ,'not in' , $tmp_arr] , ['is_staff' ,'=' , 0]])->field(['id'])->select();
+ }
+ else if (count($tmp_arr) == 1)
+ {
+ $tmp_arr = implode(',', $tmp_arr);
+ $list_mark = $this->where([['uniacid' , '=' ,$uniacid] , ['id' ,'!=' , $tmp_arr] , ['is_staff' ,'=' , 0]])->field(['id'])->select();
+ }
+ else
+ {
+ $list_mark = $this->where([['uniacid' , '=' ,$uniacid] , ['is_staff' ,'=' , 0]])->field(['id'])->select();;
+ }
+ if(empty($list_mark)) $list_mark = [];
+
+ foreach ($list_mark as $k => $v)
+ {
+ array_push($user_ids, $v['id']);
+ }
+ }
+ }
+ //已成交
+ else
+ {
+ //获取已经成交的数据
+ $mark_model = new MarkModel();
+ $list_mark = $mark_model->listMarkData(['uniacid' => $uniacid ,'mark' => 2 ,'status' => 1] ,['user_id']);
+ //如果根据跟进状态查询
+ if (isset($filter['mark']))
+ {
+ //取两者交集
+ $tmp1 = array();
+ $tmp2 = array();
+ foreach ($list_mark as $k => $v)
+ {
+ if(!in_array($v['user_id'], $tmp1)) $tmp1[] = $v['user_id'];
+ }
+ foreach($tmp1 as $v)
+ {
+ if(in_array($v, $user_ids) && !in_array($v, $tmp2)) $tmp2[] = $v;
+ }
+
+ $user_ids = $tmp2;
+ }
+ else
+ {
+ foreach ($list_mark as $k => $v)
+ {
+ array_push($user_ids, $v['user_id']);
+ }
+ }
+ }
+ }
+
+ if (isset($filter['nickName']))
+ {
+// $keyword = $filter['search'];
+ $search = '%' . $filter['nickName'] . '%';
+// $users1 = pdo_getall('longbing_card_client_info', ['uniacid' => $uniacid, 'name like' => $search]);
+ $client_model = new ClientModel();
+ $users1 = $client_model->listClientData([['uniacid' ,'=' ,$uniacid] ,['name' ,'like' ,$search]] ,['user_id']);
+// $users2 = pdo_getall('longbing_card_user', ['uniacid' => $uniacid, 'nickName like' => $search]);
+ $users2 = $this->where([['uniacid' ,'=' ,$uniacid] ,['nickName' ,'like' ,$search]])->field(['id'])->select();
+
+ $tmp = array();
+ foreach ($users1 as $k => $v)
+ {
+ if (!in_array($v['user_id'], $tmp))
+ {
+ array_push($tmp, $v['user_id']);
+ }
+ }
+ foreach ($users2 as $k => $v)
+ {
+ if (!in_array($v['id'], $tmp))
+ {
+ array_push($tmp, $v['id']);
+ }
+ }
+ $tmp = array_unique($tmp);
+
+ if (isset($filter['mark']) || isset($filter['deal']))
+ {
+ $tmp1 = array();
+ $tmp2 = $user_ids;
+ foreach ($tmp as $k => $v)
+ {
+ if (in_array($v, $tmp2))
+ {
+ if(!in_array($v, $tmp1)) array_push($tmp1, $v);
+ }
+ }
+ $user_ids = $tmp1;
+ }
+ else
+ {
+ foreach ($tmp as $k => $v)
+ {
+ if(!in_array($v, $user_ids)) array_push($user_ids, $v);
+ }
+ }
+ }
+// var_dump($user_ids);die;
+ $where[] = ['user.id' ,'in' , $user_ids];
+
+ //获取用户数据
+// $users = pdo_getslice('longbing_card_user', $where, $limit, $count, [], '');
+ $result = $this->alias('user')
+ ->leftJoin('longbing_card_user_phone phone' ,'user.id = phone.user_id')
+ ->where($where);
+
+ $count = $result->count();
+ $users = $result->page($page_config['page'] ,$page_config['page_count'])
+ ->field('user.* ,phone.phone')
+ ->order('user.id desc')
+ ->select()->toArray();
+ }
+ else
+ {
+ $result = $this->alias('user')
+ ->leftJoin('longbing_card_user_phone phone' ,'user.id = phone.user_id')
+ ->where($where);
+
+ $count = $result->count();
+ $users = $result->page($page_config['page'] ,$page_config['page_count'])
+ ->field('user.* ,phone.phone')
+ ->order('user.id desc')
+ ->select()->toArray();
+ }
+
+
+
+// var_dump(json_encode($users));die;
+ foreach ($users as $k => $v)
+ {
+
+
+ $users[$k]['user_name'] = '';
+// $client_info = pdo_get('longbing_card_client_info', ['user_id' => $v['id']]);
+ $client_model = new ClientModel();
+ $client_info = $client_model->getClientData([['uniacid' ,'=' ,$uniacid] ,['user_id' ,'=' ,$v['id']]] ,['name']);
+ if ($client_info)
+ {
+ $users[$k]['user_name'] = $client_info['name'];
+ }
+
+ $users[$k]['deal_time'] = '';
+ //获取客户跟进数据
+ $collection_model = new CollectionModel();
+ $collections = $collection_model->listCollection(['uniacid' => $uniacid ,'uid' =>$v['id'] ,'status' => 1]);
+ //获取数据
+
+
+ $users[$k]['mark'] = 0;
+ if(isset($filter['mark']) && in_array($filter['mark'], [1,2,'1','2'])) $users[$k]['mark'] = $filter['mark'];
+ if(isset($filter['deal']) && in_array($filter['deal'] ,[2,'2'])) $users[$k]['mark'] = 2;
+ $mark_staff = '';
+
+ $mark_model = new MarkModel();
+ $list_mark = $mark_model->where(['uniacid' => $uniacid ,'status' => 1 ,'user_id'=>$v['id'],'staff_id'=>$v['last_staff_id']])->value('mark');
+
+ $users[$k]['mark'] = !empty($list_mark)?$list_mark:0;
+
+ foreach($collections as $collection)
+ {
+
+ //获取跟进员工数据
+ $staff = longbingGetUserInfo($collection['to_uid'] ,$uniacid);
+
+
+ //判断是否是员工
+ if(!empty($staff) && isset($staff['is_staff']) && !empty($staff['is_staff']))
+ {
+ if(!empty($mark_staff)) $mark_staff = $mark_staff . ',' ;
+ $mark_staff = $mark_staff . $staff['name'];
+ //获取跟进数据
+ $mark_model = new MarkModel();
+ $mark = $mark_model->getMarkData(['user_id' => $v['id'] ,'staff_id' => $collection['to_uid'] ,'status' => 1] ,['id' ,'mark']);
+
+
+ if(!empty($mark))
+ {
+ if(in_array($mark['mark'], [2,'2']))
+ {
+ $mark_staff = $mark_staff . '(' . lang('traded') . ')';
+ }else{
+ $mark_staff = $mark_staff . '(' . lang('not traded') . ')';
+ }
+ if($mark['mark'] > $users[$k]['mark']) $users[$k]['mark'] = $mark['mark'];
+ }else{
+ $mark_staff = $mark_staff . '(' . lang('not traded') . ')';
+ }
+ }
+ }
+ $users[$k]['mark_staff'] = $mark_staff;
+
+ // 用户成交率
+// $users[$k]['rate'] = rate($v['id'], $uniacid);
+ $users[$k]['rate'] = 0;
+
+ if ($v['import'] == 1)
+ {
+ // $users[$k]['avatarUrl'] = transImagesOne($v ,['avatarUrl'] ,$uniacid);
+ }
+ }
+//die;
+ $result = array(
+ 'data' => $users,
+ 'count' => $count
+ );
+ return $result;
+ }
+
+
+ /**
+ * @param $filter
+ * @param $page_config
+ * @功能说明:客户数据
+ * @author chenniang
+ * @DataTime: 2020-08-07 11:23
+ */
+ public function listCustomerDataV2($filter)
+ {
+
+ $mark_model = new MarkModel();
+
+ $client_model = new ClientModel();
+
+ $collection_model = new CollectionModel();
+
+ $uniacid = $filter['uniacid'];
+ //设置查询条件
+ $where = [
+
+ ['user.uniacid' ,'=' , $uniacid],
+
+ ['user.is_staff' ,'=' , 0]
+ ];
+
+ if (!empty($filter['mark']))
+ {
+
+ $dis = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ if($filter['mark'] != 3){
+
+ $dis['mark'] = $filter['mark'];
+
+ }
+ //已经跟进
+ $user_ids = $mark_model->where($dis)->column('user_id');
+ //未跟进
+ if ($filter['mark'] == 3)
+ {
+
+ $user_ids = $this->where([['uniacid' , '=' ,$uniacid] , ['id' ,'not in' , $user_ids] , ['is_staff' ,'=' , 0]])->field(['id'])->column('id');
+
+ }
+
+ $where[] = ['user.id' ,'in' , $user_ids];
+
+ }
+ //昵称搜索
+ if (isset($filter['nickName']))
+ {
+
+ $where[] = ['user.nickName' ,'like' ,'%'.$filter['nickName'].'%'];
+
+ }
+ //判断是否查询电话号码授权
+ if(!empty($filter['empower'])&&$filter['empower']==1){
+
+ $where[] = ['phone.phone' ,'<>' ,'null'];
+ }
+
+ //判断是否授权头像/登陆信息
+ if(!empty($filter['empower'])&&$filter['empower']==2){
+
+ $where[] = ['user.avatarUrl' ,'<>' ,''];
+
+ }
+
+ //判断是否授权头像/登陆信息
+ if(!empty($filter['start_time'])&&!empty($filter['end_time'])){
+
+ $start_time = $filter['start_time'];
+
+ $end_time = $filter['end_time'];
+
+ $where[] = ['user.create_time' ,'between' ,"$start_time,$end_time"];
+
+ }
+
+ $usersdata = $this->alias('user')
+ ->leftJoin('longbing_card_user_phone phone' ,'user.id = phone.user_id')
+ ->where($where)
+ ->field('user.* ,phone.phone')
+ ->order('user.id desc')
+ ->paginate($filter['limit'])
+ ->toArray();
+
+ $users = $usersdata['data'];
+
+ if(!empty($users)){
+
+ foreach ($users as $k => $v)
+ {
+
+ $users[$k]['user_name'] = $client_model->where([['uniacid' ,'=' ,$uniacid] ,['user_id' ,'=' ,$v['id']]] ,['name'])->value('name');
+
+ $users[$k]['mark'] = !empty($filter['mark'])?$filter['mark']:0;
+
+ $users[$k]['deal_time'] = '';
+ //获取数据
+ $mark_staff = '';
+
+ $list_mark = $mark_model->where(['uniacid' => $uniacid ,'status' => 1 ,'user_id'=>$v['id'],'staff_id'=>$v['last_staff_id']])->value('mark');
+
+ $users[$k]['mark'] = !empty($list_mark)?$list_mark:0;
+
+ $users[$k]['update_time'] = $mark_model->where(['uniacid' => $uniacid ,'status' => 1 ,'user_id'=>$v['id'],'mark'=>2])->value('update_time');
+
+ $users[$k]['update_time'] = !empty($users[$k]['update_time'])?$users[$k]['update_time']:'-';
+
+ $collections = $collection_model->listCollection(['uniacid' => $uniacid ,'uid' =>$v['id'] ,'status' => 1]);
+
+ $rate_text = '';
+
+ $remark_name = '';
+
+ foreach($collections as $collection)
+ {
+ //获取跟进员工数据
+ $staff = longbingGetUserInfo($collection['to_uid'] ,$uniacid);
+ //判断是否是员工
+ if(!empty($staff) && isset($staff['is_staff']) && !empty($staff['is_staff']))
+ {
+ if(!empty($mark_staff)) $mark_staff = $mark_staff . ',' ;
+
+ if(empty($staff['name'])){
+
+ $staff['name'] = $this->where(['id'=>$collection['to_uid']])->value('nickName');
+ }
+
+ $mark_staff = $mark_staff . $staff['name'];
+
+ $mark = $mark_model->getMarkData(['user_id' => $v['id'] ,'staff_id' => $collection['to_uid'] ,'status' => 1] ,['id' ,'mark']);
+
+ if(!empty($mark))
+ {
+ if(in_array($mark['mark'], [2,'2']))
+ {
+ $mark_staff = $mark_staff . '(' . lang('traded') . ')';
+ }else{
+ $mark_staff = $mark_staff . '(' . lang('In the follow up') . ')';
+ }
+ if($mark['mark'] > $users[$k]['mark']) $users[$k]['mark'] = $mark['mark'];
+ }else{
+
+ $mark_staff = $mark_staff . '(' . lang('not follow up') . ')';
+ }
+
+ $rate_text .= $staff['name'].'('.$collection['rate'].'%)';
+
+ }
+
+ $dis = [
+
+ 'user_id' => $v['id'],
+
+ 'staff_id' => $collection['to_uid'],
+ ];
+
+// dump($dis);exit;
+
+ $staff_name = Db::name('longbing_card_client_info')->where($dis)->value('name');
+
+ if(!empty($staff_name)||!empty($staff['name'])){
+
+ $remark_name .= $staff['name'].'('.$staff_name.')';
+ }
+
+ }
+ $users[$k]['mark_staff'] = $mark_staff;
+
+ $users[$k]['rate'] = 0;
+
+ $users[$k]['rate_text'] = $rate_text;
+
+ $users[$k]['remark_name'] = $remark_name;
+
+ }
+ }
+
+ $usersdata['data'] = $users ;
+
+ return $usersdata;
+ }
+
+
+
+
+
+ //获取客户列表
+ public function listCustomer($filter ,$page_config)
+ {
+// $filter_data['user.is_staff'] = 0;
+// $filter_data['user.deleted'] = 0;
+// if(isset($filter['uniacid'])) $filter_data['user.uniacid'] = $filter['uniacid'];
+// $result = $this->alias('user')
+// ->where($filter_data);
+// if(isset($filter['nickName'])) $result = $result->where('user.nickName' ,'like' , '%' . $filter['nickName'] .'%');
+// switch($filter['follow'])
+// {
+// case 0:
+// switch($filter['mark']):
+// case 0:
+//
+// break;
+// case 1:
+//
+// break;
+// case 2:
+//
+// break;
+// default:
+// return [];
+// break;
+// break;
+// case 1:
+// switch($filter['mark']):
+// case 0:
+//
+// break;
+// case 1:
+//
+// break;
+// case 2:
+//
+// break;
+// default:
+// return [];
+// break;
+// break;
+// case 2:
+// switch($filter['mark']):
+// case 0:
+//
+// break;
+// case 1:
+//
+// break;
+// case 2:
+//
+// break;
+// default:
+// return [];
+// break;
+// break;
+// default:
+// return [];
+//
+// }
+//
+// if(isset($filter['mark']))
+// {
+// switch($filter['mark'])
+// {
+// case 0:
+// $result = $result->leftJoin('longbing_card_user_mark mark' ,'mark.user_id = user.id');
+// $result = $result->whereOr([['mark.mark' ,'in' ,[0 ,1] ],['mark.mark' , '=' , null]]);
+// break;
+// case 1:
+// $result = $result->Join('longbing_card_user_mark mark' ,'mark.user_id = user.id');
+// $result = $result->where('mark.mark' ,'=' ,2);
+// break;
+// case 2:
+// $result = $result->Join('longbing_card_user_mark mark' ,'mark.user_id = user.id');
+// $result = $result->where('mark.mark' ,'=' ,2);
+// break;
+// default:
+// $result = $result->leftJoin('longbing_card_user_mark mark' ,'mark.user_id = user.id');
+// break;
+// }
+// }
+//
+// $result = $result->leftjoin('longbing_card_user_phone phone' ,'user.id = phone.user_id');
+// if(isset($filter['is_phone']) && !empty($filter['is_phone'])) $result->where('phone.phone' ,'<>' ,null);
+// $result = $result->order('id' ,'desc')
+// ->page($page_config['page'] ,$page_config['page_count'])
+//// ->field('user.*,mark.staff_id,mark.mark,phone.phone')
+// ->field('user.id ,mark.mark')
+// ->select();
+// if(!empty($result)) $result = $result->toArray();
+// return $result;
+ }
+ public function getCoustomerCount($filter)
+ {
+ $filter_data['user.is_staff'] = 0;
+ $filter_data['user.deleted'] = 0;
+ if(isset($filter['uniacid'])) $filter_data['user.uniacid'] = $filter['uniacid'];
+ $result = $this->alias('user')
+ ->where($filter_data);
+ if(isset($filter['nickName'])) $result = $result->where('user.nickName' ,'like' , '%' . $filter['nickName'] .'%');
+ $result = $result->leftJoin('longbing_card_user_mark mark' ,'mark.user_id = user.id');
+ if(isset($filter['mark']))
+ {
+ switch($filter['mark'])
+ {
+ case 0:
+ $result = $result->whereOr([['mark.mark' ,'in' ,[0]] ,['mark.mark' , '=' , null]]);
+ break;
+ case 1:
+ $result = $result->where('mark.mark' ,'=' ,1);
+ break;
+ case 2:
+ $result = $result->where('mark.mark' ,'=' ,2);
+ break;
+ case 3:
+ $result = $result->whereOr([['mark.mark' ,'in' ,[0,1]] ,['mark.mark' ,'=' ,null]]);
+ break;
+ default:
+ break;
+ }
+ }
+ $result = $result->leftjoin('longbing_card_user_phone phone' ,'user.id = phone.user_id');
+ if(isset($filter['is_phone']) && !empty($filter['is_phone'])) $result->where('phone.phone' ,'<>' ,null);
+ $count = $result->count();
+ return $count;
+ }
+
+ //获取客户信息
+ public function getCustomer($filter)
+ {
+ $filter_data['user.is_staff'] = 0;
+ $filter_data['user.deleted'] = 0;
+ if(isset($filter['uniacid'])) $filter_data['user.uniacid'] = $filter['uniacid'];
+ if(isset($filter['customer_id'])) $filter_data['user.id'] = $filter['customer_id'];
+// var_dump($filter_data);die;
+ $result = $this->alias('user')
+ ->where($filter_data);
+// $result = $result->leftJoin('longbing_card_user_mark mark' ,'mark.user_id = user.id');
+ $result = $result->leftjoin('longbing_card_user_phone phone' ,'user.id = phone.user_id');
+// $result = $result->find();
+ $result = $result->field('user.* ,phone.phone')
+ ->find();
+ if(!empty($result))
+ {
+ $result = $result->toArray();
+// //获取客服信息
+// $collection_model = new CollectionModel();
+// //获取mark信息
+// $mark_model = new MarkModel();
+
+ }
+
+ return $result;
+ }
+ //修改客户信息
+ public function updateCustomer($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+ //修改用户信息
+ public function updateUser($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+ //获取总数
+ public function getUserCount($filter = [])
+ {
+ $count = $this->where($filter)->count();
+ return $count;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingUserInfo.php b/app/Common/model/LongbingUserInfo.php
new file mode 100755
index 0000000..b903bf2
--- /dev/null
+++ b/app/Common/model/LongbingUserInfo.php
@@ -0,0 +1,68 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //获取名片信息
+ public function getStaff($fans_id ,$uniacid)
+ {
+ $result = $this->alias('card')
+ ->field( [ 'card.*', 'job.name as job_name' ] )
+ ->join( 'longbing_card_job job', 'card.job_id = job.id', 'LEFT' )
+ ->where( [ [ 'card.fans_id', '=', $fans_id ], [ 'card.uniacid', '=', $uniacid ] ]
+ )
+ ->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //修改
+ public function updateUser($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+ //统计
+ public function getUserCount($filter = [])
+ {
+ $count = $this->where($filter)->count();
+ return $count;
+ }
+ //按顺序获取一个员工
+ public function getOneStaff($uniacid = 7777)
+ {
+ $where[] = [ 'uniacid' ,'=' ,$uniacid ];
+ $where[] = [ 'is_staff' ,'=' , 1 ];
+ $where[] = [ 'is_default' ,'=' ,1 ];
+ $where[] = [ 'fans_id' ,'<>' ,0 ];
+ $result = $this->where($where)
+ ->order('auto_count asc')
+ ->field('id,fans_id as staff_id')
+ ->find();
+ if(!empty($result))
+ {
+ $result = $result->toArray();
+ $this->where(['id' => $result['id']])->inc( 'auto_count' );
+ }
+ return $result;
+ }
+ //统计
+ public function getCount($filter)
+ {
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/model/LongbingWeqingWxApp.php b/app/Common/model/LongbingWeqingWxApp.php
new file mode 100755
index 0000000..baddeb4
--- /dev/null
+++ b/app/Common/model/LongbingWeqingWxApp.php
@@ -0,0 +1,17 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/service/LongbingUserInfoService.php b/app/Common/service/LongbingUserInfoService.php
new file mode 100755
index 0000000..4eea4b1
--- /dev/null
+++ b/app/Common/service/LongbingUserInfoService.php
@@ -0,0 +1,50 @@
+where(['fans_id'=>$userId])->value('name');
+
+ return $name;
+ }
+
+ /**
+ * @param $userId
+ * @功能说明:判断是否为员工
+ * @author jingshuixian
+ * @DataTime: 2020/1/14 14:54
+ */
+ public static function isStraffByUserId($userId){
+
+ $userInfo = new LongbingUserInfo();
+ $is_staff = $userInfo->where(['fans_id'=>$userId])->value('is_staff');
+ return $is_staff ? true : false ;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/Common/service/LongbingUserService.php b/app/Common/service/LongbingUserService.php
new file mode 100755
index 0000000..82eff88
--- /dev/null
+++ b/app/Common/service/LongbingUserService.php
@@ -0,0 +1,61 @@
+where(['id'=>$userId])->value('openid');
+
+ return $openid;
+ }
+
+ /**
+ * @param $userId
+ * @功能说明:根据用户ID获得用户昵称
+ * @author jingshuixian
+ * @DataTime: 2020/2/27 11:48
+ */
+ public static function getUserNickNameOpenId($userId){
+ $user = new LongbingUser();
+ $nickName = $user->where(['id'=>$userId])->value('nickName');
+ return $nickName;
+ }
+
+ /**
+ * @param $userId
+ * @功能说明:判断用户是否存在
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 14:58
+ */
+ public static function isUser($uniacid ,$userId){
+ $user = new LongbingUser();
+ $info = $user->where(['uniacid' => $uniacid ])->find($userId);
+
+ return $info ? true : false ;
+ }
+}
\ No newline at end of file
diff --git a/app/Common/wexinPay.php b/app/Common/wexinPay.php
new file mode 100755
index 0000000..1e00ba3
--- /dev/null
+++ b/app/Common/wexinPay.php
@@ -0,0 +1,146 @@
+
+
+
+
+
+KJK;
+$data = simplexml_load_string($xml);
+$uniacid = (string)$data->uniacid;
+unset($data->uniacid);
+$xml = $data->asXML();*/
+if(!empty($_GET['ck'])&&$_GET['ck']==789){
+ echo 1;exit;
+}
+
+function lb_api_notice_increment22($url, $data){
+ $ch = curl_init();
+ $header = "Accept-Charset: utf-8";
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+ //curl_setopt($url, CURLOPT_HTTPHEADER, $header);
+ curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ $tmpInfo = curl_exec($ch);
+ if (curl_errno($ch)) {
+ return false;
+ }else{
+ return $tmpInfo;
+ }
+}
+function lb_logOutput22($data,$flag=0) {
+ if($flag==0){
+ return ;
+ }
+ if (is_array($data)) {
+ $data = json_encode($data);
+ }
+ $filename = "./".date("Y-m-d").".log";
+ $str = date("Y-m-d H:i:s")." $data"."\r\n";
+ file_put_contents($filename, $str, FILE_APPEND|LOCK_EX);
+ return null;
+}
+
+
+function lb_makeRequest22($url, $params = array(), $expire = 0, $extend = array(), $hostIp = '')
+{
+ if (empty($url)) {
+ return array('code' => '100');
+ }
+
+ $_curl = curl_init();
+ $_header = array(
+ 'Accept-Language: zh-CN',
+ 'Connection: Keep-Alive',
+ 'Cache-Control: no-cache'
+ );
+ // ����ֱ�ӷ���Ҫ����host�ĵ�ַ
+ if (!empty($hostIp)) {
+ $urlInfo = parse_url($url);
+ if (empty($urlInfo['host'])) {
+ $urlInfo['host'] = substr(DOMAIN, 7, -1);
+ $url = "http://{$hostIp}{$url}";
+ } else {
+ $url = str_replace($urlInfo['host'], $hostIp, $url);
+ }
+ $_header[] = "Host: {$urlInfo['host']}";
+ }
+
+ // ֻҪ�ڶ�����������ֵ֮����POST��
+ if (!empty($params)) {
+ curl_setopt($_curl, CURLOPT_POSTFIELDS, http_build_query($params));
+ curl_setopt($_curl, CURLOPT_POST, true);
+ }
+
+ if (substr($url, 0, 8) == 'https://') {
+ curl_setopt($_curl, CURLOPT_SSL_VERIFYPEER, FALSE);
+ curl_setopt($_curl, CURLOPT_SSL_VERIFYHOST, FALSE);
+ }
+ curl_setopt($_curl, CURLOPT_URL, $url);
+ curl_setopt($_curl, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($_curl, CURLOPT_USERAGENT, 'API PHP CURL');
+ curl_setopt($_curl, CURLOPT_HTTPHEADER, $_header);
+
+ if ($expire > 0) {
+ curl_setopt($_curl, CURLOPT_TIMEOUT, $expire); // ����ʱʱ��
+ curl_setopt($_curl, CURLOPT_CONNECTTIMEOUT, $expire); // �������ӳ�ʱʱ��
+ }
+
+ // ���������
+ if (!empty($extend)) {
+ curl_setopt_array($_curl, $extend);
+ }
+
+ $result['result'] = curl_exec($_curl);
+ $result['code'] = curl_getinfo($_curl, CURLINFO_HTTP_CODE);
+ $result['info'] = curl_getinfo($_curl);
+ if ($result['result'] === false) {
+ $result['result'] = curl_error($_curl);
+ $result['code'] = -curl_errno($_curl);
+ }
+
+ curl_close($_curl);
+ return $result;
+}
+
+lb_logOutput22("in--weixinPay");
+
+//��ȡ�Ŵ����xml����
+$xmlData = file_get_contents('php://input');
+
+if(empty($xmlData)){
+ $xmlData = 'empty xmlData';
+}
+lb_logOutput22('xmlData in weixinPay:-----'.$xmlData);
+
+$xml_data=simplexml_load_string($xmlData);
+
+//$params=urldecode((string)$xml_data->params);
+$params=json_decode($xml_data->params,true);
+$i=$params['i'];
+$t=$params['t'];
+$v=$params['v'];
+$n=$params['n'];
+unset($xml_data->params);
+
+$xmlData = $xml_data->asXML();
+
+lb_logOutput22('weixinPay-$params:-----'.$params);
+
+
+
+$data=$xmlData;
+
+$reply_path= "https://".$_SERVER['HTTP_HOST']."/app/index.php?i=$i&t=".$t."&v=".$v."&from=wxapp&c=entry&a=wxapp&do=api&core=core2&m=".$n."&s=shop/IndexWxPay/returnPay";
+//lb_api_notice_increment22($params,$data);
+lb_api_notice_increment22($reply_path,$data);
+
+
+
diff --git a/app/Common/wxBizDataCrypt.php b/app/Common/wxBizDataCrypt.php
new file mode 100755
index 0000000..b4d5dbe
--- /dev/null
+++ b/app/Common/wxBizDataCrypt.php
@@ -0,0 +1,69 @@
+sessionKey = $sessionKey;
+ $this->appid = $appid;
+ }
+
+
+ /**
+ * 检验数据的真实性,并且获取解密后的明文.
+ * @param $encryptedData string 加密的用户数据
+ * @param $iv string 与用户数据一同返回的初始向量
+ * @param $data string 解密后的原文
+ *
+ * @return int 成功0,失败返回对应的错误码
+ */
+ public function decryptData( $encryptedData, $iv, &$data )
+ {
+ if (strlen($this->sessionKey) != 24) {
+ return ErrorCode::$IllegalAesKey;
+ }
+ $aesKey=base64_decode($this->sessionKey);
+
+
+ if (strlen($iv) != 24) {
+ return ErrorCode::$IllegalIv;
+ }
+ $aesIV=base64_decode($iv);
+
+ $aesCipher=base64_decode($encryptedData);
+
+ $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
+
+ $dataObj=json_decode( $result );
+ if( $dataObj == NULL )
+ {
+ return ErrorCode::$IllegalBuffer;
+ }
+ if( $dataObj->watermark->appid != $this->appid )
+ {
+ return ErrorCode::$IllegalBuffer;
+ }
+ $data = $result;
+ return ErrorCode::$OK;
+ }
+
+}
+
diff --git a/app/ExceptionHandle.php b/app/ExceptionHandle.php
new file mode 100755
index 0000000..375e841
--- /dev/null
+++ b/app/ExceptionHandle.php
@@ -0,0 +1,68 @@
+
+// +----------------------------------------------------------------------
+
+namespace app;
+
+use think\db\exception\DataNotFoundException;
+use think\db\exception\ModelNotFoundException;
+use think\exception\Handle;
+use think\exception\HttpException;
+use think\exception\HttpResponseException;
+use think\exception\ValidateException;
+use think\Response;
+use Throwable;
+
+/**
+ * 应用异常处理类
+ */
+class ExceptionHandle extends Handle
+{
+ /**
+ * 不需要记录信息(日志)的异常类列表
+ * @var array
+ */
+ protected $ignoreReport = [
+ HttpException::class,
+ HttpResponseException::class,
+ ModelNotFoundException::class,
+ DataNotFoundException::class,
+ ValidateException::class,
+ ];
+
+ /**
+ * 记录异常信息(包括日志或者其它方式记录)
+ *
+ * @access public
+ * @param Throwable $exception
+ * @return void
+ */
+ public function report(Throwable $exception): void
+ {
+ // 使用内置的方式记录异常日志
+ parent::report($exception);
+ }
+
+ /**
+ * Render an exception into an HTTP response.
+ *
+ * @access public
+ * @param \think\Request $request
+ * @param Throwable $e
+ * @return Response
+ */
+ public function render($request, Throwable $e): Response
+ {
+ // 添加自定义异常处理机制
+
+ // 其他错误交给系统处理
+ return parent::render($request, $e);
+ }
+}
diff --git a/app/Info.php b/app/Info.php
new file mode 100755
index 0000000..f0fc4e6
--- /dev/null
+++ b/app/Info.php
@@ -0,0 +1,70 @@
+ 'longbing_card',
+ //行业模块标题
+ 'app_model_title' => '智能名片营销系统',
+ //DIY默认数据
+ 'diy_default_data' =>[
+
+// $page = Tabbar::getAuthDefultTabbar($this->_uniacid);
+
+ 'page' => '{"1":{"list":[]},"2":{"list":[]},"3":{"list":[]},"4":{"list":[]},"20001":{"list":[{"title":"\u7528\u6237\u4fe1\u606f","type":"userInfo","icon":"iconyonghuxinxi","isDelete":false,"addNumber":1,"attr":[{"title":"\u5b57\u4f53\u989c\u8272","type":"ColorPicker","name":"fontColor"},{"title":"\u80cc\u666f\u56fe\u7247","type":"UploadImage","desc":"750*440","name":"bgImage"}],"data":{"nickName":"\u7528\u6237\u6635\u79f0","avatarUrl":"https:\/\/retail.xiaochengxucms.com\/defaultAvatar.png","nickText":"\u66f4\u65b0\u6211\u7684\u4e2a\u4eba\u8d44\u6599","fontColor":"#F9DEAF","bgImage":[{"url":"http:\/\/longbingcdn.xiaochengxucms.com\/admin\/diy\/user_bg.jpg"}]},"id":1578137234868,"compontents":"ucenterCompoent"},{"title":"\u521b\u5efa\u540d\u7247","type":"createCard","icon":"iconchuangjianmingpian","isDelete":false,"addNumber":1,"data":{"createText":"\u521b\u5efa\u6211\u7684\u540d\u7247","createBtn":"\u521b\u5efa\u540d\u7247"},"id":1578137237049,"compontents":"ucenterCompoent"},{"title":"\u8ba2\u5355\u7ba1\u7406","type":"moduleMenuShopOrder","icon":"iconshoporder","isDelete":true,"addNumber":1,"attr":[{"title":"\u6a21\u677f\u540d\u79f0","type":"Switch","name":"isShowTitle"},{"title":"\u9009\u62e9\u6a21\u677f","type":"ChooseModule","name":"module","data":[{"title":"\u4e00\u884c\u591a\u5217","name":"module-menu-row","img":"http:\/\/longbingcdn.xiaochengxucms.com\/admin\/diy\/module-menu-col.jpg"},{"title":"\u4e00\u884c\u4e00\u5217","name":"module-menu-col","img":"http:\/\/longbingcdn.xiaochengxucms.com\/admin\/diy\/module-menu-row.jpg"}]},{"title":"\u4e00\u884c\u591a\u5c11\u5217","type":"InputNumber","name":"row"}],"data":{"isShowTitle":false,"module":"module-menu-row","row":{"number":4,"min":2,"max":5,"label":"\u8bf7\u8f93\u5165"},"list":[{"title":"\u5168\u90e8","icon":"iconwodedingdan","link":{"type":2,"url":"\/shop\/pages\/order\/list?index=0"}},{"title":"\u5f85\u4ed8\u6b3e","icon":"icondingdandaifukuan","link":{"type":2,"url":"\/shop\/pages\/order\/list?index=1"}},{"title":"\u5f85\u53d1\u8d27","icon":"icondingdandaifahuo","link":{"type":2,"url":"\/shop\/pages\/order\/list?index=2"}},{"title":"\u5f85\u6536\u8d27","icon":"icondingdandaishouhuo","link":{"type":2,"url":"\/shop\/pages\/order\/list?index=3"}},{"title":"\u5df2\u5b8c\u6210","icon":"icondingdanyiwancheng","link":{"type":2,"url":"\/shop\/pages\/order\/list?index=4"}}]},"id":1578137248488,"compontents":"ucenterCompoent"},{"title":"\u5fc5\u5907\u5de5\u5177","type":"moduleMenuShop","icon":"iconshop","isDelete":true,"addNumber":1,"attr":[{"title":"\u6a21\u677f\u540d\u79f0","type":"Switch","name":"isShowTitle"},{"title":"\u9009\u62e9\u6a21\u677f","type":"ChooseModule","name":"module","data":[{"title":"\u4e00\u884c\u591a\u5217","name":"module-menu-row","img":"http:\/\/longbingcdn.xiaochengxucms.com\/admin\/diy\/module-menu-col.jpg"},{"title":"\u4e00\u884c\u4e00\u5217","name":"module-menu-col","img":"http:\/\/longbingcdn.xiaochengxucms.com\/admin\/diy\/module-menu-row.jpg"}]},{"title":"\u4e00\u884c\u591a\u5c11\u5217","type":"InputNumber","name":"row"}],"data":{"isShowTitle":false,"module":"module-menu-row","row":{"number":4,"min":2,"max":5,"label":"\u8bf7\u8f93\u5165"},"list":[{"title":"\u6211\u7684\u552e\u540e","icon":"iconwodeshouhou","link":{"type":2,"url":"\/shop\/pages\/refund\/list"}},{"title":"\u6211\u7684\u6536\u5165","icon":"icontixianguanli","link":{"type":2,"url":"\/shop\/pages\/partner\/income"}},{"title":"\u6211\u7684\u4f18\u60e0\u5238","icon":"iconwodekaquan","link":{"type":2,"url":"\/shop\/pages\/coupon\/list"}},{"title":"\u5206\u9500\u5546\u54c1","icon":"iconquanmianfenxiao","link":{"type":2,"needStaffId":true,"url":"\/shop\/pages\/partner\/distribution?staff_id="}},{"title":"\u6211\u7684\u5730\u5740","icon":"icondizhi2","link":{"type":2,"url":"\/shop\/pages\/address\/list"}}]},"id":1578137252032,"compontents":"ucenterCompoent"},{"title":"\u5207\u6362\u9500\u552e","type":"changeStaff","icon":"iconqiehuanmingpian-copy","isDelete":false,"addNumber":1,"attr":[{"title":"\u6a21\u677f\u540d\u79f0","type":"Input","name":"title"},{"title":"\u662f\u5426\u663e\u793a\u66f4\u591a","type":"Switch","name":"isShowMore"}],"data":{"title":"\u5207\u6362\u9500\u552e","isShowMore":true},"dataList":[],"id":1578137250013,"compontents":"ucenterCompoent"}]}}',
+
+ 'tabbar'=>'{"id":1,"uniacid":4,"status":1,"create_time":1578106749,"update_time":1578106749,"list":[{"is_show":1,"key":1,"iconPath":"icon-mingpian","selectedIconPath":"icon-mingpian1","pageComponents":"cardHome","name":"\u540d\u7247","url":"\/pages\/user\/home","url_out":"","jump_way":0},{"key":2,"is_show":1,"iconPath":"icon-shangcheng1","selectedIconPath":"icon-shangcheng","pageComponents":"shopHome","name":"\u5546\u57ce","url":"","url_jump_way":"0","url_out":"","is_delete":false,"bind_compoents":[],"bind_links":[],"page":[]},{"key":3,"is_show":1,"iconPath":"icon-dongtai1","selectedIconPath":"icon-dongtai","pageComponents":"infoHome","name":"\u52a8\u6001","url":"","url_jump_way":"0","url_out":"","is_delete":false,"bind_compoents":[],"bind_links":[],"page":[]},{"key":4,"is_show":1,"iconPath":"icon-guanwang","selectedIconPath":"icon-guanwang1","pageComponents":"websiteHome","name":"\u5b98\u7f51","url":"","url_jump_way":"0","url_out":"","is_delete":false,"bind_compoents":[],"bind_links":[],"page":[]},{"key":20001,"is_show":1,"iconPath":"iconyonghuduangerenzhongxin","selectedIconPath":"iconyonghuduangerenzhongxin1","pageComponents":"","name":"\u4e2a\u4eba\u4e2d\u5fc3","url":"","url_jump_way":"0","url_out":"","is_delete":false,"bind_compoents":["ucenterCompoent"],"bind_links":["case"],"page":[]}],"color":"#5d6268","selectedColor":"#19c865","backgroundColor":"#fff","borderStyle":"white"}',
+ ] ,
+ //控制能开放多少个小程序使用 这个是一个通用权限控制 , 请求授权时,应该知道是那个行业的 暂时还没用到
+ 'saas_auth_number_config' =>[
+ 'wxapp_number' => 0 ,
+ 'card_number' => 0 ,
+ 'company_number' => 0 ,
+ ],
+ //控制后台能展示的模块
+ 'saas_auth_admin_model_list' => [
+
+
+ //商城
+ 'shop'=>[
+ 'auth_platform' => true ,
+ 'auth_is_platform_check' => true ,
+ 'auth_is_saas_check' => false ,
+ ],
+ 'massage'=>[
+ 'auth_platform' => true ,
+ 'auth_is_platform_check' => true ,
+ 'auth_is_saas_check' => false ,
+ ],
+
+// 'member'=>[
+// 'auth_platform' => true ,
+// 'auth_is_platform_check' => true ,
+// 'auth_is_saas_check' => false ,
+// ],
+
+
+
+ ],
+ //独立版升级使用
+ //版本ID
+ 'version_id' => '64c7ad0322f14b9c894e95220c9d00d5',
+ //分支ID
+ 'branch_id' => '9068836a0acd11eab9c765ac55de11af',
+ //当前系统版本号
+ 'version_no' => '110',
+ //验证系统平台ID
+ 'auth_uniacid' => 1 ,
+ //授权的产品ID
+ 'auth_goods_id' => 1
+
+
+];
\ No newline at end of file
diff --git a/app/RadarInfo.php b/app/RadarInfo.php
new file mode 100755
index 0000000..7bb4864
--- /dev/null
+++ b/app/RadarInfo.php
@@ -0,0 +1,10 @@
+
+// +----------------------------------------------------------------------
+
+namespace app;
+
+class Request extends \think\Request
+{
+
+}
diff --git a/app/Rest.php b/app/Rest.php
new file mode 100755
index 0000000..554c60f
--- /dev/null
+++ b/app/Rest.php
@@ -0,0 +1,184 @@
+_uniacid = $_W[ 'uniacid' ];
+ }
+
+
+ //获取app名称
+ $this->_app = $this->request->app();
+ //获取controller
+ $this->_controller = $this->request->controller();
+ //获取action名称
+ $this->_action = $this->request->action();
+ //获取method
+ $this->_method = $this->request->method( true );
+ //获取param
+ $this->_param = $this->request->param();
+ //获取body参数
+ $this->_input = json_decode( $this->request->getInput(), true );
+ //获取头部信息
+ $this->_header = $this->request->header();
+ // //判断是否为json
+ // if(!isset($this->request->header()['Content-Type'])) {
+ // $this->_header['Content-Type'] = 'application/json';
+ // $this->app->request->withHeader($this->_header);
+ // }
+
+ //获取token
+ if ( isset( $this->_header[ 'token' ] ) ) $this->_token = $this->_header[ 'token' ];
+ //语言
+ if ( isset( $this->_header[ 'lang' ] ) ) $this->_token = $this->_header[ 'lang' ];
+ //获取请求host
+ $this->_host = $this->_header[ 'host' ];
+ //获取访问ip
+ $this->_ip = $_SERVER[ 'REMOTE_ADDR' ];
+ // 控制器初始化
+ $this->initialize();
+
+ //获取用户信息
+ if ( !empty( $this->_token ) ) $this->_user = getUserForToken( $this->_token );
+ //获取角色名称
+ if ( !empty( $this->_user ) && isset( $this->_user[ 'role_name' ] ) ) $this->_role = $this->_user[ 'role_name' ];
+ //数据检查
+ // if (!empty($this->_input)) {
+ // $schemaMethod =ucfirst($this->_app) . ucfirst($this->_controller) . ucfirst($this->_action) . 'Request';
+ // if (jsonSchemaExist($schemaMethod)) {
+ // $result = jsonSchemaValidate($schemaMethod, $this->_input);
+ // if ($result) {
+ // $this->_validate = true;
+ // } else {
+ // $this->_validate = false;
+ // exit();
+ // }
+ // } else {
+ // // 暂不处理
+ // todo('Schema文件找不到!');
+ // }
+ // }
+ //rbac
+ // if(!in_array($this->_app. $this->_controller . $this->_action, ['adminAuthauth']) && in_array($this->_role, ['guest'])){
+ // $result['error'] = 'permissions is not enough.';
+ // echo json_encode($result);exit;
+ // }
+ }
+
+ //返回请求成功的数据
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+ $result[ 'error' ] = $msg;
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', $code );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+ /**
+ * REST 调用
+ * @access public
+ * @param string $method 方法名
+ * @return mixed
+ * @throws \Exception
+ */
+ public function _empty ( $method )
+ {
+ if ( method_exists( $this, $method . '_' . $this->method . '_' . $this->type ) ) {
+ // RESTFul方法支持
+ $fun = $method . '_' . $this->method . '_' . $this->type;
+ }
+ elseif ( $this->method == $this->restDefaultMethod && method_exists( $this, $method . '_' . $this->type ) ) {
+ $fun = $method . '_' . $this->type;
+ }
+ elseif ( $this->type == $this->restDefaultType && method_exists( $this, $method . '_' . $this->method ) ) {
+ $fun = $method . '_' . $this->method;
+ }
+ if ( isset( $fun ) ) {
+ return App::invokeMethod( [
+ $this,
+ $fun
+ ]
+ );
+ }
+ else {
+ // 抛出异常
+ throw new \Exception( 'error action :' . $method );
+ }
+ }
+}
diff --git a/app/admin/common.php b/app/admin/common.php
new file mode 100755
index 0000000..45cc03a
--- /dev/null
+++ b/app/admin/common.php
@@ -0,0 +1,426 @@
+ $account ,'uniacid' => $uniacid ,'deleted' => 0])->count();
+ if(!empty($count)) $result = true;
+ return $result;
+}
+//获取角色信息
+function getRole($role_name = 'user',$uniacid = 7777) {
+ $list_role = listRole($uniacid);
+ foreach($list_role as $role) {
+ if(in_array($role_name, [$role['role_name']])) unset($role_name) ;return $role;
+ }
+ return false;
+}
+
+//获取角色模型
+function getRoleModel() {
+ return new RoleModel();
+}
+
+//获取角色列表
+function listRole($uniacid = 7777){
+ //从缓存中回去数据
+ $result = getCache('ListRole' . $uniacid);
+ if(!empty($result)) return $result;
+ $role_modle = getRoleModel();
+ $list_role = $role_modle->listRoleAll(['uniacid' => $uniacid]);
+ if(!empty($list_role)) {
+ setCache('ListRole' . $uniacid ,$list_role ,3600);
+ foreach($list_role as $role) {
+ setCache('role_' . $uniacid . '_' . $role['role_id'] ,$role ,3600);
+ }
+ }
+ return $list_role;
+}
+
+function ckeckRole($role_id ,$uniacid = 7777) {
+ $list_role = listRole($uniacid);
+ unset($list_role);
+ return getCache('role_' . $uniacid . '_' . $role['role_id']);
+}
+
+function listUserFilter($filter) {
+ $data = ['user.deleted' => 0 ,'role.deleted' => 0];
+ if(isset($filter['user_id'])) $data['user.user_id'] = $filter['user_id'];
+ if(isset($filter['account'])) $data['user.account'] = ['like' ,'%' . $filter['account'] . '%'];
+ if(isset($filter['name'])) $data['user.name'] = ['like' ,'%' . $filter['name'] . '%'];
+ if(isset($filter['creator_id'])) $data['user.creator_id'] = $filter['creator_id'];
+ if(isset($filter['status'])) $data['status'] = $filter['status'];
+ if(isset($filter['nickname'])) $data['user.nickname'] = ['like' ,'%' . $filter['nickname'] . '%'];
+ if(isset($filter['certificate_num'])) $data['user.certificate_num'] = $filter['certificate_num'];
+ if(isset($filter['email'])) $data['user.email'] = ['like' , '%' . $filter['email'] . '%'];
+ if(isset($filter['wechat'])) $data['user.wechat'] = ['like' , '%' . $filter['wechat'] . '%'];
+ if(isset($filter['qq'])) $data['user.qq'] = ['like' , '%' . $filter['qq'] . '%'];
+ if(isset($filter['mobile'])) $data['user.mobile'] = ['like' , '%' . $filter['mobile'] . '%'];
+ if(isset($filter['role_id'])) $data['user.role_id'] = $filter['role_id'];
+ if(isset($filter['uniacid'])) $data['user.uniacid'] = $filter['uniacid'];
+ if(isset($filter['department_id'])) $data['user.department_id'] = $filter['department_id'];
+ return $data;
+}
+
+function getUpdateUserFilter($data) {
+ if(isset($data['user_id'])) unset($data['user_id']);
+ if(isset($data['offset'])) unset($data['offset']);
+ if(isset($data['create_time'])) unset($data['create_time']);
+ if(isset($data['update_time'])) unset($data['update_time']);
+ if(isset($data['delete_time'])) unset($data['delete_time']);
+ return $data;
+}
+
+function getOssConfigData($data)
+{
+ $result['open_oss'] = 0;
+ if(isset($data['miniapp_name'])) $result['miniapp_name'] = $data['miniapp_name'];
+ if(isset($data['open_oss']) && in_array($data['open_oss'], [0,1,2,3,'0','1','2','3'])) $result['open_oss'] = $data['open_oss'];
+ if(isset($data['aliyun_bucket'])) $result['aliyun_bucket'] = $data['aliyun_bucket'];
+ if(isset($data['aliyun_access_key_id'])) $result['aliyun_access_key_id'] = $data['aliyun_access_key_id'];
+ if(isset($data['aliyun_access_key_secret'])) $result['aliyun_access_key_secret'] = $data['aliyun_access_key_secret'];
+ if(isset($data['aliyun_base_dir'])) $result['aliyun_base_dir'] = $data['aliyun_base_dir'];
+ if(isset($data['aliyun_zidinyi_yuming'])) $result['aliyun_zidinyi_yuming'] = $data['aliyun_zidinyi_yuming'];
+ if(isset($data['aliyun_endpoint'])) $result['aliyun_endpoint'] = $data['aliyun_endpoint'];
+ if(isset($data['aliyun_rules'])) $result['aliyun_rules'] = $data['aliyun_rules'];
+ if(isset($data['qiniu_accesskey'])) $result['qiniu_accesskey'] = $data['qiniu_accesskey'];
+ if(isset($data['qiniu_secretkey'])) $result['qiniu_secretkey'] = $data['qiniu_secretkey'];
+ if(isset($data['qiniu_bucket'])) $result['qiniu_bucket'] = $data['qiniu_bucket'];
+ if(isset($data['qiniu_yuming'])) $result['qiniu_yuming'] = $data['qiniu_yuming'];
+ if(isset($data['qiniu_rules'])) $result['qiniu_rules'] = $data['qiniu_rules'];
+ if(isset($data['tenxunyun_appid'])) $result['tenxunyun_appid'] = $data['tenxunyun_appid'];
+ if(isset($data['tenxunyun_secretid'])) $result['tenxunyun_secretid'] = $data['tenxunyun_secretid'];
+ if(isset($data['tenxunyun_secretkey'])) $result['tenxunyun_secretkey'] = $data['tenxunyun_secretkey'];
+ if(isset($data['tenxunyun_bucket'])) $result['tenxunyun_bucket'] = $data['tenxunyun_bucket'];
+ if(isset($data['tenxunyun_region'])) $result['tenxunyun_region'] = $data['tenxunyun_region'];
+ if(isset($data['tenxunyun_yuming'])) $result['tenxunyun_yuming'] = $data['tenxunyun_yuming'];
+ if(isset($data['apiclient_cert'])) $result['apiclient_cert'] = $data['apiclient_cert'];
+ if(isset($data['apiclient_key'])) $result['apiclient_key'] = $data['apiclient_key'];
+ return $result;
+}
+//底部菜单数据封装
+function longbingGetAppTabbarResponse($data)
+{
+ if(empty($data)) return [];
+ //数据处理
+ $data['data'] = [];
+ //处理过的参数
+ $menus = [];
+ //名片
+ if(isset($data['menu1_is_hide']))
+ {
+ $val = ['menu_name' => 'card'];
+ $val['is_show'] = $data['menu1_is_hide'];
+ if(isset($data['menu1_name'])) $val['name'] = $data['menu1_name'];
+ if(isset($data['menu1_url'])) $val['url'] = $data['menu1_url'];
+ if(isset($data['menu1_url_out'])) $val['url_out'] = $data['menu1_url_out'];
+ if(isset($data['menu1_url_jump_way'])) $val['url_jump_way'] = $data['menu1_url_jump_way'];
+ $data['data']['card'] = $val;
+ }
+ //商城
+ if(isset($data['menu2_is_hide']))
+ {
+ $val = ['menu_name' => 'shop'];
+ $val['is_show'] = $data['menu2_is_hide'];
+ if(isset($data['menu2_name'])) $val['name'] = $data['menu2_name'];
+ if(isset($data['menu2_url'])) $val['url'] = $data['menu2_url'];
+ if(isset($data['menu2_url_out'])) $val['url_out'] = $data['menu2_url_out'];
+ if(isset($data['menu2_url_jump_way'])) $val['url_jump_way'] = $data['menu2_url_jump_way'];
+ $data['data']['shop'] = $val;
+ }
+ //动态
+ if(isset($data['menu3_is_hide']))
+ {
+ $val = ['menu_name' => 'dynamic'];
+ $val['is_show'] = $data['menu3_is_hide'];
+ if(isset($data['menu3_name'])) $val['name'] = $data['menu3_name'];
+ if(isset($data['menu3_url'])) $val['url'] = $data['menu3_url'];
+ if(isset($data['menu3_url_out'])) $val['url_out'] = $data['menu3_url_out'];
+ if(isset($data['menu3_url_jump_way'])) $val['url_jump_way'] = $data['menu3_url_jump_way'];
+ $data['data']['dynamic'] = $val;
+ }
+ //官网
+ if(isset($data['menu4_is_hide']))
+ {
+ $val = ['menu_name' => 'website'];
+ $val['is_show'] = $data['menu4_is_hide'];
+ $menus[] = 'menu4_name';
+ if(isset($data['menu4_name'])) $val['name'] = $data['menu4_name'];
+ if(isset($data['menu4_url'])) $val['url'] = $data['menu4_url'];
+ if(isset($data['menu4_url_out'])) $val['url_out'] = $data['menu4_url_out'];
+ if(isset($data['menu4_url_jump_way'])) $val['url_jump_way'] = $data['menu4_url_jump_way'];
+ $data['data']['website'] = $val;
+ }
+ //预约
+ if(isset($data['menu_appoint_is_hide']))
+ {
+ $val = ['menu_name' => 'appointment'];
+ $val['is_show'] = $data['menu_appoint_is_hide'];
+ if(isset($data['menu_appoint_name'])) $val['name'] = $data['menu_appoint_name'];
+ if(isset($data['menu_appoint_url'])) $val['url'] = $data['menu_appoint_url'];
+ if(isset($data['menu_appoint_url_out'])) $val['url_out'] = $data['menu_appoint_url_out'];
+ if(isset($data['menu_appoint_url_jump_way'])) $val['url_jump_way'] = $data['menu_appoint_url_jump_way'];
+ $data['data']['appointment'] = $val;
+ }
+ //活动报名
+ if(isset($data['menu_activity_is_show']))
+ {
+ $val = ['menu_name' => 'activity'];
+ $val['is_show'] = $data['menu_activity_is_show'];
+ if(isset($data['menu_activity_name'])) $val['name'] = $data['menu_activity_name'];
+ if(isset($data['menu_activity_url'])) $val['url'] = $data['menu_activity_url'];
+ if(isset($data['menu_activity_url_out'])) $val['url_out'] = $data['menu_activity_url_out'];
+ if(isset($data['menu_activity_url_jump_way'])) $val['url_jump_way'] = $data['menu_activity_url_jump_way'];
+ $data['data']['activity'] = $val;
+ }
+ //房产
+ if(isset($data['menu_house_is_show']))
+ {
+ $val = ['menu_name' => 'house'];
+ $val['is_show'] = $data['menu_house_is_show'];
+ if(isset($data['menu_house_name']))$val['name'] = $data['menu_house_name'];
+ if(isset($data['menu_house_url']))$val['url'] = $data['menu_house_url'];
+ if(isset($data['menu_house_url_out']))$val['url_out'] = $data['menu_house_url_out'];
+ if(isset($data['menu_house_url_jump_way']))$val['url_jump_way'] = $data['menu_house_url_jump_way'];
+ $data['data']['house'] = $val;
+ }
+ $menus = ["menu1_name","menu1_is_hide","menu1_url","menu1_url_out","menu1_url_jump_way","menu2_name","menu2_is_hide","menu2_url","menu2_url_out","menu2_url_jump_way","menu3_name","menu3_is_hide","menu3_url","menu3_url_out","menu3_url_jump_way","menu4_name","menu4_is_hide","menu4_url","menu4_url_out","menu4_url_jump_way","menu_appoint_name","menu_appoint_is_hide","menu_appoint_url","menu_appoint_url_out","menu_appoint_url_jump_way","menu_activity_is_show","menu_activity_name","menu_activity_is_hide","menu_activity_url","menu_activity_url_out","menu_activity_url_jump_way","menu_house_is_show","menu_house_name","menu_house_is_hide","menu_house_url","menu_house_url_out","menu_house_url_jump_way"];
+ foreach($menus as $menu)
+ {
+ unset($data[$menu]);
+ }
+ return $data;
+}
+
+function longbingGetWxAppTabbarResponse($data)
+{
+ if(empty($data)) return [];
+ //数据处理
+ $data['data'] = [];
+ //处理过的参数
+ $menus = [];
+ //名片
+ if(isset($data['menu1_is_hide']) && !empty($data['menu1_is_hide']))
+ {
+ $val = [];
+ $val['is_show'] = $data['menu1_is_hide'];
+ $val['key'] = 1;
+ $val['iconPath'] = 'icon-mingpian';
+ $val['selectedIconPath'] = 'icon-mingpian1';
+ $val['pageComponents'] = 'cardHome';
+ if(isset($data['menu1_name'])) $val['name'] = $data['menu1_name'];
+ if(isset($data['menu1_url'])) $val['url'] = $data['menu1_url'];
+ if(isset($data['menu1_url_out'])) $val['url_out'] = $data['menu1_url_out'];
+ if(isset($data['menu1_url_jump_way'])) $val['jump_way'] = $data['menu1_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //商城
+ if(isset($data['menu2_is_hide']) && !empty($data['menu2_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 2;
+ $val['is_show'] = $data['menu2_is_hide'];
+ $val['iconPath'] = 'icon-shangcheng1';
+ $val['selectedIconPath'] = 'icon-shangcheng';
+ $val['pageComponents'] = 'shopHome';
+ if(isset($data['menu2_name'])) $val['name'] = $data['menu2_name'];
+ if(isset($data['menu2_url'])) $val['url'] = $data['menu2_url'];
+ if(isset($data['menu2_url_out'])) $val['url_out'] = $data['menu2_url_out'];
+ if(isset($data['menu2_url_jump_way'])) $val['url_jump_way'] = $data['menu2_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //动态
+ if(isset($data['menu3_is_hide']) && !empty($data['menu3_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 3;
+ $val['is_show'] = $data['menu3_is_hide'];
+ $val['iconPath'] = 'icon-dongtai1';
+ $val['selectedIconPath'] = 'icon-dongtai';
+ $val['pageComponents'] = 'infoHome';
+ if(isset($data['menu3_name'])) $val['name'] = $data['menu3_name'];
+ if(isset($data['menu3_url'])) $val['url'] = $data['menu3_url'];
+ if(isset($data['menu3_url_out'])) $val['url_out'] = $data['menu3_url_out'];
+ if(isset($data['menu3_url_jump_way'])) $val['url_jump_way'] = $data['menu3_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //官网
+ if(isset($data['menu4_is_hide']) && !empty($data['menu4_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 4;
+ $val['is_show'] = $data['menu4_is_hide'];
+ $val['iconPath'] = 'icon-guanwang';
+ $val['selectedIconPath'] = 'icon-guanwang1';
+ $val['pageComponents'] = 'websiteHome';
+ if(isset($data['menu4_name'])) $val['name'] = $data['menu4_name'];
+ if(isset($data['menu4_url'])) $val['url'] = $data['menu4_url'];
+ if(isset($data['menu4_url_out'])) $val['url_out'] = $data['menu4_url_out'];
+ if(isset($data['menu4_url_jump_way'])) $val['url_jump_way'] = $data['menu4_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //预约
+ if(isset($data['menu_appoint_is_hide']) && !empty($data['menu_appoint_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 7;
+ $val['is_show'] = $data['menu_appoint_is_hide'];
+ $val['iconPath'] = 'icon-yuyue';
+ $val['selectedIconPath'] = 'icon-yuyue1';
+ $val['pageComponents'] = 'reserveHome';
+ if(isset($data['menu_appoint_name'])) $val['name'] = $data['menu_appoint_name'];
+ if(isset($data['menu_appoint_url'])) $val['url'] = $data['menu_appoint_url'];
+ if(isset($data['menu_appoint_url_out'])) $val['url_out'] = $data['menu_appoint_url_out'];
+ if(isset($data['menu_appoint_url_jump_way'])) $val['url_jump_way'] = $data['menu_appoint_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //活动报名
+ if(isset($data['menu_activity_is_show']) && !empty($data['menu_activity_is_show']))
+ {
+ $val = [];
+ $val['key'] = 6;
+ $val['is_show'] = $data['menu_activity_is_show'];
+ $val['iconPath'] = 'icon-huodong1';
+ $val['selectedIconPath'] = 'icon-huodong';
+ $val['pageComponents'] = 'avtivityHome';
+ if(isset($data['menu_activity_name'])) $val['name'] = $data['menu_activity_name'];
+ if(isset($data['menu_activity_url'])) $val['url'] = $data['menu_activity_url'];
+ if(isset($data['menu_activity_url_out'])) $val['url_out'] = $data['menu_activity_url_out'];
+ if(isset($data['menu_activity_url_jump_way'])) $val['url_jump_way'] = $data['menu_activity_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //房产
+ if(isset($data['menu_house_is_show']) && !empty($data['menu_house_is_show']))
+ {
+ $val = [];
+ $val['key'] = 5;
+ $val['is_show'] = $data['menu_house_is_show'];
+ $val['iconPath'] = 'icon-fangchan1';
+ $val['selectedIconPath'] = 'icon-fangchan';
+ $val['pageComponents'] = 'houseHome';
+ if(isset($data['menu_house_name']))$val['name'] = $data['menu_house_name'];
+ if(isset($data['menu_house_url']))$val['url'] = $data['menu_house_url'];
+ if(isset($data['menu_house_url_out']))$val['url_out'] = $data['menu_house_url_out'];
+ if(isset($data['menu_house_url_jump_way']))$val['url_jump_way'] = $data['menu_house_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ $menus = ["menu1_name","menu1_is_hide","menu1_url","menu1_url_out","menu1_url_jump_way","menu2_name","menu2_is_hide","menu2_url","menu2_url_out","menu2_url_jump_way","menu3_name","menu3_is_hide","menu3_url","menu3_url_out","menu3_url_jump_way","menu4_name","menu4_is_hide","menu4_url","menu4_url_out","menu4_url_jump_way","menu_appoint_name","menu_appoint_is_hide","menu_appoint_url","menu_appoint_url_out","menu_appoint_url_jump_way","menu_activity_is_show","menu_activity_name","menu_activity_is_hide","menu_activity_url","menu_activity_url_out","menu_activity_url_jump_way","menu_house_is_show","menu_house_name","menu_house_is_hide","menu_house_url","menu_house_url_out","menu_house_url_jump_way"];
+ foreach($menus as $menu)
+ {
+ unset($data[$menu]);
+ }
+ return $data;
+}
+
+function longbingGetAppTabbarRequest($data)
+{
+ $result = [];
+ foreach($data as $key => $val)
+ {
+ switch($val['menu_name'])
+ {
+ case 'card':
+ if(isset($val['is_show'])) $result['menu1_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu1_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu1_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu1_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu1_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'shop':
+ if(isset($val['is_show'])) $result['menu2_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu2_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu2_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu2_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu2_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'dynamic':
+ if(isset($val['is_show'])) $result['menu3_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu3_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu3_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu3_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu3_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'website':
+ if(isset($val['is_show'])) $result['menu4_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu4_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu4_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu4_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu4_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'appointment':
+ if(isset($val['is_show'])) $result['menu_appoint_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu_appoint_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu_appoint_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu_appoint_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu_appoint_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'activity':
+ if(isset($val['is_show'])) $result['menu_activity_is_show'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu_activity_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu_activity_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu_activity_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu_activity_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'house':
+ if(isset($val['is_show'])) $result['menu_house_is_show'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu_house_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu_house_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu_house_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu_house_url_jump_way'] = $val['url_jump_way'];
+ break;
+ default:
+ break;
+ }
+ }
+ return $result;
+}
diff --git a/app/admin/controller/Admin.php b/app/admin/controller/Admin.php
new file mode 100755
index 0000000..24a4214
--- /dev/null
+++ b/app/admin/controller/Admin.php
@@ -0,0 +1,247 @@
+_input['user'];
+ $data = checkAccountIsExist($user['account'] ,$this->_uniacid);
+ //判读账号是否存在
+ if($data) return $this->error('account is exist ,please check again.');
+ $user_id = uuid();
+ $user['admin_id'] = $user_id;
+ $user['offset'] = createOffset();
+ $user['passwd'] = createPasswd($user['passwd'] ,$user['offset']);
+ $user['uniacid'] = $this->_uniacid;
+ //生成admin model
+ $admin_model = new AdminModel();
+ //检查用户是否存在
+ if(isset($user['user_id'])) {
+ $user_model = new UserModel();
+ $user_data = $user_model->getUser(['user_id' =>$user['user_id']]);
+ if(empty($user_data)) return $this->error('user is not exist ,please check user id.');
+ //检查用户是否已经是管理员
+ $admin_data = $admin_model->getAdmin(['user_id' => $user['user_id']]);
+ if(!empty($admin_data)) return $this->error('the user is admin already .');
+ }
+ //判断权限
+ if(!isset($user['role_id']) || !ckeckRole($user['role_id'] ,$this->_uniacid)) $user['role_id'] = getRole()['role_id'];
+ if(!empty($this->_user))$user['creator_id'] = $this->_user['user_id'];
+ //创建数据
+ $result = $admin_data->createUser($user);
+// if(!empty($result)) setAccountToCache($user['account'] ,$this->_uniacid);
+ return $this->success($result);
+ }
+
+ //获取用户列表
+ public function listAdmin() {
+ //获取查询参数
+ $param = $this->_param;
+ //获取分页数据
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 20
+ );
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+
+ //参数过滤
+ $param['uniacid'] = $this->_uniacid;
+ $filter = listAdminFilter($param);
+ //查询数据
+ $admin_model = new AdminModel();
+ //获取总数据总条数
+ $page_config['total'] = $admin_model->listAdminCount($filter);
+
+ $admins = $admin_model->listAdmin($filter ,$page_config);
+ //构造返回数据
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ $result = $page_config;
+ $result['users'] = $admins;
+ return $this->success($result);
+ }
+
+ //获取用户详情
+ public function getAdmin() {
+ $admin_id = $this->_param['admin_id'];
+ //获取用户详细信息
+ $admin_model = new AdminModel();
+ $admin = $user_model->getAdmin(['admin_id' => $admin_id ,'uniacid' => $this->_uniacid]);
+ //移除密码 偏移量
+ unset($user['passwd']);
+ unset($user['offset']);
+ //返回数据
+ return $this->success($user);
+ }
+
+ //修改用户信息
+ public function updateUser() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user not is exist ,please check user id.');
+ //获取修改信息
+ $user_data = getUpdateUserFilter($this->_input['user']);
+ //更改密码
+ if(isset($user_data['passwd'])){
+ //判断偏移量是否存在
+ if(!isset($user['offset'])) $user['offset'] = createOffset(); $user_data['offset'] = $user['offset'];
+ $user_data['passwd'] = createPasswd($user_data['passwd'] ,$user['offset']);
+ }
+ //修改数据
+ $result = $user_model->updateUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid] ,$user_data);
+ //返回数据
+ return $this->success($result);
+ }
+
+ //删除用户
+ public function delUser() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user not is exist ,please check user id.');
+ //删除用户数据
+ $result = $user_model->delUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid] ,['deleted' => 0]);
+ //删除用户权限信息
+ $admin_role_model = new UserRoleModel();
+ $admin_role_model->delUserRole(['user_id' => $user_id]);
+ //删除数据缓存
+
+ //返回数据
+ return $this->success($result);
+ }
+ //给用户增加权限
+ public function setUserRole() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //获取角色id
+ $role_id = $this->_param['role_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user is not exist ,please check user id.');
+ //获取角色信息
+ $role = ckeckRole($role_id);
+ if(empty($role)) return $this->error('the role is not exist ,please check role id.');
+ //判断用户权限是否已存在
+ $exist_role_ids = [];
+ foreach($user['role'] as $role){
+ $exist_role_ids[] = $role['role_ids'];
+ }
+ if(in_array($role_id, $exist_role_ids)) return $this->error('the user had the role ,please do not repeat add role to the user.');
+ //添加角色
+ $user_role_model = UserRoleModel();
+ $result = $user_role_model->createUserRole(['user_id' => $user_id ,$role_id => $role_id ,'uniacid' => $this->_uniacid]);
+ //返回数据
+ return $this->success($result);
+ }
+ //移除用户权限
+ public function removeUserRole() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //获取角色id
+ $role_id = $this->_param['role_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user is not exist ,please check user id.');
+ //判断用户权限是否已存在
+ $exist_role_ids = [];
+ foreach($user['role'] as $role){
+ $exist_role_ids[] = $role['role_ids'];
+ }
+ if(!in_array($role_id, $exist_role_ids)) return $this->error('the user role is not exist ,please check role id.');
+ //添加角色
+ $user_role_model = UserRoleModel();
+ $result = $user_role_model->delUserRole(['user_id' => $user_id ,$role_id => $role_id ,'uniacid' => $this->_uniacid]);
+ //返回数据
+ return $this->success($result);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-06 15:24
+ * @功能说明:检查短视频的权限
+ */
+ public function checkAuth(){
+
+ return $this->success(1);
+
+ //是否授权
+ $saasKey = longbing_get_auth_prefix('AUTH_CARD') ;
+ //是否给过验证码
+ $pass = getCache('AUTH_CARD','99999');
+ //如果授权过或者给过验证码
+ if(defined($saasKey)||(!empty($pass)&&$pass==1)){
+
+ return $this->success(1);
+
+ }else{
+
+ return $this->success(0);
+
+ }
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-06 15:32
+ * @功能说明:给权限
+ */
+ public function giveAuth(){
+
+ $input = $this->_param;
+
+ $key = 'return_admin'.$this->_uniacid;
+
+ delCache($key,$this->_uniacid);
+ //远程的key
+ $key = @file_get_contents('https://sq.xiaochengxucms.com/wexinPay.php?ck=7891');
+ //密码
+ $pass = !empty($key)&&is_numeric($key)?$key.'63791':'263791';
+
+ if($pass==$input['pass']){
+
+ setCache('AUTH_CARD',1,99999999999999,'99999');
+
+ }else{
+
+ $this->errorMsg('验证码错误,请联系服务人员');
+
+ }
+ return $this->success(1);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-19 11:01
+ * @功能说明:是否是saas版本
+ */
+ public function isSaas(){
+
+ return $this->success(longbingIsZhihuituike());
+
+ }
+
+
+}
diff --git a/app/admin/controller/AppUpgrade.php b/app/admin/controller/AppUpgrade.php
new file mode 100755
index 0000000..8470013
--- /dev/null
+++ b/app/admin/controller/AppUpgrade.php
@@ -0,0 +1,113 @@
+_param['wxapp_version'])?$this->_param['wxapp_version']:''; //微信小程序上传版本
+
+ $model = new WxUpload();
+
+ $goods_name = config('app.AdminModelList')['app_model_name'];
+
+ $auth_uniacid = config('app.AdminModelList')['auth_uniacid'];
+
+ $version_no = config('app.AdminModelList')['version_no'];
+
+ $upgrade = new LongbingUpgrade($auth_uniacid , $goods_name, Env::get('j2hACuPrlohF9BvFsgatvaNFQxCBCc' , false));
+ //微信上传配置
+ $upload_config= $model->settingInfo(['uniacid'=>$this->_uniacid]);
+
+
+
+ if(empty($upload_config['key'])){
+
+ $this->errorMsg('还未填写密钥');
+ }
+ //密钥
+ $upload_key_url = $upload_config['key'];
+ //appid
+ $app_id = Db::name('longbing_card_config')->where(['uniacid'=>$this->_uniacid])->value('appid');
+
+ if(empty($app_id)){
+
+ $this->errorMsg('小程序未配置');
+ }
+ $uploadInfo = [
+
+ 'siteinfo' => [
+
+ 'uniacid' => $this->_uniacid,
+
+ "multiid" => "0",
+
+ "version" => "3.0",
+ //小程序接口
+ 'siteroot' => $this->_is_weiqin?'https://'.$_SERVER['HTTP_HOST']."/app/index.php":'https://'.$_SERVER['HTTP_HOST']."/index.php"
+ ],
+ //密钥
+ 'upload_key' => 'http://'.$_SERVER['HTTP_HOST'].'/attachment/'.$upload_key_url ,
+ //版本号
+ 'version_no' => $version_no,
+ //版本号
+ 'version' => $upload_config['version'],
+ //描述
+ 'content' => $upload_config['content'],
+ //app_id
+ 'app_id' => $app_id,
+ 'app_id_list' => explode(',' , $upload_config['app_id']),
+ ];
+
+ $data = $upgrade->uploadWxapp($uploadInfo,$wxapp_version);
+
+ return $this->success( $data );
+
+ }
+
+ /**
+ **@author lichuanming
+ * @DataTime: 2020/6/22 17:30
+ * @功能说明: 获取微信版本信息
+ */
+ public function getWxappVersion(){
+ $goods_name = config('app.AdminModelList')['app_model_name'];
+
+ $auth_uniacid = config('app.AdminModelList')['auth_uniacid'];
+
+ $version_no = config('app.AdminModelList')['version_no'];
+
+ $upgrade = new LongbingUpgrade($auth_uniacid , $goods_name, Env::get('j2hACuPrlohF9BvFsgatvaNFQxCBCc' , false));
+ $version = $upgrade->getWxappVersion($version_no);
+ return $this->success($version);
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/Auth.php b/app/admin/controller/Auth.php
new file mode 100755
index 0000000..e789254
--- /dev/null
+++ b/app/admin/controller/Auth.php
@@ -0,0 +1,57 @@
+_input['user'];
+// //检查用户名是否存在
+// if(empty(checkAccountIsExist($filter['account'] ,$this->_uniacid))) return $this->error('account is not exist ,please check user account.');
+
+ //获取用户信息
+ $admin_model = new AdminModel();
+ $admin = $admin_model->getAdmin(['account' => $filter['account'] ,'uniacid' => $this->_uniacid]);
+ //判断用户是否存在
+ if(empty($admin)) return $this->error('account is not exist ,please check user account.');
+ //判断密码是否正确
+
+ if(!checkPasswd($filter['passwd'] ,$admin['offset'],$admin['passwd'])) return $this->error('passwd is error ,please check user passwd.');
+ //返回数据
+ unset($admin['passwd']);unset($admin['offset']);
+
+ $result['user'] = $admin;
+ $result['token'] = createToken();
+ if(empty($result['token'])) return $this->error('System is busy,please try again later.');
+ //生成加密key(暂不使用)
+// $keys = get2keys();
+// if(!empty($keys)){
+// $result['keys'] = $keys['api_key'];
+// $user['keys'] = $keys['sever_key'];
+// }
+ //添加缓存数据
+ setUserForToken($result['token'] ,$admin);
+
+ return $this->success($result);
+ }
+
+ //注销
+ public function unAuth() {
+ //判断用户是否登录
+ if(empty($this->_user)) return $this->error('The user is not logged in.');
+ //删除缓存
+ delUserForToken($this->_token);
+ //返回数据
+ return $this->success(true);
+ }
+
+}
+
diff --git a/app/admin/controller/CardStaff.php b/app/admin/controller/CardStaff.php
new file mode 100755
index 0000000..454d764
--- /dev/null
+++ b/app/admin/controller/CardStaff.php
@@ -0,0 +1,14 @@
+model = new CardUser();
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/Config.php b/app/admin/controller/Config.php
new file mode 100755
index 0000000..8c165ac
--- /dev/null
+++ b/app/admin/controller/Config.php
@@ -0,0 +1,414 @@
+_uniacid = 8;
+ }
+ //创建或者修改
+ public function updateOssConfig()
+ {
+ //获取nuiacid
+ $uniacid = $this->_uniacid;
+ //获取上传参数
+ $input = [];
+
+ if(isset($this->_input['oss_config'])) $input = $this->_input['oss_config'];
+ //数据清洗
+ $data = getOssConfigData($input);
+
+ $data['uniacid'] = $uniacid;
+ //生成操作模型
+ $oss_config_model = new OssConfig();
+ //查询数据是否存在
+ $oss_config = $oss_config_model->getConfig(['uniacid' => $uniacid]);
+
+ $result = false;
+
+ $data['is_sync'] = 1;
+
+ if(empty($oss_config))
+ {
+ $result = $oss_config_model->createConfig($data);
+ }else{
+ //检查上传配置是否正确
+ $result = $oss_config_model->updateConfig(['uniacid' => $uniacid] ,$data);
+ }
+ $config = longbingGetOssConfig($uniacid ,true);
+
+ if(!empty($result) && !empty($data['open_oss']))
+ {
+ $path = LONGBING_EXTEND_PATH . 'timg.jpg';
+ if(file_exists($path)){
+ $file = new UploadedFile($path ,'test.jpg');
+ $file_upload_model = new Upload($uniacid);
+ $check = $file_upload_model->upload('picture' ,$file);
+
+ if(empty($check)) return $this->error(lang('upload config error'));
+ }
+ }
+ return $this->success($result);
+
+ }
+ //获取配置
+ public function getOssConfig()
+ {
+ //获取uniacid
+ $uniacid = $this->_uniacid;
+ //生成操作模型
+ $oss_config_model = new OssConfig();
+ //获取数据
+ $config = $oss_config_model->getConfig(['uniacid' => $uniacid]);
+ if(!empty($config)) unset($config['id']);
+ return $this->success($config);
+ }
+
+
+ //小程序设置
+ public function getAppConfig()
+ {
+ //获取参数
+ $uniacid = $this->_uniacid;
+ //获取数据
+ $result = longbingGetAppConfig($uniacid);
+
+ //返回数据
+ return $this->success($result);
+ }
+
+ //小程序设置
+ public function setAppConfig()
+ {
+ //获取参数
+ $uniacid = $this->_uniacid;
+ //获取数据
+ $input = null;
+
+
+ if(isset($this->_input['app_config'])) $input = $this->_input['app_config'];
+
+ if(empty($input)) return $this->error('not app config data ,please check input data.');
+
+ $input['uniacid'] = $this->_uniacid;
+ //获取数据
+ $result = longbingGetAppConfig($uniacid);
+
+ $app_config_model = new AppConfig();
+
+ $input['is_sync'] = 1;
+
+ //企业微信小程序通知
+ if(!empty($input['notice_switch'])&&$input['notice_switch']==4){
+
+ $insrt['yq_corpid'] = $input['yq_corpid'];
+
+ $insrt['yq_corpsecret'] = $input['yq_corpsecret'];
+
+ $insrt['yq_agentid'] = $input['yq_agentid'];
+
+ $send_model = new SendConfig();
+
+ $data = $send_model->configUpdate(['uniacid'=>$this->_uniacid],$insrt);
+
+ unset($input['yq_corpid']);
+
+ unset($input['yq_corpsecret']);
+
+ unset($input['yq_agentid']);
+ }
+
+ if(!isset($result['uniacid']) || empty($result))
+ {
+ //创建
+ $result = $app_config_model->createConfig($input);
+ }else{
+ //更新
+ $result = $app_config_model->updateConfig(['id' => $result['id']] ,$input);
+ }
+
+ longbingGetAppConfig($uniacid ,true);
+
+ return $this->success($result);
+ }
+
+
+ //自动同步服务通知模板
+ public function autoServiceNoticeTemplate()
+ {
+ //获取配置信息
+ $config = longbingGetAppConfig($this->_uniacid);
+ if(!isset($config['appid']) || empty($config['appid']) || !isset($config['app_secret']) || empty($config['app_secret'])) return $this->error('wx app site not exist ,please check site message.');
+ //获取accesstoken
+ $ac = longbingSingleGetAccessTokenByUniacid($this->_uniacid);
+ //判断accesstoken是否存在
+ if(empty($ac)) return $this->error(lang('wx app site error'));
+ //生成获取服务通知模板的url
+ $url = "https://api.weixin.qq.com/cgi-bin/wxopen/template/add?access_token={$ac}";
+ //生成数据
+ $data = [ 'id' => 'AT1442', 'keyword_id_list' => [ 4, 7, 1 ] ];
+ $data = json_encode( $data );
+ //获取数据
+ $result = longbingCurl( $url, $data ,'POST');
+ //解析数据
+ $result = json_decode( $result, true );
+ if ( isset( $result[ 'errcode' ] ) && $result[ 'errcode' ] == 40001 ) {
+ //重新获取accesstoken
+ $ac = longbingSingleGetAccessTokenByUniacid($this->_uniacid ,true);
+ $url = "https://api.weixin.qq.com/cgi-bin/wxopen/template/add?access_token={$ac}";
+ //获取数据
+ $result = longbingCurl( $url, $data ,'POST');
+ //数据接续
+ $result = json_decode( $result, true );
+ }
+ //判断
+
+ if ( isset( $result[ 'errcode' ] ) && !empty($result[ 'errcode' ]) ) return $this->error(lang('auto get template error'));
+ //更新设置信息
+ $app_config_model = new AppConfig();
+ $mini_template_id = $result['template_id'];
+ $result = $app_config_model->updateConfig(['id' => $config['id']] ,['mini_template_id' => $mini_template_id]);
+ if($result) longbingGetAppConfig($this->_uniacid ,true); $result = ['mini_template_id' => $mini_template_id];
+
+ return $this->success($result);
+ }
+
+ //获取底部菜单
+ public function getTabbar()
+ {
+ //获取参数
+ $uniacid = $this->_uniacid;
+ //获取数据
+ $result = longbingGetAppTabbar($uniacid ,true);
+ //数据封装
+ $result = longbingGetAppTabbarResponse($result);
+
+ $pluginAuth = longbingGetPluginAuth($uniacid);
+ $plugin_map = [
+ "activity"=> 'activity',
+ 'appointment' => 'appoint',
+ 'house' => 'house',
+ ];
+ $meta_map = [
+ 'card' => 'BusinessCard',
+ 'shop' => 'Malls',
+ 'dynamic' => 'Dynamic',
+ 'website' => 'Website',
+ ];
+
+
+ foreach ($result['data'] as $k => $item) {
+ if (in_array($k, array_keys($plugin_map)) && ($pluginAuth['plugin'][$plugin_map[$k]] == 0)) {
+ unset($result['data'][$k]);
+ continue;
+ }
+
+ if (in_array($k, array_keys($meta_map)) && ($pluginAuth['web_manage_meta_config'][$meta_map[$k]] == 0)) {
+ unset($result['data'][$k]);
+ continue;
+ }
+ }
+
+ $result = array_merge($result, $pluginAuth);
+
+ return $this->success($result);
+ }
+
+ //设置底部菜单
+ public function setTabbar()
+ {
+ //获取参数
+ $uniacid = $this->_uniacid;
+ $input = null;
+ if(isset($this->_input['data'])) $input = $this->_input['data'];
+ $input = longbingGetAppTabbarRequest($input);
+ if(empty($input)) return $this->error('not tabbar data');
+// var_dump($input);die;
+ //获取数据
+ $tabbar = longbingGetAppTabbar($uniacid);
+
+
+ //限制只能有5个tabbar
+ $menu_now = [
+ 'menu1_is_hide' => $tabbar['menu1_is_hide'],
+ 'menu2_is_hide' => $tabbar['menu2_is_hide'],
+ 'menu3_is_hide' => $tabbar['menu3_is_hide'],
+ 'menu4_is_hide' => $tabbar['menu4_is_hide'],
+ 'menu_appoint_is_hide' => $tabbar['menu_appoint_is_hide'],
+ 'menu_activity_is_show' => $tabbar['menu_activity_is_show'],
+ 'menu_house_is_show' => $tabbar['menu_house_is_show'],
+ ];
+
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+
+ $not_tabbars = [];
+ if(!empty($permissions) && !empty($permissions['plugin']))
+ {
+ //预约
+ if(!isset($permissions['plugin']['appoint']) || empty($permissions['plugin']['appoint']))
+ {
+ $not_tabbars[] = 'menu_appoint_is_hide';
+ $input['menu_appoint_is_hide'] = 0;
+ }
+ //活动
+ if(!isset($permissions['plugin']['activity']) || empty($permissions['plugin']['activity']))
+ {
+ $not_tabbars[] = 'menu_activity_is_show';
+ $input['menu_activity_is_show'] = 0;
+ }
+ //房产
+ if(!isset($permissions['plugin']['house']) || empty($permissions['plugin']['house']))
+ {
+ $not_tabbars[] = 'menu_house_is_show';
+ $input['menu_house_is_show'] = 0;
+ }
+ //官网
+ if(!isset($permissions['web_manage_meta_config']['Website']) || empty($permissions['web_manage_meta_config']['Website']))
+ {
+ $not_tabbars[] = 'menu4_is_hide';
+ $input['menu4_is_hide'] = 0;
+ }
+ //商场
+ if(!isset($permissions['web_manage_meta_config']['Malls']) || empty($permissions['web_manage_meta_config']['Malls']))
+ {
+ $not_tabbars[] = 'menu2_is_hide';
+ $input['menu3_is_hide'] = 0;
+ }
+ //动态
+ if(!isset($permissions['web_manage_meta_config']['Dynamic']) || empty($permissions['web_manage_meta_config']['Dynamic']))
+ {
+ $not_tabbars[] = 'menu3_is_hide';
+ $input['menu3_is_hide'] = 0;
+ }
+ }
+ // var_dump($not_tabbars);die;
+ $max_tabbar_count = env('MAX_TABBAR_COUNT', 5);
+ $all_tabbar_count = 0;
+ foreach ($menu_now as $k => $v) {
+ if (isset($input[$k])) $v = $input[$k];
+ if(!in_array($k ,$not_tabbars)) $all_tabbar_count = $all_tabbar_count + $v;
+ }
+
+// $max_tabbar_count = env('MAX_TABBAR_COUNT', 5);
+// $all_tabbar_count = $menu_now['menu1_is_hide']
+// + $menu_now['menu2_is_hide']
+// + $menu_now['menu3_is_hide']
+// + $menu_now['menu4_is_hide']
+// + $menu_now['menu_appoint_is_hide']
+// + $menu_now['menu_activity_is_show']
+// + $menu_now['menu_house_is_show'];
+
+ if ($all_tabbar_count > $max_tabbar_count) {
+ return $this->error('显示的菜单栏不能大于 ' . $max_tabbar_count);
+ }
+
+ //判断数据是否存在
+ $result = false;
+ $tabbar_model = new AppTabbar();
+ if(empty($tabbar)){
+ $input['uniacid'] = $uniacid;
+ $result = $tabbar_model->createTabbar($input);
+ }else{
+ $result = $tabbar_model->updateTabbar(['id' => $tabbar['id']] ,$input);
+ }
+ longbingGetAppTabbar($uniacid ,true);
+ return $this->success($result);
+ }
+ //清理缓存
+ public function clearCache()
+ {
+ //获取数据
+ $uniacid = $this->_uniacid;
+
+ setCache('test',1,10,8888);
+
+ setCache('test',1,10,$uniacid);
+
+ $result = clearCache($uniacid);
+
+ clearCache(8888);
+
+ UpdateService::installSql(8888,2);
+
+ return $this->success($result);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-08 18:51
+ * @功能说明:小程序上传配置详情
+ */
+ public function wxUploadInfo(){
+
+ $model = new WxUpload();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+ //详情
+ $data = $model->settingInfo($dis);
+
+ $data['app_id'] = !empty($data['app_id'])?explode(',',$data['app_id']):[];
+
+ return $this->success($data);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-08 18:51
+ * @功能说明:小程序上传配置详情
+ */
+ public function wxUploadUpdate(){
+
+ $input = $this->_param;
+
+ $model = new WxUpload();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = [
+ //密钥
+ 'key' => $input['key'],
+ //版本号
+ 'version' => $input['version'],
+ //描述
+ 'content' => $input['content'],
+ //appid
+ 'app_id' => $input['app_id'],
+ ];
+ //详情
+ $data = $model->settingUpdate($dis,$data);
+
+ return $this->success($data);
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/controller/Coupon.php b/app/admin/controller/Coupon.php
new file mode 100755
index 0000000..f1e1efd
--- /dev/null
+++ b/app/admin/controller/Coupon.php
@@ -0,0 +1,97 @@
+model = new CouponModel();
+ }
+ /**
+ * 获取福包列表
+ */
+ public function couponList(){
+ $page = $this->_input['page'];
+ $name = $this->_input['name'];
+ $dis['uniacid'] = $this->_uniacid;
+ $dis['status'] = ['>',-1];
+ if(!empty($name)){
+ $dis['title'] = ['like',"%$name%"];
+ }
+ $data = $this->model->couponList($dis,$page);
+ $this->success($data);
+ }
+
+
+ /**
+ * 修改福包
+ */
+ public function couponUpdate(){
+ $dis = ['id'=>$this->_input['id']];
+ $res = $this->model->couponUpdate($dis,$this->_input);
+ $this->success($res);
+ }
+
+ /**
+ * 添加福包
+ */
+ public function couponsAdd(){
+ $this->_input['uniacid'] = $this->_uniacid;
+ $res = $this->model->couponAdd($this->_input);
+ $this->success($res);
+ }
+
+ /**
+ * 软删除福包
+ */
+ public function couponDel(){
+ $dis['id'] = $this->_input['id'];
+ $data['status'] = -1;
+ $res = $this->model->couponUpdate($dis,$data);
+ $this->success($res);
+ }
+
+ /**
+ * 获取福包详情
+ *
+ */
+ public function couponsInfo(){
+ $dis = ['id'=>$this->_input['id']];
+ $res = $this->model->couponInfo($dis);
+ $this->success($res);
+ }
+
+ /**
+ *
+ *获取所有分类
+ */
+ public function getCate(){
+ $cateModel = new ShopType();
+ $dis['uniacid'] = $this->_uniacid;
+ $dis['status'] = 1;
+ $data = $cateModel->catSortSelect($dis);
+ $this->success($data);
+ }
+
+ /**
+ * 获取限用的商品
+ */
+ public function getGoods(){
+ $goodsModel = new Goods();
+ $dis['uniacid'] = $this->_uniacid;
+ $dis['status'] = 1;
+ $data = $goodsModel->goodsSelect($dis);
+ $this->success($data);
+
+ }
+
+
+
+
+}
diff --git a/app/admin/controller/Department.php b/app/admin/controller/Department.php
new file mode 100755
index 0000000..be2c6a1
--- /dev/null
+++ b/app/admin/controller/Department.php
@@ -0,0 +1,119 @@
+_input['department'];
+ //生成相关数据
+ $department['department_id'] = uuid();
+ //获取创建者user_id
+ if(isset($this->_user)) $department['creator_id'] = $this->_user['user_id'];
+ //修改数据
+ $result = $deparmet_model->updateDepartment(['deparement_id' => $department_id ,'uniacid' => $this->_uniacid] ,$data);
+ //返回数据
+ return $this->success($result);
+ }
+
+ //获取Departmet列表
+ public function listDepartmet() {
+ //筛选部门信息
+ $param = $this->_param;
+ //获取分页信息
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 20
+ );
+ //设置页码
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ //设置每页的数据
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+ //查询过滤
+ $filter = $param;
+ //默认uniacid
+ $filter['uniacid'] = $this->_uniacid;
+ //生成部门模型
+ $department_model = new DepartmentModel();
+ //获取部门总数
+ $page_config['total'] = $department_model->listDepartmentCount($filter);
+ $departmets = $department_model->listDepartment($filter);
+ //生生成返回数据
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ //设置返回参数
+ $result = $page_config;
+ //返回数据
+ $result['departments'] = $departmets;
+ return $this->success($result);
+
+
+
+ }
+
+ //获取Departmet详情
+ public function getDepartmet() {
+ //获取部门id
+ $department_id = $this->_param['department_id'];
+ //获取部门详情
+ $deparmet_model = new DepartmentModel();
+ //获取部门信息
+ $department = $department_model->getDepartment(['deparement_id' => $department_id ,'uniacid' => $this->_uniacid]);
+ //判断部门信息是否存在
+ if(!empty($department)){
+ //获取部门下的子部门
+ $deparements = $department_model->listDepartmentAll(['parent_id' => $department_id ,'uniacid' => $this->_uniacid]);
+ if(!empty($departments)) $department['departments'] = $deparements;
+ //获取部门下的员工
+ $user_model = new UserModel();
+ $users = $user_model->listUserAll(['department_id' => $department_id ,'uniacid' => $this->_uniacid]);
+ if(!empty($users)) $department['users'] = $users;
+ }
+ //返回数据
+ return $this->success($department);
+ }
+
+ //更新Departmet
+ public function updateDepartmet() {
+ //获取部门id
+ $department_id = $this->_param['department_id'];
+ //获取修改数据
+ $data = $this->_input['department'];
+ //获取部门详情
+ $deparmet_model = new DepartmentModel();
+ $department = $department_model->getDepartment(['deparement_id' => $department_id ,'uniacid' => $this->_uniacid]);
+ if(empty($department)) return $this->error('the department not exist ,please check department id .');
+ if(empty($data)) return $this->error('the department change data is note exist ,please check department data.');
+ //修改数据
+ $result = $deparmet_model->updateDepartment(['deparement_id' => $department_id ,'uniacid' => $this->_uniacid] ,$data);
+ return $this->success($result);
+ }
+
+ //删除Departmet
+ public function delDepartmet() {
+ //获取部门id
+ $department_id = $this->_param['department_id'];
+ //生成部门模型
+ $deparmet_model = new DepartmentModel();
+ //获取部门信息
+ $department = $department_model->getDepartment(['deparement_id' => $department_id ,'uniacid' => $this->_uniacid]);
+ if(empty($department)) return $this->error('the department not exist ,please check department id .');
+ //删除数据
+ $result = $deparmet_model->delDepartment(['deparement_id' => $department_id ,'uniacid' => $this->_uniacid] ,$data);
+ if(!empty($result)) {
+ $user_model = new UserModel();
+ //设置部门为空
+ $user_model->updateUser(['uniacid' => $this->_uniacid ,'department_id' => $department_id] ,['department_id' => 0]);
+ }
+ return $this->success($result);
+ }
+}
diff --git a/app/admin/controller/File.php b/app/admin/controller/File.php
new file mode 100755
index 0000000..46345c1
--- /dev/null
+++ b/app/admin/controller/File.php
@@ -0,0 +1,355 @@
+_uniacid = 2;
+ $this->uid = 0;
+ }
+
+ //创建分组
+ public function createGroup()
+ {
+ //获取参数
+ $input = $this->_input;
+ //兼容写法-- lichuanming 2020/5/13
+ if(!isset($input['group']['name']) && !isset($input['name'])) return $this->error('not group name ,please check .');
+ $group['name'] = isset($input['group']['name'])?$input['group']['name']:$input['name'];
+ //获取uid
+// if(!empty($this->uid)) $group['uid'] = $this->uid;
+ $group['uniacid'] = $this->_uniacid;
+ //生成分组模型
+ $group_model = new AttachmentGroup();
+ $group_count = $group_model->where('uniacid','=',$this->_uniacid)->count('id');
+ if($group_count >= 20){ //分组不超过20个
+ return $this->error('分组最多限制为20个!');
+ }
+
+ $repeat = $group_model->where(['uniacid'=>$this->_uniacid,'name'=>$group['name']])->count();
+ if($repeat){
+ return $this->error('已存在同名分组');
+ }
+
+ $result = $group_model->createGroup($group);
+ return $this->success($result);
+ }
+
+ //获取分组列表
+ public function listGroup()
+ {
+ //获取参数
+ $param = $this->_param;
+ if(isset($param['name'])) $filter[] = $param['name'];
+ $filter['uniacid'] = $this->_uniacid;
+ //获取uid
+// if(!empty($this->uid)) $filter['uid'] = $this->uid;
+ //生成分组模型
+ $group_model = new AttachmentGroup();
+ //获取数据
+ $result = $group_model->listGroup($filter);
+ return $this->success(['groups' => $result]);
+ }
+
+ //更新分组列表
+ public function updateGroup()
+ {
+ //获取参数
+ $group_id = $this->_param['group_id'];
+ //获取更新数据
+ $data = $this->_input['group'];
+ //生成分组模型
+ $group_model = new AttachmentGroup();
+
+ $repeat = $group_model->where(['uniacid'=>$this->_uniacid,'name'=>$data['name']])->where('id','<>',$group_id)->count();
+ if($repeat){
+ return $this->error('已存在同名分组');
+ }
+
+ //更新数据
+ $result = $group_model->updateGroup(['id' => $group_id,'uniacid'=>$this->_uniacid] ,$data);
+ //返回数据
+ return $this->success($result);
+ }
+
+ //删除分组信息
+ public function delGroup()
+ {
+ //获取参数
+ if(!isset($this->_param['group_id'])) return $this->error('not group id');
+ $group_id = $this->_param['group_id'];
+
+ $where = array(
+ ['group_id','=',$group_id],
+ ['uniacid','=',$this->_uniacid]
+ );
+ //生成分组模型
+ $attachment_model = new CoreAttachment();
+ $file_count = $attachment_model->where($where)->count('id');
+ if($file_count > 0){
+ return $this->error('目前分组中有文件数据,不可删除,如要删除,请先清除文件数据');
+ }
+ $group_model = new AttachmentGroup();
+ //删除数据
+ $result = $group_model->delGroup(['id' => $group_id]);
+ //返回数据
+ return $this->success($result);
+ }
+
+ /**
+ **@author lichuanming
+ * @DataTime: 2020/5/15 14:35
+ * @功能说明:批量删除分组
+ */
+ public function delAllGroup(){
+ if(!isset($this->_param['group_id'])) return $this->error('not group id');
+ $group_id = $this->_param['group_id'];
+
+ $attachment_model = new CoreAttachment();
+ if(is_array($group_id)){
+ foreach ($group_id as $id){
+ $where = array(
+ ['group_id','=',$id],
+ ['uniacid','=',$this->_uniacid]
+ );
+ $file_count = $attachment_model->where($where)->count('id');
+ if($file_count > 0){
+ return $this->error('目前分组中有文件数据,不可删除,如要删除,请先清除文件数据');
+ }
+ }
+ $group_model = new AttachmentGroup();
+ //删除数据
+ $result = $group_model->delGroup(['id' => $group_id]);
+ //返回数据
+ return $this->success($result);
+ }else{
+ return $this->delGroup();
+ }
+ }
+
+ //上传文件
+ public function uploadFile()
+ {
+ $input = $this->_param;
+ $file = $this->request->file('file');
+ if(empty($file)) return $this->error('not file ,please check file.');
+ $uploda_model = new Upload($this->_uniacid);
+ $type = 'picture';
+ if(isset($input['type'])) $type = $input['type'];
+ $info = $uploda_model->upload($type ,$file);
+ $result = false;
+ if(!empty($info))
+ {
+ $info['uid'] = $this->uid;
+ $info['longbing_attachment_path'] = longbingGetFilePath($info['attachment'] , $this->_host,$this->_uniacid);
+ $info['longbing_from'] = 'web';
+ $attachment_model = new CoreAttachment();
+ $result = $attachment_model->createAttach($info);
+ if(!empty($result)) $result = $info;
+ }
+ //数据处理
+ return $this->success($result);
+ }
+
+
+ public function uploadFiles()
+ {
+ //获取参数
+ $input = $this->_param;
+ //获取文件列表
+ $files = $this->request->file('file');
+ //检查文件是否存在
+ if(empty($files)) return $this->error('not file ,please check file.');
+ //设置类型
+ $type = 'picture';
+ if(isset($input['type'])) $type = $input['type'];
+
+ //上传文件分组 --lichuanming 2020/5/13
+ $group_id = -1;
+ if(isset($input['group_id'])) $group_id = $input['group_id'];
+
+ $result = [];
+ //生成上传模型
+ $uploda_model = new Upload($this->_uniacid);
+ foreach($files as $file)
+ {
+ //上传文件
+ $info = $uploda_model->upload($type ,$file);
+
+ if(!empty($info))
+ {
+ //获取上传者id
+ $info['uid'] = $this->uid;
+ $info['attachment_path'] = longbingGetFilePath($info['attachment'] , $this->_host,$this->_uniacid ,$info['longbing_driver']);
+ //文件分组界定 --lichuanming 2020/5/13
+ $info['group_id'] = $group_id;
+ $info['uniacid'] = $this->_uniacid;
+ //写入数据库
+ $attachment_model = new CoreAttachment();
+ $data = $attachment_model->createAttach($info);
+ //判断写入数据库是否成功
+ if(!empty($data)) $result[] = $info;
+ }
+ }
+ //数据处理
+ return $this->success($result);
+ }
+
+
+
+
+ //获取文件列表
+ public function listFile()
+ {
+ $param = $this->_param;
+ $filter['uniacid'] = $this->_uniacid;
+ $filter['type'] = 1;
+
+ $filter['uid'] = 0;
+
+
+ //判断分组是否存在
+ if(isset($param['group_id'])) $filter['group_id'] = $param['group_id']?$param['group_id']:['0','-1'];
+ //判断文件类型是否存在
+ if(isset($param['type']) && in_array($param['type'], [1,2,3,'1','2','3'])) $filter['type'] = $param['type'];
+ //判断用户id是否存在
+// if(isset($this->uid)) return $this->error('not login,please login');
+// $filter['uid'] = $this->uid;
+ //获取和生成分页信息
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 10
+ );
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+ //生成模型类
+ $file_model = new CoreAttachment();
+ //查询总数
+ $count = $file_model->listAttachCount($filter);
+ $files = $file_model->listAttach($filter ,$page_config);
+ $files = transImagesOne($files ,['attachment'] ,$this->_uniacid);
+// foreach($files as $key => $val)
+// {
+// $files[$key]['attachment_path'] = longbingGetFilePath($val['attachment'] ,$this->_host ,$this->_uniacid);
+// }
+ //生成返回数据
+ $page_config['total'] = $count;
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ $result = $page_config;
+ $result['files'] = $files;
+ //返回数据
+ return $this->success($result);
+ }
+
+ //获取文件
+ public function getFile()
+ {
+ $param = $this->_param;
+ $filter['uniacid'] = $this->_uniacid;
+ $filter['id'] = $param['id'];
+// $filter['uid'] = $this->uid;
+ //生成模型
+ $file_model = new CoreAttachment();
+ //查询数据
+ $file = $file_model->getFile($filter);
+// if(isset($file['attachment']))
+// {
+// $file['attachment_path'] = longbingGetFilePath($file['attachment'] ,$this->_host ,$this->_uniacid);
+// }
+ //返回数据
+ return $this->success($file);
+ }
+
+ //删除文件
+ public function delFile()
+ {
+ //获取参数
+ $input = $this->_input;
+ //获取参数
+ if(!isset($input['ids'])) return $this->error('not file id,please check.');
+ $filter['ids'] = $input['ids'];
+// $filter['uid'] = $this->uid;
+ $filter['uniacid'] = $this->_uniacid;
+ //生成模型
+ $file_model = new CoreAttachment();
+ //删除
+ $result = $file_model->delAttach($filter);
+ return $this->success($result);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 14:16
+ * @功能说明:获取上传配置
+ */
+ public function uploadConfig(){
+
+ $data = longbingGetOssConfig($this->_uniacid);
+
+ $data['uniacid'] = $this->_uniacid;
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 14:17
+ * @功能说明:上传文件到数据库
+ */
+ public function addFile(){
+
+ $info = $this->_input;
+
+ $group_id = -1;
+
+ if(isset($info['group_id'])) {
+
+ $group_id = $info['group_id'];
+ }
+ //获取上传者id
+ $info['uid'] = $this->uid;
+ //$info['attachment_path'] = longbingGetFilePath($info['attachment'] , $this->_host,$this->_uniacid ,$info['longbing_driver']);
+ //文件分组界定 --lichuanming 2020/5/13
+ $info['group_id'] = $group_id;
+
+ $info['uniacid'] = $this->_uniacid;
+
+ $info['createtime'] = time();
+
+ $attachment_model = new CoreAttachment();
+
+ $data = $attachment_model->addAttach($info);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-13 15:26
+ * @功能说明:图片移动分组
+ */
+ public function moveGroup(){
+
+ $input = $this->_input;
+
+ $attachment_model = new CoreAttachment();
+
+ $res = $attachment_model->where('id','in',$input['file_id'])->update(['group_id'=>$input['group_id']]);
+
+ return $this->success($res);
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/admin/controller/Index.php b/app/admin/controller/Index.php
new file mode 100755
index 0000000..42ac1e9
--- /dev/null
+++ b/app/admin/controller/Index.php
@@ -0,0 +1,13 @@
+_param;
+ //获取模块
+ $module_model = new ModuleModel();
+ $module_filter = ['is_base' => 1];
+ if(isset($param['is_base'])) $module_filter['is_base'] = $param['is_base'];
+ $modules = $module_model->listModuleAll($module_filter ,$this->_uniacid);
+ //生成返回数据
+ $result = [];
+ foreach($modules as $module){
+ $data = [];
+ if(isset($module['path'])) $data['path'] = $module['path'];
+ if(isset($module['component'])) $data['component'] = $module['component'];
+ if(isset($module['redirect'])) $data['redirect'] = $module['redirect'];
+ if(isset($module['is_base'])) $data['is_base'] = $module['is_base'];
+ if(isset($module['menuName'])) $data['meta']['menuName'] = $module['menuName'];
+ if(isset($module['icon'])) $data['meta']['icon'] = $module['icon'];
+ //获取菜单信息
+ $meun_model = new MenuModel();
+ $menu_filter = ['uniacid' => $this->_uniacid , 'module_id' => $module['module_id'] ,'parent_id' => 0];
+ $module['status'] = 0;
+ if(!empty($module['is_base']) || !empty($module['is_public']))
+ {
+ $module['status'] = 1;
+ }else{
+ if(isset($module['module_app']['status'])) $module['status'] = $module['module_app']['status'];
+ }
+ if(empty($module['status'])) continue;
+ $menus = $meun_model->listMenu($menu_filter);
+ $child = [];
+ $subNavNames = [];
+ foreach($menus as $menu) {
+ if(empty($menu['is_son_menu'])) {
+ $child_data = [];
+ if(isset($menu['menu_path'])) $child_data['path'] = $menu['menu_path'];
+ if(isset($menu['component'])) $child_data['component'] = $menu['component'];
+ if(isset($menu['name'])) $child_data['neme'] = $menu['name'];
+ $child_data['meta']['title'] = null;
+ if(isset($menu['title'])) $child_data['meta']['title'] = $menu['title'];
+ $child_data['meta']['isOnly'] = true;
+ if(empty($menu['isOnly'])) $child_data['meta']['isOnly'] = false;
+ $child_data['meta']['pagePermission'] = [];
+ $menu_filter['parent_id'] = $menu['menu_id'];
+ $menu_filter['is_action'] = 1;
+ $actions = $meun_model->listMenu($menu_filter);
+ $auth = [];
+ foreach($actions as $action){
+ $auth[] = $action['name'];
+ }
+ $child_data['meta']['auth'] = $auth;
+ $child[] = $child_data;
+ }else{
+ $subNavName = [];
+ if(isset($menu['name'])) {
+ $subNavName['subNavName'] = $menu['name'];
+ }else{
+ $subNavName['subNavName'] = null;
+ }
+ $menu_filter['parent_id'] = $menu['menu_id'];
+ $menu_filter['is_action'] = 0;
+ $leval_2_menus = $meun_model->listMenu($menu_filter);
+ foreach($leval_2_menus as $leval_2_menu) {
+ $url = [];
+ if(isset($leval_2_menu['name'])) $url['name'] = $leval_2_menu['name'];
+ if(isset($leval_2_menu['url'])) $url['url'] = $leval_2_menu['url'];
+ $subNavName['url'][] = $url;
+ $child_data = [];
+ if(isset($leval_2_menu['menu_path'])) $child_data['path'] = $leval_2_menu['menu_path'];
+ if(isset($leval_2_menu['name'])) $child_data['name'] = $leval_2_menu['name'];
+ if(isset($leval_2_menu['component'])) $child_data['component'] = $leval_2_menu['component'];
+
+ if(isset($leval_2_menu['title'])) $child_data['meta']['title'] = $leval_2_menu['title'];
+// if(isset($leval_2_menu['component'])) $child_data['meta']['component'] = $leval_2_menu['component'];
+ $child_data['meta']['isOnly'] = false;
+ if(!empty($leval_2_menu['isOnly'])) $child_data['meta']['isOnly'] = true;
+
+ $child_data['meta']['auth'] = [];
+
+ if(!empty($leval_2_menu['is_son_menu'])){
+ $pagePermissions = [];
+ $menu_filter['parent_id'] = $leval_2_menu['menu_id'];
+ $menu_filter['is_action'] = 0;
+ $leval_3_menus = $meun_model->listMenu($menu_filter);
+
+// if(in_array('c3', [$leval_2_menu['menu_id']])){
+// var_dump(json_encode($leval_3_menus));die;
+// }
+
+ foreach($leval_3_menus as $leval_3_menu){
+ $pagePermission = [];
+ if(isset($leval_3_menu['title'])) $pagePermission['title'] = $leval_3_menu['title'];
+ if(isset($leval_3_menu['index'])) $pagePermission['index'] = $leval_3_menu['index'];
+ $menu_filter['parent_id'] = $leval_3_menu['menu_id'];
+ $menu_filter['is_action'] = 1;
+ $actions = $meun_model->listMenu($menu_filter);
+ foreach($actions as $action) {
+ $pagePermission['auth'][] = $action['name'];
+ }
+ $pagePermissions[] = $pagePermission;
+ }
+ $child_data['meta']['pagePermission'] = $pagePermissions;
+ }
+ $child[] = $child_data;
+ }
+ $subNavNames[] = $subNavName;
+
+ }
+ }
+ $data['meta']['subNavName'] = $subNavNames;
+ $data['children'] = $child;
+ $result[] = $data;
+ }
+ return $this->success($result);
+ }
+ //获取菜单详情
+ public function getMenu() {
+ $param = $this->_param;
+ $module_filter = [];
+ if(isset($param['module_id'])) $module_filter['module_id'] = $param['module_id'];
+ if(empty($module_filter)) return $this->error('module id is not exist ,please check param.');
+ $module_model = new ModuleModel();
+ //获取模块信息
+ $module = $module_model->getModule($module_filter ,$this->_uniacid);
+
+ if(empty($module)) $this->success([]);
+ $module['status'] = 0;
+ if(!empty($module['is_base']) || !empty($module['is_public']))
+ {
+ $module['status'] = 1;
+ }else{
+ if(isset($module['module_app']['status'])) $module['status'] = $module['module_app']['status'];
+ }
+ if(empty($module['status'])) return $this->success([]);
+ //生成返回数据
+ $data = [];
+ if(isset($module['path'])) $data['path'] = $module['path'];
+ if(isset($module['component'])) $data['component'] = $module['component'];
+ if(isset($module['redirect'])) $data['redirect'] = $module['redirect'];
+ if(isset($module['is_base'])) $data['is_base'] = $module['is_base'];
+ if(isset($module['menuName'])) $data['meta']['menuName'] = $module['menuName'];
+ if(isset($module['icon'])) $data['meta']['icon'] = $module['icon'];
+ //获取菜单信息
+ $meun_model = new MenuModel();
+ $menu_filter = ['uniacid' => $this->_uniacid , 'module_id' => $module['module_id'] ,'parent_id' => 0];
+ $module['status'] = 0;
+ if(!empty($module['is_base']) || !empty($module['is_public']))
+ {
+ $module['status'] = 1;
+ }else{
+ if(isset($module['module_app']['status'])) $module['status'] = $module['module_app']['status'];
+ }
+ $menus = $meun_model->listMenu($menu_filter);
+ if(empty($menus)) return $this->success($data);
+ $child = [];
+ $subNavNames = [];
+ foreach($menus as $menu) {
+ if(empty($menu['is_son_menu'])) {
+ $child_data = [];
+ if(isset($menu['menu_path'])) $child_data['path'] = $menu['menu_path'];
+ if(isset($menu['component'])) $child_data['component'] = $menu['component'];
+ if(isset($menu['name'])) $child_data['neme'] = $menu['name'];
+ $child_data['meta']['title'] = null;
+ if(isset($menu['title'])) $child_data['meta']['title'] = $menu['title'];
+ $child_data['meta']['isOnly'] = true;
+ if(empty($menu['isOnly'])) $child_data['meta']['isOnly'] = false;
+ $child_data['meta']['pagePermission'] = [];
+ $menu_filter['parent_id'] = $menu['menu_id'];
+ $menu_filter['is_action'] = 1;
+ $actions = $meun_model->listMenu($menu_filter);
+ $auth = [];
+ foreach($actions as $action){
+ $auth[] = $action['name'];
+ }
+ $child_data['meta']['auth'] = $auth;
+ $child[] = $child_data;
+ }else{
+ $subNavName = [];
+ if(isset($menu['name'])) {
+ $subNavName['subNavName'] = $menu['name'];
+ }else{
+ $subNavName['subNavName'] = null;
+ }
+ $menu_filter['parent_id'] = $menu['menu_id'];
+ $menu_filter['is_action'] = 0;
+ $leval_2_menus = $meun_model->listMenu($menu_filter);
+ foreach($leval_2_menus as $leval_2_menu) {
+ $url = [];
+ if(isset($leval_2_menu['name'])) $url['name'] = $leval_2_menu['name'];
+ if(isset($leval_2_menu['url'])) $url['url'] = $leval_2_menu['url'];
+ $subNavName['url'][] = $url;
+ $child_data = [];
+ if(isset($leval_2_menu['menu_path'])) $child_data['path'] = $leval_2_menu['menu_path'];
+ if(isset($leval_2_menu['name'])) $child_data['name'] = $leval_2_menu['name'];
+ if(isset($leval_2_menu['component'])) $child_data['component'] = $leval_2_menu['component'];
+
+ if(isset($leval_2_menu['title'])) $child_data['meta']['title'] = $leval_2_menu['title'];
+// if(isset($leval_2_menu['component'])) $child_data['meta']['component'] = $leval_2_menu['component'];
+ $child_data['meta']['isOnly'] = false;
+ if(!empty($leval_2_menu['isOnly'])) $child_data['meta']['isOnly'] = true;
+
+ $child_data['meta']['auth'] = [];
+
+ if(!empty($leval_2_menu['is_son_menu'])){
+ $pagePermissions = [];
+ $menu_filter['parent_id'] = $leval_2_menu['menu_id'];
+ $menu_filter['is_action'] = 0;
+ $leval_3_menus = $meun_model->listMenu($menu_filter);
+
+// if(in_array('c3', [$leval_2_menu['menu_id']])){
+// var_dump(json_encode($leval_3_menus));die;
+// }
+
+ foreach($leval_3_menus as $leval_3_menu){
+ $pagePermission = [];
+ if(isset($leval_3_menu['title'])) $pagePermission['title'] = $leval_3_menu['title'];
+ if(isset($leval_3_menu['index'])) $pagePermission['index'] = $leval_3_menu['index'];
+ $menu_filter['parent_id'] = $leval_3_menu['menu_id'];
+ $menu_filter['is_action'] = 1;
+ $actions = $meun_model->listMenu($menu_filter);
+ foreach($actions as $action) {
+ $pagePermission['auth'][] = $action['name'];
+ }
+ $pagePermissions[] = $pagePermission;
+ }
+ $child_data['meta']['pagePermission'] = $pagePermissions;
+ }
+ $child[] = $child_data;
+ }
+ $subNavNames[] = $subNavName;
+ }
+ }
+ $data['meta']['subNavName'] = $subNavNames;
+ $data['children'] = $child;
+ return $this->success($data);
+ }
+
+ /**
+ * By.jingshuixian
+ * 2019年11月23日14:17:16
+ */
+ public function getMenuList()
+ {
+ //By.jingshuixian
+ //2019年11月23日16:23:26
+ //测试新的载入方式
+ $menu_data = longbing_init_info_data('AdminMenu');
+ return $this->success($menu_data);
+
+
+
+
+ //所有的菜单的json文件
+ $allAdminMenus = include APP_PATH . "Common/extend/menu/allAdminMenus.php";
+ //平台的菜单配置
+ $memu_config = Config('app.adminMenus');
+ //菜单权限
+ $pluginAuth = longbingGetPluginAuth($this->_uniacid);
+ $auth = $pluginAuth['web_manage_meta_config'];
+
+
+ $auth_meta_permission = [];//前端导航栏配置json
+ foreach ($memu_config as $menu_name) {
+ if (!isset($allAdminMenus[$menu_name]) || ($menu_name !== 'App' && $auth[$menu_name] !== 1) ) {
+ continue;
+ }
+ $menu_data = json_decode($allAdminMenus[$menu_name], true);
+ //如果代理管理端有版权设置, 【系统】菜单中的子菜单【版权管理】不展示
+
+
+
+ $auth_meta_permission[] = $menu_data;
+
+ }
+
+ return $this->success($auth_meta_permission);
+
+
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/Module.php b/app/admin/controller/Module.php
new file mode 100755
index 0000000..9c04e79
--- /dev/null
+++ b/app/admin/controller/Module.php
@@ -0,0 +1,94 @@
+_param;
+ $module_model = new ModuleModel();
+ //设置默认数据
+ $filter['is_base'] = 1;
+ if(isset($param['is_base'])) $filter['is_base'] = $param['is_base'];
+ //获取模块列表
+ $modules = $module_model->listModuleAll($filter ,$this->_uniacid);
+// echo json_encode($modules ,true);die;
+ $result = [];
+ //处理数据
+ foreach($modules as $module)
+ {
+ //设置默认数据
+ $module['status'] = 1;
+ //判断模块是否是基础模块
+ if(empty($module['is_base'])){
+ //判断插件是否授权
+ if(isset($module['module_app']['status']))
+ {
+ //设置状态
+ $module['status'] = $module['module_app']['status'];
+ }else{
+ $module['status'] = 0;
+ }
+ }
+ //移除module_app信息
+ unset($module['module_app']);
+ $result[] = $module;
+
+ }
+ //返回数据
+ return $this->success($result);
+ }
+
+ //获取应用详情
+ public function getModule() {
+ //获取参数
+ $param = $this->_param;
+ $filter = [];
+ //判断相关参数是否存在
+ if(isset($param['module_id'])) $filter['module_id'] = $param['module_id'];
+ if(isset($param['is_base'])) $filter['is_base'] = $param['is_base'];
+ //判断查询参数是否存在,不存在抛出异常
+ if(empty($filter)) return $this->error('module id is not exist ,please check param.');
+ //生成模块模型
+ $module_model = new ModuleModel();
+ //查询模块信息
+ $module = $module_model->getModule($filter ,$this->_uniacid);
+ if(!empty($module)) {
+ $module['status'] = 0;
+ if(!empty($module['is_public']) || !empty($module['is_base'])){
+ $module['status'] = 1;
+ }else{
+
+ }
+
+
+
+ //判断是否是公共模块
+ if(empty($module['is_public'])){
+ //数据处理
+ if(empty($module['is_base'])){
+ if(isset($module['module_app']['status']))
+ {
+ $module['status'] = $module['module_app']['status'];
+ }else{
+ $module['status'] = 0;
+ }
+ }
+ //移除module_app数据
+ unset($module['module_app']);
+ }
+ }
+ //返回数据
+ return $this->success($module);
+ }
+}
diff --git a/app/admin/controller/Role.php b/app/admin/controller/Role.php
new file mode 100755
index 0000000..2451396
--- /dev/null
+++ b/app/admin/controller/Role.php
@@ -0,0 +1,98 @@
+_input['role'];
+ //生成和填充相关数据
+ $role['role_id'] = uuid();
+ $role['uniacid'] = $this->_uniacid;
+ //生成权限数据库操作模型
+ $role_model = new RoleModel;
+ //创建
+ $result = $role_model->createRole($role);
+ //返回相关数据
+ return $this->seccess($result);
+
+ }
+ //获取权限列表
+ public function listRole() {
+ //获取权限查询信息
+ $param = $this->_param;
+ //获取分页信息
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 20
+ );
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+ //查询过滤
+ $filter = $param;
+ $filter['uniacid'] = $this->_uniacid;
+ //生成权限操作模型
+ $role_model = new RoleModel();
+ //获取权限列表
+ $page_config['totle'] = $role_model->listRoleCount($filter);
+ $roles = $role_model->listRole($filter ,$page_config);
+ //生成返回数据
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ $result = $page_config;
+ $result['roles'] = $roles;
+ return $this->success($result);
+ }
+ //获取权限详情
+ public function getRole() {
+ //获取权限id
+ $role_id = $this->_param['role_id'];
+ //生成权限操作模型
+ $role_model = new RoleModel();
+ //获取权限数据
+ $role = $role_model->getRole(['role_id' => $role_id ,'uniacid' => $this->_uniacid]);
+ return $this->success($role);
+ }
+ //更改权限信息
+ public function updateRole() {
+ //获取角色id
+ $role_id = $this->_param['role_id'];
+ //判断权限是否存在
+ $role_model = new RoleModel();
+ $role = $role_model->getRole(['role_id' => $role_id ,'uniacid' => $this->_uniacid]);
+ if(empty($role)) return $this->error('the role is nit exist ,please check the role id.');
+ //获去角色更新信息
+ $role = $this->_input['role'];
+ //更新
+ $result = $role_model->updateRole(['role_id' => $role_id ,'uniacid' => $this->_uniacid] ,$role);
+ //返回相关数据
+ return $this->seccess($result);
+ }
+ //删除权限信息
+ public function delRole() {
+ //获取角色id
+ $role_id = $this->_param['role_id'];
+ //判断权限是否存在
+ $role_model = new RoleModel();
+ $role = $role_model->getRole(['role_id' => $role_id ,'uniacid' => $this->_uniacid]);
+ if(empty($role)) return $this->error('the role is nit exist ,please check the role id.');
+ //更新
+ $result = $role_model->delRole(['role_id' => $role_id ,'uniacid' => $this->_uniacid]);
+ if(!empty($result)) {
+ $user_model = new UserModel();
+ $user_model->update(['role_id' => $role_id ,'uniacid' => $this->_uniacid] ,['role_id' => 0]);
+ }
+ //返回相关数据
+ return $this->seccess($result);
+
+ }
+
+}
diff --git a/app/admin/controller/Update.php b/app/admin/controller/Update.php
new file mode 100755
index 0000000..4402c4e
--- /dev/null
+++ b/app/admin/controller/Update.php
@@ -0,0 +1,51 @@
+success([]);
+ $key = 'init_all_data';
+
+ $data = getCache($key,$this->_uniacid);
+
+ if(!empty($data)){
+
+ return $this->success([]);
+
+ }
+
+ setCache($key,1,7200,$this->_uniacid);
+
+ UpdateService::installSql($this->_uniacid);
+
+ UpdateService::initWeiqinConfigData();
+
+ DiyService::addDefaultDiyData($this->_uniacid);
+ //各个模块初始化数据事件
+ event('InitModelData');
+ //处理雷达
+ lbInitRadarMsg($this->_uniacid);
+
+ return $this->success([]);
+
+ }
+
+
+}
+
\ No newline at end of file
diff --git a/app/admin/controller/User.php b/app/admin/controller/User.php
new file mode 100755
index 0000000..77d4a9a
--- /dev/null
+++ b/app/admin/controller/User.php
@@ -0,0 +1,168 @@
+_input['user'];
+ $data = checkAccountIsExist($user['account'] ,$this->_uniacid);
+ //判读账号是否存在
+ if($data) return $this->error('account is exist ,please check again.');
+
+ $user_id = uuid();
+ $user['user_id'] = $user_id;
+ $user['offset'] = createOffset();
+ $user['passwd'] = createPasswd($user['passwd'] ,$user['offset']);
+ $user['uniacid'] = $this->_uniacid;
+ //判断权限
+ if(!isset($user['role_id']) || !ckeckRole($user['role_id'] ,$this->_uniacid)) $user['role_id'] = getRole()['role_id'];
+ if(!empty($this->_user))$user['creator_id'] = $this->_user['user_id'];
+ //创建数据
+ $user_model = new UserModel();
+ $result = $user_model->createUser($user);
+// if(!empty($result)) setAccountToCache($user['account'] ,$this->_uniacid);
+ return $this->success($result);
+ }
+
+ //获取用户列表
+ public function listUser() {
+ //获取查询参数
+ $param = $this->_param;
+ //获取分页数据
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 20
+ );
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+
+ //参数过滤
+ $param['uniacid'] = $this->_uniacid;
+ $filter = listUserFilter($param);
+ //查询数据
+ $user_model = new UserModel();
+ //获取总数据总条数
+ $page_config['total'] = $user_model->listUserCount($filter);
+
+ $users = $user_model->listUser($filter ,$page_config);
+ //构造返回数据
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ $result = $page_config;
+ $result['users'] = $users;
+ return $this->success($result);
+ }
+
+ //获取用户详情
+ public function getUser() {
+ $user_id = $this->_param['user_id'];
+ //获取用户详细信息
+ $user_model = new UserModel();
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ //移除密码 偏移量
+ unset($user['passwd']);
+ unset($user['offset']);
+ //返回数据
+ return $this->success($user);
+ }
+
+ //修改用户信息
+ public function updateUser() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user not is exist ,please check user id.');
+ //获取修改信息
+ $user_data = getUpdateUserFilter($this->_input['user']);
+ //更改密码
+ if(isset($user_data['passwd'])){
+ //判断偏移量是否存在
+ if(!isset($user['offset'])) $user['offset'] = createOffset(); $user_data['offset'] = $user['offset'];
+ $user_data['passwd'] = createPasswd($user_data['passwd'] ,$user['offset']);
+ }
+ //修改数据
+ $result = $user_model->updateUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid] ,$user_data);
+ //返回数据
+ return $this->success($result);
+ }
+
+ //删除用户
+ public function delUser() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user not is exist ,please check user id.');
+ //删除用户数据
+ $result = $user_model->delUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid] ,['deleted' => 0]);
+ //删除用户权限信息
+ $admin_role_model = new UserRoleModel();
+ $admin_role_model->delUserRole(['user_id' => $user_id]);
+ //删除数据缓存
+
+ //返回数据
+ return $this->success($result);
+ }
+ //给用户增加权限
+ public function setUserRole() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //获取角色id
+ $role_id = $this->_param['role_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user is not exist ,please check user id.');
+ //获取角色信息
+ $role = ckeckRole($role_id);
+ if(empty($role)) return $this->error('the role is not exist ,please check role id.');
+ //判断用户权限是否已存在
+ $exist_role_ids = [];
+ foreach($user['role'] as $role){
+ $exist_role_ids[] = $role['role_ids'];
+ }
+ if(in_array($role_id, $exist_role_ids)) return $this->error('the user had the role ,please do not repeat add role to the user.');
+ //添加角色
+ $user_role_model = UserRoleModel();
+ $result = $user_role_model->createUserRole(['user_id' => $user_id ,$role_id => $role_id ,'uniacid' => $this->_uniacid]);
+ //返回数据
+ return $this->success($result);
+ }
+ //移除用户权限
+ public function removeUserRole() {
+ //获取用户id
+ $user_id = $this->_param['user_id'];
+ //获取角色id
+ $role_id = $this->_param['role_id'];
+ //生成用户模型类
+ $user_model = new UserModel();
+ //获取用户数据
+ $user = $user_model->getUser(['user_id' => $user_id ,'uniacid' => $this->_uniacid]);
+ if(empty($user)) return $this->error('the user is not exist ,please check user id.');
+ //判断用户权限是否已存在
+ $exist_role_ids = [];
+ foreach($user['role'] as $role){
+ $exist_role_ids[] = $role['role_ids'];
+ }
+ if(!in_array($role_id, $exist_role_ids)) return $this->error('the user role is not exist ,please check role id.');
+ //添加角色
+ $user_role_model = UserRoleModel();
+ $result = $user_role_model->delUserRole(['user_id' => $user_id ,$role_id => $role_id ,'uniacid' => $this->_uniacid]);
+ //返回数据
+ return $this->success($result);
+ }
+}
diff --git a/app/admin/controller/Wx.php b/app/admin/controller/Wx.php
new file mode 100755
index 0000000..e3b5ced
--- /dev/null
+++ b/app/admin/controller/Wx.php
@@ -0,0 +1,47 @@
+_uniacid);
+ $tabbars = longbingGetWxAppTabbarResponse($tabbars);
+
+
+ $pluginAuth = longbingGetPluginAuth($this->_uniacid);
+
+ $plugin_map = [
+ "activity"=> 'activity',
+ 'appointment' => 'appoint',
+ 'house' => 'house',
+ ];
+ $meta_map = [
+ 'card' => 'BusinessCard',
+ 'shop' => 'Malls',
+ 'dynamic' => 'Dynamic',
+ 'website' => 'Website',
+ ];
+
+
+ foreach ($tabbars['data'] as $k => $item) {
+ if (in_array($k, array_keys($plugin_map)) && ($pluginAuth['plugin'][$plugin_map[$k]] == 0)) {
+ unset($tabbars['data'][$k]);
+ continue;
+ }
+
+ if (in_array($k, array_keys($meta_map)) && ($pluginAuth['web_manage_meta_config'][$meta_map[$k]] == 0)) {
+ unset($tabbars['data'][$k]);
+ continue;
+ }
+ }
+ return $this->success($tabbars);
+ }
+}
diff --git a/app/admin/controller/WxFile.php b/app/admin/controller/WxFile.php
new file mode 100755
index 0000000..ccfbde2
--- /dev/null
+++ b/app/admin/controller/WxFile.php
@@ -0,0 +1,95 @@
+uid = $this->getUserId();
+ }
+ //上传文件
+ public function uploadFile()
+ {
+ $input = $this->_param;
+ $file = $this->request->file('file');
+ if(empty($file)) $file = $this->request->file('files');
+ if(empty($file)) $file = $this->request->file('filePath');
+ if(empty($file)) return $this->error('not file ,please check file.');
+ $uploda_model = new Upload($this->_uniacid);
+ $type = 'picture';
+ if(isset($input['type'])) $type = $input['type'];
+ $info = $uploda_model->upload($type ,$file);
+ $result = false;
+ if(!empty($info))
+ {
+ if(isset($info['attachment']) && !empty($info['attachment']))
+ {
+ $info['attachment_path'] = $info['attachment'];
+ $info = transImagesOne($info ,['attachment_path'] ,$this->_uniacid);
+ }
+ //获取上传者id
+ $info['uid'] = $this->uid;
+// $info['attachment_path'] = longbingGetFilePath($info['attachment'] , $this->_host,$this->_uniacid);
+ //数据来源
+ $info['from'] = 'wx';
+ //写入数据库
+ $attachment_model = new CoreAttachment();
+ $data = $attachment_model->createAttach($info);
+ //判断写入数据库是否成功
+ if(!empty($data)) $result = $info;
+ }
+ //数据处理
+ return $this->success($result);
+ }
+
+ public function uploadFiles()
+ {
+ //获取参数
+ $input = $this->_param;
+ //获取文件列表
+ $files = $this->request->file('file');
+ if(empty($files)) $files = $this->request->file('files');
+ if(empty($files)) $files = $this->request->file('filePath');
+ //检查文件是否存在
+ if(empty($files)) return $this->error('not file ,please check file.');
+ //设置类型
+ $type = 'picture';
+ if(isset($input['type'])) $type = $input['type'];
+ $result = [];
+ //生成上传模型
+ $uploda_model = new Upload($this->_uniacid);
+ foreach($files as $file)
+ {
+ //上传文件
+ $info = $uploda_model->upload($type ,$file);
+
+ if(!empty($info))
+ {
+ if(isset($info['attachment']) && !empty($info['attachment']))
+ {
+ $info['attachment_path'] = $info['attachment'];
+ $info = transImagesOne($info ,['attachment_path'] ,$this->_uniacid);
+ }
+ //获取上传者id
+ $info['uid'] = $this->uid;
+// $info['attachment_path'] = longbingGetFilePath($info['attachment'] , $this->_host,$this->_uniacid);
+ //数据来源
+ $info['from'] = 'wx';
+ //写入数据库
+ $attachment_model = new CoreAttachment();
+ $data = $attachment_model->createAttach($info);
+ //判断写入数据库是否成功
+ if(!empty($data)) $result[] = $info;
+ }
+ }
+ //数据处理
+ return $this->success($result);
+ }
+}
\ No newline at end of file
diff --git a/app/admin/event.php b/app/admin/event.php
new file mode 100755
index 0000000..0aed2e0
--- /dev/null
+++ b/app/admin/event.php
@@ -0,0 +1,5 @@
+ $menu], true);
+return ['admin' => $menu];
+
+
diff --git a/app/admin/info/Info.php b/app/admin/info/Info.php
new file mode 100755
index 0000000..830b7b9
--- /dev/null
+++ b/app/admin/info/Info.php
@@ -0,0 +1,29 @@
+ 'admin',
+ //模块标题[必填]
+ 'title' =>'系统',
+ //内容简介
+ 'desc' =>'',
+ //封面图标
+ 'icon' =>'',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => 'model',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'admin.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.1.42',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module' => [],
+ // 插件依赖[可选],格式[[插件名, 插件唯一标识, 依赖版本, 对比方式]]
+ 'need_plugin' => [],
+];
\ No newline at end of file
diff --git a/app/admin/info/PermissionAdmin.php b/app/admin/info/PermissionAdmin.php
new file mode 100755
index 0000000..123f442
--- /dev/null
+++ b/app/admin/info/PermissionAdmin.php
@@ -0,0 +1,84 @@
+saasKey = longbing_get_auth_prefix('AUTH_MINI') ;
+ parent::__construct($uniacid, self::tabbarKey, self::adminMenuKey, $this->saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+ return true ;
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+ return true;
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+ return true;
+ }
+
+ /**
+ * 获取授权数量
+ *
+ * @author shuixian
+ * @DataTime: 2019/12/19 19:02
+ */
+ public function getAuthNumber(){
+ $authNumber = $this->getAuthVaule( $this->saasKey ,2 ) ;
+ $authNumber = $authNumber == 0 ? 99999999 : $authNumber ;
+ return $authNumber ;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/info/RadarMessage.php b/app/admin/info/RadarMessage.php
new file mode 100755
index 0000000..d4a7eb1
--- /dev/null
+++ b/app/admin/info/RadarMessage.php
@@ -0,0 +1,667 @@
+ "praises",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看",
+ "item"=> "名片",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "对你已建立信任,保持联系持续跟进",
+ "operation"=> "将",
+ "item"=> "手机号码存入了手机通讯录",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "咨询意向强烈,及时联系确保沟通顺畅",
+ "operation"=> "拨打",
+ "item"=> "手机号",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_user_info",
+ "field"=> "phone",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请随时保持电话畅通",
+ "operation"=> "拨打",
+ "item"=> "公司电话",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "客户请随时可能加你微信",
+ "operation"=> "复制了",
+ "item"=> "微信",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 5,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "可能随时邮寄文件给你,请注意查收",
+ "operation"=> "复制了",
+ "item"=> "邮箱",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 6,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "复制",
+ "item"=> "公司名称",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 7,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "对你的公司非常感兴趣",
+ "operation"=> "查看了",
+ "item"=> "公司地址",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "咨询",
+ "item"=> "产品",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 9,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "播放",
+ "item"=> "语音",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 10,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "保存了",
+ "item"=> "名片海报",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请随时保持电话畅通",
+ "operation"=> "拨打",
+ "item"=> "400热线",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商城列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机,主动提供细致的商品讲解将大大有利于成交",
+ "operation"=> "正在查看你的",
+ "item"=> "商品",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_goods",
+ "field"=> "name",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "看来TA对公司动态感兴趣",
+ "operation"=> "浏览",
+ "item"=> "动态列表",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "点赞",
+ "item"=> "动态",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 5,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "评论了",
+ "item"=> "动态",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 6,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "查看了",
+ "item"=> "企业官网",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 7,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "动态",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "动态视频",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 9,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "动态外链",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 10,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "通过动态列表跳转小程序",
+ "item"=> "",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_timeline",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商品分类列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 12,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快展开跟进",
+ "operation"=> "正在阅读",
+ "item"=> "文章",
+ "show_count"=> 0,
+ "table_name"=> "lb_marketing_article_v2",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 13,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "分享了",
+ "item"=> "文章",
+ "show_count"=> 0,
+ "table_name"=> "lb_marketing_article_v2",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 14,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "保存",
+ "item"=> "文章海报",
+ "show_count"=> 0,
+ "table_name"=> "lb_marketing_article_v2",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 15,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "查看了",
+ "item"=> "预约",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 16,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "预约栏目",
+ "show_count"=> 1,
+ "table_name"=> "lb_appoint_classify",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 17,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "预约活动",
+ "operation"=> "正在查看",
+ "item"=> "预约",
+ "show_count"=> 0,
+ "table_name"=> "lb_appoint_project",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 18,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快处理",
+ "operation"=> "在官网留言",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_form",
+ "field"=> "name,phone,content",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 19,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "订单商品已发货,系统订单号为:",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 20,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "自提商品已提货",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 21,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请等待管理员审核并注意查收",
+ "operation"=> "已申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 22,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "已取消申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 23,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "管理员拒绝退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 24,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请注意查收",
+ "operation"=> "退款成功",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 25,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "查看了",
+ "item"=> "活动",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 26,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "活动报名分类列表",
+ "show_count"=> 1,
+ "table_name"=> "lb_activity_classify",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 27,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "正在查看",
+ "item"=> "活动",
+ "show_count"=> 0,
+ "table_name"=> "lb_activity_activity",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 28,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在活动开始前提醒客户",
+ "operation"=> "已参加了活动",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "lb_activity_activity",
+ "field"=> "title",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 29,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "正在查看",
+ "item"=> "房源信息",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 30,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看了",
+ "item"=> "房源",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_house",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "语音点赞",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看",
+ "item"=> "名片",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ]
+
+];
+
+return $radar_msg;
\ No newline at end of file
diff --git a/app/admin/lang/zh-cn.php b/app/admin/lang/zh-cn.php
new file mode 100755
index 0000000..d7ca290
--- /dev/null
+++ b/app/admin/lang/zh-cn.php
@@ -0,0 +1,10 @@
+ '欢迎使用ThinkPHP',
+ 'data type error' => '数据类型错误',
+ 'tabbar count can not be greater than' => '菜单栏数量不能大于',
+ 'auto get template error' => '自动获取服务通知模板失败,请稍后再试。',
+ 'wx app site error ,please check site message.' => '微信小程序配置异常,请检查站点配置',
+ 'wx app site error' => '微信小程序配置异常,请检查站点配置',
+ 'upload config error' => '上传配置错误,请检查上传配置是否正确。'
+];
\ No newline at end of file
diff --git a/app/admin/middleware.php b/app/admin/middleware.php
new file mode 100755
index 0000000..d899c5f
--- /dev/null
+++ b/app/admin/middleware.php
@@ -0,0 +1,5 @@
+hasOne('Role' , 'role_id' ,'role_id');
+ }
+ //公司关联
+ public function company() {
+ return $this->hasOne('Company' ,'company_id' ,'company_id');
+ }
+ //创建admin
+ public function createAdmin($data) {
+ return $this->createRow($data);
+ }
+
+ //修改admin
+ public function updateAdmin($filter ,$data) {
+ return $this->updateRow($filter ,$data);
+ }
+
+ //删除admin
+ public function delAdmin($filter) {
+ return $this->delRow($filter);
+ }
+
+ //获取admin详情
+ public function getAdmin($filter) {
+ $data = $this->with(['company' => function($query) {
+ $query->where(['deleted' => 0 ,'status' => 1])->field('company_name ,is_top');
+ }])
+ ->where($filter)
+ ->find();
+ if(!empty($data)) $data = $data->toArray();
+// $data = Db::name($this->name)
+// ->alias('admin')
+// ->leftJoin('user' ,'admin.user_id = user.user_id')
+// ->where(['admin.account' => 'admin'])
+// ->find();
+ return $data;
+ }
+
+ //获取admin列表
+ public function listAdmin($filter ,$page_config) {
+
+ }
+
+ //获取admin总数
+ public function listAdminCount($filter) {
+
+ }
+
+ //获取所有admin
+ public function listAdminAll($filter) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/AdminRole.php b/app/admin/model/AdminRole.php
new file mode 100755
index 0000000..4b0166d
--- /dev/null
+++ b/app/admin/model/AdminRole.php
@@ -0,0 +1,32 @@
+time();
+ return $this->save($data);
+ }
+ //删除用户权限
+ public function delUserRole($filter){
+ return $this->delRow($filter);
+ }
+
+}
\ No newline at end of file
diff --git a/app/admin/model/AppConfig.php b/app/admin/model/AppConfig.php
new file mode 100755
index 0000000..f098596
--- /dev/null
+++ b/app/admin/model/AppConfig.php
@@ -0,0 +1,83 @@
+ $uniacid, ] );
+ }
+
+ public function getConfig ($uniacid)
+ {
+ $key = 'longbing_card_config_';
+
+ $cacheData = getCache($key, $uniacid);
+
+ // 暂时关闭缓存
+ $cacheData = false;
+
+ if ($cacheData)
+ {
+ $cacheData['fromCache'] = 1;
+ return $cacheData;
+ }
+
+ $data = self::where( [ [ 'uniacid', '=', $uniacid ] ] )
+ ->find();
+
+ if ( !$data )
+ {
+ $data = $this->initConfig($uniacid);
+ }
+
+ $data = $data->toArray();
+
+
+ $data = transImagesOne( $data, [ 'vr_cover', 'default_video', 'default_voice', 'appoint_pic', 'click_copy_show_img',
+ 'shop_carousel_more', 'copyright', 'default_video_cover' ], $uniacid
+ );
+ setCache( $key, $data, 36000, $uniacid );
+
+ return $data;
+ }
+ //获取
+ public function getConfigByUniacid($uniacid)
+ {
+ $result = $this->where(['uniacid' => $uniacid])->find();
+ if(!empty($result)){
+ $result = $result->toArray();
+ }
+ return $result;
+ }
+ //创建
+ public function createConfig($data)
+ {
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ return !empty($result);
+ }
+
+ //更新
+ public function updateConfig($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/AppTabbar.php b/app/admin/model/AppTabbar.php
new file mode 100755
index 0000000..3253c3b
--- /dev/null
+++ b/app/admin/model/AppTabbar.php
@@ -0,0 +1,52 @@
+save($data);
+ return !empty($result);
+ }
+
+ //获取
+ public function getTabbar($filter)
+ {
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //修改
+ public function updateTabbar($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ //删除
+ public function delTabbar($filter)
+ {
+ $result = $this->destoryTabbar($filter);
+ return !empty($result);
+ }
+
+ //删除(真删除)
+ public function destoryTabbar($filter)
+ {
+ $result = $this->where($filter)->delete() ;
+ return !empty($result);
+ }
+
+}
\ No newline at end of file
diff --git a/app/admin/model/AttachmentGroup.php b/app/admin/model/AttachmentGroup.php
new file mode 100755
index 0000000..644fb6c
--- /dev/null
+++ b/app/admin/model/AttachmentGroup.php
@@ -0,0 +1,69 @@
+where('name','like', '%' . $value . '%');
+ }
+
+
+ //创建
+ function createGroup($data)
+ {
+ $result = $this->save($data);
+ return !empty($result);
+ }
+
+ //更新
+ function updateGroup($filter ,$data)
+ {
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ //获取列表
+// function listGroup($filter)
+// {
+// $result = $this->where($filter)->select();
+// if(!empty($result)) $result = $result->toArray();
+// return $result;
+// }
+
+ //获取列表
+ function listGroup($filter)
+ {
+ $result = $this->withSearch(['name'] ,$filter)->where('uniacid','=',$filter['uniacid'])
+ ->order('id')
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //获取单个数据
+ function getGroup($filter)
+ {
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //删除
+ function delGroup($filter)
+ {
+ return $this->destoryGroup($filter);
+ }
+
+ //删除(真删除)
+ function destoryGroup($filter)
+ {
+ $result = $this->where($filter)->delete();
+ return !empty($result);
+ }
+}
diff --git a/app/admin/model/CardUser.php b/app/admin/model/CardUser.php
new file mode 100755
index 0000000..916d2f3
--- /dev/null
+++ b/app/admin/model/CardUser.php
@@ -0,0 +1,20 @@
+whereIn('id',$idlist)->field('id,avatarUrl')->select();
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/Company.php b/app/admin/model/Company.php
new file mode 100755
index 0000000..9cfbdd1
--- /dev/null
+++ b/app/admin/model/Company.php
@@ -0,0 +1,69 @@
+time;
+ return $this->createRow($data);
+ }
+
+ //修改公司信息
+ function updateCompany($filter ,$data) {
+ $filter['deleted'] = 0;
+ return $this->updateRow($filter ,$data);
+ }
+
+ //删除公司信息
+ function delCompany($filter){
+ $filter['deleted'] = 0;
+ return $this->delRow($filter);
+ }
+
+ //获取公司详情
+ function getCompany($filter) {
+ $filter['company.deleted'] = 0;
+ $company = $this
+ ->alias('company')
+ ->leftJoin('user user' ,'company.creator_id = user.user_id')
+ ->where($filter)
+ ->field(['company.*' ,'user.user_name as creator_name'])
+ ->find();
+ return $company;
+ }
+
+ //获取公司列表
+ function listCompany($filter ,$page_config) {
+ $filter['user.deleted'] = 0;
+ $companys = $this
+ ->alias('company')
+ ->leftJoin('user user' ,'company.creator_id = user.user_id')
+ ->where($filter)
+ ->field(['company.*' ,'user.user_name as creator_name'])
+ ->page($page_config['page'] ,$page_config['page_count'])
+ ->select();
+ return $companys;
+ }
+
+ //获取公司总数
+ function listCompanyCount($filter) {
+ $filter['user.deleted'] = 0;
+ $count = $this
+ ->alias('company')
+ ->leftJoin('user user' ,'company.creator_id = user.user_id')
+ ->field(['company.company_id'])
+ ->where($filter)
+ ->count();
+ return $count;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/CoreAttachment.php b/app/admin/model/CoreAttachment.php
new file mode 100755
index 0000000..b25163c
--- /dev/null
+++ b/app/admin/model/CoreAttachment.php
@@ -0,0 +1,89 @@
+where('id','in' ,$ids);
+ }
+ //创建
+ public function createAttach($data)
+ {
+ $data['module_upload_dir'] = 0;
+ $data['displayorder'] = 0;
+ $data['group_id'] = !empty($data['group_id'])?$data['group_id']:0;
+ $result = $this->save($data);
+ $result = !empty($result);
+ return $result;
+ }
+
+ //更新
+ public function updateAttach($filter ,$data)
+ {
+ $result = $this->where($filter)->update($data);
+ $result = !empty($result);
+ return $result;
+ }
+
+ //获取列表
+ public function listAttach($filter ,$page_config)
+ {
+ $start_row = ($page_config['page'] - 1) * $page_config['page_count'];
+ $end_row = $page_config['page_count'];
+ $result = $this->where($filter)
+ ->order('createtime' ,'desc')
+ ->limit($start_row ,$end_row)
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //获取数据总数
+ public function listAttachCount($filter)
+ {
+ $result = $this->where($filter)
+ ->count();
+ return $result;
+ }
+
+
+ //创建
+ public function addAttach($data)
+ {
+ $data['module_upload_dir'] = 0;
+
+ $result = $this->insert($data);
+
+ return $result;
+ }
+
+ //获取
+ public function getAttach($filter)
+ {
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //删除
+ public function delAttach($filter)
+ {
+ return $this->destoryAttach($filter);
+ }
+
+ //删除(真删除)
+ public function destoryAttach($filter)
+ {
+ //return $this->where($filter)->delete();
+ $result = $this->withSearch(['ids'] ,$filter)->delete();
+ return !empty($result);
+ }
+
+}
diff --git a/app/admin/model/Coupon.php b/app/admin/model/Coupon.php
new file mode 100755
index 0000000..92805ae
--- /dev/null
+++ b/app/admin/model/Coupon.php
@@ -0,0 +1,107 @@
+'已删除',0=>'未发布',1=>'已发布'];
+ return $status[$data['status']];
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @return mixed
+ * 类型
+ */
+ public function getTypeTextAttr($value,$data){
+ $type = [1=>'线上',2=>'线下'];
+ return $type[$data['type']];
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @return false|string
+ * 到期时间
+ */
+ public function getEndTimeAttr($value,$data){
+ return date('Y-m-d H:i:s',$data['end_time']);
+ }
+ /**
+ * @param $value
+ * @param $data
+ * @return false|string
+ * 创建时间
+ */
+ public function getCreateTimeAttr($value,$data){
+ return date('Y-m-d H:i:s',$data['create_time']);
+ }
+
+ /*获取福包列表
+ */
+ public function couponList($dis,$page=10){
+
+ $data = self::where($dis)->order('top desc')->paginate($page)->toArray();
+ return $data;
+ }
+
+ /**
+ * 修改福包
+ */
+
+ public function couponUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = Db::name($this->name)->where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ *
+ * 添加福包
+ */
+
+ public function couponAdd($data){
+ $data['create_time'] = time();
+ $res = Db::name($this->name)->insert($data);
+ return $res;
+ }
+
+ /**
+ * 获取福包详情
+ */
+
+ public function couponInfo($dis){
+ $data = Db::name($this->name)->where($dis)->find();
+ return $data;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/Department.php b/app/admin/model/Department.php
new file mode 100755
index 0000000..d8af0af
--- /dev/null
+++ b/app/admin/model/Department.php
@@ -0,0 +1,56 @@
+createRow($data);
+ }
+ //更新部门信息
+ public function updateDepartment($filter ,$data) {
+ return $this->updateRow($filter ,$data);
+ }
+ //删除部门信息
+ public function delDepartment($filter) {
+ return $this->delRow($filter);
+ }
+ //获取部门信息
+ public function getDepartment($filter) {
+ return $this->getRow($filter);
+ }
+ //获取部门列表信息
+ public function listDepartment($filter ,$page_config = ['page' => 1 ,'page_count' => 20]) {
+ $filter['deleted'] = 0;
+ $result = Db::name($this->name)
+ ->where($filter)
+ ->page($page_congig['page'] ,$page_config['page_count'])
+ ->select();
+ }
+ //获取部门列表总数
+ public function listDepartmentCount($filter) {
+ $filter['deleted'] = 0;
+ $result = Db::name($this->name)
+ ->where($filter)
+ ->count();
+ }
+ //获取所有部门列表信息
+ public function listDepartmentAll($filter) {
+ return $this->listRow($filter);
+ }
+}
diff --git a/app/admin/model/Goods.php b/app/admin/model/Goods.php
new file mode 100755
index 0000000..bb7f533
--- /dev/null
+++ b/app/admin/model/Goods.php
@@ -0,0 +1,68 @@
+paginate($page)->toArray();
+ return $data;
+ }
+
+ /**
+ * 修改商品
+ */
+
+ public function goodsUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = self::where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ *
+ * 添加商品
+ */
+
+ public function goodsAdd($data){
+ $data['create_time'] = time();
+ $res = self::insert($data);
+ return $res;
+ }
+
+ /**
+ * 获取商品详情
+ */
+
+ public function goodsInfo($dis){
+ $data = self::where($dis)->find();
+ return !empty($data)?$data->toArray():$data;
+ }
+
+ /**
+ * 查询所有分类
+ */
+ public function goodsSelect($dis){
+ $data = self::where($dis)->select();
+ return !empty($data)?$data->toArray():$data;
+
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/Menu.php b/app/admin/model/Menu.php
new file mode 100755
index 0000000..25e367a
--- /dev/null
+++ b/app/admin/model/Menu.php
@@ -0,0 +1,23 @@
+where($filter)
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/Module.php b/app/admin/model/Module.php
new file mode 100755
index 0000000..822d718
--- /dev/null
+++ b/app/admin/model/Module.php
@@ -0,0 +1,54 @@
+hasMany('menu' , 'module_id' ,'module_id');
+ }
+ //模块与app之间的关系
+ public function moduleApp()
+ {
+ return $this->hasOne('moduleApp' ,'module_id' ,'module_id');
+ }
+ //获取模块列表
+ public function listModuleAll($filter ,$uniacid = '7777')
+ {
+ $filter['deleted'] = 0;
+ $result = $this->with(['moduleApp' => function($query) use ($uniacid) {
+ $query->where(['deleted' => 0 ,'uniacid' => $uniacid]);
+ }])
+ ->where($filter)
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ public function getModule($filter ,$uniacid = '7777')
+ {
+ $filter['deleted'] = 0;
+ $result = $this->with(['moduleApp' => function($query) use ($uniacid) {
+ $query->where(['deleted' => 0 ,'uniacid' => $uniacid]);
+ }])
+ ->where($filter)
+ ->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //获取模块列表(分页)
+ public function listModule() {
+
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/OssConfig.php b/app/admin/model/OssConfig.php
new file mode 100755
index 0000000..9a39490
--- /dev/null
+++ b/app/admin/model/OssConfig.php
@@ -0,0 +1,67 @@
+save($data);
+ if(empty($result)) return false;
+ return true;
+ }
+ //修改
+ public function updateConfig($filter ,$data)
+ {
+ $filter['deleted'] = 0;
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ if(empty($result)) return false;
+ return true;
+ }
+
+ //获取列表
+ public function listConfig($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->where($filter)->select();
+ if(!empty($result)) $result->toArray();
+ return $result;
+ }
+ //获取总数
+ public function listConfigCount($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+
+ //获取单条数据
+ public function getConfig($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //删除
+ public function delConfig($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->updateConfig($filter ,['deleted' => 0 ,'delete_time' => time()]);
+ }
+ //删除(真删除)
+ public function destoryConfig($filter)
+ {
+ return $this->where($filter)->delete();
+ }
+
+}
\ No newline at end of file
diff --git a/app/admin/model/Role.php b/app/admin/model/Role.php
new file mode 100755
index 0000000..bb28d5c
--- /dev/null
+++ b/app/admin/model/Role.php
@@ -0,0 +1,58 @@
+ 'string',
+ 'role_name' => 'string',
+ 'is_system' => 'int',
+ 'description' => 'string',
+ 'create_time' => 'int',
+ 'uniacid' => 'int',
+ 'update_time' => 'int',
+ 'deleted' => 'int'
+ ];
+ protected $resultSetType = 'array';
+ //初始化
+ function __construct() {
+ parent::__construct();
+ }
+
+ protected static function init()
+ {
+ //TODO:初始化内容
+ }
+ //用户关联绑定
+ public function user() {
+ return $this->belongsTo('AdminUser' ,'role_id' ,'role_id');
+ }
+
+
+ //获取权限信息
+ public function getRole($filter) {
+ return $this->getRow($filter);
+ }
+ //获取权限列表
+ public function listRoleAll($filter) {
+// return $this->select($filter);
+ return $this->listRow($filter ,['role_id' ,'role_name' ,'is_system' ,'description' ,'deleted']);
+ }
+ //创建权限
+ public function createRole($data) {
+ return $this->createRow($data);
+ }
+ //更新权限
+ public function updateRole($filter ,$data) {
+ return $this->updateRow($filter ,$data);
+ }
+ //删除权限
+ public function deleteRole($filter) {
+ return $this->deleteRow($filter);
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/SellingProfit.php b/app/admin/model/SellingProfit.php
new file mode 100755
index 0000000..9574c3a
--- /dev/null
+++ b/app/admin/model/SellingProfit.php
@@ -0,0 +1,51 @@
+name)
+ ->alias('a')
+ ->leftJoin('longbing_card_user b' ,'a.user_id = b.id')
+ ->leftJoin('longbing_card_user_info c' ,'a.user_id = c.fans_id')
+ ->where($dis)
+ ->field(['a.*' ,'b.nickName','c.name'])
+ ->order('a.total_profit desc','a.id decs')
+ ->paginate($page)
+ ->toArray();
+ return $data;
+ }
+ /**
+ * @param $dis
+ * @param $data
+ * @return int
+ * 修改商城配置
+ */
+ public function configUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = self::where($dis)->update($data);
+ return $res;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/ShopBanner.php b/app/admin/model/ShopBanner.php
new file mode 100755
index 0000000..14c199e
--- /dev/null
+++ b/app/admin/model/ShopBanner.php
@@ -0,0 +1,68 @@
+paginate($page)->toArray();
+ return $data;
+ }
+ /**
+ * @param $dis
+ * @param $data
+ * @return int
+ * 修改商城轮播图
+ */
+ public function bannerUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = self::where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ * @param $data
+ * 添加商城轮播图
+ */
+ public function bannerAdd($data){
+ $data['create_time'] = time();
+ $res = self::insert($data);
+ return $res;
+ }
+
+ /**
+ * @param $dis
+ * 删除商城轮播图
+ */
+
+ public function bannerDel($dis){
+ $res = self::where($dis)->delete();
+ return $res;
+ }
+
+ /**
+ * @param $dis
+ * 轮播图详情
+ */
+ public function bannerInfo($dis){
+ $data = self::where($dis)->find();
+ return !empty($data)?$data->toArray():$data;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/ShopOrder.php b/app/admin/model/ShopOrder.php
new file mode 100755
index 0000000..bd5ea00
--- /dev/null
+++ b/app/admin/model/ShopOrder.php
@@ -0,0 +1,73 @@
+orderGoodsInfo($dis);
+ }
+ /**
+ * @param $dis
+ * @param int $page
+ * @return mixed
+ * 获取订单列表
+ */
+ public function orderList($dis,$page=10){
+ $data = self::where($dis)->paginate($page)->toArray();
+ return $data;
+ }
+ /**
+ * @param $dis
+ * @param $data
+ * @return int
+ * 修改订单
+ */
+
+ public function orderUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = self::where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ * @param $dis
+ * @return mixed
+ * 获取订单详情
+ */
+
+ public function orderInfo($dis,$field='*'){
+ $data = self::where($dis)->field($field)->find();
+ return !empty($data)?$data->toArray():$data;
+ }
+
+ //查询公司的金额
+ public function getCompanyPrice($company_id,$start,$end){
+ return $this->whereIn('company_id',$company_id)->whereBetween('create_time',[$start,$end])->where('pay_status',1)->where('order_status',3)->sum('total_price');
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/ShopOrderGoods.php b/app/admin/model/ShopOrderGoods.php
new file mode 100755
index 0000000..96790b8
--- /dev/null
+++ b/app/admin/model/ShopOrderGoods.php
@@ -0,0 +1,33 @@
+select()->toArray();
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/ShopOrderRefund.php b/app/admin/model/ShopOrderRefund.php
new file mode 100755
index 0000000..4941f83
--- /dev/null
+++ b/app/admin/model/ShopOrderRefund.php
@@ -0,0 +1,94 @@
+$data['order_goods_id']]:['order_id'=>$data['order_id']];
+ return $orer_goods_model->orderGoodsInfo($dis);
+ }
+ /**
+ * @param $value
+ * @param $data
+ * @return mixed
+ * 获取器 获取订单
+ */
+ public function getOrderTextAttr($value,$data){
+ $orer_model = new ShopOrder();
+ $dis['id'] = $data['order_id'];
+// $field = ''
+ return $orer_model->orderInfo($dis);
+
+ }
+ /**
+ * 获取订单列表
+ */
+ public function refundList($dis,$page=10){
+ $data = self::where($dis)->paginate($page)->toArray();
+ $data['data'] = $this->changeInfo($data['data']);
+ return $data;
+ }
+
+ /**
+ * 修改订单
+ */
+
+ public function refundUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = Db::name($this->name)->where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ * 获取订单详情
+ */
+
+ public function refundInfo($dis){
+ $data = self::where($dis)->find()->toArray();
+ return $data;
+ }
+
+ /**
+ * @param $data
+ * 转换数据
+ */
+ public function changeInfo($data){
+ if(!empty($data)){
+ foreach ($data as &$v){
+ $v['price'] = empty($v['price'])?$v['order_text']['price']:$v['price'];
+ $v['goods_text'][0]['number'] = !empty($v['number'])?$v['number']:$v['goods_text'][0]['number'];
+ }
+ }
+ return $data;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/ShopSetting.php b/app/admin/model/ShopSetting.php
new file mode 100755
index 0000000..f95fedd
--- /dev/null
+++ b/app/admin/model/ShopSetting.php
@@ -0,0 +1,43 @@
+find();
+ return !empty($data)?$data->toArray():$data;
+ }
+ /**
+ * @param $dis
+ * @param $data
+ * @return int
+ * 修改商城配置
+ */
+ public function configUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = self::where($dis)->update($data);
+ return $res;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/ShopType.php b/app/admin/model/ShopType.php
new file mode 100755
index 0000000..1b6af03
--- /dev/null
+++ b/app/admin/model/ShopType.php
@@ -0,0 +1,101 @@
+name)->where($dis)->paginate($page)->toArray();
+ return $this->getTree($data['data'],0);
+ }
+ /**
+ * @param $data
+ * @param $pId
+ * @return array
+ * 递归无限极
+ */
+ public function getTree($data, $pId){
+ $tree = array();
+ if(!empty($data)){
+ foreach($data as $k => $v) {
+ if($v['pid'] == $pId) {
+ $v[''] = $this->getTree($data, $v['id']);
+ $tree[] = $v;
+ }
+ }
+ }
+ return $tree;
+ }
+
+ /**
+ * 修改分类
+ */
+ public function cateUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = Db::name($this->name)->where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ *
+ * 添加分类
+ */
+
+ public function cateAdd($data){
+ $data['create_time'] = time();
+ $res = Db::name($this->name)->insert($data);
+ return $res;
+ }
+
+ /**
+ * 获取分类详情
+ */
+
+ public function cateInfo($dis){
+ $data = Db::name($this->name)->where($dis)->find();
+ return $data;
+ }
+
+
+ /**
+ * 查询分类
+ */
+ public function catSelect($dis=array()){
+ $data = Db::name($this->name)->where($dis)->select();
+ return $data;
+ }
+
+ /**
+ * 排序好的分类
+ */
+
+ public function catSortSelect($dis=array()){
+ $data = Db::name($this->name)->where($dis)->select();
+ return $this->getTree($data,0);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/User.php b/app/admin/model/User.php
new file mode 100755
index 0000000..67d2d90
--- /dev/null
+++ b/app/admin/model/User.php
@@ -0,0 +1,101 @@
+hasOne('Role' , 'role_id' ,'role_id');
+ }
+
+ //获取用户信息
+ public function getUser($filter) {
+ $user = Db::name($this->name)
+ ->where(['deleted' => 0])
+ ->where($filter)
+ ->find();
+ if(isset($user['user_id'])){
+ $user['role'] = Db::name('user_role')
+ ->alias('ur')
+ ->leftJoin('role role' ,'ur.role_id = role.role_id')
+ ->where(['role.deleted' => 0 ,'ur.deleted' => 0])
+ ->where(['ur.user_id' => $user['user_id']])
+ ->field(['role.role_name' ,'role.role_id'])
+ ->select();
+ }
+ return $user;
+ }
+ //获取所有用户
+ public function listUserAll($filter) {
+ $users = Db::name($this->name)
+ ->alias('user')
+ ->leftJoin('department dp' ,'user.department_id = dp.department_id')
+ ->where(['user.deleted' => 0 ,'dp.deleted' => 0])
+ ->where($filter)
+ ->field(['user.*' ,'dp.department_name'])
+ ->select();
+// ->leftJoin('role role' ,'user.role_id = role.role_id')
+// ->where(['user.deleted' => 0 ,'role.deleted' => 0])
+// ->where($filter)
+// ->field(['user.*' ,'role.role_name'])
+// ->select();
+ return $users;
+ }
+ //获取用户列表
+ public function listUser($filter ,$page_config = ['page' => 1 ,'page_count' => 10]) {
+// $start_row = ($page_config['page'] - 1) * $page_config['page_count'];
+// $end_row = $page_config['page'] * $page_config['page_count'];
+ $users = Db::name($this->name)
+ ->alias('user')
+// ->leftJoin('role role' ,'user.role_id = role.role_id')
+// ->where(['user.deleted' => 0 ,'role.deleted' => 0])
+// ->where($filter)
+// ->field(['user.*' ,'role.role_name'])
+ ->leftJoin('department dp' ,'user.department_id = dp.department_id')
+ ->where(['user.deleted' => 0 ,'dp.deleted' => 0])
+ ->where($filter)
+ ->field(['user.id' ,'dp.department_name'])
+ ->page($page_config['page'] ,$page_config['page_count'])
+ ->select();
+ return $users;
+ }
+ //获取用户总数
+ public function listUserCount($filter) {
+ return $users = Db::name($this->name)
+ ->alias('user')
+// ->leftJoin('role role' ,'user.role_id = role.role_id')
+// ->where(['user.deleted' => 0 ,'role.deleted' => 0])
+// ->where($filter)
+// ->field(['user.*' ,'role.role_name'])
+ ->leftJoin('department dp' ,'user.department_id = dp.department_id')
+ ->where(['user.deleted' => 0 ,'dp.deleted' => 0])
+ ->where($filter)
+ ->field(['user.id'])
+ ->count();
+ }
+
+ //创建用户
+ public function createUser($data) {
+ return $this->createRow($data);
+ }
+
+ //修改用户
+ public function updateUser($filter ,$data) {
+ return $this->updateRow($filter ,$data);
+ }
+
+ //删除用户
+ public function delUser($filter) {
+ return $this->deleteRow($filter);
+ }
+}
\ No newline at end of file
diff --git a/app/admin/model/WxUpload.php b/app/admin/model/WxUpload.php
new file mode 100755
index 0000000..07ba817
--- /dev/null
+++ b/app/admin/model/WxUpload.php
@@ -0,0 +1,66 @@
+where($dis)->find();
+
+ if(empty($data)){
+
+ $this->insert($dis);
+ }
+
+ return $this->where($dis)->field($field)->find()->toArray();
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-08 18:49
+ * @功能说明:添加
+ */
+ public function settingAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-18 12:24
+ * @功能说明:配置编辑
+ */
+ public function settingUpdate($dis,$data){
+
+ $data['app_id'] = !empty($data['app_id'])?implode(',',$data['app_id']):'';
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/admin/model/moduleApp.php b/app/admin/model/moduleApp.php
new file mode 100755
index 0000000..eb358b4
--- /dev/null
+++ b/app/admin/model/moduleApp.php
@@ -0,0 +1,19 @@
+belongsTo('Module' ,'module_id' ,'module_id');
+ }
+}
\ No newline at end of file
diff --git a/app/admin/provider.php b/app/admin/provider.php
new file mode 100755
index 0000000..317c8ed
--- /dev/null
+++ b/app/admin/provider.php
@@ -0,0 +1,5 @@
+ $model_item ) {
+ $updateSqlPath = APP_PATH . $model_name . '/info/UpdateSql.php' ;
+ $lockPath = APP_PATH . $model_name . '/info/UpdateSql.lock' ;
+ $infoPath = APP_PATH . $model_name . '/info/Info.php' ;
+ $infoData = include $infoPath ;
+
+ $isUpdate = false ;
+ $nowVersion = array_key_exists('version',$infoData) ? $infoData['version'] : '0.0.0';
+ if(file_exists($lockPath)){ // 有锁定文件,需要进一步判断模块版本号
+
+ $lockVersion = file_get_contents($lockPath); //读取锁定文件版本号
+ $isUpdate = longbing_compare_version($lockVersion, $nowVersion) ? true : false ;
+
+ }else{
+ //锁定文件不存在,直接升级
+ $isUpdate = true ;
+ }
+
+ if($type==2){
+
+ $isUpdate = true ;
+
+ }
+
+ if($isUpdate && file_exists($updateSqlPath)){
+ $sql = include $updateSqlPath ;
+ $sql = str_replace(PHP_EOL, '', $sql);
+ $sqlArray = explode(';', $sql);
+ foreach ($sqlArray as $_value) {
+ if(!empty($_value)){
+
+ try{
+ Db::query($_value) ;
+ }catch (\Exception $e){
+ if (!APP_DEBUG){
+ //echo '操作失败: '.$_value . ' ' ;
+ }
+
+ }
+ }
+ }
+
+ //调试模式下,不写入锁定文件 ,方便调试
+ if (!APP_DEBUG){
+ file_put_contents($lockPath , $nowVersion) ;
+ }
+
+ }
+
+
+ }
+
+
+ }
+
+ /**
+ * 初始化微擎数据
+ *
+ * @author shuixian
+ * @DataTime: 2020/1/4 9:42
+ */
+ public static function initWeiqinConfigData(){
+ if(longbingIsWeiqin())
+ {
+ //获取uniacid
+ global $_GPC, $_W;
+ $uniacid = $_W[ 'uniacid' ];
+ if(!empty($uniacid))
+ {
+ //获取数据
+ //获取config
+ $app_config = longbingGetAppConfig($uniacid);
+ //判断config是否存在或者是否同步
+ if(empty($app_config) || empty($app_config['is_sync']))
+ {
+ //获取微擎配置
+ $weiqing_wx_app_model = new WxAppWeqingWxApp();
+ $weiqing_wx_app = $weiqing_wx_app_model->getApp(['uniacid' => $uniacid]);
+// var_dump($weiqing_wx_app);die;
+ if(!empty($weiqing_wx_app))
+ {
+ $data = ['is_sync' => 1];
+ if(isset($weiqing_wx_app['key']) && !empty($weiqing_wx_app['key'])) $data['appid'] = $weiqing_wx_app['key'];
+ if(isset($weiqing_wx_app['secret']) && !empty($weiqing_wx_app['secret'])) $data['app_secret'] = $weiqing_wx_app['secret'];
+ if(isset($weiqing_wx_app['name']) && !empty($weiqing_wx_app['name'])) $data['mini_app_name'] = $weiqing_wx_app['name'];
+ $app_config_model = new AppConfig();
+ if(empty($app_config))
+ {
+ $data['uniacid'] = $uniacid;
+ $data['force_phone'] = 0;
+ $app_config_model->createConfig($data);
+ }else{
+ $app_config_model->updateConfig(['uniacid' => $uniacid],$data);
+ }
+ longbingGetAppConfig($uniacid ,true);
+ }
+ }
+ //同步存储设置
+ $oss_config = longbingGetOssConfig($uniacid);
+ if(empty($oss_config) || empty($oss_config['is_sync'])){
+ $weiqing_oss = null;
+ if(isset($_W['setting']['remote_complete_info'][$_W['uniacid']])) $weiqing_oss = $_W['setting']['remote_complete_info'][$_W['uniacid']];
+ if(empty($weiqing_oss) && isset($_W['setting']['remote_complete_info'])) $weiqing_oss = $_W['setting']['remote_complete_info'];
+ if(!empty($weiqing_oss))
+ {
+ $data = ['is_sync' => 1];
+ if(isset($weiqing_oss['qiniu'])){
+ $data['open_oss'] = 2;
+ if(isset($weiqing_oss['qiniu']['accesskey']) && !empty($weiqing_oss['qiniu']['accesskey'])) $data['qiniu_accesskey'] = $weiqing_oss['qiniu']['accesskey'];
+ if(isset($weiqing_oss['qiniu']['secretkey']) && !empty($weiqing_oss['qiniu']['secretkey'])) $data['qiniu_secretkey'] = $weiqing_oss['qiniu']['secretkey'];
+ if(isset($weiqing_oss['qiniu']['bucket']) && !empty($weiqing_oss['qiniu']['bucket'])) $data['qiniu_bucket'] = $weiqing_oss['qiniu']['bucket'];
+ if(isset($weiqing_oss['qiniu']['url']) && !empty($weiqing_oss['qiniu']['url'])) $data['qiniu_yuming'] = $weiqing_oss['qiniu']['url'];
+ }
+ $oss_config_model = new OssConfig();
+ if(empty($oss_config))
+ {
+ $data['uniacid'] = $uniacid;
+ $oss_config_model->createConfig($data);
+ }else{
+ $oss_config_model->updateConfig(['uniacid' => $uniacid] ,$data);
+ }
+ longbingGetOssConfig($uniacid ,true);
+ }
+ }
+ //初始化地步菜单
+ /*$tabbars = longbingGetAppTabbar($uniacid);
+ if(empty($tabbars))
+ {
+ $tabbar_model = new AppTabbar();
+ $data = array(
+ 'uniacid' => $uniacid,
+ 'menu2_is_hide' => 0,
+ 'menu3_is_hide' => 0,
+ 'menu4_is_hide' => 0,
+ 'menu_activity_is_show' => 0,
+ 'menu_house_is_show' => 0,
+ 'menu_appoint_is_hide' => 0
+ );
+ $tabbar_model->createTabbar($data);
+ $tabbars = longbingGetAppTabbar($uniacid ,true);
+ }*/
+ longbingGetCompanyConfig($uniacid);
+ }
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/common.php b/app/agent/common.php
new file mode 100755
index 0000000..fa14a5b
--- /dev/null
+++ b/app/agent/common.php
@@ -0,0 +1,620 @@
+ $account ,'uniacid' => $uniacid ,'deleted' => 0])->count();
+ if(!empty($count)) $result = true;
+ return $result;
+}
+//获取角色信息
+function getRole($role_name = 'user',$uniacid = 7777) {
+ $list_role = listRole($uniacid);
+ foreach($list_role as $role) {
+ if(in_array($role_name, [$role['role_name']])) unset($role_name) ;return $role;
+ }
+ return false;
+}
+
+//获取角色模型
+function getRoleModel() {
+ return new RoleModel();
+}
+
+//获取角色列表
+function listRole($uniacid = 7777){
+ //从缓存中回去数据
+ $result = getCache('ListRole' . $uniacid);
+ if(!empty($result)) return $result;
+ $role_modle = getRoleModel();
+ $list_role = $role_modle->listRoleAll(['uniacid' => $uniacid]);
+ if(!empty($list_role)) {
+ setCache('ListRole' . $uniacid ,$list_role ,3600);
+ foreach($list_role as $role) {
+ setCache('role_' . $uniacid . '_' . $role['role_id'] ,$role ,3600);
+ }
+ }
+ return $list_role;
+}
+
+function ckeckRole($role_id ,$uniacid = 7777) {
+ $list_role = listRole($uniacid);
+ unset($list_role);
+ return getCache('role_' . $uniacid . '_' . $role['role_id']);
+}
+
+function listUserFilter($filter) {
+ $data = ['user.deleted' => 0 ,'role.deleted' => 0];
+ if(isset($filter['user_id'])) $data['user.user_id'] = $filter['user_id'];
+ if(isset($filter['account'])) $data['user.account'] = ['like' ,'%' . $filter['account'] . '%'];
+ if(isset($filter['name'])) $data['user.name'] = ['like' ,'%' . $filter['name'] . '%'];
+ if(isset($filter['creator_id'])) $data['user.creator_id'] = $filter['creator_id'];
+ if(isset($filter['status'])) $data['status'] = $filter['status'];
+ if(isset($filter['nickname'])) $data['user.nickname'] = ['like' ,'%' . $filter['nickname'] . '%'];
+ if(isset($filter['certificate_num'])) $data['user.certificate_num'] = $filter['certificate_num'];
+ if(isset($filter['email'])) $data['user.email'] = ['like' , '%' . $filter['email'] . '%'];
+ if(isset($filter['wechat'])) $data['user.wechat'] = ['like' , '%' . $filter['wechat'] . '%'];
+ if(isset($filter['qq'])) $data['user.qq'] = ['like' , '%' . $filter['qq'] . '%'];
+ if(isset($filter['mobile'])) $data['user.mobile'] = ['like' , '%' . $filter['mobile'] . '%'];
+ if(isset($filter['role_id'])) $data['user.role_id'] = $filter['role_id'];
+ if(isset($filter['uniacid'])) $data['user.uniacid'] = $filter['uniacid'];
+ if(isset($filter['department_id'])) $data['user.department_id'] = $filter['department_id'];
+ return $data;
+}
+
+function getUpdateUserFilter($data) {
+ if(isset($data['user_id'])) unset($data['user_id']);
+ if(isset($data['offset'])) unset($data['offset']);
+ if(isset($data['create_time'])) unset($data['create_time']);
+ if(isset($data['update_time'])) unset($data['update_time']);
+ if(isset($data['delete_time'])) unset($data['delete_time']);
+ return $data;
+}
+
+function getOssConfigData($data)
+{
+ $result['open_oss'] = 0;
+ if(isset($data['miniapp_name'])) $result['miniapp_name'] = $data['miniapp_name'];
+ if(isset($data['open_oss']) && in_array($data['open_oss'], [0,1,2,3,'0','1','2','3'])) $result['open_oss'] = $data['open_oss'];
+ if(isset($data['aliyun_bucket'])) $result['aliyun_bucket'] = $data['aliyun_bucket'];
+ if(isset($data['aliyun_access_key_id'])) $result['aliyun_access_key_id'] = $data['aliyun_access_key_id'];
+ if(isset($data['aliyun_access_key_secret'])) $result['aliyun_access_key_secret'] = $data['aliyun_access_key_secret'];
+ if(isset($data['aliyun_base_dir'])) $result['aliyun_base_dir'] = $data['aliyun_base_dir'];
+ if(isset($data['aliyun_zidinyi_yuming'])) $result['aliyun_zidinyi_yuming'] = $data['aliyun_zidinyi_yuming'];
+ if(isset($data['aliyun_endpoint'])) $result['aliyun_endpoint'] = $data['aliyun_endpoint'];
+ if(isset($data['aliyun_rules'])) $result['aliyun_rules'] = $data['aliyun_rules'];
+ if(isset($data['qiniu_accesskey'])) $result['qiniu_accesskey'] = $data['qiniu_accesskey'];
+ if(isset($data['qiniu_secretkey'])) $result['qiniu_secretkey'] = $data['qiniu_secretkey'];
+ if(isset($data['qiniu_bucket'])) $result['qiniu_bucket'] = $data['qiniu_bucket'];
+ if(isset($data['qiniu_yuming'])) $result['qiniu_yuming'] = $data['qiniu_yuming'];
+ if(isset($data['qiniu_rules'])) $result['qiniu_rules'] = $data['qiniu_rules'];
+ if(isset($data['tenxunyun_appid'])) $result['tenxunyun_appid'] = $data['tenxunyun_appid'];
+ if(isset($data['tenxunyun_secretid'])) $result['tenxunyun_secretid'] = $data['tenxunyun_secretid'];
+ if(isset($data['tenxunyun_secretkey'])) $result['tenxunyun_secretkey'] = $data['tenxunyun_secretkey'];
+ if(isset($data['tenxunyun_bucket'])) $result['tenxunyun_bucket'] = $data['tenxunyun_bucket'];
+ if(isset($data['tenxunyun_region'])) $result['tenxunyun_region'] = $data['tenxunyun_region'];
+ if(isset($data['tenxunyun_yuming'])) $result['tenxunyun_yuming'] = $data['tenxunyun_yuming'];
+ if(isset($data['apiclient_cert'])) $result['apiclient_cert'] = $data['apiclient_cert'];
+ if(isset($data['apiclient_key'])) $result['apiclient_key'] = $data['apiclient_key'];
+ return $result;
+}
+//底部菜单数据封装
+function longbingGetAppTabbarResponse($data)
+{
+ if(empty($data)) return [];
+ //数据处理
+ $data['data'] = [];
+ //处理过的参数
+ $menus = [];
+ //名片
+ if(isset($data['menu1_is_hide']))
+ {
+ $val = ['menu_name' => 'card'];
+ $val['is_show'] = $data['menu1_is_hide'];
+ if(isset($data['menu1_name'])) $val['name'] = $data['menu1_name'];
+ if(isset($data['menu1_url'])) $val['url'] = $data['menu1_url'];
+ if(isset($data['menu1_url_out'])) $val['url_out'] = $data['menu1_url_out'];
+ if(isset($data['menu1_url_jump_way'])) $val['url_jump_way'] = $data['menu1_url_jump_way'];
+ $data['data']['card'] = $val;
+ }
+ //商城
+ if(isset($data['menu2_is_hide']))
+ {
+ $val = ['menu_name' => 'shop'];
+ $val['is_show'] = $data['menu2_is_hide'];
+ if(isset($data['menu2_name'])) $val['name'] = $data['menu2_name'];
+ if(isset($data['menu2_url'])) $val['url'] = $data['menu2_url'];
+ if(isset($data['menu2_url_out'])) $val['url_out'] = $data['menu2_url_out'];
+ if(isset($data['menu2_url_jump_way'])) $val['url_jump_way'] = $data['menu2_url_jump_way'];
+ $data['data']['shop'] = $val;
+ }
+ //动态
+ if(isset($data['menu3_is_hide']))
+ {
+ $val = ['menu_name' => 'dynamic'];
+ $val['is_show'] = $data['menu3_is_hide'];
+ if(isset($data['menu3_name'])) $val['name'] = $data['menu3_name'];
+ if(isset($data['menu3_url'])) $val['url'] = $data['menu3_url'];
+ if(isset($data['menu3_url_out'])) $val['url_out'] = $data['menu3_url_out'];
+ if(isset($data['menu3_url_jump_way'])) $val['url_jump_way'] = $data['menu3_url_jump_way'];
+ $data['data']['dynamic'] = $val;
+ }
+ //官网
+ if(isset($data['menu4_is_hide']))
+ {
+ $val = ['menu_name' => 'website'];
+ $val['is_show'] = $data['menu4_is_hide'];
+ $menus[] = 'menu4_name';
+ if(isset($data['menu4_name'])) $val['name'] = $data['menu4_name'];
+ if(isset($data['menu4_url'])) $val['url'] = $data['menu4_url'];
+ if(isset($data['menu4_url_out'])) $val['url_out'] = $data['menu4_url_out'];
+ if(isset($data['menu4_url_jump_way'])) $val['url_jump_way'] = $data['menu4_url_jump_way'];
+ $data['data']['website'] = $val;
+ }
+ //预约
+ if(isset($data['menu_appoint_is_hide']))
+ {
+ $val = ['menu_name' => 'appointment'];
+ $val['is_show'] = $data['menu_appoint_is_hide'];
+ if(isset($data['menu_appoint_name'])) $val['name'] = $data['menu_appoint_name'];
+ if(isset($data['menu_appoint_url'])) $val['url'] = $data['menu_appoint_url'];
+ if(isset($data['menu_appoint_url_out'])) $val['url_out'] = $data['menu_appoint_url_out'];
+ if(isset($data['menu_appoint_url_jump_way'])) $val['url_jump_way'] = $data['menu_appoint_url_jump_way'];
+ $data['data']['appointment'] = $val;
+ }
+ //活动报名
+ if(isset($data['menu_activity_is_show']))
+ {
+ $val = ['menu_name' => 'activity'];
+ $val['is_show'] = $data['menu_activity_is_show'];
+ if(isset($data['menu_activity_name'])) $val['name'] = $data['menu_activity_name'];
+ if(isset($data['menu_activity_url'])) $val['url'] = $data['menu_activity_url'];
+ if(isset($data['menu_activity_url_out'])) $val['url_out'] = $data['menu_activity_url_out'];
+ if(isset($data['menu_activity_url_jump_way'])) $val['url_jump_way'] = $data['menu_activity_url_jump_way'];
+ $data['data']['activity'] = $val;
+ }
+ //房产
+ if(isset($data['menu_house_is_show']))
+ {
+ $val = ['menu_name' => 'house'];
+ $val['is_show'] = $data['menu_house_is_show'];
+ if(isset($data['menu_house_name']))$val['name'] = $data['menu_house_name'];
+ if(isset($data['menu_house_url']))$val['url'] = $data['menu_house_url'];
+ if(isset($data['menu_house_url_out']))$val['url_out'] = $data['menu_house_url_out'];
+ if(isset($data['menu_house_url_jump_way']))$val['url_jump_way'] = $data['menu_house_url_jump_way'];
+ $data['data']['house'] = $val;
+ }
+ $menus = ["menu1_name","menu1_is_hide","menu1_url","menu1_url_out","menu1_url_jump_way","menu2_name","menu2_is_hide","menu2_url","menu2_url_out","menu2_url_jump_way","menu3_name","menu3_is_hide","menu3_url","menu3_url_out","menu3_url_jump_way","menu4_name","menu4_is_hide","menu4_url","menu4_url_out","menu4_url_jump_way","menu_appoint_name","menu_appoint_is_hide","menu_appoint_url","menu_appoint_url_out","menu_appoint_url_jump_way","menu_activity_is_show","menu_activity_name","menu_activity_is_hide","menu_activity_url","menu_activity_url_out","menu_activity_url_jump_way","menu_house_is_show","menu_house_name","menu_house_is_hide","menu_house_url","menu_house_url_out","menu_house_url_jump_way"];
+ foreach($menus as $menu)
+ {
+ unset($data[$menu]);
+ }
+ return $data;
+}
+
+function longbingGetWxAppTabbarResponse($data)
+{
+ if(empty($data)) return [];
+ //数据处理
+ $data['data'] = [];
+ //处理过的参数
+ $menus = [];
+ //名片
+ if(isset($data['menu1_is_hide']) && !empty($data['menu1_is_hide']))
+ {
+ $val = [];
+ $val['is_show'] = $data['menu1_is_hide'];
+ $val['key'] = 1;
+ $val['iconPath'] = 'icon-mingpian';
+ $val['selectedIconPath'] = 'icon-mingpian1';
+ $val['pageComponents'] = 'cardHome';
+ if(isset($data['menu1_name'])) $val['name'] = $data['menu1_name'];
+ if(isset($data['menu1_url'])) $val['url'] = $data['menu1_url'];
+ if(isset($data['menu1_url_out'])) $val['url_out'] = $data['menu1_url_out'];
+ if(isset($data['menu1_url_jump_way'])) $val['jump_way'] = $data['menu1_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //商城
+ if(isset($data['menu2_is_hide']) && !empty($data['menu2_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 2;
+ $val['is_show'] = $data['menu2_is_hide'];
+ $val['iconPath'] = 'icon-shangcheng1';
+ $val['selectedIconPath'] = 'icon-shangcheng';
+ $val['pageComponents'] = 'shopHome';
+ if(isset($data['menu2_name'])) $val['name'] = $data['menu2_name'];
+ if(isset($data['menu2_url'])) $val['url'] = $data['menu2_url'];
+ if(isset($data['menu2_url_out'])) $val['url_out'] = $data['menu2_url_out'];
+ if(isset($data['menu2_url_jump_way'])) $val['url_jump_way'] = $data['menu2_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //动态
+ if(isset($data['menu3_is_hide']) && !empty($data['menu3_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 3;
+ $val['is_show'] = $data['menu3_is_hide'];
+ $val['iconPath'] = 'icon-dongtai1';
+ $val['selectedIconPath'] = 'icon-dongtai';
+ $val['pageComponents'] = 'infoHome';
+ if(isset($data['menu3_name'])) $val['name'] = $data['menu3_name'];
+ if(isset($data['menu3_url'])) $val['url'] = $data['menu3_url'];
+ if(isset($data['menu3_url_out'])) $val['url_out'] = $data['menu3_url_out'];
+ if(isset($data['menu3_url_jump_way'])) $val['url_jump_way'] = $data['menu3_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //官网
+ if(isset($data['menu4_is_hide']) && !empty($data['menu4_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 4;
+ $val['is_show'] = $data['menu4_is_hide'];
+ $val['iconPath'] = 'icon-guanwang';
+ $val['selectedIconPath'] = 'icon-guanwang1';
+ $val['pageComponents'] = 'websiteHome';
+ if(isset($data['menu4_name'])) $val['name'] = $data['menu4_name'];
+ if(isset($data['menu4_url'])) $val['url'] = $data['menu4_url'];
+ if(isset($data['menu4_url_out'])) $val['url_out'] = $data['menu4_url_out'];
+ if(isset($data['menu4_url_jump_way'])) $val['url_jump_way'] = $data['menu4_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //预约
+ if(isset($data['menu_appoint_is_hide']) && !empty($data['menu_appoint_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 7;
+ $val['is_show'] = $data['menu_appoint_is_hide'];
+ $val['iconPath'] = 'icon-yuyue';
+ $val['selectedIconPath'] = 'icon-yuyue1';
+ $val['pageComponents'] = 'reserveHome';
+ if(isset($data['menu_appoint_name'])) $val['name'] = $data['menu_appoint_name'];
+ if(isset($data['menu_appoint_url'])) $val['url'] = $data['menu_appoint_url'];
+ if(isset($data['menu_appoint_url_out'])) $val['url_out'] = $data['menu_appoint_url_out'];
+ if(isset($data['menu_appoint_url_jump_way'])) $val['url_jump_way'] = $data['menu_appoint_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //活动报名
+ if(isset($data['menu_activity_is_show']) && !empty($data['menu_activity_is_show']))
+ {
+ $val = [];
+ $val['key'] = 6;
+ $val['is_show'] = $data['menu_activity_is_show'];
+ $val['iconPath'] = 'icon-huodong1';
+ $val['selectedIconPath'] = 'icon-huodong';
+ $val['pageComponents'] = 'avtivityHome';
+ if(isset($data['menu_activity_name'])) $val['name'] = $data['menu_activity_name'];
+ if(isset($data['menu_activity_url'])) $val['url'] = $data['menu_activity_url'];
+ if(isset($data['menu_activity_url_out'])) $val['url_out'] = $data['menu_activity_url_out'];
+ if(isset($data['menu_activity_url_jump_way'])) $val['url_jump_way'] = $data['menu_activity_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ //房产
+ if(isset($data['menu_house_is_show']) && !empty($data['menu_house_is_show']))
+ {
+ $val = [];
+ $val['key'] = 5;
+ $val['is_show'] = $data['menu_house_is_show'];
+ $val['iconPath'] = 'icon-fangchan1';
+ $val['selectedIconPath'] = 'icon-fangchan';
+ $val['pageComponents'] = 'houseHome';
+ if(isset($data['menu_house_name']))$val['name'] = $data['menu_house_name'];
+ if(isset($data['menu_house_url']))$val['url'] = $data['menu_house_url'];
+ if(isset($data['menu_house_url_out']))$val['url_out'] = $data['menu_house_url_out'];
+ if(isset($data['menu_house_url_jump_way']))$val['url_jump_way'] = $data['menu_house_url_jump_way'];
+ $data['data'][] = $val;
+ }
+ $menus = ["menu1_name","menu1_is_hide","menu1_url","menu1_url_out","menu1_url_jump_way","menu2_name","menu2_is_hide","menu2_url","menu2_url_out","menu2_url_jump_way","menu3_name","menu3_is_hide","menu3_url","menu3_url_out","menu3_url_jump_way","menu4_name","menu4_is_hide","menu4_url","menu4_url_out","menu4_url_jump_way","menu_appoint_name","menu_appoint_is_hide","menu_appoint_url","menu_appoint_url_out","menu_appoint_url_jump_way","menu_activity_is_show","menu_activity_name","menu_activity_is_hide","menu_activity_url","menu_activity_url_out","menu_activity_url_jump_way","menu_house_is_show","menu_house_name","menu_house_is_hide","menu_house_url","menu_house_url_out","menu_house_url_jump_way"];
+ foreach($menus as $menu)
+ {
+ unset($data[$menu]);
+ }
+ return $data;
+}
+
+function longbingGetAppTabbarRequest($data)
+{
+ $result = [];
+ foreach($data as $key => $val)
+ {
+ switch($val['menu_name'])
+ {
+ case 'card':
+ if(isset($val['is_show'])) $result['menu1_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu1_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu1_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu1_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu1_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'shop':
+ if(isset($val['is_show'])) $result['menu2_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu2_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu2_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu2_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu2_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'dynamic':
+ if(isset($val['is_show'])) $result['menu3_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu3_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu3_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu3_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu3_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'website':
+ if(isset($val['is_show'])) $result['menu4_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu4_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu4_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu4_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu4_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'appointment':
+ if(isset($val['is_show'])) $result['menu_appoint_is_hide'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu_appoint_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu_appoint_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu_appoint_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu_appoint_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'activity':
+ if(isset($val['is_show'])) $result['menu_activity_is_show'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu_activity_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu_activity_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu_activity_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu_activity_url_jump_way'] = $val['url_jump_way'];
+ break;
+ case 'house':
+ if(isset($val['is_show'])) $result['menu_house_is_show'] = $val['is_show'];
+ if(isset($val['name'])) $result['menu_house_name'] = $val['name'];
+// if(isset($val['url'])) $result['menu_house_url'] = $val['url'];
+ if(isset($val['url_out'])) $result['menu_house_url_out'] = $val['url_out'];
+ if(isset($val['url_jump_way'])) $result['menu_house_url_jump_way'] = $val['url_jump_way'];
+ break;
+ default:
+ break;
+ }
+ }
+ return $result;
+}
+
+/*
+ * 获取branch id 程序唯一识别号
+ * @author yangqi
+ */
+function longbingGetBranchId()
+{
+ $app_config = Config::get( 'app' );
+ $key = 'branch_id';
+ $result = false;
+ if ( isset( $app_config[ $key ] ) ) $result = $app_config[ $key ];
+ return $result;
+}
+
+/*
+ * 获取branch id 程序版本号
+ * @author yangqi
+ */
+function longbingGetBranchVersionId()
+{
+ $app_config = Config::get( 'app' );
+ $key = 'version_id';
+ $result = false;
+ if ( isset( $app_config[ $key ] ) ) $result = $app_config[ $key ];
+ return $result;
+}
+
+/*
+ * 获取branch version name
+ * @author yangqi
+ */
+function longbingGetBranchVersionName()
+{
+ $app_config = Config::get( 'app' );
+ $key = 'version_name';
+ $result = '2.0.1';
+ if ( isset( $app_config[ $key ] ) ) $result = $app_config[ $key ];
+ return $result;
+}
+
+/**
+ * 获取站点绑定的数据
+ * @yangqi
+ */
+function longbingGetWebSiteBingData()
+{
+ //生成数据
+ $pluge_key_model = new LongbingPlugeKey();
+ $result = $pluge_key_model->getPlugeKey();
+ return $result;
+}
+
+//更新站点绑定数据
+function longbingUpdateWebSiteBingData($filter ,$data)
+{
+ $pluge_key_model = new LongbingPlugeKey();
+ $result = $pluge_key_model->updatePlugeKey($filter ,$data);
+ return !empty($result);
+}
+
+function longbingGetSaasUrl()
+{
+ $app_config = Config::get( 'app' );
+ $key = 'longbing_saas_url';
+ $result = 'http://api.longbing.org';
+ if ( isset( $app_config[ $key ] ) && !empty($app_config[ $key ])) $result = $app_config[ $key ];
+ return $result;
+}
+
+/**
+ * 下载文件
+ */
+function longbingGetFile($url, $save_dir = '', $filename = '', $type = 0) {
+ if (trim($url) == '') {
+ return false;
+ }
+ if (trim($save_dir) == '') {
+ $save_dir = './';
+ }
+ if (0 !== strrpos($save_dir, '/')) {
+ $save_dir.= '/';
+ }
+ //创建保存目录
+ if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
+ return false;
+ }
+ //获取远程文件所采用的方法
+ if ($type) {
+ $ch = curl_init();
+ $timeout = 5;
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
+ $content = curl_exec($ch);
+ curl_close($ch);
+ } else {
+ ob_start();
+ readfile($url);
+ $content = ob_get_contents();
+ ob_end_clean();
+ }
+ $size = strlen($content);
+ //文件大小
+ $fp2 = @fopen($save_dir . $filename, 'a');
+
+ fwrite($fp2, $content);
+ fclose($fp2);
+// unset($content, $url);
+ return array(
+ 'file_name' => $filename,
+ 'save_path' => $save_dir . $filename
+ );
+}
+/*
+php 从zip压缩文件中提取文件
+*/
+function longbingUnZipFile($zip_file_url ,$path = './upload/') {
+ $zip = new ZipArchive;
+ if ($zip->open($zip_file_url) === TRUE) {//中文文件名要使用ANSI编码的文件格式
+ $zip->extractTo($path);//提取全部文件
+ $zip->close();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+PHP文件目录copy
+@param string $dirsrc 原目录名称字符串
+@param string $dirto 目标目录名称字符串
+ */
+function longbingCopyDir($dirSrc,$dirTo)
+{
+ //判断目标文件夹是否存在
+ if(is_file($dirTo))
+ {
+ return false;
+ }
+ //判断目的文件夹是否存在
+ if(!file_exists($dirTo))
+ {
+ mkdir($dirTo);
+ }
+ //拷贝文件
+ if($handle=opendir($dirSrc))
+ {
+ while($filename=readdir($handle))
+ {
+ if($filename!='.' && $filename!='..')
+ {
+ $subsrcfile=$dirSrc . '/' . $filename;
+ $subtofile=$dirTo . '/' . $filename;
+ if(is_dir($subsrcfile))
+ {
+ longbingCopyDir($subsrcfile,$subtofile);//再次递归调用copydir
+ }
+ if(is_file($subsrcfile))
+ {
+ copy($subsrcfile,$subtofile);
+ }
+ }
+ }
+ closedir($handle);
+ return true;
+ }
+ return false;
+}
+
+function longbingGetBetween($input, $start, $end) {
+ $str = substr($input, strlen($start)+strpos($input, $start),(strlen($input) - strpos($input, $end))*(-1));
+ return $str;
+}
+
+
+function longbingGetZipName ($url) {
+ return longbingGetBetween($url ,"/" ,".zip");
+}
+
+/**
+ * 更新APP
+ */
+function longbingUpdateAppFile($down_url ,$save_dir, $file_name ,$cp_dir) {
+ $file_name = longbingGetZipName('/' .$file_name);
+ $download_file = longbingGetFile($down_url, $save_dir, $filename = $file_name.'.zip', $type = 1);
+
+
+ if(empty($download_file)) return FALSE;
+ $zip_url = $save_dir . "/" . $file_name.".zip";
+ $get_app_file = longbingUnZipFile($zip_url ,$save_dir);
+
+ if(empty($get_app_file)) return FALSE;
+ $update_file = longbingCopyDir($save_dir. "/" . $file_name , $cp_dir);
+ return $update_file;
+}
\ No newline at end of file
diff --git a/app/agent/controller/ActivityController.php b/app/agent/controller/ActivityController.php
new file mode 100755
index 0000000..486cb9e
--- /dev/null
+++ b/app/agent/controller/ActivityController.php
@@ -0,0 +1,154 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+
+ public function list()
+ {
+ $param = $this->_param;
+ $m_activity_auth2 = new Cardauth2ActivityModel();
+
+ //By.jingshuixian 2020年4月21日15:13:50
+ //区分行业版数据
+ if($this->_is_weiqin){
+ $app_model_name = APP_MODEL_NAME;
+ $list = $m_activity_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->join('account' , 'a.modular_id = account.uniacid')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+ ->where([['a.status', '=', 1] , ['account.type', '=', 4] ,['account.isdeleted', '=', 0] , ['v.modules', 'like', "%{$app_model_name}%"]])
+ ->group('a.modular_id')
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+
+
+
+ }else{
+
+
+ $list = $m_activity_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->where([['a.status', '=', 1]])
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+
+
+ }
+
+
+
+
+ $wxapp_map = [];
+ $wxapp = Db::name('account_wxapp')->field(['uniacid', 'name'])->select();
+ foreach ($wxapp as $item) {
+ $wxapp_map[$item['uniacid']] = $item['name'];
+ }
+
+ foreach ($list['data'] as $k => $item) {
+ $list['data'][$k]['name'] = $wxapp_map[$item['modular_id']] ?? $item['mini_app_name'];
+ unset($list['data'][$k]['mini_app_name']);
+ }
+
+
+ $list['total_activity_number'] = AdminUserService::getSassNum('activity',$this->_uniacid);
+
+ $list['total_activity_used'] = (int)$m_activity_auth2->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+
+ return $this->success($list);
+ }
+
+
+ public function create()
+ {
+ $data = $this->_input;
+
+ if (!isset($data['modular_id'])) {
+ return $this->success('参数错误');
+ }
+
+ $time = time();
+ $auth_activity = Cardauth2ActivityModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if (!$auth_activity->isEmpty()) {
+ return $this->error('已存在此小程序');
+ }
+
+ $total_activity_number = AdminUserService::getSassNum('activity',$this->_uniacid);
+
+ $total_activity_used = (int)$auth_activity->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+ $remain = $total_activity_number - $total_activity_used;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+ $rst = $auth_activity->save([
+ 'modular_id' => $data[ 'modular_id' ],
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'sign' => intval( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => 1,
+ 'uniacid' => $this->_uniacid,
+ ]);
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+ return $this->error('fail');
+ }
+
+
+ public function extendedOneYear ()
+ {
+ $data = $this->_input;
+ if (!isset($data['modular_id'])) {
+ return $this->success('参数错误');
+ }
+
+ $time = time();
+ $auth_activity = Cardauth2ActivityModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if ($auth_activity->isEmpty()) {
+ return $this->error('小程序不存在');
+ }
+
+ $total_activity_number = AdminUserService::getSassNum('activity',$this->_uniacid);
+
+ $total_activity_used = (int)$auth_activity->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+ $remain = $total_activity_number - $total_activity_used;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+ $rst = $auth_activity->save([
+ 'sign' => $auth_activity[ 'sign' ] > $time ? ($auth_activity[ 'sign' ] + ( 366 * 24 * 60 * 60 )) : ( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => $auth_activity['count'] + 1,
+ 'update_time' => $time,
+ ]);
+
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+
+ return $this->error('fail');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/AdminAuthAppController.php b/app/agent/controller/AdminAuthAppController.php
new file mode 100755
index 0000000..3ad5184
--- /dev/null
+++ b/app/agent/controller/AdminAuthAppController.php
@@ -0,0 +1,188 @@
+_param['app_name'])) $this->auth_app_name = $this->_param['app_name'] ;
+
+ $this->error(lang('app_name is empty')) ;
+
+ if ($this->_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-01-03 13:46
+ * @功能说明:授权列表
+ */
+ public function list(){
+ $param = $this->_param;
+ if (!isset($param['app_name'])) {
+ return $this->error('参数错误');
+ }
+
+
+ //By.jingshuixian 2020年4月21日15:13:50
+ //区分行业版数据
+
+ //获取列表
+ if($this->_is_weiqin){
+
+ $app_model_name = APP_MODEL_NAME;
+ $list = Cardauth2Model
+ ::alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+
+ ->join('account' , 'a.modular_id = account.uniacid')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+
+ ->where([['a.status', '=', 1],['app_name','like',"%". $param['app_name'] ."%"] , ['account.type', '=', 4] ,['account.isdeleted', '=', 0] , ['v.modules', 'like', "%{$app_model_name}%"] ])
+ ->group('a.id')
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])
+ ->toArray();
+
+ }else{
+
+ $list = Cardauth2Model
+ ::alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->where([['a.status', '=', 1],['app_name','=',$param['app_name']]])
+ ->group('a.id')
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])
+ ->toArray();
+
+ }
+
+ $wxapp_map = [];
+ $wxapp = Db::name('account_wxapp')->field(['uniacid', 'name'])->select();
+ foreach ($wxapp as $item) {
+ $wxapp_map[$item['uniacid']] = $item['name'];
+ }
+ //小程序名称
+ foreach ($list['data'] as $k => $item) {
+ $list['data'][$k]['name'] = $wxapp_map[$item['modular_id']] ?? $item['mini_app_name'];
+ unset($list['data'][$k]['mini_app_name']);
+ }
+ //总的授权数量
+ $list['total_number'] = AdminUserService::getSassNum($param['app_name'],$this->_uniacid);
+ //已经使用数量
+ $list['total_used'] = Cardauth2Model::where([['uniacid','in',$this->_uniacid_arr],['app_name','=',$param['app_name']]])->sum('count');
+
+ return $this->success($list);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-01-03 13:31
+ * @功能说明:创建小程序授权
+ */
+ public function create()
+ {
+ $data = $this->_input;
+ if (!isset($data['modular_id'])||!isset($data['app_name'])) {
+ return $this->error('参数错误');
+ }
+ //获取代理端授权数量
+ $num = AdminUserService::getSassNum($data['app_name'],$this->_uniacid);
+
+
+ $time = time();
+ //查询是否有该小程序下的模块
+ $auth = Cardauth2Model::where([['modular_id', '=', $data['modular_id']],['app_name','=',$data['app_name']]])->findOrEmpty();
+
+ if (!$auth->isEmpty()) {
+ return $this->error('已存在此小程序');
+ }
+ //已经使用
+ $total_num = Cardauth2Model::where([['uniacid','in',$this->_uniacid_arr],['app_name','=',$data['app_name']]])->sum('count');
+ //剩余数量
+ $remain = $num - $total_num;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+ //添加新的授权
+ $rst = $auth->save([
+ 'modular_id' => $data[ 'modular_id' ],
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'sign' => intval( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => 1,
+ 'uniacid' => $this->_uniacid,
+ 'app_name' => $data['app_name'],
+ 'sign_data' =>'ndvjnfjvnjnv'.$time
+ ]);
+ if ($rst) {
+ return $this->success('success');
+ }
+ return $this->error('fail');
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-01-03 13:42
+ * @功能说明:增加小程序授权一年
+ */
+ public function extendedOneYear ()
+ {
+ $data = $this->_input;
+ //参数验证
+ if (!isset($data['modular_id'])||!isset($data['app_name'])) {
+ return $this->error('参数错误');
+ }
+ $time = time();
+ $auth = Cardauth2Model::where([['modular_id', '=', $data['modular_id']],['app_name','=',$data['app_name']]])->findOrEmpty();
+ if ($auth->isEmpty()) {
+ return $this->error('小程序不存在');
+ }
+ //获取授权数量
+ $num = AdminUserService::getSassNum($data['app_name'],$this->_uniacid);
+ //获取已使用数量
+ $total_used = Cardauth2Model::where([['uniacid','in',$this->_uniacid_arr],['app_name','=',$data['app_name']]])->sum('count');
+
+ $remain = $num - $total_used;
+ //判断剩余数量
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+ //修改授权时间|增加使用数量
+ $rst = $auth->save([
+ 'sign' => $auth[ 'sign' ] > $time ? ($auth[ 'sign' ] + ( 366 * 24 * 60 * 60 )) : ( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => $auth['count'] + 1,
+ 'update_time' => $time,
+ ]);
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+ return $this->error('fail');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/AdminAuthController.php b/app/agent/controller/AdminAuthController.php
new file mode 100755
index 0000000..7b85265
--- /dev/null
+++ b/app/agent/controller/AdminAuthController.php
@@ -0,0 +1,135 @@
+request->getInput(), true );
+ $admin = AdminModel::where([
+ ['account', '=', $input['account'] ?? ''],
+ ['deleted', '=', 0],
+ ['status', '=', 1],
+ ])->findOrEmpty();
+
+ if ($admin->isEmpty()) {
+ return $this->error('用户不存在', 400);
+ }
+
+ //判断密码是否正确
+ if (!checkPasswd($input['passwd'], $admin['offset'], $admin['passwd'])) {
+ return $this->error('密码错误', 400);
+ }
+ //返回数据
+ $user = [
+ 'admin_id' => $admin->admin_id,
+ 'level' => $admin->level,
+ 'account'=> $admin->account,
+ 'role' => $admin->role->role_name ?? 'user',
+ 'role_name' => $admin->role->role_name ?? 'user',
+ 'uniacid' => $admin->appAdmin->modular_id ?? -1,
+ ];
+
+ if ($user['uniacid'] == -1) {
+ return $this->error("用户没有绑定小程序, 请联系代理端超级管理员");
+ }
+ if (isset($input['isAgent']) && $input['isAgent'] == true && $user['role'] != 'admin') {
+ return $this->error('普通用户禁止访问');
+ }
+
+ if (isset($input['isAgent']) && $input['isAgent'] == false && $user['role'] == 'admin') {
+ return $this->error('超级管理员禁止访问, 请创建子管理员账号并绑定小程序登录');
+ }
+
+ $result['user'] = $user;
+ $result['token'] = createToken();
+ if (empty($result['token'])) {
+ return $this->error('系统错误', 400);
+ }
+
+ //添加缓存数据
+ setUserForToken($result['token'], $user, 99999999);
+ return $this->success($result, 200);
+ }
+
+
+ //注销
+ public function unAuth()
+ {
+ $header = $this->request->header();
+ $token = $header['token'] ?? null;
+ if ($token == null || !getUserForToken($token)) {
+ $this->error('用户未登录');
+ }
+
+ //删除缓存
+ delUserForToken($token);
+ //返回数据
+ return $this->success(true);
+ }
+
+ //获取账户状态
+ public function AuthStatus(){
+ $header = $this->request->header();
+ $token = $header['token'] ?? null;
+ $user = getUserForToken($token);
+
+ $resData = longbing_auth_status($user['uniacid']);
+ return $this->success($resData);
+ }
+
+ public function isWe7()
+ {
+ $is_we7 = defined('IS_WEIQIN');
+
+ return $this->success($is_we7);
+ }
+
+
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', 200 );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/AdminController.php b/app/agent/controller/AdminController.php
new file mode 100755
index 0000000..2e7dbc7
--- /dev/null
+++ b/app/agent/controller/AdminController.php
@@ -0,0 +1,207 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+
+ /*
+ *获取用户列表
+ */
+ public function list()
+ {
+ $param = $this->_param;
+
+
+ $dis = [];
+
+
+ if(!empty($param['name'])){
+
+ $dis[] = ['a.account','like',"%".$param['name'].'%'];
+
+ $dis[] = ['d.mini_app_name','like',"%".$param['name'].'%'];
+ }
+
+ $list = AdminModel::alias('a')
+ ->field(['a.admin_id', 'a.level','a.account', 'a.role_id', 'a.create_time', 'r.description','d.mini_app_name as mini_name','c.modular_id'])
+ ->leftJoin('longbing_role r', 'a.role_id = r.role_id')
+ ->leftJoin('longbing_app_admin c', 'a.admin_id = c.admin_id')
+ ->leftJoin('longbing_card_config d', 'c.modular_id = d.uniacid')
+ ->where([['a.status', '=', 1], ['a.uniacid', '=', $this->_uniacid]])
+ ->where(function ($query) use ($dis){
+ $query->whereOr($dis);
+ })
+ ->order('a.create_time desc')
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])
+ ->toArray();
+
+
+// $admin_ids = array_column($list['data'], 'admin_id');
+// $app_admins = [];
+// $app_admins_tmp = AppAdminModel::alias('aa')
+// ->field(['aa.admin_id', 'aa.modular_id', 'c.mini_app_name' => 'mini_name'])
+// ->leftJoin('longbing_card_config c', 'aa.modular_id = c.uniacid')
+// ->where([['aa.admin_id', 'IN', $admin_ids]])->select();
+//
+// foreach ($app_admins_tmp as $k => $v) {
+// $app_admins[$v['admin_id']] = $v;
+// }
+
+ foreach ($list['data'] as $k => $v) {
+
+ $list['data'][$k]['is_bind'] = !empty($v['mini_name']);
+
+
+ if($v['description']!='超级管理员'){
+
+ $list['data'][$k]['description'] = $v['level']==0?'管理员':'员工';
+ }
+
+// $list['data'][$k]['mini_name'] = $app_admins[$v['admin_id']]['mini_name'] ?? null;
+// $list['data'][$k]['modular_id'] = $app_admins[$v['admin_id']]['modular_id'] ?? null;
+ }
+
+ $list['zhihuituike'] = longbingIsZhihuituike();
+
+ return $this->success($list);
+ }
+
+ //添加用户
+ public function addSubAdmin()
+ {
+ $input = $this->_input;
+
+ $validate = new AgentAdminValidate();
+ if (false == $validate->scene('addSubAdmin')->check($input)) {
+ return $this->error($validate->getError());
+ };
+
+ /**
+ * @var AdminModel $subAdmin
+ */
+ $subAdmin = AdminModel::where([['account', '=', $input['account']], ['status', '=', 1]])->findOrEmpty();
+ if (!$subAdmin->isEmpty()) {
+ return $this->error('该账号已存在');
+ }
+
+ $offset = createOffset();
+ $new = [
+ 'admin_id' => uuid(),
+ 'account' => $input['account'],
+ 'uniacid' => $this->_uniacid,
+ 'offset' => $offset,
+ 'passwd' => createPasswd($input['passwd'], $offset),
+ 'role_id' => 'e7d81116997011e99b985595a87cbdcb',
+ 'creator_id' => $this->_user['admin_id'],
+ 'status' => 1,
+
+ 'level' => $input['level']
+ ];
+ $rst = $subAdmin->save($new);
+ if (!$rst) {
+ return $this->error('fail');
+ }
+ return $this->success($rst);
+ }
+
+ /*
+ * 管理员修改用户信息
+ */
+ public function updateSubAdmin()
+ {
+ //获取数据
+ $input = $this->_input;
+ //字段校验
+ $validate = new AgentAdminValidate();
+ if (false == $validate->scene('addSubAdmin')->check($input)) {
+ return $this->error($validate->getError());
+ };
+
+ /**
+ * @var AdminModel $subAdmin
+ */
+ $subAdmin = AdminModel::where([['admin_id', '=', $input['admin_id']], ['uniacid', '=', $this->_uniacid]])->find();
+ if (empty($subAdmin)) {
+ return $this->error('用户不存在');
+ }
+ //强制修改密码
+ $input['passwd'] = createPasswd($input['passwd'] ,$subAdmin['offset']);
+ $result = $subAdmin->save([
+ 'passwd' => $input['passwd'],
+ 'level' => $input['level'],
+ ]);
+
+ return $this->success($result);
+ }
+
+
+ public function delSubAdmin()
+ {
+ $input = $this->_input;
+
+ $validate = new AgentAdminValidate();
+ if (false == $validate->scene('delSubAdmin')->check($input)) {
+ return $this->error($validate->getError());
+ };
+
+ /**
+ * @var AdminModel $subAdmin
+ */
+ $subAdmin = AdminModel::where([['admin_id', '=', $input['admin_id']], ['uniacid', '=', $this->_uniacid]])->findOrEmpty();
+
+ if ($subAdmin->isEmpty()) {
+ return $this->error('用户不存在');
+ }
+
+ if ($subAdmin->admin_id == $this->_user['admin_id']) {
+ return $this->error("不可以删除自己");
+ }
+
+ $rst = $subAdmin->save([
+ 'status' => 0,
+ ]);
+
+ return $this->success($rst);
+ }
+
+
+ public function bindApp()
+ {
+ $input = $this->_input;
+ $admin_id = $input['admin_id'];
+ $modular_id = $input['modular_id'];
+
+ if ($admin_id == $this->_user['admin_id']) {
+ return $this->error("超级管理员不能绑定小程序, 您可以创建子账号绑定");
+ }
+ $admin_bind_count = AppAdminModel::where([['admin_id', '=', $admin_id]])->count();
+ if ($admin_bind_count > 0) {
+ return $this->error('该用户已经绑定了一个小程序');
+ }
+
+ $appAdmin = new AppAdminModel();
+ $rst = $appAdmin->save([
+ 'id' => md5($modular_id . $admin_id),
+ 'modular_id' => $modular_id,
+ 'uniacid' => $this->_uniacid,
+ 'admin_id' => $admin_id
+ ]);
+
+ return $this->success($rst);
+
+ }
+}
\ No newline at end of file
diff --git a/app/agent/controller/AgentLevel.php b/app/agent/controller/AgentLevel.php
new file mode 100755
index 0000000..f44ecae
--- /dev/null
+++ b/app/agent/controller/AgentLevel.php
@@ -0,0 +1,150 @@
+_input;
+
+ $dis[] = ['uniacid','in',$this->_uniacid_arr];
+
+ $dis[] = ['status','=',1];
+ //模型
+ $agent_model = new \app\agent\model\AgentLevel();
+ //查询
+ $data = $agent_model->levelList($dis,$input['page_count']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:21
+ * @功能说明:添加代理商
+ */
+ public function agentAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ if(empty(trim($input['title']))){
+
+ $this->errorMsg('标题不能为空');
+ }
+
+ $agent_model = new \app\agent\model\AgentLevel();
+
+ $res = $agent_model->levelAdd($input);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:31
+ * @功能说明:编辑代理商
+ */
+ public function agentUpdate(){
+
+ $input = $this->_input;
+
+ $agent_model = new \app\agent\model\AgentLevel();
+
+ $data = $agent_model->levelUpdate(['id'=>$input['id']],$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:33
+ * @功能说明:代理商详情
+ */
+ public function agentInfo(){
+
+ $input = $this->_input;
+
+ $agent_model = new \app\agent\model\AgentLevel();
+
+ $data = $agent_model->levelInfo(['id'=>$input['id'],'status'=>1]);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 14:12
+ * @功能说明:选择框
+ */
+ public function levelSelect(){
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['uniacid','in',$this->_uniacid_arr];
+
+ $agent_model = new \app\agent\model\AgentLevel();
+
+ $data = $agent_model->levelSelect($dis);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-26 13:46
+ * @功能说明:删除
+ */
+ public function levelDel(){
+
+ $input = $this->_input;
+
+ $level_model = new \app\agent\model\AgentLevel();
+
+ $agent_model = new \app\agent\model\AgentList();
+
+ $dis[] = ['level','=',$input['id']];
+
+ $dis[] = ['status','>',-1];
+
+ $info = $agent_model->agentInfo($dis);
+
+// dump($info);exit;
+
+ if(!empty($info)){
+
+ $this->errorMsg('该等级正在被使用,使用代理商:'.$info['user_name']);
+ }
+
+ $data = $level_model->levelUpdate(['id'=>$input['id']],['status'=>-1]);
+
+ return $this->success($data);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/AgentList.php b/app/agent/controller/AgentList.php
new file mode 100755
index 0000000..3396d3e
--- /dev/null
+++ b/app/agent/controller/AgentList.php
@@ -0,0 +1,139 @@
+_input;
+
+ $dis[] = ['uniacid','in',$this->_uniacid_arr];
+ //模型
+ $agent_model = new \app\agent\model\AgentList();
+ //等级搜索
+ if(!empty($input['level'])){
+
+ $dis[] = ['level','=',$input['level']];
+ }
+ //用户名搜索
+ if(!empty($input['user_name'])){
+
+ $dis[] = ['user_name','like','%'.$input['user_name'].'%'];
+ }
+ //状态搜索
+ if(!empty($input['status'])){
+
+ $icon = $input['status']==1?'>':'<';
+
+ $dis[] =['over_time',$icon,time()];
+ }
+ //省搜索
+ if(!empty($input['province_code'])){
+
+ $dis[] = ['province_code','=',$input['province_code']];
+
+ }
+ //市搜索
+ if(!empty($input['city_code'])){
+
+ $dis[] = ['city_code','=',$input['city_code']];
+
+ }
+ //查询
+ $data = $agent_model->agentList($dis,$input['page_count']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:21
+ * @功能说明:添加代理商
+ */
+ public function agentAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $agent_model = new \app\agent\model\AgentList();
+
+ $res = $agent_model->agentAdd($input);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:31
+ * @功能说明:编辑代理商
+ */
+ public function agentUpdate(){
+
+ $input = $this->_input;
+
+ $agent_model = new \app\agent\model\AgentList();
+
+ $data = $agent_model->agentUpdate(['id'=>$input['id']],$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:33
+ * @功能说明:代理商详情
+ */
+ public function agentInfo(){
+
+ $input = $this->_input;
+
+ $agent_model = new \app\agent\model\AgentList();
+
+ $data = $agent_model->agentInfo(['id'=>$input['id']]);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 14:12
+ * @功能说明:
+ */
+ public function agentSelect(){
+
+ $dis[] = ['uniacid','in',$this->_uniacid_arr];
+
+ $agent_model = new \app\agent\model\AgentList();
+
+ $data = $agent_model->where($dis)->order('id desc')->field('id,user_name')->select()->toArray();
+
+ return $this->success($data);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/AppController.php b/app/agent/controller/AppController.php
new file mode 100755
index 0000000..f20c3e8
--- /dev/null
+++ b/app/agent/controller/AppController.php
@@ -0,0 +1,804 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 14:18
+ * @功能说明:授权管理
+ */
+ public function list()
+ {
+ $param = $this->_param;
+
+ $m_config = new Cardauth2ConfigModel();
+
+ $dis[] = ['a.status', '=', 1];
+ //小程序名字搜索
+ if(!empty($param['mini_name'])){
+
+ $dis[] = ['a.mini_name','like','%'.$param['mini_name'].'%'];
+ }
+ //代理商搜索
+ if(!empty($param['agent_id'])){
+
+ $dis[] = ['a.agent_id','=',$param['agent_id']];
+ }
+
+ if($this->_is_weiqin){
+
+ //By.jingshuixian 2020年4月16日18:31:41
+ //新增根据模块名称关联查询 , 目的是 装修只能找到装修的授权列表, 名片只能找到名片授权列表
+ //新增授权 小程序列表也需要调整
+ //ims_account 微擎小程序记录表
+ //ims_wxapp_versions 微擎小程序版本表
+
+ $app_model_name = APP_MODEL_NAME;
+ $dis[] = ['v.modules', 'like', "%{$app_model_name}%"] ;
+ $list = $m_config
+ ->alias('a')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+ ->field(['a.id', 'a.mini_name', 'a.modular_id', 'a.number', 'a.copyright_id', 'a.create_time', 'a.end_time', 'a.remark','a.agent_id','a.upload_setting'])
+ ->group('a.modular_id')
+ ->where($dis)
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])
+ ->toArray();
+
+ }else{
+
+
+ $list = $m_config
+ ->alias('a')
+ ->field(['id', 'mini_name', 'modular_id', 'number', 'copyright_id', 'create_time', 'end_time', 'remark','agent_id','upload_setting'])
+ ->where($dis)
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])
+ ->toArray();
+
+ }
+
+
+
+
+ $copyrights = [];
+ $copyright_ids = array_column($list['data'] ?? [], 'copyright_id');
+ $copyrights_temp = Cardauth2CopyrightModel::where([['id', 'IN', $copyright_ids], ['status', '=', 1]])->field(['id', 'name'])->select();
+ foreach ($copyrights_temp as $item) {
+ $copyrights[$item['id']] = $item['name'];
+ }
+
+ //代理商模型
+ $agent_model = new \app\agent\model\AgentList();
+
+ foreach ($list['data'] as $k => $item) {
+
+ $list['data'][$k]['copyright'] = $copyrights[$item['copyright_id']] ?? "";
+// //代理商名字
+ $agent_name = $agent_model->where(['id'=>$item['agent_id']])->value('user_name');
+
+ $list['data'][$k]['agent_name'] = !empty($agent_name)?$agent_name:'';
+
+ }
+
+ return $this->success($list);
+ }
+
+ public function get()
+ {
+ $id = $this->_param['id'] ?? null;
+ if (!$id) {
+ return $this->error('参数错误');
+ }
+
+ $config = Cardauth2ConfigModel::find($id);
+ $config['boss'] = $config['boos'] ?? null;
+ $config['activity'] = $config['activity_switch'] ?? null;
+ $config['appiont'] = $config['appoint'] ?? null;
+
+ $eventData = event('AgentAppAuthEdit' , $config);
+
+
+ $eventData = LongbingArr::array_merge($eventData);
+
+ $config['authList'] = $eventData ;
+
+ return $this->success($config);
+ }
+
+ /**
+ * 新增小程序授权时,获取所有权限列表
+ *
+ * @return \think\Response
+ * @author shuixian
+ * @DataTime: 2019/12/30 14:00
+ */
+ public function getAuthList(){
+
+ $eventData = event('AgentAppAuthEdit' , []);
+ $eventData = LongbingArr::array_merge($eventData);
+ $config['authList'] = $eventData ;
+
+ return $this->success($config);
+ }
+
+ public function create()
+ {
+ $input = $this->_input;
+
+ $time = time();
+ if (defined('IS_WEIQIN')) {
+ $validate = new Cardauth2ConfigValidate();
+ $check = $validate->scene('create')->append('modular_id', 'require')->check($input);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $m_auth2_config = Cardauth2ConfigModel::where([['modular_id', '=', $input['modular_id']], ['status', '=', 1]])->findOrEmpty();
+
+ if (!$m_auth2_config->isEmpty()) {
+ return $this->error('小程序已存在');
+ }
+
+ $mini_name = Db::name('account_wxapp')->field(['acid', 'name'])->where([['uniacid', '=', $input['modular_id']]])->find();
+ $rst = $m_auth2_config->save(
+ [
+ //代理商
+ 'agent_id' => !empty($input['agent_id'])?$input['agent_id']:0,
+
+ 'upload_setting' => !empty($input['upload_setting'])?$input['upload_setting']:0,
+
+ 'modular_id' => $input['modular_id'],
+ 'number' => $input['number'],
+ 'uniacid' => 0,
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'remark' => $input['remark'],
+ 'end_time' => $input['end_time'],
+ 'mini_name' => $mini_name['name'] ?? '',
+ 'copyright_id' => $input['copyright_id'],
+ 'send_switch' => $input['send_switch'],
+ 'boos' => $input['boss'],
+ 'appoint' => $input['appiont'],
+ 'payqr' => $input['payqr'],
+ 'shop_switch' => $input['shop_switch'],
+ 'timeline_switch' => $input['timeline_switch'],
+ 'website_switch' => $input['website_switch'],
+ 'article' => $input['article'],
+ 'activity' => $input['activity'],
+ 'pay_shop' => $input['pay_shop'],
+ 'house_switch' => $input['house_switch'],
+ //带客有礼
+ 'passenger_switch' => $input['passenger_switch'],
+ //百度
+ 'baidu_switch' => $input['baidu_switch'],
+ //截流
+ 'closure_switch' => $input['closure_switch'],
+ //红包
+ 'redbag_switch' => $input['redbag_switch'],
+ //满减
+ 'reduction_switch' => $input['reduction_switch'],
+ //直播
+ 'livevideo_switch' => $input['livevideo_switch'],
+ //短视频
+ 'shortvideo_switch'=> $input['shortvideo_switch'],
+ //会员
+ 'member_switch' => $input['member_switch'],
+ //餐饮
+ 'restaurant_switch' => $input['restaurant_switch'],
+ // 霸王餐
+ 'overlord_switch' => $input['overlord_switch'],
+ // 付费课程
+ 'payclass_switch' => $input['payclass_switch'],
+
+ 'bargain_switch' => $input['bargain_switch'],
+
+ 'question_switch' => $input['question_switch'],
+
+
+// 'tool_switch' => $input['tool_switch'],
+ ]
+ );
+
+ return $this->success($rst);
+
+ }
+
+
+ $validate = new Cardauth2ConfigValidate();
+ $check = $validate->scene('create')->check($input);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $m_auth2_config = Cardauth2ConfigModel::where([['mini_name', '=', $input['mini_name']]])->findOrEmpty();
+ if (!$m_auth2_config->isEmpty()) {
+ return $this->error('小程序已存在');
+ }
+
+ $lenth_name = strlen($input['mini_name']);
+ if ($lenth_name <= 0 || $lenth_name >= 30 ) {
+ return $this->error("名字长度只能在0到30个字符");
+ }
+
+ $max_uniacid_card_config = CardConfig::field('uniacid')->order('uniacid', 'desc')->limit(1)->select()->toArray();
+ $max_uniacid = $max_uniacid_card_config[0]['uniacid'] ?? 0;
+
+ $auth_name = Cardauth2ConfigModel::where([['mini_name', '=', $input['mini_name']], ['status', '=', 1]])->find();
+ if(!empty($auth_name)){
+ return $this->error("小程序名字不能重复");
+ }
+ $rst = $m_auth2_config->save(
+ [
+ //代理商
+ 'agent_id' => !empty($input['agent_id'])?$input['agent_id']:0,
+
+ 'upload_setting' => !empty($input['upload_setting'])?$input['upload_setting']:0,
+
+ 'modular_id' => $max_uniacid + 1,
+ 'number' => $input['number'],
+ 'uniacid' => $this->_uniacid,
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'remark' => $input['remark'],
+ 'end_time' => $input['end_time'],
+ 'mini_name' => $input['mini_name'],
+ 'copyright_id' => $input['copyright_id'],
+ 'send_switch' => $input['send_switch'],
+ 'boos' => $input['boss'],
+ 'appoint' => $input['appiont'],
+ 'payqr' => $input['payqr'],
+ 'shop_switch' => $input['shop_switch'],
+ 'timeline_switch' => $input['timeline_switch'],
+ 'website_switch' => $input['website_switch'],
+ 'article' => $input['article'],
+ 'activity_switch' => $input['activity'] ?? $input['activity_switch'],
+ 'pay_shop' => $input['pay_shop'],
+ 'house_switch' => $input['house_switch'],
+ //带客有礼
+ 'passenger_switch' => $input['passenger_switch'],
+ //百度
+ 'baidu_switch' => $input['baidu_switch'],
+ //截流
+ 'closure_switch' => $input['closure_switch'],
+ //红包
+ 'redbag_switch' => $input['redbag_switch'],
+ //满减
+ 'reduction_switch' => $input['reduction_switch'],
+ //直播
+ 'livevideo_switch' => $input['livevideo_switch'],
+ //短视频
+ 'shortvideo_switch'=> $input['shortvideo_switch'],
+ //会员
+ 'member_switch' => $input['member_switch'],
+ // 餐饮
+ 'restaurant_switch' => $input['restaurant_switch'],
+ // 霸王餐
+ 'overlord_switch' => $input['overlord_switch'],
+ // 付费课程
+ 'payclass_switch' => $input['payclass_switch'],
+
+ 'bargain_switch' => $input['bargain_switch'],
+
+ 'question_switch' => $input['question_switch'],
+// 'tool_switch' => $input['tool_switch'],
+ ]
+ );
+
+ $rst = $rst && $m_auth2_config->cardConfig()->save([
+ 'uniacid' => $m_auth2_config->modular_id,
+ 'create_time' => $m_auth2_config->create_time,
+ 'update_time' => $m_auth2_config->update_time,
+ 'copyright' => "",
+ 'is_sync' =>1,
+ 'mini_app_name' => $m_auth2_config->mini_name,
+ 'create_txt' => "创建我的智能名片",
+ ]);
+
+
+ if ($rst) {
+ return $this->success($m_auth2_config->id);
+ }
+
+ return $this->error('fail');
+
+ }
+
+ public function update()
+ {
+
+
+ $input = $this->_input;
+
+ $input['boos'] = $input['boss'];
+ $input['appoint'] = $input['appiont'];
+ $input['activity_switch'] = $input['activity'];
+
+ if (defined('IS_WEIQIN')) {
+ $validate = new Cardauth2ConfigValidate();
+ $check = $validate->scene('update')->check($input);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $m_auth2_config = Cardauth2ConfigModel::where('id', '=', $input['id'])->findOrEmpty();
+ if ($m_auth2_config->isEmpty()) {
+ return $this->error('未找到小程序');
+ }
+
+ /**
+ * @var Cardauth2ConfigModel $m_auth2_config
+ */
+ $rst = $m_auth2_config->allowField([
+
+ 'agent_id',
+
+ 'upload_setting',
+
+ 'number',
+ 'end_time',
+ 'copyright_id',
+ 'send_switch',
+ 'boos',
+ 'appoint',
+ 'payqr',
+ 'shop_switch',
+ 'timeline_switch',
+ 'website_switch',
+ 'article',
+ 'activity_switch',
+ 'pay_shop' ,
+ 'house_switch',
+ 'tool_switch',
+ 'remark',
+ 'closure_switch',
+ 'baidu_switch',
+ //带客有礼
+ 'passenger_switch',
+ //红包
+ 'redbag_switch',
+ //满减
+ 'reduction_switch',
+ //视频
+ 'livevideo_switch',
+ //短视频
+ 'shortvideo_switch',
+ //会员
+ 'member_switch',
+ // 餐饮
+ 'restaurant_switch',
+ // 霸王餐
+ 'overlord_switch',
+ // 付费课程
+ 'payclass_switch',
+
+ 'bargain_switch',
+
+ 'question_switch',
+ ])->save($input);
+
+ return $this->success($rst);
+
+ }
+
+
+
+ $validate = new Cardauth2ConfigValidate();
+ $check = $validate->scene('update')->check($input);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $m_auth2_config = Cardauth2ConfigModel::where('id', '=', $input['id'])->findOrEmpty();
+ if ($m_auth2_config->isEmpty()) {
+ return $this->error('未找到小程序');
+ }
+
+ clearCache($m_auth2_config['uniacid']);
+
+ $auth_name = Cardauth2ConfigModel::where([['mini_name', '=', $input['mini_name']], ['status', '=', 1],['id','<>',$input['id']]])->find();
+ if(!empty($auth_name)){
+ return $this->error("小程序名字不能重复");
+ }
+
+ /**
+ * @var Cardauth2ConfigModel $m_auth2_config
+ */
+ $rst = $m_auth2_config->allowField([
+ 'agent_id',
+
+ 'upload_setting',
+
+ 'mini_name',
+ 'number',
+ 'end_time',
+ 'copyright_id',
+ 'send_switch',
+ 'boos',
+ 'appoint',
+ 'payqr',
+ 'shop_switch',
+ 'timeline_switch',
+ 'website_switch',
+ 'article',
+ 'activity_switch',
+ 'pay_shop' ,
+ 'house_switch',
+ 'remark',
+ 'closure_switch',
+ //百度
+ 'baidu_switch',
+ //带课有礼
+ 'passenger_switch',
+ //红包
+ 'redbag_switch',
+ //满减
+ 'reduction_switch',
+ //视频
+ 'livevideo_switch',
+ //短视频
+ 'shortvideo_switch',
+ //会员
+ 'member_switch',
+ // 餐饮
+ 'restaurant_switch',
+ // 霸王餐
+ 'overlord_switch',
+ // 付费课程
+ 'payclass_switch',
+
+ 'bargain_switch',
+
+ 'question_switch',
+ ])->save($input);
+
+
+ $rst = $rst && $m_auth2_config->cardConfig->save([
+ 'uniacid' => $m_auth2_config->modular_id,
+ 'update_time' => $m_auth2_config->update_time,
+ 'copyright' => "",
+ 'mini_app_name' => $m_auth2_config->mini_name,
+ ]);
+
+ if ($rst) {
+ return $this->success($m_auth2_config->id);
+ }
+
+ return $this->error('fail');
+
+
+ }
+
+
+ public function delete()
+ {
+ $input = $this->_input;
+
+ $validate = new Cardauth2ConfigValidate();
+ $check = $validate->scene('delete')->check($input);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ /**
+ * @var Cardauth2ConfigModel $m_auth2_config
+ */
+ $m_auth2_config = Cardauth2ConfigModel::where('id', '=', $input['id'])->findOrEmpty();
+ if ($m_auth2_config->isEmpty()) {
+ return $this->error('未找到小程序');
+ }
+ $rst = $m_auth2_config->delete();
+
+ if ($rst) {
+ if (!defined('IS_WEIQIN')) {
+ //删除小程序
+ CardConfig::where([['uniacid', '=', $m_auth2_config->modular_id]])->delete();
+ //删除绑定关系
+ AppAdminModel::where([['modular_id', '=', $m_auth2_config->modular_id]])->delete();
+
+ }
+
+ return $this->success($m_auth2_config->id);
+ }
+
+
+
+
+ return $this->error('fail');
+
+ }
+
+
+ public function getWxApp()
+ {
+ if (defined('IS_WEIQIN')) {
+
+ //By.jingshuixian 2020年4月20日15:54:09
+ //解决行业版数据独立的问题
+ //$account_uniacids = Db::name('account')->where([['type', '=', 4], ['isdeleted', '=', 0]])->column('uniacid');
+ //$wxapp = Db::name('account_wxapp')->field(['acid', 'name'])->where([['uniacid', 'IN', $account_uniacids]])->select()->toArray();
+ /*foreach ($wxapp as $k => $item) {
+ $wxapp[$k]['mini_name'] = $item['name'];
+ $wxapp[$k]['modular_id'] = $item['acid'];
+ }*/
+
+ // $a = Db::name('account_wxapp')->select();
+
+ $app_model_name = APP_MODEL_NAME;
+ $m_config = new Cardauth2ConfigModel();
+ $wxapp = Db::name('account')
+ ->alias('a')
+ ->join('wxapp_versions v' , 'a.uniacid = v.uniacid')
+ ->join('account_wxapp account_wxapp' , 'a.uniacid = account_wxapp.uniacid')
+ ->field(['account_wxapp.name as mini_name', 'account_wxapp.uniacid as modular_id'])
+ ->where([ ['v.modules', 'like', "%".'"'.$app_model_name.'"'."%"] , ['a.type', '=', 4] ,['a.isdeleted', '=', 0] ])
+ ->group('a.uniacid')
+ ->select()
+ ->toArray();
+
+
+ return $this->success($wxapp);
+ }else{
+
+ $dis[] = ['uniacid','<>',8888];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['mini_app_name','<>',''];
+
+ $list = CardConfig::field(['mini_app_name' => 'mini_name', 'uniacid' => 'modular_id'])->where($dis)->select()->toArray();
+ return $this->success($list);
+ }
+
+
+ }
+
+
+ public function isWe7()
+ {
+ $is_we7 = defined('IS_WEIQIN');
+
+ return $this->success($is_we7);
+ }
+
+
+ public function redirectAppBackgroundToken()
+ {
+ if (defined('IS_WEIQIN')) {
+ return $this->error('微擎用户禁止访问');
+ };
+
+ $modular_id = $this->_input['modular_id'];
+
+ $user = [
+ 'admin_id' => $this->_user['admin_id'],
+ 'account'=> $this->_user['account'],
+ 'role' => $this->_user['role'],
+ 'role_name' => $this->_user['role_name'],
+ 'uniacid' => $modular_id,
+ ];
+
+ $result['user'] = $user;
+ $result['token'] = createToken();
+ if (empty($result['token'])) {
+ return $this->error('System is busy,please try again later.', 400);
+ }
+ //添加缓存数据
+ setUserForToken($result['token'], $user);
+ return $this->success($result, 200);
+
+ }
+
+ //站点绑定
+ public function websitebind()
+ {
+ $type = $this->_input['type'] ?? null;
+ if (!in_array($type, ['get', 'post'])) {
+ return $this->error(lang('param error'));
+ }
+
+ $version_id = longbingGetBranchVersionId();
+ $branch_id = longbingGetBranchId();
+ $version_name = longbingGetBranchVersionName();
+
+ $domain_name = $_SERVER['HTTP_HOST'];
+ $server_url = longbingGetSaasUrl();//接口地址
+
+ $bindInfo = longbingGetWebSiteBingData();
+
+
+ if ($type == 'get') {
+ $data = array(
+ 'version_id' => $version_id,
+ 'branch_id' => $branch_id,
+ 'version_name' => $version_name,
+ 'domain_name' => $domain_name,
+ );
+ //获取最新版本
+ if(!empty($bindInfo))
+ {
+ //检查数据是否存在
+ if(empty($bindInfo) || empty($bindInfo['website_keys']) || empty($bindInfo['website_keys']) || empty($bindInfo['domain_keys'])) {
+ $data['newest_version_name'] = $data['version_name'];
+ $data['website_keys'] = '';
+ }else{
+ $data['website_keys'] = $bindInfo['website_keys'];
+ //获取最新的版本信息
+ $new_branch = json_decode($this->lb_api_notice_increment_we7($server_url.'/app_version/'.$branch_id,null,['Accept-Charset:utf-8','Origin:'.$bindInfo['domain_name'],'Referer:'.$bindInfo['domain_name']],'GET'),true);
+
+ if(empty($new_branch) || !isset($new_branch['result']['data']) || empty($new_branch['result']['data']) || isset($new_branch['error']) || in_array($new_branch['result']['data']['version_id'], [$version_id]))
+ {
+ $data['newest_version_name'] = $data['version_name'];
+ $data['newest_version_id'] = $data['version_id'];
+ }else{
+ $data['newest_version_id'] = $new_branch['result']['data']['version_id'];
+ $data['newest_version_name'] = $new_branch['result']['data']['version_name'];
+ }
+ }
+ }
+ return $this->success($data);
+
+ } else {
+ if (isset($bindInfo['website_keys']) && $bindInfo['website_keys'] ) {
+ return $this->error('已经绑定过了, 无需重复绑定');
+ }
+ $website_key = $this->_input['website_keys'] ?? null;
+ if ($type == 'post' && $website_key == null) {
+ return $this->error('请输入密钥');
+ }
+
+ $res = json_decode(($this->lb_api_notice_increment_we7($server_url . '/website/check?keys=' . $website_key, [], ['Accept-Charset:utf-8', 'Origin:' . $domain_name], 'GET')), true);
+
+ if (isset($res['error'])) {
+ return $this->error($res['error']['message']);
+ }
+ $data = $res['result']['data'];
+
+
+ $save_data = [
+ 'domain_name' => $domain_name,
+ 'domain_keys' => json_encode($data['domain_keys'], true),
+ 'domain_id' => $data['domain_id'],
+ 'website_id' => $data['website_id'],
+ 'website_keys' => $website_key,
+ ];
+ if(empty($bindInfo))
+ {
+ $result = Db::name('lb_pluge_key')->save($save_data);
+ }else{
+ $result = Db::name('lb_pluge_key')->where('id', '=', $bindInfo['id'])->update($save_data);
+ }
+
+
+ if ($result === false) {
+ return $this->error(lang('faild'));
+ }
+ }
+
+ return $this->success(true);
+ }
+ /**
+ * 更新程序
+ * @author yangqi
+ */
+ public function updateApp()
+ {
+ if(longbingIsWeiqin()) return $this->error(lang('not need update'));
+ //app 识别号
+ $branch_id = longbingGetBranchId();
+ //version_id
+ $version_id = longbingGetBranchVersionId();
+ //获取saas url
+ $server_url = longbingGetSaasUrl();
+
+ if(empty($branch_id) || empty($version_id) || empty($server_url)) return $this->error(lang('not need update'));
+
+ //获取站点绑定信息
+ $bing_data = longbingGetWebSiteBingData();
+ //检查数据是否存在
+ if(empty($bing_data) || empty($bing_data['website_keys']) || empty($bing_data['website_keys']) || empty($bing_data['domain_keys'])) return $this->error(lang('webiste not bing.'));
+ //获取最新的版本信息
+ $new_branch = json_decode($this->lb_api_notice_increment_we7($server_url.'/app_version/'.$branch_id,null,['Accept-Charset:utf-8','Origin:'.$bing_data['domain_name'],'Referer:'.$bing_data['domain_name']],'GET'),true);
+
+ if(empty($new_branch) || !isset($new_branch['result']['data']) || empty($new_branch['result']['data']) || isset($new_branch['error']) || in_array($new_branch['result']['data']['version_id'], [$version_id])) return $this->error(lang('not need update'));
+ // $version_id = $new_branch['result']['data']['version_id'];
+ //获取加密秘钥
+ $keys = $bing_data['domain_keys'];
+ $keys = json_decode($keys ,true);
+
+ $signModel=new Rsa2Sign($keys);
+ //生成查询条件
+ $data =["branch_id"=>$branch_id ,"version_id"=>$version_id];
+ //机密数据
+ $sign=$signModel->createSign(json_encode($data,true));
+ // 授权检查
+ $res= json_decode($this->lb_api_notice_increment_we7($server_url.'/authorization?sign='.$sign,json_encode(["authorization"=>$data]),['Accept-Charset:utf-8','Origin:'.$bing_data['domain_name'],'Referer:'.$bing_data['domain_name']],'POST'),true);
+
+ //接口结果 判断是否成功
+ if(isset($res['error'])){
+ return $this->error(lang($res['error']['message']));
+ }
+ //获取更新数据url
+ $down_load_url=isset($res['result']['data']['backstage_url']) && $res['result']['data']['backstage_url'] ? $res['result']['data']['backstage_url'] : '';
+ if(!$down_load_url){
+ //无需更新
+ return $this->returnSuccess(['code'=>-1],'无需更新');
+ }
+ //模块名称(目录名称)
+ $model_name=isset($res['result']['data']['model_name']) ? $res['result']['data']['model_name']: '';
+ $version_id=isset($res['result']['data']['version_id']) ? $res['result']['data']['version_id']: '';
+ $version_name =isset($res['result']['data']['version_name']) ? $res['result']['data']['version_name']: '';
+ $file_name = isset($res['result']['data']['backstage_name']) ? $res['result']['data']['backstage_name']: '';
+ //下载覆盖文件
+ $save_dir=ROOT_PATH . 'temp';
+ $cp_dir=ROOT_PATH ;
+
+ //更新文件
+ if(longbingUpdateAppFile($down_load_url,$save_dir ,$file_name,$cp_dir)){
+ //是否有更新数据库
+ if($model_name && file_exists(APP_PATH.$model_name.'/upgrade.php')){
+ $sql_all='';//更新数据库
+ require_once APP_PATH.$model_name.'/upgrade.php';
+ }
+ //写入最新版本
+ $data=[
+// 'uniacid' => $uniacid,
+ 'version_id' => $version_id,
+ 'branch_id' => $branch_id,
+ 'version_name' => $version_name
+ ];
+ $data = longbingGetWebSiteBingData(['id' => $bing_data['id']] ,$data);
+ return $this->success(lang('update success'));
+ }else{
+ return $this->success(lang('update error'));
+ }
+ }
+
+ private function lb_api_notice_increment_we7 ( $url, $data, $headers = [ 'Accept-Charset:utf-8' ], $request_type = 'POST' )
+ {
+ $ch = curl_init();
+ // $header = "Accept-Charset: utf-8";
+ curl_setopt( $ch, CURLOPT_URL, $url );
+ //设置头文件的信息作为数据流输出
+ curl_setopt( $ch, CURLOPT_HEADER, 0 );
+ curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
+ curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, $request_type );
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
+ curl_setopt( $ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)' );
+ curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
+ curl_setopt( $ch, CURLOPT_AUTOREFERER, 1 );
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
+ $tmpInfo = curl_exec( $ch );
+ // var_dump($tmpInfo);
+ // exit;
+ if ( curl_errno( $ch ) ) {
+ return false;
+ } else {
+ // var_dump($tmpInfo);
+ return $tmpInfo;
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/AppUpgrade.php b/app/agent/controller/AppUpgrade.php
new file mode 100755
index 0000000..ecb2241
--- /dev/null
+++ b/app/agent/controller/AppUpgrade.php
@@ -0,0 +1,128 @@
+checkAuth();
+
+ $data['location_version_no'] = $version_no ;
+
+ $data['is_upgrade'] = $this->getIsUpgrade();
+
+ $this->update();
+
+ return $this->success( $data );
+ }
+
+
+ /**
+ * By.jingshuixian
+ * 2019年11月23日21:43:47
+ * 升级脚本导入执行
+ */
+ public function update(){
+
+ $key = 'init_all_data';
+
+ setCache($key,'',7200,$this->_uniacid);
+
+ UpdateService::installSql($this->_uniacid);
+
+ UpdateService::initWeiqinConfigData();
+
+ DiyService::addDefaultDiyData($this->_uniacid);
+ //各个模块初始化数据事件
+ event('InitModelData');
+ //处理雷达
+ lbInitRadarMsg($this->_uniacid);
+
+ return $this->success([]);
+
+ }
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-08 18:04
+ * @功能说明: 判断是否有升级权限
+ */
+ private function getIsUpgrade(){
+
+ $goods_name = config('app.AdminModelList')['app_model_name'];
+
+ if(($goods_name == 'longbing_card')||!longbingIsWeiqin()){
+
+ return true;
+
+ }else{
+
+ return false ;
+ }
+ }
+
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020-06-08 14:43
+ * @功能说明: 升级后台系统
+ */
+ public function upgrade(){
+
+ if($this->getIsUpgrade()){
+ $goods_name = config('app.AdminModelList')['app_model_name'];
+ $auth_uniacid = config('app.AdminModelList')['auth_uniacid'];
+ $version_no = config('app.AdminModelList')['version_no'];
+
+ $upgrade = new LongbingUpgrade($auth_uniacid , $goods_name , Env::get('j2hACuPrlohF9BvFsgatvaNFQxCBCc' , false));
+
+ $file_temp_path = ROOT_PATH . "runtime/" ;
+ $toFilePath = ROOT_PATH ;
+ // 自动下载文件到 core/runtime 解压到 core/ 根目是thinkphp所在目录
+ $data = $upgrade->update( $toFilePath ,$file_temp_path );
+
+ return $this->success( $data );
+ }else{
+ return $this->success( [] );
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/app/agent/controller/AritcleController.php b/app/agent/controller/AritcleController.php
new file mode 100755
index 0000000..0386bc0
--- /dev/null
+++ b/app/agent/controller/AritcleController.php
@@ -0,0 +1,171 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+ public function list()
+ {
+ $param = $this->_param;
+ $m_article_auth2 = new Cardauth2ArticleModel();
+
+ //By.jingshuixian 2020年4月21日15:13:50
+ //区分行业版数据
+
+ if($this->_is_weiqin){
+
+ $app_model_name = APP_MODEL_NAME;
+ $list = $m_article_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a.number', 'a. create_time', 'c.autograph', 'c.signature', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->join('account' , 'a.modular_id = account.uniacid')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+ ->group('a.modular_id')
+ ->where([['a.status', '=', 1] , ['account.type', '=', 4] ,['account.isdeleted', '=', 0] , ['v.modules', 'like', "%{$app_model_name}%"]])
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+
+ }else{
+
+ $list = $m_article_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a.number', 'a. create_time', 'c.autograph', 'c.signature', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->where([['a.status', '=', 1]])
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+
+ }
+
+
+
+ $wxapp_map = [];
+ $wxapp = Db::name('account_wxapp')->field(['uniacid', 'name'])->select();
+ foreach ($wxapp as $item) {
+ $wxapp_map[$item['uniacid']] = $item['name'];
+ }
+
+ foreach ($list['data'] as $k => $item) {
+ $list['data'][$k]['used'] = $item['signature'];
+ $list['data'][$k]['left'] = $item['number'] - $item['signature'];
+ $list['data'][$k]['name'] = $wxapp_map[$item['modular_id']] ?? $item['mini_app_name'];
+ unset($list['data'][$k]['signature'], $list['data'][$k]['autograph'], $list['data'][$k]['mini_app_name']);
+ }
+ //授权数量
+ $list['total_article_number'] = AdminUserService::getSassNum('article',$this->_uniacid);
+ //使用数量
+ $list['total_article_used'] = (int)$m_article_auth2->where([['uniacid','in',$this->_uniacid_arr]])->sum('number');
+
+ return $this->success($list);
+ }
+
+
+ public function create()
+ {
+
+ $data = $this->_input;
+
+ $validate = new Cardauth2ArticleValidate();
+
+ $check = $validate->scene('create')->check($data);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $time = time();
+ $auth_article = Cardauth2ArticleModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if (!$auth_article->isEmpty()) {
+ return $this->error('已存在此小程序');
+ }
+
+ $total_article_number = AdminUserService::getSassNum('article',$this->_uniacid);
+
+ $total_article_used = (int)$auth_article->where([['uniacid','in',$this->_uniacid_arr]])->sum('number');
+
+ $remain = $total_article_number - $total_article_used - $data['number'];
+
+ if ($remain < 0) {
+ return $this->error('分配的超过可用的总数');
+ }
+
+ $rst = $auth_article->save([
+ 'modular_id' => $data[ 'modular_id' ],
+ 'number' => $data[ 'number' ],
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'uniacid' => $this->_uniacid,
+ ]);
+
+ $auth_article->cardConfig->save(['autograph' => $data['number'] + 80666]);
+
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+
+ return $this->error('fail');
+ }
+
+
+ public function update()
+ {
+ $data = $this->_input;
+
+ $validate = new Cardauth2ArticleValidate();
+ $check = $validate->scene('create')->check($data);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+
+ $auth_article = Cardauth2ArticleModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+ if ($auth_article->isEmpty()) {
+ return $this->error('小程序不存在');
+ }
+
+
+ $old_number = $auth_article['number'];
+ $new_numer = $data['number'];
+ if ($old_number > $new_numer) {
+ return $this->error('不能减少授权数量');
+ }
+
+
+ $total_article_number = AdminUserService::getSassNum('article',$this->_uniacid);
+
+ $total_article_used = (int)$auth_article->where([['uniacid','in',$this->_uniacid_arr]])->sum('number') - $old_number + $new_numer;
+ $remain = $total_article_number - $total_article_used;
+ if ($remain < 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+
+ $time = time();
+ $rst = $auth_article->save([
+ 'number' => $new_numer,
+ 'update_time' => $time,
+ ]);
+ $auth_article->cardConfig->save(['autograph' => $data['number'] + 80666]);
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+
+ return $this->error('fail');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/BossController.php b/app/agent/controller/BossController.php
new file mode 100755
index 0000000..cf9b3fb
--- /dev/null
+++ b/app/agent/controller/BossController.php
@@ -0,0 +1,149 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+ public function list()
+ {
+ $param = $this->_param;
+ $m_boss_auth2 = new Cardauth2BossModel();
+
+ //By.jingshuixian 2020年4月21日15:13:50
+ //区分行业版数据
+
+ //获取列表
+ if($this->_is_weiqin){
+ $app_model_name = APP_MODEL_NAME;
+ $list = $m_boss_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->join('account' , 'a.modular_id = account.uniacid')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+ ->where([['a.status', '=', 1] , ['account.type', '=', 4] ,['account.isdeleted', '=', 0] , ['v.modules', 'like', "%{$app_model_name}%"] ])
+ ->group('a.modular_id')
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+
+
+ }else{
+ $list = $m_boss_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->where([['a.status', '=', 1]])
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+ }
+
+ $wxapp_map = [];
+ $wxapp = Db::name('account_wxapp')->field(['uniacid', 'name'])->select();
+ foreach ($wxapp as $item) {
+ $wxapp_map[$item['uniacid']] = $item['name'];
+ }
+
+ foreach ($list['data'] as $k => $item) {
+ $list['data'][$k]['name'] = $wxapp_map[$item['modular_id']] ?? $item['mini_app_name'];
+ unset($list['data'][$k]['mini_app_name']);
+ }
+
+ //授权数量
+ $list['total_house_number'] = AdminUserService::getSassNum('boss',$this->_uniacid);
+ //使用数量
+ $list['total_house_used'] = $m_boss_auth2->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+
+ return $this->success($list);
+ }
+
+
+ public function create()
+ {
+ $data = $this->_input;
+ if (!isset($data['modular_id'])) {
+ return $this->success('参数错误');
+ }
+
+ $time = time();
+ $auth_boss = Cardauth2BossModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if (!$auth_boss->isEmpty()) {
+ return $this->error('已存在此小程序');
+ }
+
+ $total_boss_number = AdminUserService::getSassNum('boss',$this->_uniacid);
+
+ $total_boss_used = $auth_boss->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+
+ $remain = $total_boss_number - $total_boss_used;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+ $rst = $auth_boss->save([
+ 'modular_id' => $data[ 'modular_id' ],
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'sign' => intval( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => 1,
+ 'uniacid' => $this->_uniacid,
+ ]);
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+ return $this->error('fail');
+ }
+
+
+ public function extendedOneYear ()
+ {
+ $data = $this->_input;
+ if (!isset($data['modular_id'])) {
+ return $this->success('参数错误');
+ }
+
+ $time = time();
+ $auth_boss = Cardauth2BossModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if ($auth_boss->isEmpty()) {
+ return $this->error('小程序不存在');
+ }
+
+ $total_boss_number = AdminUserService::getSassNum('boss',$this->_uniacid);
+
+ $total_boss_used = $auth_boss->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+ $remain = $total_boss_number - $total_boss_used;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+ $rst = $auth_boss->save([
+ 'sign' => $auth_boss[ 'sign' ] > $time ? ($auth_boss[ 'sign' ] + ( 366 * 24 * 60 * 60 )) : ( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => $auth_boss['count'] + 1,
+ 'update_time' => $time,
+ ]);
+
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+
+ return $this->error('fail');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/ConfigDefault.php b/app/agent/controller/ConfigDefault.php
new file mode 100755
index 0000000..bbdcf5e
--- /dev/null
+++ b/app/agent/controller/ConfigDefault.php
@@ -0,0 +1,62 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+ public function getOne()
+ {
+ $default = Cardauth2DefaultModel::order('id', 'desc')->limit(1)->select();
+
+ if (!isset($default[0])) {
+ $default = new Cardauth2DefaultModel();
+ $default->uniacid = $this->_uniacid;
+ $default->card_number = 0;
+ $default->send_switch = 0;
+ $default->save();
+ return $this->success($default);
+ }
+ return $this->success($default[0]->toArray());
+ }
+
+
+ public function update()
+ {
+
+ $input = $this->_input;
+ $validate = new Validate();
+ $validate->rule([
+ 'card_number|名片数量' => 'require|number|egt:0',
+ 'send_switch|短信群发' => 'require|number|in:0,1',
+ ]);
+
+ if (!$validate->check($input)) {
+ return $this->error($validate->getError());
+ }
+
+
+ $default = Cardauth2DefaultModel::order('id', 'desc')->limit(1)->select();
+ if (!$default) {
+ $default->card_number = $input['card_number'] ;
+ $default->send_switch = $input['send_switch'] ;
+ $default->save();
+ }
+ $default[0]->card_number = $input['card_number'] ;
+ $default[0]->send_switch = $input['send_switch'] ;
+ $default[0]->save();
+
+ return $this->success('success');
+ }
+}
\ No newline at end of file
diff --git a/app/agent/controller/CopyRightAgentController.php b/app/agent/controller/CopyRightAgentController.php
new file mode 100755
index 0000000..dcf8065
--- /dev/null
+++ b/app/agent/controller/CopyRightAgentController.php
@@ -0,0 +1,108 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+ public function list()
+ {
+
+ $param= $this->_param;
+
+ $list = Cardauth2CopyrightModel::where([['status', '=', 1],['uniacid','in',$this->_uniacid_arr]])
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])
+ ->toArray();
+ return $this->success($list);
+ }
+
+ public function getAll()
+ {
+ $list = Cardauth2CopyrightModel::field(['id', 'name'])->where([['status', '=', 1],['uniacid','in',$this->_uniacid_arr]])->select()
+ ->toArray();
+ return $this->success($list);
+ }
+
+
+ public function create()
+ {
+ $data = $this->_input;
+ $validate = new CopyRightAgentValidate();
+ $check = $validate->scene('create')->check($data);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $data['uniacid'] = $this->_uniacid;
+
+ $m = new Cardauth2CopyrightModel();
+ $m->data($data, true, ['name', 'image', 'text', 'phone', 'uniacid']);
+ if ($m->save()) {
+ $id = $m->id;
+ return $this->success($id);
+ }
+ return $this->error('fail');
+ }
+
+
+ public function update()
+ {
+ $data = $this->_input;
+ $validate = new CopyRightAgentValidate();
+ $check = $validate->scene('update')->check($data);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+
+ $copyRight = Cardauth2CopyrightModel::find($data['id']);
+ if (!$copyRight) {
+ return $this->error('系统错误');
+ }
+
+ if ($copyRight->allowField(['name', 'image', 'text', 'phone'])->save($data)) {
+ return $this->success('success');
+ };
+ return $this->error('fail');
+ }
+
+
+ public function get()
+ {
+ $copyRight = Cardauth2CopyrightModel::find($this->_param['id']);
+ return $this->success($copyRight);
+ }
+
+ public function destroy()
+ {
+ $validate = new CopyRightAgentValidate();
+ $check = $validate->scene('destroy')->check($this->_input);
+ if ($check == false) {
+ return $this->error($validate->getError());
+ }
+ $m_config = new Cardauth2ConfigModel();
+
+ $auth_config = $m_config->where(['copyright_id'=>$this->_input['id']])->find();
+ if(!empty($auth_config)){
+ return $this->error('This copyright is in use and cannot be deleted');
+ }
+
+ $rst = Cardauth2CopyrightModel::destroy(function ($query) {
+ $query->where('id', '=', $this->_input['id'] ?? 0);
+ });
+
+ return $this->success($rst);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/HouseController.php b/app/agent/controller/HouseController.php
new file mode 100755
index 0000000..3d9cf88
--- /dev/null
+++ b/app/agent/controller/HouseController.php
@@ -0,0 +1,148 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+
+ public function list()
+ {
+ $param = $this->_param;
+ $m_house_auth2 = new Cardauth2HouseModel();
+
+ //By.jingshuixian 2020年4月21日15:13:50
+ //区分行业版数据
+
+ //获取列表
+ if($this->_is_weiqin) {
+ $app_model_name = APP_MODEL_NAME;
+ $list = $m_house_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+
+ ->join('account' , 'a.modular_id = account.uniacid')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+
+ ->where([ ['a.status', '=', 1] , ['account.type', '=', 4] ,['account.isdeleted', '=', 0] , ['v.modules', 'like', "%{$app_model_name}%"] ])
+ ->group('a.modular_id')
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+
+ }else{
+ $list = $m_house_auth2->alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->where([['a.status', '=', 1]])
+ ->paginate(['list_rows' => $param['page_count'] ? $param['page_count'] : 10, 'page' => $param['page'] ? $param['page'] : 1])->toArray();
+ }
+
+
+
+ $wxapp_map = [];
+ $wxapp = Db::name('account_wxapp')->field(['uniacid', 'name'])->select();
+ foreach ($wxapp as $item) {
+ $wxapp_map[$item['uniacid']] = $item['name'];
+ }
+
+ foreach ($list['data'] as $k => $item) {
+ $list['data'][$k]['name'] = $wxapp_map[$item['modular_id']] ?? $item['mini_app_name'];
+ unset($list['data'][$k]['mini_app_name']);
+ }
+
+
+ $list['total_house_number'] = AdminUserService::getSassNum('house',$this->_uniacid);
+
+ $list['total_house_used'] = $m_house_auth2->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+ return $this->success($list);
+ }
+
+
+ public function create()
+ {
+ $data = $this->_input;
+ if (!isset($data['modular_id'])) {
+ return $this->success('参数错误');
+ }
+
+ $time = time();
+ $auth_house = Cardauth2HouseModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if (!$auth_house->isEmpty()) {
+ return $this->error('已存在此小程序');
+ }
+
+ $total_house_number = AdminUserService::getSassNum('house',$this->_uniacid);
+
+ $total_house_used = $auth_house->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+ $remain = $total_house_number - $total_house_used;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+ $rst = $auth_house->save([
+ 'modular_id' => $data[ 'modular_id' ],
+ 'create_time' => $time,
+ 'update_time' => $time,
+ 'sign' => intval( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => 1,
+ 'uniacid' => $this->_uniacid,
+ ]);
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+ return $this->error('fail');
+ }
+
+
+ public function extendedOneYear ()
+ {
+ $data = $this->_input;
+ if (!isset($data['modular_id'])) {
+ return $this->success('参数错误');
+ }
+
+ $time = time();
+ $auth_house = Cardauth2HouseModel::where([['modular_id', '=', $data['modular_id']]])->findOrEmpty();
+
+ if ($auth_house->isEmpty()) {
+ return $this->error('小程序不存在');
+ }
+
+ $total_house_number = AdminUserService::getSassNum('house',$this->_uniacid);
+
+ $total_house_used = $auth_house->where([['uniacid','in',$this->_uniacid_arr]])->sum('count');
+ $remain = $total_house_number - $total_house_used;
+ if ($remain <= 0) {
+ return $this->error('分配的数量超过可用的总数');
+ }
+
+ $rst = $auth_house->save([
+ 'sign' => $auth_house[ 'sign' ] > $time ? ($auth_house[ 'sign' ] + ( 366 * 24 * 60 * 60 )) : ( $time + ( 366 * 24 * 60 * 60 ) ),
+ 'count' => $auth_house['count'] + 1,
+ 'update_time' => $time,
+ ]);
+
+
+ if ($rst) {
+ return $this->success('success');
+ }
+
+
+ return $this->error('fail');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/Index.php b/app/agent/controller/Index.php
new file mode 100755
index 0000000..b70c955
--- /dev/null
+++ b/app/agent/controller/Index.php
@@ -0,0 +1,37 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+ public function delMessageByDay()
+ {
+ if (!isset($this->_input['modular_id']) || !isset($this->_input['days'])) {
+ return $this->success('success');
+ }
+
+ $validate = new Validate();
+ $validate->rule([
+ 'days|清除时间' => 'integer',
+ ]);
+
+ if (!$validate->check($this->_input)) {
+ return $this->error($validate->getError());
+ }
+
+ $modular_id = $this->_input['modular_id'];
+ $days = $this->_input['days'];
+
+ if ($days > 0) {
+ $beginTime = mktime(0, 0, 0, date('m'), date('d') - $days, date('Y'));
+ } else {
+ $beginTime = 99999999999;
+ }
+
+ $rst = Db::name('longbing_card_message')->where([['uniacid', '=', $modular_id], ['create_time', '<', $beginTime]])->delete(true);
+ return $this->success($rst);
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/OssConfig.php b/app/agent/controller/OssConfig.php
new file mode 100755
index 0000000..d61124a
--- /dev/null
+++ b/app/agent/controller/OssConfig.php
@@ -0,0 +1,205 @@
+model = new model();
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:08
+ * @功能说明:列表
+ */
+ public function configList(){
+
+ $input = $this->_input;
+
+ $dis[] = [
+
+ 'uniacid','in' , $this->_uniacid_arr
+
+ ];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['name','like','%'.$input['name'].'%'];
+ }
+
+ $data = $this->model->configList($dis,$input['page_count']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:12
+ * @功能说明:添加
+ */
+ public function configAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+ Db::startTrans();
+ $res = $this->model->configAdd($input);
+
+ $id = $this->model->getLastInsID();
+
+ if(!empty($id) && !empty($input['open_oss']))
+ {
+ $path = LONGBING_EXTEND_PATH . 'timg.jpg';
+
+ if(file_exists($path)){
+
+ $dis['id'] = $id;
+
+ $config = $this->model->configInfo($dis);
+
+ $file = new UploadedFile($path ,'test.jpg');
+
+ $file_upload_model = new Upload($this->_uniacid);
+
+ $check = $file_upload_model->upload('picture' ,$file,$config);
+
+ if(empty($check)) return $this->error(lang('上传配置错误,请检查上传配置是否正确'));
+ }
+ }
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:14
+ * @功能说明:编辑
+ */
+ public function configUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+ Db::startTrans();
+ $res = $this->model->configUpdate($dis,$input);
+
+ if(!empty($res) && !empty($input['open_oss']))
+ {
+ $path = LONGBING_EXTEND_PATH . 'timg.jpg';
+
+ if(file_exists($path)){
+
+ $config = $this->model->configInfo($dis);
+
+ $file = new UploadedFile($path ,'test.jpg');
+
+ $file_upload_model = new Upload($this->_uniacid);
+
+ $check = $file_upload_model->upload('picture' ,$file,$config);
+
+ if(empty($check)) return $this->error(lang('上传配置错误,请检查上传配置是否正确'));
+ }
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:17
+ * @功能说明:详情
+ */
+ public function configInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $res = $this->model->configInfo($dis);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:18
+ * @功能说明:删除
+ */
+ public function configDel(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $res = $this->model->configDel($dis);
+
+ if($res==200){
+
+ $this->errorMsg('已有小程序使用该配置');
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:35
+ * @功能说明:配置下拉框
+ */
+ public function configSelect(){
+
+ $dis[] = [
+
+ 'uniacid','in' , $this->_uniacid_arr
+
+ ];
+
+ $data = $this->model->where($dis)->order('id desc')->select();
+
+ return $this->success($data);
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/PermissionContrller.php b/app/agent/controller/PermissionContrller.php
new file mode 100755
index 0000000..5a7adb9
--- /dev/null
+++ b/app/agent/controller/PermissionContrller.php
@@ -0,0 +1,991 @@
+_user['role_name'] != 'admin') {
+ echo json_encode(['code' => 401, 'error' => lang('Permission denied')]);
+ exit;
+ }
+ }
+ public function getAgentPermission()
+ {
+ $is_super_admin = ($this->_role == 'admin') ? true : false;
+
+ if (!$is_super_admin) {
+ return $this->error('非法请求, 请联系超级管理员');
+ }
+
+ $is_we7 = defined('IS_WEIQIN');
+
+ $permissionArticle = new PermissionArticle(0);
+
+ $permissionBoss = new PermissionBoss(0);
+
+ $permissionBaidu = new PermissionBaidu(0);
+ //截流
+ $permissionClosure = new PermissionClosure(0);
+ //带客有礼
+ $permissionPassenger = new PermissionPassenger(0);
+ //新客福包
+ $permissionRedbag = new PermissionRedbag(0);
+ //满减
+ $permissionReduction = new PermissionReduction(0);
+ //直播
+ $permissionLivevideo = new PermissionLivevideo(0);
+ //短视频
+ $permissionShortvideo = new PermissionShortvideo(0);
+ // 会员等级
+ $permissionMember = new PermissionMember(0);
+ // 餐饮
+ $permissionRestaurant = new PermissionRestaurant(0);
+ //霸王餐
+ $permissionOverlord = new PermissionOverlord(0);
+ //付费课程
+ $permissionPayclass = new PermissionPayclass(0);
+
+ $permissionBargain = new PermissionBargain(0);
+
+ $permissionQuestion = new PermissionQuestion(0);
+
+ $has_article = $permissionArticle->sAuth();
+
+ $has_boss = $permissionBoss->sAuth();
+
+ if($has_boss==true){
+
+ $has_boss = $permissionBoss->getSaasValue()>0?true:false;
+
+ }
+
+ $has_baidu = $permissionBaidu->sAuth();
+ //截流
+ $has_closure = $permissionClosure->sAuth();
+ //带客有礼
+ $has_passenger = $permissionPassenger->sAuth();
+ //新客户包
+ $has_redbag = $permissionRedbag->sAuth();
+ //满减
+ $has_reduction = $permissionReduction->sAuth();
+ //直播
+ $has_livevideo = $permissionLivevideo->sAuth();
+ //短视频
+ $has_shortvideo= $permissionShortvideo->sAuth();
+ //会员
+ $has_member = $permissionMember->sAuth();
+ //餐饮
+ $has_restaurant = $permissionRestaurant->sAuth();
+ // 霸王餐
+ $has_overlord = $permissionOverlord->sAuth();
+ // 付费课程
+ $has_payclass = $permissionPayclass->sAuth();
+ //临时写法==== By.jingshuixian
+ $permissionHouse = new PermissionHouse(0);
+
+ $has_house = $permissionHouse->sAuth();
+
+ $permissionActivity = new PermissionActivity(0);
+
+ $has_activity = $permissionActivity->sAuth();
+
+ $has_bargain = $permissionBargain->sAuth();
+
+ $has_question = $permissionQuestion->sAuth();
+
+
+ if(APP_MODEL_NAME=='longbing_restaurant'){
+
+ $has_restaurant = false;
+ }
+
+ if(APP_MODEL_NAME=='longbing_shortvideo'){
+
+ $has_shortvideo = false;
+ }
+
+ if(APP_MODEL_NAME=='longbing_member'){
+
+ $has_member = false;
+ }
+
+ if(APP_MODEL_NAME=='longbing_house'){
+
+ $has_house = false;
+ }
+
+ if(APP_MODEL_NAME=='longbing_liveshop'){
+
+ $has_livevideo = false;
+ }
+
+$all_meta_json = << $v) {
+ $name = $v['name'];
+
+ switch ($name) {
+ case 'Article' :
+ if (!$has_article) unset($all_meta[$k]);
+ break;
+ case 'Activity' :
+ if (!$has_activity) unset($all_meta[$k]);
+ break;
+ case 'House' :
+ if (!$has_house) unset($all_meta[$k]);
+ break;
+ case 'Company' :
+ if (!$has_boss) unset($all_meta[$k]);
+ break;
+ case 'Account' :
+ if ($is_we7) unset($all_meta[$k]);
+ break;
+ case 'Default' :
+ if (!$is_we7) unset($all_meta[$k]);
+ break;
+ case 'Baidu' :
+ if (!$has_baidu) unset($all_meta[$k]);
+ break;
+ case 'Closure' :
+ if (!$has_closure) unset($all_meta[$k]);
+ break;
+ case 'Passenger' :
+ if (!$has_passenger) unset($all_meta[$k]);
+ break;
+ case 'Cash' :
+ if (!$has_redbag) unset($all_meta[$k]);
+ break;
+ case 'Reduction' :
+ if (!$has_reduction) unset($all_meta[$k]);
+ break;
+ case 'Live' :
+ if (!$has_livevideo) unset($all_meta[$k]);
+ break;
+ case 'Shortvideo':
+ if (!$has_shortvideo) unset($all_meta[$k]);
+ break;
+ case 'Member':
+ if (!$has_member) unset($all_meta[$k]);
+ break;
+ case 'Restaurant':
+ if (!$has_restaurant) unset($all_meta[$k]);
+ break;
+ case 'Overlord':
+ if (!$has_overlord) unset($all_meta[$k]);
+ break;
+ case 'Payclass':
+ if (!$has_payclass) unset($all_meta[$k]);
+ break;
+ case 'Bargain':
+ if (!$has_bargain) unset($all_meta[$k]);
+ break;
+ case 'Questionnaire':
+ if (!$has_question) unset($all_meta[$k]);
+ break;
+ }
+ }
+
+
+ return $this->success(array_values($all_meta));
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/agent/controller/UserController.php b/app/agent/controller/UserController.php
new file mode 100755
index 0000000..b9b35e8
--- /dev/null
+++ b/app/agent/controller/UserController.php
@@ -0,0 +1,44 @@
+error(lang('没有权限'));
+ }
+ //获取数据
+ $input = $this->_input;
+ if(isset($input['admin'])) $input = $input['admin'];
+ //检查用户初始密码是否正确
+ $user = $this->_user;
+ if(isset($user['admin_id']) && !empty($user['admin_id']))
+ {
+ $admin_model = new AdminModel();
+ $user = $admin_model->getAdmin(['admin_id' => $user['admin_id']]);
+// var_dump($user);die;
+ }else{
+ return $this->error(lang('admin is not exist'));
+ }
+ if(empty($user)) return $this->error(lang('admin is not exist'));
+// var_dump($user);die;
+ $check = checkPasswd($input['old_passwd'] ,$user['offset'] ,$user['passwd']);
+ if(!$check) return $this->error(lang('old passwd error'));
+ //修改密码
+ $passwd = createPasswd($input['new_passwd'] ,$user['offset']);
+ //保存修改
+ $admin_model = new AdminModel();
+ $result = $admin_model->updateAdmin(['admin_id' => $user['admin_id']] ,['passwd' => $passwd]);
+ //返回数据
+ return $this->success($result);
+ }
+}
diff --git a/app/agent/info/Info.php b/app/agent/info/Info.php
new file mode 100755
index 0000000..acb7082
--- /dev/null
+++ b/app/agent/info/Info.php
@@ -0,0 +1,23 @@
+ 'agent',
+ //模块标题[必填]
+ 'title' =>'代理管理端',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'agent.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.19',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module' => [],
+ // 插件依赖[可选],格式[[插件名, 插件唯一标识, 依赖版本, 对比方式]]
+ 'need_plugin' => [],
+];
\ No newline at end of file
diff --git a/app/agent/lang/zh-cn.php b/app/agent/lang/zh-cn.php
new file mode 100755
index 0000000..6e985ee
--- /dev/null
+++ b/app/agent/lang/zh-cn.php
@@ -0,0 +1,17 @@
+ '欢迎使用ThinkPHP',
+ 'data type error' => '数据类型错误',
+ 'tabbar count can not be greater than' => '菜单栏数量不能大于',
+ 'auto get template error' => '自动获取服务通知模板失败,请稍后再试。',
+ 'wx app site error ,please check site message.' => '微信小程序配置异常,请检查站点配置',
+ 'wx app site error' => '微信小程序配置异常,请检查站点配置',
+ 'param error' => '参数错误',
+ 'update success' => '更新成功',
+ 'update error' => '更新失败,请稍后再试',
+ 'Permission denied' => '权限不足,请联系超级管理员操作。',
+ 'old passwd error' => '原密码错误,请检查原密码。',
+ 'This copyright is in use and cannot be deleted' => '该版权正在被使用 无法删除',
+ 'app_name is empty' => '应用名称不能为空。',
+
+];
\ No newline at end of file
diff --git a/app/agent/model/AdminModel.php b/app/agent/model/AdminModel.php
new file mode 100755
index 0000000..c9c83d2
--- /dev/null
+++ b/app/agent/model/AdminModel.php
@@ -0,0 +1,56 @@
+hasOne(AppAdminModel::class, 'admin_id', 'admin_id');
+ }
+
+
+ public function role()
+ {
+ return $this->hasOne(AdminRoleModel::class, 'role_id', 'role_id');
+ }
+
+ /**
+ *
+ */
+ public function createAdmin($data)
+ {
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ return !empty($result);
+ }
+
+ //修改
+ public function updateAdmin($filter ,$data)
+ {
+ $filter['status'] = 1;
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+// var_dump($result);die;
+ return !empty($result);
+ }
+ /**
+ * 获取用户
+ */
+ public function getAdmin($filter)
+ {
+ $filter['deleted'] = 0;
+ $filter['status'] = 1;
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/model/AdminRoleModel.php b/app/agent/model/AdminRoleModel.php
new file mode 100755
index 0000000..676c3ee
--- /dev/null
+++ b/app/agent/model/AdminRoleModel.php
@@ -0,0 +1,13 @@
+where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $list;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 10:55
+ * @功能说明:添加代理商等级
+ */
+ public function levelAdd($data){
+ //创建时间
+ $data['create_time'] = time();
+ //更新时间
+ $data['update_time'] = time();
+ //状态
+ $data['status'] = 1;
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 10:57
+ * @功能说明:代理商等级编辑
+ */
+ public function levelUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:34
+ * @功能说明:代理商等级详情
+ */
+ public function levelInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-26 13:28
+ * @功能说明:代理商选择框
+ */
+ public function levelSelect($dis){
+
+ $data = $this->where($dis)->order('top desc,id desc')->select();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/model/AgentList.php b/app/agent/model/AgentList.php
new file mode 100755
index 0000000..e7d06d0
--- /dev/null
+++ b/app/agent/model/AgentList.php
@@ -0,0 +1,152 @@
+where($dis)->value('title');
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:54
+ * @功能说明:获取状态
+ */
+ public function getStatusTextAttr($value,$data){
+
+ if(!empty($data['over_time'])){
+
+ switch ($data['over_time']){
+
+ case $data['over_time']>time():
+
+ return '使用中';
+
+ break;
+ case $data['over_time']where(['agent_id'=>$data['id']])->count();
+
+ return $num;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 10:54
+ * @功能说明:代理商列表
+ */
+ public function agentList($dis,$page=10){
+
+ $list = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $list;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 10:55
+ * @功能说明:添加代理商
+ */
+ public function agentAdd($data){
+ //创建时间
+ $data['create_time'] = time();
+ //更新时间
+ $data['update_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 10:57
+ * @功能说明:代理商编辑
+ */
+ public function agentUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-12 13:34
+ * @功能说明:代理商详情
+ */
+ public function agentInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/model/AppAdminModel.php b/app/agent/model/AppAdminModel.php
new file mode 100755
index 0000000..c31555d
--- /dev/null
+++ b/app/agent/model/AppAdminModel.php
@@ -0,0 +1,13 @@
+hasOne(CardConfig::class, 'uniacid', 'modular_id');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/model/Cardauth2AuthAppModel.php b/app/agent/model/Cardauth2AuthAppModel.php
new file mode 100755
index 0000000..fce868a
--- /dev/null
+++ b/app/agent/model/Cardauth2AuthAppModel.php
@@ -0,0 +1,53 @@
+field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+
+ ->join('account' , 'a.modular_id = account.uniacid')
+ ->join('wxapp_versions v' , 'a.modular_id = v.uniacid')
+
+ ->where([['a.status', '=', 1],['app_name','like',"%".$app_name ."%"] , ['account.type', '=', 4] ,['account.isdeleted', '=', 0] , ['v.modules', 'like', "%{$app_model_name}%"] ])
+ ->group('a.id')
+ ->sum('count');
+
+ }else{
+
+ $count = Cardauth2Model
+ ::alias('a')
+ ->field(['a.id', 'a.modular_id', 'a. create_time', 'a.sign', 'c.mini_app_name'])
+ ->join('longbing_card_config c', 'a.modular_id = c.uniacid')
+ ->where([['a.status', '=', 1],['app_name','=',$app_name]])
+ ->group('a.id')
+ ->sum('count');
+ }
+
+ return $count;
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/model/Cardauth2BossModel.php b/app/agent/model/Cardauth2BossModel.php
new file mode 100755
index 0000000..e512708
--- /dev/null
+++ b/app/agent/model/Cardauth2BossModel.php
@@ -0,0 +1,14 @@
+hasOne(CardConfig::class, 'uniacid', 'modular_id');
+ }
+}
\ No newline at end of file
diff --git a/app/agent/model/Cardauth2CopyrightModel.php b/app/agent/model/Cardauth2CopyrightModel.php
new file mode 100755
index 0000000..1e142aa
--- /dev/null
+++ b/app/agent/model/Cardauth2CopyrightModel.php
@@ -0,0 +1,13 @@
+order('id','desc')->select()->toArray();
+ if($data){
+ $data = $data[0];
+ }
+ return $data;
+ }
+ public function is_table(){
+ $prefix = config('database.connections.mysql.prefix');
+ $table = $prefix.$this->name;
+ $res = Db::query('SHOW TABLES LIKE '."'".$table."'");
+ return $res;
+ }
+
+
+ /**
+ * 获得配置值
+ *
+ * @param string|\think\model\concern\string $key
+ * @return int|mixed
+ * @author shuixian
+ * @DataTime: 2020/1/2 22:51
+ */
+ public function getDefaultValue($key ,$defualt = -1 ){
+
+ $defaultConfig = $this->getinfo();
+ $number = isset($defaultConfig[$key]) ? $defaultConfig[$key] : $defualt ;
+ return $number;
+ }
+
+
+ /**
+ * 获得名片数量默认配置
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2020/1/2 22:51
+ */
+ public function getCardNumber(){
+
+ return $this->getDefaultValue('card_number');
+ }
+
+ /**
+ * 获取短信群发默认配置
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2020/1/2 22:53
+ */
+ public function getSendMsg(){
+ return $this->getDefaultValue('send_switch' , 0 );
+ }
+}
\ No newline at end of file
diff --git a/app/agent/model/Cardauth2HouseModel.php b/app/agent/model/Cardauth2HouseModel.php
new file mode 100755
index 0000000..cbee8d4
--- /dev/null
+++ b/app/agent/model/Cardauth2HouseModel.php
@@ -0,0 +1,14 @@
+where($filter);
+ $result = $result->limit(1)->select();
+ if(!empty($result))
+ {
+ $result = $result->toArray();
+ if(isset($result[0])) $result = $result[0];
+ }
+ return $result;
+ }
+
+ public function updatePlugeKey($filter ,$data = [])
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+}
diff --git a/app/agent/model/OssConfig.php b/app/agent/model/OssConfig.php
new file mode 100755
index 0000000..e2eed4c
--- /dev/null
+++ b/app/agent/model/OssConfig.php
@@ -0,0 +1,109 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:02
+ * @功能说明:编辑
+ */
+ public function configUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:04
+ * @功能说明:列表
+ */
+ public function configList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:15
+ * @功能说明:详情
+ */
+ public function configInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $dis
+ * @功能说明:删除
+ * @author chenniang
+ * @DataTime: 2020-05-14 10:18
+ */
+ public function configDel($dis){
+
+ $config_dis = [
+
+ 'upload_setting' => $dis['id']
+
+ ];
+
+ $info = Db::name('longbing_cardauth2_config')->where($config_dis)->find();
+
+ if(!empty($info)){
+
+ return 200;
+ }
+
+ $res = $this->where($dis)->delete();
+
+ return $res;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/agent/route/route.php b/app/agent/route/route.php
new file mode 100755
index 0000000..ea4efd0
--- /dev/null
+++ b/app/agent/route/route.php
@@ -0,0 +1,141 @@
+findOrEmpty();
+ if (!$subAdmin->isEmpty()) {
+ return false;
+ }
+
+ $offset = createOffset();
+ $new = [
+ 'admin_id' => $input['uuid'],
+ 'account' => $input['account'],
+ 'uniacid' => $uniacid ,
+ 'offset' => $offset,
+ 'passwd' => createPasswd($input['passwd'], $offset),
+ 'role_id' => $input['role_id'],
+ 'creator_id' => $input['admin_id'],
+ 'status' => 1,
+ ];
+ $rst = $subAdmin->save($new);
+ if (!$rst) {
+ return false;
+ }
+ return true;
+
+
+ }
+
+ /**
+ * 初始化默认角色
+ *
+ * @throws \Exception
+ * @author shuixian
+ * @DataTime: 2019/12/31 18:46
+ */
+ public static function initDefaultRole(){
+
+ $adminRole = new AdminRoleModel();
+ $data = [] ;
+ if(!$adminRole->where(['role_id'=> 'e1af223e997011e997cb77d35351cc48'])->count()){
+
+
+ $data[] = [
+ 'role_id' =>'e1af223e997011e997cb77d35351cc48',
+ 'role_name' =>'admin',
+ 'description' =>'超级管理员',
+ 'create_time' =>null,
+ 'update_time' =>null,
+ 'delete_time' =>null,
+ 'deleted' =>'0',
+ 'uniacid' =>'8888',
+
+ ];
+
+ }
+ if(!$adminRole->where(['role_id'=> 'e7d81116997011e99b985595a87cbdcb'])->count()) {
+ $data[] = [
+ 'role_id' => 'e7d81116997011e99b985595a87cbdcb',
+ 'role_name' => 'user',
+ 'description' => '普通用户',
+ 'create_time' => null,
+ 'update_time' => null,
+ 'delete_time' => null,
+ 'deleted' => '0',
+ 'uniacid' => '8888',
+
+ ];
+ }
+
+ $adminRole->saveAll($data);
+
+
+
+ }
+
+ /**
+ * 绑定小程序管理员
+ *
+ * @param $data
+ * @author shuixian
+ * @DataTime: 2019/12/31 18:49
+ */
+ public static function bindAppAdmin($data){
+
+ if(AppAdminModel::where(['id'=> $data['id']])->count()) {
+ return false;
+ }
+
+ $appAdmin = new AppAdminModel();
+
+ $appAdmin->save($data) ;
+
+ }
+
+
+ /**
+ * @param $app_name
+ * @功能说明:获取授权数量
+ * @author chenniang
+ * @DataTime: 2020-01-03 11:19
+ */
+ public static function getSassNum($key,$uniacid){
+ //类名
+ $className = 'Permission' . ucfirst($key);
+ //类路径
+ $permissionPath = APP_PATH . $key . '/info/' . $className . '.php';
+
+// dump(file_exists($permissionPath),$permissionPath);exit;
+ $num = 0;
+ if (file_exists($permissionPath) && require_once($permissionPath)) {
+
+
+
+ //实例文件名
+ $permissionClassName = 'app\\' . $key . '\\info\\'. $className;
+
+ $permission = new $permissionClassName($uniacid);
+ //获取授权数量
+ $num = $permission->getAuthNumber();
+ }
+ return $num;
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/validate/AgentAdminValidate.php b/app/agent/validate/AgentAdminValidate.php
new file mode 100755
index 0000000..54d900b
--- /dev/null
+++ b/app/agent/validate/AgentAdminValidate.php
@@ -0,0 +1,27 @@
+ ['require'],
+ 'status' => ['require','number', 'in' => [-1, 0, 1]],
+ 'account|名字' => ['require'],
+ 'passwd|密码' => [ 'require'],
+ ];
+
+ protected $scene = [
+ 'addSubAdmin' => ['account', 'passwd'],
+ 'updateSubAdmin' => ['passwd'],
+ 'delSubAdmin' => ['admin_id']
+ ];
+
+
+
+}
\ No newline at end of file
diff --git a/app/agent/validate/Cardauth2ArticleValidate.php b/app/agent/validate/Cardauth2ArticleValidate.php
new file mode 100755
index 0000000..adbc859
--- /dev/null
+++ b/app/agent/validate/Cardauth2ArticleValidate.php
@@ -0,0 +1,21 @@
+ 'require|number|gt:0',
+ 'number|获客文章数量' => 'require|integer|egt:0',
+ ];
+
+ protected $scene = [
+ 'create' => ['number', 'modular_id'],
+ ];
+
+
+}
\ No newline at end of file
diff --git a/app/agent/validate/Cardauth2ConfigValidate.php b/app/agent/validate/Cardauth2ConfigValidate.php
new file mode 100755
index 0000000..0045e3b
--- /dev/null
+++ b/app/agent/validate/Cardauth2ConfigValidate.php
@@ -0,0 +1,62 @@
+ 'require|number|gt:0',
+ 'number|名片数量' => 'require|integer|egt:0',
+ 'end_time|到期时间' => 'require|integer',
+ 'copyright_id|版权id' => 'require|integer',
+ 'send_switch' => 'require|integer',
+ 'boss|BOSS数量' => 'require|integer|egt:0',
+// 'appiont' =>'require|integer',
+ 'payqr' =>'require|integer',
+ 'shop_switch' => 'require|integer',
+ 'timeline_switch' => 'require|integer',
+ 'website_switch' => 'require|integer',
+ 'article' => 'require|integer',
+// 'activity_switch' => 'require|integer',
+ 'pay_shop' => 'require|integer',
+ 'house_switch' => 'require|integer',
+// 'tool_switch' => 'require|integer',
+ ];
+
+ protected $scene = [
+ 'create' => ['number', 'end_time', 'copyright_id', 'send_switch',
+ 'boss', 'appiont', 'payqr', 'shop_switch', 'timeline_switch',
+ 'website_switch', 'article', 'activity', 'pay_shop' ,
+ 'house_switch'],
+ 'delete' => ['id']
+ ];
+
+
+ public function sceneUpdate()
+ {
+ return $this->only(['id','number', 'end_time', 'copyright_id', 'send_switch',
+ 'boss', 'appiont', 'payqr', 'shop_switch', 'timeline_switch',
+ 'website_switch', 'article', 'activity', 'pay_shop' ,
+ 'house_switch', 'tool_switch'])
+ ->remove('number', 'require')
+ ->remove('end_time', 'require')
+ ->remove('copyright_id', 'require')
+ ->remove('boss', 'require')
+ ->remove('appiont', 'require')
+ ->remove('payqr', 'require')
+ ->remove('shop_switch', 'require')
+ ->remove('timeline_switch', 'require')
+ ->remove('website_switch', 'require')
+ ->remove('article', 'require')
+ ->remove('activity', 'require')
+ ->remove('pay_shop', 'require')
+ ->remove('house_switch', 'require')
+ ->remove('tool_switch', 'require');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/validate/CopyRightAgentValidate.php b/app/agent/validate/CopyRightAgentValidate.php
new file mode 100755
index 0000000..215ca01
--- /dev/null
+++ b/app/agent/validate/CopyRightAgentValidate.php
@@ -0,0 +1,34 @@
+ ['require','number', '>=' => 1],
+ 'status' => ['require','number', 'in' => [-1, 0, 1]],
+ 'name|名称' => ['require'],
+ 'image|版权图片' => [ 'require', 'length' => '10,500'],
+ 'text|版权文字' => ['require'],
+ 'phone|联系号码' => ['require', 'length' => '8,20'],
+ ];
+
+ protected $scene = [
+ 'create' => ['name', 'image', 'text', 'phone'],
+ 'get' => ['id'],
+ 'destroy' => ['id']
+ ];
+
+
+ public function sceneUpdate()
+ {
+ return $this->only(['id', 'image','phone'])
+ ->remove('image', 'require')
+ ->remove('phone', 'require');
+ }
+
+}
\ No newline at end of file
diff --git a/app/agent/view/index/index.html b/app/agent/view/index/index.html
new file mode 100755
index 0000000..d7d6ee2
--- /dev/null
+++ b/app/agent/view/index/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+ 代理管理端
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.php b/app/build.php
new file mode 100755
index 0000000..ba9607c
--- /dev/null
+++ b/app/build.php
@@ -0,0 +1,26 @@
+
+// +----------------------------------------------------------------------
+
+/**
+ * php think build 自动生成应用的目录结构的定义示例
+ */
+return [
+ // 需要自动创建的文件
+ '__file__' => [],
+ // 需要自动创建的目录
+ '__dir__' => ['controller', 'model', 'view'],
+ // 需要自动创建的控制器
+ 'controller' => ['Index'],
+ // 需要自动创建的模型
+ 'model' => ['AdminUser'],
+ // 需要自动创建的模板
+ 'view' => ['index/index'],
+];
diff --git a/app/card/common.php b/app/card/common.php
new file mode 100755
index 0000000..9bb82e8
--- /dev/null
+++ b/app/card/common.php
@@ -0,0 +1,161 @@
+getStaffMaxAutoCount(['uniacid' => $uniacid]);
+ if(empty($count)) $count = 0;
+ return (int)$count;
+}
+function longbingGetWxAppTabbarResponse($data)
+{
+ if(empty($data)) return [];
+ //数据处理
+ $data['list'] = [];
+ //处理过的参数
+ $menus = [];
+ //默认设置
+ $data['color'] = '#5d6268';
+// $data['selectedColor'] = '#21bf34';
+ $data['selectedColor'] = '#19c865';
+ $data['backgroundColor'] = '#fff';
+ $data['borderStyle'] = 'white';
+ //名片
+ if(isset($data['menu1_is_hide']) && !empty($data['menu1_is_hide']))
+ {
+ $val = [];
+ $val['is_show'] = $data['menu1_is_hide'];
+ $val['key'] = 1;
+ $val['iconPath'] = 'icon-mingpian';
+ $val['selectedIconPath'] = 'icon-mingpian1';
+ $val['pageComponents'] = 'cardHome';
+ if(isset($data['menu1_name'])) $val['name'] = $data['menu1_name'];
+ if(isset($data['menu1_url'])) $val['url'] = $data['menu1_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu1_url_out'])) $val['url_out'] = $data['menu1_url_out'];
+ if(isset($data['menu1_url_jump_way'])) $val['jump_way'] = $data['menu1_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ //商城
+ if(isset($data['menu2_is_hide']) && !empty($data['menu2_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 2;
+ $val['is_show'] = $data['menu2_is_hide'];
+ $val['iconPath'] = 'icon-shangcheng1';
+ $val['selectedIconPath'] = 'icon-shangcheng';
+ $val['pageComponents'] = 'shopHome';
+ if(isset($data['menu2_name'])) $val['name'] = $data['menu2_name'];
+ if(isset($data['menu2_url'])) $val['url'] = $data['menu2_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu2_url_out'])) $val['url_out'] = $data['menu2_url_out'];
+ if(isset($data['menu2_url_jump_way'])) $val['url_jump_way'] = $data['menu2_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ //动态
+ if(isset($data['menu3_is_hide']) && !empty($data['menu3_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 3;
+ $val['is_show'] = $data['menu3_is_hide'];
+ $val['iconPath'] = 'icon-dongtai1';
+ $val['selectedIconPath'] = 'icon-dongtai';
+ $val['pageComponents'] = 'infoHome';
+ if(isset($data['menu3_name'])) $val['name'] = $data['menu3_name'];
+ if(isset($data['menu3_url'])) $val['url'] = $data['menu3_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu3_url_out'])) $val['url_out'] = $data['menu3_url_out'];
+ if(isset($data['menu3_url_jump_way'])) $val['url_jump_way'] = $data['menu3_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ //官网
+ if(isset($data['menu4_is_hide']) && !empty($data['menu4_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 4;
+ $val['is_show'] = $data['menu4_is_hide'];
+ $val['iconPath'] = 'icon-guanwang';
+ $val['selectedIconPath'] = 'icon-guanwang1';
+ $val['pageComponents'] = 'websiteHome';
+ if(isset($data['menu4_name'])) $val['name'] = $data['menu4_name'];
+ if(isset($data['menu4_url'])) $val['url'] = $data['menu4_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu4_url_out'])) $val['url_out'] = $data['menu4_url_out'];
+ if(isset($data['menu4_url_jump_way'])) $val['url_jump_way'] = $data['menu4_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ //预约
+ if(isset($data['menu_appoint_is_hide']) && !empty($data['menu_appoint_is_hide']))
+ {
+ $val = [];
+ $val['key'] = 7;
+ $val['is_show'] = $data['menu_appoint_is_hide'];
+ $val['iconPath'] = 'icon-yuyue';
+ $val['selectedIconPath'] = 'icon-yuyue1';
+ $val['pageComponents'] = 'reserveHome';
+ if(isset($data['menu_appoint_name'])) $val['name'] = $data['menu_appoint_name'];
+ if(isset($data['menu_appoint_url'])) $val['url'] = $data['menu_appoint_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu_appoint_url_out'])) $val['url_out'] = $data['menu_appoint_url_out'];
+ if(isset($data['menu_appoint_url_jump_way'])) $val['url_jump_way'] = $data['menu_appoint_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ //活动报名
+ if(isset($data['menu_activity_is_show']) && !empty($data['menu_activity_is_show']))
+ {
+ $val = [];
+ $val['key'] = 6;
+ $val['is_show'] = $data['menu_activity_is_show'];
+ $val['iconPath'] = 'icon-huodong1';
+ $val['selectedIconPath'] = 'icon-huodong';
+ $val['pageComponents'] = 'avtivityHome';
+ if(isset($data['menu_activity_name'])) $val['name'] = $data['menu_activity_name'];
+ if(isset($data['menu_activity_url'])) $val['url'] = $data['menu_activity_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu_activity_url_out'])) $val['url_out'] = $data['menu_activity_url_out'];
+ if(isset($data['menu_activity_url_jump_way'])) $val['url_jump_way'] = $data['menu_activity_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ //房产
+ if(isset($data['menu_house_is_show']) && !empty($data['menu_house_is_show']))
+ {
+ $val = [];
+ $val['key'] = 5;
+ $val['is_show'] = $data['menu_house_is_show'];
+ $val['iconPath'] = 'icon-fangchan1';
+ $val['selectedIconPath'] = 'icon-fangchan';
+ $val['pageComponents'] = 'houseHome';
+ if(isset($data['menu_house_name']))$val['name'] = $data['menu_house_name'];
+ if(isset($data['menu_house_url']))$val['url'] = $data['menu_house_url'];
+ $val['url'] = "/pages/user/home";
+ if(isset($data['menu_house_url_out']))$val['url_out'] = $data['menu_house_url_out'];
+ if(isset($data['menu_house_url_jump_way']))$val['url_jump_way'] = $data['menu_house_url_jump_way'];
+ $data['list'][] = $val;
+ }
+ $menus = ["menu1_name","menu1_is_hide","menu1_url","menu1_url_out","menu1_url_jump_way","menu2_name","menu2_is_hide","menu2_url","menu2_url_out","menu2_url_jump_way","menu3_name","menu3_is_hide","menu3_url","menu3_url_out","menu3_url_jump_way","menu4_name","menu4_is_hide","menu4_url","menu4_url_out","menu4_url_jump_way","menu_appoint_name","menu_appoint_is_hide","menu_appoint_url","menu_appoint_url_out","menu_appoint_url_jump_way","menu_activity_is_show","menu_activity_name","menu_activity_is_hide","menu_activity_url","menu_activity_url_out","menu_activity_url_jump_way","menu_house_is_show","menu_house_name","menu_house_is_hide","menu_house_url","menu_house_url_out","menu_house_url_jump_way"];
+ foreach($menus as $menu)
+ {
+ unset($data[$menu]);
+ }
+ return $data;
+}
+if ( !function_exists( 'wxContentRlue' ) ) {
+//检测评论发表是否合法
+ function wxContentRlue($content, $access_token)
+ {
+ $url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token={$access_token}";
+ $tmp = [
+ 'url' => $url,
+ 'data' => [
+ 'content' => urlencode($content)
+ ],
+ ];
+ $rest = lbCurlPost($tmp['url'], urldecode(json_encode($tmp['data'])));
+ $rest = json_decode($rest, true);
+ return $rest;
+ }
+}
+
diff --git a/app/card/config.php b/app/card/config.php
new file mode 100755
index 0000000..59e3111
--- /dev/null
+++ b/app/card/config.php
@@ -0,0 +1,35 @@
+ 1,
+ "is_show" => 1,
+ "iconPath" =>"icon-mingpian",
+ "selectedIconPath"=> "icon-mingpian1",
+ "pageComponents" => "cardHome",
+ "name" => "名片",
+ "url" => "/pages/user/home",
+ "url_out" => "",
+ "url_jump_way" => 0
+];
+
+$page_BusinessCard = [
+
+];
+
+
+return [
+
+ 'BusinessCard_tabbar' => $tabbar_BusinessCard,
+ 'BusinessCard_page' => $page_BusinessCard
+
+];
\ No newline at end of file
diff --git a/app/card/controller/Admin.php b/app/card/controller/Admin.php
new file mode 100755
index 0000000..ab2526e
--- /dev/null
+++ b/app/card/controller/Admin.php
@@ -0,0 +1,2463 @@
+modelCompany = new Company();
+ $this->modelConfig = new Config();
+
+// dump('ccc');exit;
+ }
+
+ /**
+ * @Purpose: 后台概览页面
+ *
+ * @Method: GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function overview ()
+ {
+ $time = time();
+ $modelConfig = new Config();
+ $config = $modelConfig->where( [ [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->find();
+ if ( !$config )
+ {
+ $modelConfig->initConfig( $this->_uniacid );
+ $config = $modelConfig->where( [ [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->find();
+ }
+
+
+ $data = [];
+
+ $exist = Db::query( 'show tables like "%longbing_card_config%"' );
+
+ $auth_info = false;
+
+ if ( !empty( $exist ) )
+ {
+ $auth_info = Db::name( 'longbing_cardauth2_config' )
+ ->where( [ [ 'modular_id', '=', $this->_uniacid ] ] )
+ ->find();
+ }
+
+ // 小程序版本
+ $data[ 'version' ] = '多功能无限开版';
+ if ( $this->card_auth_version )
+ {
+ $data[ 'version' ] = $this->card_auth_version . '开版';
+ }
+
+ // 已开员工名片数量
+ $data[ 'card_number' ] = User::where( [ [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->count();
+
+ // 可开通名片数量
+ $data[ 'total_card_number' ] = '无限制';
+ if ( $this->card_auth_card )
+ {
+ $data[ 'total_card_number' ] = $this->card_auth_card;
+ }
+ if ( $auth_info )
+ {
+ $data[ 'total_card_number' ] = $auth_info[ 'number' ];
+ }
+ if ( $exist && !$auth_info )
+ {
+ $existTmp = Db::query( 'show tables like "longbing_cardauth2_default"' );
+
+ if ( $existTmp )
+ {
+ $auth_info_tmp = Db::name( 'longbing_cardauth2_default' )
+ ->find();
+ if ( $auth_info_tmp )
+ {
+ $data[ 'total_card_number' ] = $auth_info_tmp[ 'number' ];
+ }
+ }
+ }
+
+ // 小程序使用天数
+ $data[ 'use_days' ] = ( $time - $config[ 'create_time' ] ) / ( 24 * 60 * 60 );
+ $data[ 'start_date' ] = date( 'Y年m月d日', $config[ 'create_time' ] );
+ if ( $data[ 'use_days' ] < 0 )
+ {
+ $data[ 'use_days' ] = 0;
+ }
+ else
+ {
+ $data[ 'use_days' ] = ceil( $data[ 'use_days' ] );
+ }
+
+ // 小程序剩余可用天数 / 日期
+ $data[ 'left_days' ] = [];
+ if ( defined( 'IS_WEIQIN' ) && IS_WEIQIN )
+ {
+ $tmp = Db::name( 'account' )
+ ->where( [ [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->find();
+ if ( $tmp && $tmp[ 'endtime' ] )
+ {
+ $data[ 'left_days' ][] = $tmp[ 'endtime' ];
+ }
+ }
+
+ if ( $auth_info )
+ {
+ $data[ 'left_days' ][] = $auth_info[ 'end_time' ];
+ }
+
+ if ( empty( $data[ 'left_days' ] ) )
+ {
+ $data[ 'left_days' ] = '无限制';
+ $data[ 'left_date' ] = '无限制';
+ }
+ else
+ {
+ sort( $data[ 'left_days' ] );
+ $data[ 'left_days' ] = $data[ 'left_days' ][ 0 ];
+ $data[ 'left_date' ] = date( 'Y年m月d日', $data[ 'left_days' ] );
+ $data[ 'left_days' ] = ( $time - $config[ 'left_days' ] ) / ( 24 * 60 * 60 );
+ if ( $data[ 'left_days' ] < 0 )
+ {
+ $data[ 'left_days' ] = 0;
+ }
+ else
+ {
+ $data[ 'left_days' ] = ceil( $data[ 'left_days' ] );
+ }
+ }
+
+
+ // 新增客户数量
+ $last = 30;
+ $data[ 'new_client_30' ] = [];
+
+ for ( $i = 0; $i < $last; $i++ )
+ {
+ $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $i, date( 'Y' ) );
+ $endTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $i + 1, date( 'Y' ) ) - 1;
+
+ $number = User::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'create_time', 'BETWEEN', [ $beginTime, $endTime ] ] ]
+ )
+ ->count();
+
+
+ $tmp = [ 'date' => date( 'm-d', $beginTime ), 'time' => $beginTime, 'number' => $number, ];
+ array_push( $data[ 'new_client_30' ], $tmp );
+ }
+
+ $data[ 'new_client_7' ] = array_slice( $data[ 'new_client_30' ], 0, 7 );
+ $data[ 'new_client_15' ] = array_slice( $data[ 'new_client_30' ], 0, 15 );
+
+
+ //咨询客户数量
+ $last = 30;
+ $data[ 'consult_client_30' ] = [];
+
+ for ( $i = 0; $i < $last; $i++ )
+ {
+ $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $i, date( 'Y' ) );
+ $endTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $i + 1, date( 'Y' ) ) - 1;
+
+ $number = CardMessage::where( [ [ 'uniacid', '=', $this->_uniacid ],
+ [ 'create_time', 'BETWEEN', [ $beginTime, $endTime ] ] ]
+ )
+ ->group( 'user_id' )
+ ->count();
+
+
+ $tmp = [ 'date' => date( 'm-d', $beginTime ), 'time' => $beginTime, 'number' => $number, ];
+ array_push( $data[ 'consult_client_30' ], $tmp );
+ }
+
+ $data[ 'consult_client_7' ] = array_slice( $data[ 'consult_client_30' ], 0, 7 );
+ $data[ 'consult_client_15' ] = array_slice( $data[ 'consult_client_30' ], 0, 15 );
+
+
+ // 客户兴趣占比
+ $interest_total = 0;
+ // 对公司感兴趣
+ $data[ 'interest_company' ][ 'number' ] = CardCount::whereOr( [ [ 'sign', '=', 'view' ], [ 'type', '=', 6 ],
+ [ 'uniacid', '=', $this->_uniacid ] ]
+ )
+ ->count();
+
+ $interest_total += $data[ 'interest_company' ][ 'number' ];
+
+
+ // 对产品感兴趣
+ $map1 = [ [ 'sign', '=', 'copy' ], [ 'type', '=', 2 ],
+ [ 'uniacid', '=', $this->_uniacid ] ];
+ $map2 = [ [ 'sign', '=', 'copy' ], [ 'type', '=', 1 ],
+ [ 'uniacid', '=', $this->_uniacid ] ];
+ $data[ 'interest_goods' ][ 'number' ] = CardCount::whereOr( [ $map1, $map2 ]
+ )
+ ->count();
+
+ $interest_total += $data[ 'interest_goods' ][ 'number' ];
+
+
+ // 对员工感兴趣
+ $map1 = [ [ 'sign', '=', 'copy' ], [ 'uniacid', '=', $this->_uniacid ] ];
+ $map2 = [ [ 'sign', '<>', 'praise' ], [ 'uniacid', '=', $this->_uniacid ] ];
+ $data[ 'interest_staff' ][ 'number' ] = CardCount::whereOr( [ $map1, $map2 ]
+ )
+ ->count();
+
+ $interest_total += $data[ 'interest_staff' ][ 'number' ];
+
+
+ $data[ 'interest_company' ][ 'rate' ] = $data[ 'interest_company' ][ 'number' ] / $interest_total * 100;
+ $data[ 'interest_company' ][ 'rate' ] = sprintf( "%.0f", $data[ 'interest_company' ][ 'rate' ] );
+
+ $data[ 'interest_goods' ][ 'rate' ] = $data[ 'interest_goods' ][ 'number' ] / $interest_total * 100;
+ $data[ 'interest_goods' ][ 'rate' ] = sprintf( "%.0f", $data[ 'interest_goods' ][ 'rate' ] );
+
+ $data[ 'interest_staff' ][ 'rate' ] = $data[ 'interest_staff' ][ 'number' ] / $interest_total * 100;
+ $data[ 'interest_staff' ][ 'rate' ] = sprintf( "%.0f", $data[ 'interest_staff' ][ 'rate' ] );
+
+
+ $data[ 'staff_power' ] = $this->bossAi( $this->_uniacid );
+
+ return $this->success( $data );
+ }
+
+ function bossAi ( $uniacid )
+ {
+
+ $default = [ 'client' => 0, // 获客能力值
+ 'charm' => 0, // 个人魅力值
+ 'interaction' => 0, // 客户互动值
+ 'product' => 0, // 产品推广值
+ 'website' => 0, // 官网推广度
+ 'active' => 0, // 销售主动性值
+ ];
+ $max = [ 'client' => 0, // 获客能力值
+ 'charm' => 0, // 个人魅力值
+ 'interaction' => 0, // 客户互动值
+ 'product' => 0, // 产品推广值
+ 'website' => 0, // 官网推广度
+ 'active' => 0, // 销售主动性值
+ ];
+ $staff_list = User::where( [ [ 'uniacid', '=', $uniacid ], [ 'is_staff', '=', 1 ] ] )
+ ->field( [ 'id', 'nickName' ] )
+ ->select()
+ ->toArray();
+
+ foreach ( $staff_list as $k => $v )
+ {
+ $info = UserInfo::where( [ [ 'uniacid', '=', $uniacid ], [ 'fans_id', '=', $v[ 'id' ] ] ] )
+ ->field( [ 'name', 'avatar', 'phone', 'job_id' ] )
+ ->find();
+
+
+ $total = 0;
+
+ $value = $this->bossGetAiValue( $v[ 'id' ], $uniacid );
+
+ foreach ( $value as $k2 => $v2 )
+ {
+ if ( $v2[ 'value' ] > $max[ $k2 ] )
+ {
+ $max[ $k2 ] = $v2[ 'value' ];
+ }
+ $total += $v2[ 'value' ];
+ }
+
+ $staff_list[ $k ][ 'value' ] = $value;
+ $staff_list[ $k ][ 'total' ] = $total;
+ $staff_list[ $k ][ 'info' ] = $info;
+ }
+
+ // 二维数组排序
+ array_multisort( array_column( $staff_list, 'total' ), SORT_DESC, $staff_list );
+
+ $staff_list = array_splice( $staff_list, 0, 3 );
+
+
+ $data = [ 'list' => $staff_list, 'max' => $max ];
+
+ return $data;
+ }
+
+ function bossGetAiValue ( $id, $uniacid )
+ {
+ $value = [ 'client' => 0, // 获客能力值
+ 'charm' => 0, // 个人魅力值
+ 'interaction' => 0, // 客户互动值
+ 'product' => 0, // 产品推广值
+ 'website' => 0, // 官网推广度
+ 'active' => 0, // 销售主动性值
+ ];
+ $check = CardValue::where( [ [ 'staff_id', '=', $id ] ] )
+ ->find();
+
+ if ( ( empty( $check ) ) || ( !empty( $check ) && $check[ 'update_time' ] - time() > 24 * 60 * 60 ) )
+ {
+ // 获客能力值
+ $value[ 'client' ] = Collection::where( [ [ 'status', '=', 1 ], [ 'to_uid', '=', $id ] ] )
+ ->count();
+
+ // 个人魅力值
+ $list1 = CardCount::where( [ [ 'type', '=', 'praise' ], [ 'type', '=', 1 ], [ 'to_uid', '=', $id ] ] )
+ ->count();
+ $list2 = CardCount::where( [ [ 'type', '=', 'praise' ], [ 'type', '=', 3 ], [ 'to_uid', '=', $id ] ] )
+ ->count();
+ $list3 = CardCount::where( [ [ 'type', '=', 'copy' ], [ 'to_uid', '=', $id ] ] )
+ ->count();
+
+ $count = $list1 + $list2 + $list3;
+ $value[ 'charm' ] = $count;
+
+ // 客户互动值
+ $list1 = CardMessage::where( [ [ 'user_id', '=', $id ] ] )
+ ->count();
+ $list2 = CardMessage::where( [ [ 'target_id', '=', $id ] ] )
+ ->count();
+ $list3 = CardCount::where( [ [ 'type', '=', 'view' ], [ 'to_uid', '=', $id ] ] )
+ ->count();
+
+ $count = $list1 + $list2 + $list3;
+ $value[ 'interaction' ] = $count;
+
+ // 产品推广值
+ $list1 = CardExtension::where( [ [ 'user_id', '=', $id ] ] )
+ ->count();
+ $list2 = UserMark::where( [ [ 'staff_id', '=', $id ], [ 'mark', '=', 2 ] ] )
+ ->count();
+ $list3 = UserFollow::where( [ [ 'staff_id', '=', $id ] ] )
+ ->count();
+
+ $count = $list1 + $list2 + $list3;
+ $value[ 'product' ] = $count;
+
+ // 官网推广度
+ $list1 = CardCount::where( [ [ 'type', '=', 'view' ], [ 'to_uid', '=', $id ], [ 'type', '=', 6 ] ] )
+ ->count();
+ $list2 = CardForward::where( [ [ 'staff_id', '=', $id ], [ 'type', '=', 4 ] ] )
+ ->count();
+ $count = $list1 + $list2;
+ $value[ 'website' ] = $count;
+
+ // 销售主动性值
+ $list1 = CardMessage::where( [ [ 'user_id', '=', $id ] ] )
+ ->count();
+ $list2 = CardMessage::where( [ [ 'target_id', '=', $id ] ] )
+ ->count();
+ $list3 = UserFollow::where( [ [ 'staff_id', '=', $id ] ] )
+ ->count();
+ $list4 = UserMark::where( [ [ 'staff_id', '=', $id ] ] )
+ ->count();
+
+ $count = $list1 + $list2 + $list3 + $list4;
+ $value[ 'active' ] = $count;
+
+ $insertData = $value;
+ $insertData[ 'staff_id' ] = $id;
+ $time = time();
+ $insertData[ 'create_time' ] = $time;
+ $insertData[ 'update_time' ] = $time;
+ $insertData[ 'uniacid' ] = $uniacid;
+ if ( empty( $check ) )
+ {
+ CardValue::create( $insertData );
+ }
+ else
+ {
+ $updateData = $value;
+ $insertData[ 'update_time' ] = $time;
+ CardValue::update( $updateData, [ 'id' => $check[ 'id' ] ] );
+ }
+ }
+ else
+ {
+ $value = [ 'client' => $check[ 'client' ], // 获客能力值
+ 'charm' => $check[ 'charm' ], // 个人魅力值
+ 'interaction' => $check[ 'interaction' ], // 客户互动值
+ 'product' => $check[ 'product' ], // 产品推广值
+ 'website' => $check[ 'website' ], // 官网推广度
+ 'active' => $check[ 'active' ], // 销售主动性值
+ ];
+ }
+ $data = [ 'client' => [ 'titlle' => '获客能力值', 'value' => $value[ 'client' ] ],
+ 'charm' => [ 'titlle' => '个人魅力值', 'value' => $value[ 'charm' ] ],
+ 'interaction' => [ 'titlle' => '客户互动值', 'value' => $value[ 'interaction' ] ],
+ 'product' => [ 'titlle' => '产品推广值', 'value' => $value[ 'product' ] ],
+ 'website' => [ 'titlle' => '官网推广度', 'value' => $value[ 'website' ] ],
+ 'active' => [ 'titlle' => '销售主动性值', 'value' => $value[ 'active' ] ], ];
+ return $data;
+ }
+
+ /**
+ * @Purpose: 工具中心
+ *
+ * @Method: GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function toolCenter ()
+ {
+ $toolList = array( 0 => array( 'sign' => 'appoint', 'title' => '预约插件', 'desc' => '为客户提供上门服务预约、到店消费预约功能',
+ 'image' => 'https://retail.xiaochengxucms.com/%E9%A2%84%E7%BA%A6.png', ),
+ 1 => array( 'sign' => 'payqr', 'title' => '线下付款',
+ 'desc' => '让门店能精准抓取客户手机号,并反复的向客户发广告,最后达到二次、三次销售提升复购率的目地',
+ 'image' => 'https://retail.xiaochengxucms.com/%E6%94%AF%E4%BB%98.png', ),
+ 2 => array( 'sign' => 'article', 'title' => '获客文章',
+ 'desc' => '为员工提供高质量文章库,员工每天发送文章,吸引用户点击阅读。再通过寻客雷达精准提取意向客户,起到引流获客的作用',
+ 'image' => 'https://retail.xiaochengxucms.com/article.png', ),
+ 3 => array( 'sign' => 'activity', 'title' => '活动报名', 'desc' => '为企业提供营销活动、团建活动等各类活动报名和签到功能',
+ 'image' => 'https://retail.xiaochengxucms.com/activity.png', ), );
+
+ $payList = array();
+ $notPayList = array();
+
+
+ $exist = Db::query( 'show tables like "%longbing_card_config%"' );
+
+ $auth_info = false;
+
+ if ( !empty( $exist ) )
+ {
+ $auth_info = Db::name( 'longbing_cardauth2_config' )
+ ->where( [ [ 'modular_id', '=', $this->_uniacid ] ] )
+ ->find();
+ }
+
+ foreach ( $toolList as $key => $value )
+ {
+ $payed = false;
+ switch ( $value[ 'sign' ] )
+ {
+ case 'appoint':
+ $existTmp = Db::query( 'show tables like "%lb_appoint_record_check%"' );
+
+ if ( $existTmp )
+ {
+ $payed = true;
+ if ( $auth_info && isset( $auth_info[ 'appoint' ] ) && $auth_info[ 'appoint' ] == 0 )
+ {
+ $payed = false;
+ }
+ }
+ break;
+ case 'payqr':
+ $existTmp = Db::query( 'show tables like "%lb_pay_qr_config%"' );
+
+ if ( $existTmp )
+ {
+ $payed = true;
+ if ( $auth_info && isset( $auth_info[ 'payqr' ] ) && $auth_info[ 'payqr' ] == 0 )
+ {
+ $payed = false;
+ }
+ }
+ break;
+ case 'article':
+ $existTmp = Db::query( 'show tables like "%longbing_cardauth2_article%"' );
+
+ if ( $existTmp )
+ {
+ $articleAuthInfo = CardAuth2Article::where( [ [ 'modular_id', '=', $this->_uniacid ] ] )
+ ->find();
+ if ( $articleAuthInfo && isset( $articleAuthInfo[ 'number' ] ) && $articleAuthInfo[ 'number' ] > 0 )
+ {
+ $payed = true;
+ }
+ }
+
+ break;
+ case 'activity':
+ $existTmp = Db::query( 'show tables like "%longbing_cardauth2_activity%"' );
+ if ( $existTmp )
+ {
+ $activityAuthInfo = CardAuth2Activity::where( [ [ 'modular_id', '=', $this->_uniacid ] ] )
+ ->find();
+ if ( $activityAuthInfo && isset( $activityAuthInfo[ 'sign' ] ) && $activityAuthInfo[ 'sign' ] > time() )
+ {
+ $payed = true;
+ }
+ }
+
+ break;
+ default:
+ $payed = false;
+ }
+ if ( $payed )
+ {
+ array_push( $payList, $value );
+ }
+ else
+ {
+ array_push( $notPayList, $value );
+ }
+
+ }
+
+ return $this->success( [ 'payList' => $payList, 'notPayList' => $notPayList ] );
+ }
+
+ /**
+ * @Purpose: 公司列表
+ *
+ * @Method: GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function companyList ()
+ {
+ $topCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+ [ 'pid', '=', 0 ] ]
+ )
+ ->field( [ 'id', 'pid', 'name', 'addr', 'status' ] )
+ ->select()
+ ->toArray();
+
+ $sonCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+ [ 'pid', '<>', 0 ] ]
+ )
+ ->field( [ 'id', 'pid', 'name', 'addr', 'status' ] )
+ ->select()
+ ->toArray();
+
+ $companyList = $this->modelCompany->handleCompanyLevel( $topCompany, $sonCompany, 'children' );
+
+ return $this->success( $companyList );
+ }
+
+ /**
+ * @Purpose: 下架 / 上架 / 删除公司
+ *
+ * @Method: POST
+ *
+ * @Param:$company_id number 公司id
+ * @Param:$method number 操作类型 0 = 下架 1 = 上架 2 = 删除
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updateCompanyStatus ()
+ {
+ $verify = [ 'company_id' => 'required', 'method' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $result = $this->modelCompany->updateStatus( $params[ 'company_id' ], $params[ 'method' ] );
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 新增 / 编辑公司
+ *
+ * @Method: POST
+ *
+ * @Param:$company_id number 公司id 编辑公司信息是需要传入
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editCompany ()
+ {
+ // desc/shop_bg 商城背景图 culture/carousel 官网轮播图
+ $verify = [ 'company_id' => 0, 'name' => 'required', 'addr' => '', 'logo' => '', 'shop_bg' => '', 'shop_name' => '',
+ 'carousel' => '', 'longitude' => '', 'latitude' => '', 'auth_code' => '', 'short_name' => '', 'top' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $dataTmp = [ 'name' => $params[ 'name' ], 'addr' => $params[ 'addr' ], 'logo' => $params[ 'logo' ],
+ 'desc' => $params[ 'shop_bg' ], 'shop_name' => $params[ 'shop_name' ],
+ 'culture' => trim( implode( ',', $params[ 'carousel' ] ), ',' ), 'longitude' => $params[ 'longitude' ],
+ 'latitude' => $params[ 'latitude' ], 'auth_code' => $params[ 'auth_code' ],
+ 'short_name' => $params[ 'short_name' ], 'top' => $params[ 'top' ] ];
+
+ // 编辑公司
+ if ( $params[ 'company_id' ] )
+ {
+ $company_id = $params[ 'company_id' ];
+ unset( $params[ 'company_id' ] );
+
+ $result = $this->modelCompany->update( $dataTmp, [ 'id' => $company_id ]
+ );
+
+ unset( $dataTmp[ 'name' ] );
+ $this->modelCompany->updateSonCompanyInfo( $company_id, $dataTmp );
+ }
+ // 新增公司
+ else
+ {
+ $dataTmp[ 'uniacid' ] = $this->_uniacid;
+ $result = $this->modelCompany->create( $dataTmp );
+ }
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [ 'operation success' ] );
+ }
+
+ /**
+ * @Purpose: 公司信息
+ *
+ * @Method: GET
+ *
+ * @Param:$company_id number 公司id 编辑公司信息是需要传入
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function companyInfo ()
+ {
+ // desc/shop_bg 商城背景图 culture/carousel 官网轮播图
+ $verify = [ 'company_id' => 'require' ];
+
+ $params = lbGetParamVerify( $this->_param, $verify );
+
+ $company = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+ [ 'id', '=', $params[ 'company_id' ] ] ]
+ )
+ ->find();
+
+
+ if ( !$company )
+ {
+ return $this->error( 'company not fount' );
+ }
+
+ $company = $company->toArray();
+
+ $company = transImages( $company, [ 'logo', 'desc', 'culture' ] );
+ $company[ 'shop_bg' ] = $company[ 'desc' ];
+ $company[ 'carousel' ] = $company[ 'culture' ];
+
+ return $this->success( $company );
+ }
+
+ /**
+ * @Purpose: 新增 / 编辑 部门信息
+ *
+ * @Method: POST
+ *
+ * @Param:$company_id number 公司id 编辑公司信息是需要传入
+ * @Param:$name string 部门名
+ * @Param:$method method 操作类型 1 = 新增部门 2 = 修改部门
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editDepartment ()
+ {
+ $verify = [ 'company_id' => 'require', 'name' => 'require', 'method' => 1 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $company_id = $params[ 'company_id' ];
+ // 新增部门
+ if ( $params[ 'method' ] == 1 )
+ {
+ $comapny = $this->modelCompany->where( [ [ 'id', '=', $company_id ] ] )
+ ->find();
+
+ if ( !$comapny )
+ {
+ return $this->error( 'company not found' );
+ }
+
+ $company = $comapny->toArray();
+ unset( $company[ 'id' ] );
+ unset( $company[ 'create_time' ] );
+ unset( $company[ 'update_time' ] );
+ $company[ 'name' ] = $params[ 'name' ];
+
+ $company[ 'pid' ] = $company_id;
+ $company[ 'status' ] = 1;
+
+ $key = 'CARD_AUTH_COMPANY_';
+ $value = getCache( $key, $this->_uniacid );
+
+ if ( !$value && false )
+ {
+ $company[ 'pid' ] = 0;
+ }
+ $company[ 'uniacid' ] = $this->_uniacid;
+
+ $result = $this->modelCompany->create( $company );
+ }
+ // 修改部门
+ else if ( $params[ 'method' ] == 2 )
+ {
+
+ $result = $this->modelCompany->update( [ 'name' => $params[ 'name' ] ], [ 'id' => $company_id ] );
+ }
+ else
+ {
+ return $this->error( 'method failed' );
+ }
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [ 'operation success' ] );
+ }
+
+ /**
+ * @Purpose: 职位列表
+ *
+ * @Method: GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function position ()
+ {
+ $page = isset( $this->_param[ 'page' ] ) ? $this->_param[ 'page' ] : 1;
+ $limit = isset( $this->_param[ 'limit' ] ) ? $this->_param[ 'limit' ] : 10;
+ $keyword = isset( $this->_param[ 'keyword' ] ) ? $this->_param[ 'keyword' ] : '';
+
+ $where = [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ] ];
+
+ if ( $keyword )
+ {
+ $where[] = [ 'name', 'like', "%{$keyword}%" ];
+ }
+
+ $data = CardJob::where( $where )
+ ->order( 'top', 'desc' )
+ ->paginate( [ 'list_rows' => $limit, 'page' => $page ]
+ )
+ ->toArray();
+
+ $data[ 'data' ] = handleTimes( $data[ 'data' ], 'create_time', 'Y-m-d H:i:s' );
+
+ $data[ 'keyword' ] = $keyword;
+
+ return $this->success( $data );
+ }
+
+ /**
+ * @Purpose: 下架 / 上架 / 删除职位
+ *
+ * @Method: POST
+ *
+ * @Param:$job_id number 职位id
+ * @Param:$method number 操作类型 0 = 下架 1 = 上架 2 = 删除
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updatePositionStatus ()
+ {
+ $verify = [ 'id' => 'required', 'method' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ switch ( $params[ 'method' ] )
+ {
+ case 0:
+ $result = CardJob::update( [ 'status' => 0 ], [ 'id' => $params[ 'id' ] ] );
+ break;
+ case 1:
+ $result = CardJob::update( [ 'status' => 1 ], [ 'id' => $params[ 'id' ] ] );
+ break;
+ case 2:
+ $result = CardJob::update( [ 'status' => -1 ], [ 'id' => $params[ 'id' ] ] );
+ break;
+ default:
+ return $this->error( 'method failed' );
+ }
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 编辑职位
+ *
+ * @Method: POST
+ *
+ * @Param:$job_id number 职位id
+ * @Param:$name string 职位名
+ * @Param:$top number 排序值
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editPosition ()
+ {
+ $verify = [ 'job_id' => 0, 'name' => 'required', 'top' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ if ( $params[ 'job_id' ] )
+ {
+ $result = CardJob::update( [ 'name' => $params[ 'name' ], 'top' => $params[ 'top' ] ], [ 'id' => $params[ 'job_id' ] ]
+ );
+ }
+ else
+ {
+ $result = CardJob::create( [ 'name' => $params[ 'name' ], 'top' => $params[ 'top' ], 'uniacid' => $this->_uniacid ] );
+ }
+
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 员工列表
+ *
+ * @Method: GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function staffs ()
+ {
+ $page = isset( $this->_param[ 'page' ] ) ? $this->_param[ 'page' ] : 1;
+ $limit = isset( $this->_param[ 'limit' ] ) ? $this->_param[ 'limit' ] : 10;
+ $keyword = isset( $this->_param[ 'keyword' ] ) ? $this->_param[ 'keyword' ] : '';
+
+ $where[] = [ 'a.uniacid', '=', $this->_uniacid ];
+ $where[] = [ 'a.is_staff', '=', 1 ];
+
+ if ( $keyword )
+ {
+ $where2 = $where;
+ $tmp = '%' . $keyword . '%';
+ $where[] = [ 'b.name', 'like', $tmp ];
+ $where2[] = [ 'a.nickName', 'like', $tmp ];
+
+ $data = User::alias( 'a' )
+ ->field( [ 'b.id as card_id', 'b.name', 'b.avatar', 'b.job_id', 'b.company_id', 'b.phone',
+ 'b.create_time', 'a.nickName', 'a.avatarUrl', 'a.is_staff', 'a.is_boss',
+ 'c.name as job_name', 'a.qr_path', 'b.is_default', 'a.id' ]
+ )
+ ->join( 'longbing_card_user_info b', 'b.fans_id = a.id' )
+ ->join( 'longbing_card_job c', 'b.job_id = c.id', 'LEFT' )
+ ->whereOr( [ $where, $where2 ] )
+ ->order( [ 'a.is_boss' => 'desc', 'a.update_time' => 'desc', 'a.id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => $limit, 'page' => $page ] )
+ ->toArray();
+
+ }
+ else
+ {
+ $data = User::alias( 'a' )
+ ->field( [ 'b.id as card_id', 'b.name', 'b.avatar', 'b.job_id', 'b.company_id', 'b.phone',
+ 'b.create_time', 'a.nickName', 'a.avatarUrl', 'a.is_staff', 'a.is_boss',
+ 'c.name as job_name', 'a.qr_path', 'b.is_default', 'a.id' ]
+ )
+ ->join( 'longbing_card_user_info b', 'b.fans_id = a.id' )
+ ->join( 'longbing_card_job c', 'b.job_id = c.id', 'LEFT' )
+ ->where( $where )
+ ->order( [ 'a.is_boss' => 'desc', 'a.is_staff' => 'desc', 'a.update_time' => 'desc', 'a.id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => $limit, 'page' => $page ] )
+ ->toArray();
+ }
+
+ foreach ( $data[ 'data' ] as $index => $item )
+ {
+ if ( !$item[ 'name' ] && $item[ 'nickName' ] )
+ {
+ $data[ 'data' ][ $index ][ 'name' ] = $item[ 'nickName' ];
+ }
+ // 获取公司名,部门名
+ list ( $data[ 'data' ][ $index ][ 'companyName' ], $data[ 'data' ][ $index ][ 'departmentName' ]
+ ) = $this->modelCompany->getCompanyAndDepartmentName( $item[ 'company_id' ] );
+ }
+
+
+ $data[ 'data' ] = transImagesOne( $data[ 'data' ], [ 'avatar', 'qr_path' ] );
+ $data[ 'data' ] = handleImagesWe7Local( $data[ 'data' ], [ 'avatar' ] );
+
+ $data[ 'data' ] = handleTimes( $data[ 'data' ] );
+
+ return $this->success( $data );
+ }
+
+
+ /**
+ * @param $str
+ * @return string|string[]|null
+ * 过滤表情包
+ */
+ public function filterEmoji($str)
+ {
+ $str = preg_replace_callback(
+ '/./u',
+ function (array $match) {
+ return strlen($match[0]) >= 4 ? '' : $match[0];
+ },
+ $str);
+
+ return $str;
+ }
+
+ /**
+ * @Purpose: 员工列表
+ *
+ * @Method: GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function users ()
+ {
+
+
+
+ $page = isset( $this->_param[ 'page' ] ) ? $this->_param[ 'page' ] : 1;
+ $limit = isset( $this->_param[ 'limit' ] ) ? $this->_param[ 'limit' ] : 10;
+ $keyword = isset( $this->_param[ 'keyword' ] ) ? $this->_param[ 'keyword' ] : '';
+ $type = isset( $this->_param[ 'type' ] ) ? $this->_param[ 'type' ] : '';
+
+ $is_default = isset( $this->_param[ 'is_default' ] ) ? $this->_param[ 'is_default' ] : '';
+
+ $where = [ [ 'a.uniacid', '=', $this->_uniacid ] ];
+
+ if(in_array($type, [1 ,'1'])) $where[] = ['a.is_staff' ,'=' ,1];
+
+ if(in_array($type, [2 ,'2'])) $where[] = ['a.is_staff' ,'=' ,0];
+
+
+ //是否推荐
+ if($is_default != 2 ) {
+ //兼容 有些是空
+ if($is_default==0){
+
+ $where[] = ['b.is_default' , '<>' , 1];
+ }else{
+ $where[] = ['b.is_default' , '=' , $is_default];
+ }
+ }
+
+ if ( $keyword )
+ {
+ $keyword = $this->filterEmoji($keyword);
+ $where2 = $where;
+ $tmp = '%' . $keyword . '%';
+ $where[] = [ 'b.name', 'like', $tmp ];
+ $where2[] = [ 'a.nickName', 'like', $tmp ];
+
+ $data = User::alias( 'a' )
+ ->field( [ 'b.id as card_id', 'b.name', 'b.avatar', 'b.job_id', 'b.company_id', 'b.phone',
+ 'b.create_time', 'a.nickName', 'a.avatarUrl', 'a.is_staff', 'a.is_boss',
+ 'c.name as job_name', 'a.qr_path', 'b.is_default', 'a.id','a.import','b.top' ]
+ )
+ ->join( 'longbing_card_user_info b', 'b.fans_id = a.id' ,'LEFT')
+ ->join( 'longbing_card_job c', 'b.job_id = c.id', 'LEFT' )
+ ->whereOr( [ $where, $where2 ] )
+ ->order( [ 'a.is_boss' => 'desc','b.top'=>'desc', 'a.update_time' => 'desc', 'a.id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => $limit, 'page' => $page ] )
+ ->toArray();
+
+ }
+ else
+ {
+
+// dump($where);exit;
+
+ $data = User::alias( 'a' )
+ ->field( [ 'b.id as card_id', 'b.name', 'b.avatar', 'b.job_id', 'b.company_id', 'b.phone',
+ 'b.create_time', 'a.nickName', 'a.avatarUrl', 'a.is_staff', 'a.is_boss',
+ 'c.name as job_name', 'a.qr_path', 'b.is_default', 'a.id' ,'a.import','b.top']
+ )
+ ->join( 'longbing_card_user_info b', 'b.fans_id = a.id' ,'LEFT')
+ ->join( 'longbing_card_job c', 'b.job_id = c.id', 'LEFT' )
+ ->where( $where )
+ ->order( [ 'a.is_boss' => 'desc', 'a.is_staff' => 'desc', 'b.top'=>'desc','a.update_time' => 'desc', 'a.id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => $limit, 'page' => $page ] )
+ ->toArray();
+ }
+
+ foreach ( $data[ 'data' ] as $index => $item )
+ {
+ if ( !$item[ 'name' ] && $item[ 'nickName' ] )
+ {
+ $data[ 'data' ][ $index ][ 'name' ] = $item[ 'nickName' ];
+ }
+ // 获取公司名,部门名
+ list ( $data[ 'data' ][ $index ][ 'companyName' ], $data[ 'data' ][ $index ][ 'departmentName' ]
+ ) = $this->modelCompany->getCompanyAndDepartmentName( $item[ 'company_id' ] );
+ }
+ foreach($data[ 'data' ] as $key => $val)
+ {
+
+ if(!empty($val['avatar'])&&$val['avatar']) $data[ 'data' ][$key]['avatarUrl'] = $val['avatar'];
+
+ if(empty($data[ 'data' ][$key]['avatarUrl'])) $data[ 'data' ][$key]['avatarUrl'] = "https://retail.xiaochengxucms.com/defaultAvatar.png";
+ }
+
+ $data[ 'data' ] = transImagesOne( $data[ 'data' ], [ 'avatar', 'avatarUrl', 'qr_path' ] );
+ $data[ 'data' ] = handleImagesWe7Local( $data[ 'data' ], [ 'avatar' ] );
+
+ $data[ 'data' ] = handleTimes( $data[ 'data' ] );
+
+ return $this->success( $data );
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-14 14:23
+ * @功能说明:
+ */
+ public function cardExcel(){
+
+ $post = $this->_param;
+
+
+ $keyword = !empty($post[ 'keyword' ])?$post[ 'keyword' ]:'' ;
+
+ $user_model = new User();
+
+ $where[] = ['a.uniacid','=',$this->_uniacid];
+
+ $where[] = ['b.is_staff','=',1];
+
+ //搜索名字
+ $where2 = [];
+
+ if(!empty($keyword)){
+
+ $keyword = $this->filterEmoji($keyword);
+
+ $tmp = '%' . $keyword . '%';
+
+ $where2[] = [ 'b.name', 'like', $tmp ];
+
+ $where2[] = [ 'a.nickName', 'like', $tmp ];
+ }
+
+ if(!empty($post['company'])){
+
+ $post['company'] = explode(',',$post['company']);
+
+ $where[] = ['b.company_id' , 'IN' , $post['company']];
+
+ }
+ if($post['date_type']==0){
+
+ $start_time = 0;
+
+ $end_time = 0;
+
+ if(!empty($post['range'])&&$post['range']!='null'){
+
+ $post['range'] = explode(',',$post['range']);
+
+ $start_time = strtotime($post['range'][0]);
+
+ $end_time = strtotime($post['range'][1])+86400-1;
+
+ }
+
+ if(!empty($end_time)){
+
+ $where[] = ['b.create_time','<',$end_time];
+ }
+
+ }else{
+
+ $start_time = strtotime(date('Y-m-d',time()));
+
+ $end_time = $start_time+86400-1;
+
+ if(!empty($post['time'])&&$post['time']!='null'){
+
+ $start_time = strtotime($post['time']);
+
+ $end_time = strtotime($post['time'])+86400-1;
+
+ }
+ $where[] = ['b.create_time','<',$end_time];
+ }
+
+ $data = $user_model->cardExcel($where,$where2,$post['date_type'],$start_time,$end_time);
+
+ return $this->success( $data );
+
+ }
+
+ /**
+ * @Purpose: 取消员工名片
+ *
+ * @Method: POST
+ *
+ * @Param: $method number 操作类型 1 => 取消名片 2 = 取消boss 3 = 取消推荐
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function cancelStaff ()
+ {
+
+
+ //By.jingshuixian
+ //校验必须要设置一张名片并推荐名片
+// if(UserService::getDefaultStraffNumber($this->_uniacid) == 1 ){
+// return $this->error( 'At least one staff is required' );
+// }
+
+ //获取数据
+ $verify = [ 'staff_id' => 'required', 'method' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+
+ //获取员工信息
+ $info = User::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'id', '=', $params[ 'staff_id' ] ], [ 'is_staff', '=', 1 ] ]
+ )
+ ->find();
+ //判断员工是否存在
+ if ( !$info )
+ {
+ return $this->error( 'staff info not found' );
+ }
+
+ $is_d = Db::name('longbing_card_user_info')->where(['fans_id'=>$params[ 'staff_id' ]])->value('is_default');
+ if(!empty($params[ 'method' ])&&$params[ 'method' ]!=2){
+ if(UserService::getDefaultStraffNumber($this->_uniacid) == 1&&$is_d==1 ){
+ return $this->error( 'At least one staff is required' );
+ }
+ }
+
+ //操作
+ switch ( $params[ 'method' ] )
+ {
+ //取消名片
+ case 1:
+ $data = User::update( [ 'is_staff' => 0, 'is_boss' => 0 ], [ 'id' => $params[ 'staff_id' ] ] );
+ if(!empty($data)) {
+ $data = UserInfo::update( [ 'is_staff' => 0, 'is_default' => 0 ,'is_boss' => 0], [ 'fans_id' => $params[ 'staff_id' ] ] );
+
+ User::update( [ 'is_boss' => 0 ], [ 'id' => $params[ 'staff_id' ] ] );
+ }
+ if(!empty($data))
+ {
+ CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )->delete();
+ longbingGetCardNum($this->_uniacid ,true);
+ longbingGetBossNum($this->_uniacid ,true);
+ }
+
+ break;
+ //取消boss权限
+ case 2:
+ $data = User::update( [ 'is_boss' => 0 ], [ 'id' => $params[ 'staff_id' ] ] );
+ if(!empty($data))
+ {
+// CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )->delete();
+ longbingGetBossNum($this->_uniacid ,true);
+ }
+ break;
+ //取消推荐
+ case 3:
+ UserInfo::update( [ 'is_default' => 0 ], [ 'fans_id' => $params[ 'staff_id' ] ] );
+ break;
+ default:
+ return $this->error( 'method error' );
+ }
+ longbingGetUser($params[ 'staff_id' ] ,$this->_uniacid ,true);
+ longbingGetUserInfo($params[ 'staff_id' ] ,$this->_uniacid ,true);
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 设置员工名片
+ *
+ * @Method: POST
+ *
+ * @Param: $method number 操作类型 1 => 设置名片 2 = 设置boss 3 = 设置推荐
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function setStaff ()
+ {
+ $verify = [ 'staff_id' => 'required', 'method' => 0 ];
+
+ $params = lbGetParamVerify( $this->_param, $verify );
+
+ $info = User::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'id', '=', $params[ 'staff_id' ] ] ] )
+ ->find();
+
+ if ( !$info )
+ {
+ return $this->error( 'staff info not found' );
+ }
+ $user_info = longbingGetUserInfo($params['staff_id'] ,$this->_uniacid);
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+ switch ( $params[ 'method' ] )
+ {
+ case 1:
+ //检查名片数量是否超标
+ if(empty($info['is_staff']) && !empty($permissions) && isset($permissions['card_number']) && !empty($permissions['card_number']))
+ {
+ if(!(longbingGetCardNum($this->_uniacid) < $permissions['card_number']))
+ {
+ return $this->error(lang('not card num'));
+ }
+ }
+ //修改信息
+ $data = User::update( [ 'is_staff' => 1 ], [ 'id' => $params[ 'staff_id' ] ] );
+ if(!empty($data)) UserInfo::update( [ 'is_staff' => 1 ], [ 'fans_id' => $params[ 'staff_id' ] ] );
+ longbingGetCardNum($this->_uniacid ,true);
+ break;
+ case 2:
+ if ( empty($info[ 'is_staff' ]) )
+ {
+ return $this->error( 'need set card first' );
+ }
+ //检查名片数量是否超标
+ if(empty($info['is_boss']) && !empty($permissions) && isset($permissions['boss_num']) && !empty($permissions['boss_num']))
+ {
+ if(!(longbingGetBossNum($this->_uniacid) < $permissions['boss_num']))
+ {
+ return $this->error(lang('not boss num'));
+ }
+ }
+ User::update( [ 'is_boss' => 1 ], [ 'id' => $params[ 'staff_id' ] ] );
+ longbingGetBossNum($this->_uniacid ,true);
+ break;
+ case 3:
+ if ( $info[ 'is_staff' ] != 1 )
+ {
+ return $this->error( 'need set card first' );
+ }
+ //获取最小auto_count
+ $count = longbingGetUserInfoMinAutoCount($this->_uniacid);
+ UserInfo::update( [ 'is_default' => 1 ,'auto_count' => $count], [ 'fans_id' => $params[ 'staff_id']]);
+ break;
+ default:
+ return $this->error( 'method error' );
+ }
+ longbingGetUser($params[ 'staff_id' ] ,$this->_uniacid ,true);
+ longbingGetUserInfo($params[ 'staff_id' ] ,$this->_uniacid ,true);
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 编辑员工名片回显数据
+ *
+ * @Method: GET
+ *
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function staffInfo ()
+ {
+ //判断是否拥有分公司的boss权限
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+
+ $verify = [ 'staff_id' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_param, $verify );
+
+ $info = UserInfo::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'fans_id', '=', $params[ 'staff_id' ] ] ] )
+ ->find();
+
+ if ( !$info )
+ {
+ return $this->error( lang('staff info not found') );
+ }
+
+ $info = $info->toArray();
+// if(empty($info['avatar']))
+// {
+// $user = longbingGetUser($params['staff_id'] ,$this->_uniacid);
+// if(!empty($user)) $info['avatar'] = $user['avatarUrl'];
+// if(empty($info['avatar'])) $info['avatar'] = "https://retail.xiaochengxucms.com/defaultAvatar.png";
+// }
+ // 处理图片
+ $info = transImages( $info, [ 'images' ], ',' );
+ $info = transImagesOne( $info, [ 'avatar', 'voice', 'my_url', 'my_video', 'my_video_cover', 'bg', 'vr_cover', 'vr_path' ] ,$this->_uniacid);
+
+ $jobs = CardJob::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '=', 1 ] ] )
+ ->field( [ 'id', 'name' ] )
+ ->order( [ 'top' => 'desc' ] )
+ ->select()
+ ->toArray();
+
+ foreach ( $jobs as $index => $item )
+ {
+ $jobs[ $index ][ 'selected' ] = 0;
+ if ( $item[ 'id' ] == $info[ 'job_id' ] )
+ {
+ $jobs[ $index ][ 'selected' ] = 1;
+ $info[ 'job_name' ] = $jobs[ $index ]['name'];
+ }
+ }
+ if(!isset($info[ 'job_name' ])) $info[ 'job_name' ] = lang('not set job');
+
+ $companyCheck = CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )
+ ->find();
+ $info['company_ids'] = longbingGetUpCompanyIds($info['company_id']);
+ $boss_permission = true;
+ if(empty($permissions) || !isset($permissions['plugin']) || !isset($permissions['plugin']['boss']) || empty($permissions['plugin']['boss']))
+ {
+ $boss_permission = false;
+ }
+ //顶级公司列表
+ $topCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ],
+ [ 'status', '>', -1 ],
+ [ 'pid', '=', 0 ]
+ ])
+ ->field( [ 'id', 'pid', 'name', 'addr', 'status' ,'top_id'] )
+ ->select()
+ ->toArray();
+
+ $sonCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ],
+ [ 'status', '>', -1 ],
+ [ 'pid', '<>', 0 ]
+ ])
+ ->field( [ 'id', 'pid', 'name', 'addr', 'status' ,'top_id'] )
+ ->select()
+ ->toArray();
+
+ if ( !empty($companyCheck) && $boss_permission)
+ {
+ $companyCheck = explode( ',', $companyCheck['boss'] );
+ foreach($topCompany as $key => $val)
+ {
+ $topCompany[$key]['selected'] = 0;
+ if(in_array($val['id'], $companyCheck)) $topCompany[$key]['selected'] = 1;
+ }
+ foreach($sonCompany as $key => $val)
+ {
+ $sonCompany[$key]['selected'] = 0;
+ if(in_array($val['id'], $companyCheck)) $sonCompany[$key]['selected'] = 1;
+ }
+ }
+ $company = $this->modelCompany->handleCompanyLevel( $topCompany, $sonCompany, 'children' );
+// if ( !empty($companyCheck) && $boss_permission)
+// {
+// $companyCheck = explode( ',', $companyCheck['boss'] );
+//
+//// $company = $this->modelCompany->where( [ [ 'id', 'in', $companyCheck ], [ 'status', '=', 1 ] ,['pid' , '=', 0]] )
+// $company = $this->modelCompany->where( [ [ 'id', 'in', $companyCheck ], [ 'status', '=', 1 ]] )
+// ->field( [ 'id', 'name' ] )
+// ->select()
+// ->toArray();
+// }
+
+// else
+// {
+// $topCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+// [ 'pid', '=', 0 ] ]
+// )
+// ->field( [ 'id', 'pid', 'name', 'addr', 'status' ] )
+// ->select()
+// ->toArray();
+//
+// $sonCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+// [ 'pid', '<>', 0 ] ]
+// )
+// ->field( [ 'id', 'pid', 'name', 'addr', 'status' ] )
+// ->select()
+// ->toArray();
+//
+// $company = $this->modelCompany->handleCompanyLevel( $topCompany, $sonCompany, 'children' );
+//// $company = [];
+// }
+
+
+// foreach ( $company as $index => $item )
+// {
+// $company[ $index ][ 'selected' ] = 0;
+// if ( $item[ 'id' ] == $info[ 'company_id' ] )
+// {
+// $company[ $index ][ 'selected' ] = 1;
+// $info[ 'company_name' ] = $company[ $index ]['name'];
+// }
+// }
+// if(!isset($info[ 'company_name' ])) $info[ 'company_name' ] = lang('not set company');
+ $info[ 'job_list' ] = $jobs;
+ $info[ 'company_list' ] = $company;
+ //字符替换
+ $info['desc'] = str_replace(" "," ",$info['desc']);
+ $info['boss_permission'] = $boss_permission;
+ return $this->success( $info );
+ }
+
+ /**
+ * @Purpose: 编辑员工名片
+ *
+ * @Method: POST
+ *
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editStaff ()
+ {
+ //获取数据
+ $verify = [ 'staff_id' => 'required', 'name' => 'required', 'avatar' => '', 'job_id' => 'required',
+ 'company_id' => 'required', 'phone' => '', 'wechat' => '', 'telephone' => '', 'phone400' => '', 'email' => '',
+ 'share_text' => '', 'voice' => '', 'voice_time' => 0, 'desc' => '', 'my_video' => '', 'my_video_cover' => '',
+ 'images' => '', 'my_url' => '', 'view_number' => '', 't_number' => '', 'ww_account' => '', 'bg' => '',
+ 'bg_switch' => 0, 'vr_tittle' => '', 'vr_cover' => '', 'vr_path' => '', 'vr_switch' => '' ,'from_company_ids' => '','top'=>''];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+// dump($params);exit;
+ //获取所属公司列表
+ $company_list = $params['from_company_ids'];
+ unset($params['company_list']);
+ //获取权限信息
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+ //检查权限
+ if(empty($permissions) || !isset($permissions['plugin']) || !isset($permissions['plugin']['boss']) || empty($permissions['plugin']['boss']))
+ {
+ CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )
+ ->delete();
+ }else{
+ //检查所属公司是否存在
+ if(empty($company_list)) return $this->error(lang('not from company'));
+ //检查公司是否在所属公司中
+ if(!in_array($params['company_id'], $company_list)) return $this->error('not set company');
+ CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )
+ ->delete();
+ $boss = implode( ',', $company_list );
+ $result = CardBoss::create( [ 'user_id' => $params[ 'staff_id' ], 'boss' => $boss, 'uniacid' => $this->_uniacid ] );
+ if(empty($result)) return $this->error(lang('chage card error'));
+ }
+ if ( is_array( $params[ 'images' ] ) && !empty( $params[ 'images' ] ) )
+ {
+ $params[ 'images' ] = implode( ',', $params[ 'images' ] );
+ }else{
+ $params[ 'images' ] = '';
+ }
+ if ( is_array( $params[ 'avatar' ] ) && !empty( $params[ 'avatar' ] ) )
+ {
+ $params[ 'avatar' ] = implode( ',', $params[ 'avatar' ] );
+ }
+
+ if ( is_array( $params[ 'my_video_cover' ] ) && !empty( $params[ 'my_video_cover' ] ) )
+ {
+ $params[ 'my_video_cover' ] = implode( ',', $params[ 'my_video_cover' ] );
+ }else{
+ $params[ 'my_video_cover' ] = '';
+ }
+
+ if ( is_array( $params[ 'vr_cover' ] ) && !empty( $params[ 'vr_cover' ] ) )
+ {
+ $params[ 'vr_cover' ] = implode( ',', $params[ 'vr_cover' ] );
+ }else{
+ $params[ 'vr_cover' ] = '';
+ }
+
+ $staff_id = $params[ 'staff_id' ];
+ unset( $params[ 'staff_id' ] );
+
+ $result = UserInfo::update( $params, [ 'fans_id' => $staff_id ] );
+
+ if ( $result === false )
+ {
+ return $this->error( 'edit failed' );
+ }
+
+ UserService::createHeaderQr( $this->_uniacid ,['staff_id'=> $staff_id ]);
+
+ longbingGetUserInfo($staff_id ,$this->_uniacid ,true);
+ //清除名片缓存
+ $key = 'longbing_card_card_info_' . $staff_id;
+ delCache($key ,$this->_uniacid);
+
+ return $this->success([]);
+ }
+
+ /**
+ * @Purpose: 分配BOSS权限回显数据
+ *
+ * @Method: GET
+ *
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function authBossInfo ()
+ {
+ //判断是否拥有分公司的boss权限
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+
+ if(empty($permissions) || !isset($permissions['plugin']) || !isset($permissions['plugin']['boss']) || empty($permissions['plugin']['boss']))
+ {
+ return $this->success([]);
+ }
+ $verify = [ 'staff_id' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_param, $verify );
+
+ $authInfo = CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )
+ ->find();
+
+ $authArr = [];
+ if ( $authInfo )
+ {
+ $authArr = explode( ',', $authInfo[ 'boss' ] );
+ }
+
+ $topCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+ [ 'pid', '=', 0 ] ]
+ )
+ ->field( [ 'id', 'pid', 'name', 'addr', 'status' ] )
+ ->select()
+ ->toArray();
+
+ $sonCompany = $this->modelCompany->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '>', -1 ],
+ [ 'pid', '<>', 0 ] ]
+ )
+ ->field( [ 'id', 'pid', 'name', 'addr', 'status' ] )
+ ->select()
+ ->toArray();
+
+ foreach ( $topCompany as $index => $item )
+ {
+ $topCompany[ $index ][ 'selected' ] = 0;
+ if ( in_array( $item[ 'id' ], $authArr ) )
+ {
+ $topCompany[ $index ][ 'selected' ] = 1;
+ }
+ }
+
+ foreach ( $sonCompany as $index => $item )
+ {
+ $sonCompany[ $index ][ 'selected' ] = 0;
+ if ( in_array( $item[ 'id' ], $authArr ) )
+ {
+ $sonCompany[ $index ][ 'selected' ] = 1;
+ }
+ }
+
+ $company = $this->modelCompany->handleCompanyLevel( $topCompany, $sonCompany, 'children' );
+
+ return $this->success( $company );
+
+ }
+
+ /**
+ * @Purpose: 分配BOSS权限
+ *
+ * @Method: POST
+ *
+ * @Param: $staff_id number 员工id
+ * @Param: $company_ids array 公司ID组成的数组
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editAuthBoss ()
+ {
+ $verify = [ 'staff_id' => 'required', 'company_ids' => '' ];
+ //获取数据
+ $params = lbGetParamVerify( $this->_input, $verify );
+ //检查数据是否存在
+
+ $userService = new UserService() ;
+
+ $result = $userService->addUserToStaff($params['staff_id'] , $params['company_ids'] , $this->_uniacid) ;
+
+ if(is_string($result)){
+ return $this->error( $result );
+ }
+
+ return $this->success( $result );
+
+ }
+
+ /**
+ * @Purpose: 生成名片码
+ *
+ * @Method: POST
+ *
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function createStaffQr ()
+ {
+
+ $verify = [ 'staff_id' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $result = UserService::createHeaderQr($this->_uniacid ,$params );
+
+ if(is_string($result)){
+
+ return $this->error($result);
+ }
+ //返回数据
+ return $this->success( ['src' => $result['qr_path']]);
+ }
+
+ /**
+ * @Purpose: 印象标签列表
+ *
+ * @Method: GET
+ *
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function tags ()
+ {
+ $page = isset( $this->_param[ 'page' ] ) ? $this->_param[ 'page' ] : 1;
+ $limit = isset( $this->_param[ 'limit' ] ) ? $this->_param[ 'limit' ] : 10;
+
+ $data = CardTags::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'user_id', '=', 0 ], [ 'status', '>', -1 ] ] )
+ ->order( [ 'top' => 'desc', 'id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => $limit, 'page' => $page ] )
+ ->toArray();
+
+ $data[ 'data' ] = handleTimes( $data[ 'data' ] );
+
+ return $this->success( $data );
+ }
+
+ /**
+ * @Purpose: 下架 / 上架 / 删除印象标签
+ *
+ * @Method: POST
+ *
+ * @Param:$id number 标签id
+ * @Param:$method number 操作类型 0 = 下架 1 = 上架 2 = 删除
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updateTagStatus ()
+ {
+ $verify = [ 'id' => 'required', 'method' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ switch ( $params[ 'method' ] )
+ {
+ case 0:
+ $result = CardTags::update( [ 'status' => 0 ], [ 'id' => $params[ 'id' ] ] );
+ break;
+ case 1:
+ $result = CardTags::update( [ 'status' => 1 ], [ 'id' => $params[ 'id' ] ] );
+ break;
+ case 2:
+ $result = CardTags::update( [ 'status' => -1 ], [ 'id' => $params[ 'id' ] ] );
+ break;
+ default:
+ return $this->error( 'method failed' );
+ }
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 新增 / 编辑标签
+ *
+ * @Method: POST
+ *
+ * @Param:$id number 标签id
+ * @Param:$name string 标签名
+ * @Param:$top number 排序值
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editTag ()
+ {
+ $this->_input['name'] = trim( $this->_input['name'] );
+
+ $verify = [ 'id' => 0, 'name' => 'required', 'top' => 0 ];
+
+ if(!$this->_input['name']){
+ return $this->error('请填写标签名');
+ }
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ if ( $params[ 'id' ] )
+ {
+ $tag_model = new CardTags();
+ $count = $tag_model->getTagCount([ ['id' , '<>', $params[ 'id' ] ] , [ 'tag' , '=' , $params['name'] ], [ 'uniacid' , '=',$this->_uniacid ], ['status' , '=',1], ['user_id' ,'=', 0]]);
+ if (!empty($count)) return $this->error(lang('tag is exist'));
+
+ $result = CardTags::update( [ 'tag' => $params[ 'name' ], 'top' => $params[ 'top' ] ], [ 'id' => $params[ 'id' ] ]);
+ }
+ else {
+ $tag_model = new CardTags();
+ $count = $tag_model->getTagCount(['tag' => $params['name'], 'uniacid' => $this->_uniacid, 'status' => 1, 'user_id' => 0]);
+ if (!empty($count)) return $this->error(lang('tag is exist'));
+ $result = CardTags::create(['tag' => $params['name'], 'top' => $params['top'], 'uniacid' => $this->_uniacid, 'user_id' => 0]);
+ }
+
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 免审口令
+ *
+ * @Method: POST
+ *
+ * @Param:$action string 操作类型 edit = 修改 其他 = 回显数据
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function authCode ()
+ {
+
+ $config = $this->modelConfig->getConfig( $this->_uniacid );
+
+ if ( $this->_input[ 'action' ] !== 'edit' )
+ {
+ return $this->success( [ 'code' => $config[ 'code' ], 'btn_code_err' => $config[ 'btn_code_err' ],
+ 'btn_code_miss' => $config[ 'btn_code_miss' ] ]
+ );
+ }
+ else
+ {
+
+ $verify = [ 'code' => '', 'btn_code_err' => 'required', 'btn_code_miss' => 'required', 'action' => '' ];
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $result = $this->modelConfig->update( [ 'code' => $params[ 'code' ],
+ 'btn_code_err' => $params[ 'btn_code_err' ],
+ 'btn_code_miss' => $params[ 'btn_code_miss' ] ], [ 'id' => $config[ 'id' ] ]
+ );
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ $key = 'longbing_card_config_';
+
+ delCache($key, $this->_uniacid);
+ longbingGetAppConfig($this->_uniacid ,true);
+ return $this->success( [] );
+ }
+ }
+
+ /**
+ * @Purpose: 手机创建设置
+ *
+ * @Method: POST
+ *
+ * @Param:$action string 操作类型 edit = 修改 其他 = 回显数据
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function phoneCreate ()
+ {
+
+ $config = $this->modelConfig->getConfig( $this->_uniacid );
+
+ if ( $this->_input[ 'action' ] !== 'edit' )
+ {
+ return $this->success( [ 'allow_create' => $config[ 'allow_create' ], 'create_text' => $config[ 'create_text' ],'agreement_status'=>$config['agreement_status'],'agreement'=>$config['agreement'] ]
+ );
+ }
+ else
+ {
+
+ $verify = [ 'allow_create' => 0, 'create_text' => 'required', 'action' => '','agreement'=>'','agreement_status'=>0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+// dump($params['agreement']);exit;
+ $result = $this->modelConfig->update( [ 'allow_create' => $params[ 'allow_create' ],
+ 'create_text' => $params[ 'create_text' ],'agreement'=>$params['agreement'],'agreement_status'=>$params['agreement_status'] ], [ 'id' => $config[ 'id' ] ]
+ );
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ longbingGetAppConfig($this->_uniacid ,true);
+ return $this->success( [] );
+ }
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-18 12:26
+ * @功能说明:默认配置
+ */
+ public function defaultSetting(){
+
+ $input = $this->_input;
+
+ $default = new DefaultSetting();
+
+ if(!empty($input)&&count($input)>1){
+
+ $input['new_setting']['my_photo_cover'] = !empty($input['new_setting']['my_photo_cover'])?implode(',',$input['new_setting']['my_photo_cover'] ):'';
+ //新的配置
+ $default->settingUpdate(['id' => $input['new_setting']['id']],$input['new_setting']);
+ //新的配置
+ $data = $this->modelConfig->where(['id' => $input['old_setting']['id']])->update($input['old_setting']);
+
+ }else{
+ //新的配置
+ $data['new_setting'] = $default->settingInfo(['uniacid' => $this->_uniacid]);
+
+ $data['new_setting'] = transImages($data['new_setting'],['my_photo_cover']);
+ //新的配置
+ $data['old_setting'] = $this->modelConfig->getConfig( $this->_uniacid );
+ }
+
+ longbingGetAppConfig($this->_uniacid ,true);
+
+ return $this->success($data);
+ }
+
+
+
+ /**
+ * @Purpose: 音频视频设置
+ *
+ * @Method: POST
+ *
+ * @Param:$action string 操作类型 edit = 修改 其他 = 回显数据
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function defaultMedia ()
+ {
+ $verify = [ 'default_video' => '', 'default_voice' => '', 'default_video_cover' => '', 'default_voice_switch' => 0,
+ 'action' => '' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+ $config = $this->modelConfig->getConfig( $this->_uniacid );
+
+// zDumpAndDie($config);
+
+ if ( $params[ 'action' ] !== 'edit' )
+ {
+ return $this->success(
+ [
+
+ 'default_video' => $config[ 'default_video' ],
+ 'default_voice' => $config[ 'default_voice' ],
+ 'default_video_cover' => $config[ 'default_video_cover' ],
+ 'default_voice_switch' => $config[ 'default_voice_switch' ],
+ 'vr_tittle' => $config[ 'vr_tittle' ],
+ 'vr_cover' => $config[ 'vr_cover' ],
+ 'vr_path' => $config[ 'vr_path' ],
+ 'vr_switch' => $config[ 'vr_switch' ],
+
+ ]
+ );
+ }
+ else
+ {
+ if(isset($params[ 'default_video_cover' ][0])){
+ $params[ 'default_video_cover' ] = $params[ 'default_video_cover' ][0];
+ } else{
+ $params[ 'default_video_cover' ] = '';
+ }
+ $result = $this->modelConfig->update(
+ [
+ 'default_video' => $params[ 'default_video' ],
+ 'default_voice' => $params[ 'default_voice' ],
+ 'default_video_cover' => $params[ 'default_video_cover' ],
+ 'default_voice_switch' => $params[ 'default_voice_switch' ],
+
+ 'vr_tittle' => $params[ 'vr_tittle' ],
+
+ 'vr_cover' => $params[ 'vr_cover' ],
+
+ 'vr_path' => $params[ 'vr_path' ],
+
+ 'vr_switch' => $params[ 'vr_switch' ]
+
+ ]
+ , [ 'id' => $config[ 'id' ] ]
+ );
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ longbingGetAppConfig($this->_uniacid ,true);
+ return $this->success( [] );
+ }
+ }
+
+ /**
+ * @Purpose: 名片设置
+ *
+ * @Method: POST
+ *
+ * @Param:$action string 操作类型 edit = 修改 其他 = 回显数据
+ * @Param:$force_phone number 强制授权手机号开关
+ * @Param:$preview_switch number 大图模式开关
+ * @Param:$card_type number 名片板式 1=点击向下展开 2=左右滑动模式
+ * @Param:$exchange_switch number 交换名片开关
+ * @Param:$motto_switch number 员工名片是否显示个性签名开关
+ * @Param:$btn_consult number 咨询按钮文字
+ * @Param:$exchange_btn number 名片详情也交换手机号自定义文字
+ * @Param:$vr_tittle number 默认vr展示标题
+ * @Param:$vr_cover number 默认vr封面图
+ * @Param:$vr_path number 默认vr连接地址
+ * @Param:$vr_switch number 默认VR地址类型 1=网页链接 0=小程序APPID
+ * @Param:$qr_avatar_switch number 替换名片码中间头像开关
+ * @Param:$auto_switch number 自动分配开关
+ * @Param:$auto_switch_way number 分配方式 1=随机分配 2=顺序分配
+ * @Param:$job_switch number 是否允许员工在手机端切换职位开关
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function cardSetting ()
+ {
+ $verify = [ 'force_phone' => 0, 'preview_switch' => 0, 'card_type' => 1, 'exchange_switch' => 0, 'motto_switch' => 0,
+ 'btn_consult' => '', 'exchange_btn' => '', 'vr_tittle' => '', 'vr_cover' => 0, 'vr_path' => '',
+ 'vr_switch' => 0, 'qr_avatar_switch' => 0, 'auto_switch' => 1, 'auto_switch_way' => 0, 'job_switch' => 0,
+ 'action' => '' ,'auth_switch' => 1 ,'chat_switch' => 1 ,'dynamic_switch' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ if ( is_array( $params[ 'vr_cover' ] ) && !empty( $params[ 'vr_cover' ] ) )
+ {
+ $params[ 'vr_cover' ] = implode( ',', $params[ 'vr_cover' ] );
+ }else{
+ $params[ 'vr_cover' ] = '';
+ }
+
+
+ $config = $this->modelConfig->getConfig( $this->_uniacid );
+
+ if ( $params[ 'action' ] !== 'edit' )
+ {
+ return $this->success( [ 'force_phone' => $config[ 'force_phone' ],
+ 'preview_switch' => $config[ 'preview_switch' ], 'card_type' => $config[ 'card_type' ],
+ 'exchange_switch' => $config[ 'exchange_switch' ],
+ 'motto_switch' => $config[ 'motto_switch' ], 'btn_consult' => $config[ 'btn_consult' ],
+ 'exchange_btn' => $config[ 'exchange_btn' ], 'vr_tittle' => $config[ 'vr_tittle' ],
+ 'vr_cover' => $config[ 'vr_cover' ], 'vr_path' => $config[ 'vr_path' ],
+ 'vr_switch' => $config[ 'vr_switch' ],
+ 'qr_avatar_switch' => $config[ 'qr_avatar_switch' ],
+ //'auto_switch' => $config[ 'auto_switch' ],
+ 'auto_switch' => 1,
+ 'auto_switch_way' => $config[ 'auto_switch_way' ],
+ 'job_switch' => $config[ 'job_switch' ],
+ 'auth_switch' => $config[ 'auth_switch' ],
+ 'chat_switch' => $config[ 'chat_switch' ],
+ 'dynamic_switch' => $config[ 'dynamic_switch'] ,
+ ]
+ );
+ }
+ else
+ {
+ $result = $this->modelConfig->update( [ 'force_phone' => $params[ 'force_phone' ],
+ 'preview_switch' => $params[ 'preview_switch' ],
+ 'card_type' => $params[ 'card_type' ],
+ 'exchange_switch' => $params[ 'exchange_switch' ],
+ 'motto_switch' => $params[ 'motto_switch' ],
+ 'btn_consult' => $params[ 'btn_consult' ],
+ 'exchange_btn' => $params[ 'exchange_btn' ],
+ 'vr_tittle' => $params[ 'vr_tittle' ],
+ 'vr_cover' => $params[ 'vr_cover' ],
+ 'vr_path' => $params[ 'vr_path' ],
+ 'vr_switch' => $params[ 'vr_switch' ],
+ 'qr_avatar_switch' => $params[ 'qr_avatar_switch' ],
+ //'auto_switch' => $params[ 'auto_switch' ],
+ 'auto_switch' => 1,
+ 'auto_switch_way' => $params[ 'auto_switch_way' ],
+ 'job_switch' => $params[ 'job_switch' ] ,
+ 'auth_switch' => $params[ 'auth_switch' ],
+ 'chat_switch' => $params[ 'chat_switch' ] ,
+ 'dynamic_switch' => $params[ 'dynamic_switch'] ,
+ ],
+ [ 'id' => $config[ 'id' ] ]
+ );
+
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }
+
+ longbingGetAppConfig($this->_uniacid ,true);
+
+ return $this->success( [] );
+ }
+ }
+
+
+ /**
+ * User: chenniang
+ * Date: 2019-09-24 17:40
+ * @return void
+ * descption:获取微擎版权接口
+ */
+ public function getW7Tmp(){
+ global $_W;
+ if(defined('IS_WEIQIN')){
+ $w['footerleft'] = !empty($_W['setting']['copyright']['footerleft'])?$_W['setting']['copyright']['footerleft']:'';
+ $w['version'] = !empty($_W['setting']['site']['version'])?$_W['setting']['site']['version']:'';
+ $w['icp'] = !empty($_W['setting']['copyright']['icp'])?$_W['setting']['copyright']['icp']:'';
+ }else{
+ $w = 1;
+ }
+ return $this->success($w);
+ }
+
+ //插件权限列表
+ public function getPluginAuth()
+ {
+ $pluginAuth = longbingGetPluginAuth($this->_uniacid);
+ return $this->success($pluginAuth);
+ }
+
+
+ public function getPermissionV2()
+ {
+
+ $adminMenes = AdminMenu::all($this->_uniacid);
+
+ $data = $adminMenes;
+
+ if(longbingIsZhihuituike()){
+
+ $level = Db::name('longbing_admin')->where(['admin_id'=>$this->_user['admin_id']])->value('level');
+
+ $this->changeUserCache($level);
+
+ if($level==1){
+
+ $data = [];
+
+ foreach ($adminMenes as &$v){
+
+ if($v['path']=='/customer'){
+
+ $v['redirect'] = '/customer/talkingSkill';
+ $v['meta']['subNavName'] = array_splice($v['meta']['subNavName'],1);
+ }
+
+ if($v['path']!='/sys'){
+
+ $data[] = $v;
+ }
+ }
+ }
+
+ }
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-17 18:04
+ * @功能说明:
+ */
+ public function changeUserCache($level){
+
+ if($level!=$this->_user['level']){
+
+ setCache("Token_" . $this->_token ,'' ,72000);
+
+ }
+
+ return true;
+ }
+
+
+
+ public function websitebind()
+ {
+ $type = $this->_input['type'] ?? null;
+ if (!in_array($type, ['get', 'post'])) {
+ return $this->error('参数错误');
+ }
+
+ $version_id = '64c7ad0322f14b9c894e95220c9d00d5';
+ $branch_id = '64c7ad0322f14b9c894e95220c9d00d6';
+ $version_name = '1.0.1';
+
+ $domain_name = $_SERVER['HTTP_HOST'];
+ $server_url = 'http://api.longbing.org';//接口地址
+
+ $bindInfo = Db::name('lb_pluge_key')->where('domain_name', '=', $domain_name)->find();
+
+
+ if ($type == 'get') {
+ if ( !$bindInfo ) {
+ $data = array(
+ 'version_id' => $version_id,
+ 'branch_id' => $branch_id,
+ 'version_name' => $version_name,
+ 'domain_name' => $domain_name,
+ );
+ Db::name('lb_pluge_key')->insert($data);
+ $bindInfo = Db::name('lb_pluge_key')->where('domain_name', '=', $domain_name)->find();
+ }
+
+ return $this->success($bindInfo);
+
+ } else {
+ $website_key = $this->_input['website_key'] ?? null;
+ if ($type == 'post' && $website_key == null) {
+ return $this->error('请输入密钥');
+ }
+
+ if (isset($bindInfo['website_keys']) && $bindInfo['website_keys']) {
+ return $this->error('已经绑定过了, 无需重复绑定');
+ }
+
+ $res = json_decode(($this->lb_api_notice_increment_we7($server_url . '/website/check?keys=' . $website_key, [], ['Accept-Charset:utf-8', 'Origin:' . $domain_name], 'GET')), true);
+
+ if (isset($res['error'])) {
+ return $this->error($res['error']['message']);
+ }
+ $data = $res['result']['data'];
+
+
+ $save_data = [
+ 'domain_name' => $domain_name,
+ 'domain_keys' => json_encode($data['domain_keys'], true),
+ 'domain_id' => $data['domain_id'],
+ 'website_id' => $data['website_id'],
+ 'website_keys' => $website_key,
+ ];
+
+ $result = Db::name('lb_pluge_key')->where('domain_name', '=', $domain_name)->save($save_data);
+
+ if ($result === false) {
+ return $this->error('fail');
+ }
+ }
+
+ return $this->success(true);
+ }
+
+
+
+ private function lb_api_notice_increment_we7 ( $url, $data, $headers = [ 'Accept-Charset:utf-8' ], $request_type = 'POST' )
+ {
+ $ch = curl_init();
+ // $header = "Accept-Charset: utf-8";
+ curl_setopt( $ch, CURLOPT_URL, $url );
+ //设置头文件的信息作为数据流输出
+ curl_setopt( $ch, CURLOPT_HEADER, 0 );
+ curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
+ curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, $request_type );
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
+ curl_setopt( $ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)' );
+ curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 );
+ curl_setopt( $ch, CURLOPT_AUTOREFERER, 1 );
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
+ $tmpInfo = curl_exec( $ch );
+ // var_dump($tmpInfo);
+ // exit;
+ if ( curl_errno( $ch ) ) {
+ return false;
+ } else {
+ // var_dump($tmpInfo);
+ return $tmpInfo;
+ }
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-18 14:38
+ * @功能说明:返回json
+ */
+ public function returnJson(){
+
+ $input = $this->_input;
+
+ $m_diy = new DiyModel();
+
+ $data = $m_diy->where(['uniacid'=>$this->_uniacid,'status'=>1])->find();
+
+ $tabbar = [];
+ if(!empty($data)){
+
+ $data = $data->toArray();
+
+ $tabbar = json_decode($data['tabbar'],true);
+
+ }
+
+ return $this->success($tabbar);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-12-17 15:58
+ * @功能说明:
+ */
+ public function admin(){
+
+ $input = $this->_input;
+
+ $key = 'return_admin'.$this->_uniacid;
+
+ $arr = getCache($key,$this->_uniacid);
+
+ if(!empty($arr)){
+
+ return $this->success($arr);
+
+ }
+
+ $this->update();
+
+ $arr['checkAuth'] = $this->checkAuth();
+
+ $arr['permission'] = $this->getPermissionV3();
+
+ $arr['w7tmp'] = $this->getW7TmpV2();
+
+ $arr['app_model_name'] = config('app.AdminModelList')['app_model_name'];
+
+ $arr['copyright'] = Db::name('longbing_card_config')->where(['uniacid'=>$this->_uniacid])->value('copyright');
+
+ $arr = transImagesOne($arr,['copyright'],$this->_uniacid);
+
+ setCache($key,$arr,3600,$this->_uniacid);
+
+ return $this->success($arr);
+ }
+
+
+ /**
+ * By.jingshuixian
+ * 2019年11月23日21:43:47
+ * 升级脚本导入执行
+ */
+ public function update(){
+
+// return $this->success([]);
+ $key = 'init_all_data';
+
+ $data = getCache($key,$this->_uniacid);
+
+ if(!empty($data)){
+
+ return [];
+
+ }
+
+ setCache($key,1,7200,$this->_uniacid);
+
+ UpdateService::installSql($this->_uniacid);
+
+ UpdateService::initWeiqinConfigData();
+
+ DiyService::addDefaultDiyData($this->_uniacid);
+ //各个模块初始化数据事件
+ event('InitModelData');
+ //处理雷达
+ lbInitRadarMsg($this->_uniacid);
+
+ return [];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-06-06 15:24
+ * @功能说明:检查短视频的权限
+ */
+ public function checkAuth(){
+
+
+ if(longbingIsWeiqin()){
+ //是否授权
+ $saasKey = longbing_get_auth_prefix('AUTH_CARD') ;
+ //是否给过验证码
+ $pass = getCache('AUTH_CARD','99999');
+ //如果授权过或者给过验证码
+ if(defined($saasKey)||(!empty($pass)&&$pass==1)){
+
+ return 1;
+
+ }else{
+
+ return 0;
+
+ }
+ }else{
+
+ return 1;
+ }
+
+ }
+
+
+ public function getPermissionV3()
+ {
+
+ $adminMenes = AdminMenu::all($this->_uniacid);
+
+ $data = $adminMenes;
+
+ if(longbingIsZhihuituike()){
+
+ $level = Db::name('longbing_admin')->where(['admin_id'=>$this->_user['admin_id']])->value('level');
+
+ $this->changeUserCache($level);
+
+ if($level==1){
+
+ $data = [];
+
+ foreach ($adminMenes as &$v){
+
+ if($v['path']=='/customer'){
+
+ $v['redirect'] = '/customer/talkingSkill';
+ $v['meta']['subNavName'] = array_splice($v['meta']['subNavName'],1);
+ }
+
+ if($v['path']!='/sys'){
+
+ $data[] = $v;
+ }
+ }
+ }
+
+ }
+ return $data;
+
+ }
+
+
+
+ public function getW7TmpV2(){
+ global $_W;
+ if(defined('IS_WEIQIN')){
+ $w['footerleft'] = !empty($_W['setting']['copyright']['footerleft'])?$_W['setting']['copyright']['footerleft']:'';
+ $w['version'] = !empty($_W['setting']['site']['version'])?$_W['setting']['site']['version']:'';
+ $w['icp'] = !empty($_W['setting']['copyright']['icp'])?$_W['setting']['copyright']['icp']:'';
+ }else{
+ $w = 1;
+ }
+ return $w;
+ }
+
+
+}
diff --git a/app/card/controller/CardCacheKey.php b/app/card/controller/CardCacheKey.php
new file mode 100755
index 0000000..0f4199d
--- /dev/null
+++ b/app/card/controller/CardCacheKey.php
@@ -0,0 +1,41 @@
+request->param();
+ $path = $param['path'] ?? null ;
+ if (!$path ) {
+ return $this->error('请传入参数');
+ }
+//
+// $path = $_SERVER[ 'QUERY_STRING' ];
+// $position = strpos($path, 'getImage&path=');
+// $sub_str = substr($path, $position + 14);
+// $path = urldecode($sub_str);
+ //把https 替换为 http
+ $path = str_replace("https://" , "http://" , $path) ;
+ //判断类型
+ $type_img = getimagesize($path);
+
+ ob_start();
+
+ if ( strpos($type_img[ 'mime' ], 'jpeg') ) {
+ $resourch = imagecreatefromjpeg($path);
+ imagejpeg($resourch);
+ } elseif ( strpos($type_img[ 'mime' ], 'png') ) {
+ $resourch = imagecreatefrompng($path);
+ imagepng($resourch);
+ }
+
+ $content = ob_get_clean();
+ imagedestroy($resourch);
+ return response($content, 200, [ 'Content-Length' => strlen($content) ])->contentType('image/png');
+ }
+}
\ No newline at end of file
diff --git a/app/card/controller/Index.php b/app/card/controller/Index.php
new file mode 100755
index 0000000..bc21bb4
--- /dev/null
+++ b/app/card/controller/Index.php
@@ -0,0 +1,2561 @@
+app = $app;
+ $this->modelUser = new User();
+ $this->modelUserInfo = new UserInfo();
+ $this->modelCollection = new Collection();
+ $this->modelCompany = new Company();
+ $this->modelConfig = new Config();
+ //$this->_user_id = '2';
+ }
+
+ /**
+ * @Purpose: 清除缓存
+ *
+ * @Method:GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function clearCacheData ()
+ {
+ clearCache( $this->_uniacid );
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 用户在小程序授权之后跟新信息
+ *
+ * @Method:POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updateWechatInfo ()
+ {
+ $userId = $this->getUserId();
+ $userInfo = $this->getUserInfo();
+
+ $verify = [ 'avatarUrl' => '', 'city' => '', 'country' => '', 'gender' => '', 'language' => '', 'nickName' => '',
+ 'province' => '' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $result = User::update( $params, [ 'id' => $userId ] );
+
+ if ( $result === false )
+ {
+ return $this->error( 'update failed' );
+ }
+
+ $key = 'longbing_user_autograph_' . $userId;
+ $key = md5( $key );
+ $userInfo[ 'need_auth' ] = 0;
+ setCache( $key, $userInfo, 3600, $this->_uniacid );
+ if(!empty($params))
+ {
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ if(!empty($user)){
+ if(isset($params['avatarUrl']) && !empty($params['avatarUrl'])) $user['avatarUrl'] = $params['avatarUrl'];
+ if(isset($params['city']) && !empty($params['city'])) $user['city'] = $params['city'];
+ if(isset($params['country']) && !empty($params['country'])) $user['country'] = $params['country'];
+ if(isset($params['gender']) && !empty($params['gender'])) $user['gender'] = $params['gender'];
+ if(isset($params['language']) && !empty($params['language'])) $user['language'] = $params['language'];
+ if(isset($params['nickName']) && !empty($params['nickName'])) $user['nickName'] = $params['nickName'];
+ if(isset($params['province']) && !empty($params['avataprovincerUrl'])) $user['province'] = $params['province'];
+ if(!in_array($user['avatarUrl'] ,[$this->defaultImage['avatar']]) && !empty($user['avatarUrl'])) $user[ 'need_auth' ] = 0;
+ longbingSetUser($userId ,$this->_uniacid ,$user);
+ }
+ }
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 个人中心
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function userCenter()
+ {
+ $userInfo = $this->getUserInfo();
+ $userId = $this->getUserId();
+ $userInfo = longbingGetUser($userId, $this->_uniacid);
+ // $modelCompany = new Company();
+// $company = $modelCompany->getInfo($this->_uniacid, $userId, 0);
+
+ $page = isset( $this->_param[ 'page' ] ) ? $this->_param[ 'page' ] : 1;
+
+ // 判断有没有浏览过名片
+ $checkCollection = $this->modelCollection->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'uid', '=', $userId ],
+ [ 'status', '=', 1 ] ]
+ )
+ ->count();
+
+ // 浏览过名片,返回已绑定的名片列表
+ if ( $checkCollection )
+ {
+ $cardList = $this->modelCollection->bindCardList( $userId, $userInfo, $page, $this->_uniacid );
+ }
+ // 没有浏览过名片返回推荐名片列表
+ else
+ {
+ $cardList = $this->modelCollection->defaultCardList( $page, $this->_uniacid ,$userId);
+ }
+
+// $cardList['company_info'] = $company;
+ $cardList['is_staff'] = $userInfo['is_staff'];
+
+ return $this->success( $cardList, 200 );
+ }
+
+ /**
+ * @Purpose: 用户信息
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function userInfo ()
+ {
+
+ $uniacid = $this->_uniacid;
+
+
+ $permissionAdmin = new PermissionAdmin($this->_uniacid);
+ $longbing_auth_mini = $permissionAdmin->getAuthNumber();
+
+ $userModel = new User();
+ $userInfoModel = new UserInfo();
+ $cardCountModel = new CardCount();
+
+ //By.jingshuixian 2020年4月21日12:12:53
+ //解决微擎版本同一个域名授权问题
+ if($this->_is_weiqin ){
+ $app_model_name = APP_MODEL_NAME;
+ $wxapp = Db::name('account')
+ ->alias('a')
+ ->join('wxapp_versions v' , 'a.uniacid = v.uniacid')
+ ->join('account_wxapp account_wxapp' , 'a.uniacid = account_wxapp.uniacid')
+ ->field(['account_wxapp.name as mini_name', 'account_wxapp.uniacid as modular_id' , 'account_wxapp.uniacid' ])
+ ->where([ ['v.modules', 'like', "%{$app_model_name}%"] , ['a.type', '=', 4] ,['a.isdeleted', '=', 0] ])
+ ->group('account_wxapp.uniacid')
+ ->order('account_wxapp.uniacid asc')
+ ->select()
+ ->toArray();
+
+ $check_mini_user_count = count($wxapp) ;
+ if ( $check_mini_user_count > $longbing_auth_mini) {
+ foreach ($wxapp as $index => $item) {
+ $now = $index + 1;
+ if ($item['uniacid'] == $uniacid && $now > $longbing_auth_mini) {
+ $msg = '小程序数量达到上限! 请联系管理员(' . $check_mini_user_count . '-' . $longbing_auth_mini.')';
+ //echo json_encode(['code' => 402, 'error' => $msg]);
+ //exit;
+ return $this->error( $msg , 402);
+ }
+ }
+ }
+
+
+ }else{
+ $check_mini_user = $userModel
+ ->field('uniacid')
+ ->group('uniacid')
+ ->order('id asc')
+ ->select();
+
+ $check_mini_user_count = count($check_mini_user);
+
+ if ($check_mini_user_count > $longbing_auth_mini) {
+ foreach ($check_mini_user as $index => $item) {
+ $now = $index + 1;
+ if ($item['uniacid'] == $uniacid && $now > $longbing_auth_mini) {
+ $msg = '小程序数量达到上限! 请联系管理员' . $check_mini_user_count . '-' . $longbing_auth_mini;
+ //echo json_encode(['code' => 402, 'error' => $msg]);
+ //exit;
+ return $this->error( $msg , 402);
+ }
+ }
+ }
+
+ $check_mini_info = $userInfoModel
+ ->field('uniacid')
+ ->group('uniacid')
+ ->order('id asc')
+ ->select();
+ $check_mini_info_count = count($check_mini_user);
+
+ if ($check_mini_info_count > $longbing_auth_mini) {
+ foreach ($check_mini_info as $index => $item) {
+ $now = $index + 1;
+ if ($item['uniacid'] == $uniacid && $now > $longbing_auth_mini) {
+ $msg = '小程序数量达到上限!! 请联系管理员' . $check_mini_info_count . '-' . $longbing_auth_mini;
+ //echo json_encode(['code' => 402, 'error' => $msg]);
+ //exit;
+ return $this->error( $msg , 402);
+ }
+ }
+ }
+
+ $check_mini_count = $cardCountModel
+ ->field('uniacid')
+ ->group('uniacid')
+ ->order('id asc')
+ ->select();
+
+ $check_mini_count_count = count($check_mini_user);
+ if ($check_mini_count_count > $longbing_auth_mini) {
+ foreach ($check_mini_count as $index => $item) {
+ $now = $index + 1;
+// longbingDebugOneService('now ' . $now . 'uniacid '. $item[ 'uniacid' ]);
+ if ($item['uniacid'] == $uniacid && $now > $longbing_auth_mini) {
+ $msg = '小程序数量达到上限!!! 请联系管理员' . $check_mini_count_count . '-' . $longbing_auth_mini;
+ //echo json_encode(['code' => 402, 'error' => $msg]);
+ //exit;
+
+ return $this->error( $msg , 402);
+ }
+ }
+ }
+ }
+
+ $user_id = $this->getUserId();
+ $userInfo = longbingGetUser($user_id, $this->_uniacid);
+
+
+ //最后访问的名片处理
+ if (!empty($userInfo) && isset($userInfo['last_staff_id'])) {
+ //判断last_staff_id是否是员工 chenniang
+ $staff_user = $userModel->where(['id'=>$userInfo['last_staff_id'],'is_staff'=>1])->count();
+ //如果不是
+ if(empty($staff_user)){
+ //模型
+ $collectionModel = new Collection();
+ //分配一个
+ $user['last_staff_id'] = $collectionModel->getCard($user_id,$uniacid);
+ //从新获取信息
+ $userInfo = longbingGetUser($user_id, $this->_uniacid);
+ }
+ }
+ $userInfo['cardInfo'] = [];
+ //是员工则把名片信息查出来
+ if (isset($userInfo['is_staff']) && $userInfo['is_staff'] == 1) {
+ $key = 'longbing_user_card_info_' . $userInfo['id'];
+
+// $value = getCache( $key, $this->_uniacid );
+ $value = [];
+ if ($value && false) {
+ $value['from_cache'] = 1;
+ $userInfo['cardInfo'] = $value;
+ } else {
+// $cardInfo = UserInfo::where( [ [ 'fans_id', '=', $userInfo[ 'id' ] ] ] )
+// ->find();
+ $cardInfo = longbingGetUserInfo($user_id, $this->_uniacid);
+ if ($cardInfo) {
+// $cardInfo = $cardInfo->toArray();
+
+ $job = Job::where([['id', '=', $cardInfo['job_id']]])
+ ->find();
+
+ if (!$job) {
+ $cardInfo['job_name'] = '未设置职位';
+ } else {
+ $job = $job->toArray();
+ $cardInfo['job_name'] = $job['name'];
+ }
+ $cardInfo = transImages($cardInfo, ['images'], ',');
+ $cardInfo = transImagesOne($cardInfo, ['avatar', 'voice', 'my_url', 'my_video', 'my_video_cover', 'bg',
+ 'vr_cover', 'vr_path']
+ );
+ if (isset($cardInfo['my_video']) && is_array($cardInfo['my_video']) && !empty($cardInfo['my_video'])) {
+ $cardInfo['my_video_vid'] = lbGetTencentVideo($cardInfo['my_video'][0]);
+ }
+
+ $modelCount = new RadarCount();
+ list($viewCount, $thumbCount) = $modelCount->RadarNumber($userInfo['id'], $this->_uniacid);
+ $cardInfo['viewCount'] = $viewCount;
+ $cardInfo['thumbCount'] = $thumbCount;
+ //获取公司信息
+
+ $company = longbingGetUserCompany($cardInfo['company_id'], $uniacid);
+ if (isset($company['name'])) $company_name = $company['name'];
+
+ $cardInfo['company_info'] = $company;
+
+ $modelCompany = new Company();
+
+ $cardInfo[ 'company_info' ] = $modelCompany->changeTopName($cardInfo[ 'company_info' ]);
+
+ $cardInfo['company_name'] = !empty($cardInfo[ 'company_info' ]['name'])? $cardInfo[ 'company_info' ]['name']:$cardInfo['company_name'];
+ //获取递名片数量
+ $radar_model = new RadarCount();
+ $cardInfo['share_number'] = $radar_model->getShareNumberV2($user_id);
+
+ //生成活动二维码
+ $qrData = [
+ 'pid' => $this->_user_id,
+ 'staff_id' => $this->_user_id,
+ 'type' => 12,
+ 'key' => 1
+ ];
+
+
+ $src = 'image/' . $this->_uniacid . '/' . 'wxcode/' . md5($this->_uniacid . json_encode($qrData, true)) . '.jpeg';
+ if (!longbingHasLocalFile($src)) {
+ $push_data = array(
+ 'action' => 'longbingCreateWxCode',
+ 'event' => 'longbingCreateWxCode',
+ 'uniacid' => $this->_uniacid,
+ 'data' => $qrData,
+ 'page' => 'pages/user/home',
+ 'type' => 3
+ );
+ publisher(json_encode($push_data, true));
+ }
+ //获取名片图
+ $cardInfo['share_img'] = "images/share_img/{$uniacid}/share-{$this->_user_id}.png";
+ if (!longbingHasLocalFile($cardInfo['share_img'])) {
+ $user['share_img'] = null;
+ $cardInfo['share_img'] = null;
+ } else {
+ $cardInfo = transImagesOne($cardInfo, ['share_img']);
+ }
+
+ //
+ $cardInfo['posterQr'] = $src;
+ $cardInfo = transImagesOne($cardInfo, ['posterQr'], $this->_uniacid);
+ //获取名片码
+ $card_code_data = ["data" => ["staff_id" => (string)$user_id, "pid" => (string)$user_id, "type" => 4, "key" => 1]];
+ $qr_path = 'image/' . $this->_uniacid . '/' . 'wxcode/' . md5($this->_uniacid . json_encode($card_code_data, true)) . '.jpeg';
+ $cardInfo['qr_path'] = null;
+ if (longbingHasLocalFile($qr_path)) {
+ $cardInfo['qr_path'] = $qr_path;
+ } else {
+ $wxcode_data = longbingCreateWxCode($this->_uniacid, $card_code_data);
+
+
+ if (isset($wxcode_data['path']) && !empty($wxcode_data['path'])) $cardInfo['qr_path'] = $wxcode_data['path'];
+ }
+ if (!empty($cardInfo['qr_path'])) $cardInfo = transImagesOne($cardInfo, ['qr_path'], $this->_uniacid);
+ $userInfo['cardInfo'] = $cardInfo;
+ setCache($key, $cardInfo, 1800, $this->_uniacid);
+ //数据处理
+ if (isset($cardInfo['share_text']) && !empty($cardInfo['share_text'])) {
+
+ $share_text = $cardInfo['share_text'];
+ if (strpos($share_text, '#公司#')) $share_text = str_replace('#公司#', $company_name, $share_text);
+ if (strpos($share_text, '#职务#')) $share_text = str_replace('#职务#', $cardInfo['job_name'], $share_text);
+ if (strpos($share_text, '#我的名字#')) $share_text = str_replace('#我的名字#', $cardInfo['name'], $share_text);
+ if (strpos($share_text, '$company')) $share_text = str_replace('$company', $company_name, $share_text);
+ if (strpos($share_text, '$job')) $share_text = str_replace('$job', $cardInfo['job_name'], $share_text);
+ if (strpos($share_text, '$name')) $share_text = str_replace('$name', $cardInfo['name'], $share_text);
+ $userInfo['cardInfo']['share_text'] = $share_text;
+ } else {
+ $userInfo['cardInfo']['share_text'] = lang("card share text");
+ }
+ }
+ }
+ }
+ return $this->success($userInfo);
+ }
+
+ /**
+ * @Purpose: 小程序配置接口
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function config ()
+ {
+
+ $data = longbingGetAppConfig($this->_uniacid);
+
+ unset( $data[ 'auth_code' ] );
+
+ $exist = Db::query( 'show tables like "%longbing_card_config%"' );
+
+ $auth_info = false;
+
+ $cardauth2_config_exist = Db::query('show tables like "%longbing_cardauth2_config%"');
+
+ if (!empty($exist) && !empty($cardauth2_config_exist)) {
+ $auth_info = Db::name('longbing_cardauth2_config')
+ ->where([['modular_id', '=', $this->_uniacid]])
+ ->find();
+ }
+ $data[ 'is_pay_shop' ] = 1;
+ // 判断能不能使用商城的支付功能
+ if ( $auth_info && isset( $auth_info[ 'pay_shop' ] ) && $auth_info[ 'pay_shop' ] == 0 )
+ {
+ $data[ 'is_pay_shop' ] = 0;
+ }
+
+ if ( isset( $data[ 'btn_talk' ] ) && !$data[ 'btn_talk' ] )
+ {
+
+ $data[ 'btn_talk' ] = '面议';
+
+ }
+ $data['tabBar1'] = [];
+ //tabbar用新的方式返回
+ $data['tabBar1'] = Tabbar::all($this->_uniacid, $this->_user_id);
+
+ $pluginAuth = longbingGetPluginAuth($this->_uniacid, $this->_user_id, $auth_info);
+
+
+ $data = array_merge($data, $pluginAuth);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @Purpose: 小程序允许使用的名片样式
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function cardType ()
+ {
+ $userId = $this->getUserId();
+
+ $card = UserInfo::where( [ [ 'fans_id', '=', $userId ], [ 'is_staff', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->field( [ 'card_type' ] )
+ ->find();
+
+ if ( !$card )
+ {
+ $this->error( 'card info not found', 402 );
+ }
+
+ $modelCardType = new CardType();
+
+ $count = $modelCardType->where( [ [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->count();
+ if ( !$count )
+ {
+ // 初始化名片样式
+ $data = $modelCardType->initCardType( $this->_uniacid );
+ }
+ else
+ {
+ $data = $modelCardType->where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'status', '=', 1 ] ] )
+ ->field( [ 'card_type', 'img' ] )
+ ->select();
+ }
+
+ foreach ( $data as $index => $item )
+ {
+ $data[ $index ][ 'selected' ] = 0;
+ if ( $item[ 'card_type' ] == $card->card_type )
+ {
+ $data[ $index ][ 'selected' ] = 1;
+ }
+ }
+
+ return $this->success( $data );
+ }
+
+ /**
+ * @Purpose: 修改名片样式
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editCardType ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'card_type' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $card = UserInfo::where( [ [ 'fans_id', '=', $userId ], [ 'is_staff', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->field( [ 'card_type' ] )
+ ->find();
+
+ if ( !$card )
+ {
+ $this->error( 'card info not found', 402 );
+ }
+
+ $card->card_type = $params[ 'card_type' ];
+ $result = $card->save();
+
+ if ( $result === false )
+ {
+ $this->error( 'edit fail', 402 );
+ }else{
+ //清除名片缓存
+ $key = 'longbing_card_card_info_' . $userId;
+ delCache($key ,$this->_uniacid);
+ }
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 修改名片录音
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editCardVoice ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'voice_id' => 'required', 'voice_time' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $card = UserInfo::where( [ [ 'fans_id', '=', $userId ], [ 'is_staff', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->field( [ 'voice', 'voice_time' ] )
+ ->find();
+
+ if ( !$card )
+ {
+ $this->error( 'card info not found', 402 );
+ }
+
+ $card->voice = $params[ 'voice_id' ];
+ $card->voice_time = $params[ 'voice_time' ];
+ $result = $card->save();
+
+ if ( $result === false )
+ {
+ $this->error( 'edit fail', 402 );
+ }else{
+ //清除名片缓存
+ $key = 'longbing_card_info_' . $userId;
+ delCache($key ,$this->_uniacid);
+ longbingGetUserInfo($userId ,$this->_uniacid ,true);
+ }
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 创建 / 编辑名片时回显数据
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function reviewData ()
+ {
+ $userId = $this->getUserId();
+ $userInfo = $this->getUserInfo();
+
+ $modelCompany = new Company();
+ $modelJob = new CardJob();
+ $modelType = new CardType();
+
+ $card = UserInfo::where( [ [ 'uniacid', '=', $this->_uniacid ], [ 'fans_id', '=', $userId ] ] )
+ ->find();
+
+ if ( $card )
+ {
+ $card = $card->toArray();
+
+ $data = transImagesOne( $card, [ 'avatar' ] ,$this->_uniacid);
+
+ $data[ 'companyList' ] = $modelCompany->getListByUser( $userId, $this->_uniacid, 0, $card[ 'company_id' ] );
+
+ $data[ 'jobList' ] = $modelJob->getListByUser( $card[ 'job_id' ], $this->_uniacid );
+
+ $data[ 'typeList' ] = $modelType->getCardTypeList( $this->_uniacid, $card[ 'card_type' ] );
+
+ $data[ 'company_info' ] = $modelCompany->getInfo( $this->_uniacid, 0, $card[ 'company_id' ] );
+
+ if(!empty($data['company_info'])){
+
+ $data[ 'company_info' ]['top_name'] = $modelCompany->where(['id'=>$data['company_info']['top_id'],'status'=>1])->value('name');
+ }
+
+ }
+ else
+ {
+ $data = [ 'avatar' => $userInfo[ 'avatarUrl' ], 'name' => $userInfo[ 'nickName' ],
+ 'phone' => $userInfo[ 'phone' ], 'email' => '' ];
+ $data[ 'companyList' ] = $modelCompany->getListByUser( $userId, $this->_uniacid, 1, 0 );
+ $data[ 'jobList' ] = $modelJob->getListByUser( 0, $this->_uniacid );
+ $data[ 'typeList' ] = $modelType->getCardTypeList( $this->_uniacid );
+ $data[ 'company_info' ] = [];
+ }
+
+ $config = $this->modelConfig->getConfig( $this->_uniacid );
+
+ $data[ 'job_switch' ] = $config[ 'job_switch' ];
+
+ return $this->success( $data );
+ }
+
+ /**
+ * @Purpose: 名片信息
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function cardInfo ()
+ {
+ //获取用户id
+ $userId = $this->getUserId();
+ $uniacid = $this->_uniacid;
+ //获取必要参数
+ $verify = [ 'staff_id' => 'required' ];
+ $params = lbGetParamVerify( $this->_param, $verify );
+ $staff_id = $params['staff_id'];
+
+ $staff = longbingGetUserInfo($staff_id ,$this->_uniacid);
+ if(empty($staff) || empty($staff['is_staff'])) return $this->error(lang('card info not found') ,403);
+
+
+
+ /*
+ //获取缓存数据
+ $key = 'longbing_card_info_'.$staff_id;
+ $plugin_model = new PluginManager($this->app);
+ if(hasCache($key ,$this->_uniacid))
+ {
+ $result = getCache($key ,$this->_uniacid);
+ $result['plugin'] = $plugin_model->trigger('decorate');
+ if(!empty($result)) return $this->success($result);
+
+ }
+ */
+
+
+ //获取名片数据
+ $card = UserInfo::alias( 'a' )
+ ->field( [ 'a.*', 'b.name as job_name' ] )
+ ->join( 'longbing_card_job b', 'a.job_id = b.id', 'LEFT' )
+ ->where( [ [ 'a.fans_id', '=', $params[ 'staff_id' ] ], [ 'a.is_staff', '=', 1 ],
+ [ 'a.uniacid', '=', $this->_uniacid ] ]
+ )
+ ->find();
+ //判断名片是否存在
+ if ( empty($card) )
+ {
+ return $this->error( lang('card info not found') ,403);
+ }
+ //更新最后查看信息
+ if(!in_array($userId, [$params[ 'staff_id' ]]))
+ {
+ $user_update = User::update( [ 'last_staff_id' => $params[ 'staff_id' ] ], [ 'id' => $userId] );
+ if(!empty($user_update)){
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ $user['last_staff_id'] = $params[ 'staff_id' ];
+ longbingSetUser($userId ,$this->_uniacid ,$user);
+ }
+ }
+ $cardInfo = $card->toArray();
+ //判断名片是否拥有职位(没有就默认)
+ if ( !$cardInfo[ 'job_name' ] )
+ {
+ $cardInfo[ 'job_name' ] = lang('not set job');
+ }
+ //默认vr数据
+ if(!isset($cardInfo['vr_tittle']) || empty($cardInfo['vr_tittle']))
+ {
+ $config = longbingGetAppConfig($this->_uniacid);
+ if(!empty($config) && !empty($config['vr_tittle']))
+ {
+ $cardInfo['vr_tittle'] = $config['vr_tittle'];
+ }else{
+ $cardInfo['vr_tittle'] = lang('panoramic');
+ }
+ }
+ $modelConfig = new Config();
+// $config = $modelConfig->getConfig( $this->_uniacid );
+ $config = longbingGetAppConfig($this->_uniacid);
+ //默认背景音乐
+ if ( !$cardInfo[ 'bg' ] )
+ {
+ $cardInfo[ 'bg' ] = $config[ 'default_voice' ];
+ }
+
+ if ( !$cardInfo[ 'bg_switch' ] )
+ {
+ $cardInfo[ 'bg_switch' ] = $config[ 'default_voice_switch' ];
+ }
+
+
+ // 处理图片
+ $cardInfo = transImages( $cardInfo, [ 'images' ], ',' );
+ $cardInfo = transImagesOne( $cardInfo, [ 'avatar', 'voice', 'my_url', 'my_video', 'my_video_cover', 'bg', 'vr_cover',
+ 'vr_path' ]
+ );
+ $modelCount = new RadarCount();
+ list( $viewCount, $thumbCount ) = $modelCount->RadarNumber( $cardInfo[ 'fans_id' ] ,$this->_uniacid);
+ $cardInfo[ 'viewCount' ] = $viewCount;
+ $cardInfo[ 'thumbCount' ] = $thumbCount;
+
+ // 名片最近浏览情况
+ list( $cardInfo[ 'view_list' ], $cardInfo[ 'view_count' ] ) = $modelCount->getCardViewInfo( $params[ 'staff_id' ], $this->_uniacid );
+ //获取公司信息
+ $modelCompany = new Company();
+ if ( $cardInfo[ 'company_id' ] )
+ {
+ $card_company = new CardCompany();
+ $company_id = $card_company->getUserTopCompanyId($cardInfo[ 'company_id' ]);
+ $company = $card_company->getinfo(['uniacid'=>$this->_uniacid,'id'=>$company_id]);
+// $company = $modelCompany->getInfo( $this->_uniacid, 0, $cardInfo[ 'company_id' ] );
+ }
+ else
+ {
+ $company = $modelCompany->getInfo( $this->_uniacid, 0, 0 );
+ }
+ $cardInfo[ 'company_info' ] = $company;
+ $company_name = '';
+ if(isset($company['name'])) $company_name = $company['name'];
+ //获取名片码
+ $card_code_data = ["data" => ["staff_id" => $params['staff_id'] ,"pid" => $userId ,"type" => 4 ,"key" => 1]];
+ $qr_path = 'image/' . $this->_uniacid . '/' . 'wxcode/' . md5($this->_uniacid . json_encode($card_code_data ,true)) . 'jpeg';
+ $cardInfo['qr_path'] = null;
+ if(longbingHasLocalFile($qr_path))
+ {
+ $cardInfo['qr_path'] = $qr_path;
+ }else{
+ $wxcode_data = longbingCreateWxCode($this->_uniacid ,$card_code_data);
+ if(isset($wxcode_data['path']) && !empty($wxcode_data['path'])) $cardInfo['qr_path'] = $wxcode_data['path'];
+ }
+ if(!empty($cardInfo['qr_path'])) $cardInfo = transImagesOne($cardInfo ,['qr_path']);
+ //设置分享数据
+ if(isset($cardInfo['share_text']) && !empty($cardInfo['share_text']))
+ {
+ $share_text = $cardInfo['share_text'];
+ if(strpos($share_text,'#公司#')) $share_text = str_replace('#公司#',$company_name,$share_text);
+ if(strpos($share_text,'#职务#')) $share_text = str_replace('#职务#',$cardInfo[ 'job_name' ],$share_text);
+ if(strpos($share_text,'#我的名字#')) $share_text = str_replace('#我的名字#',$cardInfo[ 'name' ],$share_text);
+ if(strpos($share_text,'$company')) $share_text = str_replace('$company',$company_name,$share_text);
+ if(strpos($share_text,'$job')) $share_text = str_replace('$job',$cardInfo[ 'job_name' ],$share_text);
+ if(strpos($share_text,'$name')) $share_text = str_replace('$name',$cardInfo[ 'name' ],$share_text);
+ $cardInfo['share_text'] = $share_text;
+ }else{
+ $cardInfo['share_text'] = lang("card share text");
+ }
+ //名片分享链接
+ $cardInfo['share_img'] = "images/share_img/{$uniacid}/share-{$staff_id}.png";
+ if(!longbingHasLocalFile($cardInfo['share_img'])) {
+ $user['share_img'] = null;
+ $cardInfo['share_img'] = null;
+ }else{
+ $cardInfo = transImagesOne($cardInfo, ['share_img']);
+ }
+ //判断视频等参数
+// $config = longbingGetAppConfig($this->_uniacid);
+ //默认视频
+ if(isset($config['default_video']) && empty($cardInfo['my_video'])) $cardInfo['my_video'] = $config['default_video'];
+ //默认视频图片
+ if(isset($config['default_video_cover']) && empty($cardInfo['my_video_cover'])) $cardInfo['my_video_cover'] = $config['default_video_cover'];
+ //默认背景音乐
+ if(isset($config['default_voice']) && empty($cardInfo['bg'])) $cardInfo['bg'] = $config['default_voice'];
+ //VR图片
+ if(isset($config['vr_cover']) && empty($cardInfo['vr_cover'])) $cardInfo['vr_cover'] = $config['vr_cover'];
+ //默认VR路径
+ if(isset($config['vr_path']) && empty($cardInfo['vr_path'])) {
+ $cardInfo['vr_path'] = $config['vr_path'];
+ //默认VR switch
+ $cardInfo['vr_switch'] = $config['vr_switch'];
+ }
+ //默认VR标题
+ if(isset($config['vr_tittle']) && empty($cardInfo['vr_tittle'])) $cardInfo['vr_tittle'] = $config['vr_tittle'];
+ //默认视频(处理)
+ if ( isset( $cardInfo[ 'my_video' ] ) && $cardInfo[ 'my_video' ] ) $cardInfo[ 'my_video_vid' ] = lbGetTencentVideo( $cardInfo[ 'my_video' ] );
+ $modelTags = new CardTags();
+
+ $cardInfo[ 'tag_list' ] = $modelTags->cardTagList( $params[ 'staff_id' ], $userId, $this->_uniacid );
+
+
+
+ //获取商品推荐列表 By.jingshuixian
+
+ /*$modelExtension = new CardExtension();
+
+ $cardInfo[ 'goods_list' ] = $modelExtension->cardExtensionList( $params[ 'staff_id' ], $this->_uniacid );
+ foreach($cardInfo[ 'goods_list'] as $key => $val)
+ {
+ $cardInfo[ 'goods_list'][$key]['is_collage'] = 0;
+ $collage_model = new IndexShopCollage();
+ $count = $collage_model->getCollage(['goods_id' => $val['id'] ,'uniacid' => $this->_uniacid ,'status' => 1]);
+ if(!empty($count)) $cardInfo[ 'goods_list'][$key]['is_collage'] = 1;
+ }*/
+
+
+
+
+
+ if ( isset( $cardInfo[ 'vr_tittle' ] ) && !$cardInfo[ 'vr_tittle' ] )
+ {
+ $cardInfo[ 'vr_tittle' ] = 'VR全景';
+ }
+
+
+ // 是否语音点赞
+ $checkVoice = CardCount::where( [ [ 'type', '=', 1 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->count();
+ // 是否给名片点赞
+ $checkThumb = CardCount::where( [ [ 'type', '=', 3 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->count();
+ //递名片
+ $radar_model = new RadarCount();
+ $share_number = $radar_model->getShareNumberV2($params['staff_id']);
+ if ( $checkVoice )
+ {
+ $cardInfo[ 'voiceThumbs' ] = 1;
+ }
+ else
+ {
+ $cardInfo[ 'voiceThumbs' ] = 0;
+ }
+ if ( $checkThumb )
+ {
+ $cardInfo[ 'isThumbs' ] = 1;
+ }
+ else
+ {
+ $cardInfo[ 'isThumbs' ] = 0;
+ }
+
+ $cardInfo[ 'view_count' ] = $cardInfo[ 'view_count' ] + $cardInfo[ 'view_number' ];
+ $cardInfo[ 'thumbCount' ] = $cardInfo[ 'thumbCount' ] + $cardInfo[ 't_number' ];
+ $cardInfo[ 'share_number' ] = $share_number;
+
+
+
+ $time = time();
+
+ $coupon = CardCoupon::where( [ [ 'end_time', '>', $time ], [ 'status', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] , [ 'number' , '>' , 0]] )
+ ->order( [ 'top' => 'desc', 'id' => 'desc' ] )
+ ->select()
+ ->toArray();
+
+ $cardInfo[ 'coupon' ] = array();
+ $cardInfo[ 'coupon_last_record' ] = array();
+ $cardInfo[ 'coupon_last_record_user' ] = array();
+ if ( $coupon )
+ {
+ foreach ( $coupon as $index => $item )
+ {
+ $record_list = CardCouponRecord::where( [ [ 'coupon_id', '=', $item[ 'id' ] ],
+ [ 'staff_id', '=', $params[ 'staff_id' ] ],
+ [ 'uniacid', '=', $this->_uniacid ] ,
+
+ ] )
+ ->order( [ 'id' => 'desc' ] )
+ ->select()
+ ->toArray();
+ if ( count( $record_list ) < $item[ 'number' ] )
+ {
+ $cardInfo[ 'coupon' ] = $item;
+ if ( count( $record_list ) )
+ {
+ $cardInfo[ 'coupon_last_record' ] = $record_list;
+ }
+ break;
+ }
+ }
+ }
+ if ( !empty( $cardInfo[ 'coupon_last_record' ] ) )
+ {
+ foreach ( $cardInfo[ 'coupon_last_record' ] as $index => $item )
+ {
+ $user = longbingGetUser($item[ 'user_id' ] ,$this->_uniacid);
+ if ( mb_strlen( $user[ 'nickName' ], 'utf8' ) > 4 )
+ {
+ $user[ 'nickName' ] = mb_substr( $user[ 'nickName' ], 0, 4, "UTF-8" );
+ }
+ $cardInfo[ 'coupon_last_record' ][ $index ][ 'user_info' ] = $user;
+ }
+ }
+
+
+ //By.jingshuixian 删除 缓存 和 装修
+
+ /*if(!empty($cardInfo)) setCache($key ,$cardInfo ,600 ,$this->_uniacid);
+ $cardInfo['plugin'] = $plugin_model->trigger('decorate');*/
+ return $this->success( $cardInfo );
+ }
+
+
+ /**
+ * @Purpose: 名片信息
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function cardInfoV2 ()
+ {
+
+ //获取用户id
+ $userId = (string) $this->getUserId();
+ $uniacid = $this->_uniacid;
+
+ //获取必要参数
+ $verify = [ 'staff_id' => 'required' ,'is_base' => 0];
+ $params = lbGetParamVerify( $this->_param, $verify );
+ $input = $this->_param;
+ $staff_id = $params['staff_id'];
+ //获取员工数据
+ $cardInfo = longbingGetUserCard($staff_id ,$this->_uniacid);
+ if(empty($cardInfo) || empty($cardInfo['is_staff'])) return $this->error(lang('card info not found') ,403);
+ //判断名片是否拥有职位(没有就默认)
+ if ( !$cardInfo[ 'job_name' ] )
+ {
+ $cardInfo[ 'job_name' ] = lang('not set job');
+ }
+ //获取名片码
+ $card_code_data = ["data" => ["staff_id" => $params['staff_id'] ,"pid" => $userId ,"type" => 4 ,"key" => 1]];
+ $qr_path = 'image/' . $this->_uniacid . '/' . 'wxcode/' . md5($this->_uniacid . json_encode($card_code_data ,true)) . '.jpeg';
+ if(!longbingHasLocalFile($qr_path))
+ {
+ $push_data = array(
+
+ 'action' => 'longbingCreateWxCode',
+ 'event' => 'longbingCreateWxCode',
+ 'uniacid' => $this->_uniacid,
+ 'data' => $card_code_data,
+ 'page' => '',
+ 'type' => 3
+ );
+
+ publisher(json_encode($push_data ,true));
+
+ }
+ $cardInfo['qr_path'] = $qr_path;
+
+ if(!empty($cardInfo['qr_path'])) $cardInfo = transImagesOne($cardInfo ,['qr_path']);
+
+
+ $modelCompany = new Company();
+ //检查公司默认数据
+ if ( empty($cardInfo['company_info']) )
+ {
+ //jingshuixian 0 = $cardInfo['fans_id']
+ $company = $modelCompany->getInfo( $this->_uniacid, $cardInfo['fans_id'], 0 );
+
+ $cardInfo[ 'company_info' ] = $company;
+
+ if(isset($company['name'])) $company_name = $company['name'];
+ }
+
+ $cardInfo[ 'company_info' ] = $modelCompany->changeTopName($cardInfo[ 'company_info' ]);
+
+ $cardInfo['company_name'] = !empty($cardInfo[ 'company_info' ]['name'])? $cardInfo[ 'company_info' ]['name']:$cardInfo['company_name'];
+
+ //设置分享数据
+ if(isset($cardInfo['share_text']) && !empty($cardInfo['share_text']))
+ {
+ $share_text = $cardInfo['share_text'];
+
+ if(strpos($share_text,'#公司#')) $share_text = str_replace('#公司#',$cardInfo[ 'company_name' ],$share_text);
+
+ if(strpos($share_text,'#职务#')) $share_text = str_replace('#职务#',$cardInfo[ 'job_name' ],$share_text);
+
+ if(strpos($share_text,'#我的名字#')) $share_text = str_replace('#我的名字#',$cardInfo[ 'name' ],$share_text);
+
+ if(strpos($share_text,'$company')) $share_text = str_replace('$company',$cardInfo[ 'company_name' ],$share_text);
+
+ if(strpos($share_text,'$job')) $share_text = str_replace('$job',$cardInfo[ 'job_name' ],$share_text);
+
+ if(strpos($share_text,'$name')) $share_text = str_replace('$name',$cardInfo[ 'name' ],$share_text);
+ $cardInfo['share_text'] = $share_text;
+ }else{
+
+// $cardInfo['share_text'] = lang("card share text");
+ $cardInfo['share_text'] = '您好,我是'.$cardInfo[ 'company_name' ].'的'.$cardInfo[ 'job_name' ].$cardInfo[ 'name' ].',请惠存';
+ }
+ //名片分享链接
+ $cardInfo['share_img'] = "images/share_img/{$uniacid}/share-{$staff_id}.png";
+ // var_dump($cardInfo['share_img']);die;
+ if(!longbingHasLocalFile($cardInfo['share_img'])) {
+ $user['share_img'] = null;
+ $cardInfo['share_img'] = null;
+ }else{
+ $cardInfo = transImagesOne($cardInfo, ['share_img']);
+ }
+
+
+
+
+ //更新最后查看信息
+ //By.jingshuixian 最后访问的员工ID不同是更新
+// if(!in_array($userId, [$params[ 'staff_id' ]]))
+// {
+ $user_update = User::update( [ 'last_staff_id' => $params[ 'staff_id' ] ], [ 'id' => $userId] );
+ if(!empty($user_update)){
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ $user['last_staff_id'] = $params[ 'staff_id' ];
+ longbingSetUser($userId ,$this->_uniacid ,$user);
+ }
+// }
+
+
+ //是否只需要基础数据======================================================================================================有返回结果==============================
+ if(isset($params['is_base']) && !empty($params['is_base']))
+ {
+ $cardInfo = transImagesOne( $cardInfo, [ 'avatar']);
+ return $this->success($cardInfo);
+ }
+ //是否只需要基础数据======================================================================================================有返回结果==============================
+
+
+ //默认vr数据
+ if(!isset($cardInfo['vr_tittle']) || empty($cardInfo['vr_tittle']))
+ {
+ $config = longbingGetAppConfig($this->_uniacid);
+ if(!empty($config) && !empty($config['vr_tittle']))
+ {
+ $cardInfo['vr_tittle'] = $config['vr_tittle'];
+ }else{
+ $cardInfo['vr_tittle'] = lang('panoramic');
+ }
+ }
+
+ $config = longbingGetAppConfig($this->_uniacid);
+ //默认背景音乐
+ if ( !$cardInfo[ 'bg' ] )
+ {
+ $cardInfo[ 'bg' ] = $config[ 'default_voice' ];
+ }
+
+ if ( !$cardInfo[ 'bg_switch' ] )
+ {
+ $cardInfo[ 'bg_switch' ] = $config[ 'default_voice_switch' ];
+ }
+ // 处理图片
+ $cardInfo = transImages( $cardInfo, [ 'images' ], ',' );
+ $cardInfo = transImagesOne( $cardInfo, [ 'avatar', 'voice', 'my_url', 'my_video', 'my_video_cover', 'bg', 'vr_cover',
+ 'vr_path' ]
+ );
+
+ //判断视频等参数
+ $config = longbingGetAppConfig($this->_uniacid);
+
+ //默认视频
+ if(isset($config['default_video']) && empty($cardInfo['my_video'])) $cardInfo['my_video'] = $config['default_video'];
+ //默认视频图片
+ if(isset($config['default_video_cover']) && empty($cardInfo['my_video_cover'])) $cardInfo['my_video_cover'] = $config['default_video_cover'];
+ //默认背景音乐
+ if(isset($config['default_voice']) && empty($cardInfo['bg'])) $cardInfo['bg'] = $config['default_voice'];
+ //VR图片
+ if(isset($config['vr_cover']) && empty($cardInfo['vr_cover'])) $cardInfo['vr_cover'] = $config['vr_cover'];
+ //默认VR路径
+ if(isset($config['vr_path']) && empty($cardInfo['vr_path'])) {
+ $cardInfo['vr_path'] = $config['vr_path'];
+ //默认VR switch
+ $cardInfo['vr_switch'] = $config['vr_switch'];
+ }
+ //默认VR标题
+ if(isset($config['vr_tittle']) && empty($cardInfo['vr_tittle'])) $cardInfo['vr_tittle'] = $config['vr_tittle'];
+ //默认视频(处理)
+ if ( isset( $cardInfo[ 'my_video' ] ) && $cardInfo[ 'my_video' ] ) $cardInfo[ 'my_video_vid' ] = lbGetTencentVideo( $cardInfo[ 'my_video' ] );
+ //设置vr tatile
+ if ( isset( $cardInfo[ 'vr_tittle' ] ) && !$cardInfo[ 'vr_tittle' ] )
+ {
+ $cardInfo[ 'vr_tittle' ] = 'VR全景';
+ }
+
+ if(isset($input['is_update'])&&$input['is_update']!=1){
+ //新的默认配置模型
+ $defult_setting = new DefaultSetting();
+ //默认配置数据
+ $defult_setting_data = $defult_setting->settingInfo(['uniacid'=>$this->_uniacid]);
+
+ $defult_setting_data = transImages($defult_setting_data,['my_photo_cover']);
+ //我的签名
+ $cardInfo['desc'] = !empty($cardInfo['desc'])?$cardInfo['desc']:$defult_setting_data['my_sign'];
+ //我的照片
+ $cardInfo['images'] = !empty($cardInfo['images'])?$cardInfo['images']:$defult_setting_data['my_photo_cover'];
+ //我的照片链接
+ $cardInfo['my_url'] = !empty($cardInfo['my_url'])?$cardInfo['my_url']:$defult_setting_data['my_photo_link'];
+ //个人简介语音
+ $cardInfo['voice'] = !empty($cardInfo['voice'])?$cardInfo['voice']:$defult_setting_data['voice_text'];
+ //我的语音时长
+ $cardInfo['voice_time'] = !empty($cardInfo['voice_time'])?$cardInfo['voice_time']:$defult_setting_data['voice_time'];
+ }
+
+ //获取福报
+// $coupon = CardCoupon::where( [ [ 'end_time', '>', time() ], [ 'status', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] , [ 'number' , '>' , 0]] )
+// ->order( [ 'top' => 'desc', 'id' => 'desc' ] )
+// ->select()
+// ->toArray();
+
+ $coupon_dis = ['status'=>1,'uniacid'=>$this->_uniacid];
+
+ $coupon_model = new IndexCoupon();
+
+ $coupon = $coupon_model->couponListSelect($coupon_dis,$this->getUserId(),$staff_id,100);
+
+ $cardInfo[ 'coupon' ] = array();
+ $cardInfo[ 'coupon_last_record' ] = array();
+ $cardInfo[ 'coupon_last_record_user' ] = array();
+ if ( $coupon )
+ {
+ foreach ( $coupon as $index => $item )
+ {
+ $record_list = CardCouponRecord::where( [ [ 'coupon_id', '=', $item[ 'id' ] ],
+ [ 'staff_id', '=', $params[ 'staff_id' ] ],
+ [ 'uniacid', '=', $this->_uniacid ] ,
+
+ ] )
+ ->order( [ 'id' => 'desc' ] )
+ ->select()
+ ->toArray();
+ if ( count( $record_list ) < $item[ 'number' ] )
+ {
+ $cardInfo[ 'coupon' ] = $item;
+ if ( count( $record_list ) )
+ {
+ $cardInfo[ 'coupon_last_record' ] = $record_list;
+ }
+ break;
+ }
+ }
+ }
+
+
+ if ( !empty( $cardInfo[ 'coupon_last_record' ] ) )
+ {
+
+ foreach ( $cardInfo[ 'coupon_last_record' ] as $index => $item )
+ {
+//
+ $user = longbingGetUser($item[ 'user_id' ] ,$this->_uniacid);
+ if ( mb_strlen( $user[ 'nickName' ], 'utf8' ) > 4 )
+ {
+ $user[ 'nickName' ] = mb_substr( $user[ 'nickName' ], 0, 4, "UTF-8" );
+ }
+
+ $cardInfo[ 'coupon_last_record' ][ $index ][ 'user_info' ] = $user;
+ }
+
+ }
+
+ //数据统计
+ $modelCount = new RadarCount();
+ list( $viewCount, $thumbCount ) = $modelCount->RadarNumber( $staff_id ,$this->_uniacid);
+ $cardInfo[ 'view_count' ] = $viewCount;
+ $cardInfo[ 'thumbCount' ] = $thumbCount;
+
+ // 是否语音点赞
+ $checkVoice = CardCount::where( [ [ 'type', '=', 1 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->count();
+ // 是否给名片点赞
+ $checkThumb = CardCount::where( [ [ 'type', '=', 3 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->count();
+ //递名片
+ $radar_model = new RadarCount();
+ $share_number = $radar_model->getShareNumber($params['staff_id']);
+ if ( $checkVoice )
+ {
+ $cardInfo[ 'voiceThumbs' ] = 1;
+ }
+ else
+ {
+ $cardInfo[ 'voiceThumbs' ] = 0;
+ }
+ if ( $checkThumb )
+ {
+ $cardInfo[ 'isThumbs' ] = 1;
+ }
+ else
+ {
+ $cardInfo[ 'isThumbs' ] = 0;
+ }
+
+ $cardInfo[ 'view_count' ] = $cardInfo[ 'view_count' ] + $cardInfo[ 'view_number' ];
+ $cardInfo[ 'thumbCount' ] = $cardInfo[ 'thumbCount' ] + $cardInfo[ 't_number' ];
+ $cardInfo[ 'share_number' ] = $share_number;
+ $modelTags = new CardTags();
+ $cardInfo[ 'tag_list' ] = $modelTags->cardTagList( $params[ 'staff_id' ], $userId, $this->_uniacid );
+
+
+ //By.jingshuixian
+ //监听获取名片展示信息
+ $eventCardInfoData = event("CardInfo" , $params);
+ //兼容老数据
+ foreach ($eventCardInfoData as $items){
+
+ foreach ($items as $key => $item){
+ if( $key == 'decorate'){ //装修老板兼容
+ $cardInfo['plugin'] = $item ;
+ }else{ //默认都放到根节点上 例如: goods_list
+ $cardInfo[$key] = $item ;
+ }
+ }
+
+ }
+
+ return $this->success( $cardInfo );
+ }
+
+
+ /**
+ * @Purpose: 名片信息
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function cardInfoV3 ()
+ {
+
+ //获取diy的数据
+ $diy_data = DiyModel::where([['status', '=', 1],['uniacid', '=', $this->_uniacid]])->find();
+ //获取商城的
+ $page_data= json_decode($diy_data['page'], true)[1] ?? [];
+ //判断有没有diy过
+ if(empty($page_data)|| (array_key_exists('list',$page_data) && empty($page_data['list']))){
+
+ $page_data = longbing_default_Page(1);
+
+ }
+ //获取用户id
+ $userId = (string) $this->getUserId();
+ $uniacid = $this->_uniacid;
+
+ //获取必要参数
+ $verify = [ 'staff_id' => 'required' ,'is_base' => 0];
+ $params = lbGetParamVerify( $this->_param, $verify );
+ $input = $this->_param;
+ $staff_id = $params['staff_id'];
+ //获取员工数据
+ $cardInfo = longbingGetUserCard($staff_id ,$this->_uniacid);
+ if(empty($cardInfo) || empty($cardInfo['is_staff'])) return $this->error(lang('card info not found') ,403);
+ //判断名片是否拥有职位(没有就默认)
+ if ( !$cardInfo[ 'job_name' ] )
+ {
+ $cardInfo[ 'job_name' ] = lang('not set job');
+ }
+ //获取名片码
+ $card_code_data = ["data" => ["staff_id" => $params['staff_id'] ,"pid" => $userId ,"type" => 4 ,"key" => 1]];
+ $qr_path = 'image/' . $this->_uniacid . '/' . 'wxcode/' . md5($this->_uniacid . json_encode($card_code_data ,true)) . '.jpeg';
+ if(longbingHasLocalFile($qr_path))
+ {
+ $cardInfo['qr_path'] = $qr_path;
+ }else{
+// $wxcode_data = longbingCreateWxCode($this->_uniacid ,$card_code_data);
+// if(isset($wxcode_data['path']) && !empty($wxcode_data['path'])) $cardInfo['qr_path'] = $wxcode_data['path'];
+ $push_data = array(
+ 'action' => 'longbingCreateWxCode',
+ 'event' => 'longbingCreateWxCode',
+ 'uniacid' => $this->_uniacid,
+ 'data' => $card_code_data,
+ 'page' => '',
+ 'type' => 3
+ );
+ publisher(json_encode($push_data ,true));
+
+ $cardInfo['qr_path'] = $qr_path;
+
+ }
+
+ if(!empty($cardInfo['qr_path'])) $cardInfo = transImagesOne($cardInfo ,['qr_path']);
+
+ $modelCompany = new Company();
+
+ //检查公司默认数据
+ if ( empty($cardInfo['company_info']) )
+ {
+ //jingshuixian 0 = $cardInfo['fans_id']
+ $company = $modelCompany->getInfo( $this->_uniacid, $cardInfo['fans_id'], 0 );
+
+ $cardInfo[ 'company_info' ] = $company;
+ if(isset($company['name'])) $company_name = $company['name'];
+ }
+ $cardInfo[ 'company_info' ] = $modelCompany->changeTopName($cardInfo[ 'company_info' ]);
+
+ $cardInfo['company_name'] = !empty($cardInfo[ 'company_info' ]['name'])? $cardInfo[ 'company_info' ]['name']:$cardInfo['company_name'];
+
+ //设置分享数据
+ if(isset($cardInfo['share_text']) && !empty($cardInfo['share_text']))
+ {
+ $share_text = $cardInfo['share_text'];
+
+ if(strpos($share_text,'#公司#')) $share_text = str_replace('#公司#',$cardInfo[ 'company_name' ],$share_text);
+
+ if(strpos($share_text,'#职务#')) $share_text = str_replace('#职务#',$cardInfo[ 'job_name' ],$share_text);
+
+ if(strpos($share_text,'#我的名字#')) $share_text = str_replace('#我的名字#',$cardInfo[ 'name' ],$share_text);
+
+ if(strpos($share_text,'$company')) $share_text = str_replace('$company',$cardInfo[ 'company_name' ],$share_text);
+
+ if(strpos($share_text,'$job')) $share_text = str_replace('$job',$cardInfo[ 'job_name' ],$share_text);
+
+ if(strpos($share_text,'$name')) $share_text = str_replace('$name',$cardInfo[ 'name' ],$share_text);
+ $cardInfo['share_text'] = $share_text;
+ }else{
+
+// $cardInfo['share_text'] = lang("card share text");
+ $cardInfo['share_text'] = '您好,我是'.$cardInfo[ 'company_name' ].'的'.$cardInfo[ 'job_name' ].$cardInfo[ 'name' ].',请惠存';
+ }
+ //名片分享链接
+ $cardInfo['share_img'] = "images/share_img/{$uniacid}/share-{$staff_id}.png";
+ // var_dump($cardInfo['share_img']);die;
+ if(!longbingHasLocalFile($cardInfo['share_img'])) {
+ $user['share_img'] = null;
+ $cardInfo['share_img'] = null;
+ }else{
+ $cardInfo = transImagesOne($cardInfo, ['share_img']);
+ }
+
+
+
+
+ //更新最后查看信息
+ //By.jingshuixian 最后访问的员工ID不同是更新
+// if(!in_array($userId, [$params[ 'staff_id' ]]))
+// {
+ $user_update = User::update( [ 'last_staff_id' => $params[ 'staff_id' ] ], [ 'id' => $userId] );
+ if(!empty($user_update)){
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ $user['last_staff_id'] = $params[ 'staff_id' ];
+ longbingSetUser($userId ,$this->_uniacid ,$user);
+ }
+// }
+
+
+ //是否只需要基础数据======================================================================================================有返回结果==============================
+ if(isset($params['is_base']) && !empty($params['is_base']))
+ {
+ $cardInfo = transImagesOne( $cardInfo, [ 'avatar']);
+ return $this->success($cardInfo);
+ }
+ //是否只需要基础数据======================================================================================================有返回结果==============================
+
+
+ //默认vr数据
+ if(!isset($cardInfo['vr_tittle']) || empty($cardInfo['vr_tittle']))
+ {
+ $config = longbingGetAppConfig($this->_uniacid);
+ if(!empty($config) && !empty($config['vr_tittle']))
+ {
+ $cardInfo['vr_tittle'] = $config['vr_tittle'];
+ }else{
+ $cardInfo['vr_tittle'] = lang('panoramic');
+ }
+ }
+
+ $config = longbingGetAppConfig($this->_uniacid);
+ //默认背景音乐
+ if ( !$cardInfo[ 'bg' ] )
+ {
+ $cardInfo[ 'bg' ] = $config[ 'default_voice' ];
+ }
+
+ if ( !$cardInfo[ 'bg_switch' ] )
+ {
+ $cardInfo[ 'bg_switch' ] = $config[ 'default_voice_switch' ];
+ }
+ // 处理图片
+ $cardInfo = transImages( $cardInfo, [ 'images' ], ',' );
+ $cardInfo = transImagesOne( $cardInfo, [ 'avatar', 'voice', 'my_url', 'my_video', 'my_video_cover', 'bg', 'vr_cover',
+ 'vr_path' ]
+ );
+
+ //判断视频等参数
+ $config = longbingGetAppConfig($this->_uniacid);
+
+ //默认视频
+ if(isset($config['default_video']) && empty($cardInfo['my_video'])) $cardInfo['my_video'] = $config['default_video'];
+ //默认视频图片
+ if(isset($config['default_video_cover']) && empty($cardInfo['my_video_cover'])) $cardInfo['my_video_cover'] = $config['default_video_cover'];
+ //默认背景音乐
+ if(isset($config['default_voice']) && empty($cardInfo['bg'])) $cardInfo['bg'] = $config['default_voice'];
+ //VR图片
+ if(isset($config['vr_cover']) && empty($cardInfo['vr_cover'])) $cardInfo['vr_cover'] = $config['vr_cover'];
+ //默认VR路径
+ if(isset($config['vr_path']) && empty($cardInfo['vr_path'])) {
+ $cardInfo['vr_path'] = $config['vr_path'];
+ //默认VR switch
+ $cardInfo['vr_switch'] = $config['vr_switch'];
+ }
+ //默认VR标题
+ if(isset($config['vr_tittle']) && empty($cardInfo['vr_tittle'])) $cardInfo['vr_tittle'] = $config['vr_tittle'];
+ //默认视频(处理)
+ if ( isset( $cardInfo[ 'my_video' ] ) && $cardInfo[ 'my_video' ] ) $cardInfo[ 'my_video_vid' ] = lbGetTencentVideo( $cardInfo[ 'my_video' ] );
+ //设置vr tatile
+ if ( isset( $cardInfo[ 'vr_tittle' ] ) && !$cardInfo[ 'vr_tittle' ] )
+ {
+ $cardInfo[ 'vr_tittle' ] = 'VR全景';
+ }
+
+ if(empty($input['is_update'])){
+ //新的默认配置模型
+ $defult_setting = new DefaultSetting();
+ //默认配置数据
+ $defult_setting_data = $defult_setting->settingInfo(['uniacid'=>$this->_uniacid]);
+
+ $defult_setting_data = transImages($defult_setting_data,['my_photo_cover']);
+ //我的签名
+ $cardInfo['desc'] = !empty($cardInfo['desc'])?$cardInfo['desc']:$defult_setting_data['my_sign'];
+ //我的照片
+ $cardInfo['images'] = !empty($cardInfo['images'])?$cardInfo['images']:$defult_setting_data['my_photo_cover'];
+ //我的照片链接
+ $cardInfo['my_url'] = !empty($cardInfo['my_url'])?$cardInfo['my_url']:$defult_setting_data['my_photo_link'];
+ //个人简介语音
+ $cardInfo['voice'] = !empty($cardInfo['voice'])?$cardInfo['voice']:$defult_setting_data['voice_text'];
+ //我的语音时长
+ $cardInfo['voice_time'] = !empty($cardInfo['voice_time'])?$cardInfo['voice_time']:$defult_setting_data['voice_time'];
+ }
+
+ //获取福报
+// $coupon = CardCoupon::where( [ [ 'end_time', '>', time() ], [ 'status', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] , [ 'number' , '>' , 0]] )
+// ->order( [ 'top' => 'desc', 'id' => 'desc' ] )
+// ->select()
+// ->toArray();
+
+ $coupon_model = new IndexCoupon();
+ //循环diy获取优惠券样式
+ foreach ($page_data['list'] as &$value){
+
+ if($value['type']=='couponList'&&empty($value['data']['dataList'])) {
+
+ $coupon_dis = ['status'=>1,'uniacid'=>$this->_uniacid];
+
+ $dataList = $coupon_model->couponListSelect($coupon_dis,$this->getUserId(),$staff_id);
+
+ if(!empty($dataList)){
+ //列表样式
+ if($value['data']['type']==2){
+
+ $value['data']['dataList'] = $dataList;
+
+ $cardInfo['coupon'] = $dataList;
+
+ }else{
+ //弹窗样式
+ $cardInfo['coupon'] = $dataList[0];
+ //领取记录
+ $r_dis = [
+ //优惠券id
+ 'coupon_id' => $dataList[0]['id'],
+ //员工
+ 'staff_id' => $staff_id,
+ //uniacid
+ 'uniacid' => $this->_uniacid
+ ];
+ $cardInfo['coupon_last_record'] = CardCouponRecord::where($r_dis)->order('id desc')->limit(3)->select()->toArray();
+
+ if ( !empty( $cardInfo[ 'coupon_last_record' ] ) )
+ {
+
+ foreach ( $cardInfo[ 'coupon_last_record' ] as $index => $item )
+ {
+//
+ $user = longbingGetUser($item[ 'user_id' ] ,$this->_uniacid);
+ if ( mb_strlen( $user[ 'nickName' ], 'utf8' ) > 4 )
+ {
+ $user[ 'nickName' ] = mb_substr( $user[ 'nickName' ], 0, 4, "UTF-8" );
+ }
+
+ $cardInfo[ 'coupon_last_record' ][ $index ][ 'user_info' ] = $user;
+ }
+
+ }
+ }
+ }
+
+ }
+ }
+ //数据统计
+ $modelCount = new RadarCount();
+ list( $viewCount, $thumbCount ) = $modelCount->RadarNumber( $staff_id ,$this->_uniacid);
+ $cardInfo[ 'view_count' ] = $viewCount;
+ $cardInfo[ 'thumbCount' ] = $thumbCount;
+
+ // 是否语音点赞
+ $checkVoice = CardCount::where( [ [ 'type', '=', 1 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->count();
+ // 是否给名片点赞
+ $checkThumb = CardCount::where( [ [ 'type', '=', 3 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->count();
+ //递名片
+ $radar_model = new RadarCount();
+ $share_number = $radar_model->getShareNumber($params['staff_id']);
+ if ( $checkVoice )
+ {
+ $cardInfo[ 'voiceThumbs' ] = 1;
+ }
+ else
+ {
+ $cardInfo[ 'voiceThumbs' ] = 0;
+ }
+ if ( $checkThumb )
+ {
+ $cardInfo[ 'isThumbs' ] = 1;
+ }
+ else
+ {
+ $cardInfo[ 'isThumbs' ] = 0;
+ }
+
+
+
+ $cardInfo[ 'view_count' ] = $cardInfo[ 'view_count' ] + $cardInfo[ 'view_number' ];
+ $cardInfo[ 'thumbCount' ] = $cardInfo[ 'thumbCount' ] + $cardInfo[ 't_number' ];
+ $cardInfo[ 'share_number' ] = $share_number;
+ $modelTags = new CardTags();
+ $cardInfo[ 'tag_list' ] = $modelTags->cardTagList( $params[ 'staff_id' ], $userId, $this->_uniacid );
+
+
+ //By.jingshuixian
+ //监听获取名片展示信息
+ $eventCardInfoData = event("CardInfo" , $params);
+
+ //兼容老数据
+ foreach ($eventCardInfoData as $items){
+
+ foreach ($items as $key => $item){
+ if( $key == 'decorate'){ //装修老板兼容
+ $cardInfo['plugin'] = $item ;
+ }else{ //默认都放到根节点上 例如: goods_list
+ $cardInfo[$key] = $item ;
+ }
+ }
+
+ }
+ $arr_data['card_info'] = $cardInfo;
+
+ $arr_data['list'] = $page_data['list'];
+
+ return $this->success( $arr_data );
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-18 16:11
+ * @功能说明:默认配置
+ */
+ public function defaultSetting(){
+
+ $d_model = new DefaultSetting();
+
+ $data = $d_model->settingInfo(['uniacid'=>$this->_uniacid]);
+
+ return $this->success( $data );
+ }
+ /**
+ * 获取统计数据
+ */
+
+ public function getCardCount()
+ {
+ //获取用户id
+ $userId = $this->getUserId();
+ $uniacid = $this->_uniacid;
+ //获取必要参数
+ $verify = [ 'staff_id' => 'required' ];
+ $params = lbGetParamVerify( $this->_param, $verify );
+ $staff_id = $params['staff_id'];
+ //获取员工数据
+ $cardInfo_default = longbingGetUserCard($staff_id ,$this->_uniacid);
+ if(empty($cardInfo_default) || empty($cardInfo_default['is_staff'])) return $this->success([]);
+ $cardInfo=[];
+
+
+ // 名片最近浏览情况
+ $modelCount = new RadarCount();
+ list( $cardInfo[ 'view_list' ] ) = $modelCount->getCardViewInfo( $params[ 'staff_id' ], $this->_uniacid );
+ return $this->success($cardInfo);
+ }
+ /**
+ * @Purpose: 编辑自我描述
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editDesc ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'desc' => '' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $card = UserInfo::where( [ [ 'fans_id', '=', $userId ], [ 'is_staff', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->field( [ 'desc' ] )
+ ->find();
+
+ if ( !$card )
+ {
+ $this->error( 'card info not found', 402 );
+ }
+
+ $card->desc = $params[ 'desc' ] ?? '';
+ $result = $card->save();
+
+ if ( $result === false )
+ {
+ $this->error( 'edit fail', 402 );
+ }else{
+ //清除名片缓存
+ $key = 'longbing_card_info_' . $userId;
+ delCache($key ,$this->_uniacid);
+ }
+ longbingGetUserInfo($userId ,$this->_uniacid ,true);
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 编辑名片详情图片
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editImages ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'images' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $card = UserInfo::where( [ [ 'fans_id', '=', $userId ], [ 'is_staff', '=', 1 ], [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->field( [ 'images' ] )
+ ->find();
+
+ if ( !$card )
+ {
+ $this->error( 'card info not found', 402 );
+ }
+
+
+ $params[ 'images' ] = implode(',', $params[ 'images' ]);
+
+
+ $card->images = trim( $params[ 'images' ], ',' );
+ $result = $card->save();
+
+ if ( $result === false )
+ {
+ $this->error( 'edit fail', 402 );
+ }else{
+ //清除名片缓存
+ $key = 'longbing_card_info_' . $userId;
+ delCache($key ,$this->_uniacid);
+ }
+ longbingGetUserInfo($userId ,$this->_uniacid ,true);
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 创建 / 修改名片
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function createCard ()
+ {
+ $userId = $this->getUserId();
+ $uniacid = $this->_uniacid;
+
+ $verify = [ 'avatar' => '', 'name' => 'required', 'job_id' => 'required', 'phone' => 'required', 'email' => '',
+ 'company_id' => 'required', 'auth_code' => '', 'ww_account' => '', 'telephone' => '', 'wechat' => '' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+ //微信库类
+ $service_model = new WxSetting($this->_uniacid);
+ //违禁词检查
+ $rest = $service_model->wxContentRlue($params['name']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('内容含有违法违规内容');
+ }
+
+
+ $modelConfig = new Config();
+
+// $config = $modelConfig->getConfig( $this->_uniacid );
+ //获取配置信息
+ $config = longbingGetAppConfig($this->_uniacid);
+
+ $defaultCode = $config[ 'code' ];
+
+ $companyInfo = $this->modelCompany->getInfo( $this->_uniacid, 0, $params[ 'company_id' ] );
+
+ if ( !$companyInfo )
+ {
+ return $this->error( lang('not the company') );
+ }
+
+ $modelCompany= new Company();
+
+ $companyInfo = $modelCompany->changeTopName($companyInfo);
+ //获取工作信息
+ $job_model = new CardJob();
+ $job = $job_model->getJob(['uniacid' => $uniacid ,'id' => $params['job_id']]);
+ if(empty($job)) return $this->error( lang('not the job') );
+ $companyCode = $companyInfo[ 'auth_code' ];
+
+ // 是否需要免审口令
+ $code = '';
+ if ( $companyCode )
+ {
+ $code = $companyCode;
+ }
+ if ( !$code && $defaultCode )
+ {
+ $code = $defaultCode;
+ }
+
+
+ $modelUserInfo = new UserInfo();
+ $userInfo = $modelUserInfo->where( [ [ 'fans_id', '=', $userId ], [ 'uniacid', '=', $this->_uniacid ] ] )
+ ->find();
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ if ( $code && $code != $params[ 'auth_code' ] && empty($user['is_staff']))
+ {
+ if(isset($params['auth_code']) && !empty($params['auth_code']))
+ {
+ if(isset($config['btn_code_err']) && !empty($config['btn_code_err']))
+ {
+ return $this->error($config['btn_code_err'] ,402);
+ }
+ }else{
+ if(isset($config['btn_code_miss']) && !empty($config['btn_code_miss']))
+ {
+ return $this->error($config['btn_code_miss'] ,402);
+ }
+ }
+ return $this->error(lang('code error') ,402);
+ }
+
+
+ // 编辑
+ if(empty($userInfo) || empty($userInfo['is_staff']))
+ {
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+ if(!empty($permissions) && isset($permissions['card_number']) && !empty($permissions['card_number']) && !(longbingGetCardNum($this->_uniacid) < $permissions['card_number']))
+ {
+ return $this->error(lang('not card num'));
+ }
+ }
+ if ( $userInfo )
+ {
+ $userInfo->avatar = $params[ 'avatar' ];
+ $userInfo->name = $params[ 'name' ];
+ $userInfo->job_id = $params[ 'job_id' ];
+ $userInfo->phone = $params[ 'phone' ];
+ $userInfo->email = $params[ 'email' ];
+ $userInfo->company_id = $params[ 'company_id' ];
+ $userInfo->ww_account = $params[ 'ww_account' ];
+ $userInfo->telephone = $params[ 'telephone' ];
+
+ $userInfo->wechat = !empty($params[ 'wechat' ])?$params[ 'wechat' ]:'';
+
+ $userInfo->is_staff = 1;
+
+ User::update( [ 'is_staff' => 1 ], [ 'id' => $userId ] );
+
+ $result = $userInfo->save();
+ //清除名片缓存
+ $key = 'longbing_card_info_' . $userId;
+ delCache($key ,$this->_uniacid);
+ }
+ // 创建
+ else
+ {
+
+
+ $modelUserInfo = new UserInfo();
+ $modelUserInfo->uniacid = $this->_uniacid;
+ $modelUserInfo->fans_id = $userId;
+ $modelUserInfo->avatar = $params[ 'avatar' ];
+ $modelUserInfo->name = $params[ 'name' ];
+ $modelUserInfo->job_id = $params[ 'job_id' ];
+ $modelUserInfo->phone = $params[ 'phone' ];
+ $modelUserInfo->email = $params[ 'email' ];
+ $modelUserInfo->company_id = $params[ 'company_id' ];
+ $modelUserInfo->ww_account = $params[ 'ww_account' ];
+ $modelUserInfo->telephone = $params[ 'telephone' ];
+ $modelUserInfo->wechat = $params[ 'wechat' ];
+ $modelUserInfo->is_staff = 1;
+ $modelUserInfo->auto_count = longbingGetUserInfoMinAutoCount($this->_uniacid);;
+ $modelUserInfo->is_default = 1;
+ User::update( [ 'is_staff' => 1 ], [ 'id' => $userId ] );
+// if ( $is_staff )
+// {
+// User::update( [ 'is_staff' => $is_staff ], [ 'id' => $userId ] );
+// }
+ $result = $modelUserInfo->save();
+
+ }
+
+
+ //By.jingshuixian 判断是否拥有分公司的boss权限
+ $permissions = new PermissionBoss($uniacid);
+ //有分公司权限 自动绑定当前公司
+ if( $permissions->pAuth() ) {
+ //如果没有Boss信息就绑定一个
+ $bossData = CardBoss::where( [ [ 'user_id', '=', $userId ] , ['uniacid' , '=' , $this->_uniacid ] ] )->find();
+ if(empty($bossData)){
+ CardBoss::create( [ 'user_id' => $userId , 'boss' => $params[ 'company_id' ], 'uniacid' => $this->_uniacid ] );
+ }
+ }
+
+
+ if ( $result === false )
+ {
+ return $this->error( 'operation failed' );
+ }else{
+ //画像
+ $file_path = "images/share_img/{$uniacid}/share-{$userId}.png";
+// longbingchmodr(FILE_UPLOAD_PATH);
+ if(longbingHasLocalFile($file_path)) unlink(FILE_UPLOAD_PATH . $file_path);
+ $params = transImagesOne($params ,['avatar']);
+ $gData = array(
+ 'company_logo' => $companyInfo['logo'],
+ 'company_name' => longbingSortStr ( $companyInfo['name'] ,10),
+ 'name' => longbingSortStr ( $params[ 'name' ] ,10),
+ 'job' => longbingSortStr ( $job['name'] ,10),
+ 'phone' => longbingSortStr ( $params[ 'phone' ] ,12),
+ 'email' => longbingSortStr ( $params[ 'email' ] ,18),
+ 'address' => longbingSortStr ( $companyInfo['addr'] ,10),
+ 'img' => $params['avatar']
+ );
+ if(empty($gData['company_logo'])) $gData['company_logo'] = $this->defaultImage['image'];
+ if(empty($gData['img'])) $gData['img'] = $this->defaultImage['avatar'];
+
+ try{
+// longbingCreateSharePng( $gData, $userId, $uniacid );
+ $push_data = array(
+ 'action' => 'longbingCreateSharePng',
+ 'event' => 'longbingCreateSharePng',
+ 'gData' => $gData,
+ 'user_id' => $userId,
+ 'uniacid' => $uniacid
+ );
+ publisher(json_encode($push_data ,true));
+// longbingCreateWxCode($data['gData'] ,$data['user_id'] ,$data['uniacid']);
+ }catch (Exception $e) { }
+ }
+ longbingGetUser($userId ,$this->_uniacid ,true);
+ longbingGetUserInfo($userId ,$this->_uniacid ,true);
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 点赞 / 取消点赞 名片 / 语音
+ *
+ * @Param: $type number 操作类型 0 = 名片 1 = 语音
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function thumbStaff ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'staff_id' => 'required', 'type' => 0 ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ if ( $params[ 'type' ] == 0 )
+ {
+ // 是否给名片点赞
+ $check = CardCount::where( [ [ 'type', '=', 3 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->find();
+ $type = 3;
+ }
+ else
+ {
+ // 是否语音点赞
+ $check = CardCount::where( [ [ 'type', '=', 1 ], [ 'user_id', '=', $userId ],
+ [ 'to_uid', '=', $params[ 'staff_id' ] ], [ 'sign', '=', 'praise' ] ]
+ )
+ ->find();
+ $type = 1;
+ }
+
+
+ if ( $check )
+ {
+ $check = $check->toArray();
+ $result = CardCount::where( [ [ 'id', '=', $check[ 'id' ] ] ] )
+ ->delete();
+ }
+ else {
+
+
+ $result = CardCount::create( [ 'type' => $type, 'user_id' => $userId, 'to_uid' => $params[ 'staff_id' ],
+ 'sign' => 'praise', 'uniacid' => $this->_uniacid ]
+ );
+ }
+
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 点赞 / 取消点赞 印象标签
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function thumbTag ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'tag_id' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $check = CardUserTags::where( [ [ 'user_id', '=', $userId ], [ 'tag_id', '=', $params[ 'tag_id' ] ] ] )
+ ->find();
+
+ if ( $check )
+ {
+ CardUserTags::where( [ [ 'id', '=', $check[ 'id' ] ] ] )
+ ->delete();
+ CardTags::where( [ [ 'id', '=', $check[ 'tag_id' ] ] ] )
+ ->dec( 'count' )
+ ->update();
+ }
+ else
+ {
+ CardUserTags::create( [ 'user_id' => $userId, 'tag_id' => $params[ 'tag_id' ], 'uniacid' => $this->_uniacid ] );
+ CardTags::where( [ [ 'id', '=', $params[ 'tag_id' ] ] ] )
+ ->inc( 'count' )
+ ->update();
+ }
+
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 收集formId
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getFormIdFromMini ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'form_id' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $data = explode( ',', $params[ 'form_id' ] );
+ $insertData = [];
+ foreach ( $data as $index => $item )
+ {
+ if ($item !== 'the formId is a mock one')
+ {
+ $insertData[] = [ 'user_id' => $userId, 'formId' => $item, 'uniacid' => $this->_uniacid ];
+ }
+ }
+ if(empty($insertData)) return $this->success( [] );
+ $push_data = array(
+ 'action' => 'longbingSaveFormId',
+ 'event' => 'longbingSaveFormId',
+ 'data' => $insertData
+ );
+ publisher(json_encode($push_data ,true));
+
+ return $this->success( [] );
+ }
+
+ /**
+ * @Purpose: 上报手机号
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function reportPhone ()
+ {
+ $userId = $this->getUserId();
+
+
+ $verify = [ 'staff_id' => 'required', 'encryptedData' => 'required', 'iv' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $staff_id = $params[ 'staff_id' ];
+ $uniacid = $this->_uniacid;
+ $encryptedData = $params[ 'encryptedData' ];
+ $iv = $params[ 'iv' ];
+
+ $info = UserPhone::where( [ [ 'user_id', '=', $userId ], [ 'uniacid', '=', $uniacid ] ] )
+ ->find();
+
+ if ( $info )
+ {
+ return $this->success( [ 'phone' => $info[ 'phone' ], 'new' => 3, 'iv' => $iv ] );
+ }
+
+
+ $config = longbingGetAppConfig($this->_uniacid);
+ // var_dump(json_encode($config));die;
+ $appid = $config[ 'appid' ];
+ $appsecret = $config[ 'app_secret' ];
+
+
+ $check_sk = UserSk::where( [ [ 'user_id', '=', $userId ] ] )
+ ->find();
+ if ( !$check_sk )
+ {
+ return $this->error( -1, 'need login', [] );
+ }
+ else
+ {
+ $session_key = $check_sk[ 'sk' ];
+ }
+
+
+ $data = null;
+ // 解密
+ $errCode = decryptDataLongbing( $appid, $session_key, $encryptedData, $iv, $data );
+// $errCode = baiduDecryptDataLongbing( $appid, $session_key, $encryptedData, $iv, $data );
+
+ if ( $errCode == 0 )
+ {
+ $data = json_decode( $data, true );
+
+ $phone = $data[ 'purePhoneNumber' ];
+
+ }
+ else
+ {
+ return $this->error( $errCode );
+ }
+
+ $data = [ 'user_id' => $userId, 'to_uid' => $params[ 'staff_id' ], 'phone' => $phone, 'uniacid' => $uniacid ];
+ $data = UserPhone::create( $data );
+ if(!empty($data))
+ {
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ $user['phone'] = $phone;
+ longbingSetUser($userId ,$this->_uniacid ,$user);
+ }
+ return $this->success( [ 'phone' => $phone, 'new' => 1, ] );
+ }
+
+
+ /**
+ * @Purpose: 上报手机号
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function baiduReportPhone ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'staff_id' => 'required', 'encryptedData' => 'required', 'iv' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $staff_id = $params[ 'staff_id' ];
+ $uniacid = $this->_uniacid;
+ $encryptedData = $params[ 'encryptedData' ];
+ $iv = $params[ 'iv' ];
+
+ $info = UserPhone::where( [ [ 'user_id', '=', $userId ], [ 'uniacid', '=', $uniacid ] ] )
+ ->find();
+
+ if ( $info )
+ {
+ return $this->success( [ 'phone' => $info[ 'phone' ], 'new' => 3, 'iv' => $iv ] );
+ }
+
+
+ $config = Db::name('longbing_card_baidu_setting')->where(['uniacid'=>$this->_uniacid])->find();
+ $appid = $config[ 'client_id' ];
+ $appsecret = $config[ 'client_secret' ];
+
+
+ $check_sk = UserSk::where( [ [ 'user_id', '=', $userId ] ] )->find();
+ if ( !$check_sk )
+ {
+ return $this->error( -1, 'need login', [] );
+ }
+ else
+ {
+ $session_key = $check_sk[ 'sk' ];
+ }
+
+ $data = null;
+ // 解密
+ $errCode = baiduDecryptDataLongbing( $encryptedData,$iv,$appid, $session_key);
+
+
+ if ( $errCode!=false)
+ {
+ $errCode = json_decode($errCode,true);
+ $phone = $errCode['mobile'];
+ } else {
+ return $this->error( $errCode );
+ }
+ $data = [ 'user_id' => $userId, 'to_uid' => $params[ 'staff_id' ], 'phone' => $phone, 'uniacid' => $uniacid ];
+ $data = UserPhone::create( $data );
+ if(!empty($data))
+ {
+ $user = longbingGetUser($userId ,$this->_uniacid);
+ $user['phone'] = $phone;
+ longbingSetUser($userId ,$this->_uniacid ,$user);
+ }
+ return $this->success( [ 'phone' => $phone, 'new' => 1, ] );
+ }
+
+ /**
+ * @Purpose: 编辑标签回显数据
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function reviewTags ()
+ {
+ $userId = $this->getUserId();
+
+ $staffTags = CardTags::where( [ [ 'user_id', '=', $userId ], [ 'uniacid', '=', $this->_uniacid ], [ 'status', '=', 1 ] ] )
+ ->field( [ 'id', 'tag', 'count' ] )
+ ->select()
+ ->toArray();
+
+ $sysTags = CardTags::where( [ [ 'user_id', '=', 0 ], [ 'uniacid', '=', $this->_uniacid ], [ 'status', '=', 1 ] ] )
+ ->field( [ 'id', 'tag', 'count' ] )
+ ->select()
+ ->toArray();
+
+ foreach ( $sysTags as $index => $item )
+ {
+ $sysTags[ $index ][ 'selected' ] = 0;
+ foreach ( $staffTags as $index2 => $item2 )
+ {
+ if ( $item2[ 'tag' ] == $item[ 'tag' ] )
+ {
+ $sysTags[ $index ][ 'selected' ] = 1;
+ break;
+ }
+ }
+ }
+
+ $data[ 'staffTags' ] = $staffTags;
+ $data[ 'sysTags' ] = $sysTags;
+
+ return $this->success( $data );
+ }
+
+ /**
+ * @Purpose: 编辑标签
+ *
+ * @Method POST
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function editTags ()
+ {
+ $userId = $this->getUserId();
+
+ $verify = [ 'tags' => 'required' ];
+
+ $params = lbGetParamVerify( $this->_input, $verify );
+
+ $model = new CardTags();
+
+ $staffTags = $model->where( [ [ 'user_id', '=', $userId ], [ 'uniacid', '=', $this->_uniacid ], [ 'status', '=', 1 ] ] )
+ ->field( [ 'id', 'tag', 'count' ] )
+ ->select()
+ ->toArray();
+
+ $tmpArr = [];
+
+ $updateData = [];
+
+ foreach ( $staffTags as $index => $item )
+ {
+ $tmpArr[] = $item[ 'tag' ];
+ if ( !in_array( $item[ 'tag' ], $params[ 'tags' ] ) )
+ {
+ $updateData[] = [ 'id' => $item[ 'id' ], 'status' => -1 ];
+ }
+ }
+ if ( !empty( $updateData ) )
+ {
+ $model->saveAll( $updateData );
+ }
+
+ $insertData = [];
+
+ foreach ( $params[ 'tags' ] as $index => $item )
+ {
+ if ( !in_array( $item, $tmpArr ) )
+ {
+ $insertData[] = [ 'user_id' => $userId, 'tag' => $item, 'count' => 0, 'uniacid' => $this->_uniacid, 'status' => 1,
+ 'top' => 0 ];
+ }
+ }
+ if ( !empty( $insertData ) )
+ {
+ $model->saveAll( $insertData );
+ }
+
+
+ return $this->success( [] );
+ }
+ //收藏名片
+ public function collectionCard()
+ {
+ //获取用户信息
+ $userInfo = $this->getUserInfo();
+ $userId = $this->getUserId();
+ //获取参数
+ $input = $this->_input;
+ if(isset($input['collection'])) $input =$input['collection'] ;
+ //判断员工id是否存在
+// if(!isset($input['staff_id']) || empty($input['staff_id'])) return $this->error(lang('not staff id ,please check param.'));
+ if(!isset($input['staff_id']) || empty($input['staff_id'])) return $this->success([]);
+ //检查员工是否已被收藏
+ $check_filter = array(
+ 'uniacid' => $this->_uniacid,
+ 'uid' => $userId,
+ 'to_uid' => $input['staff_id']
+ );
+ $check = $this->modelCollection->checkCollection($check_filter);
+// var_dump($check);die;
+// if(!empty($check) && isset($check['status']) && in_array($check['status'], ['1' ,1])) return $this->error(lang('the card has been collected ,Please don not double collect'));
+ if(!empty($check) && isset($check['status']) && in_array($check['status'], ['1' ,1])) return $this->success([]);
+ //检查员工是否存在
+ $staff = longbingGetUserInfo($input['staff_id'] ,$this->_uniacid);
+ //检查被收藏的员工是否存在和是否是员工
+// if(!isset($staff['is_staff']) || empty($staff['is_staff'])) return $this->error(lang('the staff is not exist.'));
+ if(!isset($staff['is_staff']) || empty($staff['is_staff'])) return $this->success([]); //Update by jingshuixian $this->success([])
+ //判断来源
+ if(isset($input['from_uid']))
+ {
+ $from_user = longbingGetUser($input['from_uid'] ,$this->_uniacid);
+ if(!empty($from_user)) $check_filter['from_uid'] = $input['from_uid'];
+ }
+ //判断encryptedData 和 iv是否存在
+ if(isset($input['encryptedData'])){
+ if(!isset($input['iv'])) $input['iv'] = '';
+ //获取session key
+ $sk = longbingGetUserSk($userId ,$this->_uniacid);
+ //获取appid
+ $appid = null;
+ //获取config
+ $config = longbingGetAppConfig($this->_uniacid);
+ if(isset($config['appid']) && !empty($config['appid'])) $appid = $config['appid'];
+ //判断session key 是否存在
+ if(!empty($sk) && !empty($appid)) {
+ $data = null;
+ $errCode = decryptDataLongbing( $appid, $sk, $input['encryptedData'], $input['iv'], $data );
+ // 判断解密是否有错误
+ if ( $errCode == 0 )
+ {
+ $data = json_decode( $data, true );
+ $check_filter['openGId'] = $data[ 'openGId' ];
+ }
+ }
+ }
+ //判断scene是否存在
+ if(isset($input['scene'])) $check_filter['scene'] = $input['scene'];
+ //判断type是否存在
+ if(isset($input['type'])) $check_filter['type'] = $input['type'];
+ //创建收藏关系
+ $result = false;
+ if(empty($check)){
+ $result = $this->modelCollection->createCollection($check_filter);
+ }else{
+ $check_filter['status'] = 1;
+ $result = $this->modelCollection->updateCollection(['id' => $check['id']] ,$check_filter);
+ }
+ return $this->success([]);
+// return $this->success($result);
+ }
+
+ //取消收藏
+ public function unCollectionCard()
+ {
+ //获取用户信息
+ $userInfo = $this->getUserInfo();
+ $userId = $this->getUserId();
+ //获取参数
+ $input = $this->_input;
+ if(isset($input['collection'])) $input =$input['collection'] ;
+ //判断员工id是否存在
+ if(!isset($input['staff_id']) || empty($input['staff_id'])) return $this->error(lang('not staff id ,please check param.'));
+ //检查员工是否已被收藏
+ $check_filter = array(
+ 'uniacid' => $this->_uniacid,
+ 'uid' => $userId,
+ 'to_uid' => $input['staff_id']
+ );
+ $check = $this->modelCollection->checkCollection($check_filter);
+ if(empty($check) || !isset($check['status']) || !in_array($check['status'], ['1' ,1])) return $this->error(lang('the card has not been collected ,Please collect'));
+ //创建收藏关系
+ $result = $this->modelCollection->updateCollection(['id' => $check['id']] ,['status' => 0]);
+ return $this->success($result);
+ }
+
+ //生成小程序码
+ public function getWxCode()
+ {
+ //获取数据
+ $input = null;
+ if(isset($this->_input['data'])) $input = $this->_input['data'];
+ if(empty($input)) return $this->error('not data ,please check input data.');
+ $input['user_id'] = $this->_user_id;
+ $result = longbingCreateWxCode($this->_uniacid ,$input);
+ return $this->success($result);
+ }
+
+
+ //获取微信小程序码信息
+ public function getWxCodeData()
+ {
+ $code_id = null;
+ if(isset($this->_param['code_id'])) $code_id = $this->_param['code_id'];
+ if(empty($code_id)) return $this->error('not code id ,please check param.');
+ $result = longbingGetWxCode($code_id ,$this->_uniacid , $is_update = false);
+
+ return $this->success($result);
+ }
+
+
+
+ /**
+ * 将线上图片转为本地图片用于前端cavans画图
+ */
+ public function getImage ()
+ {
+
+ $path = $this->_param['path'] ?? 'http://longbing.cncnconnect.com/attachment/image/2/wxcode/8e1cc25f24bd0c10ad238e1ce8b7a2e2.jpeg' ;
+ if (!$path ) {
+ return $this->error('请传入参数');
+ }
+//
+// $path = $_SERVER[ 'QUERY_STRING' ];
+// $position = strpos($path, 'getImage&path=');
+// $sub_str = substr($path, $position + 14);
+// $path = urldecode($sub_str);
+
+ //判断类型
+ $type_img = getimagesize($path);
+
+ ob_start();
+
+ if ( strpos($type_img[ 'mime' ], 'jpeg') ) {
+ $resourch = imagecreatefromjpeg($path);
+ imagejpeg($resourch);
+ } elseif ( strpos($type_img[ 'mime' ], 'png') ) {
+ $resourch = imagecreatefrompng($path);
+ imagepng($resourch);
+ }
+ $content = ob_get_clean();
+ imagedestroy($resourch);
+ return response($content, 200, [ 'Content-Length' => strlen($content) ])->contentType('image/png');
+ }
+
+
+
+ /**
+ * 剩余通知条数
+ * @access public
+ * @return json
+ */
+ public function formIds ()
+ {
+ global $_GPC, $_W;
+ $uid = $this->_user_id ?? $_GPC[ 'user_id' ] ?? null;
+ $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - 7, date( 'Y' ) );
+
+ $m_form_id = new LongbingCardFromId();
+ $count = $m_form_id->where([
+ ['uniacid', '=', $this->_uniacid],
+ ['user_id', '=', $uid],
+ ['create_time', '>', $beginTime]
+
+ ])->count();
+
+ return $this->success(['count' => $count]);
+ }
+
+ //删除录音
+ public function clearCardInfoVoice()
+ {
+ //获取员工信息
+ $userId = $this->getUserId();
+ $card = longbingGetUserInfo($userId ,$this->_uniacid);
+ //判断员工是否存在
+ if ( !$card )
+ {
+ return $this->success([]);
+ }
+ //清除录音数据
+ $result = $this->modelUserInfo->updateUser(['fans_id' => $userId] ,['voice' => null , 'voice_time' => 0]);
+ if(!empty($result)) longbingGetUserInfo($userId ,$this->_uniacid ,true);
+ return $this->success( [] );
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-09-26 10:32
+ * @return void
+ * descption:生成商品二维码
+ */
+ public function getQr(){
+ $input = $this->_input;
+ $qr = getCache($this->getUserId().'-'.$input['type'].'-'.$input['staff_id'].'-'.$input['id']."-qr",$this->_uniacid);
+ if(empty($qr)){
+ $user = $this->getUserInfo();
+ $input['user_id'] = $this->getUserId();
+ $input['pid'] = $user['pid'];
+ $data = longbingCreateWxCode($this->_uniacid,$input,$input['page']);
+ $data = transImagesOne($data ,['qr_path'] ,$this->_uniacid);
+ $qr = $data['qr_path'];
+ setCache($this->getUserId().'-'.$input['type'].'-'.$input['staff_id'].'-'.$input['id']."-qr",$qr,3600,$this->_uniacid);
+ }
+ return $this->success($qr);
+ }
+
+ /**
+ **@author lichuanming
+ * @DataTime: 2020/5/15 10:58
+ * @功能说明:判断当前套餐是否过期
+ */
+ public function authStatus(){
+ $user_id = $this->getUserId();
+ $is_staff = (new User())->where('id','=',$user_id)->value('is_staff');
+ $info = longbing_auth_status($this->_uniacid);
+ $info['is_staff'] = $is_staff;
+ return $this->success($info);
+ }
+
+
+
+
+// public function
+
+}
diff --git a/app/card/controller/IndexV2.php b/app/card/controller/IndexV2.php
new file mode 100755
index 0000000..68beeab
--- /dev/null
+++ b/app/card/controller/IndexV2.php
@@ -0,0 +1,179 @@
+app = $app;
+ $this->modelUser = new User();
+ $this->modelUserInfo = new UserInfo();
+ $this->modelCollection = new Collection();
+ $this->modelCompany = new Company();
+ $this->modelConfig = new Config();
+ //$this->_user_id = '2';
+ }
+
+
+ /**
+ * @Purpose: 小程序配置接口
+ *
+ * @Method GET
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function config ()
+ {
+
+ $data = longbingGetAppConfig($this->_uniacid);
+
+ unset( $data[ 'auth_code' ] );
+
+ $exist = Db::query( 'show tables like "%longbing_card_config%"' );
+
+ $auth_info = false;
+
+ $cardauth2_config_exist = Db::query('show tables like "%longbing_cardauth2_config%"');
+
+ if (!empty($exist) && !empty($cardauth2_config_exist)) {
+ $auth_info = Db::name('longbing_cardauth2_config')
+ ->where([['modular_id', '=', $this->_uniacid]])
+ ->find();
+ }
+ $data[ 'is_pay_shop' ] = 1;
+ // 判断能不能使用商城的支付功能
+ if ( $auth_info && isset( $auth_info[ 'pay_shop' ] ) && $auth_info[ 'pay_shop' ] == 0 )
+ {
+ $data[ 'is_pay_shop' ] = 0;
+ }
+ if ( isset( $data[ 'btn_talk' ] ) && !$data[ 'btn_talk' ] )
+ {
+ $data[ 'btn_talk' ] = '面议';
+ }
+ $data['tabBar1'] = [];
+ //tabbar用新的方式返回
+ $data['tabBar1'] = Tabbar::all($this->_uniacid, $this->_user_id);
+
+ $pluginAuth = longbingGetPluginAuth($this->_uniacid, $this->_user_id, $auth_info);
+
+ $data = array_merge($data, $pluginAuth);
+
+ $data = LongbingArr::delBykey($data , ['web_manage_meta_config','wx_appid','wx_tplid'
+ ,'update_time','create_time','app_secret','appid',
+ 'aliyun_sms_access_key_id','aliyun_sms_access_key_secret'
+ ,'coupon_pass','corpsecret',
+ 'coupon_pass','order_pwd','mini_template_id']) ;
+
+ $config_model = new DefaultSetting();
+ //默认配置
+ $DefaultSetting = $config_model->settingInfo(['uniacid'=>$this->_uniacid],'primaryColor,subColor,share_more');
+ //主色
+ $data['primaryColor'] = !empty($DefaultSetting['primaryColor'])?$DefaultSetting['primaryColor']:'#19c865';
+ //辅色
+ $data['subColor'] = !empty($DefaultSetting['subColor'])?$DefaultSetting['subColor']:'#f86c53';
+
+ $data['share_more'] = $DefaultSetting['share_more'];
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-25 09:44
+ * @功能说明:
+ */
+ public function configV2(){
+
+ $data = longbingGetAppConfig($this->_uniacid);
+
+ unset( $data[ 'auth_code' ] );
+
+ $exist = Db::query( 'show tables like "%longbing_card_config%"' );
+
+ $auth_info = false;
+
+ $cardauth2_config_exist = Db::query('show tables like "%longbing_cardauth2_config%"');
+
+ if (!empty($exist) && !empty($cardauth2_config_exist)) {
+ $auth_info = Db::name('longbing_cardauth2_config')
+ ->where([['modular_id', '=', $this->_uniacid]])
+ ->find();
+ }
+ $data[ 'is_pay_shop' ] = 1;
+ // 判断能不能使用商城的支付功能
+ if ( $auth_info && isset( $auth_info[ 'pay_shop' ] ) && $auth_info[ 'pay_shop' ] == 0 )
+ {
+ $data[ 'is_pay_shop' ] = 0;
+ }
+ if ( isset( $data[ 'btn_talk' ] ) && !$data[ 'btn_talk' ] )
+ {
+ $data[ 'btn_talk' ] = '面议';
+ }
+ $data['tabBar1'] = [];
+ //tabbar用新的方式返回
+ //$data['tabBar1'] = Tabbar::all($this->_uniacid, $this->_user_id);
+ $config_model = new DefaultSetting();
+ //默认配置
+ $DefaultSetting = $config_model->settingInfo(['uniacid'=>$this->_uniacid],'primaryColor,subColor,share_more');
+ //主色
+ $data['primaryColor'] = !empty($DefaultSetting['primaryColor'])?$DefaultSetting['primaryColor']:'#19c865';
+ //辅色
+ $data['subColor'] = !empty($DefaultSetting['subColor'])?$DefaultSetting['subColor']:'#f86c53';
+
+ $data['share_more'] = $DefaultSetting['share_more'];
+
+ return $this->success($data);
+
+ }
+
+
+}
diff --git a/app/card/info/AdminMenu.php b/app/card/info/AdminMenu.php
new file mode 100755
index 0000000..f04a980
--- /dev/null
+++ b/app/card/info/AdminMenu.php
@@ -0,0 +1,163 @@
+ $menu];
+
+
diff --git a/app/card/info/DiyCompoents.php b/app/card/info/DiyCompoents.php
new file mode 100755
index 0000000..3434559
--- /dev/null
+++ b/app/card/info/DiyCompoents.php
@@ -0,0 +1,87 @@
+ "业务组件",
+ 'type' => 'cardCompoent',
+ "data" => [
+ json_decode($gzh, true),
+
+ json_decode($acrd, true),
+
+ json_decode($userinfo, true),
+
+ json_decode($vr, true),
+
+ json_decode($video, true),
+
+ json_decode($photo, true),
+
+ json_decode($goods, true),
+
+ json_decode($dynamic, true),
+ ]
+ ]
+
+];
\ No newline at end of file
diff --git a/app/card/info/DiyDefaultCompoents.php b/app/card/info/DiyDefaultCompoents.php
new file mode 100755
index 0000000..a25ea9a
--- /dev/null
+++ b/app/card/info/DiyDefaultCompoents.php
@@ -0,0 +1,19 @@
+ 1 ,
+ //是否显示
+ 'is_show' => 1 ,
+ //图标
+ 'iconPath' => 'icon-mingpian',
+ //选中图标样式
+ 'selectedIconPath' => 'icon-mingpian1',
+ //那个页面 英文名称
+ 'pageComponents' => 'cardHome',
+ //名称
+ 'name' => '名片',
+ 'url' => '',
+ 'url_jump_way' => '0',
+ 'url_out' => '',
+ 'is_delete' => false ,
+ 'bind_compoents'=>[
+
+ 'cardCompoent',
+
+ 'operate'
+ ],
+ 'bind_links' => [],
+ 'page'=> []
+ ],
+
+];
\ No newline at end of file
diff --git a/app/card/info/FunctionPage.php b/app/card/info/FunctionPage.php
new file mode 100755
index 0000000..7a21d70
--- /dev/null
+++ b/app/card/info/FunctionPage.php
@@ -0,0 +1,28 @@
+'',
+
+ 'key'=> 1,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "名片页面",
+ //小程序路径
+ "path" => "/pages/user/home?key=1&staff_id="
+ ]
+
+
+
+
+];
\ No newline at end of file
diff --git a/app/card/info/Info.php b/app/card/info/Info.php
new file mode 100755
index 0000000..e230e77
--- /dev/null
+++ b/app/card/info/Info.php
@@ -0,0 +1,34 @@
+ 'card',
+ //模块标题[必填]
+ 'title' =>'名片',
+ //内容简介
+ 'desc' =>'',
+ //封面图标
+ 'icon' =>'',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => 'model',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'card.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.8',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module' => [
+ ['admin', 'admin.longbing.module', '1.0.0']
+ ],
+ // 应用依赖[可选],格式[[插件名, 应用唯一标识, 依赖版本, 对比方式]]
+ 'need_app' => [],
+
+
+
+];
\ No newline at end of file
diff --git a/app/card/info/PermissionCard.php b/app/card/info/PermissionCard.php
new file mode 100755
index 0000000..854b72c
--- /dev/null
+++ b/app/card/info/PermissionCard.php
@@ -0,0 +1,131 @@
+saasKey = longbing_get_auth_prefix('AUTH_CARD') ;
+ parent::__construct($uniacid, self::tabbarKey, self::adminMenuKey, $this->saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+ return true ;
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+ return true;
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+ return true;
+ }
+
+
+ /**
+ * 添加名片数量
+ *
+ * @author shuixian
+ * @DataTime: 2019/12/19 19:02
+ */
+ public function getAuthNumber()
+ {
+ $returnAuthNumber = -1;
+ //代理管理端控制的数量
+ $pAuthConfig = $this->getPAuthConfig();
+
+ $authCardNumber = $this->getAuthVaule($this->saasKey, 5);
+
+ $pAuthNumber = isset($pAuthConfig['number']) ? $pAuthConfig['number'] : -1;
+ //全局设置配置
+ $cardauth2DefaultModel = new Cardauth2DefaultModel();
+
+ $defaultAuthNumber = $cardauth2DefaultModel->getCardNumber() ;
+
+ if ($authCardNumber > 0) {
+
+ if ($pAuthNumber > 0){
+
+ $returnAuthNumber = $pAuthNumber >= $authCardNumber ? $authCardNumber : $pAuthNumber;
+
+ } else {
+
+ $returnAuthNumber = $authCardNumber;
+
+ }
+
+ }else if( $authCardNumber == 0 ){
+ //无限开模式
+ if ($pAuthNumber >=0) {
+
+ $returnAuthNumber = $pAuthNumber;
+
+ }else if($defaultAuthNumber >= 0 ){
+
+ $returnAuthNumber = $defaultAuthNumber;
+
+ }else{
+
+ $returnAuthNumber = $pAuthNumber;
+ }
+
+ } else {
+
+ $returnAuthNumber = $pAuthNumber;
+ }
+
+ return $returnAuthNumber;
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/info/RadarMessage.php b/app/card/info/RadarMessage.php
new file mode 100755
index 0000000..34f6a61
--- /dev/null
+++ b/app/card/info/RadarMessage.php
@@ -0,0 +1,216 @@
+ "praise",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "查看",
+ "item"=> "名片",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "对你已建立信任,保持联系持续跟进",
+ "operation"=> "将",
+ "item"=> "手机号码存入了手机通讯录",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "咨询意向强烈,及时联系确保沟通顺畅",
+ "operation"=> "拨打",
+ "item"=> "手机号",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_user_info",
+ "field"=> "phone",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请随时保持电话畅通",
+ "operation"=> "拨打",
+ "item"=> "公司电话",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "客户请随时可能加你微信",
+ "operation"=> "复制了",
+ "item"=> "微信",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 5,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "可能随时邮寄文件给你,请注意查收",
+ "operation"=> "复制了",
+ "item"=> "邮箱",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 6,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "复制",
+ "item"=> "公司名称",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 7,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "对你的公司非常感兴趣",
+ "operation"=> "查看了",
+ "item"=> "公司地址",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 9,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "播放",
+ "item"=> "语音",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 10,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "保存了",
+ "item"=> "名片海报",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "copy",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请随时保持电话畅通",
+ "operation"=> "拨打",
+ "item"=> "400热线",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "语音点赞",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "",
+ "operation"=> "Ta给你点赞了",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "praise",
+ "type"=> 4,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "正在帮你裂变人脉,请及时留意雷达动态(快去表达一下你的感谢)",
+ "operation"=> "分享了",
+ "item"=> "名片",
+ "show_count"=> 0,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+];
+
+return $radar_msg;
diff --git a/app/card/info/Subscribe.php b/app/card/info/Subscribe.php
new file mode 100755
index 0000000..9b8ca14
--- /dev/null
+++ b/app/card/info/Subscribe.php
@@ -0,0 +1,163 @@
+ "",
+ "createBtn" => ""
+ ];*/
+
+ return $data;
+ }
+
+ /**
+ * 监听用户中心切换按钮
+ *
+ * @param $data
+ * @author shuixian
+ * @DataTime: 2019/12/18 14:07
+ */
+ public function onDiyChangeStaff($data)
+ {
+
+ $userModel = new User();
+
+ $last_staff_id = $userModel->where('id',$this->getUserId())->value('last_staff_id ');
+
+ if ( $last_staff_id) {
+
+ $staff_model = new LongbingUserInfo();
+
+ $staff_info = $staff_model->getStaff($last_staff_id, $this->_uniacid);
+
+ if(!empty($staff_info)){
+
+ $job_model = new Job();
+ $job_name = $job_model->where( 'id' , $staff_info['job_id'])->value('name') ;
+ $staff_info['job_name'] = $job_name;
+
+ $staff_info = longbing_array_columns([$staff_info],['id','fans_id','name','avatar','job_name']) ;
+ $staff_info = $staff_info[0] ;
+
+ //获取职位信息
+
+ }
+
+ $data['dataList'] = $staff_info;
+ }
+
+ return $data ;
+ }
+ /**
+ * 监听用户中心模块
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/18 14:04
+ */
+ public function onAddUcenterCompoent(){
+
+ $userInfo = <<initFirstUserToStaff($user['id'], $user['uniacid']) ;
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/lang/zh-cn.php b/app/card/lang/zh-cn.php
new file mode 100755
index 0000000..79009e3
--- /dev/null
+++ b/app/card/lang/zh-cn.php
@@ -0,0 +1,34 @@
+ '欢迎使用ThinkPHP',
+ 'data type error' => '数据类型错误',
+ 'test' => '你好啊',
+ 'picture' => '图片',
+ 'audio' => '音频',
+ 'vedio' => '视频',
+ 'Hello, I am ' => '您好,我是',
+ ', May I help you? Please contact me!' => ',有什么可以帮到您的吗?记得联系我!',
+ 'panoramic' => 'VR全景',
+ 'tag is exist ,please do not create twice.' => '标签已存在,请勿重复添加。',
+ 'not user' => '用户不存在',
+ 'code error' => '免审口令错误',
+ 'not set job' => '未设置职位',
+ 'card info not found' => '名片不存在',
+ 'create qr error.'=> '生成二维码失败',
+ 'tag is exist' => '标签已存在,请勿重复添加。',
+ 'not the job' => '没有此职位',
+ 'not the company' => '没有此公司',
+ 'staff info not found' => '员工不存在',
+ 'not set company' => '未设置公司',
+ 'traded' => '已成交',
+ 'not staff' => '员工不存在',
+ 'not company id' => '公司不能为空',
+ 'not card num' => '名片数量已超过限制数量,请联系管理员。',
+ 'not boss num' => 'boss数量超标,请联系管理员',
+ 'not from company'=> '所属公司不能为空',
+ 'chage card error'=> '修改用户名片信息失败',
+ 'card share text' => '您好,我是您的专属客户经理,这是我的名片,请惠存。',
+ 'At least one staff is required' => '系统必须保留一名推荐员工。',
+ 'create qr error' => '生成失败,请重试!',
+
+];
\ No newline at end of file
diff --git a/app/card/model/CardAuth2Activity.php b/app/card/model/CardAuth2Activity.php
new file mode 100755
index 0000000..a7e6be5
--- /dev/null
+++ b/app/card/model/CardAuth2Activity.php
@@ -0,0 +1,21 @@
+where($where)->value('boss');
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardCount.php b/app/card/model/CardCount.php
new file mode 100755
index 0000000..299c216
--- /dev/null
+++ b/app/card/model/CardCount.php
@@ -0,0 +1,460 @@
+where($where)
+ ->whereDay('create_time','yesterday')
+ ->field('to_uid as user_id,type,sign,count(to_uid) as number,uniacid')
+ ->group('to_uid')
+ ->order('create_time','desc')
+ ->select()
+ ->toArray();
+ if($data){
+ $stat = new CardStatistics();
+ foreach ($data as $key=>$val){
+ $data[$key]['create_time'] = strtotime("-1 day");
+ $data[$key]['table'] = 'CardCount';
+// $whe['user_id'] = $val['to_uid'];
+// $whe['type'] = $val['type'];
+// $whe['sign'] = $val['sign'];
+// $info = $stat->getUserid($whe);
+// if($info){
+// $stat->where($whe)->inc('number',$val['number'])->update();
+// }else{
+// $whe['number'] =$val['number'];
+// $stat->addinfo($whe);
+ }
+// }print_r(123);exit;
+ $stat->createRows($data);
+ }
+ return $data;
+ }
+ //昨日数据
+ public function getYesterday($where){
+ return $this->where($where)->whereDay('create_time','yesterday')->count();
+ }
+ //今日数据
+ public function gettoday($where){
+ return $this->where($where)->whereDay('create_time')->count();
+ }
+ //新增咨询
+ public function zxInfo($user_id,$where=[],$type=0){
+ if($type==1){
+ $de = '=';
+ }else{
+ $de = 'in';
+ }
+ $where1 = [
+ ['to_uid',$de,$user_id],
+ ['sign','=','copy'],
+ ['type','=','8'],
+ $where
+ ];
+ $where2 = [
+ ['to_uid',$de,$user_id],
+ ['sign','=','praise'],
+ ['type','=','5'],
+ $where
+ ];
+ $count = $this->where([array_filter($where1)])->whereor([array_filter($where2)])->count();
+ return $count;
+ }
+ public function getCount($where5){
+ $data = $this->where($where5)->count();
+ return $data;
+ }
+ public function radarList ( $where = [], $page = 1, $list_rows = 20 )
+ {
+ $data = self::where( $where )
+ ->alias( 'a' )
+ ->field( [ 'a.*','b.nickName as name']
+ )
+ ->join( 'longbing_card_user b', 'a.user_id = b.id' )
+ ->join( 'longbing_card_collection c', 'a.user_id = c.uid && a.to_uid = c.to_uid' )
+ ->order( [ 'a.id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => $list_rows, 'page' => $page ]
+ )
+ ->toArray();
+
+ // 查询手机号
+// $tmpArr = [];
+// foreach ( $data[ 'data' ] as $index => $item )
+// {
+// $data[ 'data' ][ $index ][ 'phone' ] = '';
+// array_push( $tmpArr, $item[ 'user_id' ] );
+// }
+// if ( !empty( $tmpArr ) )
+// {
+// $tmpArr = array_unique( $tmpArr );
+//
+// $list = UserPhone::where( [ [ 'user_id', 'in', $tmpArr ] ] )
+// ->field( [ 'user_id', 'phone' ] )
+// ->select()
+// ->toArray();
+//
+// $tmpArr = [];
+// foreach ( $list as $index => $item )
+// {
+// $tmpArr[ $item[ 'user_id' ] ] = $item[ 'phone' ];
+// }
+// foreach ( $data[ 'data' ] as $index => $item )
+// {
+// if ( isset( $tmpArr[ $item[ 'user_id' ] ] ) )
+// {
+// $data[ 'data' ][ $index ][ 'phone' ] = $tmpArr[ $item[ 'user_id' ] ];
+// }
+// }
+// }
+
+ if (!empty($data[ 'data' ]))
+ {
+ // 处理雷达展示日期
+ //$data[ 'data' ] = lbHandelRadarDate( $data[ 'data' ] );
+
+ // 处理用户来源
+ //$data[ 'data' ] = lbHandelRadarSource( $data[ 'data' ] );
+
+ // 处理雷达激励提醒文案
+ $data[ 'data' ] = lbHandelRadarMsg( $data[ 'data' ] );
+ }
+ return $data;
+ }
+ //兴趣占比
+ public function doPageBossInterest ($where,$uniacid)
+ {
+
+ $filter = [
+ ['sign','=','copy'] , ['uniacid','=',$uniacid],$where,[ 'type', 'in', [ 6, 7 ,11] ]
+ ];
+ $filter1 = [
+ ['sign','=','view'] , [ 'type', '=', 6 ],['uniacid','=',$uniacid],$where
+ ];
+//// // 对公司感兴趣
+ $compony = $this->where([$filter])->whereor([$filter1])->count();
+ $filter2 = [
+ ['sign','=','copy'] , ['uniacid','=',$uniacid],$where,[ 'type', '=', 8 ]
+ ];
+ $where3 = [
+ ['sign','=','view'] ,['uniacid','=',$uniacid],$where,[ 'type', 'in', [ 1, 2, 11, 15, 16, 17, 19, 20, 25, 26, 27, 28, 29, 30 ] ]
+ ];
+ $where21 = [
+ ['sign','=','praise'] , ['uniacid','=',$uniacid],$where, [ 'type', 'in', [ 5, 6, 7, 8 ] ]
+ ];
+ $where31 = [
+ ['sign','=','order'] ,['uniacid','=',$uniacid],$where
+ ];
+
+ // 对产品感兴趣
+ $goods = $this->where([$filter2])->whereor([$where3])->whereor([$where21])->whereor([$where31])->count();
+
+ // 对员工感兴趣
+ $where4 = [
+ ['sign','=','copy'],['uniacid','=',$uniacid],$where, [ 'type', 'in', [ 1, 2, 3, 4, 5, 9, 10 ] ]
+ ];
+ $where5 = [
+ ['sign','=','praise'],['uniacid','=',$uniacid],$where,[ 'type', 'in', [ 1, 2, 3, 4 ] ]
+ ];
+ $staff = $this->where([$where4])->whereor([array_filter($where5)])->count();
+
+ $total = $compony + $goods + $staff;
+ $data = [
+ [
+ 'data' => $compony,
+ 'rate' => 0,
+ 'name'=>'对公司感兴趣'
+ ],
+ [
+ 'data' => $goods,
+ 'rate' => 0,
+ 'name'=>'对产品感兴趣'
+ ],
+ [
+ 'data' => $staff,
+ 'rate' => 0,
+ 'name'=>'对我感兴趣'
+ ],
+ ];
+ if ( $total ) {
+ foreach ( $data as $k => $v ) {
+ $data[ $k ][ 'rate' ] = sprintf( "%.2f", $v[ 'data' ] / $total ) * 100;
+ }
+ }
+ return $data;
+ }
+ //活跃度0,1,2 $type 单个用户还是多个
+// public function doPageActivity ($uid,$type=0)
+// {
+// if($type ==1){
+// $str = 'in';
+// $last = 7;
+// }else{
+// $str = '=';
+// $last = 30;
+// }
+// //$forward = new CardForward();
+// //$stat = new CardStatistics();
+// $card_count = new CardCount();
+// $data = [];
+// $ss = [];
+// for ( $i = 0; $i < $last; $i++ ) {
+// $beginTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $i, date( 'Y' ) );
+// $endTime = mktime( 0, 0, 0, date( 'm' ), date( 'd' ) - $i + 1, date( 'Y' ) ) - 1;
+// $date = date( 'm/d', $beginTime );
+// $data[ $i ][ 'date' ] = $date;
+// $data[ $i ][ 'beginTime' ] = $beginTime;
+// $data[ $i ][ 'endTime' ] = $endTime;
+//
+//
+//// $where1[] = [
+//// ['user_id',$str,$uid],['table','=','forward'],['create_time','BETWEEN',[$beginTime,$endTime]]
+//// ];
+// // $count2 = $forward->forwardCount($where1);
+//// $wherez = [['sign','=','praise'], ['type','=',4],['to_uid','=',$uid],['uniacid','=',$this->_uniacid],['create_time','BETWEEN',[$beginTime,$endTime]]];
+//// $count2 =$card_count->getCount($wherez);
+// //$count2 = $stat->getCustomerCount($where1);
+// $card_message = new CardMessage();
+//// $where2[] = [
+//// ['user_id',$str,$uid],['table','=','message'],['create_time','BETWEEN',[$beginTime,$endTime]]
+//// ];
+// $where3 = [['status','=',1], ['deleted','=',0],['target_id',$str,$uid],['uniacid','=',$this->_uniacid],['create_time','BETWEEN',[$beginTime,$endTime]]];
+// $count3 = $card_message->getCount($where3);
+// //$count3 = $stat->getCustomerCount($where2);
+//
+// //$card_count = new CardCount();
+// $where4 = [['sign','=','copy'],['to_uid',$str,$uid],['uniacid','=',$this->_uniacid],['create_time','BETWEEN',[$beginTime,$endTime]]];
+//// $where3[] = [
+//// ['user_id',$str,$uid],['create_time','BETWEEN',[$beginTime,$endTime],['sign','=','copy']]
+//// ];
+// $count4 = $card_count->getCount($where4);
+//// $where3[] = [
+//// ['user_id',$str,$uid],['create_time','BETWEEN',[$beginTime,$endTime],['sign','=','view']]
+//// ];
+// $where5 = [['sign','=','view'],['to_uid',$str,$uid],['uniacid','=',$this->_uniacid],['create_time','BETWEEN',[$beginTime,$endTime]]];
+// $count5 = $card_count->getCount($where5);
+// $where3[] = [
+// ['user_id',$str,$uid],['create_time','BETWEEN',[$beginTime,$endTime],['sign','=','praise']]
+// ];
+// $where6 = [['sign','=','praise'],['to_uid',$str,$uid],['uniacid','=',$this->_uniacid],['create_time','BETWEEN',[$beginTime,$endTime]]];
+// $count6 = $card_count->getCount($where6);
+//
+//// $count6 = $stat->getCustomerCount($where3);$count2 +
+// $count = $count3 + $count4 + $count5 + $count6;
+// $data[ $i ][ 'number' ] = $count;
+// $ss[] = $count;
+// }
+// $arr = max($ss);
+// if($arr ==0){
+// $arr =5;
+// }
+// return ['max'=>$arr,'data'=>$data];
+// }
+ public function active ( $staff_id, $uniacid,$type=0 )
+ {
+ if($type ==1){
+ $str = 'in';
+ // $last = 7;['uniacid'=>$uniacid],
+ }else{
+ $str = '=';
+ // $last = 30;
+ }
+ $data = [];
+
+
+ $lastday = date( 'Y/m/d' );
+
+ $number = self::where( [ [ 'to_uid',$str, $staff_id ], [ 'create_time', 'between',
+ [ strtotime( $lastday . ' 00:00:00' ), strtotime( $lastday . ' 23:59:59' ) ] ] ]
+ )
+ ->count();
+ $data[] = [ 'date' => date( 'm/d' ), 'number' => $number ];
+
+ $max = $number;
+
+ for ( $i = 1; $i < 15; $i++ )
+ {
+
+ $start_time = strtotime( "$lastday -$i days" );
+
+ $md = date( 'm/d', $start_time );
+ $ymd = date( 'Y/m/d', $start_time );
+
+ $end_time = strtotime( $ymd . ' 23:59:59' );
+
+ $number = self::where( [ [ 'to_uid',$str, $staff_id ],
+ [ 'create_time', 'between', [ $start_time, $end_time ] ] ]
+ )
+ ->count();
+
+ if ( $number > $max )
+ {
+ $max = $number;
+ }
+
+
+ $data[] = [ 'date' => $md, 'number' => $number ];
+ }
+
+ return [ 'data'=>$data, 'max'=>$max ];
+ }
+ public function getsss($staff_id,$uniacid,$type=0){
+ if($type==1){
+ $str = '=';
+ }else{
+ $str = 'in';
+ }
+ $data = [ 'max_number' => 0, 'total' => 0, 'data' => [] ];
+
+ //咨询产品
+ $count = self::where( [ [ 'sign', '=', 'copy' ], [ 'to_uid',$str, $staff_id ],
+ [ 'type', '=', 8 ],[ 'uniacid', '=', $uniacid ] ]
+ )
+ ->count();
+
+ $data[ 'max_number' ] = $count;
+ $data[ 'total' ] += $count;
+ $data[ 'data' ][] = [ 'name' => '咨询产品', 'number' => $count ];
+
+ // 保存电话
+ $count = self::where( [ [ 'sign', '=', 'copy' ], [ 'to_uid', $str, $staff_id ],
+ [ 'type', '=', 1 ] ,[ 'uniacid', '=', $uniacid ]]
+ )
+ ->count();
+
+ if ( $count > $data[ 'max_number' ] )
+ {
+ $data[ 'max_number' ] = $count;
+ }
+ $data[ 'total' ] += $count;
+ $data[ 'data' ][] = [ 'name' => '保存电话', 'number' => $count ];
+
+ // 拨打电话
+ $count = self::where( [ [ 'sign', '=', 'copy' ], [ 'to_uid', $str, $staff_id ],[ 'uniacid', '=', $uniacid ],
+ [ 'type', 'in', [ 2, 3, 11 ] ] ]
+ )
+ ->count();
+
+ $count += self::where( [ [ 'sign', '=', 'praise' ], [ 'to_uid', $str, $staff_id ],[ 'uniacid', '=', $uniacid ],
+ [ 'type', '=', 7 ] ]
+ )
+ ->count();
+
+ if ( $count > $data[ 'max_number' ] )
+ {
+ $data[ 'max_number' ] = $count;
+ }
+ $data[ 'total' ] += $count;
+ $data[ 'data' ][] = [ 'name' => '拨打电话', 'number' => $count ];
+
+
+
+ $view_base_filter = [
+ ['to_uid', $str, $staff_id],
+ ['sign', '=', 'view'],[ 'uniacid', '=', $uniacid ]
+ ];
+
+ //浏览商城
+ $view_shop_filter = $view_base_filter;
+ $view_shop_filter[] = ['type' , '=' , 1];
+ $view_shop_number = self::where($view_shop_filter)->count();
+ $data['total'] += $view_shop_number;
+ $data['data'][] = ['name' => '浏览商城', 'number' => $view_shop_number];
+
+
+ //浏览商品
+ $view_goods_filter = $view_base_filter;
+ $view_goods_filter[] = ['type' , '=' , 2];
+ $view_goods_number = self::where($view_goods_filter)->count();
+ $data['total'] += $view_goods_number;
+ $data['data'][] = ['name' => '浏览商品', 'number' => $view_goods_number];
+
+ //查看官网
+ $view_official_web_filter = $view_base_filter;
+ $view_official_web_filter[] = ['type' , '=' , 6];
+ $view_official_web_number = self::where($view_official_web_filter)->count();
+ $data['total'] += $view_official_web_number;
+ $name = tabbarName(4,$uniacid);
+
+ $data['data'][] = ['name' =>!empty($name)?'查看'.$name: '查看官网', 'number' => $view_official_web_number];
+
+
+ //浏览动态
+ $view_timeline_filter = $view_base_filter;
+ $view_timeline_filter[] = ['type' , '=' , 3];
+ $view_timeline_number = self::where($view_timeline_filter)->count();
+ $data['total'] += $view_timeline_number;
+ $data['data'][] = ['name' => '浏览动态', 'number' => $view_timeline_number];
+
+
+ //点赞
+ $praise_filter = [
+ ['to_uid', $str, $staff_id],[ 'uniacid', '=', $uniacid ],
+ ['sign', '=', 'praise'],
+ ['type', 'IN', [1, 3]]
+ ];
+ $praise_number = self::where($praise_filter)->count();
+ $data['total'] += $praise_number;
+ $data['data'][] = ['name' => '点赞', 'number' => $praise_number];
+
+
+
+ //分享名片
+ $share_filter = [
+ ['to_uid', $str, $staff_id],[ 'uniacid', '=', $uniacid ],
+ ['sign', '=', 'praise'],
+ ['type', '=', 4]
+ ];
+ $share_number = self::where($share_filter)->count();
+ $data['total'] += $share_number;
+ $data['data'][] = ['name' => '分享', 'number' => $share_number];
+
+
+
+
+ //按number倒序
+ $sort_arr = [];
+ foreach ($data['data'] as $k => $v) {
+ $sort_arr[] = $v['number'];
+ }
+
+ array_multisort($sort_arr, SORT_DESC, $data['data']);
+ $data['max_number'] = $data['data'][0]['number'] ?? 0;
+
+ //计算rate
+ foreach ($data['data'] as $index => $item) {
+ if ($data['max_number'] == 0) {
+ $rate = 0;
+ } else {
+ $rate = $item['number'] / $data['max_number'] * 100;
+ }
+ $rate = sprintf("%.0f", $rate);
+ $data['data'][$index]['rate'] = $rate;
+ }
+
+ return $data;
+ }
+ public function getCountUser($where,$time){
+ $data = $this->alias('a')
+ ->join( 'longbing_card_user_info b', 'a.to_uid = b.fans_id' )
+ ->where($where)
+ ->whereDay('a.create_time',$time)
+ ->group('user_id')
+ ->count();
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardCoupon.php b/app/card/model/CardCoupon.php
new file mode 100755
index 0000000..0d7576b
--- /dev/null
+++ b/app/card/model/CardCoupon.php
@@ -0,0 +1,21 @@
+getCompanyId(['fans_id'=>$staff_id],$uniacid);
+
+ $member_model= new Member();
+
+ $arr = [];
+
+ if($member_model->getAuth($uniacid)==true){
+
+ $arr[] = ['b.is_member','=',0];
+
+ }
+
+ $dis[] = ['d.company_id','=',$company_id];
+
+ $dis[] = ['b.public_goods','=',1];
+
+ $config = longbingGetAppConfig($uniacid);
+ //自选
+ if($config['myshop_switch']==1){
+ $user_shop = new IndexUserShop();
+
+ $my_goods = $user_shop->MyGoodList(['user_id'=>$staff_id,'uniacid'=>$uniacid]);
+
+ $arrs[] = ['a.id','in',$my_goods];
+
+ }else{
+
+ $arrs[] = ['a.index_show', '=', 1];
+ }
+
+ $data = self::where( [ [ 'a.user_id', '=', $staff_id ], [ 'a.status', '=', 1 ], [ 'b.status', '=', 1 ], [ 'a.uniacid', '=', $uniacid ] ] )
+ ->where($arr)
+ ->alias( 'a' )
+ ->field( [ 'a.id as e_id','b.id', 'b.name', 'b.cover', 'b.price', 'b.status', 'b.unit', 'b.recommend', 'b.is_collage' ]
+ )
+ ->where(function ($query) use ($dis){
+ $query->whereOr($dis);
+ })
+ ->join('longbing_card_goods b', 'a.goods_id = b.id')
+ ->join('longbing_card_user_info c','a.user_id = c.fans_id')
+ ->join('longbing_card_company_goods d' ,'c.company_id = d.company_id and a.goods_id = d.goods_id','left')
+// ->order( [ 'a.id' => 'desc' ] )
+ ->order('a.status desc,b.recommend desc,b.top desc,b.id desc,b.update_time desc')
+ ->select()
+ ->toArray();
+
+
+
+ if($data){
+ $spe_price = new AdminShopSpePrice();
+ foreach ($data as $key=>$val){
+ $o_dis = [];
+ $o_dis[] = ['status','=',1];
+ $o_dis[] = ['goods_id','=',$val['id']];
+ $data[$key]['price_text'] = $spe_price->where($o_dis)->min('price');
+ $o_dis[] = ['original_price','<>',0];
+ $data[$key]['original_price'] = $spe_price->where($o_dis)->min('original_price');
+ }
+ }
+ $data = transImagesOne($data, ['cover']);
+ $data = formatNumberPrice($data);
+
+
+
+ return $data;
+ }
+ public function getlist($dis){
+ $data = $this
+ ->alias('a')
+ ->join('longbing_card_user_info b','a.user_id = b.fans_id')
+ ->join('longbing_card_company_goods c' ,'b.company_id = c.company_id and a.goods_id = c.goods_id')
+ ->join('longbing_card_goods d' ,'a.goods_id = d.id and d.status = 1')
+ ->where($dis)
+ ->field(['a.*'])
+ ->order('a.create_time','desc')
+ ->select()
+ ->toArray();
+ return $data;
+ }
+ public function getCount($where){
+ return $this->where($where)->count();
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/card/model/CardFormId.php b/app/card/model/CardFormId.php
new file mode 100755
index 0000000..0e76b7c
--- /dev/null
+++ b/app/card/model/CardFormId.php
@@ -0,0 +1,21 @@
+field('staff_id as user_id,count(staff_id) as number,uniacid')
+ ->whereDay('create_time','yesterday')
+ ->group('staff_id')
+ ->where($where)->select()->toArray();
+ if($data){
+ foreach ($data as $key=>$val){
+ $data[$key]['table'] = 'forward';
+ $data[$key]['create_time'] = strtotime("-1 day");
+ }
+ $stat = new CardStatistics();
+ $stat->createRows($data);
+ }
+ return $data;
+ }
+ public function getYesterday($where){
+ return $this->where($where)->whereDay('create_time','yesterday')->count();
+ }
+ public function forwardCount($where4){
+ return $this->where($where4)->count();
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardJob.php b/app/card/model/CardJob.php
new file mode 100755
index 0000000..69e26bb
--- /dev/null
+++ b/app/card/model/CardJob.php
@@ -0,0 +1,147 @@
+field( [ 'id', 'name' ] )
+ ->order( 'top', 'desc' )
+ ->select()
+ ->toArray();
+
+ if ( !$list )
+ {
+ $list = $this->initCardJob( $uniacid );
+ }
+
+ foreach ( $list as $index => $item )
+ {
+ $list[ $index ][ 'selected' ] = 0;
+ if ( isset( $item[ 'id' ] ) && $item[ 'id' ] == $card_id )
+ {
+ $list[ $index ][ 'selected' ] = 1;
+ }
+ }
+
+ return $list;
+ }
+
+ /**
+ * @Purpose: 初始化名片样式
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function initCardJob ( $uniacid )
+ {
+ $data = [ [ 'name' => '首席服务官', 'uniacid' => $uniacid ] ];
+ $result = self::createRows( $data );
+ return $result->toArray();
+ }
+
+// public function getJob($filter)
+// {
+// $result = $this->where($filter)->find();
+// if(!empty($result)) $result = $result->toArray();
+// return $result;
+// }
+
+ /**
+ * @Purpose: 创建职位
+ *
+ * @Author: yangqi
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function createJob($data){
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ return !empty($result);
+ }
+ /**
+ * @Purpose: 更新职位
+ *
+ * @Author: yangqi
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updateJob($filter ,$data){
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+ /**
+ * @Purpose: 获取职位列表
+ *
+ * @Author: yangqi
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function listJob($filter ,$page_config = ['page' => 1 ,'page_count' => 20 ]){
+ $result = $this->where($filter)
+ ->order('top desc , id desc')
+ ->page($page_config['page'] ,$page_config['page_count'])
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ /**
+ * @Purpose: 获取职位详情
+ *
+ * @Author: yangqi
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getJob($filter){
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ /**
+ * @Purpose: 删除职位信息
+ *
+ * @Author: yangqi
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function delJob($filter){
+ $result = $this->updateJob($filter ,['status' => -1 ,'update_time' => time()]);
+ return !empty($result);
+ }
+ /**
+ * @Purpose: 获取职位总数
+ *
+ * @Author: yangqi
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getJobCount($filter){
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardLabel.php b/app/card/model/CardLabel.php
new file mode 100755
index 0000000..790facc
--- /dev/null
+++ b/app/card/model/CardLabel.php
@@ -0,0 +1,20 @@
+where($where)->count();
+ }
+// public function getCountlist($where){
+// $data = $this
+// ->field('target_id as user_id,count(target_id) as number,uniacid')
+// ->whereDay('create_time','yesterday')
+// ->group('target_id')
+// ->where($where)->select()->toArray();
+// if($data){
+// foreach ($data as $key=>$val){
+// $data[$key]['table'] = 'message';
+// $data[$key]['create_time'] = strtotime("-1 day");
+// }
+// $stat = new CardStatistics();
+// $stat->createRows($data);
+// }
+// return $data;
+// }
+}
\ No newline at end of file
diff --git a/app/card/model/CardTags.php b/app/card/model/CardTags.php
new file mode 100755
index 0000000..71f97d1
--- /dev/null
+++ b/app/card/model/CardTags.php
@@ -0,0 +1,63 @@
+select()
+ ->toArray();
+
+ foreach ( $data as $index => $item )
+ {
+ $data[ $index ][ 'thumbed' ] = 0;
+ $check = CardUserTags::where( [ [ 'tag_id', '=', $item[ 'id' ] ],
+ [ 'user_id', '=', $client_id ], [ 'uniacid', '=', $uniacid ],
+ [ 'status', '=', 1 ] ]
+ )
+ ->count();
+
+ if ($check)
+ {
+ $data[ $index ][ 'thumbed' ] = 1;
+ }
+ }
+
+ return $data;
+ }
+
+ public function getTag($filter)
+ {
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function getTagCount($filter)
+ {
+ $count = $this->where($filter)->count();
+ return $count;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardType.php b/app/card/model/CardType.php
new file mode 100755
index 0000000..cced49f
--- /dev/null
+++ b/app/card/model/CardType.php
@@ -0,0 +1,61 @@
+ 'cardType1', 'img' => 'https://retail.xiaochengxucms.com/1.png', 'uniacid' => $uniacid ],
+ [ 'card_type' => 'cardType4', 'img' => 'https://retail.xiaochengxucms.com/2.png', 'uniacid' => $uniacid ],
+ [ 'card_type' => 'cardType2', 'img' => 'https://retail.xiaochengxucms.com/4.png', 'uniacid' => $uniacid ],];
+ $result = self::createRows( $data );
+ return $result->toArray();
+ }
+
+ /**
+ * @Purpose: 初始化名片样式
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getCardTypeList ( $uniacid, $type = '' )
+ {
+ $list = self::where( [ [ 'uniacid', '=', $uniacid ], [ 'status', '=', 1 ] ] )
+ ->select()
+ ->toArray();
+
+ foreach ( $list as $index => $item )
+ {
+ $list[$index]['selected'] = 0;
+
+ if ($item['card_type'] == $type)
+ {
+ $list[$index]['selected'] = 1;
+ }
+ }
+ return $list;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardUserLabel.php b/app/card/model/CardUserLabel.php
new file mode 100755
index 0000000..59e3b67
--- /dev/null
+++ b/app/card/model/CardUserLabel.php
@@ -0,0 +1,22 @@
+where($where)->group('user_id')->field('user_id,uniacid')->select()->toArray();
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/CardUserTags.php b/app/card/model/CardUserTags.php
new file mode 100755
index 0000000..7940e48
--- /dev/null
+++ b/app/card/model/CardUserTags.php
@@ -0,0 +1,20 @@
+where($where)->order('update_time','desc')->find();
+ }
+ public function bossGetAiValue ( $id,$uniacid )
+ {
+ $value = [
+ 'client' => 0, // 获客能力值
+ 'charm' => 0, // 个人魅力值
+ 'interaction' => 0, // 客户互动值
+ 'product' => 0, // 产品推广值
+ 'website' => 0, // 官网推广度
+ 'active' => 0, // 销售主动性值
+ ];
+ $check = $this->getlist([ 'staff_id' => $id ]);
+ if ( !$check || ( $check && time() - $check[ 'update_time' ] > 24 * 60 * 60 ) ) {
+ $colle = new Collection();
+ // 获客能力值
+ $client = $colle->getlistCount(['status' => 1, 'to_uid' => $id,]);
+ if ( $client > 0 ) {
+ $client -= 1;
+ }
+ $value[ 'client' ] = $client;
+ $card_count = new CardCount();
+ // 个人魅力值
+ $list1 = $card_count->getCount([ 'sign' => 'praise', 'type' => 1, 'to_uid' => $id ]);
+ $list2 = $card_count->getCount( [ 'sign' => 'praise', 'type' => 3, 'to_uid' => $id ]);
+ $list3 = $card_count->getCount([ 'sign' => 'copy', 'to_uid' => $id ]);
+ $count = $list1 + $list2+ $list3;
+ $value[ 'charm' ] = $count;
+ $card_message = new CardMessage();
+
+ // 客户互动值
+ $list1 = $card_message->getCount([ 'user_id' => $id ]);
+ $list2 = $card_message->getCount([ 'target_id' => $id ]);
+ $list3 = $card_count->getCount([ 'sign' => 'view', 'to_uid' => $id ]);
+ $count = $list1 + $list2 + $list3;
+ $value[ 'interaction' ] = $count;
+ $extension = new CardExtension();
+ $mark = new UserMark();
+ $forward = new CardForward();
+ $group = new CardShareGroup();
+
+ // 产品推广值
+ $list1 = $extension->getCount([ 'user_id' => $id, 'uniacid' => $uniacid ]);
+ $list2 = $mark->getCount([ 'staff_id' => $id, 'uniacid' => $uniacid, 'mark' => 2 ]);
+ $list3 = $forward->forwardCount([ 'staff_id' => $id, 'uniacid' => $uniacid, 'type' => 2 ]);
+
+ $where=[['user_id','=',$id],['uniacid','=',$uniacid], ['view_goods','<>',''] ];
+ $list4 = $group->getCount($where);
+ $count = $list1 + $list2 + $list3 + $list4;
+ $value[ 'product' ] = $count;
+
+ // 官网推广度
+ $list1 = $card_count->getCount([ 'sign' => 'view', 'type' => 6, 'to_uid' => $id ]);
+ $list2 = $forward->forwardCount([ 'staff_id' => $id, 'uniacid' => $uniacid, 'type' => 4 ]);
+ $count = $list1 + $list2;
+ $value[ 'website' ] = $count;
+ $follow = new UserFollow();
+
+ // 销售主动性值
+ $list1 = $card_message->getCount([ 'user_id' => $id ]);
+ $list2 = $card_message->getCount([ 'target_id' => $id ]);
+ $list3 = $follow->getCount([ 'staff_id' => $id ]);
+ $list4 = $mark->getCount([ 'staff_id' => $id ]);
+ $count = $list1 + $list2 + $list3+ $list4;
+ $value[ 'active' ] = $count;
+
+ $insertData = $value;
+ $insertData[ 'staff_id' ] = $id;
+ $time = time();
+ $insertData[ 'update_time' ] = $time;
+ $insertData[ 'uniacid' ] = $uniacid;
+ if ( !$check ) {
+ $insertData[ 'create_time' ] = $time;
+ $this->createRow($insertData);
+ } else {
+ $insertData[ 'update_time' ] = $time;
+ $this->upsave([ 'id' => $check[ 'id' ]],$insertData);
+ }
+ } else {
+ $value = [
+ 'client' => $check[ 'client' ], // 获客能力值
+ 'charm' => $check[ 'charm' ], // 个人魅力值
+ 'interaction' => $check[ 'interaction' ], // 客户互动值
+ 'product' => $check[ 'product' ], // 产品推广值
+ 'website' => $check[ 'website' ], // 官网推广度
+ 'active' => $check[ 'active' ], // 销售主动性值
+ ];
+ }
+
+ $max=array_sum(array($value[ 'active' ],$value[ 'charm' ],$value[ 'client' ],$value[ 'interaction' ],$value[ 'product' ],$value[ 'website' ]));
+
+ $web_name = tabbarName(4,$uniacid);
+
+ $data = [
+ [
+ 'name'=>'销售主动性值',
+ 'number'=>$value[ 'active' ],
+
+ ],
+ [
+ 'name'=>!empty($web_name)?$web_name.'推广度':'官网推广度',
+ 'number'=>$value[ 'website' ],
+ $bb[] = $value[ 'website' ]
+ ],
+ [
+ 'name'=>'产品推广值',
+ 'number'=>$value[ 'product' ],
+
+ ],
+ [
+ 'name'=>'客户互动值',
+ 'number'=>$value[ 'interaction' ],
+
+ ],
+ [
+ 'name'=>'获客能力值',
+ 'number'=>$value[ 'client' ],
+
+ ],
+ [
+ 'name'=>'个人魅力值',
+ 'number'=>$value[ 'charm' ],
+
+ ],
+ ];
+
+ return ['max'=>$max,'data'=>$data];
+ }
+ function bossAi ($user_list, $uniacid )
+ {
+ $max = [
+ 0 => 0, // 销售主动性值
+ 1 => 0, // 官网推广度
+ 2 => 0, // 产品推广值
+ 3 => 0, // 客户互动值
+ 4 => 0, // 获客能力值
+ 5 => 0, // 个人魅力值
+ ];
+ $staff_list = User::where( [ [ 'uniacid', '=', $uniacid ], [ 'is_staff', '=', 1 ] ] )
+ ->field( [ 'id', 'nickName' ] )
+ ->where('id','in',$user_list)
+ ->select()
+ ->toArray();
+
+ foreach ( $staff_list as $k => $v )
+ {
+ $total = 0;
+ $value = $this->bossGetAiValue( $v[ 'id' ], $uniacid );
+
+ foreach ( $value['data'] as $k2 => $v2 )
+ {
+ if ( $v2[ 'number' ] > $max[ $k2 ] )
+ {
+ $max[ $k2 ] = $v2[ 'number' ];
+ }
+ $total += $v2[ 'number' ];
+ }
+
+ $staff_list[ $k ][ 'number' ] = $value['data'];
+ //$staff_list[ $k ][ 'total' ] = $total;
+// $staff_list[ $k ][ 'info' ] = $info;
+ }
+
+// // 二维数组排序
+// array_multisort( array_column( $staff_list, 'total' ), SORT_DESC, $staff_list );
+//
+// $staff_list = array_splice( $staff_list, 0, 3 );
+
+
+ $data = ['max_data' => $max,'max_number'=>max($max) ];
+
+ return $data;
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/model/ClientInfo.php b/app/card/model/ClientInfo.php
new file mode 100755
index 0000000..b1fb0b5
--- /dev/null
+++ b/app/card/model/ClientInfo.php
@@ -0,0 +1,20 @@
+join( 'longbing_card_user_info b', 'a.to_uid = b.fans_id' )
+ ->join( 'longbing_card_job c', 'b.job_id = c.id', 'LEFT' )
+ ->where( [ [ 'a.uniacid', '=', $uniacid ], [ 'a.uid', '=', $userId ], [ 'a.status', '=', 1 ],
+ [ 'b.is_staff', '=', 1 ], [ 'a.to_uid', '<>', $userId ] ]
+ )
+ ->field( [ 'a.to_uid', 'b.name', 'b.avatar', 'b.job_id', 'b.phone', 'b.email', 'c.name as job_name' ,'b.name']
+ )
+ ->order( [ 'a.id' => 'desc' ] )
+ ->paginate( [ 'list_rows' => 10, 'page' => $page ]
+ )
+ ->toArray();
+
+
+ // 自己如果是员工则把自己返回在第一页第一个
+// if ( $userInfo[ 'is_staff' ] == 1 && $page == 1 )
+// {
+// $card = self::alias( 'a' )
+// ->where( [ [ 'a.uniacid', '=', $uniacid ], [ 'a.uid', '=', $userId ], [ 'a.status', '=', 1 ],
+// [ 'b.is_staff', '=', 1 ], [ 'a.to_uid', '=', $userId ] ]
+// )
+// ->field( [ 'a.to_uid', 'b.name', 'b.avatar', 'b.job_id', 'b.phone', 'b.email', 'c.name as job_name' ]
+// )
+// ->join( 'longbing_card_user_info b', 'a.to_uid = b.fans_id' )
+// ->join( 'longbing_card_job c', 'b.job_id = c.id', 'LEFT' )
+// ->find();
+// if ($card)
+// {
+// $card = $card->toArray();
+//
+// $data[ 'data' ] = array_merge([$card], $data[ 'data' ]);
+// }
+// }
+
+ foreach ($data[ 'data' ] as $index => $item)
+ {
+ if ($item['job_name'] === null)
+ {
+ $data[ 'data' ][$index]['job_name'] = '未设置职位';
+ }
+ }
+
+ $data[ 'data' ] = transImages( $data[ 'data' ], [ 'avatar' ] );
+
+ return $data;
+ }
+
+ /**
+ * @Purpose: 默认推荐员工列表
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function defaultCardList ($page = 1, $uniacid = 0 ,$staff_id = null)
+ {
+ $page = intval( $page );
+
+ $page = $page ? $page : 1;
+
+ $modelUserInfo = new UserInfo();
+ //Update by jingshuixian 'a.fans_id', 'a.fans_id as to_uid', 修复无法访问的bug
+ $where = [ [ 'a.uniacid', '=', $uniacid ], [ 'a.is_default', '=', 1 ], [ 'a.is_staff', '=', 1 ]];
+ if(!empty($staff_id)) $where[] = ['fans_id' ,'<>' , $staff_id];
+ $data = $modelUserInfo->alias('a')
+ ->where($where)
+ ->field( [ 'a.fans_id', 'a.fans_id as to_uid', 'a.name', 'a.avatar', 'a.job_id', 'a.phone', 'a.email', 'b.name as job_name' ]
+ )
+ ->join( 'longbing_card_job b', 'a.job_id = b.id', 'LEFT' )
+ ->order( [ 'a.top' => 'desc' ] )
+ ->paginate( [ 'list_rows' => 10, 'page' => $page ]
+ )
+ ->toArray();
+
+ foreach ($data[ 'data' ] as $index => $item)
+ {
+ if ($item['job_name'] === null)
+ {
+ $data[ 'data' ][$index]['job_name'] = '未设置职位';
+ }
+ }
+
+ $data[ 'data' ] = transImages( $data[ 'data' ], [ 'avatar' ] );
+
+ return $data;
+ }
+ //收藏名片
+ public function createCollection($data)
+ {
+ $data['create_time'] = time();
+// var_dump($data);die;
+ $result = $this->save($data);
+ return !empty($result);
+ }
+ //修改
+ public function updateCollection($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+ //获取收藏名片总数
+ public function getCollectionCount($filter)
+ {
+ $result = $this->where($filter)->count();
+ return $result;
+ }
+ //获取收藏名片信息
+ public function checkCollection($filter)
+ {
+ $result = $this->where($filter)->field('id ,status')->find();
+ if($result) $result = $result->toArray();
+ return $result;
+ }
+ //获去信息
+ public function getCollection($filter)
+ {
+ $result = $this->where($filter)->find();
+ if($result) $result = $result->toArray();
+ return $result;
+ }
+ //获取需要更新的rate数据总数
+// public function getCollectionJoinRateCount()
+// {
+// $time = time() - 24*60*60;
+// $result = $this->alias('a')
+// ->leftJoin('longbing_card_rate b' ,'a.uid = b.user_id && a.to_uid = b.staff_id && a.uniacid = b.uniacid')
+//// ->whereOr([['b.update_time' ,'<' ,$time] ,['b.id' , '=',null]])
+//// ->fetchSql()
+// ->count();
+//// var_dump($result);die;
+// return $result;
+// }
+ //获取需要更新的rate数据
+// public function listCollectionJoinRate($page_config = ['page' => 1 ,'page_count' =>200])
+// {
+// $time = time() - 24*60*60;
+// $result = $this->alias('a')
+// ->leftJoin('longbing_card_rate b' ,'a.uid = b.user_id && a.to_uid = b.staff_id && a.uniacid = b.uniacid')
+// ->whereOr([['b.update_time' ,'<' ,$time] ,['b.id' ,'=' ,null]])
+// ->field('a.id ,b.id as rate_id')
+// ->page($page_config['page'] ,$page_config['page_count'])
+// ->select();
+// if(!empty($result)) $result = $result->toArray();
+// return $result;
+// }
+//
+ public function getCollectionJoinRateCount()
+ {
+ $time = time() - 24*60*60;
+ $result = $this->where([['update_rate_time' ,'<' ,$time]])->count();
+// var_dump($result);die;
+ return $result;
+ }
+ //获取需要更新的rate数据
+ public function listCollectionJoinRate($page_config = ['page' => 1 ,'page_count' =>200])
+ {
+ $time = time() - 24*60*60;
+ $result = $this->where([['update_rate_time' ,'<' ,$time]])
+ ->field('id')
+ ->page($page_config['page'] ,$page_config['page_count'])
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ public function getYesterdaylist($where){
+ $data = $this->alias('a')
+ ->join( 'longbing_card_user_info b', 'a.to_uid = b.fans_id')
+ ->join( 'longbing_card_user d', 'b.fans_id = d.id && d.is_staff = 1','left')
+ ->join( 'longbing_card_job c', 'c.id = b.job_id ','left')
+ ->field('a.to_uid,count(a.to_uid) as number,a.uniacid,b.name,avatar,c.name as job_name,nickName,avatarUrl')
+ ->where($where)
+ ->limit(3)
+ ->group('a.to_uid')
+ ->order('number desc ,a.to_uid asc')
+ ->whereDay('a.create_time','yesterday')
+ ->select()->toArray();
+ foreach ($data as $k=>$v){
+ if(!$v['name']){
+ $data[$k]['name'] = $v['nickName'];
+ }
+ if(!$v['avatar']){
+ $data[$k]['avatar'] = $v['avatarUrl'];
+ }
+ if(!$v['job_name']){
+ $data[$k]['job_name'] = '未设置职位';
+ }
+ }
+ $data = transImagesOne($data,['avatar']);
+ return $data;
+ }
+
+ public function getlistAll($where,$page,$list_rows,$type =0,$desc = 0){
+ if($desc == 0){
+ $de = 'asc';
+ }else{
+ $de = 'desc';
+ }
+ if($desc == 0){
+ $de1 = 'desc';
+ }else{
+ $de1 = 'asc';
+ }
+ $data = $this->alias('a')
+ ->join( 'longbing_card_user_info b', 'a.to_uid = b.fans_id')
+ ->join( 'longbing_card_user d', 'b.fans_id = d.id && d.is_staff = 1','left')
+ ->join( 'longbing_card_job c', 'c.id = b.job_id ','left')
+ ->field('a.to_uid,count(a.to_uid) as number,a.uniacid,b.name,avatar,c.name as job_name,nickName,avatarUrl')
+ ->where($where)
+ ->group('a.to_uid')
+ ->order("number $de,a.to_uid $de1")
+ ->paginate([ 'list_rows' => $list_rows, 'page' => $page ])->each(function ($item,$key)use ($type){
+ if(!$item['name']){
+ $item['name'] = $item['nickName'];
+ }
+ if(!$item['avatar']){
+ $item['avatar'] = $item['avatarUrl'];
+ }
+ if(!$item['job_name']){
+ $item['job_name'] = '未设置职位';
+ }
+ return $item;
+ })->toArray();
+ $data = transImagesOne($data,['avatar']);
+ return $data;
+ }
+ //查询昨天新增客户的数据
+ public function getTodaylist($where){
+ $data = $this->alias('a')
+ //->leftJoin( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->join( 'longbing_card_user c', 'a.uid = c.id' )
+ ->where($where)
+ ->field('a.to_uid as user_id,count(a.to_uid) as number,a.uniacid')
+ ->whereDay('a.create_time','yesterday')
+ ->group( 'a.to_uid' )
+ ->select()->toArray();
+ if($data){
+ foreach ($data as $key=>$val){
+ $data[$key]['table'] = 'customer';
+ $data[$key]['create_time'] = strtotime("-1 day");
+ }
+ $stat = new CardStatistics();
+ $stat->createRows($data);
+ }
+ return $data;
+ }
+ public function getCount($where){
+ return $this->alias('a')
+ ->where($where)
+ ->count();
+ }
+ //查询今天线索
+ public function today($where){
+ return $this->alias('a')
+ ->leftJoin( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->join( 'longbing_card_user c', 'a.uid = c.id' )
+ ->where($where)
+ ->whereDay('a.create_time')
+ ->group( 'a.uid, a.to_uid' )
+ ->count();
+ }
+ //查询七天类的客户数量
+ public function weekToday($where){
+ $weekday = date("Y-m-d",strtotime("-6 day"));
+ $data = $this->alias('a')
+ ->leftJoin( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->join( 'longbing_card_user c', 'a.uid = c.id' )
+ ->where($where)
+ ->whereWeek('a.update_time',$weekday)
+ ->group( 'a.uid, a.to_uid' )
+ ->count();
+ return $data;
+ }
+ //查询昨天线索的数据
+ public function Yesterday($where){
+ return $this->alias('a')
+ ->leftJoin( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->join( 'longbing_card_user c', 'a.uid = c.id' )
+ ->where($where)
+ ->whereDay('a.create_time','yesterday')
+ ->group( 'a.uid, a.to_uid' )
+ ->count();
+ }
+// public function getLookCount($where){
+// return $this->alias('a')
+// ->join( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+// ->where($where)
+// ->count();
+// }
+ //查询客户当天的数据
+ public function todayLook($where){
+ return $this->alias('a')
+ ->join( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->whereDay('a.update_time')
+ ->where($where)
+ ->count();
+ }
+ //更新变更线索人数
+// public function changeNember($where){
+// $data = $this->where($where)
+// ->alias('a')
+// //->join( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+// ->field('a.to_uid as user_id,count(a.to_uid) as number,a.uniacid')
+// //->whereDay('a.create_time')
+// ->group('a.to_uid')
+// ->select()
+// ->toArray();
+// if($data){
+// $stat = new CardStatistics();
+// foreach ($data as $key=>$val){
+// $id = $stat->getUserid(['user_id'=>$val['user_id'],'sign'=>'customer_no']);
+// if($id){
+// $stat->updateinfo(['user_id'=>$val['user_id'],'sign'=>'customer_no'],['number'=>$val['number'],'create_time'=>strtotime("-1 day")]);
+// }else{
+// $val['sign'] = 'customer_no';
+// $val['create_time'] = strtotime("-1 day");
+// $stat->addinfo($val);
+// }
+// }
+// }
+// return $data;
+// }
+ //查询线索数据
+ public function todayUid($where){
+ $data = $this->alias('a')
+ ->leftJoin( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->join( 'longbing_card_user c', 'a.uid = c.id','left' )
+ ->where($where)
+ ->group( 'a.uid, a.to_uid' )
+ ->count();
+ return $data;
+ }
+ //线索池
+ public function xian($where){
+ $sc1 = $this->alias('a')
+ //->join( 'longbing_card_collection b', 'a.uid = b.user_id' )
+ ->field('uid,to_uid,intention')
+ ->where($where)
+ ->column('to_uid','uid');
+// if($sc1){
+// foreach ($sc1 as $key=>$value){
+// $uid = $this->where(['uid'=>$key,'intention'=>1])->value('uid');
+// if($uid){
+// unset($sc1[$key]);
+// }
+// }
+// }
+ return count($sc1);
+ }
+ //今天线索池
+ public function Todayxian($where){
+ $sc1 = $this->alias('a')
+ //->join( 'longbing_card_collection b', 'a.uid = b.user_id' )
+ ->field('uid,to_uid,intention')
+ ->whereDay('create_time')
+ ->where($where)
+ ->column('to_uid','uid');
+// if($sc1){
+// foreach ($sc1 as $key=>$value){
+// $uid = $this->where(['uid'=>$key,'intention'=>1])->value('uid');
+// if($uid){
+// unset($sc1[$key]);
+// }
+// }
+// }
+ return count($sc1);
+ }
+ //总线索数量
+ public function allXian($where){
+ $data = $this->alias('a')->leftJoin( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->join( 'longbing_card_user c', 'a.uid = c.id' )
+ ->where($where)
+ ->group( 'a.uid, a.to_uid' )->count();
+ return $data;
+ }
+ public function getlistCount($where){
+ return $this->where($where)->count();
+ }
+ //累计访问量
+ public function visit($where){
+ $visit_number = 0;
+ $visit = $this->alias('a')
+ ->join( 'longbing_card_count b', 'a.uid = b.user_id && a.to_uid = b.to_uid' )
+ ->field('count(a.to_uid) as number')
+ ->where($where)
+ ->group('a.to_uid')
+ // ->where($where)
+ ->select()->toArray();
+ if($visit){
+ foreach ($visit as $value){
+ $visit_number += $value['number'];
+ }
+ }
+ return $visit_number;
+ }
+ public function staffInfo($where_s,$page,$list_rows){
+ $data = $this->alias('a')
+ ->join( 'longbing_card_user_info b', 'a.to_uid = b.fans_id' )
+ ->join( 'longbing_card_company c', 'b.company_id = c.id')
+ ->join( 'longbing_card_job d', 'b.job_id = d.id','left' )
+ ->join( 'longbing_card_user e', 'e.id = b.fans_id' )
+ ->where($where_s)
+ ->field('avatar,b.name,company_id,job_id,b.phone,a.create_time,c.name as company_name,d.name as job_name,b.fans_id,a.uniacid,b.create_time as start_time,a.to_uid,e.create_time as start_time')
+ ->find();//
+ $arr =[] ;
+ $follow_info = [];
+ $radar_count = [];
+ $behavior = [];
+ $ability = [];
+ $Interest = [];
+ $active = [];
+ $start_time = 0;
+ if($data){
+ $data = $data ->toArray();
+ if ($data['job_name'] === null)
+ {
+ $data[ 'job_name' ] = '未设置职位';
+ }
+ $timediff = time() - $data['start_time'];
+ $data['day'] = intval($timediff / 86400);
+ $data['time'] = '今天'.date('H:i',time());
+ // $card_value = new CardValue();
+// $rest = $card_value->bossGetAiValue($data['to_uid'],$data['uniacid']);
+// $data['total_info'] = $rest['data'];
+ $data['create_time'] = date('Y-m-d',$data['create_time']);
+ //新增线索
+ $collect = new Collection();
+ $beginToday=mktime(0,0,0,date('m'),date('d'),date('Y'));
+ $endToday=mktime(0,0,0,date('m'),date('d')+1,date('Y'))-1;
+
+ $beginYesterday=mktime(0,0,0,date('m'),date('d')-1,date('Y'));
+ $endYesterday=mktime(0,0,0,date('m'),date('d'),date('Y'))-1;
+
+ $beginbeforeYesterday=mktime(0,0,0,date('m'),date('d')-2,date('Y'));
+ $endbeforeYesterday=mktime(0,0,0,date('m'),date('d')-1,date('Y'))-1;
+ $user_id = $data['fans_id'];
+ $stat = new CardStatistics();
+ //累计线索
+// $wherex[] =[
+// ['user_id','=',$user_id],
+// ['uniacid','=',$this->_uniacid],
+// ['table','=','customer']
+// ];
+
+ //查询关联公司的员工
+// $user_info = new UserInfo();
+ //一个公司的员工
+// $other_staff = $user_info->getIsStaff($user_id,$data['uniacid']);
+
+ //日增长线索
+ $whes[] = [
+ ['intention','=',0],
+ ['a.uid','<>',$user_id],['a.to_uid','=',$user_id],['a.uniacid','=',$data['uniacid']]
+
+ ];
+ $cumulative_clues = $collect->todayUid($whes);
+ $todayKh = $collect->today($whes);
+ //昨天线索
+ $yesterdaytodayKh = $collect->Yesterday($whes);
+ //前天的线索
+ $whes[1] =[
+ [ 'a.create_time', 'BETWEEN', [ $beginbeforeYesterday, $endbeforeYesterday ]]
+ ];
+ $beforXs = $collect->todayUid($whes);
+ //昨天对比前天新增数
+ $contrastKh =$yesterdaytodayKh-$beforXs;
+
+ //线索池
+ $whes1[] =[
+
+ ['a.uid','<>',$user_id],['a.to_uid','=',$user_id],['a.uniacid','=',$data['uniacid']]
+ ];
+ $xs = $collect->todayUid($whes1);
+ //今天的线索池
+ $whes1[1] =[[ 'a.create_time', 'BETWEEN', [ $beginToday, $endToday ]]];
+ $todayxs = $collect->todayUid($whes1);
+ //昨天线索池
+ $whes1[1] =[[ 'a.create_time', 'BETWEEN', [ $beginYesterday, $endYesterday ]]];
+ $yesterdayxs = $collect->todayUid($whes1);
+ //前天线索池
+ $whes1[1] =[[ 'a.create_time', 'BETWEEN', [ $beginbeforeYesterday, $endbeforeYesterday ]]];
+ $beforexs = $collect->todayUid($whes1);
+ //昨天对比前天新增数
+ $contrastxs =$yesterdayxs-$beforexs;
+ $whez[] =[
+ ['a.uid','<>',$user_id],
+ ['intention','=',1],
+ ['a.to_uid','=',$user_id],
+ ['a.uniacid','=',$data['uniacid']]
+ ];
+
+// //累计客户数量
+ $customer = $collect->todayUid($whez);
+
+ //日增长客户
+ $today = $collect->today($whez);
+ //日线索增长
+ $addTodayxs = $todayxs-$today;
+ //昨天客户数
+ $yesterdaykh = $collect->Yesterday($whez);
+ //前天的客户
+ $whez[] = [
+ [ 'a.update_time', 'BETWEEN', [ $beginbeforeYesterday, $endbeforeYesterday ]]
+ ];
+ $beforkh = $collect->todayUid($whez);
+ //昨天对比前天新增数
+ $contrastkh =$yesterdaykh-$beforkh;
+
+ //累计访问量
+ $card_count = new CardCount();
+// $visit_number = $stat->getCustomerCount([['user_id','=',$user_id],
+// ['sign','=','praise'],
+// ['type','=',2],['uniacid','=',$this->_uniacid]]);
+
+ //今天的访问量
+ $wheres[] = [
+ ['to_uid','=',$user_id],
+ ['sign','=','praise'],
+ ['type','=',2],
+ ['uniacid','=',$data['uniacid']]
+ ];
+ $visit_number = $card_count->getCount($wheres);
+ $wheres[1] =[[ 'create_time', 'BETWEEN', [ $beginToday, $endToday ]]];
+ $todayVisitNumber = $card_count->getCount($wheres);
+ //昨天的访问量
+ $wheres[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginYesterday, $endYesterday ] ],
+ ];
+ $yesterdayVisit = $card_count->getCount($wheres);
+ //前天的访问量
+ $wheres[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginbeforeYesterday, $endbeforeYesterday] ],
+ ];
+ $beforVisit = $card_count->getCount($wheres);
+ //昨天对比前天新增数
+ $contrastVisit =$yesterdayVisit-$beforVisit;
+
+ //咨询
+ //消息
+ $whereMsg[] = [
+ ['message_type','=','text'],
+ ['deleted','=',0],
+ ['uniacid','=',$this->_uniacid],
+ ['target_id','=',$user_id]
+ ];
+ $card_message = new CardMessage();
+ //累计消息
+ $message = $card_message->getCount($whereMsg);
+ //今天消息
+ $whereMsg[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginToday, $endToday ] ],
+ ];
+ $today_message = $card_message->getCount($whereMsg);
+ //昨天的消息
+ $whereMsg[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginYesterday, $endYesterday ] ],
+ ];
+ $Yesterday_message = $card_message->getCount($whereMsg);
+ //前天的消息
+ $whereMsg[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginbeforeYesterday, $endbeforeYesterday ] ],
+ ];
+ $before_message = $card_message->getCount($whereMsg);
+ $zx = $card_count->zxInfo($user_id,[],1);
+ $zx = $zx+$message;
+ $where1 = ['create_time','BETWEEN',[ $beginToday, $endToday ]];
+ $zxtoday = $card_count->zxInfo($user_id,$where1,1);
+ $zxtoday = $zxtoday+$today_message;
+ //昨天的咨询
+ $where1 = ['create_time','BETWEEN',[ $beginYesterday, $endYesterday ]];
+ $zxYesterday = $card_count->zxInfo($user_id,$where1,1);
+ $zxYesterday = $zxYesterday+$Yesterday_message;
+ //前天的咨询
+ $where1 = ['create_time','BETWEEN',[ $beginbeforeYesterday, $endbeforeYesterday ]];
+ $zxbefore = $card_count->zxInfo($user_id,$where1,1);
+ $zxbefore = $zxbefore+$before_message;
+ //昨天对比前天新增数
+ $contrastzx =$zxYesterday-$zxbefore;
+
+ //跟进客户次数
+ $user_mark = new UserFollow();
+ $where3[] = [
+ ['staff_id','=',$user_id],
+ ['status','=',1],
+ //['uniacid','=',$this->_uniacid]
+ ];
+ $mark = $user_mark->getCount($where3);
+ $where3[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginToday, $endToday ] ],
+ ];
+ $today_mark = $user_mark->getCount($where3);
+ //昨天的跟进客户
+ $where3[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginYesterday, $endYesterday ] ],
+ ];
+ $Yesterday_mark = $user_mark->getCount($where3);
+ //前天的跟进客户
+ $where3[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginbeforeYesterday, $endbeforeYesterday ] ],
+ ];
+ $before_mark = $user_mark->getCount($where3);
+ $contrastzmark =$Yesterday_mark-$before_mark;
+ //被转发次数
+// $forward = new CardForward();
+ $where4[] = [
+ ['to_uid','=',$user_id],
+ ['type','=',4],
+ ['sign','=','praise'],
+ ['uniacid','=',$data['uniacid']]
+ ];
+ $forward_count = $card_count->getCount($where4);
+ $today_forward_count =$card_count->gettoday($where4);
+ //昨天转发
+ $Yesterday_forward_count =$card_count->getYesterday($where4);
+ //前天转发
+ $where4[] = [
+ [ 'create_time', 'BETWEEN', [$beginbeforeYesterday, $endbeforeYesterday] ],
+ ];
+ $before_forward_count =$card_count->getCount($where4);
+ $contrastzforward =$Yesterday_forward_count-$before_forward_count;
+ //累计被点赞次数
+ $where5[] = [
+ ['to_uid','=',$user_id],
+ ['type','=',3],
+ ['sign','=','praise'],
+ ['uniacid','=',$data['uniacid']]
+ ];
+ $dz = $card_count->getCount($where5);
+ $where5[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginToday, $endToday ] ],
+ ];
+ $today_dz = $card_count->getCount($where5);
+ //昨天点赞
+ $where5[1] = [
+ [ 'create_time', 'BETWEEN', [$beginYesterday, $endYesterday] ],
+ ];
+ $Yesterday_dz = $card_count->getCount($where5);
+ //前天点赞
+ $where5[1] = [
+ [ 'create_time', 'BETWEEN', [$beginbeforeYesterday, $endbeforeYesterday] ],
+ ];
+ $before_dz = $card_count->getCount($where5);
+ $contrastzdz =$Yesterday_dz-$before_dz;
+ //累计被保存次数
+ $where6[] = [
+ ['to_uid','=',$user_id],
+ ['type','=',1],
+ ['sign','=','copy'],
+ ['uniacid','=',$data['uniacid']]
+ ];
+ $bc = $card_count->getCount($where6);
+ $where6[1] = [
+ [ 'create_time', 'BETWEEN', [ $beginToday, $endToday ] ],
+ ];
+ $today_bc = $card_count->getCount($where6);
+ //昨天保存
+ $where6[1] = [
+ [ 'create_time', 'BETWEEN', [$beginYesterday, $endYesterday] ],
+ ];
+ $Yesterday_bc = $card_count->getCount($where6);
+ //前天保存
+ $where6[1] = [
+ [ 'create_time', 'BETWEEN', [$beginbeforeYesterday, $endbeforeYesterday] ],
+ ];
+ $before_bc = $card_count->getCount($where6);
+ $contrastzbc =$Yesterday_bc-$before_bc;
+ //商城订单笔数和销售金额
+ $admin_goods = new CardShopOrder();
+ $where7[]= [
+ ['company_id','=',$data['company_id']],
+ ['to_uid','=',$user_id],
+ ['uniacid','=',$data['uniacid']]
+ ];
+ $sales_count = $admin_goods->getGoosSale($where7);
+ //昨天的商品销售
+ $where7[] = [
+ [ 'create_time', 'BETWEEN', [$beginYesterday, $endYesterday] ],
+ ];
+ $Yesterday_sales_count = $admin_goods->getGoosSale($where7);
+ //数据
+ $arr = [
+ 'count'=>[
+ [
+ [
+ 'name'=>'累计线索(人)',
+ 'number'=>$xs,
+ 'rate'=>$todayKh,
+ ],
+ [
+ 'name'=>'线索池(人)',
+ 'number'=>$cumulative_clues,
+ // 'text'=>$title,
+ 'rate'=>$addTodayxs,
+ // 'up'=>$up
+ ],
+ [
+ 'name'=>'累计客户(人)',
+ 'number'=>$customer,
+ 'rate'=>$today,
+ ],
+ [
+ 'name'=>'累计访问量(次)',
+ 'number'=>$visit_number,
+ 'rate'=>$todayVisitNumber,
+ ],
+ [
+ 'name'=>'累计咨询(次)',
+ 'number'=>$zx,
+ 'rate'=>$zxtoday,
+ ],
+ [
+ 'name'=>'累计跟进客户(次)',
+ 'number'=>$mark,
+ 'rate'=>$today_mark,
+ ],
+ [
+ 'name'=>'累计被转发(次)',
+ 'number'=>$forward_count,
+ 'rate'=>$today_forward_count,
+ ],
+ [
+ 'name'=>'累计被点赞(次)',
+ 'number'=>$dz,
+ 'rate'=>$today_dz,
+ ],
+ [
+ 'name'=>'累计被保存(次)',
+ 'number'=>$bc,
+ 'rate'=>$today_bc,
+ ]
+ ],
+ [
+ [
+ 'name'=>'新增线索(人)',
+ 'number'=>$yesterdaytodayKh,
+ 'rate'=>$contrastKh,
+ ],
+ [
+ 'name'=>'变动线索池(人)',
+ 'number'=>$yesterdayxs,
+ 'rate'=>$contrastxs,
+ ],
+ [
+ 'name'=>'新增客户(人)',
+ 'number'=>$yesterdaykh,
+ 'rate'=>$contrastkh,
+ ],
+ [
+ 'name'=>'新增访问量(次)',
+ 'number'=>$yesterdayVisit,
+ 'rate'=>$contrastVisit,
+ ],
+ [
+ 'name'=>'新增咨询(次)',
+ 'number'=>$zxYesterday,
+ 'rate'=>$contrastzx,
+ ],
+ [
+ 'name'=>'新增跟进客户(次)',
+ 'number'=>$Yesterday_mark,
+ 'rate'=>$contrastzmark,
+ ],
+ [
+ 'name'=>'新增被转发(次)',
+ 'number'=>$Yesterday_forward_count,
+ 'rate'=>$contrastzforward,
+ ],
+ [
+ 'name'=>'新增被点赞(次)',
+ 'number'=>$Yesterday_dz,
+ 'rate'=>$contrastzdz,
+ ],
+ [
+ 'name'=>'新增被保存(次)',
+ 'number'=>$Yesterday_bc,
+ 'rate'=>$contrastzbc,
+ ]
+ ],
+ ],
+ 'goods_sale'=>[
+ $sales_count,$Yesterday_sales_count
+ ]
+ ];
+ $title1 = '日增涨';
+ $title2 = '日减少';
+ $title3 = '持平 -';
+ foreach ($arr['count'][0] as $key=>$value){
+ if($value['rate']>0){
+ $arr['count'][0][$key]['text'] = $title1;
+ $arr['count'][0][$key]['up'] =1;
+ }elseif ($value['rate']==0){
+ $arr['count'][0][$key]['up'] =-1;
+ $arr['count'][0][$key]['text'] = $title3;
+ }else{
+ $arr['count'][0][$key]['up'] =0;
+ $arr['count'][0][$key]['text'] = $title2;
+ }
+ $arr['count'][0][$key]['rate'] = abs($value['rate']);
+ }
+ foreach ($arr['count'][1] as $k=>$val){
+
+ if($val['rate']>0){
+ $arr['count'][1][$k]['text'] = $title1;
+ $arr['count'][1][$k]['up'] =1;
+ }elseif ($val['rate']==0){
+ $arr['count'][1][$k]['up'] =-1;
+ $arr['count'][1][$k]['text'] = $title3;
+ }else{
+ $arr['count'][1][$k]['up'] =0;
+ $arr['count'][1][$k]['text'] = $title2;
+ }
+ $arr['count'][1][$k]['rate'] = abs($val['rate']);
+ }
+ //跟进客户记录
+ $follow_info = UserFollow::alias( 'a' )
+ ->join( 'longbing_card_user b', 'a.user_id = b.id')
+ ->field( [ 'content', 'a.create_time','user_id','b.nickName as name' ] )
+ ->where( [
+ [ 'a.staff_id', '=',$user_id ] ]
+ )->order( 'a.id', 'desc' )
+ ->paginate( [ 'list_rows' => 4, 'page' => 1 ])->toArray();
+ $follow_info['data'] = lbHandelRadarDate( $follow_info['data'], 'create_time' );
+ foreach ($follow_info['data'] as $index => $item )
+ {
+ $follow_info['data'][ $index ][ 'create_time' ] = date( 'Y-m-d H:i', $item[ 'create_time' ] );
+ }
+
+ $ardar = new CardCount();
+ $radar_count = $ardar->radarList([ [ 'a.to_uid', '=', $user_id ],[ 'a.user_id', '<>', $user_id ] ], 1,4);
+ $radar_count['data'] = lbHandelRadarDate( $radar_count['data'], 'create_time' );
+ if($radar_count['data']){
+ foreach ($radar_count['data'] as $k => $v )
+ {
+ $radar_count['data'][ $k ][ 'create_time' ] = date( 'Y-m-d H:i', $v[ 'create_time' ] );
+ }
+ }
+ //客户行为
+ $card_count = new CardCount();
+ $behavior = $card_count->getsss($user_id,$data['uniacid'],1);
+ //能力雷达
+ $card_value = new CardValue();
+
+ $ability = $card_value->bossGetAiValue($user_id,$data['uniacid']);
+ //兴趣占比
+ $Interest = $ardar->doPageBossInterest(['to_uid','=',$user_id],$data['uniacid']);
+ //客户活跃度
+ $active = $ardar->active($user_id,$data['uniacid']);
+ $timediff = time() - $data['start_time'];
+ $start_time = intval($timediff / 86400);
+ }
+ $data['look'] =$arr;
+ $data['interaction'] =$radar_count;
+ $data['follow_info'] =$follow_info;
+ $data['behavior'] =$behavior;
+ $data['ability'] =$ability;
+ $data['interest'] =$Interest;
+ $data['active'] =$active;
+ $data['day'] = $start_time;
+ $data = transImagesOne($data, ['avatar']);
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-30 15:06
+ * @功能说明:获取浏览过的名片
+ */
+ public function getCard($uid,$uniacid){
+ //查看浏览过的名片
+ $data = $this->alias('a')
+ ->join('longbing_card_user b', 'a.to_uid = b.id AND b.is_staff = 1')
+ ->where(['uid'=>$uid])
+ ->value('to_uid');
+
+ //如果没有就给一个推荐的
+ if(empty($data)){
+
+ $data = Db::name('longbing_card_user_info')->where(['uniacid'=>$uniacid,'is_default'=>1])->value('fans_id');
+ }
+ //修改
+ if(!empty($data)){
+ //修改最近浏览的名片
+ Db::name('longbing_card_user')->where(['id'=>$uid])->update(['last_staff_id'=>$data]);
+ //增肌默认分配次数
+ Db::name('longbing_card_user')->where(['id'=>$data])->inc('auto_count');
+ //缓存的键
+ $key = 'longbing_card_user_' . $uid;
+ //删除缓存
+ delCache($key,$uniacid);
+ }
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/Company.php b/app/card/model/Company.php
new file mode 100755
index 0000000..7aac3a5
--- /dev/null
+++ b/app/card/model/Company.php
@@ -0,0 +1,358 @@
+save($data);
+ return !empty($result);
+ }
+
+ /**
+ * @Purpose: 获取公司信息
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getInfo ( $uniacid = 0, $userId = 0, $company_id = 0 )
+ {
+ $company = [];
+
+ if ( $userId )
+ {
+ $userInfo = UserInfo::where( [ [ 'fans_id', '=', $userId ] ] )
+ ->find();
+ if ( $userInfo && $userInfo[ 'company_id' ] )
+ {
+ $company = self::where( [ [ 'id', '=', $userInfo[ 'company_id' ] ], [ 'status', '=', 1 ] ] )
+ // ->withoutField( [ 'auth_code' ] )
+ ->find();
+ }
+ }
+
+ if ( $company_id )
+ {
+ $company = self::where( [ [ 'id', '=', $company_id ], [ 'status', '=', 1 ] ] )
+ // ->withoutField( [ 'auth_code' ] )
+ ->find();
+ }
+
+ if ( is_array( $company ) && $company = [] )
+ {
+ $company = self::where( [ [ 'status', '=', 1 ], [ 'uniacid', '=', $uniacid ] ] )
+ // ->withoutField( [ 'auth_code' ] )
+ ->find();
+ }
+
+ if ( $company )
+ {
+ $company = $company->toArray();
+ $company = transImages( $company, [ 'culture' ] );
+ $company = transImagesOne( $company, [ 'logo', 'desc' ] );
+ $company[ 'shop_bg' ] = $company[ 'desc' ];
+ $company[ 'carousel' ] = $company[ 'culture' ];
+ }
+ return $company;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-21 14:02
+ * @功能说明:替换顶级公司的名字
+ */
+
+ public function changeTopName($company){
+
+ if(!empty($company['top_id'])){
+
+ $dis = [
+
+ 'status' => 1,
+
+ 'id' => $company['top_id'],
+
+ 'uniacid'=> $company['uniacid']
+
+ ];
+
+ $top_name = $this->where($dis)->value('name');
+
+ $short_name = $this->where($dis)->value('short_name');
+
+ if(!empty($top_name)){
+
+ $company['name'] = $top_name;
+
+ $company['short_name'] = $short_name;
+
+ }
+ }
+
+ return $company;
+ }
+
+ /**
+ * @Purpose: 根据用户id返回公司列表
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getListByUser ( $user_id, $uniacid, $is_all = 0, $company_id = 0 )
+ {
+ if ( $is_all )
+ {
+ $companyList = self::where( [ [ 'uniacid', '=', $uniacid ], [ 'status', '=', 1, ], [ 'pid', '=', 0 ] ] )
+ ->field( [ 'id', 'pid', 'name', 'logo', 'addr' ] )
+ ->order('top desc,pid asc,id desc')
+ ->select()
+ ->toArray();
+
+ $sonList = self::where( [ [ 'uniacid', '=', $uniacid ], [ 'status', '=', 1, ], [ 'pid', '<>', 0 ] ] )
+ ->field( [ 'id', 'pid', 'name', 'logo', 'addr' ] )
+ ->order('top desc,pid asc,id desc')
+ ->select()
+ ->toArray();
+
+ $companyList = self::handleCompanyLevel( $companyList, $sonList );
+
+ }
+ else
+ {
+ $modelCardBoss = new CardBoss();
+ $check = $modelCardBoss->where( [ [ 'user_id', '=', $user_id ], [ 'uniacid', '=', $uniacid ],
+ [ 'boss', '<>', '' ] ]
+ )
+ ->field( [ 'boss' ] )
+ ->find();
+ if ( !$check )
+ {
+ return $this->getListByUser( $user_id, $uniacid, $is_all = 1 );
+ }
+
+ $tmpArr = explode( ',', $check[ 'boss' ] );
+ $companyList = self::where( [ [ 'uniacid', '=', $uniacid ], [ 'status', '=', 1, ], [ 'id', 'in', $tmpArr ] ] )
+ ->field( [ 'id', 'pid', 'name', 'logo', 'addr' ] )
+ ->order('top desc,pid asc,id desc')
+ ->select()
+ ->toArray();
+ foreach ( $companyList as $index => $item )
+ {
+ $companyList[ $index ][ 'sec' ] = [];
+ }
+
+ }
+
+ $companyList = transImagesOne( $companyList, [ 'logo' ] );
+
+ foreach ( $companyList as $index => $item )
+ {
+ $companyList[ $index ][ 'selected' ] = 0;
+ if ( isset( $item[ 'id' ] ) && $item[ 'id' ] == $company_id )
+ {
+ $companyList[ $index ][ 'selected' ] = 1;
+ }
+ }
+
+ return $companyList;
+ }
+
+ /**
+ * @Purpose: 处理公司层级--无限级
+ *
+ * @Param: array $list 顶级公司列表
+ * @Param: array $son 部门列表
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function handleCompanyLevel ( $list, $son, $item_name = 'sec' )
+ {
+ foreach ( $list as $index => $item )
+ {
+ if ( !isset( $list[ $index ][ $item_name ] ) )
+ {
+ $list[ $index ][ $item_name ] = array();
+ }
+ foreach ( $son as $key => $value )
+ {
+ if ( $item[ 'id' ] == $value[ 'pid' ] )
+ {
+ array_push( $list[ $index ][ $item_name ], $value );
+ unset( $son[ $key ] );
+ }
+ }
+
+ if ( $list[ $index ][ $item_name ] && count( $list[ $index ][ $item_name ] ) && count( $son ) )
+ {
+
+ $list[ $index ][ $item_name ] = self::handleCompanyLevel( $list[ $index ][ $item_name ], $son, $item_name );
+ }
+ }
+
+
+ return $list;
+ }
+
+ /**
+ * @Purpose: 改变公司状态
+ *
+ * @Param:$company_id number 公司id
+ * @Param:$method number 操作类型 0 = 下架 1 = 上架 2 = 删除
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updateStatus ( $company_id, $method = 0 )
+ {
+ $result = false;
+ switch ( $method )
+ {
+ case 0:
+ $result = self::update( [ 'status' => 0 ], [ 'id' => $company_id ] );
+ $this->updateSonCompanyInfo( $company_id, [ 'status' => 0 ] );
+ break;
+ case 1:
+ $result = self::update( [ 'status' => 1 ], [ 'id' => $company_id ] );
+ break;
+ case 2:
+ $result = self::update( [ 'status' => -1 ], [ 'id' => $company_id ] );
+ $this->updateSonCompanyInfo( $company_id, [ 'status' => -1 ] );
+ break;
+ default:
+ return false;
+ }
+
+ if ( $result === false )
+ {
+ return false;
+ }
+
+ return $result;
+ }
+
+ /**
+ * @Purpose: 改变下级公司信息
+ *
+ * @Param:$company_id number 公司id
+ * @Param:$data array 修改内容
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function updateSonCompanyInfo ( $company_id, $data )
+ {
+ $list = self::where( [ [ 'pid', '=', $company_id ] ] )
+ ->select()
+ ->toArray();
+
+ foreach ( $list as $index => $item )
+ {
+ $check = self::where( [ [ 'pid', '=', $item[ 'id' ] ] ] )
+ ->count();
+ if ( $check )
+ {
+ $this->updateSonCompanyInfo( $item[ 'id' ], $data );
+ }
+ self::update( $data, [ 'id' => $item[ 'id' ] ] );
+ }
+
+ return true;
+ }
+
+ /**
+ * @Purpose: 获取公司和部门名
+ *
+ * @Param:$company_id number 公司id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+ public function getCompanyAndDepartmentName ( $company_id )
+ {
+ $info = self::where( [ [ 'id', '=', $company_id ] ] )
+ ->find();
+
+ if ( !$info )
+ {
+ return [ '未设置公司', '未设置部门' ];
+ }
+
+ if ( $info[ 'pid' ] == 0 )
+ {
+ return [ $info[ 'name' ], '未设置部门' ];
+ }
+
+ $topCompany = $this->getTopCompany( $info[ 'pid' ] );
+
+ $companyName = '未设置公司';
+
+ if ( $topCompany && $topCompany[ 'status' ] )
+ {
+ $companyName = $topCompany[ 'name' ];
+ }
+
+ return [ $companyName, $info[ 'name' ] ];
+
+ }
+
+ protected function getTopCompany ( $pid )
+ {
+ $info = self::where( [ [ 'id', '=', $pid ] ] )
+ ->find();
+ if ( !$info )
+ {
+ return '';
+ }
+
+ if ( $info[ 'pid' ] )
+ {
+ return $this->getTopCompany( $info[ 'pid' ] );
+ }
+
+ return $info;
+ }
+
+ public function getCompany($filter ,$field = [])
+ {
+ if(isset($filter['company_id']))
+ {
+ $filter['id'] = $filter['company_id'];
+ unset($filter['company_id']);
+ }
+ $result = $this->where($filter);
+ if(!empty($field)) $result = $result->field($field);
+ $result = $result->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/model/Config.php b/app/card/model/Config.php
new file mode 100755
index 0000000..41dfd0d
--- /dev/null
+++ b/app/card/model/Config.php
@@ -0,0 +1,71 @@
+ $uniacid,'agreement'=>'' ] );
+ }
+
+ public function getConfig ($uniacid)
+ {
+ $key = 'longbing_card_config_';
+
+ $cacheData = getCache($key, $uniacid);
+
+ // 暂时关闭缓存
+ $cacheData = false;
+
+ if ($cacheData)
+ {
+ $cacheData['fromCache'] = 1;
+ return $cacheData;
+ }
+
+ $data = self::where( [ [ 'uniacid', '=', $uniacid ] ] )
+ ->find();
+
+ if ( !$data )
+ {
+ $data = $this->initConfig($uniacid);
+ }
+
+ $data = $data->toArray();
+
+
+ $data = transImagesOne( $data, [ 'vr_cover', 'default_video', 'default_voice', 'appoint_pic', 'click_copy_show_img',
+ 'shop_carousel_more', 'copyright', 'default_video_cover' ], $uniacid
+ );
+ setCache( $key, $data, 36000, $uniacid );
+
+ return $data;
+ }
+ //获取
+ public function getConfigByUniacid($uniacid)
+ {
+ $result = $this->where(['uniacid' => $uniacid])->find();
+ if(!empty($result)){
+ $result = $result->toArray();
+ $result = transImagesOne($data, [ 'vr_cover', 'default_video', 'default_voice', 'appoint_pic', 'click_copy_show_img',
+ 'shop_carousel_more', 'copyright', 'default_video_cover' ], $uniacid);
+ }
+ return $result;
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/model/DefaultSetting.php b/app/card/model/DefaultSetting.php
new file mode 100755
index 0000000..0b1ee55
--- /dev/null
+++ b/app/card/model/DefaultSetting.php
@@ -0,0 +1,54 @@
+where($dis)->find();
+
+ if(empty($data)){
+
+ $dis['my_photo_cover'] = !empty($dis['my_photo_cover'])?$dis['my_photo_cover']:'';
+
+ $dis['share_text'] = !empty($dis['share_text'])?$dis['share_text']:'';
+
+ $this->insert($dis);
+ }
+
+ return $this->where($dis)->field($field)->find()->toArray();
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-18 12:24
+ * @功能说明:配置编辑
+ */
+ public function settingUpdate($dis,$data){
+
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/card/model/Job.php b/app/card/model/Job.php
new file mode 100755
index 0000000..3ac16b1
--- /dev/null
+++ b/app/card/model/Job.php
@@ -0,0 +1,33 @@
+save($data);
+ return !empty($result);
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/model/User.php b/app/card/model/User.php
new file mode 100755
index 0000000..5eda194
--- /dev/null
+++ b/app/card/model/User.php
@@ -0,0 +1,453 @@
+where('nickName','like', '%' . $value . '%');
+ }
+
+ public function createUser($data)
+ {
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ return !empty($result);
+ }
+
+ public function updateUser($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ public function getUser($filter)
+ {
+ $result = $this->where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ public function listUser($filter)
+ {
+
+ }
+
+
+ /**
+ * @param $where
+ * @功能说明:名片导出
+ * @author chenniang
+ * @DataTime: 2020-04-14 14:41
+ */
+ public function cardExcel($where,$mapor,$type=0,$start_time='',$end_time=''){
+
+ $data = User::alias( 'a' )
+ ->join( 'longbing_card_user_info b', 'b.fans_id = a.id' ,'LEFT')
+ ->join( 'longbing_card_company c', 'b.company_id = c.id', 'LEFT' )
+ ->join( 'longbing_card_company d', 'c.top_id = d.id', 'LEFT' )
+ ->where( $where )
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field( [ 'b.id as card_id', 'b.name', 'b.avatar', 'b.job_id', 'b.company_id', 'b.phone',
+ 'b.create_time', 'a.nickName', 'a.avatarUrl', 'a.is_staff', 'a.is_boss',
+ 'c.name as company_name', 'd.name as top_company_name', 'b.is_default', 'a.id' ,'a.import','a.uniacid']
+ )
+ ->group('a.id')
+ ->order( [ 'a.is_boss' => 'desc', 'a.is_staff' => 'desc', 'a.update_time' => 'desc', 'a.id' => 'desc' ] )
+ ->select()
+ ->toArray();
+
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ if(empty($v['top_company_name'])){
+
+ $data[$k]['top_company_name'] = $v['company_name'];
+
+ $data[$k]['company_name'] = '未设置部门';
+ }
+ $data[$k]['name'] = !empty($v['name'])?$v['name']:$v['nickName'];
+ //累计客户数量
+ $data[$k]['all_customer'] = $this->customerCount($v['id'],$v['uniacid'],0,$end_time);
+ //新增客户
+ $data[$k]['new_customer'] = $this->customerCount($v['id'],$v['uniacid'],$start_time,$end_time);
+ //累计线索
+ $data[$k]['all_collection'] = $this->collectionCount($v['id'],$v['uniacid'],0,$end_time);
+ //新增线索
+ $data[$k]['new_collection'] = $this->collectionCount($v['id'],$v['uniacid'],$start_time,$end_time);
+ //总浏览量
+ $data[$k]['all_visit'] = $this->visitCount($v['id'],$v['uniacid'],0,$end_time);
+ //新增浏览量
+ $data[$k]['new_visit'] = $this->visitCount($v['id'],$v['uniacid'],$start_time,$end_time);
+ //累计转发
+ $data[$k]['all_zf'] = $this->zfCount($v['id'],$v['uniacid'],0,$end_time);
+ //新增转发
+ $data[$k]['new_zf'] = $this->zfCount($v['id'],$v['uniacid'],$start_time,$end_time);
+ //累计被保存
+ $data[$k]['all_save'] = $this->saveCount($v['id'],$v['uniacid'],0,$end_time);
+ //新增保存
+ $data[$k]['new_save'] = $this->saveCount($v['id'],$v['uniacid'],$start_time,$end_time);
+ //累计点赞
+ $data[$k]['all_dz'] = $this->dzCount($v['id'],$v['uniacid'],0,$end_time);
+ //新增点赞
+ $data[$k]['new_dz'] = $this->dzCount($v['id'],$v['uniacid'],$start_time,$end_time);
+ }
+ }
+
+ $header=[
+ '序号',
+ '分公司',
+ '部门',
+ '员工姓名',
+ '客户数',
+ '',
+ '累计线索',
+ '',
+ '累计浏览量',
+ '',
+ '累计被转发',
+ '',
+ '累计被保存',
+ '',
+ '累计被点赞',
+ '',
+ ];
+
+ if($type==1){
+ $header_one=[
+ '',
+ '',
+ '',
+ '',
+ '新增',
+ '总数',
+ '新增',
+ '总数',
+ '新增',
+ '总数',
+ '新增',
+ '总数',
+ '新增',
+ '总数',
+ '新增',
+ '总数',
+ ];
+ }else{
+
+ $header_one=[
+ '',
+ '',
+ '',
+ '',
+ '累计新增',
+ '总数',
+ '累计新增',
+ '总数',
+ '累计新增',
+ '总数',
+ '累计新增',
+ '总数',
+ '累计新增',
+ '总数',
+ '累计新增',
+ '总数',
+ ];
+ }
+ $new_data = [];
+
+ $new_data[] = $header_one;
+
+ $data = array_values($data);
+
+ foreach ($data as $k=>$v){
+
+ $info = array();
+
+ $info[] = $k+1;
+
+ $info[] = $v['top_company_name'];
+
+ $info[] = $v['company_name'];
+
+ $info[] = $v['name'];
+
+ $info[] = $v['new_customer'];
+
+ $info[] = $v['all_customer'];
+
+ $info[] = $v['new_collection'];
+
+ $info[] = $v['all_collection'];
+
+ $info[] = $v['new_visit'];
+
+ $info[] = $v['all_visit'];
+
+ $info[] = $v['new_zf'];
+
+ $info[] = $v['all_zf'];
+
+ $info[] = $v['new_save'];
+
+ $info[] = $v['all_save'];
+
+ $info[] = $v['new_dz'];
+
+ $info[] = $v['all_dz'];
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $name = '员工列表';
+
+ if($type==1){
+
+ $name = date('Y-m-d',$start_time).'——'.'员工列表';
+ }
+
+ if($type==0&&!empty($start_time)&&!empty($end_time)){
+
+ $name = date('Y-m-d',$start_time).'——'.date('Y-m-d',$end_time).'-'.'员工列表';
+ }
+
+
+// dump($name);exit;
+ $fileName=$excel->excelExport($name,$header,$new_data,1);
+
+ return $data;
+
+ }
+
+
+ /**
+ * @param $user_id
+ * @param $start_time
+ * @param $end_time
+ * @功能说明:客户数量
+ * @author chenniang
+ * @DataTime: 2020-04-14 16:14
+ */
+ public function customerCount($user_id,$uniacid,$start_time='',$end_time=''){
+ //线索模型
+ $collect = new Collection();
+
+ $whez[] =[
+
+ ['a.uid','<>',$user_id],
+
+ ['intention','=',1],
+
+ ['a.to_uid','=',$user_id],
+
+ ['a.uniacid','=',$uniacid]
+ ];
+
+ //如果选了时间
+ if(!empty($start_time)||!empty($end_time)){
+
+ $whez[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+
+ $new_customer = $collect->todayUid($whez);
+
+ return $new_customer;
+
+ }
+
+ /**
+ * @param $user_id
+ * @param $start_time
+ * @param $end_time
+ * @功能说明:线索数量
+ * @author chenniang
+ * @DataTime: 2020-04-14 16:14
+ */
+ public function collectionCount($user_id,$uniacid,$start_time='',$end_time=''){
+ //线索模型
+ $collect = new Collection();
+
+
+ $whes[] = [
+
+ ['a.uid','<>',$user_id],
+
+ ['a.to_uid','=',$user_id],
+
+ ['a.uniacid','=',$uniacid],
+
+// ['intention','=',0],
+ ];
+
+ //如果选了时间
+ if(!empty($start_time)||!empty($end_time)){
+
+ $whes[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+
+ $data = $collect->todayUid($whes);
+
+ return $data;
+
+ }
+
+ /**
+ * @param $user_id
+ * @param $start_time
+ * @param $end_time
+ * @功能说明:线索数量
+ * @author chenniang
+ * @DataTime: 2020-04-14 16:14
+ */
+ public function visitCount($user_id,$uniacid,$start_time='',$end_time=''){
+
+ //雷达模型
+ $card_count = new CardCount();
+
+ $wheres[] = [
+ ['to_uid','=',$user_id],
+
+ ['sign','=','praise'],
+
+ ['type','=',2],
+
+ ['uniacid','=',$uniacid]
+ ];
+
+ //如果选了时间
+ if(!empty($start_time)||!empty($end_time)){
+
+ $wheres[] = ['create_time','between',"$start_time,$end_time"];
+ }
+ //新增浏览量
+ $data = $card_count->getCount($wheres);
+
+ return $data;
+
+ }
+
+ /**
+ * @param $user_id
+ * @param $start_time
+ * @param $end_time
+ * @功能说明:转发数量
+ * @author chenniang
+ * @DataTime: 2020-04-14 16:14
+ */
+ public function zfCount($user_id,$uniacid,$start_time='',$end_time=''){
+
+ //雷达模型
+ $card_count = new CardCount();
+
+ $where4[] = [
+
+ ['to_uid','=',$user_id],
+
+ ['type','=',4],
+
+ ['sign','=','praise'],
+
+ ['uniacid','=',$uniacid]
+ ];
+
+ //如果选了时间
+ if(!empty($start_time)||!empty($end_time)){
+
+ $where4[] = ['create_time','between',"$start_time,$end_time"];
+ }
+ //新增浏览量
+ $data = $card_count->getCount($where4);
+
+ return $data;
+
+ }
+
+ /**
+ * @param $user_id
+ * @param $start_time
+ * @param $end_time
+ * @功能说明:保存数量
+ * @author chenniang
+ * @DataTime: 2020-04-14 16:14
+ */
+ public function saveCount($user_id,$uniacid,$start_time='',$end_time=''){
+ //雷达模型
+ $card_count = new CardCount();
+
+ $where6[] = [
+
+ ['to_uid','=',$user_id],
+
+ ['type','=',1],
+
+ ['sign','=','copy'],
+
+ ['uniacid','=',$uniacid]
+ ];
+ //如果选了时间
+ if(!empty($start_time)||!empty($end_time)){
+
+ $where6[] = ['create_time','between',"$start_time,$end_time"];
+ }
+ //保存
+ $data = $card_count->getCount($where6);
+
+ return $data;
+
+ }
+
+ /**
+ * @param $user_id
+ * @param $start_time
+ * @param $end_time
+ * @功能说明:点赞数量
+ * @author chenniang
+ * @DataTime: 2020-04-14 16:14
+ */
+ public function dzCount($user_id,$uniacid,$start_time='',$end_time=''){
+ //雷达模型
+ $card_count = new CardCount();
+
+ $where5[] = [
+
+ ['to_uid','=',$user_id],
+
+ ['type','=',3],
+
+ ['sign','=','praise'],
+
+ ['uniacid','=',$uniacid]
+ ];
+ //如果选了时间
+ if(!empty($start_time)&&!empty($end_time)){
+
+ $where5[] = ['create_time','between',"$start_time,$end_time"];
+ }
+ //点赞
+ $data = $card_count->getCount($where5);
+
+ return $data;
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/model/UserFollow.php b/app/card/model/UserFollow.php
new file mode 100755
index 0000000..2465fcd
--- /dev/null
+++ b/app/card/model/UserFollow.php
@@ -0,0 +1,17 @@
+where($where)->count();
+ return $data;
+ }
+
+}
\ No newline at end of file
diff --git a/app/card/model/UserInfo.php b/app/card/model/UserInfo.php
new file mode 100755
index 0000000..b426e48
--- /dev/null
+++ b/app/card/model/UserInfo.php
@@ -0,0 +1,49 @@
+save($data);
+ return !empty($result);
+ }
+
+ public function updateUser($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ public function cardList ()
+ {
+ $data = $this->where(['fans_id' => 1])->find();
+ return $data;
+ }
+
+ public function getUserPhone($user_id ,$uniacid = null)
+ {
+ $filter = ['fans_id' => $user_id];
+ if(!empty($uniacid)) $filter['uniacid'] = $uniacid;
+ $result = $this->where($filter)->field('phone,wechat')->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ public function getStaffMaxAutoCount($filter)
+ {
+ $filter['is_staff'] = 1;
+ $filter['is_default'] = 1;
+ $count = $this->where($filter)->min('auto_count');
+ return $count;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/UserMark.php b/app/card/model/UserMark.php
new file mode 100755
index 0000000..3efa6fe
--- /dev/null
+++ b/app/card/model/UserMark.php
@@ -0,0 +1,43 @@
+where($where3)->count();
+ }
+ public function getCountlist($where){
+ $data = $this
+ ->field('staff_id as user_id,count(staff_id) as number,uniacid')
+ ->whereDay('create_time','yesterday')
+ ->group('staff_id')
+ ->where($where)->select()->toArray();
+ if($data){
+ foreach ($data as $key=>$val){
+ $data[$key]['table'] = 'mark';
+ $data[$key]['create_time'] = strtotime("-1 day");
+ }
+ $stat = new CardStatistics();
+ $stat->createRows($data);
+ }
+ return $data;
+ }
+ //跟进状态
+ public function getMarkStatus($where){
+ $mark = $this->where($where)->value('mark');
+ if($mark ==2){
+ $mark ='已成交';
+ }elseif ($mark ==1){
+ $mark ='跟进中';
+ }else{
+ $mark ='还未跟进';
+ }
+ return $mark;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/UserPhone.php b/app/card/model/UserPhone.php
new file mode 100755
index 0000000..915bf59
--- /dev/null
+++ b/app/card/model/UserPhone.php
@@ -0,0 +1,21 @@
+ $user_id];
+ if(!empty($uniacid)) $filter['uniacid'] = $uniacid;
+ $result = $this->where($filter)->field('phone')->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/card/model/UserSk.php b/app/card/model/UserSk.php
new file mode 100755
index 0000000..6154f30
--- /dev/null
+++ b/app/card/model/UserSk.php
@@ -0,0 +1,19 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/card/route/route.php b/app/card/route/route.php
new file mode 100755
index 0000000..c51a051
--- /dev/null
+++ b/app/card/route/route.php
@@ -0,0 +1,215 @@
+ $uniacid ,'is_staff' => 1] )->count() ;
+ $result = false ;
+ if (!$count){
+ $result = $this->addUserToStaff($staff_id , [] , $uniacid) ;
+ }
+
+ return $result ;
+ }
+
+ /**
+ * 添加用户为模拟人员工说
+ *
+ * @param $staff_id
+ * @param $companyIds
+ * @param $uniacid
+ * @return CardBoss|bool|\think\Model
+ * @throws \Exception
+ * @author shuixian
+ * @DataTime: 2019/12/30 16:50
+ */
+ public function addUserToStaff($staff_id , $companyIds ,$uniacid){
+
+ $params = [ 'staff_id' => $staff_id , 'company_ids' => $companyIds];
+
+ $this->_uniacid = $uniacid ;
+
+ //检查数据是否存在
+ if(!isset($params['staff_id']) || empty($params['staff_id'])) return lang('not staff');
+
+ $user = longbingGetUser($params[ 'staff_id' ] ,$this->_uniacid);
+ //判断用户是否存在
+ if(empty($user)) return lang('not user');
+ //获取boss端权限
+ $permissions = longbingGetPluginAuth($this->_uniacid);
+ if(empty($user['is_staff']))
+ {
+ //获取名片总数
+ if(!empty($permissions) && isset($permissions['card_number']) && !empty($permissions['card_number']))
+ {
+ if(!(longbingGetCardNum($this->_uniacid) < $permissions['card_number']))
+ {
+ return lang('not card num');
+ }
+ }
+ }
+ $result = true;
+ if(empty($permissions) || !isset($permissions['plugin']) || !isset($permissions['plugin']['boss']) || empty($permissions['plugin']['boss']))
+ {
+ $params['company_ids'] = [];
+ //获取一个默认的公司id
+ $company_model = new Company();
+ $company = $company_model->getCompany(['uniacid' => $this->_uniacid ,'status' => 1] ,['id']);
+ if(!empty($company)) $params['company_ids'][] = $company['id'];
+ }else{
+ if(!isset($params['company_ids']) || empty($params['company_ids'])) return lang('not company id');
+ CardBoss::where( [ [ 'user_id', '=', $params[ 'staff_id' ] ] ] )
+ ->delete();
+
+ $boss = implode( ',', $params[ 'company_ids' ] );
+
+ $result = CardBoss::create( [ 'user_id' => $params[ 'staff_id' ], 'boss' => $boss, 'uniacid' => $this->_uniacid ] );
+ }
+
+ if ( $result === false )
+ {
+ return 'edit failed' ;
+ }else{
+ $check = true;
+ //判断用户是否是员工
+ if(empty($user['is_staff'])){
+ $user['is_staff'] = 1;
+ longbingSetUser($params[ 'staff_id' ] ,$this->_uniacid ,$user);
+ //更新数据
+ $user_model = new User();
+ $check = $user_model->updateUser(['id' => $params[ 'staff_id' ] ,'uniacid' => $this->_uniacid] ,['is_staff' => 1]);
+ }
+ if($check){
+ //判断员工名片是否存在
+ $staff = longbingGetUserInfo($params[ 'staff_id' ] ,$this->_uniacid);
+ $staff_model = new UserInfo();
+ $company_id = '';
+ if(isset($params[ 'company_ids' ][0]) && !empty($params[ 'company_ids' ][0])) $company_id = $params[ 'company_ids' ][0];
+ if(empty($staff))
+ {
+ $result = $staff_model->createUser(['fans_id' => $params[ 'staff_id' ] ,'uniacid' => $this->_uniacid ,'is_staff' => 1 ,'company_id' => $company_id ,'is_default' => 1]);
+ longbingGetUserInfo($params[ 'staff_id' ] ,$this->_uniacid ,true);
+ }
+ if(!empty($staff))
+ {
+ $company_id = $staff['company_id'];
+ if(isset($params[ 'company_ids' ]) && !empty($params[ 'company_ids' ]) && !in_array($staff['company_id'], $params[ 'company_ids' ])) $company_id = $params[ 'company_ids' ][0];
+ $result = $staff_model->updateUser(['fans_id' => $params[ 'staff_id' ] ,'uniacid' => $this->_uniacid] ,['is_staff' => 1 , 'is_default' => 1 ,'company_id' => $company_id ]);
+ $staff['is_staff'] = 1;
+ $staff['is_default'] = 1;
+ $staff['company_id'] = $company_id;
+ longbingSetUserInfo($params[ 'staff_id' ] ,$this->_uniacid ,$staff);
+ }
+
+ }
+ }
+
+ return $result ;
+ }
+
+ /**
+ * 获取推荐员工数量
+ *
+ * @param $uniacid
+ * @return int
+ * @author shuixian
+ * @DataTime: 2020/1/2 17:04
+ */
+ public static function getDefaultStraffNumber($uniacid){
+
+ $count = User::alias( 'a' )
+ ->join( 'longbing_card_user_info b', 'b.fans_id = a.id' )
+ ->where('a.is_staff' , 1)
+ ->where('b.is_staff' , 1)
+ ->where('b.is_default' , 1)
+ ->where('a.uniacid',$uniacid)
+ ->where('b.uniacid',$uniacid)
+ ->count();
+
+ return $count ;
+ }
+
+
+ /**
+ * 生成员工头像二维码
+ *
+ * @param $_uniacid
+ * @param $params
+ * @return array|bool|mixed
+ * @author shuixian
+ * @DataTime: 2020/1/2 21:15
+ */
+ public static function createHeaderQr($_uniacid , $params){
+
+ $staff = longbingGetUserInfo($params['staff_id'] ,$_uniacid);
+
+ if(empty($staff) || empty($staff['is_staff'])) return lang('staff info not found');
+ //生成数据
+ $data = ["data" => ["staff_id" => $params['staff_id'] ,"pid" => $params['staff_id'] ,"type" => 4 ,"key" => 1]];
+ //生成二维码
+ $result = longbingCreateWxCode($_uniacid,$data);
+
+ if(isset($result['qr_path'])) $result = transImagesOne($result ,['qr_path'] ,$_uniacid);
+ //获取名片设置
+ $config = longbingGetAppConfig($_uniacid);
+ //是否用头像替换二维码中心
+ if(!empty($staff['avatar']) && !empty($result) && !empty($result['qr_path']) && !empty($result['path']) && isset($config['qr_avatar_switch']) && !empty($config['qr_avatar_switch']))
+ {
+ $staff = transImagesOne($staff ,['avatar'] ,$_uniacid);
+
+ $dat = longbingUpdateQrByAvatar($staff['avatar'] ,$result['qr_path'] , $_uniacid ,$result['path']);
+ }
+ //判断是否成功
+ if(empty($result) || !isset($result['qr_path'])) return lang('create qr error');
+ //改写数据
+ User::update( [ 'qr_path' => $result['qr_path'] ], [ 'id' => $params[ 'staff_id' ] ] );
+ //更新缓存
+ longbingGetUser($params['staff_id'] , $_uniacid ,true);
+
+ return $result;
+ }
+
+ /**
+ * @param $_uniacid
+ * @param $userId
+ * @功能说明:获取用户最后访问名片的ID
+ * @author jingshuixian
+ * @DataTime: 2020/1/7 17:22
+ */
+ public static function getLastStaffId($_uniacid,$userId){
+
+ $where[] = ['uniacid','=' , $_uniacid ];
+ $where[] = ['id','=' , $userId ];
+ $last_staff_id = User::where($where)->value('last_staff_id');
+
+ return $last_staff_id;
+ }
+
+
+ /**
+ * @param $_uniacid
+ * @param $userId
+ * @功能说明:删除用户缓存信息
+ * @author jingshuixian
+ * @DataTime: 2020/1/10 14:43
+ */
+ public static function delUserInfoCache($_uniacid , $userId){
+ $key = 'longbing_card_info_' . $userId;
+ return delCache($key ,$_uniacid);
+ }
+}
\ No newline at end of file
diff --git a/app/common.php b/app/common.php
new file mode 100755
index 0000000..759fc63
--- /dev/null
+++ b/app/common.php
@@ -0,0 +1,6055 @@
+
+// +----------------------------------------------------------------------
+use app\agent\model\Cardauth2ConfigModel;
+use app\card\controller\CardCacheKey;
+use app\card\model\CardCount;
+use app\card\model\CardFormId;
+use app\card\model\UserSk;
+use app\card\model\Collection;
+use app\card\model\UserPhone;
+use app\card\model\Company as CompanyModel;
+use app\diy\model\DiyModel;
+use longbingcore\permissions\AdminMenu;
+use longbingcore\wxcore\WxSetting;
+use think\facade\Cache;
+use think\facade\Db;
+use think\facade\File;
+use think\facade\Request;
+use app\Common\JsonSchema;
+use app\Common\Rsa2;
+use app\Common\Rsa2Sign;
+use app\Common\ConsumerApi;
+use app\Common\LongbingServiceNotice;
+use app\Common\LongbingCurl;
+use app\Common\WeChatCode;
+use app\Common\model\LongbingCardCount;
+use app\Common\model\LongbingUser;
+use app\Common\model\LongbingUserInfo;
+use app\Common\model\LongbingCardWechatCode;
+use app\Common\model\LongbingCardRate;
+use app\Common\model\LongbingCardUserMark;
+use app\Common\model\LongbingCardCommonModel;
+use app\admin\model\AppConfig;
+use app\admin\model\AppTabbar;
+use app\admin\model\OssConfig;
+use app\im\model\ImChat;
+use app\im\model\ImMessage;
+use app\card\model\Job as CardJob;
+use app\card\model\Company as CardCompany;
+use Ramsey\Uuid\Uuid;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
+use think\facade\Log;
+use think\facade\Env;
+
+
+//判断是否是微擎
+function longbingIsWeiqin ()
+{
+
+ return false;
+}
+
+
+
+
+
+
+
+
+
+
+/**
+ * 判断Schema文件是否存在
+ * @param string $schemamethod schemamethod
+ * @return boolean
+ *
+ */
+function jsonSchemaExist ( $schemaMethod )
+{
+ // var_dump('../schema/' . $schemaMethod . '.json');die;
+ return file_exists( APP_PATH . $schemaMethod . '.json' );
+}
+
+//根据Rsamy uuid 生成32位uuid
+function uuid ()
+{
+ try
+ {
+ // Generate a version 1 (time-based) UUID object
+ // Generate a version 3 (name-based and hashed with MD5) UUID object
+ // Generate a version 4 (random) UUID object
+ // Generate a version 5 (name-based and hashed with SHA1) UUID object
+ $uuid1 = Uuid::uuid4();
+ return str_replace( '-', '', $uuid1->toString() );
+ // i.e. e4eaaaf2-d142-11e1-b3e4-080027620cdd
+ }
+ catch ( UnsatisfiedDependencyException $e )
+ {
+ // Some dependency was not met. Either the method cannot be called on a
+ // 32-bit system, or it can, but it relies on Moontoast\Math to be present.
+ error( 'Caught exception: ' . $e->getMessage(), 1100 );
+ }
+}
+
+/**
+ * TODO回调函数
+ * @param string $description 未完成需求描述
+ * @return
+ */
+function todo ( $description )
+{
+ // $req = think\Request::instance();
+ // trace('[TODO] {' . join('/', [$req->module(), $req->controller(), $req->action()]) . '} ' . $description, 'log');
+}
+
+//设置缓存
+function setCache ( $key, $value, $expire = 0, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+
+ $tag = 'longbing_card_' . $uniacid;
+ // if(is_array($value)) $value = json_encode($value ,ture);
+ $key = $key . '_' . $uniacid;
+
+
+
+ return Cache::tag( $tag )
+ ->set( $key, $value, $expire );
+}
+
+//获取缓存
+function getCache ( $key, $uniacid = '7777' )
+{
+
+ if ( !hasCache( $key, $uniacid ) ) return false;
+
+ $key.=$_SERVER['HTTP_HOST'];
+
+ $key = $key . '_' . $uniacid;
+
+ return Cache::get( $key );
+}
+
+//追加缓存
+function pushCache ( $key, $value, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+ $key = $key . '_' . $uniacid;
+ return Cache::push( $key, $value );
+}
+
+//删除缓存
+function delCache ( $key, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+ $key = $key . '_' . $uniacid;
+ return Cache::delete( $key );
+}
+
+//获取并删除缓存
+function pullCache ( $key, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+ $key = $key . '_' . $uniacid;
+ return Cache::pull( $key );
+}
+
+//不存在则写入缓存数据后返回
+function rememberCache ( $key, $value, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+ $key = $key . '_' . $uniacid;
+ return Cache::remember( $key, $value );
+}
+
+//清空缓存
+function clearCache ( $uniacid = '7777' )
+{
+ $tag = 'longbing_card_' . $uniacid;
+ return Cache::tag( $tag )
+ ->clear();
+}
+
+//缓存自增
+function incCache ( $key, $step = 1, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+ $key = $key . '_' . $uniacid;
+ return Cache::inc( $key, $step );
+}
+
+//缓存自减
+function decCache ( $key, $step = 1, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+ $key = $key . '_' . $uniacid;
+ return Cache::dec( $key, $step );
+}
+
+//判断缓存是否存在
+function hasCache ( $key, $uniacid = '7777' )
+{
+ $key.=$_SERVER['HTTP_HOST'];
+
+ $key = $key . '_' . $uniacid;
+
+ return Cache::has( $key );
+}
+
+//获取controller 和 action
+function getRouteMessage ( $route )
+{
+ $data = explode( "\\", $route );
+ $data = explode( "@", $data[ count( $data ) - 1 ] );
+ return $data;
+}
+
+//通过Token获取用户信息
+function getUserForToken ( $token )
+{
+ return getCache( "Token_" . $token );
+}
+
+/**
+ * 生成RSA2类获取秘钥
+ */
+function getRsa2Keys ()
+{
+ $rsa2 = new Rsa2();
+ return $rsa2->getKeys();
+}
+
+/**
+ * 获取两组交叉keys
+ */
+function get2keys ()
+{
+ $key1 = getRsa2Keys();
+ $key2 = getRsa2Keys();
+ if ( isset( $key1[ 'public_key' ] ) && isset( $key1[ 'private_key' ] ) && isset( $key2[ 'public_key' ] ) && isset( $key2[ 'private_key' ] ) )
+ {
+ $result[ 'api_key' ] = [ 'public_key' => $key1[ 'public_key' ], 'private_key' => $key1[ 'private_key' ] ];
+ $result[ 'sever_key' ] = [ 'public_key' => $key2[ 'public_key' ], 'private_key' => $key2[ 'private_key' ] ];
+ return $result;
+ }
+ return false;
+}
+
+/**
+ * 获取RSA2秘钥(测试)
+ */
+function setRsa2Key ()
+{
+ $rsa2_key = getRsa2Keys();
+ $rsa2_sign = new Rsa2Sign( $rsa2_key );
+ //设置签名
+ $sign = $rsa2_sign->createSign( "12333212" );
+ //验证签名
+ $data = $rsa2_sign->verifySign( "12333212", $sign );
+ //生成加密数据
+ $jiami = $rsa2_sign->encrypt( json_encode( "123", true ) );
+ //数据解密
+ $jiemi = $rsa2_sign->decrypt( $jiami );
+ return $data;
+}
+
+//签名
+function rsa2CreateSign ( $keys, $data )
+{
+ $rsa2_sign = new Rsa2Sign( $keys );
+ $sign = $rsa2_sign->createSign( $data );
+ return $sign;
+}
+
+//验证签名
+function rsa2VerifySign ( $keys, $data, $sign )
+{
+ $rsa2_sign = new Rsa2Sign( $keys );
+ $jiemi = $rsa2_sign->verifySign( $data, $sign );
+ return $jiemi;
+}
+
+//加密
+function rsa2Encrypt ( $keys, $data )
+{
+ $rsa2_sign = new Rsa2Sign( $keys );
+ $cipher = $rsa2_sign->encrypt( $data );
+ return $cipher;
+}
+
+//解密
+function rsa2Decrypt ( $keys, $cipher )
+{
+ $rsa2_sign = new Rsa2Sign( $keys );
+ $clear = $rsa2_sign->decrypt( $cipher );
+ return $clear;
+}
+
+//批量加密
+function rsa2Encrypts ( $keys, $arrs )
+{
+ //判断需要加密的文件是否为空
+ if ( !is_array( $arrs ) ) return false;
+ $rsa2_sign = new Rsa2Sign( $keys );
+ $result = [];
+ foreach ( $arrs as $arr )
+ {
+ $result = $rsa2_sign->encrypt( $arr );
+ }
+ return $result;
+}
+
+//批量解密
+function rsa2Decrypts ( $keys, $ciphers )
+{
+ if ( !is_array( $ciphers ) ) return false;
+ $rsa2_sign = new Rsa2Sign( $keys );
+ $result = [];
+ foreach ( $ciphers as $cipher )
+ {
+ $result[] = $rsa2_sign->decrypt( $cipher );
+ }
+ return $result;
+}
+
+//创建签名 (一个超级简单的签名)
+function createSimpleSign ( $token, $data )
+{
+ // $key1 = md5($token);
+ // $key2 = md5($data);
+ // $sign = md5($key1 . $key2 .$token);
+ $sign = md5( $token . $data . $token );
+ return $sign;
+}
+
+//异步消息控制
+function messagesProcess ( $msg )
+{
+ //获取消息内容
+ if ( is_object( $msg ) )
+ {
+ $messages = [ $msg->getBody() ];
+ $ack = true;
+ }
+ else
+ {
+ // 兼容以前的消息格式
+ $messages = $msg;
+ $ack = false;
+ }
+
+ //循环处理消息
+
+ foreach ( $messages as $message )
+ {
+ //解析json数据
+ $data = json_decode( $message, true );
+ //处理
+// var_dump($data);
+ try{
+ switch ( $action = $data[ 'action' ] )
+ {
+ case 'previewSchedule':
+ $Schedule = new app\preview\Schedule( $data->preview, [ $data->source ] );
+ $Schedule->process();
+ break;
+ // 定时任务调度
+ case 'SCHEDULER':
+ // 确认消息已经被处理,则返回此信号
+ $msg->delivery_info[ 'channel' ]->basic_ack( $msg->delivery_info[ 'delivery_tag' ] );
+ scheduleProcess( $data );
+ $ack = false;
+ break;
+ case 'addMessage':
+ asyncAddMessage( $data[ 'message' ] );
+ break;
+ //发送消息服务通知
+ case 'sendMessageWxServiceNotice':
+ longbingSendMessageWxServiceNotice($data['message']);
+ break;
+ //发送普通服务通知
+ case 'SendWxServiceNotice':
+ longbingSendWxServiceNotice($data['count_id']);
+ break;
+ case 'longbingSendWxServiceNoticeBase':
+ longbingSendWxServiceNoticeBase($data['data']);
+ break;
+ case 'updatecollectionRate':
+ updatecollectionRate($data['client_id']);
+ break;
+ case 'updateCustomerRate':
+ updateCustomerRate($data['page'] ,$data['page_count']);
+ break;
+ case 'longbingCreateWxCode':
+ longbingCreateWxCode($data['uniacid'] ,$data['data'] ,$data['page'] ,$data['type']);
+ break;
+ case 'longbingCreateSharePng':
+ longbingCreateSharePng($data['gData'] ,$data['user_id'] ,$data['uniacid']);
+ break;
+ case 'longbingSaveFormId':
+ longbingSaveFormId($data['data']);
+ break;
+ case 'test':
+ test( $data[ 'uuid' ], $data[ 'data' ] );
+ break;
+
+ }
+ }catch(Exception $e)
+ {}
+ }
+ if ( $ack )
+ {
+ // 确认消息已经被处理,则返回此信号
+ $msg->delivery_info[ 'channel' ]->basic_ack( $msg->delivery_info[ 'delivery_tag' ] );
+ }
+
+ // 保存并清空日志,避免导致内存溢出
+ // \think\Log::save();
+ // \think\Log::clear();
+
+}
+
+//计划任务
+function scheduleProcess ( $data )
+{
+ //获取计划任务
+ if ( is_object( $data ) ) $data = get_object_vars( $data );
+
+ $taskName = $data[ 'event' ];
+ $lockName = 'SCHEDULER_RUNNING_LOCK_' . $taskName;
+ $processLock = 'SCHEDULER_PROCESS_LOCK_' . $taskName;
+ $schedulerConfigs = \think\Config::get( 'SCHEDULER' );
+ $redisConfig = \think\Config::get( 'cache' );
+ $publisherapi = new \think\PublisherApi();
+ $redis = Cache::connect( $redisConfig );
+
+ // 判断配置中是否还存在该任务
+ if ( !isset( $schedulerConfigs[ 'tasks' ][ $taskName ] ) ) return false;
+ // 读取配置
+ list( $interval, $callback, $params, $wait ) = $schedulerConfigs[ 'tasks' ][ $taskName ];
+
+ // 更新运行锁
+ $redis->handler()
+ ->setnx( $lockName, time() );
+ $redis->handler()
+ ->expire( $lockName, $interval + $schedulerConfigs[ 'LOCKDELAY' ] );
+
+ // 任务唯一性判断
+ $info = $publisherapi->scheduleInfo( $taskName, $interval * 1000 );
+ if ( $info[ 'ready' ] > 0 )
+ {
+ // 等待下次任务启动,本次不做处理
+ return false;
+ }
+
+ // 设置执行锁
+ if ( $redis->handler()
+ ->setnx( $processLock, time() ) )
+ {
+ // 执行锁为1秒,避免大量启动
+ $redis->handler()
+ ->expire( $processLock, 1 );
+ }
+ else
+ {
+ // 抛弃多余的数据
+ return false;
+ }
+ //生成异步消息
+ $msg = array( 'action' => 'SCHEDULER', 'event' => $taskName, 'options' => $data[ 'options' ] );
+ //判断回调
+ if ( is_array( $callback ) )
+ {
+ $class = new $callback[ 0 ];
+ $func = $callback[ 1 ];
+ $call = array( $class, $func );
+ }
+ else if ( is_string( $callback ) )
+ {
+ $call = $callback;
+ }
+ else
+ {
+ return false;
+ }
+ if ( !$wait ) $publisherapi->scheduleMessage( json_encode( $msg ), $taskName, $interval * 1000 );
+
+ // 执行过程,避免报错,catch出所有错误
+ try
+ {
+ if ( is_null( $params ) )
+ {
+ call_user_func( $call );
+ }
+ else
+ {
+ call_user_func( $call, $params );
+ }
+ }
+ catch ( Exception $error )
+ {
+
+ }
+ if ( $wait ) $publisherapi->scheduleMessage( json_encode( $msg ), $taskName, $interval * 1000 );
+}
+
+//消费者
+
+function consumer ()
+{
+ $consumerapi = new ConsumerApi();
+ $messages = $consumerapi->consumerMessage();
+ messagesProcess( $messages );
+}
+
+//生成者
+
+function publisher ( $messages, $delayTime = null )
+{
+// $param = Request::param() ;
+// $param['s'] = "publics/HttpAsyn/message" ;
+// $url = Request::baseFile(true);
+// $url = $url . '?' . http_build_query($param);
+// $res = longbing_do_request($url, ['message' => $messages] );
+//
+// return $res;
+
+}
+
+
+//获取毫秒级时间戳
+function getMillisecond ()
+{
+ list( $s1, $s2 ) = explode( ' ', microtime() );
+ return (float)sprintf( '%.0f', ( floatval( $s1 ) + floatval( $s2 ) ) * 1000 );
+}
+
+/**
+ * 发送邮件
+ * @param string $address 需要发送的邮箱地址 发送给多个地址需要写成数组形式
+ * @param string $subject 标题
+ * @param string $content 内容
+ * @return boolean 是否成功
+ */
+function send_email ( $address, $subject, $content )
+{
+ $email_smtp = \think\Config::get( 'API_CONFIG.EMAIL_SMTP' );
+ $email_username = \think\Config::get( 'API_CONFIG.EMAIL_USERNAME' );
+ $email_password = \think\Config::get( 'API_CONFIG.EMAIL_PASSWORD' );
+ $email_from_name = \think\Config::get( 'API_CONFIG.EMAIL_FROM_NAME' );
+ $email_smtp_secure = \think\Config::get( 'API_CONFIG.EMAIL_SMTP_SECURE' );
+ $email_port = \think\Config::get( 'API_CONFIG.EMAIL_PORT' );
+
+ if ( empty( $email_smtp ) || empty( $email_username ) || empty( $email_password ) || empty( $email_from_name ) )
+ {
+ return error( 'The mailbox configuration is incomplete!', '1109' );
+ }
+ require_once '../thinkphp/library/think/class.phpmailer.php';
+ require_once '../thinkphp/library/think/class.smtp.php';
+ $phpmailer = new \Phpmailer();
+ // 设置PHPMailer使用SMTP服务器发送Email
+ $phpmailer->IsSMTP();
+ // 设置设置smtp_secure
+ $phpmailer->SMTPSecure = $email_smtp_secure;
+ // 设置port
+ $phpmailer->Port = $email_port;
+ // 设置为html格式
+ $phpmailer->IsHTML( true );
+ // 设置邮件的字符编码'
+ $phpmailer->CharSet = 'UTF-8';
+ // 设置SMTP服务器。
+ $phpmailer->Host = $email_smtp;
+ // 设置为"需要验证"
+ $phpmailer->SMTPAuth = true;
+ // 设置用户名
+ $phpmailer->Username = $email_username;
+ // 设置密码
+ $phpmailer->Password = $email_password;
+ // 设置邮件头的From字段。
+ $phpmailer->From = $email_username;
+ // 设置发件人名字
+ $phpmailer->FromName = $email_from_name;
+ // 添加收件人地址,可以多次使用来添加多个收件人
+ if ( is_array( $address ) )
+ {
+ foreach ( $address as $addressv )
+ {
+ $phpmailer->AddAddress( $addressv );
+ }
+ }
+ else
+ {
+ $phpmailer->AddAddress( $address );
+ }
+ // 设置邮件标题
+ $phpmailer->Subject = $subject;
+ // 设置邮件正文
+ $phpmailer->Body = $content;
+ // 发送邮件。
+
+ if ( !$phpmailer->Send() )
+ {
+ $phpmailererror = $phpmailer->ErrorInfo;
+ return error( $phpmailererror, '1102' );
+ }
+ else
+ {
+ return array( "status" => 'success' );
+ }
+}
+
+//测试数据
+//use app\admin\model\Test as TestModel;
+function test ( $uuid, $data )
+{
+ dump( $data );
+ // $test_model = new TestModel;
+ // $data['uuid'] = $uuid;
+ // $test_model->createTest($data);
+
+}
+
+/**
+ * @Purpose: 处理数组中的图片为完整能访问的URL
+ *
+ * @Param: array $data 需要处理图片的数组,可以是一维数组也可以是多维数组
+ * @Param: array $target 需要处理字段名组成的数组,一维数组
+ * @Param: string $split 多张图片放在一起的分隔符
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'transImages' ) )
+{
+ function transImages ( $data, $target, $split = ',' )
+ {
+
+ if ( !is_array( $data ) )
+ {
+ return $data;
+ }
+
+
+ foreach ( $data as $index => $item )
+ {
+ if ( is_array( $item ) )
+ {
+ $data[ $index ] = transImages( $item, $target, $split );
+ continue;
+ }
+
+
+ if ( in_array( $index, $target ) && $item )
+ {
+ $tmpArr = explode( $split, $item );
+ $data[ $index ] = handleImages( $tmpArr );
+ }
+ }
+
+
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 处理数组中的图片为完整能访问的URL--单张图片
+ *
+ * @Param: array $data 需要处理图片的数组,可以是一维数组也可以是多维数组
+ * @Param: array $target 需要处理字段名组成的数组,一维数组
+ * @Param: string $split 多张图片放在一起的分隔符
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'transImagesOne' ) )
+{
+ function transImagesOne ( $data, $target ,$uniacid = '7777')
+ {
+ if(longbingIsWeiqin())
+ {
+ global $_W;
+ if (isset($_W['uniacid']))
+ {
+ $uniacid = $_W['uniacid'];
+ }
+ else
+ {
+ if(defined('LONGBING_CARD_UNIACID'))
+ {
+ $uniacid = LONGBING_CARD_UNIACID;
+ }
+ }
+ }
+ if ( !is_array( $data ) )
+ {
+ return $data;
+ }
+ foreach ( $data as $index => $item )
+ {
+ if ( is_array( $item ) )
+ {
+ $data[ $index ] = transImagesOne( $item, $target ,$uniacid);
+ continue;
+ }
+
+ if ( in_array( $index, $target ) && $item )
+ {
+ $src = trim( $item );
+
+ // 老版本微擎的图片
+ if ( empty( $src ) || !$src )
+ {
+ $data[ $index ] = $src;
+ continue;
+ }
+
+ $sub = substr( $src, 0, 4 );
+ // 连接已经是完整的连接了,无需在处理
+ if ( $sub == 'http' )
+ {
+ continue;
+ }
+ $sub = substr( $src, 0, 2 );
+ if ( $sub == '//' || $sub == 'wx' )
+ {
+ continue;
+ }
+
+ // 是新版的图片id用新的处理方法
+ if ( is_numeric( $src ) )
+ {
+ //TODO 新版的图片处理方法
+ continue;
+ }
+ if(longbingIsWeiqin())
+ {
+
+ if ( strstr( $src, 'addons/' ) !== false )
+ {
+ $data[ $index ] = $_W[ 'siteroot' ] . substr( $src, strpos( $src, 'addons/' ) );
+ }
+ if ( strstr( $src, $_W[ 'siteroot' ] ) !== false && strstr( $src, '/addons/' ) === false )
+ {
+ $urls = parse_url( $src );
+ $data[ $index ] = $t = substr( $urls[ 'path' ], strpos( $urls[ 'path' ], 'images' ) );
+ continue;
+ }
+ if ( empty( $_W[ 'setting' ][ 'remote' ][ 'type' ] ) && ( empty( $_W[ 'uniacid' ] ) || !empty( $_W[ 'uniacid' ] ) && empty( $_W[ 'setting' ][ 'remote' ][ $_W[ 'uniacid' ] ][ 'type' ] ) ) || file_exists( IA_ROOT . '/' . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $src ) )
+ {
+
+ $data[ $index ] = $_W[ 'siteroot' ] . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $src;
+
+ }
+ else
+ {
+
+ $result = longbingGetOssConfig($uniacid);
+
+ if (isset($result['default_url']) && !$result['default_url']){
+ $result['default_url'] = $_SERVER['HTTP_HOST'] . '/attachment/upload';
+ }
+ $data[ $index ] = $result['default_url'] . '/' . $src;
+
+ }
+ }
+ if(strpos($src,'http') === false){
+ $longbingOssConfig = longbingGetOssConfig($uniacid);
+ $http_agreemet = 'https';
+ if(!isset($longbingOssConfig['default_url']) || empty($longbingOssConfig['default_url']) || empty($longbingOssConfig['open_oss']))
+ {
+ $longbingOssConfig['default_url'] = $_SERVER['HTTP_HOST'] . '/attachment';
+ if(isset($_SERVER['REQUEST_SCHEME']) && !empty($_SERVER['REQUEST_SCHEME'])) $http_agreemet = $_SERVER['REQUEST_SCHEME'];
+ }
+ if(longbingHasLocalFile($src))
+ {
+ $longbingOssConfig['default_url'] = $_SERVER['HTTP_HOST'] . '/attachment';
+ if(isset($_SERVER['REQUEST_SCHEME']) && !empty($_SERVER['REQUEST_SCHEME'])) $http_agreemet = $_SERVER['REQUEST_SCHEME'];
+ }
+ //http协议
+ if(strpos($longbingOssConfig['default_url'],'http') === false){
+ $longbingOssConfig['default_url'] = $http_agreemet . '://'.$longbingOssConfig['default_url'];
+ }
+ $data[ $index ] = $longbingOssConfig['default_url'] . '/' . $src;
+ }else{
+ $data[ $index ] = $src;
+ }
+ }
+
+ }
+ return $data;
+ }
+}
+
+function longbingHasLocalFile($file_name)
+{
+ $file_path = FILE_UPLOAD_PATH . $file_name;
+ return file_exists($file_path);
+}
+
+
+/**
+ * @Purpose: 微擎处理本地图片
+ *
+ * @Param: array $data 需要处理图片的数组,可以是一维数组也可以是多维数组
+ * @Param: array $target 需要处理字段名组成的数组,一维数组
+ * @Param: string $split 多张图片放在一起的分隔符
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'handleImagesWe7Local' ) )
+{
+ function handleImagesWe7Local ( $data, $target, $split = ',' )
+ {
+ global $_W;
+ if ( !is_array( $data ) )
+ {
+ return $data;
+ }
+
+
+ foreach ( $data as $index => $item )
+ {
+ if ( is_array( $item ) )
+ {
+ $data[ $index ] = handleImagesWe7Local( $item, $target, $split );
+ continue;
+ }
+
+
+ if ( in_array( $index, $target ) && $item )
+ {
+ $item = trim( $item, $split );
+ $tmpArr = explode( $split, $item );
+ foreach ( $tmpArr as $index2 => $item2 )
+ {
+ $tmpArr[ $index2 ] = $_W[ 'siteroot' ] . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $item2;
+ }
+ $data[ $index ] = $tmpArr;
+ }
+ }
+
+
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 处理图片
+ *
+ * @Param: array $data 图片数组
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'handleImages' ) )
+{
+ function handleImages ( $data )
+ {
+ global $_W;
+
+ if (isset($_W['uniacid']))
+ {
+ $uniacid = $_W['uniacid'];
+ }
+ else
+ {
+ if(defined('LONGBING_CARD_UNIACID'))
+ {
+ $uniacid = LONGBING_CARD_UNIACID;
+ }
+ else
+ {
+ $uniacid = 7777;
+ }
+ }
+
+
+ if ( !is_array( $data ) )
+ {
+ return $data;
+ }
+
+ foreach ( $data as $index => $item )
+ {
+ $src = trim( $item );
+ //$src = strtolower( $src );
+
+ $sub = substr( $src, 0, 4 );
+ // 连接已经是完整的连接了,无需在处理
+ if ( $sub == 'http' )
+ {
+ continue;
+ }
+ $sub = substr( $src, 0, 2 );
+ if ( $sub == '//' || $sub == 'wx' )
+ {
+ continue;
+ }
+
+
+ // 是新版的图片id用新的处理方法
+ if ( is_numeric( $src ) )
+ {
+ //TODO 新版的图片处理方法
+ continue;
+ }
+
+
+ // 老版本微擎的图片
+ if ( empty( $src ) || !$src )
+ {
+ $data[ $index ] = $src;
+ continue;
+ }
+
+ if ( strstr( $src, 'addons/' ) !== false )
+ {
+ $data[ $index ] = $_W[ 'siteroot' ] . substr( $src, strpos( $src, 'addons/' ) );
+ }
+ if ( strstr( $src, $_W[ 'siteroot' ] ) !== false && strstr( $src, '/addons/' ) === false )
+ {
+ $urls = parse_url( $src );
+ $data[ $index ] = $t = substr( $urls[ 'path' ], strpos( $urls[ 'path' ], 'images' ) );
+ continue;
+ }
+
+// if ( empty( $_W[ 'setting' ][ 'remote' ][ 'type' ] ) && ( !empty( $_W[ 'uniacid'] ) && empty( $_W[ 'setting' ][ 'remote' ][ $_W[ 'uniacid' ] ][ 'type' ] ) ) || file_exists( IA_ROOT . '/' . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $src ) )
+// {
+//
+//
+// $data[ $index ] = $_W[ 'siteroot' ] . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $src;
+//
+// }
+// else
+// {
+// $result = longbingGetOssConfig($uniacid,true);
+// if (empty($result['default_url'])){
+// $result['default_url'] = $_SERVER['HTTP_HOST'] . '/attachment/upload';
+// }
+// if(strpos($result['default_url'],'http') === false){
+// $result['default_url'] = 'https://'.$result['default_url'];
+// }
+// $data[ $index ] = $result['default_url'] . '/' . $src;
+
+ if(strpos($src,'http') === false){
+ $longbingOssConfig = longbingGetOssConfig($uniacid);
+ $http_agreemet = 'https';
+ if(!isset($longbingOssConfig['default_url']) || empty($longbingOssConfig['default_url']) || empty($longbingOssConfig['open_oss']))
+ {
+ $longbingOssConfig['default_url'] = $_SERVER['HTTP_HOST'] . '/attachment';
+ if(isset($_SERVER['REQUEST_SCHEME']) && !empty($_SERVER['REQUEST_SCHEME'])) $http_agreemet = $_SERVER['REQUEST_SCHEME'];
+ }
+ if(longbingHasLocalFile($src))
+ {
+ $longbingOssConfig['default_url'] = $_SERVER['HTTP_HOST'] . '/attachment';
+ if(isset($_SERVER['REQUEST_SCHEME']) && !empty($_SERVER['REQUEST_SCHEME'])) $http_agreemet = $_SERVER['REQUEST_SCHEME'];
+ }
+ //http协议
+ if(strpos($longbingOssConfig['default_url'],'http') === false){
+ $longbingOssConfig['default_url'] = $http_agreemet . '://'.$longbingOssConfig['default_url'];
+ }
+ $data[ $index ] = $longbingOssConfig['default_url'] . '/' . $src;
+ }else{
+ $data[ $index ] = $src;
+ }
+ }
+
+// }
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 打印并终止程序
+ *
+ * @Param: array $data 需要打印的数据
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'zDumpAndDie' ) )
+{
+ function zDumpAndDie ( $data )
+ {
+ echo '';
+ var_dump( $data );
+ echo ' ';
+ die;
+ }
+}
+
+/**
+ * @Purpose: 打印数据
+ *
+ * @Param: array $data 需要打印的数据
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'zDump' ) )
+{
+ function zDump ( $data )
+ {
+ echo '';
+ var_dump( $data );
+ echo ' ';
+ }
+}
+
+
+/**
+ * 检验数据的真实性,并且获取解密后的明文.
+ * @param $encryptedData string 加密的用户数据
+ * @param $iv string 与用户数据一同返回的初始向量
+ * @param $data string 解密后的原文
+ *
+ * @return int 成功0,失败返回对应的错误码
+ */
+if ( !function_exists( 'decryptDataLongbing' ) )
+{
+ function decryptDataLongbing ( $appid, $sessionKey, $encryptedData, $iv, &$data )
+ {
+ $OK = 0;
+ $IllegalAesKey = -41001;
+ $IllegalIv = -41002;
+ $IllegalBuffer = -41003;
+ $DecodeBase64Error = -41004;
+
+ if ( strlen( $sessionKey ) != 24 )
+ {
+ return $IllegalAesKey;
+ }
+ $aesKey = base64_decode( $sessionKey );
+
+
+ if ( strlen( $iv ) != 24 )
+ {
+ return $IllegalIv;
+ }
+ $aesIV = base64_decode( $iv );
+
+ $aesCipher = base64_decode( $encryptedData );
+
+ $result = openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV );
+
+ $dataObj = json_decode( $result );
+ if ( $dataObj == NULL )
+ {
+ return $IllegalBuffer;
+ }
+ if ( $dataObj->watermark->appid != $appid )
+ {
+ return $IllegalBuffer;
+ }
+ $data = $result;
+ return $OK;
+ }
+}
+
+/**
+ * 数据解密:低版本使用mcrypt库(PHP < 5.3.0),高版本使用openssl库(PHP >= 5.3.0)。
+ *
+ * @param string $ciphertext 待解密数据,返回的内容中的data字段
+ * @param string $iv 加密向量,返回的内容中的iv字段
+ * @param string $app_key 创建小程序时生成的app_key
+ * @param string $session_key 登录的code换得的
+ * @return string | false
+ */
+if ( !function_exists( 'baiduDecryptDataLongbing' ) )
+{
+ function baiduDecryptDataLongbing($ciphertext, $iv, $app_key, $session_key) {
+ $session_key = base64_decode($session_key);
+ $iv = base64_decode($iv);
+ $ciphertext = base64_decode($ciphertext);
+
+ $plaintext = false;
+ if (function_exists("openssl_decrypt")) {
+ $plaintext = openssl_decrypt($ciphertext, "AES-192-CBC", $session_key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
+ } else {
+ $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, null, MCRYPT_MODE_CBC, null);
+ mcrypt_generic_init($td, $session_key, $iv);
+ $plaintext = mdecrypt_generic($td, $ciphertext);
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+ }
+ if ($plaintext == false) {
+ return false;
+ }
+
+ // trim pkcs#7 padding
+ $pad = ord(substr($plaintext, -1));
+ $pad = ($pad < 1 || $pad > 32) ? 0 : $pad;
+ $plaintext = substr($plaintext, 0, strlen($plaintext) - $pad);
+
+ // trim header
+ $plaintext = substr($plaintext, 16);
+ // get content length
+ $unpack = unpack("Nlen/", substr($plaintext, 0, 4));
+ // get content
+ $content = substr($plaintext, 4, $unpack['len']);
+ // get app_key
+ $app_key_decode = substr($plaintext, $unpack['len'] + 4);
+
+ return $app_key == $app_key_decode ? $content : false;
+ }
+}
+
+/**
+ * @Purpose: 获取随机字符串
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+
+if ( !function_exists( 'getRandStr' ) )
+{
+ function getRandStr ( $len )
+ {
+ $len = intval( $len );
+ $a = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,S,Y,Z";
+ $a = explode( ',', $a );
+ $tmp = '';
+ for ( $i = 0; $i < $len; $i++ )
+ {
+ $rand = rand( 0, count( $a ) - 1 );
+ $tmp .= $a[ $rand ];
+ }
+ return $tmp;
+ }
+}
+
+
+/**
+ * @Purpose: 处理腾讯视频
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbGetTencentVideo' ) )
+{
+ function lbGetTencentVideo ( $src )
+ {
+ if ( !$src )
+ {
+ return '';
+ }
+
+ if ( !strstr( $src, 'v.qq.com' ) )
+ {
+ return 0;
+ }
+
+ if ( strstr( $src, 'vid' ) )
+ {
+ $str = strstr( $src, 'vid' );
+ $tmpArr = explode( '=', $str );
+ $str = $tmpArr[ 1 ];
+ }
+ else
+ {
+ $tmpArr = explode( '/', $src );
+ $str = $tmpArr[ count( $tmpArr ) - 1 ];
+ $tmpArr = explode( '.', $str );
+ $str = $tmpArr[ 0 ];
+ }
+
+ if ( $str )
+ {
+ return $str;
+ }
+ return $src;
+ }
+}
+
+
+/**
+ * @Purpose: 处理雷达数据返回文字
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbHandelRadarList' ) )
+{
+ function lbHandelRadarList ( $data )
+ {
+ $tmp = array();
+ foreach ( $data as $index => $item )
+ {
+ switch ( $item[ 'sign' ] )
+ {
+ case 'copy':
+ break;
+ case 'view':
+ break;
+ case 'praise':
+ break;
+ case 'order':
+ break;
+ case 'qr':
+ break;
+ }
+ }
+ return $tmp;
+ }
+}
+
+
+/**
+ * @Purpose: 处理雷达日期
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbHandelRadarDate' ) )
+{
+ function lbHandelRadarDate ( $data, $field = 'create_time' )
+ {
+ // 今天的时间戳
+ $time = time();
+ // 昨天的时间戳
+ $Yesterday = $time - ( 24 * 60 * 60 );
+
+ $today = mktime( 0, 0, 0, date( "m", $time ), date( "d", $time ), date( "Y", $time ) );
+ $Yesterday = mktime( 0, 0, 0, date( "m", $Yesterday ), date( "d", $Yesterday ), date( "Y", $Yesterday ) );
+
+ foreach ( $data as $index => $item )
+ {
+
+ if(!key_exists($field,$item)){
+
+ continue;
+ }
+
+ $tmpTime = $item[ $field ];
+
+ if ( $tmpTime > $today )
+ {
+ // $data[ $index ][ 'radar_time' ] = '今天 ';
+ $data[ $index ][ 'radar_group' ] = '今天';
+ $data[ $index ][ 'radar_time' ] = date( 'H:i', $item[ $field ] );
+ }
+ else if ( $tmpTime > $Yesterday )
+ {
+ // $data[ $index ][ 'radar_time' ] = '昨天 ';
+ $data[ $index ][ 'radar_group' ] = '昨天';
+ $data[ $index ][ 'radar_time' ] = date( 'H:i', $item[ $field ] );
+ }
+ else
+ {
+ $thisYear = date( 'Y' );
+ $itemYear = date( 'Y', $item[ $field ] );
+ if ( $thisYear == $itemYear )
+ {
+ $data[ $index ][ 'radar_group' ] = date( 'm-d', $item[ $field ] );
+ $data[ $index ][ 'radar_time' ] = date( ' H:i', $item[ $field ] );
+ }
+ else
+ {
+ $data[ $index ][ 'radar_group' ] = date( 'Y-m-d', $item[ $field ] );
+ $data[ $index ][ 'radar_time' ] = date( ' H:i', $item[ $field ] );
+ }
+
+ }
+ }
+
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 处理雷达用户来源
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbHandelRadarSource' ) )
+{
+ function lbHandelRadarSource ( $data )
+ {
+
+ $modelUser = new \app\card\model\User();
+ // share_source 用户端来源 1 => 微信小程序
+ foreach ( $data as $index => $item )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自搜索', 'is_openGId' => 0 ] ];
+ $data[ $index ][ 'share_source' ] = 1;
+
+
+ if ( isset($item[ 'from_uid' ]) )
+ {
+ $share_info = $modelUser->where( [ [ 'id', '=', $item[ 'from_uid' ] ] ] )
+ ->find();
+ if ( $share_info )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自' . $share_info[ 'nickName' ], 'is_openGId' => 0 ] ];
+ if ( $share_info[ 'is_staff' ] == 1 )
+ {
+ $share_info = \app\card\model\UserInfo::where( [ [ 'fans_id', '=', $item[ 'from_uid' ] ] ]
+ )
+ ->find();
+ // $data['share_str'] = '来自' . $share_info['name'] . '分享的名片';
+ if ( isset( $share_info[ 'name' ] ) && $share_info[ 'name' ] )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自' . $share_info[ 'name' ], 'is_openGId' => 0 ] ];
+ }
+ }
+
+ if ( $item[ 'is_qr' ] == 0 && $item[ 'is_group' ] == 0 )
+ {
+ $data[ $index ][ 'share_str' ][1] = [ 'title' => '分享的名片', 'is_openGId' => 0 ];
+ }
+
+ if ( $item[ 'is_qr' ] )
+ {
+ $data[ $index ][ 'share_str' ][1] = [ 'title' => '分享的二维码', 'is_openGId' => 0 ];
+ }
+ if ( $item[ 'is_group' ] )
+ {
+ $data[ $index ][ 'share_str' ][1] = [ 'title' => '分享到群的名片', 'is_openGId' => 0 ];
+ $data[ $index ][ 'is_group_opGId' ] = $item[ 'openGId' ];
+ }
+ if ( $item[ 'is_group' ] && $item[ 'is_qr' ] )
+ {
+ $data[ $index ][ 'share_str' ][1] = [ 'title' => '分享到群的二维码', 'is_openGId' => 0 ];
+ $data[ $index ][ 'is_group_opGId' ] = $item[ 'openGId' ];
+ }
+ if ( $item[ 'is_group' ] && $item[ 'openGId' ] )
+ {
+ $data[ $index ][ 'share_str' ][1] = [ 'title' => '分享到群', 'is_openGId' => 0 ];
+ $data[ $index ][ 'share_str' ][2] = [ 'title' => $item[ 'openGId' ], 'is_openGId' => 1 ];
+ $data[ $index ][ 'share_str' ][3] = [ 'title' => '的名片', 'is_openGId' => 0 ];
+ $data[ $index ][ 'is_group_opGId' ] = $item[ 'openGId' ];
+ }
+ if ( $item[ 'is_group' ] && $item[ 'is_qr' ] && $item[ 'openGId' ] )
+ {
+ $data[ $index ][ 'share_str' ][1] = [ 'title' => '分享到群', 'is_openGId' => 0 ];
+ $data[ $index ][ 'share_str' ][2] = [ 'title' => $item[ 'openGId' ], 'is_openGId' => 1 ];
+ $data[ $index ][ 'share_str' ][3] = [ 'title' => '的二维码', 'is_openGId' => 0 ];
+ $data[ $index ][ 'is_group_opGId' ] = $item[ 'openGId' ];
+ }
+ }
+ }
+ if ( $item &&isset($item[ 'from_uid' ])&&$item[ 'from_uid' ] == 0 )
+ {
+ if ( $item[ 'is_qr' ] )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自二维码', 'is_openGId' => 0 ] ];
+ }
+ if ( $item[ 'is_group' ] )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自群分享', 'is_openGId' => 0 ] ];
+ $data[ $index ][ 'is_group_opGId' ] = $item[ 'openGId' ];
+ }
+ if ( $item[ 'is_group' ] && $item[ 'openGId' ] )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自群', 'is_openGId' => 0 ] ];
+ $data[ $index ][ 'share_str' ][] = [ 'title' => $item[ 'openGId' ], 'is_openGId' => 1 ];
+ $data[ $index ][ 'share_str' ][] = [ 'title' => '分享', 'is_openGId' => 0 ];
+ $data[ $index ][ 'is_group_opGId' ] = $item[ 'openGId' ];
+ }
+ }
+ if ( $item &&isset($item[ 'handover_name' ])&&$item[ 'handover_name' ])
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自' . $item[ 'handover_name' ] . '的工作交接', 'is_openGId' => 0 ] ];
+ }
+
+ // 导入客户头像
+ if ( isset($item[ 'import' ])&&$item[ 'import' ] )
+ {
+ $data[ $index ][ 'avatarUrl' ] = $item[ 'avatarUrl' ];
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自后台管理员导入', 'is_openGId' => 0 ] ];
+ }
+ // 导入客户头像
+ if ( $item && isset($item[ 'is_auto' ])&&$item[ 'is_auto' ] )
+ {
+ $data[ $index ][ 'share_str' ] = [ [ 'title' => '来自系统自动分配', 'is_openGId' => 0 ] ];
+ }
+ }
+
+ return $data;
+ }
+}
+
+
+/**
+ * 获取地步菜单名字
+ */
+if ( !function_exists( 'tabbarName' ) )
+{
+
+ function tabbarName($key,$uniacid){
+
+
+ $web = [];
+
+ $m_diy = new DiyModel();
+
+ $data = $m_diy->where(['uniacid'=>$uniacid,'status'=>1])->find();
+
+ if(!empty($data)){
+
+ $data = $data->toArray();
+
+ $tabbar = json_decode($data['tabbar'],true);
+
+ $list = $tabbar['list'];
+
+ if(!empty($list)){
+ foreach ($list as $value){
+
+ if($value['key'] == $key){
+
+ $web = $value['name'];
+ }
+ }
+ }
+ }
+ return $web;
+ }
+}
+
+
+if ( !function_exists( 'changeRadarMsg' ) )
+{
+
+ function changeRadarMsg($msgList,$uniacid){
+
+ if(!empty($msgList)){
+
+ foreach ($msgList as $k=>$v){
+ //官网
+ if(($v['sign']=='view'&&$v['type']==6)||($v['sign']=='view'&&$v['type']==18)){
+
+ $name = tabbarName(4,$uniacid);
+
+ if(!empty($name)&&$name!='官网'){
+
+ $msgList[$k]['item'] = str_replace('企业官网',$name, $msgList[$k]['item']);
+
+ $msgList[$k]['operation'] = str_replace('官网',$name, $msgList[$k]['operation']);
+ }
+ }
+ }
+ }
+ return $msgList;
+ }
+}
+
+
+/**
+ * @Purpose: 处理雷达激励提醒文案
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbHandelRadarMsg' ) )
+{
+ function lbHandelRadarMsg ( $data )
+ {
+ $result = [];
+ if ( empty( $data )||empty($data[ 0 ][ 'uniacid' ]) )
+ {
+ return $data;
+ }
+ $msgList = \app\radar\model\RadarMsg::where( [ [ 'uniacid', '=', $data[ 0 ][ 'uniacid' ] ] ])->order( [ 'mini' => 'desc' ] )->select()->toArray();
+ if ( !$msgList || empty( $msgList ) )
+ {
+ $msgList = lbInitRadarMsg( $data[ 0 ][ 'uniacid' ] );
+ }
+
+
+ //替换文字
+ $msgList = changeRadarMsg($msgList,$data[ 0 ][ 'uniacid' ]);
+
+//dump($msgList);exit;
+
+ foreach ( $data as $index => $item )
+ {
+
+
+ $data[ $index ][ 'radar_arr' ] = [];
+
+ foreach ( $msgList as $index2 => $item2 )
+ {
+
+
+
+ if ( $item2[ 'sign' ] != $item[ 'sign' ] || $item2[ 'type' ] != $item[ 'type' ] )
+ {
+ continue;
+ }
+
+
+ $radar = $item2;
+
+ if ( $radar[ 'show_count' ] )
+ {
+ $showCount = lbHandelRadarShowCount( $item );
+
+ $out = false;
+
+ if ( $showCount <= $radar[ 'mini' ] || $showCount >= $radar[ 'max' ] )
+ {
+ $out = true;
+ }
+
+ if ( $showCount >= $radar[ 'mini' ] && $radar[ 'max' ] == 0 )
+ {
+ $out = false;
+ }
+
+ if ( $radar[ 'mini' ] == 0 && $radar[ 'max' ] == 0 )
+ {
+ $out = false;
+ }
+
+ if ( $out )
+ {
+ continue;
+ }
+
+ if ( $showCount === 0 )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '首次', 'color' => 0 ];
+ }
+ else
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '第' . ($showCount+1) . '次', 'color' => 0 ];
+ }
+ }
+
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $radar[ 'operation' ], 'color' => 1 ];
+
+ if ( $radar[ 'item' ] )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '你的', 'color' => 0 ];
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $radar[ 'item' ], 'color' => 1 ];
+ }
+
+ if ( $radar[ 'table_name' ] && $item[ 'target' ] && $radar[ 'field' ] )
+ {
+ $info = @\think\facade\Db::name( $radar[ 'table_name' ] )
+ ->find( $item[ 'target' ] );
+
+
+ $tmpArr = explode( ',', $radar[ 'field' ] );
+ //预约零时解决方案
+ $tmpStr1 = null;
+ if(in_array($radar['sign'], ['order']) && in_array($radar['type'], ['3']))
+ {
+ $project_name = '';
+ if(isset($info['project_id']) && !empty($info['project_id']))
+ {
+ $project = @\think\facade\Db::name( 'lb_appoint_project' )->field('title')->find($info['project_id']);
+ if(!empty($project) && !empty($project['title'])) $project_name = $project['title'];
+ }
+ $time = time();
+ if(!empty($info['start_time'])) $time = $info['start_time'];
+ $remerk = '暂无';
+ if(!empty($info['remerk'])) $remerk = $info['remerk'];
+ $tmpStr1 = $project_name .' ,预约时间:' . date('y-m-d H:m:s' ,$time) . ' ,备注信息:' .$remerk;
+ }
+ if ( $info && !empty( $tmpArr ) )
+ {
+ $tmpStr = '';
+ foreach ( $info as $index2 => $item2 )
+ {
+
+ if ( in_array( $index2, $tmpArr ) )
+ {
+ $tmpStr .= ',' . $item2;
+ }
+ }
+
+ $tmpStr = $tmpStr.' ';
+
+ $tmpStr = trim( $tmpStr, ',' );
+
+
+ if(!empty($tmpStr1)) $tmpStr = $tmpStr1;
+ if ( $tmpStr )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => ': ', 'color' => 0 ];
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $tmpStr, 'color' => 0 ];
+ }
+ }
+
+ }
+
+ if ( !empty( $data[ $index ][ 'radar_arr' ] ) && $radar[ 'msg' ] )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => ',', 'color' => 0 ];
+ }
+
+
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $radar[ 'msg' ], 'color' => 0 ];
+
+ if ( $item[ 'duration' ] )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '时长: ' . $item[ 'duration' ] . '秒', 'color' => 1 ];
+ }
+
+
+ }
+
+ if ( empty( $data[ $index ][ 'radar_arr' ] ) )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '进入你的名片,请把握商机!', 'color' => 0 ];
+ }
+
+
+ if(!json_encode($data))
+ {
+ unset($data[ $index ]);
+ }else{
+
+ if(key_exists($index,$data)){
+ $result[] = $data[ $index ];
+ }
+
+ }
+ }
+
+ return $result;
+ }
+}
+if ( !function_exists( 'lbHandelRadarMsgBac' ) )
+{
+ function lbHandelRadarMsgBac ( $data )
+ {
+ if ( empty( $data ) )
+ {
+ return $data;
+ }
+ $msgList = \app\radar\model\RadarMsg::where([['uniacid', '=', $data[0]['uniacid']]])->select()->toArray();
+
+ //自动导入雷达数据
+ if ( !$msgList || empty( $msgList ) )
+ {
+ $msgList = lbInitRadarMsg( $data[ 0 ][ 'uniacid' ] );
+ }
+
+ $tmpMsgList = array();
+ foreach ( $msgList as $index => $item )
+ {
+ $tmpMsgList[ $item[ 'sign' ] . $item[ 'type' ] ] = $item;
+ }
+
+ foreach ( $data as $index => $item )
+ {
+ $data[ $index ][ 'radar_arr' ] = [];
+ if ( isset( $tmpMsgList[ $item[ 'sign' ] . $item[ 'type' ] ] ) )
+ {
+ $radar = $tmpMsgList[ $item[ 'sign' ] . $item[ 'type' ] ];
+
+ if ( $radar[ 'show_count' ] )
+ {
+ $showCount = lbHandelRadarShowCount( $item );
+ if ( $showCount === 0 )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '首次', 'color' => 0 ];
+ }
+ else
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '第' . $showCount . '次', 'color' => 0 ];
+ }
+ }
+
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $radar[ 'operation' ], 'color' => 1 ];
+
+ if ( $radar[ 'item' ] )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '你的', 'color' => 0 ];
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $radar[ 'item' ], 'color' => 1 ];
+ }
+
+ if ( $radar[ 'table_name' ] && $item[ 'target' ] && $radar[ 'field' ] )
+ {
+ $info = @\think\facade\Db::name( $radar[ 'table_name' ] )
+ ->find( $item[ 'target' ] );
+ $tmpArr = explode( ',', $radar[ 'field' ] );
+ if ( $info && !empty( $tmpArr ) )
+ {
+ $tmpStr = '';
+ foreach ( $info as $index2 => $item2 )
+ {
+ if ( in_array( $index2, $tmpArr ) )
+ {
+ $tmpStr .= ',' . $item2;
+ }
+ }
+ $tmpStr = trim( $tmpStr, ',' );
+ if ( $tmpStr )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => ': ', 'color' => 0 ];
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $tmpStr, 'color' => 0 ];
+ }
+ }
+ }
+
+ if ( !empty( $data[ $index ][ 'radar_arr' ] ) && $radar[ 'msg' ] )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => ',', 'color' => 0 ];
+ }
+
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => $radar[ 'msg' ], 'color' => 0 ];
+
+ if ( $item[ 'duration' ] )
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '时长: ' . $item[ 'duration' ] . '秒', 'color' => 1 ];
+ }
+
+
+ }
+ else
+ {
+ $data[ $index ][ 'radar_arr' ][] = [ 'title' => '进入你的名片,请把握商机!', 'color' => 0 ];
+ }
+ }
+
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 雷达相同类型出现的次数
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbHandelRadarShowCount' ) )
+{
+ function lbHandelRadarShowCount ( $item )
+ {
+ $model = new \app\radar\model\RadarCount();
+
+ $count = $model->where( [ [ 'uniacid', '=', $item[ 'uniacid' ] ], [ 'to_uid', '=', $item[ 'to_uid' ] ],
+ [ 'sign', '=', $item[ 'sign' ] ], [ 'type', '=', $item[ 'type' ] ],
+ [ 'id', '<', $item[ 'id' ] ], [ 'user_id', '=', $item[ 'user_id' ] ], ]
+ )
+ ->count();
+ return intval( $count );
+ }
+}
+
+/**
+ * @Purpose: 初始化雷达激励提醒文案
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbInitRadarMsg' ) )
+{
+ function lbInitRadarMsg ( $uniacid )
+ {
+
+ $model = new \app\radar\model\RadarMsg();
+ //$list = longbingInitRadarMessage();
+ $list = longbing_init_info_data('RadarMessage');
+
+ //var_dump($list);exit;
+
+ $time = time();
+ $saveList = [];
+ foreach ( $list as $index => $item )
+ {
+ //判断是否新增过了 , 应该判断几个核心字段,可能需要新增字段判断,这里判断不科学
+ $whereCountData[ 'uniacid' ] = $uniacid;
+ $whereCountData[ 'sign' ] = $item['sign'];
+ $whereCountData[ 'type' ] = $item['type'];
+
+ $radarMsgData = $model->where($whereCountData)->find();
+
+ if(!$radarMsgData){
+ $item[ 'create_time' ] = $time;
+ $item[ 'update_time' ] = $time;
+ $item[ 'uniacid' ] = $uniacid;
+ //$saveList[] = $item;
+ $model->insert($item);
+ }else{
+ $item[ 'update_time' ] = $time;
+ $item[ 'uniacid' ] = $uniacid;
+ $item = array_merge($radarMsgData->toArray(),$item); //合并配置更新
+ $model->update($item);
+ }
+
+ }
+ //判断一个加入一个,还没有好办法判断导入的$list 去重
+ //$result = $model->saveAll( $saveList );
+
+ return $model->where( [ [ 'uniacid', '=', $uniacid ] ])->select()->toArray();
+ }
+}
+
+/**
+ * @Purpose: 参数验证
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'lbGetParamVerify' ) )
+{
+ function lbGetParamVerify ( $data, $verify )
+ {
+ $tmpData = [];
+ foreach ( $verify as $index => $item )
+ {
+ if ( isset( $data[ $index ] ) )
+ {
+ if ( $item === 'required' && is_string( $data[ $index ] ) && !$data[ $index ] )
+ {
+ echo json_encode( [ 'code' => 400, 'error' => '缺少参数' . $index ] );
+ exit;
+ }
+ if ( ( is_string( $data[ $index ] ) || is_numeric( $data[ $index ] ) ) && !is_array( $data[ $index ] ) )
+ {
+ $data[ $index ] = trim( $data[ $index ] );
+ }
+ $tmpData[ $index ] = $data[ $index ];
+ }
+ else
+ {
+ if ( $item === 'required' )
+ {
+ echo json_encode( [ 'code' => 400, 'error' => 'need param ' . $index ] );
+ exit;
+ }
+ else
+ {
+ if ( ( is_string( $item ) || is_numeric( $item ) ) && !is_array( $item ) )
+ {
+ $item = trim( $item );
+ }
+ $tmpData[ $index ] = $item;
+ }
+ }
+ }
+
+ return $tmpData;
+ }
+}
+
+/**
+ * @Purpose: 处理时间戳--单个
+ *
+ * @Param: $data array 需要处理的二维数组
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'handleTimes' ) )
+{
+ function handleTimes ( $data, $item_name = 'create_time', $rule = 'Y-m-d H:i:s' )
+ {
+ foreach ( $data as $index => $item )
+ {
+ $data[ $index ][ $item_name ] = date( $rule, $item[ $item_name ] );
+ }
+
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 处理时间戳--数组
+ *
+ * @Param: $data array 需要处理的二维数组
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'handleTimesByArray' ) )
+{
+ function handleTimesByArray ( $data, $item_name = ['create_time'], $rule = 'Y-m-d H:i:s' )
+ {
+ foreach ( $data as $index => $item )
+ {
+
+ foreach ($item_name as $index2 => $item2)
+ {
+ $data[ $index ][$item2] = date( $rule, $item[ $item2 ] );
+ }
+
+ }
+
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 生成小程序码
+ *
+ * @Param: $staff_id number 员工id
+ * @Param: $from_id number 来自谁的ID
+ * @Param: $target_id number 详情id,商品详情,动态详情等
+ * @Param: $page number 用户端首页tabbar页面类型 1=>名片;2=>商城;3=>动态;4=>官网;5=>房产;6=>活动;7=>预约;
+ * @Param: $name string 用户小程序码区分命名 card_qr = 名片码
+ * @Param: $version string 小程序码版本
+ * @Param: $miniPath string 小程序页面路径
+ * @Param: $imagePath string 本地图片存储路径
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ *
+ * 已弃用
+ */
+if ( !function_exists( 'createMiniQr' ) )
+{
+ function createMiniQr ( $staff_id, $from_id, $name, $uniacid, $miniPath, $imagePath, $target_id = 0, $page = 1, $version = 'v2' )
+ {
+ global $_W;
+ $imageName = "{$name}_{$staff_id}_{$from_id}_{$uniacid}_{$version}.png";
+
+ $scene = "$staff_id-$staff_id-$target_id-$page";
+
+ $accessToken = getAccessToken( $uniacid );
+
+ if ( $accessToken === 0 )
+ {
+ return '';
+ }
+
+ if ( defined( 'IS_WE7' ) && IS_WE7 )
+ {
+ if ( defined( 'ATTACHMENT_ROOT' ) && ATTACHMENT_ROOT )
+ {
+ $imagePathRoot = ATTACHMENT_ROOT . '/' . $imagePath;
+ }
+ else
+ {
+ $imagePathRoot = $_SERVER[ 'DOCUMENT_ROOT' ] . '/public/upload/' . $imagePath;
+ }
+ }
+ else
+ {
+ $imagePathRoot = $_SERVER[ 'DOCUMENT_ROOT' ] . '/public/upload/' . $imagePath;
+ }
+ $result = mkdirs_v2( $imagePathRoot );
+
+ if ( $result === false )
+ {
+ return '';
+ }
+
+ $post_data = '{"scene":"' . $scene . '","page":"' . $miniPath . '"}';
+ $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=$accessToken";
+
+// $result = lbSingleCurlPost( $url, $post_data );
+ $result = longbingCurl($url ,$post_data ,'POST');
+ if ( strstr( $accessToken, 'errcode' ) )
+ {
+ return '';
+ }
+
+ $result = file_put_contents( $imagePathRoot . $imageName, $result );
+
+ if ( !$result )
+ {
+ return '';
+ }
+
+ if ( defined( 'IS_WE7' ) && IS_WE7 )
+ {
+ if ( defined( 'ATTACHMENT_ROOT' ) && ATTACHMENT_ROOT )
+ {
+ $src = $_W[ 'siteroot' ] . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $imagePath . '/' . $imageName;
+ }
+ else
+ {
+ $src = $_SERVER[ 'HTTP_HOST' ] . '/public/upload/' . $imagePath . '/' .$imageName;
+ }
+ }
+ else
+ {
+ $src = $_SERVER[ 'HTTP_HOST' ] . '/public/upload/' . $imagePath . '/' .$imageName;
+ }
+
+ return $src;
+ }
+}
+
+
+if ( !function_exists( 'getMiniQr' ) )
+{
+ function getMiniQr ( $staff_id, $from_id, $name, $uniacid, $imagePath, $version = 'v2' )
+ {
+ global $_W;
+ $imageName = "{$name}_{$staff_id}_{$from_id}_{$uniacid}_{$version}.png";
+
+ if ( defined( 'IS_WE7' ) && IS_WE7 )
+ {
+ if ( defined( 'ATTACHMENT_ROOT' ) && ATTACHMENT_ROOT )
+ {
+ $src = $_W[ 'siteroot' ] . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $imagePath . '/' . $imageName;
+ }
+ else
+ {
+ $src = $_SERVER[ 'HTTP_HOST' ] . '/public/upload/' . $imagePath . '/' .$imageName;
+ }
+ }
+ else
+ {
+ $src = $_SERVER[ 'HTTP_HOST' ] . '/public/upload/' . $imagePath . '/' .$imageName;
+ }
+
+ return $src;
+ }
+}
+
+/**
+ * @Purpose: 处理数字
+ *
+ * @Param: $staff_id number 员工id
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'formatNumberPrice' ) )
+{
+ function formatNumberPrice ( $data, $target = [ 'price' ], $un = 10000, $unit = '万' )
+ {
+ global $_W;
+
+ foreach ( $data as $index => $item )
+ {
+ if ( is_array( $item ) )
+ {
+ $data[ $index ] = formatNumberPrice( $item, $target, $un );
+ }
+ else
+ {
+ if ( in_array( $index, $target ) && $item > $un )
+ {
+ $data[ $index ] = bcdiv( $item, $un, 2 ) . $unit;
+ }
+ }
+ }
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 处理默认图片
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'formatDefaultImage' ) )
+{
+ function formatDefaultImage ( $data, $target, $default, $defaultArr )
+ {
+
+ foreach ( $data as $index => $item )
+ {
+ if ( is_array( $item ) )
+ {
+ $data[ $index ] = formatDefaultImage( $item, $target, $default, $defaultArr );
+ }
+ else
+ {
+ if ($index == $target && $item == '' && isset($defaultArr[$default]))
+ {
+ $data[$index] = $defaultArr[$default];
+ }
+ }
+ }
+ return $data;
+ }
+}
+
+/**
+ * @Purpose: 清除用户相关缓存
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if ( !function_exists( 'clearUserCache' ) )
+{
+ function clearUserCache ( $user_id )
+ {
+ $key = 'longbing_user_autograph_' . $uid;
+ foreach ( $data as $index => $item )
+ {
+ if ( is_array( $item ) )
+ {
+ $data[ $index ] = formatDefaultImage( $item, $target, $default, $defaultArr );
+ }
+ else
+ {
+ if ($index == $target && $item == '' && isset($defaultArr[$default]))
+ {
+ $data[$index] = $defaultArr[$default];
+ }
+ }
+ }
+ return $data;
+ }
+}
+
+if ( !function_exists( 'mkdirs_v2' ) )
+{
+ function mkdirs_v2 ( $dir, $mode = 0777 )
+ {
+
+ if ( is_dir( $dir ) || @mkdir( $dir, $mode ) ) return TRUE;
+
+ if ( !mkdirs_v2( dirname( $dir ), $mode ) ) return FALSE;
+
+ return @mkdir( $dir, $mode );
+
+ }
+}
+
+
+if ( !function_exists( 'getAccessToken' ) )
+{
+ function getAccessToken ( $uniacid )
+ {
+ $key = "longbing_card_access_token";
+
+ $value = getCache( $key,$uniacid);
+
+ if ( $value !== false )
+ {
+ return $value;
+ }
+
+ $modelConfig = new \app\card\model\Config();
+ $config = $modelConfig->getConfig( $uniacid );
+ $key = '';
+ $secret = '';
+
+ if ( defined( 'IS_WE7' ) && IS_WE7 )
+ {
+ global $_W;
+ $key = $_W[ 'account' ][ 'key' ];
+ $secret = $_W[ 'account' ][ 'secret' ];
+ }
+
+ if ( isset( $config[ 'appid' ] ) && $config[ 'appid' ] )
+ {
+ $key = $config[ 'appid' ];
+ }
+
+ if ( isset( $config[ 'app_secret' ] ) && $config[ 'app_secret' ] )
+ {
+ $secret = $config[ 'app_secret' ];
+ }
+
+ if ( !$key || !$secret )
+ {
+ echo json_encode( [ 'code' => 402, 'error' => 'need appid appsecret' ] );
+ exit;
+ }
+
+ $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$key&secret={$secret}";
+
+ $accessToken = file_get_contents( $url );
+
+ if ( strstr( $accessToken, 'errcode' ) )
+ {
+ return 0;
+ }
+
+ $accessToken = json_decode( $accessToken, true );
+ $accessToken = $accessToken[ 'access_token' ];
+
+ setCache( $key, $accessToken, 7000, $uniacid );
+
+ return $accessToken;
+ }
+}
+
+if ( !function_exists( 'lbCurlPost' ) )
+{
+ function lbCurlPost ( $url, $data )
+ {
+ //初使化init方法
+ $ch = curl_init();
+
+ //指定URL
+ curl_setopt( $ch, CURLOPT_URL, $url );
+
+ //设定请求后返回结果
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
+
+ //声明使用POST方式来进行发送
+ curl_setopt( $ch, CURLOPT_POST, 1 );
+
+ //发送什么数据呢
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
+
+
+ //忽略证书
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false );
+
+ //忽略header头信息
+ curl_setopt( $ch, CURLOPT_HEADER, 0 );
+
+ //设置超时时间
+ curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
+
+ //发送请求
+ $output = curl_exec( $ch );
+
+ //关闭curl
+ curl_close( $ch );
+
+ //返回数据
+ return $output;
+ }
+}
+
+if ( !function_exists( 'lbGetDates' ) )
+{
+ function lbGetDates ( $time )
+ {
+ if ( $time >= 86400 * 30 )
+ {
+ $month = floor( $time / ( 86400 * 30 ) ) . '月后过期';
+ return $month;
+ }
+
+ if ( $time >= 86400 )
+ {
+ $day = floor( $time / ( 86400 ) ) . '天后过期';
+ return $day;
+ }
+
+ if ( $time >= 3600 )
+ {
+ $hour = floor( $time / ( 3600 ) ) . '时后过期';
+ return $hour;
+ }
+
+ if ( $time >= 60 )
+ {
+ $min = floor( $time / ( 60 ) ) . '分后过期';
+ return $min;
+ }
+
+ if ( $time >= 1 )
+ {
+ $sin = $time . '秒后过期';
+ return $sin;
+ }
+ else
+ {
+ return '已过期';
+ }
+ }
+}
+
+
+if ( !function_exists( 'lbGetDatesNoMonth' ) )
+{
+ function lbGetDatesNoMonth ( $time )
+ {
+// if ( $time >= 86400 * 30 )
+// {
+// $month = floor( $time / ( 86400 * 30 ) ) . '月后过期';
+// return $month;
+// }
+
+ if ( $time >= 86400 )
+ {
+ $day = floor( $time / ( 86400 ) ) . '天后过期';
+ return $day;
+ }
+
+ if ( $time >= 3600 )
+ {
+ $hour = floor( $time / ( 3600 ) ) . '时后过期';
+ return $hour;
+ }
+
+ if ( $time >= 60 )
+ {
+ $min = floor( $time / ( 60 ) ) . '分后过期';
+ return $min;
+ }
+
+ if ( $time >= 1 )
+ {
+ $sin = $time . '秒后过期';
+ return $sin;
+ }
+ else
+ {
+ return '已过期';
+ }
+ }
+}
+
+if ( !function_exists( 'lbGetDatess' ) )
+{
+ function lbGetDatess ( $time )
+ {
+ $s_time = $time;
+
+ if ( $time >= 86400 * 30 )
+ {
+ $month = floor( $time / ( 86400 * 30 ) );
+ $time -= 86400 * 30 * $month;
+ $month .= '月';
+ }
+ else
+ {
+ $month = '';
+ }
+ if ( $time >= 86400 )
+ {
+ $day = floor( $time / ( 86400 ) );
+ $time -= 86400 * $day;
+ $day .= '天';
+
+ }
+ else
+ {
+ $day = '';
+ }
+ if ( $time >= 3600 )
+ {
+ $hour = floor( $time / ( 3600 ) );
+ $time -= 3600 * $hour;
+ $hour .= '时';
+
+ }
+ else
+ {
+ $hour = '';
+ }
+ if ( $time >= 60 )
+ {
+ $min = floor( $time / ( 60 ) );
+ $time -= 60 * $min;
+ $min .= '分';
+ }
+ else
+ {
+ $min = '';
+ }
+
+ if ( $time >= 1 )
+ {
+ $sin = $time . '秒';
+
+ }elseif($s_time == $time&&$time<=0){
+
+ return '已过期';
+
+ }else{
+
+ $sin = '';
+ }
+ return '还剩' . $month . $day . $hour . $min . $sin;
+
+ }
+}
+
+if ( !function_exists( 'lbGetDatesss' ) )
+{
+ function lbGetDatesss ( $time )
+ {
+ $s_time = $time;
+
+ if ( $time >= 86400 * 30 )
+ {
+ $month = floor( $time / ( 86400 * 30 ) );
+ $time -= 86400 * 30 * $month;
+ $month .= '月';
+ }
+ else
+ {
+ $month = '';
+ }
+ if ( $time >= 86400 )
+ {
+ $day = floor( $time / ( 86400 ) );
+ $time -= 86400 * $day;
+ $day .= '天';
+
+ }
+ else
+ {
+ $day = '';
+ }
+ if ( $time >= 3600 )
+ {
+ $hour = floor( $time / ( 3600 ) );
+ $time -= 3600 * $hour;
+ $hour .= '时';
+
+ }
+ else
+ {
+ $hour = '';
+ }
+ if ( $time >= 60 )
+ {
+ $min = floor( $time / ( 60 ) );
+ $time -= 60 * $min;
+ $min .= '分';
+ }
+ else
+ {
+ $min = '';
+ }
+
+ if ( $time >= 1 )
+ {
+ $sin = $time . '秒';
+
+ }elseif($s_time == $time&&$time<=0){
+
+ return '已过期';
+
+ }else{
+
+ $sin = '';
+ }
+ return $month . $day . $hour . $min . $sin;
+
+ }
+}
+
+
+if ( !function_exists( 'lbGetfDate' ) )
+{
+ function lbGetfDate ( $time )
+ {
+ if ( $time >= 86400 * 30 )
+ {
+ $month = floor( $time / ( 86400 * 30 ) ) . '月前';
+ return $month;
+ }
+ if ( $time >= 86400 * 7 )
+ {
+ $month = floor( $time / ( 86400 * 7 ) ) . '周前';
+ return $month;
+ }
+ if ( $time >= 86400 ) {
+ $day = floor($time / (86400)) . '天前';
+ return $day;
+ }else{
+ return '今天';
+ }
+ }
+}
+
+
+//插入消息数据(异步)
+
+function asyncAddMessage ( $data )
+{
+ //存储消息
+ $message_model = new ImMessage();
+ $result = $message_model->createMessage( $data );
+ //修改时间chat
+ $chat_model = new ImChat();
+ $chat_model->updateChat(['id' => $data['chat_id']] ,[]);
+ return $result;
+}
+
+//创建文件夹
+function longbingMkdirs ( $path )
+{
+ if ( !is_dir( $path ) )
+ {
+ mkdirs( dirname( $path ) );
+ mkdir( $path );
+ }
+
+ return is_dir( $path );
+}
+
+//复制文件
+function longbingFileCopy ( $src, $des, $filter )
+{
+ $dir = opendir( $src );
+ @mkdir( $des );
+ while ( false !== ( $file = readdir( $dir ) ) )
+ {
+ if ( ( $file != '.' ) && ( $file != '..' ) )
+ {
+ if ( is_dir( $src . '/' . $file ) )
+ {
+ file_copy( $src . '/' . $file, $des . '/' . $file, $filter );
+ }
+ elseif ( !in_array( substr( $file, strrpos( $file, '.' ) + 1 ), $filter ) )
+ {
+ copy( $src . '/' . $file, $des . '/' . $file );
+ }
+ }
+ }
+ closedir( $dir );
+}
+
+//删除文件
+function longbingRmdirs ( $path, $clean = false )
+{
+ if ( !is_dir( $path ) )
+ {
+ return false;
+ }
+ $files = glob( $path . '/*' );
+ if ( $files )
+ {
+ foreach ( $files as $file )
+ {
+ is_dir( $file ) ? rmdirs( $file ) : @unlink( $file );
+ }
+ }
+
+ return $clean ? true : @rmdir( $path );
+}
+
+function longbingStrexists ( $string, $find )
+{
+ return !( strpos( $string, $find ) === FALSE );
+}
+
+
+//微擎方法
+function longbingTomedia ( $src, $local_path = false, $is_cahce = false )
+{
+ global $_W;
+ $src = trim( $src );
+ if ( empty( $src ) )
+ {
+ return '';
+ }
+ if ( $is_cahce )
+ {
+ $src .= "?v=" . time();
+ }
+
+ if ( longbingStrexists( $src, "c=utility&a=wxcode&do=image&attach=" ) )
+ {
+ return $src;
+ }
+
+ $t = strtolower( $src );
+ if ( longbingStrexists( $t, 'https://mmbiz.qlogo.cn' ) || longbingStrexists( $t, 'http://mmbiz.qpic.cn' ) )
+ {
+ $url = url( 'utility/wxcode/image', array( 'attach' => $src ) );
+ return $_W[ 'siteroot' ] . 'web' . ltrim( $url, '.' );
+ }
+
+ if ( substr( $src, 0, 2 ) == '//' )
+ {
+ return 'http:' . $src;
+ }
+ if ( ( substr( $src, 0, 7 ) == 'http://' ) || ( substr( $src, 0, 8 ) == 'https://' ) )
+ {
+ return $src;
+ }
+
+ if ( longbingStrexists( $src, 'addons/' ) )
+ {
+ return $_W[ 'siteroot' ] . substr( $src, strpos( $src, 'addons/' ) );
+ }
+ if ( longbingStrexists( $src, $_W[ 'siteroot' ] ) && !longbingStrexists( $src, '/addons/' ) )
+ {
+ $urls = parse_url( $src );
+ $src = $t = substr( $urls[ 'path' ], strpos( $urls[ 'path' ], 'images' ) );
+ }
+ if ( $local_path || empty( $_W[ 'setting' ][ 'remote' ][ 'type' ] ) && ( empty( $_W[ 'uniacid' ] ) || !empty( $_W[ 'uniacid' ] ) && empty( $_W[ 'setting' ][ 'remote' ][ $_W[ 'uniacid' ] ][ 'type' ] ) ) || file_exists( IA_ROOT . '/' . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $src ) )
+ {
+ $src = $_W[ 'siteroot' ] . $_W[ 'config' ][ 'upload' ][ 'attachdir' ] . '/' . $src;
+ }
+ else
+ {
+ $src = $_W[ 'attachurl_remote' ] . $src;
+
+ }
+ return $src;
+}
+
+
+//获取文件地址
+function longbingGetFilePath($path , $web_url,$uniacid = '7777' ,$type = null)
+{
+ $oss_config = longbingGetOssConfig($uniacid);
+// if(longbingIsWeiqin() && empty($oss_config)){
+// return longbingTomedia($path);
+// }
+ $website_url = $web_url . '/attachment';
+ if(!empty($oss_config) && !empty($oss_config['open_oss']) && !in_array($type, ['loacl']))
+ {
+ $website_url = $oss_config['default_url'];
+ }
+ return $website_url . '/' .$path;
+}
+
+
+//获取配置
+function longbingGetOssConfig($uniacid = '7777' ,$is_update = false)
+{
+ $key = 'longbing_oos_config_';
+ //判断是否更新数据
+ if(!$is_update)
+ {
+ if(hasCache($key ,$uniacid))
+ {
+ return getCache($key ,$uniacid);
+ }
+ }
+ //生成操作模型
+ $oss_config_model = new OssConfig();
+ //小程序授权模型
+// $card_Auth_model = new Cardauth2ConfigModel();
+// //获取代理端配置端上传信息
+// $uplode_setting = $card_Auth_model->where(['modular_id'=>$uniacid])->find();
+// //如果统一使用了上传配置
+// if(!empty($uplode_setting['upload_setting'])){
+// //获取数据
+// $config = $oss_config_model->getConfig(['id' => $uplode_setting['upload_setting']]);
+// }else{
+ //获取数据
+ $config = $oss_config_model->getConfig(['uniacid' => $uniacid]);
+// }
+
+ $result = [];
+ if(!empty($config))
+ {
+ $filter = [];
+ switch($config['open_oss'])
+ {
+ case 0:
+ $filter = ['uniacid','miniapp_name' ,'open_oss' ,'is_sync'];
+ break;
+ case 1:
+ $filter = ['uniacid','miniapp_name' ,'open_oss' ,'is_sync' ,'aliyun_bucket' ,'aliyun_access_key_id' ,'aliyun_access_key_secret' ,'aliyun_base_dir' ,'aliyun_zidinyi_yuming' ,'aliyun_endpoint' ,'aliyun_rules'];
+ break;
+ case 2:
+ $filter = ['uniacid','miniapp_name' ,'open_oss' ,'is_sync' ,'qiniu_accesskey' ,'qiniu_secretkey' ,'qiniu_bucket' ,'qiniu_yuming' ,'qiniu_rules'];
+ break;
+ case 3:
+ $filter = ['uniacid','miniapp_name' ,'open_oss' ,'is_sync' ,'tenxunyun_appid' ,'tenxunyun_secretid' ,'tenxunyun_secretkey' ,'tenxunyun_bucket' ,'tenxunyun_region' ,'tenxunyun_yuming'];
+ break;
+ default:
+ $filter = ['uniacid','miniapp_name' ,'open_oss' ,'is_sync'];
+ break;
+ }
+ foreach($config as $k => $v)
+ {
+ if(in_array($k, $filter))
+ {
+ $result[$k] = $v;
+ }
+ }
+ switch($result['open_oss'])
+ {
+ case 1:
+ $result['default_url'] = $result['aliyun_zidinyi_yuming'];
+ break;
+ case 2:
+ $result['default_url'] = $result['qiniu_yuming'];
+ break;
+ case 3:
+ $result['default_url'] = $result['tenxunyun_yuming'];
+ break;
+ default:
+ $result['default_url'] = $_SERVER['HTTP_HOST'];
+ break;
+ }
+
+ }else{
+ $oss_config_model->createConfig(['uniacid' => $uniacid ,'open_oss' => 0]);
+ $result = longbingGetOssConfig($uniacid ,true);
+ }
+ if(!empty($result)) setCache($key, $result , 3600 ,$uniacid);
+ return $result;
+}
+
+
+//微信接口返回数据处理
+function LongbingGetWxApiReturnData($result)
+{
+ if (!is_array($result)) return $result;
+ if(isset($result['page'])) $result['current_page'] = $result['page'];unset($result['page']);
+ if(isset($result['page_count'])) $result['per_page'] = $result['page_count'];unset($result['page_count']);
+ if(isset($result['total_page'])) $result['last_page'] = $result['total_page'];unset($result['total_page']);
+ return $result;
+}
+function getStr($str){
+ $vid = strstr($str, 'vid=');
+ if($vid){
+ $sdd = substr($str,strpos($str,"vid=")+4);
+ $dd = explode('"',$sdd)[0];
+ }else{
+ $aa = basename($str);
+ $bb = explode('.',$aa);
+ $dd = $bb[0];
+ }
+ return $dd;
+}
+//获取html src里面的内容替换
+function getimgs($str)
+{
+ $arr1 = [];
+ $arr2 = [];
+ $reg = "/src=\"(.+?)\"/";
+ $matches = array();
+ $str = htmlspecialchars_decode($str);
+ preg_match_all($reg, $str, $matches);
+ foreach ($matches[0] as $value) {
+ if(!strstr($value, '/v.qq.com/')){
+ continue;
+ }
+ $in = rtrim(getStr($value),'"');
+ $sf = "src=\"$in\" lbType=vid";
+ $arr1[] = $value;
+ $arr2[] = $sf;
+ }
+ $ssf = str_replace($arr1, $arr2, $str);
+ return htmlspecialchars($ssf);
+}
+
+function getimgsV2($str)
+{
+ $arr1 = [];
+ $arr2 = [];
+ $reg = "/src=\"(.+?)\"/";
+ $matches = array();
+ $str = htmlspecialchars_decode($str);
+ preg_match_all($reg, $str, $matches);
+ foreach ($matches[0] as $value) {
+ if(!strstr($value, '/v.qq.com/')){
+ continue;
+ }
+ $in = rtrim(getStr($value),'"');
+ $sf = "src=\"$in\" lbType=\"vid\"";
+ $arr1[] = $value;
+ $arr2[] = $sf;
+ }
+ $ssf = str_replace($arr1, $arr2, $str);
+ $ssf = str_replace('lbType=vid','lbType="vid"',$ssf);
+
+ return ($ssf);
+}
+
+function datachange($data,$field = 'create_time'){
+
+// dump($data);exit;
+ // 今天的时间戳
+ $time = time();
+ // 昨天的时间戳
+ $Yesterday = $time - ( 24 * 60 * 60 );
+
+ $today = mktime( 0, 0, 0, date( "m", $time ), date( "d", $time ), date( "Y", $time ) );
+ $Yesterday = mktime( 0, 0, 0, date( "m", $Yesterday ), date( "d", $Yesterday ), date( "Y", $Yesterday ) );
+
+
+
+ $tmpTime = $data[ $field ];
+ if ( $tmpTime > $today )
+ {
+ // $data[ $index ][ 'radar_time' ] = '今天 ';
+ $data[ 'radar_group' ] = '今天';
+ $data[ 'radar_time' ] = date( 'H:i', $data[ $field ] );
+ }
+ else if ( $tmpTime > $Yesterday )
+ {
+ // $data[ $index ][ 'radar_time' ] = '昨天 ';
+ $data[ 'radar_group' ] = '昨天';
+ $data[ 'radar_time' ] = date( 'H:i', $data[ $field ] );
+ }
+ else
+ {
+ $thisYear = date( 'Y' );
+ $itemYear = date( 'Y', $data[ $field ] );
+ if ( $thisYear == $itemYear )
+ {
+ $data[ 'radar_group' ] = date( 'm-d', $data[ $field ] );
+ $data[ 'radar_time' ] = date( ' H:i', $data[ $field ] );
+ }
+ else
+ {
+ $data[ 'radar_group' ] = date( 'Y-m-d', $data[ $field ] );
+ $data[ 'radar_time' ] = date( ' H:i', $data[ $field ] );
+ }
+
+ }
+ return $data;
+}
+
+//服务通知
+function longbingSendWxServiceNotice($count_id)
+{
+ //生成count操作模型
+ $count_model = new LongbingCardCount();
+ //获取count数据
+ $count = $count_model->getCount(['id' => $count_id]);
+ //判断count是否存在
+ if(empty($count) || !isset($count['uniacid'])) return false;
+ //生成服务通知模型
+// var_dump($count);die;
+ $service_notice_model = new LongbingServiceNotice($count['uniacid']);
+ //发送
+ return $service_notice_model->sendServiceNoticeToStaff($count_id);
+}
+
+//服务通知
+function longbingSendMessageWxServiceNotice($message)
+{
+ //判断messange是否为空
+ if(empty($message) || !isset($message['content']) || !isset($message['user_id']) || !isset($message['target_id']) || !isset($message['uniacid'])) return false;
+ $message['to_user_id'] = $message['target_id'];
+ //生成服务通知模型
+ $service_notice_model = new LongbingServiceNotice($message['uniacid']);
+ //发送
+ return $service_notice_model->sendMessageServiceNotice($message);
+}
+
+function longbingSendWxServiceNoticeBase($data)
+{
+ $openid = null;
+ $form_id = null;
+ $nickName = null;
+ $send_body = null;
+ $uniacid = null;
+ $time = time();
+ $page_data = "longbing_card/staff/radar/radar";
+ if(isset($data['open_id']) && !empty($data['open_id'])) $openid = $data['open_id'];
+ if(isset($data['uniacid']) && !empty($data['uniacid'])) $uniacid = $data['uniacid'];
+ if(isset($data['form_id']) && !empty($data['form_id'])) $form_id = $data['form_id'];
+ if(isset($data['nickName']) && !empty($data['nickName'])) $nickName = $data['nickName'];
+ if(isset($data['send_body']) && !empty($data['send_body'])) $send_body = $data['send_body'];
+ if(isset($data['time']) && !empty($data['time'])) $time = $data['time'];
+ if(isset($data['page_data']) && !empty($data['page_data'])) $page_data = $data['page_data'];
+
+ //判断数据是否存在
+ if(empty($openid) || empty($form_id) || empty($nickName) || empty($send_body)||empty($uniacid)) return;
+
+ $service_notice_model = new LongbingServiceNotice($uniacid);
+ return $service_notice_model->sendWxService($openid ,$form_id ,$nickName ,$send_body ,$time ,$page_data);
+}
+
+
+
+
+
+
+//获取用户信息
+function longbingGetUser($user_id ,$uniacid ='7777' ,$is_update = false)
+{
+
+ //缓存数据key
+ $key = 'longbing_card_user_' . $user_id;
+ //数据
+ $user = null;
+ //判断缓存是否存在
+ if(hasCache($key ,$uniacid) && empty($is_update)){
+ //获取缓存数据
+ $user = getCache($key ,$uniacid);
+ //判断缓存数据是否为空,否则返回
+ if(!empty($user)) return $user;
+ }
+ //获取用户数据
+ $user_model = new LongbingUser();//生成查询类
+
+ //获取数据
+ $user = $user_model->getUser(['id' => $user_id ,'uniacid' => $uniacid]);
+
+ //判断用户是否为空
+ if(empty($user)) return null;
+ $user['need_auth'] = 0;
+ if(!isset($user['avatarUrl']) || empty($user['avatarUrl']) || in_array($user['avatarUrl'], ['https://retail.xiaochengxucms.com/defaultAvatar.png'])) $user['need_auth'] = 1;
+ //获取用户授权手机号
+ $user['phone'] = longbingGetUserAuthorizationPhone($user_id ,$uniacid);
+ //设置缓存
+ //setCache ( $key, $user, 3600, $uniacid);
+ longbingSetUser($user_id ,$uniacid ,$user);
+ //返回数据
+ return $user;
+}
+
+//设置用户信息
+function longbingSetUser($user_id ,$uniacid ,$data)
+{
+ //缓存数据key
+ $key = 'longbing_card_user_' . $user_id;
+ if(empty($data) || empty($uniacid) || empty($user_id)) return false;
+ return setCache ( $key, $data, 3600, $uniacid);
+}
+//获取用户授权手机号信息
+function longbingGetUserAuthorizationPhone($user_id ,$uniacid)
+{
+ $phone_model = new UserPhone();
+ $phone = $phone_model->getUserPhone($user_id ,$uniacid);
+ if(isset($phone['phone'])) $phone = $phone['phone'];
+ return $phone;
+}
+
+////获取用户信息
+//function longbingGetUserInfo($user_id ,$uniacid ='7777' ,$is_update = false)
+//{
+// //缓存数据key
+// $key = 'longbing_card_user_info_' . $user_id;
+// //数据
+// $user = null;
+// //判断缓存是否存在
+// if(hasCache($key ,$uniacid) && empty($is_update)){
+// //获取缓存数据
+// $user = getCache($key ,$uniacid);
+// //判断缓存数据是否为空,否则返回
+// if(!empty($user)) return $user;
+// }
+// //获取用户数据
+// $user_model = new LongbingUserInfo();//生成查询类
+// //获取数据
+// $user = $user_model->getUser(['fans_id' => $user_id ,'uniacid' => $uniacid]);
+// //判断用户是否为空
+// if(empty($user)) return null;
+// $user['share_img'] = "images/share_img/{$uniacid}/share-{$user_id}.png";
+// if(!longbingHasLocalFile($user['share_img'])) {
+// $user['share_img'] = null;
+// }else{
+// $user = transImagesOne($user, ['share_img']);
+// }
+// //设置缓存
+//// setCache ( $key, $user, 600, $uniacid);
+// longbingSetUserInfo($user_id ,$uniacid ,$user);
+// //返回数据
+// return $user;
+//}
+
+function longbingGetUserInfo($user_id ,$uniacid ='7777' ,$is_update = false)
+{
+ //缓存数据key
+ $key = 'longbing_card_user_info_' . $user_id;
+ //数据
+ $user = null;
+ //判断缓存是否存在
+ if(hasCache($key ,$uniacid) && empty($is_update)){
+ //获取缓存数据
+ $user = getCache($key ,$uniacid);
+ //判断缓存数据是否为空,否则返回
+ if(!empty($user)) return $user;
+ }
+ //获取用户数据
+ $user_model = new LongbingUserInfo();//生成查询类
+ //获取数据
+ $user = $user_model->getStaff($user_id ,$uniacid);
+ //判断用户是否为空
+ if(empty($user)) return null;
+
+ $user['share_img'] = "images/share_img/{$uniacid}/share-{$user_id}.png";
+ if(!longbingHasLocalFile($user['share_img'])) {
+ $user['share_img'] = null;
+ }else{
+ $user = transImagesOne($user, ['share_img']);
+ }
+ //设置缓存
+ setCache ( $key, $user, 600, $uniacid);
+ longbingSetUserInfo($user_id ,$uniacid ,$user);
+ //返回数据
+ return $user;
+}
+
+function longbingGetUserCard($user_id ,$uniacid ='7777' ,$is_update = false)
+{
+
+ $user = longbingGetUserInfo($user_id ,$uniacid);
+ if(empty($user) || empty($user['is_staff'])) return FALSE;
+ $user['company_info'] = [];
+ $user['company_name'] = '';
+ if(isset($user['company_id']) && !empty($user['company_id'])) {
+ $company = longbingGetUserCompany($user['company_id'] ,$uniacid);
+ $user['company_info'] = $company;
+ if(!empty($user['company_info']) && isset($user['company_info']['name'])) $user['company_name'] = $user['company_info']['name'];
+ }
+ return $user;
+}
+
+function longbingGetUserCompany($company_id ,$uniacid = '7777' ,$is_update = false)
+{
+ //获取公司信息
+ $company = null;
+ $key = 'longbing_card_company_' . $company_id;
+ if(hasCache($key ,$uniacid) && empty($is_update)){
+ //获取缓存数据
+ $company = getCache($key ,$uniacid);
+ //判断缓存数据是否为空,否则返回
+ if(!empty($company)) return $company;
+
+ }
+ $company_model = new CompanyModel();
+
+ $company = $company_model->getCompany([['id' ,'=' , $company_id] ,['status' ,'>' ,-1]]);
+ if(empty($company)) return null;
+ setCache ( $key, $company, 600, $uniacid);
+ return $company;
+}
+//设置缓存数据
+function longbingSetUserInfo($user_id ,$uniacid ,$data)
+{
+ //缓存数据key
+ $key = 'longbing_card_user_info_' . $user_id;
+ if(empty($data) || empty($uniacid) || empty($user_id)) return false;
+ return setCache ( $key, $data, 600, $uniacid);
+}
+
+//获取小程序配置信息
+function longbingGetAppConfig($uniacid ,$is_update = false)
+{
+ //获取缓存信息
+ $key = 'lbfarm_config';
+
+ $result = getCache($key ,$uniacid);
+
+ if(empty($result)) {
+
+ $config_model = new \app\farm\model\Config();
+
+ $dis = [
+
+ 'uniacid' => $uniacid
+ ];
+
+ $result = $config_model->dataInfo($dis);
+ }
+
+ //返回数据
+ return $result;
+}
+
+//获取小程序底部菜单信息
+function longbingGetAppTabbar($uniacid ,$is_update = false)
+{
+ $key = 'longbing_app_tabbar_' . $uniacid;
+ if(hasCache($key ,$uniacid) && empty($is_update))
+ {
+ $result = getCache($key ,$uniacid);
+ if(!empty($result)) return $result;
+ }
+ //获取数据
+ $app_tabbar_model = new AppTabbar();
+ $result = $app_tabbar_model->getTabbar(['uniacid' => $uniacid]);
+ //设置缓存
+ if(!empty($result))
+ {
+ setCache($key, $result ,600 ,$uniacid);
+ }else{
+ $tabbar_model = new AppTabbar();
+ $data = array(
+ 'uniacid' => $uniacid,
+ 'menu2_is_hide' => 0,
+ 'menu3_is_hide' => 0,
+ 'menu4_is_hide' => 0,
+ 'menu_activity_is_show' => 0,
+ 'menu_house_is_show' => 0,
+ 'menu_appoint_is_hide' => 0
+ );
+ $tabbar_model->createTabbar($data);
+ $result = longbingGetAppTabbar($uniacid ,true);
+ }
+ //返回数据
+ return $result;
+}
+
+if ( !function_exists( 'longbingArticleToXml' ) ) {
+ function longbingArticleToXml ($data)
+ {
+ include_once __DIR__."/../extend/html2wxml/class.ToWXML.php";
+
+ $content = htmlspecialchars_decode($data);
+
+
+ if ( $content != strip_tags($content) ) {
+ } else {
+ $content = '' . $content . '
';
+ }
+
+ $towxml = new ToWXML2();
+ $json = $towxml->towxml($content, array(
+ 'type' => 'html',
+ 'highlight' => true,
+ 'linenums' => true,
+ 'imghost' => null,
+ 'encode' => false,
+ 'highlight_languages' => array( 'html', 'js', 'php', 'css' )
+ ));
+ return $json;
+ }
+}
+
+//获取accessToken
+function longbingSingleGetAccessToken($appid ,$appsecret ,$uniacid ,$is_update = false)
+{
+
+ $setting = new WxSetting($uniacid);
+
+ $token = $setting->lbSingleGetAccessToken();
+
+ return $token;
+
+}
+
+//获取accesstoken通过uniacid
+function longbingSingleGetAccessTokenByUniacid($uniacid ,$is_update = false)
+{
+ $config = longbingGetAppConfig($uniacid ,$is_update);
+ if(!isset($config['appid']) || empty($config['appid']) || !isset($config['app_secret']) || empty($config['app_secret'])) return false;
+ $access_token = longbingSingleGetAccessToken($config['appid'] ,$config['app_secret'] ,$uniacid ,$is_update);
+ if(empty($access_token)) $access_token = false;
+ return $access_token;
+}
+
+//生成curl方法
+function longbingCurl($url,$post,$method = 'GET')
+{
+ $curl_model = new LongbingCurl();
+ return $curl_model->curlPublic($url,$post,$method);
+}
+
+//获取usersession key
+function longbingGetUserSk($user_id ,$uniacid ,$is_update = false)
+{
+ //生成key
+ $key = 'longbing_user_sk_' . $user_id;
+ //判断缓存是否存在
+ $sk = null;
+ if(hasCache($key ,$uniacid) && !empty($is_update))
+ {
+ $sk = getCache($key ,$uniacid);
+ if(empty($result)) return $sk;
+ }
+ $user_sk_model = new UserSk();
+ //获取数据
+ $result = $user_sk_model->getSk(['user_id' => $user_id ,'uniacid' => $uniacid ,'status' => 1]);
+ //判断数据是否存在
+ if(isset($result['sk']) && !empty($result['sk']))
+ {
+ setCache($key, $result['sk'] ,3600 ,$uniacid);
+ $sk = $result['sk'];
+ }
+ return $sk;
+}
+
+/**
+ * 友好的时间显示
+ *
+ * @param int $sTime 待显示的时间
+ * @param string $type 类型. normal | mohu | full | ymd | other
+ * @param string $alt 已失效
+ * @return string
+ */
+if (!function_exists('lb_friendly_date')) {
+ function lb_friendly_date($sTime,$type = 'mohu',$alt = 'false') {
+ if (!$sTime)
+ return '';
+ //sTime=源时间,cTime=当前时间,dTime=时间差
+ $cTime = time();
+ $dTime = $cTime - $sTime;
+
+ //$dDay = intval(date("z",$ cTime)) - intval(date("z",$sTime));
+
+ $dDay = intval($dTime/3600/24);
+
+ $dYear = intval(date("Y",$cTime)) - intval(date("Y",$sTime));
+ //normal:n秒前,n分钟前,n小时前,日期
+ if($type=='normal'){
+ if( $dTime < 60 ){
+ if($dTime < 10){
+ return '刚刚'; //by yangjs
+ }else{
+ return intval(floor($dTime / 10) * 10).'秒前';
+ }
+ } elseif( $dTime < 3600 ){
+ return intval($dTime/60).'分钟前';
+ //今天的数据.年份相同.日期相同.
+ } elseif( $dYear==0 && $dDay == 0 ){
+ //return intval($dTime/3600).L('_HOURS_AGO_');
+ return '今天'.date('H:i',$sTime);
+ } elseif( $dDay > 0 && $dDay<=3 ){
+ return intval($dDay).'天前';
+ } elseif($dYear==0){
+ return date("m月d日 H:i",$sTime);
+ } else{
+ return date("m-d H:i",$sTime);
+ }
+ } elseif($type=='mohu'){
+ if( $dTime < 60 ){
+ return $dTime.'秒前';
+ } elseif( $dTime < 3600 ){
+ return intval($dTime/60).'分钟前';
+ } elseif( $dTime >= 3600 && $dDay == 0 ){
+ return intval($dTime/3600).'小时前';
+ } elseif( $dDay > 0 && $dDay<=7 ){
+ return intval($dDay).'天前';
+ } elseif( $dDay > 7 && $dDay <= 30 ){
+ return intval($dDay/7) . '周前';
+ } elseif( $dDay > 30 ){
+ return intval($dDay/30) .'个月前';
+ }
+ //full: Y-m-d , H:i:s
+ } elseif($type=='full'){
+ return date("m-d , H:i",$sTime);
+ } elseif($type=='ymd'){
+ return date("Y-m-d",$sTime);
+ } else{
+ if( $dTime < 60 ){
+ return $dTime.'秒前';
+ } elseif( $dTime < 3600 ){
+ return intval($dTime/60).'分钟前';
+ } elseif( $dTime >= 3600 && $dDay == 0 ){
+ return intval($dTime/3600).'小时前';
+ } elseif($dYear==0){
+ return date("m-d H:i",$sTime);
+ } else{
+ return date("m-d H:i",$sTime);
+ }
+ }
+ }
+}
+
+function longbingGetAccessToken($uniacid , $is_update = false)
+{
+
+
+ $setting = new WxSetting($uniacid);
+
+ $token = $setting->lbSingleGetAccessToken();
+
+ return $token;
+
+}
+//生成微信小程序二维码
+function longbingCreateWxCode($uniacid ,$data ,$page = '' ,$type = 3)
+{
+ $code_id = md5($uniacid . json_encode($data ,true));
+ //上传路径
+ $path = 'image/' . $uniacid . '/' . 'wxcode';
+
+ if(!mkdirs_v2(FILE_UPLOAD_PATH . $path)) return false;
+ //设置文件权限
+ longbingchmodr(FILE_UPLOAD_PATH);
+ //封装数据
+ if(!isset($data['data'])) $data['data'] = $data;
+ $code_data = array(
+ 'uniacid' => $uniacid,
+ 'data' => json_encode($data['data'] ,true)
+ );
+ //写入数据
+ $wechat_code_model = new LongbingCardWechatCode();
+
+ //判断数据是否存在
+ $code = longbingGetWxCode($code_id ,$uniacid);
+ //创建
+ if(empty($code))
+ {
+ $code_data['id'] = $code_id;
+ $result = $wechat_code_model->createCode($code_data);
+ }else{
+ $result = $wechat_code_model->updateCode(['id' => $code_id] ,$code_data);
+ }
+
+
+ //刷新缓存
+ longbingGetWxCode($code_id ,$uniacid ,true);
+ if(empty($result)) return false;
+ $path = null;
+ $with = 430;
+ $auto_color = true;
+ $line_color = '{"r":0,"g":0,"b":0}';
+ $is_hyaline = false;
+ //获取数据
+ if(isset($data['path'])) $path = $data['path'];
+ if(isset($data['with'])) $with = $data['with'];
+ if(isset($data['auto_color'])) $auto_color = $data['auto_color'];
+ if(isset($data['line_color'])) $line_color = $data['line_color'];
+ if(isset($data['is_hyaline'])) $is_hyaline = $data['is_hyaline'];
+ //生成获取微信code接口
+ $wechat_code_model = new WeChatCode($uniacid);
+ switch($type)
+ {
+ case 1:
+ $result = $wechat_code_model->getQRCode($path ,$width = 430);
+ break;
+ case 2:
+ $result = $wechat_code_model->getWxCode($path ,$width = 430 ,$auto_color = true ,$line_color = '{"r":0,"g":0,"b":0}' ,$is_hyaline = false);
+ break;
+ default:
+ $result = $wechat_code_model->getUnlimitedCode($code_id ,$page ,$width = 430 ,$auto_color = false ,$line_color = '{"r":0,"g":0,"b":0}' ,$is_hyaline = true);
+ break;
+ }
+ //判断是否生成失败
+ $data = json_decode($result ,true);
+ if(isset($data['errcode']) || isset($data['errmsg'])) return false;
+ //存储文件
+ $path = 'image/' . $uniacid . '/' . 'wxcode';
+ $file_name = $code_id . '.jpeg';
+ $path = $path . '/' . $file_name;
+ if(longbingHasLocalFile($path)) unlink(FILE_UPLOAD_PATH . $path);
+ $data = file_put_contents(FILE_UPLOAD_PATH . $path ,$result);
+ //设置文件权限
+
+
+ //上传到云端
+// $file = new UploadedFile($path ,$file_name);
+// $file_upload_model = new Upload($uniacid);
+// $result = $file_upload_model->upload('picture' ,$file);
+ //删除文件
+// unlink($path);
+ if(empty($data)) return false;
+ //数据转换
+ return ['qr_path' => $path ,'path' => $path];
+
+}
+//获取微信小程序二维码数据
+function longbingGetWxCode($code_id ,$uniacid , $is_update = false)
+{
+ //生成key
+ $key = 'longbing_wechat_code_' . $code_id;
+ $data = null;
+ //获取缓存数据
+// if(hasCache($key ,$uniacid) && empty($is_update))
+// {
+// $data = getCache($key ,$uniacid);
+// if(!empty($data)) return $data;
+// }
+ //从数据库中获取数据
+ $wechat_code_model = new LongbingCardWechatCode();
+ $data = $wechat_code_model->getCode(['id' => $code_id ,'uniacid' => $uniacid]);
+ if(!empty($data)) {
+ if(isset($data['data'])) $data['data'] = json_decode($data['data'],true);
+
+ }
+ return $data;
+}
+//获取企业的token
+function qyGetAccessToken ( $uniacid )
+{
+ $key = "longbing_card_access_token_qy";
+
+ $value = getCache( $key );
+
+ if ( $value !== false )
+ {
+ return $value;
+ }
+
+ $modelConfig = new \app\card\model\Config();
+ $config = $modelConfig->getConfig( $uniacid );
+ $key = '';
+ $secret = '';
+ if ( isset( $config[ 'corpid' ] ) && $config[ 'corpid' ] )
+ {
+ $key = $config[ 'corpid' ];
+ }
+
+ if ( isset( $config[ 'corpsecret' ] ) && $config[ 'corpsecret' ] )
+ {
+ $secret = $config[ 'corpsecret' ];
+ }
+
+ if ( !$key || !$secret )
+ {
+ echo json_encode( [ 'code' => 402, 'error' => 'need corpid corpsecret' ] );
+ exit;
+ }
+
+ $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$key&corpsecret=$secret";
+
+ $accessToken = file_get_contents( $url );
+ $accessToken = json_decode( $accessToken, true );
+ if($accessToken['errcode'] != 0){
+ echo json_encode( [ 'code' => 402, 'error' => '获取token失败' ] );
+ exit;
+ }
+ $accessToken = $accessToken[ 'access_token' ];
+ setCache( $key, $accessToken, 7200, $uniacid );
+ return $accessToken;
+}
+
+
+/**
+ * @Purpose: 检查能不能使用获客文章
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+if (!function_exists('lbSingleCheckArticleV2')) {
+ function lbSingleCheckArticleV2($uniacid, $user_id)
+ {
+ $userInfo = Db::name('longbing_card_user_info')->where(['fans_id' => $user_id, 'is_staff' => 1])->find();
+ if (!$userInfo) {
+ return 0;
+ }
+
+ $cacheKey = 'article_' . $userInfo['id'];
+
+// delCache($cacheKey, $uniacid);
+ $cache = getCache($cacheKey, $uniacid);
+ if ($cache === 1) {
+ return 1;
+ }
+
+
+//
+// if (!defined('LONGBING_AUTH_ARTICLE_SINGLE')) {
+// return 2;
+// }
+//
+// if ($userInfo['signature'] > LONGBING_AUTH_ARTICLE_SINGLE) {
+// return 8;
+// }
+
+ if ($userInfo['autograph'] == 0 || $userInfo['signature'] == 0) {
+ return 7;
+ }
+
+ $time = time();
+
+ if ($userInfo['autograph'] - 123456789 < $time) {
+ return 9;
+ }
+
+ setCache($cacheKey, 1, $userInfo['autograph'] - 123456789 - $time, $uniacid);
+ return 1;
+ }
+}
+
+
+//获取插件的权限
+if (!function_exists('longbingGetPluginAuth')) {
+ function longbingGetPluginAuth($uniacid, $user_id = null, $auth_info_pass = false): array
+ {
+ $auth_info = false;
+ do {
+ if ($auth_info_pass) {
+ $auth_info = $auth_info_pass;
+ break;
+ }
+
+ $cardauth2_config_exist = Db::query('show tables like "%longbing_cardauth2_config%"');
+ if (!empty($cardauth2_config_exist)) {
+ $auth_info = Db::name('longbing_cardauth2_config')
+ ->where([['modular_id', '=', $uniacid]])
+ ->find();
+ break;
+ }
+ } while (false);
+
+ $data = [];
+
+ /**
+ * @var int $has_plugin_send 短信群发插件 0-没有, 1-有
+ * 验权条件:
+ * 1. ims_longbing_cardauth2_config表不存在, 或者 ims_longbing_cardauth2_config.send_switch的值等于1
+ */
+
+ $permission_send = new \app\sendmsg\info\PermissionSendmsg($uniacid);
+
+ $data['checkSend'] = $permission_send->pAuth();
+
+ $data['plugin']['send'] = $data['checkSend']==true?1:0;
+
+ /**
+ * @var int $has_plugin_appoint 预约插件 0-没有, 1-有
+ * 验权条件:
+ * 1. 系统中存在LONGBING_AUTH_APPOINT_SINGLE, 且等于1
+ * 2. ims_longbing_cardauth2_config表不存在, 或者 ims_longbing_cardauth2_config.appoint的值等于1
+ * 3. ims_lb_appoint_record_check这张表存在
+ */
+
+ $permission_appoint = new \app\appoint\info\PermissionAppoint($uniacid);
+
+ $data['checkAppoint'] = $permission_appoint->pAuth();
+
+ $data['plugin']['appoint'] = $data['checkAppoint']==true?1:0;
+
+ /**
+ * @var int $has_plugin_payqr 扫码支付插件 0-没有, 1-有
+ * 验权条件:
+ * 1. 系统中存在 LONGBING_AUTH_PAYQR_SINGLE, 且等于1
+ * 2. ims_longbing_cardauth2_config表不存在, 或者 ims_longbing_cardauth2_config.payqr的值等于1
+ * 3. ims_lb_pay_qr_config 存在
+ */
+
+ $permission_payqr = new \app\payqr\info\PermissionPayqr($uniacid);
+
+ $data['checkPayQr'] = $permission_payqr->pAuth();
+
+ $data['plugin']['payqr'] = $data['checkPayQr']==true?1:0;
+
+ /**
+ * @var int $has_plugin_article 获客文章插件 0-没有, 1-有
+ * 验权条件:
+ * 1. 系统中定义 LONGBING_AUTH_ARTICLE_SINGLE 常量, 并且值大于0;
+ * 2. 不存在ims_longbing_cardauth2_config这样表,或者 ims_longbing_cardauth2_config.article的值等于1
+ * 3. 存在ims_lb_marketing_record这张表
+ * 4. ims_longbing_card_config.autograph - 80666, 这个值大于等于 ims_longbing_card_config.signature
+ && ims_longbing_cardauth2_article.number 这个值大于0
+ */
+
+ $permission_article = new \app\article\info\PermissionArticle($uniacid);
+
+ $data['checkArticle'] = $permission_article->pAuth();
+
+ $data['plugin']['article'] = $data['checkArticle']==true?1:0;
+
+ /**
+ * @var int $has_plugin_activity 活动报名插件 0-没有, 1-有
+ * 验权条件:
+ * 1. 系统中有定义LONGBING_AUTH_ACTIVITY_SINGLE 且 值大于0;
+ * 2. ims_longbing_cardauth2_config表不存在,
+ * 或者 (ims_longbing_cardauth2_config.activity_switch值不存在,
+ * 或者ims_longbing_cardauth2_config.activity_switch的值等于1,
+ * );
+ * 3. longbing_cardauth2_activity.sum(count) < LONGBING_AUTH_ACTIVITY_SINGLE
+ * 4. longbing_cardauth2_activity.sign > time() && longbing_cardauth2_activity.count > 0;
+ *
+ */
+
+ $permission_atv = new \app\activity\info\PermissionActivity($uniacid);
+
+ $data['checkActivity'] = $permission_atv->pAuth();
+
+ $data['plugin']['activity'] = $data['checkActivity']==true?1:0;
+
+ /**
+ * @var int $has_plugin_house 房产插件 0-没有, 1-有
+ * 验权条件:
+ * 1. 系统中有定义 LONGBING_AUTH_HOUSE 且 值大于0;
+ * 2. ims_longbing_cardauth2_config表不存在,
+ 或者 ims_longbing_cardauth2_config.house_switch 的值等于1,
+ * 3. longbing_cardauth2_house.count > 0,
+ * 4. longbing_cardauth2_house.sign>time() && longbing_cardauth2_house.sum(count) < LONGBING_AUTH_HOUSE
+
+ */
+
+ $permission_house = new \app\house\info\PermissionHouse($uniacid);
+
+ $data['checkHouse'] = $permission_house->pAuth();
+
+ $data['plugin']['house'] = $data['checkHouse']==true?1:0;
+
+
+ /**
+ * @var int $has_plugin_poster 获客海报 0-没有, 1-有
+ * 验权条件:
+ * 所有小程序都可以使用
+ */
+ $has_plugin_poster = 1;
+
+ $data['plugin']['poster'] = $has_plugin_poster;
+
+ $data['checkPoster'] = true;
+
+ /**
+ * @var int $has_plugin_boss 公司部门 0-没有, 1-有
+ * 验权条件:
+ * 1. 系统中有定义 LONGBING_AUTH_BOSS_SINGLE 且 值大于0;
+ * 2. ims_longbing_cardauth2_config表不存在,
+ 或者 ims_longbing_cardauth2_config.boss 的值 > 已开通的boss值,
+ * 3. longbing_cardauth2_boss.count > 0,
+ * 4. longbing_cardauth2_boss.sign>time() && longbing_cardauth2_boss.sum(count) < LONGBING_AUTH_HOUSE
+ */
+
+ $permission_boss = new \app\boss\info\PermissionBoss($uniacid);
+
+ $data[ 'checkBoss' ] = $permission_boss->pAuth();
+
+ $data['plugin']['boss'] = $data[ 'checkBoss' ]==true?1:0;
+
+
+
+// $adminMenus = config('app.adminMenus');
+ $myModelList = \config('app.AdminModelList');
+
+ $myModelList = $myModelList['saas_auth_admin_model_list'];
+
+ $adminMenus = [];
+
+ foreach($myModelList as $key=>$value ) {
+
+ $adminMenus[] = $key;
+ }
+
+ /**
+ * @var array $web_manage_meta_config 后台导航列配置
+ */
+ $web_manage_meta_config = [
+ 'survey' => in_array('survey', $adminMenus) ? 1 : 0, //概况
+ 'card' => in_array('card', $adminMenus) ? 1 : 0, //名片
+ 'shop' => (!$auth_info || $auth_info['shop_switch']) && in_array('shop', $adminMenus) ? 1: 0, //商城
+ 'Malls' => (!$auth_info || $auth_info['shop_switch']) && in_array('shop', $adminMenus) ? 1: 0, //商城(兼容老版本)
+ 'dynamic' => (!$auth_info || $auth_info['timeline_switch']) && in_array('dynamic', $adminMenus)? 1 : 0, //动态
+ 'website' => (!$auth_info || $auth_info['website_switch']) && in_array('Website', $adminMenus) ? 1 : 0, //官网
+ 'customer' => in_array('customer', $adminMenus) ? 1: 0, //客户
+ 'company' => in_array('company', $adminMenus) ? 1: 0, //公司
+ 'system' => in_array('admin', $adminMenus) ? 1: 0, //系统
+ 'renovation' => in_array('renovation', $adminMenus) ? 1: 0, //装修
+ 'diy' => in_array('diy', $adminMenus) ? 1: 0, //Diy
+ 'copyright_id' => $auth_info['copyright_id'] ?? 0,
+ 'appstore' => in_array('app', $adminMenus) ? [ //应用
+ 'payqr' => $has_plugin_payqr, //扫码支付
+ 'poster' => $has_plugin_poster, //海报
+ 'send' => $has_plugin_send, //群发
+ 'appiont' => $has_plugin_appoint, //活动
+ 'house' => $has_plugin_house, //房产
+ 'activity' => $has_plugin_activity, //活动
+ 'article' => $has_plugin_article, //文章
+ ] : []
+ ];
+
+ $data['web_manage_meta_config'] = $web_manage_meta_config;
+
+ //$data['card_number'] = isset($auth_info['number']) ? $auth_info['number'] : LONGBING_AUTH_CARD;
+ //$data['boss_num'] = isset($auth_info['boos']) ? $auth_info['boos'] : LONGBING_AUTH_CARD;
+ //新的名片数量获取方式
+ $permissionCard = new \app\card\info\PermissionCard($uniacid) ;
+ $authCardNumber = $permissionCard->getAuthNumber() ;
+
+ $data['boss_num'] = isset($auth_info['boos']) ? $auth_info['boos'] : $authCardNumber ;
+ $data['card_number'] = $authCardNumber ;
+
+
+ return $data;
+ }
+}
+
+/**
+ * 获取应用模块列表
+ */
+
+
+//获取connection数据
+function longbingGetCollectionById($client_id ,$is_update = false)
+{
+ $uniacid = 'longbing';
+ //获取缓存数据
+ $key = 'longbing_collection_id_' . $client_id;
+ if(hasCache($key,$uniacid) && empty($is_update))
+ {
+ $result = getCache($key ,$uniacid);
+ if(empty($result)) return $result;
+ }
+ //获取数据库数据
+ $collection_model = new Collection();
+ $result = $collection_model->getCollection(['id' => $client_id]);
+ if(!empty($result)) setCache($key, $result ,300 ,$uniacid);
+ return $result;
+}
+//获取connection数据
+function longbingGetCollection($user_id ,$staff_id ,$uniacid ,$is_update = false)
+{
+ $key = 'longbing_collection_' . $user_id. '_' .$staff_id;
+ if(hasCache($key,$uniacid) && empty($is_update))
+ {
+ $result = getCache($key ,$uniacid);
+ if(empty($result)) return $result;
+ }
+ //获取数据库数据
+ $collection_model = new Collection();
+ $result = $collection_model->getCollection(['uid' => $user_id ,'to_uid' => $staff_id ,'uniacid' => $uniacid]);
+ if(!empty($result))
+ {
+ setCache($key, $result ,300 ,$uniacid);
+ }else{
+ //创建
+ $collection_model = new Collection();
+ $collection_model->createCollection(['uid' => $user_id ,'to_uid' => $staff_id ,'uniacid' => $uniacid]);
+ $result = longbingGetCollection($user_id ,$staff_id ,$uniacid);
+ }
+ return $result;
+ }
+
+//更新collection数据
+function longbingUpdateCollection($collection_id ,$rate)
+{
+ $collection_model = new Collection();
+ return $collection_model->updateCollection(['id' => $collection_id ] ,['rate' => $rate ,'update_rate_time' => time()]);
+}
+
+//获取rate更新信息
+function longbingGetRate($user_id ,$staff_id ,$uniacid ,$is_update = false)
+{
+ $key = 'longbing_rate_update_' . $user_id. '_' .$staff_id;
+ if(hasCache($key,$uniacid) && empty($is_update))
+ {
+ $result = getCache($key ,$uniacid);
+ if(empty($result)) return $result;
+ }
+ //获取数据库数据
+ $rate_model = new LongbingCardRate();
+ $result = $rate_model->getRate(['user_id' => $user_id ,'staff_id' => $staff_id ,'uniacid' => $uniacid]);
+ if(empty($result))
+ {
+ $rate_model = new LongbingCardRate();
+ $rate_model->createRate(['user_id' => $user_id ,'staff_id' => $staff_id ,'uniacid' => $uniacid]);
+ $result = longbingGetRate($user_id ,$staff_id ,$uniacid);
+ }else{
+ setCache($key, $result ,60 ,$uniacid);
+ }
+ return $result;
+}
+
+/*
+ * 更新Rate信息
+ * @creator yangqi
+ */
+function longbingUpdateRate($rate_id ,$rate)
+{
+ $rate_model = new LongbingCardRate();
+ $result = $rate_model->updateRate(['id' => $rate_id] ,['rate' => $rate]);
+ return $result;
+}
+/*
+ * 更新客户成交率
+ * @creator yangqi
+ */
+
+function updateCustomerRate($page = 1 ,$page_count = 200)
+{
+ //获取客户数据
+ $collections = listCollections($page ,$page_count);
+// var_dump($collections['total']);die;
+// var_dump($page . '--------------------------------------------------' .$collections['total_page']);
+ //判断当前页数是否小于总页数
+ if($page < $collections['total_page'])
+ {
+ //递归查询
+ $page += 1;
+ $push_data = array(
+ 'action' => 'updateCustomerRate',
+ 'event' => 'updateCustomerRate',
+ 'page' => $page,
+ 'page_count' =>$page_count
+ );
+ publisher(json_encode($push_data ,true));
+ }
+ //查询更新数据
+ foreach($collections['data'] as $collection)
+ {
+ $push_data = array(
+ 'action' => 'updatecollectionRate',
+ 'event' => 'updatecollectionRate',
+ 'client_id' => $collection['id']
+ );
+// var_dump($collection['id']);
+ publisher(json_encode($push_data ,true) ,30000);
+ }
+ return $collections;
+}
+
+//获取客户列表
+function listCollections($page ,$page_count)
+{
+ //设置分页默认参数
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 200
+ );
+ //获取分页参数
+ if(!empty($page) && $page > 0) $page_config['page'] = $page;
+ if(!empty($page_count) && $page_count > 0) $page_config['page_count'] = $page_count;
+// var_dump($page_config);
+ //获取数据
+ $collection_model = new Collection();
+ //获取总数
+ $page_config['total'] = $collection_model->getCollectionJoinRateCount();
+ //获取数据
+ $collections = $collection_model->listCollectionJoinRate($page_config);
+ //生成总页数
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ //返回客户数据
+ $page_config['data'] = $collections;
+ $result = $page_config;
+ return $result;
+}
+
+//更新单个客户列表rate
+function updatecollectionRate($client_id)
+{
+// return ;
+ //获取collection
+ $collection = longbingGetCollectionById($client_id);
+ if(empty($collection) || ($collection['update_rate_time'] + 12*3600) > time()) return;
+ //获取信息数据
+ $user_id = $collection['uid'];
+ $staff_id = $collection['to_uid'];
+ $uniacid = $collection['uniacid'];
+ $rate = longbingGetRate($user_id ,$staff_id ,$uniacid);
+ if(isset($collection['rate']) && in_array($collection['rate'], [100 ,'100'])){
+ longbingUpdateRate($rate['id'] ,100);
+ longbingUpdateCollection($collection['id'] ,100);
+ return;
+ }
+ //获取rate分数
+ $count = countRate($client_id);
+ //更新数据
+ longbingUpdateCollection($collection['id'] ,$count);
+
+ longbingUpdateRate($rate['id'] ,$count);
+ return $rate;
+}
+
+//获取最新的rate
+function countRate($client_id)
+{
+ //获取client(uid ,to_uid ,uniacid)
+ $collection = longbingGetCollectionById($client_id);
+ if(empty($collection)) return 0;
+ $user_id = $collection['uid'];
+ $staff_id = $collection['to_uid'];
+ $uniacid = $collection['uniacid'];
+ //检查mark
+ $mark_model = new LongbingCardUserMark();
+ $mark_count = $mark_model->getMarkCount(['user_id' => $user_id ,'staff_id' => $staff_id ,'uniacid' => $uniacid ,'mark' => 2 ,'status' => 1]);
+ if(!empty($mark_count)) return 100;
+ //获取count
+ $staff_count = 5;
+ $client_count = 0;
+
+ //mark
+ $info = longbingGetCount('longbing_card_user_mark' ,['user_id' => $user_id ,'staff_id' => $staff_id ,'uniacid' => $uniacid]);
+ if(!empty($info)) $staff_count += 5;
+ //聊天
+ $chat_model = new ImChat();
+ $info = $chat_model->getChat($user_id ,$staff_id ,$uniacid);
+ if(isset($info['chat_id']))
+ {
+ $info = longbingGetCount('longbing_card_message' ,['chat_id' => $info['chat_id']]);
+ if(!empty($info)) $client_count += 4;
+ if($info > 15) $info = 15;
+ $staff_count += $info;
+ }
+ //打标签
+ $info = longbingGetCount('longbing_card_user_label' ,['user_id' => $user_id, 'staff_id' => $staff_id]);
+ if($info >10) $info = 10;
+ $staff_count += $info * 2;
+ //用户留下电话
+ $info = longbingGetCount('longbing_card_user_phone' ,['user_id' => $user_id, 'to_uid' => $staff_id]);
+ if(!empty($info)) $client_count += 6;
+ //打电话
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'copy', 'type' => 2]);
+ if(!empty($info)) $client_count += 4;
+
+ //存电话
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'copy', 'type' => 1]);
+ if(!empty($info)) $client_count += 4;
+
+ //复制微信
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'copy', 'type' => 4]);
+ if(!empty($info)) $client_count += 4;
+
+ //语音点赞
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'praise', 'type' => 1]);
+ if(!empty($info)) $client_count += 1;
+ //靠谱
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'praise', 'type' => 3]);
+ if(!empty($info)) $client_count += 1;
+ //浏览名片
+ $client_count += 2;
+ //浏览商城列表
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'view', 'type' => 1]);
+ if(!empty($info)) $client_count += 2;
+ //浏览商城详情
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'view', 'type' => 2]);
+ if(!empty($info)) $client_count += 2;
+ //浏览动态
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'view', 'type' => 3]);
+ if(!empty($info)) $client_count += 2;
+ //浏览官网
+ $info = longbingGetCount('longbing_card_count' , ['user_id' => $user_id, 'to_uid' => $staff_id, 'sign' => 'view', 'type' => 6]);
+ if(!empty($info)) $client_count += 2;
+ //授权基本信息
+ $info = longbingGetCount('longbing_card_user' , ['id' => $user_id]);
+ if(!empty($info) && !empty($info['avatarUrl'])) $client_count += 2;
+ //分享
+ $info = longbingGetCount('longbing_card_forward' , ['user_id' => $user_id, 'staff_id' => $staff_id ,'type' => 1]);
+ if(!empty($info) && !empty($info['avatarUrl'])) $client_count += 2;
+
+ $count = $staff_count + $client_count;
+
+ if($count>92) $count = 92;
+ return $count;
+}
+
+//获取数量
+function longbingGetCount($table_name ,$filter)
+{
+ if(empty($table_name) || empty($filter) || !is_array($filter)) return false;
+ $common_model = new LongbingCardCommonModel();
+ return $common_model->getCount($table_name ,$filter);
+}
+
+//获取相关数据
+function longbingListData($table_name ,$filter ,$field = [])
+{
+ if(empty($table_name) || empty($filter) || !is_array($filter)) return false;
+ $common_model = new LongbingCardCommonModel();
+ return $common_model->listRows($table_name ,$filter ,$field);
+}
+//浏览人数
+function longbingView(){
+ $card_count = new CardCount();
+ //$yesterday = date("Y-m-d",strtotime("-1 day"));
+ //统计昨天的CardCount s数据
+// $where = [];
+// $card_count->getYesterdaylist($where);
+
+ //统计昨日新增客户
+// $collect = new Collection();
+// $where['intention'] = 1;
+// $collect->getTodaylist($where);
+// //转发名片
+// $forward_count = new CardForward();
+// $where2['type'] = 1;
+// $where2['status'] = 1;
+// $forward_count->getCount($where2);
+ //消息
+// $where4[] = [
+// ['status','=',1],
+// ['deleted','=',0],
+// ];
+// $card_message = new CardMessage();
+// $card_message->getCountlist($where4);
+ //
+}
+
+function getImageExt ( $src = '' )
+{
+ $src = explode( '.', $src );
+ $count = count( $src );
+ if ( $count < 2 )
+ {
+ return false;
+ }
+ $ext = strtolower( $src[ $count - 1 ] );
+ if ( $ext == 'jpg' )
+ {
+ return 'jpg';
+ }
+ if ( $ext == 'png' )
+ {
+ return 'png';
+ }
+ if ( $ext == 'jpeg' )
+ {
+ return 'jpeg';
+ }
+ return false;
+}
+
+function longbingCreateSharePng ( $gData, $codeName, $uniacid )
+{
+ //创建画布
+ // $im = imagecreatetruecolor(680, 390);
+ $im = imagecreatetruecolor( 738, 420 );
+// longbingchmodr(FILE_UPLOAD_PATH);
+ //填充画布背景色
+ $color = imagecolorallocate( $im, 255, 255, 255 );
+ imagefill( $im, 0, 0, $color );
+
+ //字体文件
+ $font_file = APP_PATH . "Common/extend/vista.ttf";
+
+
+ //设定字体的颜色
+ $font_color_1 = ImageColorAllocate( $im, 140, 140, 140 );
+ $font_color_2 = ImageColorAllocate( $im, 28, 28, 28 );
+ $font_color_3 = ImageColorAllocate( $im, 129, 129, 129 );
+ $font_color_4 = ImageColorAllocate( $im, 50, 50, 50 );
+ $font_color_5 = ImageColorAllocate( $im, 68, 68, 68 );
+ $font_color_red = ImageColorAllocate( $im, 217, 45, 32 );
+
+
+ // 画又边的图
+ list( $l_w, $l_h ) = getimagesize( $gData[ 'img' ] );
+ $ext = longbingSingleGetImageExtWx( $gData[ 'img' ] );
+ if ( $ext == 'jpg' || $ext == 'jpeg' )
+ {
+ $logoImg = @imagecreatefromjpeg( $gData[ 'img' ] );
+ }
+ else if ( $ext == 'png' )
+ {
+ $logoImg = @imagecreatefrompng( $gData[ 'img' ] );
+ }
+ else
+ {
+ return false;
+ }
+ // imagecopyresized($im, $logoImg, 368, 0, 0, 0, 312, 390, $l_w, $l_h);
+ // imagecopyresized($im, $logoImg, 399, 0, 0, 0, 339, 420, $l_w, $l_h);
+ imagecopyresized( $im, $logoImg, 358, 0, 0, 0, 420, 420, $l_w, $l_h );
+
+
+ // 画左边的图
+ list( $l_w1, $l_h1 ) = getimagesize( 'http://retail.xiaochengxucms.com/images/2/2018/12/F9O1e9o7EfFC9ZT3eVE3w739irRWs1.png' );
+ $logoImg1 = @imagecreatefrompng( 'http://retail.xiaochengxucms.com/images/2/2018/12/F9O1e9o7EfFC9ZT3eVE3w739irRWs1.png' );
+
+ imagecopyresized( $im, $logoImg1, 0, 0, 0, 0, 738, 420, $l_w1, $l_h1 );
+
+
+ //By.jingshuixian 判断logo是否存在,不存在使用默认图片
+ if( \longbingcore\tools\LongbingImg::exits( $gData[ 'company_logo' ] ) ){
+ //$gData[ 'company_logo' ] = \app\company\controller\CompanyDefine::$logo_404 ;
+
+ // 画logo
+ list( $l_w, $l_h ) = getimagesize( $gData[ 'company_logo' ] );
+ $ext = getImageExt( $gData[ 'company_logo' ] );
+
+ if ( $ext == 'jpg' || $ext == 'jpeg' )
+ {
+ $logoImg = @imagecreatefromjpeg( $gData[ 'company_logo' ] );
+ }
+ else if ( $ext == 'png' )
+ {
+ $logoImg = @imagecreatefrompng( $gData[ 'company_logo' ] );
+ }
+
+ if(!$logoImg){
+
+
+ if ( $ext == 'jpg' || $ext == 'jpeg' )
+ {
+ $logoImg = @imagecreatefrompng( $gData[ 'company_logo' ] );
+ }
+ else if ( $ext == 'png' )
+ {
+ $logoImg = @imagecreatefromjpeg( $gData[ 'company_logo' ] );
+ }
+ }
+
+
+ imagecopyresized( $im, $logoImg, 32, 22, 0, 0, 30, 30, $l_w, $l_h );
+
+ }
+
+ // 画图标
+ // list($l_w, $l_h) = getimagesize('http://longbingcard.xiaochengxucms.com/images/4/2018/11/Wz22ev7946Q5EN7E82F6R8ZTe2Rx24.png');
+ // $logoImg = @imagecreatefrompng('http://longbingcard.xiaochengxucms.com/images/4/2018/11/Wz22ev7946Q5EN7E82F6R8ZTe2Rx24.png');
+ //
+ //
+ // imagecopyresized($im, $logoImg, 30, 230, 0, 0, 30, 117, $l_w, $l_h);
+
+
+ imagettftext( $im, 14, 0, 68, 42, $font_color_4, $font_file, $gData[ 'company_name' ] );
+ imagettftext( $im, 14, 0, 78, 250, $font_color_5, $font_file, $gData[ 'phone' ] );
+ imagettftext( $im, 14, 0, 78, 295, $font_color_5, $font_file, $gData[ 'email' ] );
+ imagettftext( $im, 14, 0, 78, 338, $font_color_5, $font_file, $gData[ 'address' ] );
+
+ imagettftext( $im, 22, 0, 30, 115, $font_color_4, $font_file, $gData[ 'name' ] );
+ imagettftext( $im, 14, 0, 30, 155, $font_color_5, $font_file, $gData[ 'job' ] );
+
+
+ $radius = 30;
+ // lt(左上角)
+ $lt_corner = longbingGetItRoundCorner( $radius );
+
+ imagecopymerge( $im, $lt_corner, 0, 0, 0, 0, $radius, $radius, 100 );
+ // lb(左下角)
+ $lb_corner = imagerotate( $lt_corner, 90, 0 );
+ imagecopymerge( $im, $lb_corner, 0, 420 - $radius, 0, 0, $radius, $radius, 100 );
+ // rb(右上角)
+ $rb_corner = imagerotate( $lt_corner, 180, 0 );
+ imagecopymerge( $im, $rb_corner, 738 - $radius, 420 - $radius, 0, 0, $radius, $radius, 100 );
+ // rt(右下角)
+ $rt_corner = imagerotate( $lt_corner, 270, 0 );
+ imagecopymerge( $im, $rt_corner, 738 - $radius, 0, 0, 0, $radius, $radius, 100 );
+
+ $file_path = FILE_UPLOAD_PATH . "images/share_img/{$uniacid}";
+ mkdirs_v2($file_path);
+ $fileName = FILE_UPLOAD_PATH . "images/share_img/{$uniacid}/share-{$codeName}.png";
+ imagepng( $im, $fileName );
+
+
+ // $im = imagecreatetruecolor(780, 500);
+ $im = imagecreatetruecolor( 780, 624 );
+ $color = imagecolorallocate( $im, 223, 223, 223 );
+ imagefill( $im, 0, 0, $color );
+ list( $l_w1, $l_h1 ) = getimagesize( 'http://retail.xiaochengxucms.com/images/2/2018/12/WzRC39R9CsgmC9Rqq8b3rm8xBTsYG9.png' );
+ $bg = @imagecreatefrompng( 'http://retail.xiaochengxucms.com/images/2/2018/12/WzRC39R9CsgmC9Rqq8b3rm8xBTsYG9.png' );
+ // $im = @imagecreatefrompng('http://retail.xiaochengxucms.com/images/2/2018/12/WzRC39R9CsgmC9Rqq8b3rm8xBTsYG9.png');
+
+ imagecopyresized( $im, $bg, 0, 0, 0, 0, 780, 624, $l_w1, $l_h1 );
+
+
+ list( $l_w1, $l_h1 ) = getimagesize( $fileName );
+ $bg = @imagecreatefrompng( $fileName );
+
+ imagecopyresized( $im, $bg, 20, 20, 0, 0, 740, 420, $l_w1, $l_h1 );
+
+ $fileName = FILE_UPLOAD_PATH . "images/share_img/{$uniacid}/share-{$codeName}.png";
+ imagepng( $im, $fileName );
+ imagedestroy( $im );
+ imagedestroy( $logoImg );
+ imagedestroy( $logoImg1 );
+ imagedestroy( $bg );
+ return true;
+
+
+ //输出图片
+// if ( $fileName )
+// {
+// imagepng( $im, $fileName );
+// }
+// else
+// {
+// Header( "Content-Type: image/png" );
+// imagepng( $im );
+// }
+}
+
+function longbingGetItRoundCorner ( $radius )
+{
+ $img = imagecreatetruecolor( $radius, $radius ); // 创建一个正方形的图像
+ $bgcolor = imagecolorallocate( $img, 210, 210, 210 ); // 图像的背景
+ $fgcolor = imagecolorallocate( $img, 0, 0, 0 );
+ imagefill( $img, 0, 0, $bgcolor );
+
+ // $radius,$radius:以图像的右下角开始画弧
+ // $radius*2, $radius*2:已宽度、高度画弧
+ // 180, 270:指定了角度的起始和结束点
+ // fgcolor:指定颜色
+ imagefilledarc( $img, $radius, $radius, $radius * 2, $radius * 2, 180, 270, $fgcolor, IMG_ARC_PIE );
+ // 将弧角图片的颜色设置为透明
+ imagecolortransparent( $img, $fgcolor );
+ // 变换角度
+ // $img = imagerotate($img, 90, 0);
+ // $img = imagerotate($img, 180, 0);
+ // $img = imagerotate($img, 270, 0);
+ // header('Content-Type: image/png');
+ // imagepng($img);
+ // die;
+ return $img;
+}
+
+function longbingSortStr ( $str, $len )
+{
+ if ( mb_strlen( $str, 'utf8' ) > $len )
+ {
+ $str = mb_substr( $str, 0, $len, "UTF-8" ) . '...';
+ }
+ return $str;
+}
+//初始化公司和职务
+function longbingGetCompanyConfig($uniacid){
+ if($uniacid){
+ $company = new CardCompany();
+ //公司
+ $key = 'longbing_company_init_'.$uniacid;
+ if(hasCache($key ,$uniacid)) return ;
+ $company_count = $company->where('uniacid', '=', $uniacid)->count();
+ if( empty($company_count) )
+ {
+ $rest = $company->createRow([
+ 'name'=>'某某科技公司',
+ 'short_name'=>'某公司',
+ 'addr'=>'某某地址',
+ 'phone'=>'1008611',
+ 'desc'=>'',
+ 'culture'=>'',
+ 'uniacid'=>$uniacid,
+ ]);
+ }else{
+ setCache($key, $company_count ,7200 ,$uniacid);
+ }
+ //职位
+ $key1 = 'longbing_job'.$uniacid;
+ $job = new CardJob();
+ if($job->where('uniacid', '=', $uniacid)->count() == 0)
+ {
+ $res = $job->createRow([
+ 'name'=>'某某职位',
+ 'uniacid'=>$uniacid,
+ ]);
+ }
+ }
+}
+
+/**
+ * @Purpose: 获取文件后缀名
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+function longbingSingleGetImageExt ( $src = '' )
+{
+ $src = explode( '.', $src );
+ $count = count( $src );
+ if ( $count < 2 )
+ {
+ return false;
+ }
+ $ext = strtolower( $src[ $count - 1 ] );
+ if ( $ext == 'jpg' )
+ {
+ return 'jpg';
+ }
+ if ( $ext == 'png' )
+ {
+ return 'png';
+ }
+ if ( $ext == 'jpeg' )
+ {
+ return 'jpeg';
+ }
+ return false;
+}
+
+function longbingSingleGetImageExtWx ( $src = '' )
+{
+ $src = explode( '.', $src );
+ $count = count( $src );
+ if ( $count < 2 )
+ {
+ return false;
+ }
+ $ext = strtolower( $src[ $count - 1 ] );
+ if ( $ext == 'jpg' )
+ {
+ return 'jpg';
+ }
+ if ( $ext == 'png' )
+ {
+ return 'png';
+ }
+ if ( $ext == 'jpeg' )
+ {
+ return 'jpeg';
+ }
+ return 'jpg';
+}
+
+/**
+ * @Purpose: 将图片处理为圆形
+ *
+ * @Author: zzf
+ *
+ * @Return: mixed 查询返回值(结果集对象)
+ */
+function longbingSingleYuanImg ( $imgpath )
+{
+ //$ext = pathinfo( $imgpath );
+ //$src_img = null;
+
+ $wh = getimagesize( $imgpath );
+ $ext = $wh[ 'mime' ];
+
+ switch ( $ext)
+ {
+ case 'image/jpg' :
+ case 'image/jpeg' :
+ $src_img = imagecreatefromjpeg( $imgpath );
+ break;
+ case 'image/png':
+ $src_img = imagecreatefrompng( $imgpath );
+ break;
+ }
+
+ $w = $wh[ 0 ];
+ $h = $wh[ 1 ];
+ $w = min( $w, $h );
+ $h = $w;
+ $img = imagecreatetruecolor( $w, $h );
+ //这一句一定要有
+ imagesavealpha( $img, true );
+ //拾取一个完全透明的颜色,最后一个参数127为全透明
+ $bg = imagecolorallocatealpha( $img, 255, 255, 255, 127 );
+ imagefill( $img, 0, 0, $bg );
+ $r = $w / 2; //圆半径
+ $y_x = $r; //圆心X坐标
+ $y_y = $r; //圆心Y坐标
+ for ( $x = 0; $x < $w; $x++ )
+ {
+ for ( $y = 0; $y < $h; $y++ )
+ {
+ $rgbColor = imagecolorat( $src_img, $x, $y );
+ if ( ( ( ( $x - $r ) * ( $x - $r ) + ( $y - $r ) * ( $y - $r ) ) < ( $r * $r ) ) )
+ {
+ imagesetpixel( $img, $x, $y, $rgbColor );
+ }
+ }
+ }
+
+ return $img;
+}
+
+function longbingUpdateQrByAvatar($avatar ,$qrImage ,$uniacid ,$image_name)
+{
+
+ $img = longbingSingleYuanImg( $avatar );
+
+ $extAvatar = longbingSingleGetImageExtWx( $avatar );
+
+ $local = FILE_UPLOAD_PATH . 'images/test' . rand( 10000, 99999 ) . '.' . $extAvatar;
+// dump(1);exit;
+
+ imagepng( $img, $local );
+
+
+
+ $im = imagecreatetruecolor( 430, 430 );
+
+ //填充画布背景色
+ $color = imagecolorallocate( $im, 255, 255, 255 );
+ imagefill( $im, 0, 0, $color );
+
+ // 画背景二维码
+ $result = getimagesize( $qrImage );
+
+ $l_w1 = $result[ 0 ];
+ $l_h1 = $result[ 1 ];
+ $mime = $result[ 'mime' ];
+ if ( $mime == 'image/png' ) {
+ $qr = imagecreatefrompng( $qrImage );
+ }
+ else if ( $mime == 'image/jpeg' ) {
+ $qr = imagecreatefromjpeg( $qrImage );
+ }
+ else {
+
+ return false;
+ }
+
+ imagecopyresized( $im, $qr, 0, 0, 0, 0, 430, 430, $l_w1, $l_h1 );
+
+ // 画中间头像
+ $result = getimagesize( $local );
+ $l_w1 = $result[ 0 ];
+ $l_h1 = $result[ 1 ];
+ $mime = $result[ 'mime' ];
+ if ( $mime == 'image/png' ) {
+ $avatar = imagecreatefrompng( $local );
+ }
+ else if ( $mime == 'image/jpeg' ) {
+ $avatar = imagecreatefromjpeg( $local );
+ }
+ else {
+ die;
+ }
+ imagecopyresized( $im, $avatar, 120, 120, 0, 0, 190, 190, $l_w1, $l_h1 );
+ $localAvatarQr = realpath(FILE_UPLOAD_PATH . $image_name);
+ if(longbingHasLocalFile($image_name)) unlink($localAvatarQr);
+ // die;
+ $result = imagepng( $im, $localAvatarQr );
+ imagedestroy( $im );
+ @unlink( $local );
+ return $result;
+}
+
+
+//if (!function_exists('debugOneService') ){
+//function longbingDebugOneService ($data, $log_file = '') {
+// if (env('APP_DEBUG') != true) {
+// return;
+// }
+// $default_file = '/www/wwwroot/longbingtest.xiaochengxucms.com/xinlingshou_caoshi/addons/longbing_card/core2/runtime/article/log/201910/09.log';
+// if (!is_file($default_file)) {
+// return;
+// }
+// $filename = $log_file == '' ? $default_file : $log_file;
+// file_put_contents($filename, 'debug ====' . json_encode($data, JSON_UNESCAPED_UNICODE) . PHP_EOL, FILE_APPEND);
+//}
+//}
+
+if (!function_exists('lbIsStaff') ){
+
+ function lbIsStaff($id){
+ $data = Db::name('longbing_card_user_info')->where(['fans_id'=>$id,'is_staff'=>1])->field('id')->find();
+ return !empty($data)?1:0;
+ }
+}
+//获取当前小程序名片总数
+function longbingGetCardNum($uniacid ,$is_update = false)
+{
+// $key = 'longbing_card_card_num_' . $uniacid;
+//
+// //判断缓存是否存在
+// if(hasCache($key ,$uniacid) && empty($is_update)){
+// //获取缓存数据
+// $count = getCache($key ,$uniacid);
+// //判断缓存数据是否为空,否则返回
+// if(!empty($count)) return $count;
+// }
+ //获取用户数据
+ $staff_model = new LongbingUserInfo();//生成查询类
+ //获取数据
+ $count = $staff_model->getUserCount(['uniacid' => $uniacid ,'is_staff' => 1]);
+ //设置缓存
+// setCache ( $key, $count, 600, $uniacid);
+ //返回数据
+ return $count;
+}
+
+
+if (!function_exists('lbGetCopyrightInfo')) {
+ function lbGetCopyrightInfo ($copyright_id) {
+ $cardauth2_copyright = Db::name('longbing_cardauth2_copyright')->where('id', '=', $copyright_id)->find();
+ return $cardauth2_copyright ?? null;
+ }
+}
+
+
+function longbingGetBossNum($uniacid ,$is_update = false)
+{
+// $key = 'longbing_card_boss_num_' .$uniacid;
+// //判断缓存是否存在
+// if(hasCache($key ,$uniacid) && empty($is_update)){
+// //获取缓存数据
+// $count = getCache($key ,$uniacid);
+// //判断缓存数据是否为空,否则返回
+// if(!empty($count)) return $count;
+// }
+ //获取用户数据
+ $user_model = new LongbingUser();//生成查询类
+ //获取数据
+ $count = $user_model->getUserCount(['uniacid' => $uniacid ,'is_staff' => 1 ,'is_boss' => 1]);
+ //设置缓存
+// setCache ( $key, $count, 600, $uniacid);
+ //返回数据
+ return $count;
+}
+
+function longbingGetCompany($company_id ,$filter = [])
+{
+ $company_model = new CompanyModel();
+ $company = $company_model->getCompany(['id' => $company_id] ,$filter);
+ return $company;
+}
+
+function longbingGetUpCompanyIds($company_id)
+{
+ $result = [];
+ $company = longbingGetCompany(['id' => $company_id] ,['pid']);
+ if(!empty($company)) $result[] = $company_id;
+ if(!empty($company) && !empty($company['pid']))
+ {
+ $result[] = $company['pid'];
+ $pid = $company['pid'];
+ while(!empty($pid))
+ {
+ $company = longbingGetCompany(['id' => $pid] ,['pid']);
+ if(!empty($company) && !empty($company['pid']))
+ {
+ $result[] = $company['pid'];
+ $pid = $company['pid'];
+ }else{
+ $pid = 0;
+ }
+ }
+ }
+ if(!empty($result)) $result = array_reverse($result);
+ return $result;
+}
+
+/**
+ * 获取插件配置
+ */
+if (!function_exists('lbPulgSettingInfo')) {
+ function lbPulgSettingInfo($uniacid,$name,$key=[]){
+ $dis['uniacid']= $uniacid;
+ $dis['name'] = $name;
+ if(empty($key)){
+ $data = Db::name('longbing_card_plug_setting')->where($dis)->select();
+ }else{
+ foreach ($key as $value){
+ $dis['key'] = $value;
+ $singe = Db::name('longbing_card_plug_setting')->where($dis)->find();
+ if(empty($singe['key'])){
+ $singe = lbPulgSettingInsert($uniacid,$name,$value);
+ }
+ $data[] = $singe;
+ }
+ }
+ $arr = [];
+ if(!empty($data)){
+ foreach ($data as $k=>$v){
+ $v['value'] = !empty($v['value'])?json_decode($v['value'],true):$v['value'];
+ $arr[$v['key']] = $v['value'];
+ }
+ }
+ return $arr;
+ }
+}
+
+
+/**
+ * 插入插件配置
+ */
+if (!function_exists('lbPulgSettingInsert')) {
+ function lbPulgSettingInsert($uniacid,$name,$key){
+ $ins['uniacid'] = $uniacid;
+ $ins['name'] = $name;
+ $ins['key'] = $key;
+ $ins['value'] = 0;
+ $ins['create_time'] = time();
+ $ins['update_time'] = time();
+ $res = Db::name('longbing_card_plug_setting')->insert($ins);
+ $data= Db::name('longbing_card_plug_setting')->where(['uniacid'=>$uniacid,'name'=>$name,'key'=>$key])->find();
+ return $data;
+ }
+}
+
+
+/**
+ * 编辑插件配置
+ */
+if (!function_exists('lbPulgSettingUpdate')) {
+ function lbPulgSettingUpdate($uniacid,$name,$key,$vaule){
+ $res = Db::name('longbing_card_plug_setting')->where(['uniacid'=>$uniacid,'name'=>$name,'key'=>$key])->update(['value'=>json_encode($vaule),'update_time'=>time()]);
+ return $res;
+ }
+}
+
+
+
+//按顺序分配客服
+function lingbingGetAutoStaff($uniacid)
+{
+ $user_model = new LongbingUserInfo();//生成查询类
+ $staff = $user_model->getOneStaff($uniacid);
+ return $staff;
+}
+
+//通过账号获取员工信息
+function longbingGetStaff($account)
+{
+ if(empty($account)) return false;
+ //获取数据
+ $staff_model = new LongbingUserInfo();
+ $staff = $staff_model->getUser(['account' => $account ,'is_staff' => 1]);
+ return $staff;
+}
+
+//检查账号是否存在
+function longbingCheckStaffAccount($account)
+{
+ if(empty($account)) return false;
+ //获取数据
+ $staff_model = new LongbingUserInfo();
+ $count = $staff_model->getCount(['account' => $account]);
+ return !empty($count);
+}
+
+if (!function_exists('lbUserInfoAvatar')) {
+
+ function lbUserInfoAratar($uid){
+ $data = Db::name('longbing_card_user')->where(['id'=>$uid])->value('avatarUrl');
+ $data = !empty($data)?$data:'https://retail.xiaochengxucms.com/defaultAvatar.png';
+ return $data;
+ }
+
+}
+
+//默认员工头像
+if (!function_exists('lbUserAvatar')) {
+
+ function lbUserAvatar($uid){
+
+ $data = Db::name('longbing_card_user_info')->where(['fans_id'=>$uid])->value('avatar');
+
+ $data = !empty($data)?$data:Db::name('longbing_card_user')->where(['id'=>$uid])->value('avatarUrl');
+
+ $data = !empty($data)?$data:'https://retail.xiaochengxucms.com/defaultAvatar.png';
+
+ return $data;
+ }
+}
+
+//员工姓名
+if (!function_exists('lbUserName')) {
+
+ function lbUserName($uid){
+
+ $data = Db::name('longbing_card_user_info')->where(['fans_id'=>$uid])->value('name');
+
+ $data = !empty($data)?$data:Db::name('longbing_card_user')->where(['id'=>$uid])->value('nickName');
+
+ return $data;
+ }
+}
+//员工姓名
+if (!function_exists('lbUserCompany')) {
+
+ function lbUserCompany($uid){
+
+ $company_id = Db::name('longbing_card_user_info')->where(['fans_id'=>$uid])->value('company_id');
+
+ $top_id = Db::name('longbing_card_company')->where(['id'=>$company_id])->value('top_id');
+
+ $company_id = !empty($top_id)?$top_id:$company_id;
+
+ $data = Db::name('longbing_card_company')->where(['id'=>$company_id])->value('name');;
+
+ return $data;
+ }
+}
+
+
+
+//收集formId
+function longbingSaveFormId($data)
+{
+ $model = new CardFormId();
+ if(!is_array($data) || empty($data)) return ;
+ return $model->saveAll( $data );
+}
+
+function longbingchmodr($path) {
+
+ $filemode = 0777;
+ //判断文件夹是否存在
+ if (!is_dir($path)) return chmod($path, $filemode);
+ //获取文件夹下
+ $dh = opendir($path);
+
+ while (($file = readdir($dh)) !== false) {
+
+ if($file != '.' && $file != '..') {
+
+ $fullpath = $path.'/'.$file;
+
+ if(is_link($fullpath))
+ {
+ return FALSE;
+ }elseif(!is_dir($fullpath) && !chmod($fullpath, $filemode)){
+ return FALSE;
+ }elseif(!longbingchmodr($fullpath, $filemode))
+ {
+ return FALSE;
+ }
+ }
+ }
+ closedir($dh);
+
+ if(chmod($path, $filemode))
+ {
+ return TRUE;
+ }else{
+ return FALSE;
+ }
+}
+
+/**
+ * 功能说明
+ *
+ * @param $infoName
+ * @param string $type
+ * @param int $uniacid 大于0时,需要做权限过滤
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/26 15:29
+ */
+function longbing_init_info_data($infoName , $type = '' , $uniacid = 0 ){
+
+ $myModelList = \config('app.AdminModelList');
+
+ $myModelList = $myModelList['saas_auth_admin_model_list'];
+
+ $returnMenuData = [];
+ //获取模权限
+ $denyAdminMenuKeys = AdminMenu::getAuthList(intval($uniacid));
+ //加载所有配置内容
+ foreach ($myModelList as $model_name => $model_item ) {
+ //过滤权限
+ if(!empty($uniacid) && !array_key_exists($model_name, $denyAdminMenuKeys)){
+ continue ;
+ }
+ //需要判断文件是否存在
+ $dataPath = APP_PATH . $model_name . '/info/' . $infoName . '.php' ;
+
+ if(file_exists($dataPath)){
+
+ $admin_menu = include $dataPath ;
+ //空数据不放入
+ if ($admin_menu != []) {
+
+ if (in_array($infoName,['DiyMenu','DiyCompoents','DiyLink', 'DiyTabbar','RadarMessage','FunctionPage'])) { //小程序底部菜单,需要合并数组
+
+ foreach ($admin_menu as $diyMenu){
+
+ array_push($returnMenuData,$diyMenu);
+
+ }
+
+ }else if(in_array($infoName,['Info'])){
+
+ if(!empty($type) && array_key_exists('type' , $admin_menu) && $type == $admin_menu['type'] ){
+
+ array_push($returnMenuData ,$admin_menu);
+ }
+
+ } else if(in_array($infoName,['AdminMenu'])){ //AdminMenu获取指定数据
+
+
+ //导入info信息查看
+ $infoDataPath = APP_PATH . $model_name . '/info/Info.php' ;
+
+ $infoData = include $infoDataPath ;
+
+ if(!empty($type) && array_key_exists('type' , $infoData) && $type == $infoData['type'] ){
+
+ $returnMenuData[key($admin_menu)] = $admin_menu[key($admin_menu)];
+ }
+
+ }elseif(in_array($infoName,['DiyDefaultCompoents'])){
+
+ $returnMenuData[] = $admin_menu;
+
+ }else{
+
+ $returnMenuData[key($admin_menu)] = $admin_menu[key($admin_menu)];
+ }
+
+ }
+
+ }
+
+ }
+
+ return $returnMenuData;
+}
+
+
+/**
+ * @author chenniang
+ * @DataTime: 2020-06-28 11:37
+ * @功能说明:获取有权限的组建
+ */
+function getAuthCompoentsData($returnCompoentsData,$uniacid){
+
+ $data = [];
+
+ if(!empty($returnCompoentsData)){
+
+ $denyAdminMenuKeys = AdminMenu::getAuthList(intval($uniacid));
+
+
+
+ foreach ($returnCompoentsData as $k=>$v){
+
+ $new_data = [];
+
+ if(!empty($v['data'])){
+
+ foreach ($v['data'] as $vs){
+
+ if(isset($vs['re_name_key'])){
+
+ $intersect = array_intersect($vs['re_name_key'],array_keys($denyAdminMenuKeys));
+
+ }
+
+ if(!empty($intersect)||!isset($vs['model_name_key'])||(isset($vs['model_name_key'])&&array_key_exists($vs['model_name_key'],$denyAdminMenuKeys))){
+
+ $new_data[] = $vs;
+ }
+ }
+ }
+
+ $v['data'] = $new_data;
+
+ if(!empty($new_data)){
+
+ $data[$k] = $v;
+ }
+ }
+ }
+
+ return array_values($data);
+
+}
+
+/**
+ * @author chenniang
+ * @DataTime: 2020-06-11 14:27
+ * @功能说明:默认页面
+ */
+function longbing_default_Page($key){
+
+ $DiyCompoentsData = longbing_init_info_data('DiyDefaultCompoents');
+
+ $data =[];
+
+ foreach ($DiyCompoentsData as $v){
+
+ if($v['key']==$key){
+
+ $data = $v;
+ break;
+ }
+ }
+
+ return $data;
+}
+
+
+/**
+ * @author yangqi
+ * @time 2019年11月28日00:15:10
+ * 加载雷达信息
+ */
+function longbingInitRadarMessage() {
+ //雷达模块数据
+ $config_path = APP_PATH . 'RadarInfo.php';
+ //判断文件是否存在
+ if(!file_exists($config_path)) return [];
+ //获取模块数据
+ $model_list = include_once($config_path);
+ $result = [];
+ if(!is_array($model_list)) return $result;
+ foreach($model_list as $value){
+ $data_path = APP_PATH . $value . '/info/RadarMessage.php';
+ if(file_exists($data_path)){
+ $val = require $data_path;
+ if(!empty($val) && is_array($val)){
+ $result = array_merge($result ,$val);
+ }
+ }
+ }
+ return $result;
+}
+
+/**
+ * @author yangqi
+ * 2019年11月29日11:43:26
+ * 多维数据拆分成一维数组
+ */
+
+function longbingGetArrToOne($arr)
+{
+ $result = array();
+ foreach ($arr as $key => $val) {
+ if( is_array($val) ) {
+ $result = array_merge($result, longbingGetArrToOne($val));
+ } else {
+ $result[$key] = $val;
+ }
+ }
+ return $result;
+}
+
+/**
+ * @author yangqi
+ * @time 2019年11月28日00:15:10
+ * 加载雷达信息
+ */
+function longbingGetPersionalCenterMenu($uniacid) {
+ //雷达模块数据
+ $config_path = APP_PATH . 'PersonalCenterConfig.php';
+ //判断文件是否存在
+ if(!file_exists($config_path)) return [];
+ //获取模块数据
+ $model_list = include_once($config_path);
+ $result = [];
+ if(!is_array($model_list)) return $result;
+ //权限验证(获取权限)
+ $pluginAuth = longbingGetPluginAuth($uniacid);
+ $auth = $pluginAuth['web_manage_meta_config'];
+
+ //数据处理
+ foreach($model_list as $key=>$value){
+ //是否导入
+ $is_load = false;
+ //判断是否是默认
+ if(isset($value['is_default']) && !empty($value['is_default'])) $is_load = true;
+ //权限判断
+ if(empty($is_load) && isset($auth[$key]) && !empty($auth[$key])) $is_load = true;
+ if($is_load){
+ $data_path = APP_PATH . $key . '/info/PersonalCenterMenu.php';
+ if(file_exists($data_path)){
+ $val = require $data_path;
+// var_dump($val);die;
+ if(!empty($val) && is_array($val)){
+ $result = array_merge($result ,$val);
+ }
+ }
+ }
+ }
+ return $result;
+}
+
+/**
+ * @author yangqi
+ * @time 2019年11月28日00:15:10
+ * 加载雷达信息
+ */
+function longbingGetStaffCenterMenu($uniacid) {
+ //雷达模块数据
+ $config_path = APP_PATH . 'StaffCenterConfig.php';
+ //判断文件是否存在
+ if(!file_exists($config_path)) return [];
+ //获取模块数据
+ $model_list = include_once($config_path);
+ $result = [];
+ if(!is_array($model_list)) return $result;
+ //权限验证(获取权限)
+ $pluginAuth = longbingGetPluginAuth($uniacid);
+ $auth = $pluginAuth['web_manage_meta_config'];
+
+ foreach($model_list as $key=>$value){
+ //是否导入
+ $is_load = false;
+ //判断是否是默认
+ if(isset($value['is_default']) && !empty($value['is_default'])) $is_load = true;
+ //权限判断
+ if(empty($is_load) && isset($auth[$key]) && !empty($auth[$key])) $is_load = true;
+ if($is_load){
+ $data_path = APP_PATH . $key . '/info/StaffCenterMenu.php';
+ if(file_exists($data_path)){
+ $val = require $data_path;
+ if(!empty($val) && is_array($val)){
+ $result = array_merge($result ,$val);
+ }
+ }
+ }
+ }
+ return $result;
+}
+
+/**
+ * @author yangqi
+ * @time 2019年11月28日00:15:10
+ * 加载雷达信息
+ */
+function longbingGetWorkCenterMenu($uniacid) {
+ //雷达模块数据
+ $config_path = APP_PATH . 'WorkCenterConfig.php';
+ //判断文件是否存在
+ if(!file_exists($config_path)) return [];
+ //获取模块数据
+ $model_list = include_once($config_path);
+ $result = [];
+ if(!is_array($model_list)) return $result;
+ //权限验证(获取权限)
+ $pluginAuth = longbingGetPluginAuth($uniacid);
+ $auth = $pluginAuth['web_manage_meta_config'];
+ foreach($model_list as $key=>$value){
+ //是否导入
+ $is_load = false;
+ //判断是否是默认
+ if(isset($value['is_default']) && !empty($value['is_default'])) $is_load = true;
+ //权限判断
+ if(empty($is_load) && isset($auth[$key]) && !empty($auth[$key])) $is_load = true;
+ //是否载入
+ if($is_load){
+ $data_path = APP_PATH . $key . '/info/WorkCenterMenu.php';
+ if(file_exists($data_path)){
+ $val = require $data_path;
+ if(!empty($val) && is_array($val)){
+ $result = array_merge($result ,$val);
+ }
+ }
+ }
+ }
+ return $result;
+}
+
+/**
+ * @author yangqi
+ * @time 2019年11月29日15:04:05
+ * 加载tabbar
+ */
+
+function longbingGetTabbarMenu()
+{
+ $myModelList = \config('app.AdminModelList');
+ $myModelList = array_merge($myModelList['saas_auth_admin_model_list'] ,$myModelList['saas_auth_app_list']);
+ $result = [];
+ foreach($myModelList as $key=>$val)
+ {
+ $result[] = $key;
+ }
+ return $result;
+}
+
+/**
+ * By.jingshuixian
+ * 2019年11月24日19:37:43
+ * 获取缓存key
+ */
+function longbing_get_cache_key($key , $uniacid){
+ //longbing_端口_key_7777
+ //龙兵科技前缀_区分端口_key_平台ID
+ return 'longbing_' . $key . '_' . $uniacid;
+}
+
+/**
+ * By.jingshuixian
+ * 2019年11月24日19:46:35
+ * 自动缓存方法,具体实现打算使用闭包方式
+ */
+function longbing_auto_cahe(){
+
+ //自动获取模块/查件名称、类名称、方法名称、来组合缓存key
+
+
+}
+
+/**
+ * By.jingshuixian
+ * 2019年11月26日13:57:16
+ * 执行异步的方法
+ * @param $url
+ * @param array $param
+ */
+if (!function_exists('getRangeMem')) {
+
+
+ function longbing_do_request($url, $param = array())
+ {
+
+// try {
+ $urlinfo = parse_url($url);
+
+ $host = $urlinfo['host'];
+
+ $query_url = $urlinfo['query'];
+
+ //By.jingshuixian 2019年12月4日00:19:11
+ // 当前请求的内容里有get 参数时 , 拼接 path
+ if (!empty($query_url)) {
+ $path = $urlinfo['path'] . '?' . $query_url;
+ }
+// dump($path,$host);exit;
+ $query = isset($param) ? http_build_query($param) : '';
+ if (empty($host)) return false;
+
+ $port = !empty($urlinfo['scheme']) && $urlinfo['scheme'] == 'https' ? 443 : 80;//判断https 还是 http
+ $errno = 0;
+ $errstr = '';
+ $timeout = 50;
+ $c_houst = !empty($urlinfo['scheme']) && $urlinfo['scheme'] == 'https' ? 'ssl://' . $host : $host;//判断https 还是 http
+
+ $fp = fsockopen($c_houst, $port, $errno, $errstr, $timeout);
+
+
+ $out = "POST " . $path . " HTTP/1.1\r\n";
+ $out .= "host:" . $host . "\r\n";
+ $out .= "content-length:" . strlen($query) . "\r\n";
+ $out .= "content-type:application/x-www-form-urlencoded\r\n";
+ $out .= "connection:close\r\n\r\n";
+ $out .= $query;
+
+
+ fputs($fp, $out);
+ $resp_str = '';
+ while (!feof($fp)) {
+ $resp_str .= fgets($fp, 512);//返回值放入$resp_str
+ }
+ fclose($fp);
+
+ //By.jingshuixian 增加内容返回值
+ return [$resp_str, $out];
+//
+// } catch (\Exception $e) {
+//
+// }
+
+ }
+}
+/**
+ * 记录区间的内存使用情况
+ * @param string $start 开始标签
+ * @param string $end 结束标签
+ * @param integer|string $dec 小数位
+ * @return string
+ */
+if (!function_exists('getRangeMem')) {
+ function getRangeMem($start, $end = null, $dec = 2)
+ {
+ if (!isset($end)) {
+ $end = memory_get_usage();
+ }
+ $size = $end - $start;
+ $a = ['B', 'KB', 'MB', 'GB', 'TB'];
+ $pos = 0;
+ while ($size >= 1024) {
+ $size /= 1024;
+ $pos++;
+ }
+ return round($size, $dec) . " " . $a[$pos];
+ }
+}
+
+
+/**
+ * 统计某个区间的时间(微秒)使用情况 返回值以秒为单位
+ * @param string $start 开始标签
+ * @param string $end 结束标签
+ * @param integer|string $dec 小数位
+ * @return integer
+ */
+if (!function_exists('getRangeTime')) {
+ function getRangeTime($start, $end = null, $dec = 6)
+ {
+ if (!isset($end)) {
+ $end = microtime(true);
+ }
+ return number_format(($end - $start), $dec);
+ }
+}
+
+
+
+if (!function_exists('longbing_init_info_subscribe')) {
+ /**
+ * 自动加载监听事件
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/12 9:47
+ */
+ function longbing_init_info_subscribe()
+ {
+ $myModelList = \config('app.AdminModelList');
+
+ $saas_auth_admin_model_list = $myModelList['saas_auth_admin_model_list'] ;
+
+
+ $returnMenuData = [];
+ foreach ($saas_auth_admin_model_list as $model_name => $model_item) {
+
+
+ //需要判断文件是否存在
+ $dataPath = app_path() . $model_name . '/info/Subscribe.php';
+ if (file_exists($dataPath)) {
+ $returnMenuData[] = 'app\\' . $model_name . '\\info\\Subscribe';
+ }
+ }
+ return $returnMenuData;
+ }
+}
+
+
+if (!function_exists('longbing_array_columns')) {
+ /**
+ * 取出数组里的一列或者多列
+ *
+ * @param $arr
+ * @param $keys
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/16 10:39
+ */
+ function longbing_array_columns($arr, $keys)
+ {
+ $returnArray = [] ;
+ foreach ($arr as $v) {
+ foreach ($keys as $k) {
+ if(array_key_exists($k,$v)){
+ $n[$k] = $v[$k];
+ }
+ }
+ $returnArray[] = $n;
+ }
+ return $returnArray;
+ }
+}
+
+if (!function_exists('longbing_get_auth_prefix')) {
+ /**
+ * 获得SAAS授权的参数前缀内容 , 需要不要分行业授权,需要根据实际需求确定
+ *
+ * @return string
+ * @author shuixian
+ * @DataTime: 2019/12/19 16:31
+ */
+ function longbing_get_auth_prefix($authName)
+ {
+ //统一添加参数前缀
+
+ $prefix = strtoupper(APP_MODEL_NAME);
+ $prefix = (($prefix == 'LONGBING_CARD') ? 'LONGBING_' : $prefix . '_');
+ return $prefix . $authName;
+ }
+}
+
+if (!function_exists('longbing_dd')) {
+
+ /**
+ * 打印调试信息
+ * @access public
+ * @param mixed $message 日志信息
+ * @param array $context 替换内容
+ * @return void
+ * @author shuixian
+ * @DataTime: 2019/12/23 16:31
+ */
+ function longbing_dd($message, array $context = [])
+ {
+ if(Env::get('APP_DEBUG', false) ){
+ Log::debug($message, $context);
+ }
+
+ }
+}
+
+
+if (!function_exists('longbing_compare_version')) {
+ /**
+ * 功能说明
+ *
+ * @param $oldVersion 老版本号
+ * @param $newVersion 新版本号
+ * @return bool 是否升级,新版本号大于老版本号,就升级
+ * @author shuixian
+ * @DataTime: 2019/12/17 10:16
+ */
+ function longbing_compare_version($oldVersion, $newVersion)
+ {
+ $isNew = false;
+ $oldVersion = explode('.', $oldVersion);
+ $newVersion = explode('.', $newVersion);
+ foreach ($newVersion as $key => $value) {
+
+ if (intval($value) > intval($oldVersion[$key])) {
+ $isNew = true;
+ break;
+ }
+
+ }
+
+ return $isNew;
+ }
+}
+
+if (!function_exists('longbing_tablename')) {
+ /**
+ * 根据当前表名获取完整的前缀+表名
+ *
+ * @param $tablename
+ * @return string
+ * @author shuixian
+ * @DataTime: 2019/12/17 11:01
+ */
+ function longbing_tablename($tablename)
+ {
+ $prefix = config('database.connections.mysql.prefix');
+ return $prefix . $tablename;
+ }
+}
+if (!function_exists('longbing_get_prefix')) {
+ /**
+ * 获得数据库表前缀
+ *
+ * @return mixed
+ * @author shuixian
+ * @DataTime: 2019/12/17 13:44
+ */
+ function longbing_get_prefix()
+ {
+ $prefix = config('database.connections.mysql.prefix');
+ return $prefix;
+ }
+}
+if (!function_exists('longbing_get_table_prefix')) {
+ /**
+ * 获得数据库表前缀(感觉名字比较易懂一点)
+ *
+ * @return mixed
+ * @author shuixian
+ * @DataTime: 2019/12/17 13:44
+ */
+ function longbing_get_table_prefix()
+ {
+ $prefix = config('database.connections.mysql.prefix');
+ return $prefix;
+ }
+}
+
+if (!function_exists('longbing_check_install')) {
+ /**
+ * 检查是否安装,没有安装就自动安装
+ *
+ * @author shuixian
+ * @DataTime: 2020/1/2 18:34
+ */
+ function longbing_check_install()
+ {
+ $lockPath = APP_PATH . 'install/controller/install.lock';
+ if (!file_exists($lockPath)) {
+ \app\admin\service\UpdateService::installSql(8888);
+ file_put_contents($lockPath, time());
+ }
+ }
+}
+if (!function_exists('longbing_get_app_type')) {
+ /**
+ * 获取app类型
+ *
+ * @return string
+ * @author shuixian
+ * @DataTime: 2020/1/3 15:43
+ */
+ function longbing_get_app_type()
+ {
+ $type = '';
+ $agent = Request::header('user-agent');
+ if (strpos($agent, 'baiduboxapp')) {
+ $type = 'baiduboxapp';
+ }
+ return $type;
+ }
+}
+if (!function_exists('longbing_get_mobile_type')) {
+ /**
+ * 获取app类型
+ *
+ * @return string
+ * @author shuixian
+ * @DataTime: 2020/1/3 15:43
+ */
+ function longbing_get_mobile_type()
+ {
+ $type = '';
+ $agent = Request::header('user-agent');
+ if (strpos($agent, 'Android')) {
+ $type = 'Android';
+ }elseif (strpos($agent, 'iPhone')) {
+ $type = 'iPhone';
+ }
+ return $type;
+ }
+}
+
+if (!function_exists('longbing_filterEmoji')) {
+ /**
+ * @param $str
+ * @return string|string[]|null
+ * 过滤表情包
+ */
+ function longbing_filterEmoji($str)
+ {
+ $str = preg_replace_callback(
+ '/./u',
+ function (array $match) {
+ return strlen($match[0]) >= 4 ? '' : $match[0];
+ },
+ $str);
+
+ return $str;
+ }
+}
+
+if(!function_exists('longbing_auth_status')){
+ /**
+ **@author lichuanming
+ * @DataTime: 2020/5/15 10:35
+ * @功能说明: 账户状态
+ */
+ function longbing_auth_status($uniacid){
+ $resData = [
+ 'name' => '', #套餐名称
+ 'time' => '', #到期时间
+ 'status' => 0, #状态 0未过期 1即将到期 2已到期
+ ];
+
+ //如果是微擎 则不判断是否到期
+ if(!longbingIsWeiqin()){
+ $info = Db::name('longbing_cardauth2_config')->where('modular_id','=',$uniacid)
+ ->field('end_time,mini_name')->find(); #获取过期时间
+
+ $end_time = $info['end_time'];
+
+ if($end_time <= time()){ //已过期
+ list($resData['name'],$resData['time'],$resData['status']) = array($info['mini_name'],date('Y-m-d',$end_time),2);
+
+ }else if($end_time < time() + 30*86400 && $end_time > time()){ #即将过期/30天
+
+ list($resData['name'],$resData['time'],$resData['status']) = array($info['mini_name'],date('Y-m-d',$end_time),1);
+ }
+ }
+ return $resData;
+ }
+}
+
+
+//随机生成偏移量
+function createOffset() {
+ return substr(uuid() ,8,10);
+}
+
+//生成密码
+function createPasswd($passwd ,$offset) {
+ return password_hash($offset.$passwd.$offset ,PASSWORD_DEFAULT);
+}
+
+//多维数组排序
+if(!function_exists('arraySort')){
+
+ function arraySort($array,$keys,$sort='asc'){
+
+ $newArr = $valArr = array();
+
+ foreach ($array as $key=>$value) {
+
+ $valArr[$key] = $value[$keys];
+ }
+ ($sort == 'asc') ? asort($valArr) : arsort($valArr);
+ reset($valArr);
+
+ foreach($valArr as $key=>$value) {
+ $newArr[$key] = $array[$key];
+ }
+
+ return array_values($newArr);
+ }
+}
+
+/**
+ * 转星期
+ */
+if(!function_exists('changeWeek')){
+
+
+ function changeWeek($week){
+
+ switch ($week){
+ case 1:
+ return '周一';
+ break;
+ case 2:
+ return '周二';
+ break;
+ case 3:
+ return '周三';
+ break;
+ case 4:
+ return '周四';
+ break;
+ case 5:
+ return '周五';
+ break;
+ case 6:
+ return '周六';
+ break;
+ case 0:
+ return '周天';
+ break;
+ }
+ }
+}
+
+if(!function_exists('orderCode')){
+
+ function orderCode(){
+
+ $i = rand(1,999);
+
+ $out_trade_no = date( 'YmdHis' ) . '0' . $i. '0';
+
+ $idlen = strlen($i);
+
+ $out_trade_no = $out_trade_no . str_repeat( '0', 7 - $idlen ) . $i;
+
+ return $out_trade_no;
+ }
+}
+
+if(!function_exists('short_orderCode')){
+
+ function short_orderCode(){
+
+ $i = rand(1,999);
+
+ $out_trade_no = date( 'mdHis' ). $i;
+
+ return $out_trade_no;
+ }
+}
+
+if(!function_exists('orderRefundApi')){
+
+ function orderRefundApi($paymentApp,$total_fee,$refund_fee,$order_code){
+
+ $setting['mini_appid'] = $paymentApp['app_id'];
+
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+
+ if(!is_file($setting['apiclient_cert'])||!is_file($setting['apiclient_cert_key'])){
+
+ return ['return_msg'=>'未配置支付证书,或支付证书错误请重新上传','code'=>500];
+
+ }
+ defined('WX_APPID') or define('WX_APPID', $setting['mini_appid']);
+
+ defined('WX_MCHID') or define('WX_MCHID', $setting['mini_mid']);
+
+ defined('WX_KEY') or define('WX_KEY', $setting['mini_apicode']);
+
+ defined('WX_APPSECRET') or define('WX_APPSECRET', $setting['mini_appsecrept']);
+
+ defined('WX_SSLCERT_PATH') or define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+
+ defined('WX_SSLKEY_PATH') or define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+
+ defined('WX_CURL_PROXY_HOST') or define('WX_CURL_PROXY_HOST', '0.0.0.0');
+
+ defined('WX_CURL_PROXY_PORT') or define('WX_CURL_PROXY_PORT', 0);
+
+ defined('WX_REPORT_LEVENL') or define('WX_REPORT_LEVENL', 0);
+
+ require_once PAY_PATH . "/weixinpay/lib/WxPay.Api.php";
+
+ require_once PAY_PATH . "/weixinpay/example/WxPay.JsApiPay.php";
+
+ $input = new \WxPayRefund();
+
+ $input->SetTotal_fee($total_fee*100);
+
+ $input->SetRefund_fee($refund_fee*100);
+
+ $input->SetOut_refund_no(WX_MCHID.date("YmdHis"));
+
+ $input->SetTransaction_id($order_code);
+
+ $input->SetOp_user_id(WX_MCHID);
+
+ $order = \WxPayApi::refund($input);
+
+ return $order;
+
+ }
+}
+
+
+
+if(!function_exists('getdistance')){
+
+/**
+ * User: chenniang
+ * Date: 2019-10-18 16:00
+ * @param $lng1
+ * @param $lat1
+ * @param $lng2
+ * @param $lat2
+ * @return float|int
+ * descption:获取距离
+ */
+ function getdistance($lng1, $lat1, $lng2, $lat2) {
+ $radLat1 = deg2rad($lat1); //deg2rad()函数将角度转换为弧度
+ $radLat2 = deg2rad($lat2);
+ $radLng1 = deg2rad($lng1);
+ $radLng2 = deg2rad($lng2);
+ $a = $radLat1 - $radLat2;
+ $b = $radLng1 - $radLng2;
+
+ $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))) * 6378.137 * 1000;
+ return $s;
+
+
+ }
+}
+if(!function_exists('getDistances')){
+
+function getDistances($longitude1, $latitude1, $longitude2, $latitude2, $unit=2, $decimal=2){
+
+ $EARTH_RADIUS = 6370.996; // 地球半径系数
+ $PI = 3.1415926;
+
+ $radLat1 = $latitude1 * $PI / 180.0;
+ $radLat2 = $latitude2 * $PI / 180.0;
+
+ $radLng1 = $longitude1 * $PI / 180.0;
+ $radLng2 = $longitude2 * $PI /180.0;
+
+ $a = $radLat1 - $radLat2;
+ $b = $radLng1 - $radLng2;
+
+ $distance = 2 * asin(sqrt(pow(sin($a/2),2) + cos($radLat1) * cos($radLat2) * pow(sin($b/2),2)));
+ $distance = $distance * $EARTH_RADIUS * 1000;
+
+// if($unit==2){
+// $distance = $distance / 1000;
+// }
+
+ return $distance;
+
+}
+}
+
+
+if(!function_exists('checkPass')){
+
+ function checkPass ($pass){
+
+ return md5('shequ'.$pass);
+
+ }
+
+
+}
+
+
+if(!function_exists('initLogin')){
+
+ function initLogin ($uniacid = 1){
+
+ $admin_model = new \app\farm\model\Admin();
+
+ $admin = $admin_model->dataInfo(['uniacid'=>$uniacid]);
+
+ if(empty($admin)){
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'username'=> 'admin',
+
+ 'passwd' => checkPass('admin123'),
+
+ 'create_time' => time()
+ ];
+
+ $admin_model->dataAdd($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+}
+
+if(!function_exists('setUserForToken')){
+ function setUserForToken($token ,$user) {
+ return setCache("Token_" . $token ,$user ,72000);
+ }
+}
+
+
+
+if(!function_exists('is_time_cross')){
+
+ /**
+ * PHP计算两个时间段是否有交集(边界重叠不算)
+ *
+ * @param string $beginTime1 开始时间1
+ * @param string $endTime1 结束时间1
+ * @param string $beginTime2 开始时间2
+ * @param string $endTime2 结束时间2
+ * @return bool
+ */
+ function is_time_cross($beginTime1 = '', $endTime1 = '', $beginTime2 = '', $endTime2 = '') {
+
+ $status = $beginTime2 - $beginTime1;
+
+ if ($status > 0) {
+
+ $status2 = $beginTime2 - $endTime1;
+
+ if ($status2 >= 0) {
+
+ return true;
+
+ } else {
+
+ return false;
+ }
+ } else {
+
+ $status2 = $endTime2 - $beginTime1;
+
+ if ($status2 > 0) {
+
+ return false;
+
+ } else {
+
+ return true;
+ }
+
+ }
+
+ }
+}
+
+
+if(!function_exists('distance_text')){
+
+ /**
+ * PHP计算两个时间段是否有交集(边界重叠不算)
+ *
+ * @param string $beginTime1 开始时间1
+ * @param string $endTime1 结束时间1
+ * @param string $beginTime2 开始时间2
+ * @param string $endTime2 结束时间2
+ * @return bool
+ */
+ function distance_text($distance) {
+
+ if($distance>1000){
+
+ $distance = round($distance/1000,2);
+
+ $text = $distance.'km';
+ }else{
+
+ $text = round($distance,2).'m';
+
+ }
+
+ return $text;
+
+ }
+
+}
+
+if(!function_exists('syn_status')){
+
+ /**
+ * PHP计算两个时间段是否有交集(边界重叠不算)
+ *
+ * @param string $beginTime1 开始时间1
+ * @param string $endTime1 结束时间1
+ * @param string $beginTime2 开始时间2
+ * @param string $endTime2 结束时间2
+ * @return bool
+ */
+ function syn_status() {
+
+ return 0;
+
+ }
+
+}
+
+if(!function_exists('point_success')){
+
+ /**
+ * PHP计算两个时间段是否有交集(边界重叠不算)
+ *
+ * @param string $beginTime1 开始时间1
+ * @param string $endTime1 结束时间1
+ * @param string $beginTime2 开始时间2
+ * @param string $endTime2 结束时间2
+ * @return bool
+ */
+ function point_success($uniacid) {
+
+ $shop_model = new \app\shop\model\Order();
+
+ $restaurant_model = new \app\restaurant\model\Order();
+
+ $car_record_model = new \app\massage\model\CarAtvRecord();
+
+ $car_record_model->pointSuccess($uniacid);
+
+ $shop_model->capArrPrice($uniacid);
+
+ $restaurant_model->capArrPrice($uniacid);
+
+ return true;
+
+ }
+
+}
+
+
+if(!function_exists('autoCancelOrder')){
+
+ /**
+ * @param $uniacid
+ * @param int $user_id
+ * @功能说明:超时取消订单
+ * @author chenniang
+ * @DataTime: 2022-01-06 17:58
+ */
+ function autoCancelOrder($uniacid,$user_id=0) {
+
+ $cancel_model = new \app\farm\server\CancelOrder();
+
+ $land_order = new \app\farm\model\LandOrder();
+
+ $claim_order = new \app\farm\model\ClaimOrder();
+
+ $send_order = new \app\farm\model\SendOrder();
+
+ $shop_order = new \app\farm\model\ShopOrder();
+
+ $cancel_model->addObserver($land_order);
+
+ $cancel_model->addObserver($claim_order);
+
+ $cancel_model->addObserver($send_order);
+
+ $cancel_model->addObserver($shop_order);
+
+ $cancel_model->notify($uniacid,$user_id);
+
+ return true;
+
+ }
+
+}
+
+if(!function_exists('game_time')){
+
+ /**
+ * @param $time
+ * @功能说明:比赛时间格式转化(精确到毫秒)
+ * @author chenniang
+ * @DataTime: 2021-09-28 11:54
+ */
+ function game_time($time) {
+ //分
+
+ if(empty($time)){
+
+ return 0;
+ }
+
+
+ if($time>=60*1000){
+
+ $i = intval($time/(60*1000));
+
+ $time -= $i*(60*1000);
+
+ $i = $i.'′';
+
+ }else{
+
+ $i = '';
+ }
+ //秒
+ if($time>1000){
+
+ $s = intval($time/(1000));
+
+ $time -= $s*(1000);
+
+ }else{
+
+ $s = '00';
+
+ }
+
+ if($time>10){
+
+ $w = intval($time/10);
+
+ }else{
+
+ $w = '00';
+ }
+
+
+ return $i.$s.'″'.$w;
+
+ }
+
+}
+
+
+if(!function_exists('landNotice')){
+
+ /**
+ * @param $time
+ * @功能说明:土地订单到期通知
+ * @author chenniang
+ * @DataTime: 2022-03-17 10:21
+ */
+ function landNotice($uniacid) {
+
+ $model = new \app\farm\model\LandOrder();
+ //土地到期
+ $model->landOverService($uniacid);
+
+ $claim_model = new \app\farm\model\ClaimOrder();
+ //认养
+ $claim_model->claimSendNotice($uniacid);
+
+ $kill_model = new \app\shop\model\SeckillInfo();
+ //秒杀提醒
+ $kill_model->sendMsg($uniacid);
+
+ $signin_model = new \app\shop\model\SigninRecord();
+
+ $signin_model->sendMsg($uniacid);
+
+ return true;
+
+ }
+
+}
+
+if(!function_exists('randKey')){
+
+ function randKey($length,$type=1)
+ {
+
+ $key = '';
+
+ if($type==1){
+
+ $pattern = 'abcdefghijklmnopqrstuvwxyz';
+
+ }else{
+
+ $pattern = '123456789012345678901234567890';
+ }
+
+ for($i=0;$i<$length;$i++)
+ {
+ $key .= $pattern{mt_rand(0,25)}; //生成php随机数
+ }
+ return $key;
+ }
+
+
+}
+
+if(!function_exists('getCardCode')){
+
+ function getCardCode()
+ {
+
+ $user_model = new \app\farm\model\User();
+
+ $code = randKey(7);
+
+ $find = $user_model->dataInfo(['fx_code'=>$code]);
+
+ if(!empty($find)){
+
+ getCardCode();
+ }
+
+ return $code;
+ }
+
+}
+if(!function_exists('object_array')) {
+
+ function object_array($array)
+ {
+ if (is_object($array)) {
+ $array = (array)$array;
+ }
+ if (is_array($array)) {
+ foreach ($array as $key => $value) {
+ $array[$key] = object_array($value);
+ }
+ }
+ return $array;
+ }
+}
+
+
+if(!function_exists('getCode')){
+
+ function getCode($uniacid,$data,$type=1,$page='pages/home'){
+
+ if($type==1){
+
+ $model = new WxSetting($uniacid);
+
+ $data = $model->phpQrCode($data);
+
+ }else{
+ //小程序码
+ $data = longbingCreateWxCode($uniacid,$data,$page,1);
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+ $data = $data['qr_path'];
+
+ }
+
+ return $data;
+
+ }
+
+}
+
+if(!function_exists('infoFriendTime')){
+
+
+ function infoFriendTime($time){
+
+ $time = strtotime(date('Y-m-d',$time));
+
+ $now = strtotime(date('Y-m-d',time()));
+
+ $day = $now-$time;
+
+ $i = ceil($day/86400);
+
+ if($i==0){
+
+ $text = '今天';
+
+ }elseif($i==1){
+
+ $text = '昨天';
+
+ }elseif($i==2){
+
+ $text = '前天';
+
+ }elseif ($i<7){
+
+ $text = changeWeek(date('w',$time));
+
+ }else{
+
+ $text = date('Y-m-d',$time);
+
+ }
+
+ return $text;
+ }
+
+
+
+}
+
+
+
+
+
+
+
diff --git a/app/event.php b/app/event.php
new file mode 100755
index 0000000..292b7d6
--- /dev/null
+++ b/app/event.php
@@ -0,0 +1,25 @@
+
+// +----------------------------------------------------------------------
+
+// 事件定义文件
+return [
+ 'bind' => [],
+
+ 'listen' => [
+ 'AppInit' => ['app\Common\listener\AppInit'],
+ 'HttpRun' => [],
+ 'HttpEnd' => ['app\Common\listener\HttpEndLog'],
+ 'LogLevel' => [],
+ 'LogWrite' => [],
+ ],
+
+ 'subscribe' => longbing_init_info_subscribe(),
+];
diff --git a/app/farm/controller/Admin.php b/app/farm/controller/Admin.php
new file mode 100755
index 0000000..9300bcf
--- /dev/null
+++ b/app/farm/controller/Admin.php
@@ -0,0 +1,132 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-11 13:53
+ * @功能说明:登陆
+ */
+ public function login(){
+
+// $input = $this->_input;
+
+ initLogin();
+
+ $input = json_decode( $this->request->getInput(), true );
+
+ //dump($input);exit;
+
+ $dis = [
+
+ // 'uniacid' => $this->_uniacid,
+
+ 'username'=> $input['username']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ if(empty($data)){
+
+ return $this->error('该用户不存在', 400);
+
+ }
+
+ if($data['passwd']!=checkPass($input['passwd'])){
+
+
+ return $this->error('密码错误', 400);
+ }
+
+ $result['user'] = $data;
+
+ $result['token'] = uuid();
+
+ if (empty($result['token'])) {
+
+ return $this->error('系统错误', 400);
+ }
+ //添加缓存数据
+ setUserForToken($result['token'], $data, 99999999);
+
+ return $this->success($result);
+
+ }
+
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', 200 );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminBalance.php b/app/farm/controller/AdminBalance.php
new file mode 100755
index 0000000..e6664ce
--- /dev/null
+++ b/app/farm/controller/AdminBalance.php
@@ -0,0 +1,191 @@
+model = new BalanceCard();
+
+ $this->order_model = new BalanceOrder();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:储值充值卡列表
+ */
+ public function cardList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加充值卡
+ */
+ public function cardAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑充值卡
+ */
+ public function cardUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:充值卡详情
+ */
+ public function cardInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:储值订单列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['pay_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->order_model->dataList($dis,$input['limit']);
+
+
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:充值订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->order_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+}
diff --git a/app/farm/controller/AdminBreed.php b/app/farm/controller/AdminBreed.php
new file mode 100755
index 0000000..cdd99d2
--- /dev/null
+++ b/app/farm/controller/AdminBreed.php
@@ -0,0 +1,161 @@
+model = new BalanceCard();
+
+ $this->massif_model = new Massif();
+
+ $this->land_model = new LandList();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:29
+ * @功能说明:养殖管理
+ */
+ public function breedList(){
+
+ $input = $this->_param;
+
+ $breed_model = new Breed();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['a.title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['b.farmer_id','=',$input['farmer_id']];
+
+ $dis[] = ['b.type','=',5];
+ }
+
+ $data = $breed_model->breedList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $farmer_model = new Farmer();
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_name'] = $farmer_model->where('id','in',$v['farmer_id'])->column('title');
+
+ $v['farmer_name'] = implode(',',$v['farmer_name']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:30
+ * @功能说明:添加养殖管理
+ */
+ public function breedAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $breed_model = new Breed();
+
+ $res = $breed_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:34
+ * @功能说明:编辑养殖管理
+ */
+ public function breedUpdate(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $breed_model = new Breed();
+
+ $res = $breed_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:34
+ * @功能说明:编辑养殖管理
+ */
+ public function breedInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $breed_model = new Breed();
+
+ $res = $breed_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+}
diff --git a/app/farm/controller/AdminClaim.php b/app/farm/controller/AdminClaim.php
new file mode 100755
index 0000000..d79bb49
--- /dev/null
+++ b/app/farm/controller/AdminClaim.php
@@ -0,0 +1,843 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:10
+ * @功能说明:领地 认养分类列表
+ */
+ public function claimCateList(){
+
+ $input = $this->_param;
+
+ $cate_model = new LandCate();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['type','=',$input['type']];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $cate_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $farmer_model = new Farmer();
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_title'] = $farmer_model->where('id','in',$v['farmer_id'])->where(['status'=>2])->column('title');
+
+ $v['farmer_title'] = array_values($v['farmer_title']);
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function claimCateInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $cate_model = new LandCate();
+
+ $data = $cate_model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:领地 认养分类编辑
+ */
+ public function claimCateUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $cate_model = new LandCate();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $cate_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:13
+ * @功能说明:领地 认养分类添加
+ */
+ public function claimCateAdd(){
+
+ $input = $this->_input;
+
+ $cate_model = new LandCate();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $cate_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:26
+ * @功能说明:用户下单列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['a.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['b.mobile','like','%'.$input['mobile'].'%'];
+
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $order_model = new ClaimOrder();
+
+ $farmer_model = new Farmer();
+
+ $user_model = new User();
+
+ $data = $order_model->adminDataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id'=>$v['farmer_id']],'title');
+
+ $v['user_info'] = $user_model->dataInfo(['id'=>$v['user_id']]);
+
+ }
+ }
+
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:52
+ * @功能说明:用户下单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $farmer_model = new Farmer();
+
+ $source_model = new Source();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new ClaimOrder();
+
+ $data = $order_model->dataInfo($dis);
+
+ $data['time_text'] = date('Y-m-d',$data['start_time']).'~'.date('Y-m-d',$data['end_time']);
+ //农场信息
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']]);
+ //溯源信息
+ $data['source'] = $source_model->dataInfo(['id'=>$data['source_id']]);
+
+ $address_model = new OrderAddress();
+
+ $data['address_info'] = $address_model->dataInfo(['order_id'=>$input['id'],'type'=>2]);
+
+ if($data['is_collage']==1){
+
+ $collage_model = new CollageJoin();
+
+ $collage_info = $collage_model->dataInfo(['order_id'=>$input['id']]);
+
+ if(!empty($collage_info)){
+
+ $data['collage_status'] = $collage_info['status'];
+
+ $data['collage_discount_price'] = $data['init_price']-$collage_info['price'];
+
+ $data['collage_discount_price'] = $data['collage_discount_price']>0?$data['collage_discount_price']:0;
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:14
+ * @功能说明:配送订单列表
+ */
+ public function userSendOrderList(){
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $data = $send_order_model->orderSendOrder($input['claim_order_id'],1,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-16 17:21
+ * @功能说明:配送订单列表
+ */
+ public function sendOrderList(){
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['pay_time','>',0];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+
+ }
+
+ if(!empty($input['send_type'])){
+
+ $dis[] = ['send_type','=',$input['send_type']];
+
+ }
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+
+ }
+
+
+ $data = $send_order_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 14:00
+ * @功能说明:配送订单详情
+ */
+ public function sendOrderInfo()
+ {
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $seed_model = new LandOrderSeed;
+
+ $farmer_model = new Farmer();
+
+ $send_order = $send_order_model->dataInfo(['id' => $input['id']]);
+
+ if($send_order['type']==1){
+
+ $order_model = new ClaimOrder();
+
+ $send_order['claim_order'] = $order_model->dataInfo(['id' => $send_order['order_id']]);
+
+ }else{
+
+ $order_model = new LandOrder();
+
+ $send_order['land_order'] = $order_model->dataInfo(['id' => $send_order['order_id']]);
+ //种子列表
+ $send_order['land_order']['seed'] = $seed_model->orderSeed($send_order['order_id']);
+ }
+
+ $send_order['farmer_info'] = $farmer_model->dataInfo(['id'=>$send_order['farmer_id']]);
+
+ return $this->success($send_order);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 10:24
+ * @功能说明:配送订单收货
+ */
+ public function sendOrderReceiving(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=2&&$send_order['send_type']==1){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ if($send_order['pay_type']!=3&&$send_order['send_type']==2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $send_order_model->sendOrderReceiving($send_order);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 09:47
+ * @功能说明:发货订单发货
+ */
+ public function sendOrderSend(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $update = [
+
+ 'pay_type' => 3,
+
+ 'send_time'=> time(),
+
+ 'auto_receiving_time' => $config['auto_hx_time']*86400+time()
+
+ ];
+
+ Db::startTrans();
+
+ $res = $send_order_model->dataUpdate(['id'=>$input['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('发货失败');
+ }
+
+ if($send_order['type']==1){
+
+ $claim_order_model = new ClaimOrder();
+
+ $claim_order_model->dataUpdate(['id'=>$send_order['order_id']],['pay_type'=>3]);
+ }
+
+ Db::commit();
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:06
+ * @功能说明:认养拼团列表
+ */
+ public function collageList(){
+
+ $input = $this->_param;
+
+ $collage_model = new ClaimCollage();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['a.title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['b.title','like','%'.$input['goods_name'].'%'];
+ }
+
+ $data = $collage_model->adminDataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:11
+ * @功能说明:添加拼团
+ */
+ public function collageAdd(){
+
+ $input = $this->_input;
+
+ $collage_model = new ClaimCollage();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $collage_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:11
+ * @功能说明:添加拼团
+ */
+ public function collageUpdate(){
+
+ $input = $this->_input;
+
+ $collage_model = new ClaimCollage();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $collage_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:11
+ * @功能说明:添加拼团
+ */
+ public function collageInfo(){
+
+ $input = $this->_param;
+
+ $collage_model = new ClaimCollage();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $collage_model->dataInfo($dis);
+
+ $claim_model = new Claim();
+
+ $res['claim_title'] = $claim_model->where(['id'=>$res['claim_id']])->value('title');
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 15:28
+ * @功能说明:认养管理列表
+ */
+ public function claimList(){
+
+ $input = $this->_param;
+
+ $claim_model = new Claim();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(isset($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['status','>',-1];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $claim_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $farmer_model = new Farmer();
+
+ $cate_model = new LandCate();
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_name'] = $farmer_model->where(['id'=>$v['farmer_id']])->value('title');
+
+ $cate_name = $cate_model->where('id','in',$v['cate_id'])->column('title');
+
+ $v['cate_name'] = implode(',',$cate_name);
+
+ }
+
+ }
+
+ $arr = [
+
+ 0 => 'off_num',
+
+ 1 => 'on_num',
+ ];
+
+ foreach ($arr as $key => $value){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => $key
+ ];
+
+ $data[$value] = $claim_model->where($dis)->count();
+
+ }
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:添加认养
+ */
+ public function claimAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:认养详情
+ */
+ public function claimInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->dataInfo($dis);
+
+ $claim_text_model = new ClaimText();
+
+ $monitor_text_model= new MonitorText();
+ //流程
+ $res['process'] = $claim_text_model->where(['claim_id'=>$input['id']])->select()->toArray();
+ //监控
+ $res['monitor'] = $monitor_text_model->where(['obj_id'=>$input['id'],'type'=>2])->column('monitor_id');
+
+ $res['monitor'] = array_values($res['monitor']);
+
+ $freightTemplate_model = new FreightTemplate();
+
+ $res['send_template_type'] = $freightTemplate_model->where(['id'=>$res['send_tmpl_id']])->value('type');
+
+ $claimSpecModel = new ClaimSpec();
+
+ $res['spec_list'] = $claimSpecModel->getList($res['id']);
+
+ $claimHarvestModel = new ClaimHarvest();
+ $res['harvest_list'] = $claimHarvestModel->getList($res['id']);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:编辑认养
+ */
+ public function claimUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:编辑认养
+ */
+ public function claimStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->where($dis)->update($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-31 15:11
+ * @功能说明:认养和土地分类
+ */
+ public function landAndClaimCate(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'a.status' => 1,
+
+ 'a.uniacid'=> $this->_uniacid,
+
+ 'a.type' => $input['type']
+ ];
+
+ $where = [];
+
+ if(!empty($input['farmer_id'])){
+
+ $where = [
+
+ 'a.is_public' => 1,
+
+ 'b.farmer_id' => $this->farmer['id']
+ ];
+ }
+
+
+ $cate_model = new LandCate();
+
+ $data = $cate_model->alias('a')
+ ->join('lbfarm_land_cate_text b','a.id = b.cate_id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminClaimEarTag.php b/app/farm/controller/AdminClaimEarTag.php
new file mode 100755
index 0000000..491b796
--- /dev/null
+++ b/app/farm/controller/AdminClaimEarTag.php
@@ -0,0 +1,66 @@
+model = new Model();
+ }
+
+ public function addEarTag()
+ {
+ $input = $this->_input;
+
+ $earModel = new ClaimEarTag();
+ $data = $earModel->addTag($input);
+
+ return $this->success($data);
+ }
+
+ public function updateEarTag()
+ {
+ $input = $this->_input;
+
+ $earModel = new ClaimEarTag();
+ $data = $earModel->updateTag($input, $input['id']);
+
+ return $this->success($data);
+ }
+
+ public function getEarList()
+ {
+ $input = $this->_param;
+
+ $earModel = new ClaimEarTag();
+ $data = $earModel->getList($input);
+
+ return $this->success($data);
+
+ }
+
+ public function deleteEarTag()
+ {
+ $input = $this->_input;
+ $earModel = new ClaimEarTag();
+ $data = $earModel->deleteEatTag($input['id']);
+
+ return $this->success($data);
+ }
+}
diff --git a/app/farm/controller/AdminClaimTraceability.php b/app/farm/controller/AdminClaimTraceability.php
new file mode 100755
index 0000000..74283d0
--- /dev/null
+++ b/app/farm/controller/AdminClaimTraceability.php
@@ -0,0 +1,67 @@
+model = new Model();
+ }
+
+ public function addTraceability()
+ {
+ $input = $this->_input;
+
+ $earModel = new ClaimTraceability();
+ $data = $earModel->addTraceability($input);
+
+ return $this->success($data);
+ }
+
+ public function updateTraceability()
+ {
+ $input = $this->_input;
+
+ $earModel = new ClaimTraceability();
+ $data = $earModel->updateTraceability($input, $input['id']);
+
+ return $this->success($data);
+ }
+
+ public function getTraceabilityList()
+ {
+ $input = $this->_param;
+
+ $earModel = new ClaimTraceability();
+ $data = $earModel->getList($input);
+
+ return $this->success($data);
+
+ }
+
+ public function deleteTraceability()
+ {
+ $input = $this->_input;
+ $earModel = new ClaimTraceability();
+ $data = $earModel->deleteTraceability($input['id']);
+
+ return $this->success($data);
+ }
+}
diff --git a/app/farm/controller/AdminCoupon.php b/app/farm/controller/AdminCoupon.php
new file mode 100755
index 0000000..52174e5
--- /dev/null
+++ b/app/farm/controller/AdminCoupon.php
@@ -0,0 +1,372 @@
+model = new Coupon();
+
+ $this->atv_model = new BagAtv();
+
+ $this->record_model = new CouponRecord();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:优惠券列表
+ */
+ public function couponList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['status','>',-1];
+
+ }
+
+ if(isset($input['send_type'])){
+
+ $dis[] = ['send_type','=',$input['send_type']];
+
+ }
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加优惠券
+ */
+ public function couponAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑优惠券
+ */
+ public function couponUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-02 09:51
+ * @功能说明:卡券上下架删除
+ */
+ public function couponStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+ //删除优惠券 需要判断该优惠券是否正在参加活动
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $atv_record_model = new CouponAtvRecord();
+
+ $have_atv = $atv_record_model->couponIsAtv($input['id']);
+
+ if($have_atv==true){
+
+ $this->errorMsg('该优惠券正在参加活动,只有等用户发起等活动结束后才能删除');
+ }
+
+ }
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:优惠券详情
+ */
+ public function couponInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 19:19
+ * @功能说明:活动详情
+ */
+ public function couponAtvInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->atv_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 19:22
+ * @功能说明:活动编辑
+ */
+ public function couponAtvUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->atv_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 16:26
+ * @功能说明:后台派发卡劵
+ */
+ public function couponRecordAdd(){
+
+ $input = $this->_input;
+
+ foreach ($input['user'] as $value){
+
+ $res = $this->record_model->recordAdd($input['coupon_id'],$value['id'],$value['num']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:31
+ * @功能说明:优惠券下拉框
+ */
+ public function couponSelect(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+
+ $data = $this->model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:36
+ * @功能说明:活动列表
+ */
+ public function bagAtvList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like',"%".$input['title'].'%'];
+ }
+
+ $data = $this->atv_model->dataList($dis,$input['limie']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:39
+ * @功能说明:添加活动
+ */
+ public function bagAtvAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input = $this->atv_model->changeData($input);
+
+ $res = $this->atv_model->dataAdd($input);
+
+ return $this->success($res);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:39
+ * @功能说明:添加活动
+ */
+ public function bagAtvUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input = $this->atv_model->changeData($input);
+
+ $res = $this->atv_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:39
+ * @功能说明:添加活动
+ */
+ public function bagAtvInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->atv_model->dataInfo($dis);
+
+ return $this->success($res);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminExcel.php b/app/farm/controller/AdminExcel.php
new file mode 100755
index 0000000..e69896b
--- /dev/null
+++ b/app/farm/controller/AdminExcel.php
@@ -0,0 +1,693 @@
+model = new LandOrder();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function landOrderList(){
+
+ $input = $this->_param;
+
+ $order_model = new LandOrder();
+
+ $farmer_model = new Farmer();
+
+ $user_model = new User();
+ //初始化订单
+ $order_model->orderInit();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['a.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['b.mobile','like','%'.$input['mobile'].'%'];
+
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }
+
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $order_model->adminDataSelect($dis);
+
+ if(!empty($data)){
+
+ foreach ($data as &$vs){
+
+ $vs['farmer_info'] = $farmer_model->dataInfo(['id'=>$vs['farmer_id']],'title');
+
+ $vs['user_info'] = $user_model->dataInfo(['id'=>$vs['user_id']]);
+
+ }
+ }
+
+ $name = '土地订单列表';
+
+ $header=[
+ '订单ID',
+ '商品名',
+ '到期时间',
+ '面积',
+ '农场名称',
+ '服务类型',
+ '租赁人',
+ '租赁人手机号',
+ '下单人',
+ '下单人手机号',
+ '实收金额',
+ '系统订单号',
+ '付款订单号',
+ '下单时间',
+ '支付方式',
+ '状态',
+ ];
+
+ $new_data = [];
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = $v['goods_name'];
+
+ $info[] = date('Y-m-d H:i:s',$v['end_time']);
+
+ $info[] = $v['area'].'m²';
+
+ $info[] = !empty($v['farmer_info']['title'])?$v['farmer_info']['title']:'';
+
+ $info[] = $v['massif_title'];
+
+ $info[] = $v['rent_user_name'];
+
+ $info[] = $v['rent_mobile'];
+
+ $info[] = $v['user_name'];
+
+ $info[] = $v['mobile'];
+
+ $info[] = $v['pay_price'];
+
+ $info[] = $v['order_code'];
+
+ $info[] = $v['transaction_id'];
+
+ $info[] = $v['create_time']?date('Y-m-d H:i:s',$v['create_time']):'暂无信息';
+
+ $info[] = !empty($v['balance'])&&$v['balance']>0?'余额支付':'微信支付';
+
+ $info[] = $this->orderStatusText($v['pay_type']);
+
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:26
+ * @功能说明:用户下单列表
+ */
+ public function claimOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['a.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['b.mobile','like','%'.$input['mobile'].'%'];
+
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $order_model = new ClaimOrder();
+
+ $farmer_model = new Farmer();
+
+ $user_model = new User();
+
+ $data = $order_model->adminDataSelect($dis);
+
+ if(!empty($data)){
+
+ foreach ($data as &$vs){
+
+ $vs['farmer_info'] = $farmer_model->dataInfo(['id'=>$vs['farmer_id']],'title');
+
+ $vs['user_info'] = $user_model->dataInfo(['id'=>$vs['user_id']]);
+
+ }
+ }
+
+
+ $name = '认养订单列表';
+
+ $header=[
+ '订单ID',
+ '商品名',
+ '数量',
+ '配送周期',
+ '农场名称',
+ '认养编号',
+ '下单人',
+ '下单人手机号',
+ '实收金额',
+ '系统订单号',
+ '付款订单号',
+ '下单时间',
+ '支付方式',
+ '配送方式',
+ '状态',
+ ];
+
+ $new_data = [];
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = $v['goods_name'];
+
+ $info[] = $v['num'];
+
+ $info[] = $v['send_cycle'].'共'.$v['send_times'].'次';
+
+ $info[] = $v['farmer_info']['title'];
+
+ $info[] = $v['claim_code'];
+
+ $info[] = $v['user_name'];
+
+ $info[] = $v['mobile'];
+
+ $info[] = $v['pay_price'];
+
+ $info[] = $v['order_code'];
+
+ $info[] = $v['transaction_id'];
+
+ $info[] = $v['create_time']?date('Y-m-d H:i:s',$v['create_time']):'暂无信息';
+
+ $info[] = !empty($v['balance'])&&$v['balance']>0?'余额支付':'微信支付';
+
+ $info[] = $v['send_type']==1?'自提':'快递';
+
+ $info[] = $this->orderStatusText($v['pay_type'],2);
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-08 14:55
+ * @功能说明:商城订单导出
+ */
+ public function shopOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['store_id'])){
+
+ $dis[] = ['a.store_id','=',$input['store_id']];
+
+ }
+
+ $order_model = new ShopOrder();
+
+ $data = $order_model->adminDataSelect($dis,$where);
+
+
+ return $this->success($data);
+
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 16:32
+ * @功能说明:
+ */
+ public function orderStatusText($status,$type=1){
+
+ switch ($status){
+
+ case 1:
+ return '待支付';
+
+ break;
+ case 2:
+ return $type==1?'租赁中':'认养中';
+
+ break;
+ case 3:
+ return '配送中';
+
+ break;
+
+ case 7:
+ return '已完成';
+
+ break;
+
+ case -1:
+ return '已取消';
+
+ break;
+
+ }
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 13:37
+ * @功能说明:财务数据统计导出
+ */
+ public function dateCount(){
+
+ $input = $this->_param;
+
+ $water_model = new FinanceWater();
+
+ if($input['type']==1){
+
+ $where[] = ['farmer_id','=',$input['farmer_id']];
+
+ }else{
+
+ $where[] = ['store_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $where[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+ }
+
+// dump($where);exit;
+
+ $data = $water_model->where($where)->field('create_date')->group('create_date')->select()->toArray();
+
+ if(!empty($data)){
+
+ foreach ($data as &$vs){
+ //查询各个类型的单日的流水除去余额
+ $date_water = $water_model->getDateList($input['farmer_id'],$vs['create_date'],$input['type']);
+
+ $vs = array_merge($vs,$date_water);
+ //查询当前余额
+ $day_water = $water_model->getDayCash($input['farmer_id'],$input['type'],$vs['create_date']);
+
+ $vs['cash'] = $day_water['cash'];
+
+ }
+
+ }
+ $farmer_model = new Farmer();
+
+ $farmer_name = $farmer_model->where(['id'=>$input['farmer_id']])->value('title');
+
+ $name = $farmer_name.'账务列表';
+
+ $header=[
+ '收支时间',
+ '土地订单收入(元)',
+ '土地配送收入(元)',
+ '认养订单收入(元)',
+ '认养配送收入(元)',
+ '养殖订单收入(元)',
+ '提现(元)',
+ '余额(元)',
+ ];
+
+ $new_data = [];
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['create_date'];
+
+ $info[] = $v['land_cash'];
+
+ $info[] = $v['land_send_cash'];
+
+ $info[] = $v['claim_cash'];
+
+ $info[] = $v['claim_send_cash'];
+
+ $info[] = $v['breed_cash'];
+
+ $info[] = $v['wallet_cash'];
+
+ $info[] = $v['cash'];
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 14:48
+ * @功能说明:用户收益列表
+ */
+ public function userProfitListExcel(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['a.nickName','like','%'.$input['name'].'%'];
+
+ $where[] = ['b.user_name','like','%'.$input['name'].'%'];
+
+ }
+
+ $fx_model = new DistributionList();
+
+ $cash_model = new DistributionCash();
+
+ $wallet_model = new Wallet();
+
+ $data = $fx_model->userProfitSelect($dis,$where);
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+ //产生收益
+ $v['total_fx_cash'] = $cash_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('cash');
+ //未入账
+ $v['unrecorded_fx_cash'] = $cash_model->where(['user_id'=>$v['id']])->where('status','in',[1])->sum('cash');
+ //累计提现
+ $v['total_wallte_cash'] = $wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('pay_price');
+ //提现中
+ $v['wallte_ing_cash'] = $wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1])->sum('pay_price');
+
+ }
+
+ }
+
+ $name = '收益信息列表';
+
+ $header=[
+ 'ID',
+ '姓名',
+ '微信昵称',
+ '总收益',
+ '总提现',
+ '提现中',
+ '未入账',
+ '当前余额',
+ ];
+
+ $new_data = [];
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = !empty($v['user_name'])?$v['user_name']:'';
+
+ $info[] = $v['nickName'];
+
+ $info[] = $v['total_fx_cash'];
+
+ $info[] = $v['total_wallte_cash'];
+
+ $info[] = $v['wallte_ing_cash'];
+
+ $info[] = $v['unrecorded_fx_cash'];
+
+ $info[] = $v['fx_cash'];
+
+ $new_data[] = $info;
+ }
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($data);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 10:17
+ * @功能说明:分销商列表导出
+ */
+ public function userRelationshipListExcel(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'is_fx' => 1
+ ];
+
+ $user_model = new User();
+
+ $cash_model = new DistributionCash();
+
+ $wallet_model = new Wallet();
+
+ $data = $user_model->where($dis)->field('id,avatarUrl,nickName,pid,fx_bind_time,fx_cash')->order('fx_bind_time')->select()->toArray();
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+
+ $v['top_name'] = $user_model->where(['id'=>$v['pid'],'is_fx'=>1])->value('nickName');
+ //产生收益
+ $v['total_fx_cash'] = $cash_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('cash');
+ //累计提现
+ $v['wallte_cash'] = $wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('pay_price');
+
+ }
+
+ }
+
+ $name = '分销商列表';
+
+ $header=[
+ 'ID',
+ '微信昵称',
+ '产生收益(元)',
+ '总收益(元)',
+ '已提现(元)',
+ '上线id',
+ '上线昵称',
+ '创建时间',
+ ];
+
+ $new_data = [];
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = $v['nickName'];
+
+ $info[] = $v['total_fx_cash'];
+
+ $info[] = $v['fx_cash'];
+
+ $info[] = $v['wallte_cash'];
+
+ $info[] = $v['pid'];
+
+ $info[] = !empty($v['top_name']);
+
+ $info[] = date('Y-m-d H:i:s',$v['fx_bind_time']);
+
+ $new_data[] = $info;
+ }
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminFarmer.php b/app/farm/controller/AdminFarmer.php
new file mode 100755
index 0000000..5371c18
--- /dev/null
+++ b/app/farm/controller/AdminFarmer.php
@@ -0,0 +1,1265 @@
+model = new Model();
+
+ $this->pay_model = new PayModel($this->payConfig());
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function farmerList(){
+
+
+// $a = 'a:26:{s:10:"gmt_create";s:19:"2022-08-19 11:53:51";s:7:"charset";s:5:"UTF-8";s:12:"seller_email";s:16:"860200049@qq.com";s:7:"subject";s:11:"claim_order";s:4:"sign";s:344:"JeRSkvK1AE/MEbS1l6/djz0HbYiMQ1A7Twt3NcYiLHtwvQiT2n2W6ZDldB4ip9Je35/YqrHkyioLOWgCvUKT11bbIBI6O+wEJzvPJSncXk60CX49G+OVYLjZPNy9379XH7AUfKq+6W2E7CbgjRZTbp/shgXbskJxD7h6sMASsU/NGEDxLLzx5L/+BFOpQrIYJX68dhIiSnXFFSoaCKcuzJ2sXNkwhmPbW1BXTw0uRhfS/t9+PUBPMIH0yUgCD5UP01RaOyMWMRX2uTTLxj7khaEgAVLtJybeKK90UxbWTStn6KZZi+9O/LqjVczg4HOIovjNWGaChlNlf/hjnqtxig==";s:8:"buyer_id";s:16:"2088802696250503";s:14:"invoice_amount";s:4:"0.01";s:9:"notify_id";s:34:"2022081900222115352050501423546615";s:14:"fund_bill_list";s:49:"[{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}]";s:11:"notify_type";s:17:"trade_status_sync";s:12:"trade_status";s:13:"TRADE_SUCCESS";s:14:"receipt_amount";s:4:"0.01";s:6:"app_id";s:16:"2021003144604274";s:16:"buyer_pay_amount";s:4:"0.01";s:9:"sign_type";s:4:"RSA2";s:9:"seller_id";s:16:"2088441813624801";s:11:"gmt_payment";s:19:"2022-08-19 11:53:52";s:11:"notify_time";s:19:"2022-08-19 11:53:52";s:7:"version";s:3:"1.0";s:12:"out_trade_no";s:25:"2022081911534305900000059";s:12:"total_amount";s:4:"0.01";s:8:"trade_no";s:28:"2022081922001450501410705206";s:11:"auth_app_id";s:16:"2021003144604274";s:14:"buyer_logon_id";s:11:"182****4093";s:12:"point_amount";s:4:"0.00";s:4:"flag";b:1;}';
+//
+//
+// // $jsApiParameters = $this->pay_model->aliPay('20220722151244011900000119',1,'SchoolShop');
+// $jsApiParameters = $this->pay_model->aliRefund('2022082222001450501413499954',0.01);
+//
+// $jsApiParameters = object_array($jsApiParameters);
+//
+// dump($jsApiParameters);exit;
+
+// $a = new PushMsgModel($this->_uniacid);
+//
+// $data = ['registration_id'=>['170976fa8a62f84b1ff']];
+//
+// // $data = json_encode($data);
+//
+//
+// $n = $a->send_pub('1wwww1',$data);
+//
+// dump($n);exit;
+
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $type = !empty($input['type'])?$input['type']:1;
+
+ $dis[] = ['a.type','=',$type];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['a.user_name','like','%'.$input['title'].'%'];
+
+ }
+
+ if(!empty($input['store_name'])){
+
+ $dis[] = ['a.title','like','%'.$input['store_name'].'%'];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['a.user_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.phone','like','%'.$input['name'].'%'];
+ }
+
+ $data = $this->model->adminDataList($dis,$input['limit'],$where);
+
+ $list = [
+
+ 0=>'all',
+
+ 1=>'ing',
+
+ 2=>'pass',
+
+ 4=>'nopass'
+ ];
+
+ foreach ($list as $k=> $value){
+
+ $dis_s = [];
+
+ $dis_s[] =['uniacid','=',$this->_uniacid];
+
+ $dis_s[] = ['type','=',$type];
+
+ if(!empty($k)){
+
+ $dis_s[] = ['status','=',$k];
+
+ }else{
+
+ $dis_s[] = ['status','>',-1];
+
+ }
+
+ $data[$value] = $this->model->where($dis_s)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 13:35
+ * @功能说明:申请认证农场主
+ */
+ public function farmerAdd(){
+
+ $input = $this->_input;
+
+ $farmer_model = new Farmer();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['status'] = 2;
+
+ $input['is_admin']= 1;
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+
+ $input['idcard_imgs'] = !empty($input['idcard_imgs'])?implode(',',$input['idcard_imgs']):'';
+
+ $res = $farmer_model->dataAdd($input);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:车手详情
+ */
+ public function farmerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $user_model = new User();
+
+ $data['nickName'] = $user_model->where(['id'=>$data['user_id']])->value('nickName');
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-03 00:15
+ * @功能说明:审核(2通过,3取消,4拒绝)
+ */
+ public function farmerUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $water_model = new FinanceWater();
+
+ $water_model->cashArrival($input['id']);
+
+ $info = $this->model->dataInfo($dis);
+
+ if(!empty($input['status'])&&in_array($input['status'],[2,4,-1])){
+
+ $input['sh_time'] = time();
+
+ if($input['status']==2){
+
+ $this->model->initLandLord($info,$info['uniacid']);
+ }
+
+ if($input['status']==-1){
+
+ if($info['cash']>0){
+
+ $this->errorMsg('农场主还有余额未提现');
+ }
+
+ $where[] = ['farmer_id','=',$info['id']];
+
+ $where[] = ['pay_type','in',[2,3,4,5,6]];
+
+ $arr = [
+
+ 'land_order' => new LandOrder(),
+
+ 'claim_order'=> new ClaimOrder(),
+
+ 'send_order' => new SendOrder()
+ ];
+
+ foreach ($arr as $value){
+
+ $find = $value->where($where)->find();
+
+ if(!empty($find)){
+
+ $this->errorMsg('农场主还有订单未处理');
+
+ }
+
+ }
+ $wallet_model = new Wallet();
+
+ $wallet = $wallet_model->dataInfo(['farmer_id'=>$info['id'],'status'=>1]);
+
+ if(!empty($wallet)){
+
+ $this->errorMsg('农场主还有提现未处理');
+
+ }
+ //
+ $diss = [
+
+ 'farmer_id' => $input['id'],
+
+ 'cash_status'=> 1,
+
+ 'role_type' => 1
+ ];
+
+ $water = $water_model->where($diss)->sum('price');
+
+ if(!empty($water)&&$water>0){
+
+ $this->errorMsg('农场主还有冻结金额');
+
+ }
+
+ }
+
+ }
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 15:21
+ * @功能说明:
+ */
+ public function farmerSelectList(){
+
+ $input = $this->_param;
+
+ $type = isset($input['type'])?$input['type']:1;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['type','=',$type];
+
+ if(!empty($input['cate_id'])){
+
+ if($input['cate_type']==3){
+
+ $store_goods_model = new StoreGoods();
+
+ $list = $store_goods_model->where(['type'=>2])->where('goods_id','in',$input['cate_id'])->column('store_id');
+
+ }else{
+
+ $cate_text = new LandCateText();
+
+ $list = $cate_text->where(['type'=>$input['cate_type']])->where('cate_id','in',$input['cate_id'])->column('farmer_id');
+ }
+
+ if (!empty($list)){
+ $dis[] = ['id','in',$list];
+ }
+
+ }
+
+ $farmer_model = new Farmer();
+
+ $data = $farmer_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 17:09
+ * @功能说明:农场主提现列表
+ */
+ public function walletList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['is_show','=',1];
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ $wallet_model = new Wallet();
+
+ $data = $wallet_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:29
+ * @功能说明:同意提现打款
+ */
+ public function walletPass(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $wallet_model = new Wallet();
+
+ $data = $wallet_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('记录未找到');
+ }
+
+ if($data['status']!=1){
+
+ $this->errorMsg('记录状态错误');
+ }
+
+ $update = [
+
+ 'sh_time' => time(),
+
+ 'status' => 2,
+
+ 'online' => $input['online'],
+
+ ];
+
+ Db::startTrans();
+
+ $res = $wallet_model->dataUpdate(['id'=>$input['id'],'status'=>1],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('打款失败');
+
+ }
+ //线上转账
+ if($input['online']==1){
+
+ $user_model = new User();
+
+ $openid = $user_model->where(['id'=>$data['user_id']])->value('openid');
+
+ if(empty($openid)){
+
+ return $this->error('用户信息错误,未获取到openid');
+ }
+ //微信相关模型
+ $wx_pay = new WxPay($this->_uniacid);
+ //微信提现
+ $res = $wx_pay->crteateMchPay($this->payConfig(),$openid,$data['true_price']);
+
+ if($res['result_code']=='SUCCESS'&&$res['return_code']=='SUCCESS'){
+
+ if(!empty($res['payment_no'])){
+
+ $wallet_model->dataUpdate(['id'=>$input['id']],['payment_no'=>$res['payment_no']]);
+ }
+
+ }else{
+
+ Db::rollback();
+
+ return $this->error(!empty($res['err_code_des'])?$res['err_code_des']:'你还未该权限');
+
+ }
+
+ }
+
+ Db::commit();
+
+ $sys_model = new PushMsgModel($data['uniacid']);
+
+ $sys_model->sendMsg($data,1);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:43
+ * @功能说明:拒绝退款
+ */
+ public function walletNoPass(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $wallet_model = new Wallet();
+
+ $data = $wallet_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('记录未找到');
+ }
+
+ if($data['status']!=1){
+
+ $this->errorMsg('记录状态错误');
+ }
+
+ Db::startTrans();
+
+ $update = [
+
+ 'sh_time' => time(),
+
+ 'status' => 3,
+
+ ];
+
+ $res = $wallet_model->dataUpdate(['id'=>$input['id'],'status'=>1],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('拒绝失败');
+
+ }
+
+ if($data['type']!=3){
+
+ $water_model = new FinanceWater();
+ //添加拒绝提现记录
+ $res = $water_model->addWater($data['id'],12,$data['type'],1);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('拒绝失败');
+
+ }
+
+ if($data['type']==1){
+
+ $res = $water_model->cashArrival($data['farmer_id']);
+
+ }else{
+
+ $res = $water_model->cashArrival(0,$data['store_id']);
+ }
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('拒绝失败');
+
+ }
+ }else{
+
+ $user_model = new User();
+
+ $cash = $data['pay_price'];
+
+ $res = $user_model->where(['id'=>$data['user_id']])->update(['fx_cash'=>Db::Raw("fx_cash+$cash")]);
+
+ }
+
+ Db::commit();
+
+ $sys_model = new PushMsgModel($data['uniacid']);
+
+ $sys_model->sendMsg($data,2);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-12 15:20
+ * @功能说明:农场主财务流水
+ */
+ public function fincanceWaterList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['status','in',[2,3]];
+
+ $dis[] = ['type','=',$input['type']];
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['store_name'])){
+
+ $dis[] = ['title','like','%'.$input['store_name'].'%'];
+ }
+
+ $start_time = !empty($input['start_time'])?$input['start_time']:'';
+
+ $end_time = !empty($input['end_time'])?$input['end_time']:'';
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ $water_model = new FinanceWater();
+
+ $water_model->cashArrival();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $water_data = $water_model->getDayCash($v['id'],$v['type'],'',$start_time,$end_time,2);
+ //当前余额
+ $v['cash'] = $water_data['cash'];
+ //当前收入
+ $v['income_cash'] = $water_data['income_cash'];
+ //当前提现
+ $v['wallet_cash'] = $water_data['wallet_cash'];
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-12 16:12
+ * @功能说明:农场主财务流水详情
+ */
+ public function fincanceWaterInfo(){
+
+ $input = $this->_param;
+
+ $water_model = new FinanceWater();
+
+ $water_model->cashArrival();
+
+ if($input['type']==1){
+
+ $where[] = ['farmer_id','=',$input['farmer_id']];
+
+ }else{
+
+ $where[] = ['store_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $where[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+ }
+
+ $data = $water_model->where($where)->field('create_date')->group('create_date')->paginate($input['limit'])->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //查询各个类型的单日的流水除去余额
+ $date_water = $water_model->getDateList($input['farmer_id'],$v['create_date'],$input['type']);
+
+ $v = array_merge($v,$date_water);
+ //查询当前余额
+ $day_water = $water_model->getDayCash($input['farmer_id'],$input['type'],$v['create_date']);
+
+ $v['cash'] = $day_water['cash'];
+
+ }
+
+ }
+ $farmer_model = new Farmer();
+
+ $data['farmer_name'] = $farmer_model->where(['id'=>$input['farmer_id']])->value('title');
+
+ if(!empty($input['start_time'])){
+
+ $data['start_time'] = $input['start_time'];
+
+ $data['end_time'] = $input['end_time'];
+
+ }else{
+
+ $data['start_time'] = $water_model->where($where)->order('id')->value('create_date');
+
+ $data['start_time'] = strtotime($data['start_time']);
+
+ $data['end_time'] = $water_model->where($where)->order('id desc')->value('create_date');
+
+ $data['end_time'] = strtotime($data['end_time']);
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-18 10:07
+ * @功能说明:平台统计详情
+ */
+ public function statisticsCash(){
+
+ $input = $this->_param;
+
+ $water_model = new FinanceWater();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+ //总收入
+ $data['cash']['total_cash'] = $water_model->where($dis)->where(['add'=>1])->where('type','not in',[12])->sum('price');
+ //商城收入
+ $data['cash']['shop_cash'] = $water_model->where($dis)->where('type','in',[8,16])->sum('price');
+ //土地收入
+ $data['cash']['land_cash'] = $water_model->where($dis)->where(['type'=>3])->sum('price');
+ //认养收入
+ $data['cash']['claim_cash'] = $water_model->where($dis)->where(['type'=>1])->sum('price');
+ //养殖收入
+ $data['cash']['breed_cash'] = $water_model->where($dis)->where(['type'=>6])->sum('price');
+ //配送订单
+ $data['cash']['send_cash'] = $water_model->where($dis)->where('type','in',[14,10])->sum('price');
+ //退款
+ $data['cash']['refund_cash']= $water_model->where($dis)->where('type','in',[2,4,9,11,13,17])->sum('price');
+
+ $total = ($input['end_time']-$input['start_time'])/86400;
+
+ $total = ceil($total);
+
+ $day = 0;
+
+ $arr = [
+
+ '1' => 'claim_cash',
+
+ '3' => 'land_cash',
+
+ '8' => 'shop_cash',
+ //商城订单运费
+ '16'=> 'shop_car_cash',
+
+ ];
+ //每页条数
+ $list['per_page'] = 30;
+ //当前页
+ $list['current_page'] = $input['page'];
+ //总条数
+ $list['total'] = $total;
+ //最后一页
+ $list['last_page'] = ceil($total/$list['per_page']);
+
+ $total -= $list['per_page']*($list['current_page']-1);
+
+ $all = $total>$list['per_page']?$list['per_page']:$total;
+
+ while ($day<$all){
+
+ $date = $input['start_time']+$day*86400+$list['per_page']*($list['current_page']-1)*86400;
+
+ foreach ($arr as $ks=>$vs){
+
+ $where = [
+
+ 'create_date' => date('Y-m-d',$date),
+
+ 'type' => $ks
+ ];
+
+ $list['data'][$day][$vs] = $water_model->where($where)->sum('price');
+ }
+
+ $list['data'][$day]['shop_cash']+= $list['data'][$day]['shop_car_cash'];
+
+ $list['data'][$day]['date'] = date('m-d',$date);
+
+ $day ++;
+
+ }
+
+ $data['list'] = $list;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-18 11:03
+ * @功能说明:用户统计详情
+ */
+ public function statisticsUser(){
+
+ $input = $this->_param;
+
+ $user_model = new User();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //用户总数量
+ $data['total_count'] = $user_model->where($dis)->count();
+
+ $year = date('Y');
+
+ $last_year = $year-1;
+
+ $where['year'] = $last_year;
+
+ $now_where['year'] = $year;
+
+ switch ($input['date']){
+
+ case 1:
+ $time = 'today';
+
+ $last_time = 'yesterday';
+ //去年今日
+ $where['create_date'] = date('Y-m-d',strtotime("-1 year"));
+
+ $now_where['create_date'] = date('Y-m-d',time());
+
+ break;
+ case 2:
+ $time = 'week';
+
+ $last_time = 'last week';
+
+ $where['week'] = date('W');
+
+ $now_where['week'] = date('W');
+
+ break;
+ case 3:
+ $time = 'month';
+
+ $last_time = 'last month';
+
+ $where['month'] = date('m');
+
+ $now_where['month'] = date('m');
+
+ break;
+ case 4:
+ $time = 'year';
+
+ $last_time = 'last year';
+
+ break;
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+ //新增人数
+ $data['new_count'] = $user_model->where($dis)->count();
+ //去年当日/当周/当月用户数量
+ $last_time_count = $user_model->where($where)->count();
+
+ $now_time_count = $user_model->where($now_where)->count();
+ //同比
+ $data['t_balance'] = $last_time_count>0?round(($now_time_count-$last_time_count)/$last_time_count*100,2):0;
+
+ $last_count = $user_model->whereTime('create_time',$last_time)->count();
+
+ $now_count = $user_model->whereTime('create_time',$time)->count();
+
+// dump($last_count,$now_count);exit;
+ //环比
+ $data['h_balance'] = $last_count>0?round(($now_count-$last_count)/$last_count*100,2):0;
+
+ $total = ($input['end_time']-$input['start_time'])/86400;
+
+ $day = 0;
+ //每页条数
+ $list['per_page'] = 30;
+ //当前页
+ $list['current_page'] = $input['page'];
+ //总条数
+ $list['total'] = $total;
+ //最后一页
+ $list['last_page'] = ceil($total/$list['per_page']);
+
+ $total -= $list['per_page']*($list['current_page']-1);
+
+ $all = $total>$list['per_page']?$list['per_page']:$total;
+
+ while ($day<$all){
+
+ $date = $input['start_time']+$day*86400+$list['per_page']*($list['current_page']-1)*86400;
+
+ $list['data'][$day]['week'] = changeWeek(date('w',$date));
+
+ $where = [
+
+ 'create_date' => date('Y-m-d',$date),
+
+ ];
+
+ $list['data'][$day]['count'] = $user_model->where($where)->count();
+
+ $list['data'][$day]['date'] = date('m-d',$date);;
+
+ $day++;
+
+ }
+
+ $data['list'] = $list;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 11:00
+ * @功能说明:仪器列表
+ */
+ public function machineList(){
+
+ $input = $this->_param;
+
+ $mac_model = new Machine();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $mac_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 11:00
+ * @功能说明:仪器列表
+ */
+ public function machineSelect(){
+
+ $input = $this->_param;
+
+ $mac_model = new Machine();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $mac_model->where($dis)->order('status desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 11:00
+ * @功能说明:仪器详情
+ */
+ public function machineInfo(){
+
+ $input = $this->_param;
+
+ $mac_model = new Machine();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $mac_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 11:00
+ * @功能说明:添加仪器
+ */
+ public function machineAdd(){
+
+ $input = $this->_input;
+
+ $mac_model = new Machine();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $mac_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 11:00
+ * @功能说明:编辑仪器
+ */
+ public function machineUpdate(){
+
+ $input = $this->_input;
+
+ $mac_model = new Machine();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $mac_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 17:40
+ * @功能说明:店铺下拉框
+ */
+ public function storeSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['type','=',2];
+
+ if(!empty($input['goods_id'])){
+
+ $goods_store_model = new StoreGoods();
+
+ $store_id = $goods_store_model->where(['goods_id'=>$input['goods_id']])->column('store_id');
+
+ $dis[] = ['id','in',$store_id];
+
+ }
+
+ $farmer_model = new Farmer();
+
+ $data = $farmer_model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:22
+ * @功能说明:监控列表
+ */
+ public function monitorList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+
+ }
+
+ $monitor_model = new Monitor();
+
+ $data = $monitor_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_name'] = $this->model->where(['id'=>$v['farmer_id']])->value('title');
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:22
+ * @功能说明:监控列表
+ */
+ public function monitorSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+
+ }
+
+ $monitor_model = new Monitor();
+
+ $data = $monitor_model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:25
+ * @功能说明:添加监控
+ */
+ public function monitorAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $monitor_model = new Monitor();
+
+ $res = $monitor_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:25
+ * @功能说明:添加监控
+ */
+ public function monitorInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $monitor_model = new Monitor();
+
+ $res = $monitor_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:25
+ * @功能说明:添加监控
+ */
+ public function monitorUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $monitor_model = new Monitor();
+
+ $res = $monitor_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminGoods.php b/app/farm/controller/AdminGoods.php
new file mode 100755
index 0000000..fb75b42
--- /dev/null
+++ b/app/farm/controller/AdminGoods.php
@@ -0,0 +1,582 @@
+model = new ShopGoods();
+
+ $this->cate_model = new ShopGoodsCate();
+
+ $this->spe_model = new Shop;
+
+ $this->spe_price_model = new GoodsSpePrice();
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:01
+ * @功能说明:商品分类列表
+ */
+ public function goodsCateList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->cate_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:17
+ * @功能说明:添加分类
+ */
+ public function goodsCateAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->cate_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:18
+ * @功能说明:编辑分类
+ */
+ public function goodsCateUpdate(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->cate_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:18
+ * @功能说明:编辑分类
+ */
+ public function goodsCateInfo(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->cate_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 17:58
+ * @功能说明:分类下拉框
+ */
+ public function goodsCateSelect(){
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+
+ ];
+
+ $data = $this->cate_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * 获取商品列表
+ */
+ public function goodsList(){
+
+ $input= $this->_param;
+
+ $dis[]= ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['name','like',"%".$input['name']."%"];
+ }
+
+ if(!empty($input['cate'])){
+
+ $dis[] = ['type','=',$input['cate']];
+ }
+ //自提
+ if(!empty($input['is_self'])){
+
+ $dis[] = ['is_self','=',$input['is_self']];
+ }
+ //快递
+ if(!empty($input['is_send'])){
+
+ $dis[] = ['is_send','=',$input['is_send']];
+
+ }
+
+ $sale_type = $input['type']==2?0:1;
+
+ $sale_out_goods = $this->spe_price_model->getSellOut($this->_uniacid,$sale_type);
+
+ switch ($input['type']){
+
+ case 1:
+ $dis[] = ['status','=',1];
+ break;
+
+ case 2:
+ $dis[]= ['status','>',-1];
+ break;
+
+ case 3:
+ $dis[] = ['status','=',0];
+
+ break;
+ }
+
+ $dis[] = ['id','in',$sale_out_goods];
+
+ $data = $this->model->dataList($dis,$this->_input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //总库存
+ $v['all_stock'] = $this->spe_price_model->getGoodsStock($v['id']);
+ //规格
+ $v['spe_info'] = $this->goodsSpeList($v['id']);
+
+ $v['cate_text'] = $this->cate_model->where(['id'=>$v['type']])->value('title');
+
+ }
+
+ }
+ //销售中
+ $data['sale_ing'] = $this->model->saleIngCount($this->_uniacid);
+ //售罄
+ $data['sale_out'] = $this->model->saleIngCount($this->_uniacid,2);
+ //下架
+ $data['sale_end'] = $this->model->saleIngCount($this->_uniacid,3);
+
+ return $this->success($data);
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:33
+ * @功能说明:添加商品
+ */
+ public function goodsAdd(){
+
+ $input = $this->_input;
+
+ $data = $this->model->returnData($input);
+
+ $discount_data = $input['memberForm']['discount_data'];
+
+ $data['uniacid'] = $this->_uniacid;
+
+ Db::startTrans();
+
+ $goods_id = $this->model->dataAdd($data);
+
+ $spe_arr = $this->goodsSpeAdd($input['specsForm']['specsItem'],$goods_id);
+
+ $spe_res = $this->goodsSpePriceAdd($input['specsForm']['specsTable'],$goods_id,$spe_arr);
+ //会员折扣模型
+ $discount_model = new DiscountGoods();
+ //会员折扣
+ $res = $discount_model->goodsAdd($discount_data,$this->_uniacid,$goods_id);
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * 修改商品
+ */
+ public function goodsUpdate(){
+
+ $input= $this->_input;
+ //会员折扣模型
+ $discount_model = new DiscountGoods();
+
+ $dis = is_array($input['id'])? ['id','in',$input['id']]:['id' =>$input['id']];
+
+ $discount_data = $input['memberForm']['discount_data'];
+
+ Db::startTrans();
+
+ $data = $this->model->returnData($input);
+ //判断商品名字长度
+ if(strlen($data['name'])>110){
+
+ $this->errorMsg('商品名字不得超过110字符,当前字符'.strlen($data['name']));
+ }
+
+ if(isset($data['is_limit'])&&$data['is_limit']==2&&$data['start_min']>$data['limit']){
+
+ $this->errorMsg('起购数不能大于限购');
+
+ }
+
+ $this->model->goodsUpdate($dis,$data);
+
+ $this->spe_model->goodsSpeUpdate(['uniacid'=>$this->_uniacid,'goods_id'=>$input['id']],['status'=>-1]);
+
+ $this->spe_price_model->goodsSpePriceUpdate(['uniacid'=>$this->_uniacid,'goods_id'=>$input['id']],['status'=>-1]);
+
+ $spe_arr = $this->goodsSpeAdd($input['specsForm']['specsItem'],$input['id']);
+
+ $res = $this->goodsSpePriceAdd($input['specsForm']['specsTable'],$input['id'],$spe_arr);
+
+
+ if($data['is_parameter']==1 && empty($input['parameter'])){
+
+ return $this->error('请添加商品参数');
+ }
+ //会员折扣
+ $discount_model->goodsAdd($discount_data,$this->_uniacid,$input['id']);
+
+ Db::commit();
+
+ return $this->success($res);
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:21
+ * @功能说明:分类详情
+ */
+ public function goodsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ //会员折扣模型
+ $discount_model = new DiscountGoods();
+
+ $res['goods_info'] = $this->model->dataInfo($dis);
+
+ $res['spe_info'] = $this->goodsSpeList($input['id']);
+ //会员商品信息
+ $res['memberForm']['is_discount'] = $res['goods_info']['is_discount'];
+ //商品折扣信息
+ $res['memberForm']['discount_data'] = $discount_model->goodsDiscount($input['id']);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * 获取商品规格
+ */
+ public function goodsSpeList($goods_id){
+
+ $dis['goods_id'] = $goods_id;
+
+ $dis['status'] = 1;
+
+ $data['text'] = $this->spe_model->goodsSpe($dis);
+
+ $data['price'] = $this->spe_price_model->goodsSpePrice($dis);
+
+ if(!empty($data['price'])){
+
+ foreach ($data['price'] as &$v){
+
+ $v['title'] = $v['spe_name_text'];
+
+ $v['true_id'] = $v['id'];
+
+ $v['id'] = implode(',',$v['spe_array_text']);
+
+ }
+ }
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-26 10:09
+ * @功能说明:列表页修改商品库存
+ */
+ public function updateSpe(){
+
+ $input= $this->_input;
+
+ $input= $input['stock'];
+
+ if(!empty($input)&&!is_array($input)){
+
+ $this->errorMsg('数据错误');
+ }
+
+ foreach ($input as $value){
+
+ $this->spe_price_model->goodsSpePriceUpdate(['id'=>$value['id']],['stock'=>$value['stock']]);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-28 10:33
+ * @功能说明:修改商品基本的参数
+ */
+ public function goodsBasicUpdate(){
+
+ $input= $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->goodsUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * 上下架删除商品
+ */
+ public function goodsStatusUpdate(){
+
+ $input= $this->_input;
+
+ if(isset($input['status'])){
+
+ $data = ['status'=>$input['status']];
+
+ }else{
+
+ $data = ['index_show'=>$input['index_show']];
+
+ }
+ $res = $this->model->goodsUpdateStatus($data,$input['id']);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @param $data
+ * @param $goods_id
+ * @return array
+ * 添加多规格
+ */
+ public function goodsSpeAdd($data,$goods_id){
+ /**
+ * 循环判断是否存在多个规格名添加图片的问题
+ * @date 2020/5/14 10:42 --lichuanming
+ */
+ $isimg_count = 0;
+ foreach ($data as $item ){
+ if($item['is_img'] == 1){
+ $isimg_count++;
+ }
+ }
+ if($isimg_count > 1){
+ return $this->error('当前已有规格名添加了图片,继续添加则需取消上一个规格名的图片勾选');
+ }
+
+ $arr = array();
+ if(!empty($data)){
+ foreach ($data as $v){
+ $is_img = $v['is_img']?$v['is_img']:0; #@date 2020/5/14 10:42 --lichuanming
+ if(strlen($v['pid'])>10){
+ $pid = $this->spe_model->goodsSpeAdd(['uniacid'=>$this->_uniacid,'goods_id'=>$goods_id,'title'=>$v['title'],'is_img'=>$is_img]);
+ }else{
+ $this->spe_model->goodsSpeUpdate(['id'=>$v['id']],['status'=>1,'title'=>$v['title'],'is_img'=>$is_img]);
+ $pid = $v['id'];
+ }
+ if(!empty($v['cate'])){
+ foreach ($v['cate'] as $value){
+ $image = $is_img?$value['image']:''; #@date 2020/5/14 10:42 --lichuanming
+
+ if(strlen($value['id'])>10) {
+ $id = $this->spe_model->goodsSpeAdd(['uniacid' => $this->_uniacid, 'goods_id' => $goods_id, 'title' => $value['title'], 'pid' => $pid,'is_img'=>$is_img,'image'=>$image]);
+ }else{
+ $this->spe_model->goodsSpeUpdate(['id'=>$value['id']],['status'=>1,'title'=>$value['title'],'is_img'=>$is_img,'image'=>$image]);
+ $id = $value['id'];
+ }
+ $arr[$value['id']] = $id;
+ }
+ }
+ }
+ }
+ return $arr;
+ }
+
+
+ /**
+ * @param $data
+ * @param $good_id
+ * @param $arr
+ * @return int|string
+ * 添加多规格价格
+ */
+ public function goodsSpePriceAdd($data,$good_id,$arr){
+ if(!empty($data)){
+ foreach ($data as $v){
+ if (strlen($v['price'])>8||strlen($v['original_price'])>8){
+
+ $this->errorMsg('价格最多8位');
+
+ }
+
+ $pid = explode(',',$v['id']);
+ $spe_id = [];
+ if(empty($arr)){
+ $this->errorMsg('规格不正确,请删除错误规格,重新编辑');
+ }
+ foreach ($pid as $value){
+ if(!key_exists($value,$arr)){
+ $this->errorMsg('规格不正确,请删除错误规格,重新编辑');
+ }
+ $spe_id[] = $arr[$value];
+ }
+ $spe_price_id = implode('-',$spe_id);
+
+ $ins['uniacid'] = $this->_uniacid;
+
+ $ins['goods_id']= $good_id;
+
+ $ins['spe_id_1']= $spe_price_id;
+
+ $ins['price'] = $v['price'];
+
+ $ins['stock'] = $v['stock'];
+
+// $ins['alert_stock'] = $v['alert_stock'];
+
+ $ins['status'] = 1;
+ //原价
+ $ins['original_price'] = !empty($v['original_price'])?$v['original_price']:0;
+ //成本价
+ $ins['cost_price'] = !empty($v['cost_price'])?$v['cost_price']:0;
+
+ $spe_price = $this->spe_price_model->singeSpePrice(['goods_id'=>$good_id,'spe_id_1'=>$spe_price_id,'uniacid'=>$this->_uniacid]);
+
+ if(empty($spe_price)) {
+
+ $res = $this->spe_price_model->goodsSpePriceAdd($ins);
+
+ }else{
+
+ $res = $this->spe_price_model->goodsSpePriceUpdate(['id'=>$spe_price['id']],$ins);
+ }
+ }
+ }
+ return !empty($res)?$res:1;
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminLand.php b/app/farm/controller/AdminLand.php
new file mode 100755
index 0000000..4b31fd9
--- /dev/null
+++ b/app/farm/controller/AdminLand.php
@@ -0,0 +1,1172 @@
+model = new LandList();
+
+ $this->cate_model = new LandCate();
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:42
+ * @功能说明:认养分类列表
+ */
+ public function landCateList(){
+
+ $input = $this->_param;
+
+ $cate_model = new LandCate();
+
+ $dis = [
+
+ 'type' => 1,
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ $data = $cate_model->where($dis)->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+// /**
+// * @author chenniang
+// * @DataTime: 2021-12-14 17:53
+// * @功能说明:土地列表
+// */
+// public function landList(){
+//
+// $input = $this->_param;
+//
+// $input['sort'] = !empty($input['sort'])?$input['sort']:1;
+//
+// $dis[] = ['uniacid','=',$this->_uniacid];
+//
+// $dis[] = ['status','=',1];
+//
+// if(!empty($input['cate_id'])){
+//
+// $dis[] = ['cate_id','=',$input['cate_id']];
+// }
+//
+// if(!empty($input['title'])){
+//
+// $dis[] = ['title','like','%'.$input['title'].'%'];
+//
+// }
+//
+// if(!empty($input['farmer_id'])){
+//
+// $dis[] = ['farmer_id','=',$input['farmer_id']];
+// }
+//
+// $lat = !empty($input['lat'])?$input['lat']:0;
+//
+// $lng = !empty($input['lng'])?$input['lng']:0;
+//
+// $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(PI()*('.$lng.'- `lng`)/360),2)+COS(PI()*33.07078170776367/180)* COS('.$lat.' * PI()/180)*POW(SIN(PI()*('.$lat.'- lat)/360),2))))*1000 as distance';
+//
+// $data = $this->model->indexDataList($dis,$alh,$input['sort']);
+//
+// return $this->success($data);
+//
+// }
+
+
+// /**
+// * @author chenniang
+// * @DataTime: 2021-12-16 10:34
+// * @功能说明:土地详情
+// */
+// public function landInfo(){
+//
+// $input = $this->_param;
+//
+// $dis = [
+//
+// 'id' => $input['id']
+// ];
+//
+// $data = $this->model->landInfo($dis);
+//
+// $farmer_model = new Farmer();
+// //农场主消息
+// $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']],'mobile,title,cover');
+//
+// $app_num = 0;
+//
+// if(!empty($data['spe'])){
+//
+// $order_model = new LandOrder();
+//
+// foreach ($data['spe'] as &$v){
+//
+// $dis = [
+//
+// 'land_id' => $input['id'],
+//
+// 'spe_id' => $v['id']
+// ];
+//
+// $v['is_app'] = $order_model->where($dis)->where('pay_type','>',1)->find();
+//
+// $v['is_app'] = !empty($v['is_app'])?1:0;
+//
+// if($v['is_app']==1){
+//
+// $app_num ++;
+// }
+//
+// }
+//
+// }
+//
+// $data['spe_info'] = [
+// //总数量
+// 'all_num' => count($data['spe']),
+// //已被预约数量
+// 'app_num' => $app_num
+//
+// ];
+//
+// return $this->success($data);
+//
+// }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-11 11:24
+ * @功能说明:土地预支付信息
+ */
+ public function landPayOrderInfo(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $farmer_model = new Farmer();
+
+ $data = $order_model->payOrderInfo($input);
+
+ if(!empty($data['code'])){
+
+ $this->errorMsg($data['msg']);
+ }
+
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['land']['farmer_id']],'title');
+
+ $address_model = new OrderAddress();
+ //地址
+ $data['address']= $address_model->dataInfo(['id'=>$input['address_id']]);
+
+ return $this->success($data);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 10:57
+ * @功能说明:土地下单
+ */
+ public function landPayOrder(){
+
+ $input = $this->_input;
+
+ $address_model = new OrderAddress();
+
+ $order_model = new LandOrder();
+
+ $land_seed_model= new LandOrderSeed();
+
+ $pay_order = $order_model->payOrderInfo($input);
+
+ if(!empty($pay_order['code'])){
+
+ $this->errorMsg($pay_order['msg']);
+ }
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'pay_type' => 1,
+
+ 'order_code' => orderCode(),
+
+ 'user_id' => $this->getUserId(),
+
+ 'land_id' => $input['land_id'],
+
+ 'pay_price' => $pay_order['pay_price'],
+
+ 'farmer_id' => $pay_order['land']['farmer_id'],
+
+ 'goods_name' => $pay_order['land']['title'],
+
+ 'goods_cover' => $pay_order['land']['cover'],
+
+ 'massif_id' => $input['massif_id'],
+
+ 'spe_id' => $input['spe_id'],
+
+ 'spe_name' => $pay_order['spe']['spe_name'],
+
+ 'area' => $pay_order['spe']['area'],
+
+ 'land_price' => $pay_order['land_price'],
+
+ 'seed_price' => $pay_order['seed_price'],
+
+ 'cycle' => $input['cycle'],
+ //到期时间
+ 'end_time' => $input['cycle']*86400+time(),
+
+ 'rent_mobile' => $input['rent_mobile'],
+
+ 'rent_user_name'=> $input['rent_user_name'],
+
+ 'massif_price' => $pay_order['massif']['price'],
+
+ 'massif_title' => $pay_order['massif']['title'],
+
+ 'total_massif_price' => $pay_order['total_massif_price'],
+ //
+ 'over_time' => time()+$this->_config['over_time']*60,
+
+ 'send_type' => $input['send_type'],
+
+ ];
+
+ Db::startTrans();
+
+ $res = $order_model->dataAdd($order_insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+
+ $order_id = $order_model->getLastInsID();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $address_model->orderAddressAdd($input['address_id'],$order_id,$input['send_type'],1,$input);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+
+ if(!empty($pay_order['seed'])){
+
+ $res = $land_seed_model->orderSeedAdd($pay_order['seed'],$order_id);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+ }
+
+ Db::commit();
+ //如果是0元
+ if($order_insert['pay_price']<=0){
+
+ $order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if(!empty($input['is_balance'])){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"土地订单",['type' => 'Land' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 10:17
+ * @功能说明:土地重新下单
+ */
+ public function landRePayOrder(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $order_insert = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+ }
+ //余额支付
+ if(!empty($input['is_balance'])){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"认养订单",['type' => 'Claim' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 18:03
+ * @功能说明:种子列表
+ */
+ public function seedList(){
+
+ $input = $this->_param;
+
+ $land_text_model = new LandText();
+
+ $obj = $land_text_model->where(['land_id'=>$input['land_id'],'type'=>2])->column('obj_id');
+
+ $dis[] = ['a.status','=',1];
+
+ $dis[] = ['a.id','in',$obj];
+ //查询当前季节
+ if(!empty($input['season'])){
+
+ $month = date('m',time());
+
+ $season = ceil($month/3);
+
+ $dis[] = ['b.season','=',$season];
+ }
+
+ $seed_model = new Seed();
+ //种子
+ $data = $seed_model->indexDataList($dis,$input['sort']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 18:17
+ * @功能说明:种子详情
+ */
+ public function seedInfo(){
+
+ $input = $this->_param;
+
+ $seed_model = new Seed();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+ //种子
+ $data = $seed_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:26
+ * @功能说明:用户下单列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $order_model = new LandOrder();
+
+ $farmer_model = new Farmer();
+
+ $user_model = new User();
+ //初始化订单
+ $order_model->orderInit();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['a.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['b.mobile','like','%'.$input['mobile'].'%'];
+
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $order_model->adminDataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id'=>$v['farmer_id']],'title');
+
+ $v['user_info'] = $user_model->dataInfo(['id'=>$v['user_id']]);
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:52
+ * @功能说明:用户下单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $farmer_model = new Farmer();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new LandOrder();
+
+ $seed_model = new LandOrderSeed();
+
+ $data = $order_model->dataInfo($dis);
+ //农场信息
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']]);
+ //是否可以配送
+ $data['can_send'] = $data['pay_type']>1&&$data['end_time']orderSeed($data['id']);
+
+ $address_model = new OrderAddress();
+
+ $data['address_info'] = $address_model->dataInfo(['order_id'=>$input['id'],'type'=>1]);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 13:42
+ * @功能说明:
+ */
+ public function cancelOrder(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order = $order_model->dataInfo($dis);
+
+ if($order['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $order_model->cancelOrder($order);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 13:53
+ * @功能说明:申请认养订单发货
+ */
+ public function sendOrderApply(){
+
+ $input = $this->_input;
+
+ $order_model = new ClaimOrder();
+
+ $farmer_model= new Farmer();
+
+ $config_model= new Config();
+
+ $address_model = new Address();
+
+ $send_order_model = new SendOrder();
+
+ $order = $order_model->dataInfo(['id'=>$input['order_id']]);
+
+ $times = $send_order_model->where(['order_id'=>$input['order_id'],'type'=>2])->where('pay_time','>',0)->count();
+
+ $farmer= $farmer_model->dataInfo(['id'=>$order['farmer_id']]);
+
+ if(empty($farmer)){
+
+ $this->errorMsg('农场主未找到');
+ }
+
+ $send_price = $distance = 0;
+ //快递
+ if($input['send_type']==2){
+
+ $address = $address_model->dataInfo(['id'=>$input['address_id']]);
+
+ if(empty($address)){
+
+ $this->errorMsg('地址信息未找到');
+
+ }
+
+ $distance = getdistance($address['lng'],$address['lat'],$farmer['lng'],$farmer['lat']);
+
+ $distance = round($distance/1000,2);
+
+ $send_price = $config_model->getSendPrice($distance,$this->_uniacid);
+
+ }else{
+
+ $address['user_name'] = $input['user_name'];
+
+ $address['mobile'] = $input['mobile'];
+
+ }
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'order_id' => $input['order_id'],
+
+ 'user_id' => $order['user_id'],
+
+ 'farmer_id' => $order['farmer_id'],
+
+ 'pay_price' => $send_price,
+
+ 'order_code' => orderCode(),
+
+ 'text' => $input['text'],
+ //
+ 'over_time' => time()+$this->_config['over_time']*60,
+
+ 'type' => 2,
+
+ 'start_time' => $input['start_time'],
+
+ 'end_time' => $input['end_time'],
+
+ 'times' => $times+1,
+
+ 'send_type' => $input['send_type'],
+
+ 'address' => $input['send_type']==2?$address['address'].$address['address_info']:'',
+
+ 'user_name' => $address['user_name'],
+
+ 'mobile' => $address['mobile'],
+
+ 'lng' => $input['send_type']==2?$address['lng']:'',
+
+ 'lat' => $input['send_type']==2?$address['lat']:'',
+
+ 'balance' => !empty($input['is_balance'])?$send_price:0,
+
+ ];
+
+ $res = $send_order_model->dataAdd($order_insert);
+
+ if($res==0){
+
+ $this->errorMsg('申请配送失败');
+ }
+ //如果是0元
+ if($order_insert['pay_price']<=0){
+
+ $send_order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if(!empty($input['is_balance'])){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $send_order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"认养配送订单",['type' => 'ClaimSend' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 15:23
+ * @功能说明:配送订单下单详情
+ */
+ public function sendOrderPayInfo(){
+
+ $input = $this->_param;
+
+ $order_model = new LandOrder();
+
+ $farmer_model= new Farmer();
+
+ $config_model= new Config();
+
+ $address_model = new Address();
+
+ $order = $order_model->dataInfo(['id'=>$input['order_id']]);
+
+ $farmer= $farmer_model->dataInfo(['id'=>$order['farmer_id']]);
+
+ if(empty($farmer)){
+
+ $this->errorMsg('农场主未找到');
+ }
+
+ $address = $address_model->dataInfo(['id'=>$input['address_id']]);
+
+ if(empty($address)){
+
+ $this->errorMsg('地址信息未找到');
+
+ }
+ $distance = getdistance($address['lng'],$address['lat'],$farmer['lng'],$farmer['lat']);
+
+ $distance = round($distance/1000,2);
+
+ $send_price = $config_model->getSendPrice($distance,$this->_uniacid);
+
+ $data['send_price'] = $send_price;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:14
+ * @功能说明:配送订单列表
+ */
+ public function userSendOrderList(){
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $data = $send_order_model->orderSendOrder($input['land_order_id'],2,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 14:00
+ * @功能说明:配送订单详情
+ */
+ public function sendOrderInfo()
+ {
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $claim_order_model = new LandOrder();
+
+ $send_order = $send_order_model->dataInfo(['id' => $input['id']]);
+
+ $send_order['create_time'] = date('Y-m-d H:i:s', $send_order['create_time']);
+
+ $send_order['time_text'] = date('Y-m-d H:i', $send_order['start_time']) . '~' . date('H:i', $send_order['end_time']);
+
+ $send_order['pay_time'] = $send_order['pay_time'] > 0 ? date('Y-m-d H:i:s', $send_order['pay_time']) : 0;
+
+ $send_order['send_time'] = $send_order['send_time'] > 0 ? date('Y-m-d H:i:s', $send_order['send_time']) : 0;
+
+ $send_order['receiving_time'] = $send_order['receiving_time'] > 0 ? date('Y-m-d H:i:s', $send_order['receiving_time']) : 0;
+
+ $send_order['refund_time'] = $send_order['refund_time'] > 0 ? date('Y-m-d H:i:s', $send_order['refund_time']) : 0;
+
+ $send_order['claim_order'] = $claim_order_model->dataInfo(['id' => $send_order['order_id']]);
+
+ return $this->success($send_order);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:57
+ * @功能说明:配送订单退款
+ */
+ public function sendOrderRefund(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ Db::startTrans();
+
+ if($send_order['send_type']==2&&$send_order['pay_price']>0&&$send_order['balance']<=0){
+ //微信退款
+ $response = orderRefundApi($this->payConfig($this->_uniacid),$send_order['pay_price'],$send_order['pay_price'],$send_order['transaction_id']);
+
+ }else{
+ //余额或者自提或者0元
+ $response[ 'return_code' ] = 'SUCCESS';
+
+ $response[ 'result_code' ] = 'SUCCESS';
+ }
+ //余额退款
+ if($send_order['balance']>0){
+
+ $water_model = new BalanceWater();
+
+ $res = $water_model->addWater($send_order,4,1);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败2');
+ }
+
+ }
+ //增加财务流水
+ $fin_water_model = new FinanceWater();
+
+ $res = $fin_water_model->addWater($input['id'],13,1,1);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败1');
+ }
+
+ $res = $fin_water_model->dataUpdate(['order_id'=>$send_order['id'],'type'=>14],['cash_status'=>-1]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败3');
+ }
+ //如果退款成功修改一下状态
+ if ( isset( $response[ 'return_code' ] ) && isset( $response[ 'result_code' ] ) && $response[ 'return_code' ] == 'SUCCESS' && $response[ 'result_code' ] == 'SUCCESS' ) {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no'])?$response['out_refund_no']:$send_order['order_code'];
+
+ $send_order_model->dataUpdate(['id'=>$send_order['id']],['refund_code'=>$response['out_refund_no'],'refund_time'=>time(),'pay_type'=>-1,'refund'=>1]);
+
+ }else {
+
+ Db::rollback();
+ //失败就报错
+ $discption = !empty($response['err_code_des'])?$response['err_code_des']:$response['return_msg'];
+
+ $this->errorMsg($discption);
+
+ }
+ Db::commit();
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 10:24
+ * @功能说明:配送订单收货
+ */
+ public function sendOrderReceiving(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $send_order_model->sendOrderReceiving($send_order);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:51
+ * @功能说明:土地列表
+ */
+ public function landList(){
+
+ $input = $this->_param;
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(isset($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['status','>',-1];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $farmer_model = new Farmer();
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_name'] = $farmer_model->where(['id'=>$v['farmer_id']])->value('title');
+
+ $cate_name = $this->cate_model->where('id','in',$v['cate_id'])->column('title');
+
+ $v['cate_name'] = implode(',',$cate_name);
+
+ }
+ }
+
+ $arr = [
+
+ 0 => 'off_num',
+
+ 1 => 'on_num',
+ ];
+
+ foreach ($arr as $key => $value){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => $key
+ ];
+
+ $data[$value] = $this->model->where($dis)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:添加土地
+ */
+ public function landAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:编辑土地
+ */
+ public function landUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:编辑土地
+ */
+ public function landStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $res = $this->model->where($dis)->update($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:土地详情
+ */
+ public function landInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->model->landInfo($dis);
+
+ $data['text'] = html_entity_decode($data['text']);
+
+ $data['massif'] = array_values(array_column($data['massif'],'id'));
+
+ $data['monitor'] = array_values(array_column($data['monitor'],'id'));
+
+ $data['seed'] = array_values(array_column($data['seed'],'id'));
+
+ $freightTemplate_model = new FreightTemplate();
+
+ $res['send_template_type'] = $freightTemplate_model->where(['id'=>$data['send_tmpl_id']])->value('type');
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminMassif.php b/app/farm/controller/AdminMassif.php
new file mode 100755
index 0000000..e52ac85
--- /dev/null
+++ b/app/farm/controller/AdminMassif.php
@@ -0,0 +1,175 @@
+model = new BalanceCard();
+
+ $this->massif_model = new Massif();
+
+ $this->land_model = new LandList();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:43
+ * @功能说明:地块列表
+ */
+ public function massifList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->massif_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:43
+ * @功能说明:地块列表下拉框
+ */
+ public function massifSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->massif_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:49
+ * @功能说明:添加地块
+ */
+ public function massifAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->massif_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑地块
+ */
+ public function massifUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+ //删除
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $find = $this->land_model->landSomeFind($input['id'],1);
+
+ if($find==1){
+
+ $this->errorMsg('该地块服务正在被使用');
+ }
+
+ }
+
+ $data = $this->massif_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:地块详情
+ */
+ public function massifInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->massif_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+}
diff --git a/app/farm/controller/AdminOrder.php b/app/farm/controller/AdminOrder.php
new file mode 100755
index 0000000..84d735b
--- /dev/null
+++ b/app/farm/controller/AdminOrder.php
@@ -0,0 +1,451 @@
+model = new ShopOrder();
+
+ $this->refund_model = new ShopRefund();
+
+ $this->order_goods_model = new ShopOrderGoods();
+
+ autoCancelOrder($this->_uniacid);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['d.mobile','like','%'.$input['mobile'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['store_id'])){
+
+ $dis[] = ['a.store_id','=',$input['store_id']];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->model->adminDataList($dis,$input['limit']);
+
+ $arr = [
+ //未支付
+ 'no_pay_count' => 1,
+ //未发货
+ 'no_send_count' => 2,
+ //已经发货
+ 'have_send_count'=> 3
+ ];
+
+ foreach ($arr as $ks=>$vs){
+
+ $map = [
+
+ 'pay_type'=> $vs
+ ];
+
+ $data[$ks] = $this->model->where($map)->count();
+ }
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['hx_time'] = date('Y-m-d H:i:s',$data['hx_time']);
+ //剩余可申请退款数量
+ $can_refund_num = array_sum(array_column($data['order_goods'],'can_refund_num'));
+ //是否可以申请退款
+ if(($data['pay_type']==7&&$data['can_refund_time']>time()&&$can_refund_num>0)||($data['pay_type']==2&&$can_refund_num>0)){
+
+ $data['can_refund'] = 1;
+
+ }else{
+
+ $data['can_refund'] = 0;
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:29
+ * @功能说明:退款订单详情
+ *
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $where = [];
+
+ if(!empty($input['order_code'])){
+
+ $where[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ $where[] = ['d.order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+// if(!empty($input['order_code'])){
+//
+// $dis[] = ['d.order_code','like','%'.$input['order_code'].'%'];
+//
+// }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $data = $this->refund_model->indexDataList($dis,$where,$input['limit']);
+
+ $map = [
+
+ 'status' => 1,
+
+// 'user_id'=> $this->getUserId()
+ ];
+ //退款中数量
+ $data['ing_count'] = $this->refund_model->where($map)->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->refund_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ $order_model = new ShopOrder();
+
+ $data['pay_order_code'] = $order_model->where(['id'=>$data['order_id']])->value('order_code');
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:14
+ * @功能说明:楼长核销订单
+ */
+ public function endOrder(){
+
+ $input = $this->_input;
+
+ $order_model= new ShopOrder();
+
+ $order = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+ //自提
+ if($order['send_type']==1&&$order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+ //快递
+ if($order['send_type']==2&&$order['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ if($order['send_type']==1){
+
+ $user_model = new \app\massage\model\User();
+
+ $role = $user_model->where(['id'=>$this->getUserId()])->value('role');
+
+ if($role!=1){
+
+ $this->errorMsg('只有管理员才能核销');
+ }
+ }
+
+ $refund_model = new ShopRefund();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $order_model->hxOrder($input['id'],$this->getUserId());
+
+ return $this->success($res);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:21
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund(){
+
+ $input = $this->_input;
+
+ $refund_order_model = new ShopRefund();
+
+ $res = $refund_order_model->noPassRefund($input['id'],$this->_user['id'],1);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**\
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:28
+ * @功能说明:同意退款
+ */
+ public function passRefund(){
+
+ $input = $this->_input;
+
+ $refund_order_model = new ShopRefund();
+
+ $res = $refund_order_model->passOrder($input['id'],$input['price'],$this->payConfig(),$this->_user['id'],$input['text'],1);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 11:08
+ * @功能说明:地主商城订单发货
+ */
+ public function shopOrderSend(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new ShopOrder();
+
+ $order = $order_model->dataInfo($dis);
+
+ if(empty($order)||$order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+ $refund_model = new ShopRefund();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$input['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $update = [
+
+ 'pay_type' => 3,
+
+// 'express_company' => $input['express_company'],
+//
+// 'express_code' => $input['express_code'],
+//
+// 'express_mobile' => $input['express_mobile'],
+//
+// 'express_user' => $input['express_user'],
+
+ 'send_time' => time(),
+
+ 'hx_over_time' => time()+$config['auto_hx_time']*86400,
+
+ ];
+
+ $data = $order_model->dataUpdate($dis,$update);
+
+// $water_model = new FinanceWater();
+// //商城订单农场主获得运费
+// $water_model->addWater($order['id'],16,1,0);
+
+ $order = $order_model->dataInfo($dis);
+
+ $order_model->sendOrderService($order);
+
+ $sys_model = new PushMsgModel($order['uniacid']);
+
+ $sys_model->sendMsg($order,4);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 15:27
+ * @功能说明:上传视频
+ */
+ public function uploadVideo(){
+
+ $input = $this->_input;
+
+ $res = $this->model->dataUpdate(['id'=>$input['id']],['video'=>$input['video']]);
+
+ return $this->success($res);
+
+ }
+
+
+}
diff --git a/app/farm/controller/AdminReseller.php b/app/farm/controller/AdminReseller.php
new file mode 100755
index 0000000..bee3ebc
--- /dev/null
+++ b/app/farm/controller/AdminReseller.php
@@ -0,0 +1,436 @@
+model = new DistributionList();
+
+ $this->cash_model = new DistributionCash();
+
+ $this->user_model = new User();
+
+ $this->wallet_model = new Wallet();
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function resellerList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['a.user_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.mobile','like','%'.$input['name'].'%'];
+ }
+
+ $data = $this->model->adminDataList($dis,$input['limit'],$where);
+
+ $list = [
+
+ 0=>'all',
+
+ 1=>'ing',
+
+ 2=>'pass',
+
+ 4=>'nopass'
+ ];
+
+ foreach ($list as $k=> $value){
+
+ $dis_s = [];
+
+ $dis_s[] =['uniacid','=',$this->_uniacid];
+
+ if(!empty($k)){
+
+ $dis_s[] = ['status','=',$k];
+
+ }else{
+
+ $dis_s[] = ['status','>',-1];
+
+ }
+
+ $data[$value] = $this->model->where($dis_s)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 10:17
+ * @功能说明:用户管理列表
+ */
+ public function userRelationshipList(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'is_fx' => 1
+ ];
+
+ $data = $this->user_model->where($dis)->field('id,avatarUrl,nickName,pid,fx_bind_time,fx_cash')->order('fx_bind_time')->paginate($input['limit'])->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['top_info'] = $this->user_model->where(['id'=>$v['pid'],'is_fx'=>1])->field('nickName,avatarUrl')->find();
+ //产生收益
+ $v['total_fx_cash'] = $this->cash_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('cash');
+ //累计提现
+ $v['wallte_cash'] = $this->wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('pay_price');
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 10:49
+ * @功能说明:分销关系查找
+ */
+ public function userRelationshipListFind(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'is_fx' => 1
+ ];
+
+ if($input['type']==1){
+ //自己
+ $dis['id'] = $input['user_id'];
+
+ }elseif ($input['type']==2){
+ //下级
+ $dis['pid'] = $input['user_id'];
+
+ }else{
+ //上级
+ $top_id = $this->user_model->where(['id'=>$input['user_id'],'is_fx'=>1])->value('pid');
+
+ $dis['id'] = $top_id;
+ }
+
+ $data = $this->user_model->where($dis)->field('id,avatarUrl,nickName,pid,fx_bind_time,fx_cash')->order('fx_bind_time')->paginate($input['limit'])->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //产生收益
+ $v['total_fx_cash'] = $this->cash_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('cash');
+ //累计提现
+ $v['wallte_cash'] = $this->wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('pay_price');
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:分销商详情
+ */
+ public function resellerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $user_model = new User();
+
+ $data['nickName'] = $user_model->where(['id'=>$data['user_id']])->value('nickName');
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-03 00:15
+ * @功能说明:审核(2通过,3取消,4拒绝)
+ */
+ public function resellerUpdate(){
+
+ $input = $this->_input;
+
+ $diss = [
+
+ 'id' => $input['id']
+ ];
+
+ $info = $this->model->dataInfo($diss);
+
+ if(!empty($input['status'])&&in_array($input['status'],[2,4,-1])){
+
+ $input['sh_time'] = time();
+
+ if($input['status']==-1){
+
+ $fx_cash = $this->user_model->where(['id'=>$info['user_id']])->sum('fx_cash');
+
+ if($fx_cash>0){
+
+ $this->errorMsg('分销商还有佣金未提现');
+ }
+
+ $dis = [
+
+ 'user_id' => $info['user_id'],
+
+ 'status' => 1
+ ];
+
+ $cash = $this->cash_model->dataInfo($dis);
+
+ if(!empty($cash)){
+
+ $this->errorMsg('分销商还有佣金未到账');
+
+ }
+
+ $dis['type'] = 5;
+
+ $wallet = $this->wallet_model->dataInfo($dis);
+
+ if(!empty($wallet)){
+
+ $this->errorMsg('分销商还有提现未处理');
+
+ }
+
+ }
+ }
+
+ $data = $this->model->dataUpdate($diss,$input);
+
+ if(isset($input['status'])){
+
+ $update = [
+
+ 'is_fx' => 0
+ ];
+
+ if($input['status']==2){
+
+ $update['fx_bind_time'] = time();
+
+ // $update['pid'] = $info['pid'];
+
+ $update['is_fx'] = 1;
+
+ }
+
+ $this->user_model->dataUpdate(['id'=>$info['user_id']],$update);
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 11:30
+ * @功能说明:分销佣金详情
+ */
+ public function cashList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.user_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['c.nickName','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->cash_model->adminCashList($dis,$where,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['source_info'] = $this->user_model->where(['id'=>$v['source_id']])->field('nickName,avatarUrl')->find();
+
+ $v['order_price'] = array_sum(array_column($v['order_goods'],'pay_price'));
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 14:48
+ * @功能说明:用户收益列表
+ */
+ public function userProfitList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['a.nickName','like','%'.$input['name'].'%'];
+
+ $where[] = ['b.user_name','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->userProfitList($dis,$input['limit'],$where);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //产生收益
+ $v['total_fx_cash'] = $this->cash_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('cash');
+ //未入账
+ $v['unrecorded_fx_cash'] = $this->cash_model->where(['user_id'=>$v['id']])->where('status','in',[1])->sum('cash');
+ //累计提现
+ $v['total_wallte_cash'] = $this->wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1,2])->sum('pay_price');
+ //提现中
+ $v['wallte_ing_cash'] = $this->wallet_model->where(['user_id'=>$v['id']])->where('status','in',[1])->sum('pay_price');
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminSeed.php b/app/farm/controller/AdminSeed.php
new file mode 100755
index 0000000..f7fbe90
--- /dev/null
+++ b/app/farm/controller/AdminSeed.php
@@ -0,0 +1,218 @@
+model = new BalanceCard();
+
+ $this->massif_model = new Massif();
+
+ $this->land_model = new LandList();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:54
+ * @功能说明:种子列表
+ */
+ public function seedList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ // $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:54
+ * @功能说明:种子列表
+ */
+ public function seedSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:57
+ * @功能说明:添加种子
+ */
+ public function seedAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑种子
+ */
+ public function seedUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $seed_model = new Seed();
+ //删除
+ if(isset($input['status'])&&in_array($input['status'],[-1,0])){
+
+ $find = $this->land_model->landSomeFind($input['id'],2);
+
+ if($find==1){
+
+ $this->errorMsg('该种子正在被使用');
+ }
+
+ }
+
+ $data = $seed_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑种子
+ */
+ public function seedInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑种子
+ */
+ public function seedStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->where($dis)->update($input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminSetting.php b/app/farm/controller/AdminSetting.php
new file mode 100755
index 0000000..f96868f
--- /dev/null
+++ b/app/farm/controller/AdminSetting.php
@@ -0,0 +1,861 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function configInfo(){
+
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:14
+ * @功能说明:编辑配置
+ */
+ public function configUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ if(!empty($input['app_banner'])){
+
+ $input['app_banner'] = implode(',',$input['app_banner']);
+ }
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:15
+ * @功能说明:banner列表
+ */
+ public function bannerList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+
+ }
+
+ $banner_model = new Banner();
+
+ $data = $banner_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:18
+ * @功能说明:添加banner
+ */
+ public function bannerAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:20
+ * @功能说明:编辑banner
+ */
+ public function bannerUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $banner_model = new Banner();
+
+ $input['uniacid'] = $this->_uniacid;
+
+
+ $res = $banner_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:27
+ * @功能说明:banner详情
+ */
+ public function bannerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataInfo($dis);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:27
+ * @功能说明:新闻列表
+ */
+ public function articleList(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $article_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:37
+ * @功能说明:添加文章
+ *
+ */
+ public function articleAdd(){
+
+ $input = $this->_input;
+
+ $article_model = new Article();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $article_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:编辑文章
+ */
+ public function articleUpdate(){
+
+ $input = $this->_input;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $article_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:文章详情
+ */
+ public function articleInfo(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $article_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:50
+ * @功能说明:文章下拉框
+ */
+ public function articleSelect(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $res = $article_model->where($dis)->field('id,title')->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:53
+ * @功能说明:支付配置详情
+ */
+ public function payConfigInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $pay_model = new PayConfig();
+
+ $data = $pay_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:55
+ * @功能说明:编辑支付配置
+ */
+ public function payConfigUpdate(){
+
+ $input = $this->_input;
+
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+
+ if(isset($input['cert_path'])&&isset($input['key_path'])){
+
+ if(!strstr($input['cert_path'],FILE_UPLOAD_PATH)){
+
+ $input['cert_path'] = FILE_UPLOAD_PATH.$input['cert_path'];
+
+ }
+ if(!strstr($input['key_path'],FILE_UPLOAD_PATH)){
+
+ $input['key_path'] = FILE_UPLOAD_PATH.$input['key_path'];
+ }
+ }
+
+ $pay_model = new PayConfig();
+
+ $data = $pay_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-31 15:16
+ * @功能说明:修改密码
+ */
+ public function updatePass(){
+
+ $input = $this->_input;
+
+ $admin = new \app\farm\model\Admin();
+
+ $update = [
+
+ 'passwd' => checkPass($input['pass']),
+ ];
+
+ $res = $admin->dataUpdate(['uniacid'=>$this->_uniacid],$update);
+
+
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function msgConfigInfo(){
+
+ $msg_model = new MsgConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $msg_model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:14
+ * @功能说明:编辑配置
+ */
+ public function msgConfigUpdate(){
+
+ $input = $this->_input;
+
+ $msg_model = new MsgConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $msg_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 11:58
+ * @功能说明:桌号列表
+ */
+ public function tableList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $table_model = new Table();
+
+ $data = $table_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:21
+ * @功能说明:添加桌号
+ */
+ public function tableAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $table_model = new Table();
+
+ $res = $table_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:23
+ * @功能说明:编辑桌号
+ */
+ public function tableUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $table_model = new Table();
+
+ $res = $table_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:23
+ * @功能说明:桌号详情
+ */
+ public function tableInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $table_model = new Table();
+
+ $res = $table_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-09 15:15
+ * @功能说明:刷新桌号码
+ */
+ public function reTableQr(){
+
+ $input = $this->_input;
+
+ $qr_insert = [
+
+ 'id' => $input['id']
+ ];
+
+ $table_model = new Table();
+
+ $qr = $table_model->orderQr($qr_insert,$this->_uniacid);
+
+ if(!empty($qr)){
+
+ $table_model->dataUpdate(['id'=>$input['id']],['qr'=>$qr]);
+
+ }
+
+ return $this->success($qr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:51
+ * @功能说明:关于我们列表
+ */
+ public function aboutUsList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['type','=',0];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $us_model = new AboutUs();
+
+ $data = $us_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:21
+ * @功能说明:添加我们列表
+ */
+ public function aboutUsAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $us_model = new AboutUs();
+
+ $res = $us_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:23
+ * @功能说明:编辑我们列表
+ */
+ public function aboutUsUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $us_model = new AboutUs();
+
+ $res = $us_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:23
+ * @功能说明:我们列表详情
+ */
+ public function aboutUsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id'],
+
+ ];
+
+ $us_model = new AboutUs();
+
+ $res = $us_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:23
+ * @功能说明:我们列表详情
+ */
+ public function aboutUsInfoType(){
+
+ $input = $this->_param;
+
+ $input['type'] = !empty($input['type'])?$input['type']:0;
+
+ $dis = [
+
+ 'type'=> $input['type'],
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $us_model = new AboutUs();
+
+ $res = $us_model->dataInfo($dis);
+
+ if(!empty($input['type'])&&empty($res)){
+
+ $title = $input['type']==1?'动物认养协议':'土地租赁协议';
+
+ $dis['title'] = $title;
+
+ $us_model->dataAdd($dis);
+
+ $res = $us_model->dataInfo($dis);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-11 10:48
+ * @功能说明:配送配置详情
+ */
+ public function sendConfigInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $config = $this->model->dataInfo($dis);
+
+ $send_model = new SendConfig();
+
+ $send_config = $send_model->where($dis)->select()->toArray();
+
+ $config['send_time'] = $send_config;
+
+ return $this->success($config);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-11 11:51
+ * @功能说明:编辑配送设置
+ */
+ public function sendConfigUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+
+ ];
+
+ $update = [
+
+ 'app_day' => $input['app_day'],
+
+ // 'start_distance' => $input['start_distance'],
+
+// 'start_price' => $input['start_price'],
+//
+// 'renew_distance' => $input['renew_distance'],
+//
+// 'renew_price' => $input['renew_price'],
+
+ ];
+
+ $res = $this->model->dataUpdate($dis,$update);
+
+ $send_model = new SendConfig();
+
+ $send_model->where($dis)->delete();
+
+ if(!empty($input['send_time'])){
+
+ foreach ($input['send_time'] as $key => $value){
+
+ $input['send_time'][$key]['uniacid'] = $this->_uniacid;
+
+ }
+
+ $send_model->saveAll($input['send_time']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:27
+ * @功能说明:公益栏目列表
+ */
+ public function welfareList(){
+
+ $input = $this->_param;
+
+ $welfare_model = new WelfareColumn();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $type = !empty($input['type'])?$input['type']:1;
+
+ $dis[] = ['type','=',$type];
+
+ $data = $welfare_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:37
+ * @功能说明:添加公益栏目
+ *
+ */
+ public function welfareAdd(){
+
+ $input = $this->_input;
+
+ $welfare_model = new WelfareColumn();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $welfare_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:编辑公益栏目
+ */
+ public function welfareUpdate(){
+
+ $input = $this->_input;
+
+ $welfare_model = new WelfareColumn();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $welfare_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:公益栏目详情
+ */
+ public function welfareInfo(){
+
+ $input = $this->_param;
+
+ $welfare_model = new WelfareColumn();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $welfare_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/AdminSource.php b/app/farm/controller/AdminSource.php
new file mode 100755
index 0000000..88c6e3d
--- /dev/null
+++ b/app/farm/controller/AdminSource.php
@@ -0,0 +1,190 @@
+model = new BalanceCard();
+
+ $this->massif_model = new Massif();
+
+ $this->land_model = new LandList();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:04
+ * @功能说明:溯源列表
+ */
+ public function sourceList(){
+
+ $input = $this->_param;
+
+ $source_model = new Source();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ $data = $source_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:04
+ * @功能说明:溯源下拉框
+ */
+ public function sourceSelect(){
+
+ $input = $this->_param;
+
+ $source_model = new Source();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['farmer_id','=',$input['farmer_id']];
+ }
+
+ $data = $source_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:10
+ * @功能说明:添加溯源
+ */
+ public function sourceAdd(){
+
+ $input = $this->_input;
+
+ $source_model = new Source();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $source_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:12
+ * @功能说明:编辑溯源
+ */
+ public function sourceUpdate(){
+
+ $input = $this->_input;
+
+ $source_model = new Source();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+ //删除
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $find = $this->land_model->landSomeFind($input['id'],3);
+
+ if($find==1){
+
+ $this->errorMsg('该溯源正在被使用');
+ }
+
+ }
+
+ $res = $source_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:12
+ * @功能说明:编辑溯源
+ */
+ public function sourceInfo(){
+
+ $input = $this->_param;
+
+ $source_model = new Source();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $source_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+
+}
diff --git a/app/farm/controller/AdminUser.php b/app/farm/controller/AdminUser.php
new file mode 100755
index 0000000..2c60f83
--- /dev/null
+++ b/app/farm/controller/AdminUser.php
@@ -0,0 +1,852 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 10:24
+ * @功能说明:用户列表
+ */
+ public function userList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //是否授权
+ if(!empty($input['type'])){
+
+ if($input['type']==1){
+
+ $dis[] = ['avatarUrl','=',''];
+
+ }else{
+
+ $dis[] = ['avatarUrl','<>',''];
+
+ }
+
+ }
+
+ if(isset($input['role'])){
+
+ $dis[] = ['role','=',$input['role']];
+ }
+
+ if(isset($input['is_black'])){
+
+ $dis[] = ['is_black','=',$input['is_black']];
+ }
+
+ $where = [];
+
+ if(!empty($input['nickName'])){
+
+ $where[] = ['nickName','like','%'.$input['nickName'].'%'];
+
+ $where[] = ['phone','like','%'.$input['nickName'].'%'];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['create_time','between',"$start_time,$end_time"];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit'],$where);
+
+ if(!empty($data['data'])){
+
+ $finance_model = new FinanceWater();
+
+ $water_model = new BalanceWater();
+
+ $inte_model = new IntegralLog();
+
+ foreach ($data['data'] as &$v){
+
+ $cash_data = $finance_model->getUserCashData($v['id']);
+ //总消费
+ $v['pay_cash'] = $cash_data['cash'];
+ //总退款
+ $v['refund_cash'] = $cash_data['refund_cash'];
+ //充值金额
+ $v['balance_cash']= $water_model->where(['type'=>1,'user_id'=>$v['id']])->sum('price');
+ //总积分
+ $v['total_integral'] = $inte_model->where(['user_id'=>$v['id']])->where('integral_add','>',0)->sum('integral_add');
+ //兑换积分
+ $v['pay_integral'] = round($v['total_integral']-$v['integral'],2);
+
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 14:39
+ * @功能说明:编辑员工
+ */
+ public function userUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-28 23:03
+ * @功能说明:佣金记录
+ */
+ public function commList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+ }
+
+ if(!empty($input['top_name'])){
+
+ $dis[] = ['c.nickName','like','%'.$input['top_name'].'%'];
+
+ }
+
+ $comm_model = new Commission();
+
+ $data = $comm_model->recordList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 15:02
+ * @功能说明:用户所有获得的奖杯
+ */
+ public function userTrophy(){
+
+ $input = $this->_param;
+
+ $user_trophy_model = new CarUserTrophy();
+
+ $dis = [
+
+ 'a.user_id' => $input['user_id'],
+
+ 'a.status' => 1,
+
+ 'b.status' => 1
+
+ ];
+
+ $data = $user_trophy_model->alias('a')
+ ->join('shequshop_car_trophy b','a.trophy_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title,b.cover')
+ ->select()
+ ->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 15:04
+ * @功能说明:用户添加奖杯
+ */
+ public function userTrophyAdd(){
+
+ $input = $this->_input;
+
+ $user_trophy_model = new CarUserTrophy();
+
+ foreach ($input['user_id'] as $value){
+
+ foreach ($input['trophy_id'] as $v){
+
+ $dis = [
+
+ 'user_id' => $value,
+
+ 'trophy_id'=> $v,
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $find = $user_trophy_model->where($dis)->where('status','>',-1)->find();
+ //增加
+ if($input['add']==1){
+
+ if(empty($find)){
+
+ $user_trophy_model->dataAdd($dis);
+ }
+
+ }else{
+ //减少
+ if(!empty($find)){
+
+ $user_trophy_model->dataUpdate($dis,['status'=>-1]);
+ }
+
+ }
+
+ }
+
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-10 13:32
+ * @功能说明:评价管理
+ */
+ public function evaluateList(){
+
+ $input = $this->_param;
+
+ $eva_model = new Evaluate();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','>',-1];
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['a.type','=',$input['type']];
+
+ }
+
+ if(!empty($input['good'])){
+
+ $dis[] = ['a.star','>=',3];
+
+ }
+
+ if(!empty($input['bad'])){
+
+ $dis[] = ['a.star','<',3];
+
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['b.title','line',"%".$input['title'].'%'];
+
+ }
+
+ $data = $eva_model->adminList($dis,$input['limit']);
+
+ $where[] = ['uniacid','=',$this->_uniacid];
+
+ $where[] = ['status','>',-1];
+
+ if(!empty($input['type'])){
+
+ $where[] = ['type','=',$input['type']];
+
+ }
+
+ $data['good_eva'] = $eva_model->where($where)->where('star','>=',3)->count();
+
+ $data['bad_eva'] = $eva_model->where($where)->where('star','<',3)->count();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-10 13:45
+ * @功能说明:编辑评论
+ */
+ public function evaluateUpdate(){
+
+ $input = $this->_input;
+
+ $eva_model = new Evaluate();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $eva_model->dataInfo($dis);
+
+ $res = $eva_model->dataUpdate($dis,$input);
+
+ if(!empty($input['status'])&&$input['status']==-1){
+ //修改农场主的评分
+ $res = $eva_model->updateFarmerStar($data['farmer_id']);
+ }
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:02
+ * @功能说明:角色列表
+ */
+ public function roleList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $role_model = new Role();
+
+ $data = $role_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:02
+ * @功能说明:角色列表
+ */
+ public function roleSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $role_model = new Role();
+
+ $data = $role_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 13:56
+ * @功能说明:添加角色
+ */
+ public function roleAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $role_model = new Role();
+
+ $data = $role_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:17
+ * @功能说明:编辑角色
+ */
+ public function roleUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $role_model = new Role();
+ //删除
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $adminRole_mdoel = new AdminRole();
+
+ $find = $adminRole_mdoel->alias('a')
+ ->join('lbfarm_school_admin b','a.admin_id = b.id')
+ ->where(['a.role_id'=>$input['id']])
+ ->where('b.status','>',-1)
+ ->find();
+
+ if(!empty($find)){
+
+ $this->errorMsg('该角色正在被使用');
+ }
+
+ }
+
+ $data = $role_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:17
+ * @功能说明:角色详情
+ */
+ public function roleInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $role_model = new Role();
+
+ $data = $role_model->dataInfo($dis);
+
+ $node_model = new Node();
+
+ $node = $node_model->where(['role_id'=>$input['id']])->select()->toArray();
+
+ if(!empty($node)){
+
+ foreach ($node as $k=>$v){
+
+ $node[$k]['auth'] = !empty($v['auth'])?explode(',',$v['auth']):[];
+
+ }
+
+ }
+
+ $data['node'] = $node;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:18
+ * @功能说明:给账号分配角色(多选)
+ */
+ public function adminRoleAdd(){
+
+ $input = $this->_input;
+
+ $adminRole_mdoel = new AdminRole();
+
+ $adminRole_mdoel->where(['admin_id'=>$input['admin_id']])->delete();
+
+ if(!empty($input['role'])){
+
+ foreach ($input['role'] as $key => $value){
+
+ $insert[$key] = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'admin_id'=> $input['admin_id'],
+
+ 'role_id' => $value
+
+ ];
+
+ }
+
+ $adminRole_mdoel->saveAll($insert);
+ }
+
+ return $this->success(true);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:24
+ * @功能说明:账号所匹配的角色详情
+ */
+ public function adminInfo(){
+
+ $input = $this->_param;
+
+ $adminRole_mdoel = new AdminRole();
+
+ $admin_model = new \app\farm\model\Admin();
+
+ $dis= [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $admin_model->dataInfo($dis);
+
+ $dis = [
+
+ 'a.uniacid' => $this->_uniacid,
+
+ 'b.status' => 1,
+
+ 'a.admin_id'=> $input['id']
+ ];
+
+ $data['role'] = $adminRole_mdoel->alias('a')
+ ->join('lbfarm_role b','a.role_id = b.id')
+ ->where($dis)
+ ->field('b.*,a.role_id')
+ ->group('b.id')
+ ->select()
+ ->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:24
+ * @功能说明:账号所匹配的角色的节点详情
+ */
+ public function adminNodeInfo(){
+
+ $input = $this->_param;
+
+ $adminRole_mdoel = new AdminRole();
+
+ $data['is_admin'] = isset($this->_user['is_admin'])?$this->_user['is_admin']:1;
+
+ $dis = [
+
+ 'a.uniacid' => $this->_uniacid,
+
+ 'b.status' => 1,
+
+ 'a.admin_id'=> $this->_user['id']
+ ];
+
+ $data['node'] = $adminRole_mdoel->alias('a')
+ ->join('lbfarm_role b','a.role_id = b.id')
+ ->join('lbfarm_node c','c.role_id = b.id')
+ ->where($dis)
+ ->field('c.*')
+ ->group('c.id')
+ ->select()
+ ->toArray();
+
+ if(!empty($data['node'])){
+
+ foreach ($data['node'] as $k=>$v){
+
+ $data['node'][$k]['auth'] = !empty($v['auth'])?explode(',',$v['auth']):[];
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:41
+ * @功能说明:账号列表
+ */
+ public function adminList(){
+
+ $input = $this->_param;
+
+ $admin_model = new \app\farm\model\Admin();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['username','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $admin_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:47
+ * @功能说明:添加账号
+ */
+ public function adminAdd(){
+
+ $input = $this->_input;
+
+ $admin_model = new \app\farm\model\Admin();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'username'=> $input['username'],
+ ];
+
+ $find = $admin_model->where($dis)->where('status','>',-1)->find();
+
+ if(!empty($find)){
+
+ $this->errorMsg('账号名不能重复');
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'username'=> $input['username'],
+
+ 'o_passwd'=> $input['passwd'],
+
+ 'passwd' => checkPass($input['passwd']),
+
+ 'is_admin'=> 0,
+
+ ];
+
+ $admin_model->dataAdd($insert);
+
+ $admin_id = $admin_model->getLastInsID();
+
+ $adminRole_mdoel = new AdminRole();
+
+ $adminRole_mdoel->where(['admin_id'=>$admin_id])->delete();
+
+ if(!empty($input['role'])){
+
+ foreach ($input['role'] as $key => $value){
+
+ $inserts[$key] = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'admin_id'=> $admin_id,
+
+ 'role_id' => $value
+
+ ];
+
+ }
+
+ $adminRole_mdoel->saveAll($inserts);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:47
+ * @功能说明:添加账号
+ */
+ public function adminUpdate(){
+
+ $input = $this->_input;
+
+ $admin_model = new \app\farm\model\Admin();
+
+ if(!empty($input['username'])){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'username'=> $input['username'],
+ ];
+
+ $find = $admin_model->where($dis)->where('status','>',-1)->where('id','<>',$input['id'])->find();
+
+ if(!empty($find)){
+
+ $this->errorMsg('账号名不能重复');
+ }
+
+ }
+
+ if(!empty($input['passwd'])){
+
+ $input['o_passwd'] = $input['passwd'];
+
+ $input['passwd'] = checkPass($input['passwd']);
+
+ }
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ if(isset($input['role'])){
+
+ $role = $input['role'];
+
+ unset($input['role']);
+ }
+
+ $admin_model->dataUpdate($dis,$input);
+
+ $adminRole_mdoel = new AdminRole();
+
+ $adminRole_mdoel->where(['admin_id'=>$input['id']])->delete();
+
+ if(!empty($role)){
+
+ foreach ($role as $key => $value){
+
+ $inserts[$key] = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'admin_id'=> $input['id'],
+
+ 'role_id' => $value
+
+ ];
+
+ }
+
+ $adminRole_mdoel->saveAll($inserts);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-20 16:00
+ * @功能说明:修改用户积分
+ */
+ public function userIntegralUpdate(){
+
+ $input = $this->_input;
+
+ $log_model = new IntegralLog();
+
+ $type = $input['integral']>0?12:13;
+
+ $res = $log_model->integralUserAdd($input['user_id'],$input['integral'],$this->_uniacid,2,$type);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/Index.php b/app/farm/controller/Index.php
new file mode 100755
index 0000000..eabf92e
--- /dev/null
+++ b/app/farm/controller/Index.php
@@ -0,0 +1,1117 @@
+model = new User();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-02 16:58
+ * @功能说明:首页
+ */
+ public function index(){
+
+ $input = $this->_param;
+
+ $config_model = new \app\farm\model\Config();
+
+ $data['weather'] = $config_model->getPlaceWeather();
+
+ $arr = [
+ //轮播
+ 1 => 'rotation',
+ //广告
+ 2 => 'poster'
+ ];
+
+ $banner_model = new Banner();
+
+ foreach ($arr as $k=>$v){
+
+ $dis = [
+
+ 'type' => $k,
+
+ 'status' => 1,
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data['banner'][$v] = $banner_model->where($dis)->order('top desc,id desc')->select()->toArray();
+ }
+
+ $where[] = ['uniacid','=',$this->_uniacid];
+
+ $where[] = ['status','=',1];
+
+ $where[] = ['type','=',0];
+
+ $us_model = new AboutUs();
+
+ $about = $us_model->dataInfo($where);
+ //收否有关于我们
+ $data['about_us'] = !empty($about)?1:0;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 2,
+
+ 'type' => 2,
+
+ 'business_status' => 1
+ ];
+
+ $farmer_model = new \app\farm\model\Farmer();
+
+ $lat = !empty($input['lat'])?$input['lat']:0;
+
+ $lng = !empty($input['lng'])?$input['lng']:0;
+
+ $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(PI()*('.$lng.'- `lng`)/360),2)+COS(PI()*33.07078170776367/180)* COS('.$lat.' * PI()/180)*POW(SIN(PI()*('.$lat.'- lat)/360),2))))*1000 as distance';
+ //门店列表
+ $store = $farmer_model->where($dis)->field(['*',$alh])->order('distance,id desc')->limit(3)->select()->toArray();
+
+ if(!empty($store)){
+
+ foreach ($store as &$v){
+
+ $v['distance'] = getDistances($v['lng'],$v['lat'],$lng,$lat);
+
+ $v['distance'] = $farmer_model->getDistanceAttr($v['distance']);
+
+ }
+
+ }
+
+ $data['store_list'] = $store;
+
+ $arr = [
+
+ 1 => 'welfare_list',
+
+ 2 => 'system_list'
+ ];
+
+ $welfare_model = new WelfareColumn();
+
+ foreach ($arr as $k=>$value){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ 'type' => $k
+ ];
+
+ $data[$value] = $welfare_model->where($dis)->order('top desc,id desc')->limit(5)->select()->toArray();
+
+ }
+
+ $goods_model = new ShopGoods();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'index_show' => 1,
+
+ 'status' => 1
+ ];
+
+ $data['hot_goods'] = $goods_model->where($dis)->order('top desc,id desc')->limit(3)->select()->toArray();
+
+ return $this->success($data);
+ }
+
+
+ public function earTagTest(){
+
+ $url = 'https://fw.shujuzhu.cn/dgw/meishan/query/list';
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ $response = curl_exec($ch);
+ curl_close($ch);
+
+
+
+ $url = 'http://127.0.0.1:9090/aes/decrypt?key=SICHUANMEISHAN';
+
+ $data11 = array(
+ 'content' => $response
+ );
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data11));
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+ $response = curl_exec($ch);
+ curl_close($ch);
+
+ $dataAr = json_decode($response,true);
+ foreach ($dataAr['data'] as $item){
+ $model = new ClaimEarTagLog();
+
+ $dt = [];
+ $dt['screate_time'] = $item['createTime'];
+ $dt['equipment_id'] = $item['equipmentId'];
+ $dt['jbu'] = $item['jbu'];
+ $dt['mac'] = $item['mac'];
+ $dt['power'] = $item['power'];
+ $dt['repeater_mac'] = $item['repeaterMac'];
+ $dt['rssi'] = $item['rssi'];
+ $dt['temp'] = $item['temp'];
+ $dt['create_time'] = date('Y-m-d H:i:s');
+ $model->addTagLog($dt);
+ }
+
+ return $this->success('ok');
+ }
+ function aesDecryptByBytes($encryptBytes, $decryptKey) {
+ $decryptBytes = '';
+ try {
+ $kgen = openssl_pkey_new(array('digest_alg' => 'sha1', 'private_key_bits' => 128, 'private_key_type' => OPENSSL_KEYTYPE_AES));
+ openssl_pkey_export($kgen, $privateKey);
+ $decryptKey = openssl_pkey_get_details($kgen)['key'];
+ $cipher = openssl_decrypt($encryptBytes, 'AES-128-ECB', $decryptKey, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
+ $decryptBytes = mb_convert_encoding($cipher, 'UTF-8', 'UTF-8');
+ return $decryptBytes;
+ } catch (Exception $e) {
+ echo $e->getMessage();
+ }
+ return $decryptKey;
+ }
+
+
+
+
+ function AesDecrypt($key, $data) {
+// $ciphertext_raw = $data;
+ $ciphertext_raw = base64_decode($data);
+ $iv = substr($ciphertext_raw, 0, 16);
+// $ciphertext = substr($ciphertext_raw, 16);
+// $key = hash('sha256', $key);
+ $cipher = 'AES-256-ECB';
+ $result = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
+ return $result;
+ }
+
+ function aes_decrypt($encrypted, $key) {
+ $cipher = "AES-256-ECB";
+ $ivlen = openssl_cipher_iv_length($cipher);
+ $iv = substr($encrypted, 0, $ivlen);
+ $encrypted = substr($encrypted, $ivlen);
+ $decrypted = openssl_decrypt($encrypted, $cipher, $key, OPENSSL_RAW_DATA, $iv);
+ return $decrypted;
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-18 16:41
+ * @功能说明:获取天气
+ */
+ public function weather(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo($dis);
+
+ $url = 'https://apis.map.qq.com/ws/geocoder/v1/?location='.$input['lat'].','.$input['lng'];
+
+ $url = $url.'&key='.$config['map_secret'];
+
+ $location = longbingCurl($url,[]);
+
+ $location = json_decode($location,true);
+
+ $data['weather'] = [];
+
+ if(!empty($location['result']['address_component'])){
+
+ $location = $location['result']['address_component'];
+
+ if(!empty($location['province'])){
+
+ $province = $location['province'];
+
+ $city = $location['city'];
+
+ $county = $location['district'];
+
+ $url = 'https://wis.qq.com/weather/common?source=pc&weather_type=observe|forecast_24h|air&province='.$province.'&city='.$city.'&county='.$county;
+
+ $weather = file_get_contents($url);
+
+ $weather = @json_decode($weather,true);
+ //天气
+ $data['weather'] = $weather;
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 14:16
+ * @功能说明:获取配置信息
+ */
+ public function configInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo($dis);
+
+ return $this->success($config);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 15:21
+ * @功能说明:
+ */
+ public function farmerSelectList(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 2,
+
+ 'type' => 1
+ ];
+
+ $farmer_model = new \app\farm\model\Farmer();
+
+ $data = $farmer_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 14:35
+ * @功能说明:农场列表
+ */
+ public function farmerList(){
+
+ $input = $this->_param;
+
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['type','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $sort = !empty($input['sort'])?$input['sort']:2;
+
+ $farmer_model = new \app\farm\model\Farmer();
+
+ $lat = !empty($input['lat'])?$input['lat']:0;
+
+ $lng = !empty($input['lng'])?$input['lng']:0;
+
+ $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(PI()*('.$lng.'- `lng`)/360),2)+COS(PI()*33.07078170776367/180)* COS('.$lat.' * PI()/180)*POW(SIN(PI()*('.$lat.'- lat)/360),2))))*1000 as distance';
+
+ switch ($sort){
+
+ case 1:
+
+ $top = 'id desc';
+
+ break;
+
+ case 2:
+
+ $top = 'distance,id desc';
+
+ break;
+
+ case 3:
+
+ $top = 'iv desc,id desc';
+
+ break;
+ }
+
+ $data = $farmer_model->where($dis)->field(['*',$alh])->order($top)->paginate(10)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $dis = [
+
+ 'type' => 2,
+
+ 'user_id' => $v['user_id'],
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $v['store_id'] = $farmer_model->where($dis)->value('id');
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 14:43
+ * @功能说明:农场详情
+ *
+ */
+ public function farmerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $farmer_model = new \app\farm\model\Farmer();
+
+ $data = $farmer_model->dataInfo($dis);
+
+ $farmer_model->dataUpdate($dis,['iv'=>$data['iv']+1]);
+
+ $dis = [
+
+ 'type' => 2,
+
+ 'user_id' => $data['user_id'],
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data['store_id'] = $farmer_model->where($dis)->value('id');
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 15:21
+ * @功能说明:文章详情
+ */
+ public function articleInfo(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $data = $article_model->dataInfo(['id'=>$input['article_id']]);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:51
+ * @功能说明:关于我们列表
+ */
+ public function aboutUsList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['type','=',0];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $us_model = new AboutUs();
+
+ $data = $us_model->where($dis)->order('top desc,id desc')->limit(10)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:23
+ * @功能说明:我们列表详情
+ */
+ public function aboutUsInfoType(){
+
+ $input = $this->_param;
+
+ $input['type'] = !empty($input['type'])?$input['type']:0;
+
+ $dis = [
+
+ 'type'=> $input['type'],
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $us_model = new AboutUs();
+
+ $res = $us_model->dataInfo($dis);
+
+ if(!empty($input['type'])&&empty($res)){
+
+ $title = $input['type']==1?'动物认养协议':'土地租赁协议';
+
+ $dis['title'] = $title;
+
+ $us_model->dataAdd($dis);
+
+ $res = $us_model->dataInfo($dis);
+ }
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:07
+ * @功能说明:添加评价
+ */
+ public function evaluateAdd(){
+
+ $input = $this->_input;
+
+ $eva_model = new Evaluate();
+
+ $dis = [
+
+ 'order_id' => $input['order_id'],
+
+ 'type' => $input['type']
+ ];
+
+ $find = $eva_model->where($dis)->where('status','>',-1)->find();
+
+ if(!empty($find)){
+
+ $this->errorMsg('你已经评价过该订单了');
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id'=> $input['order_id'],
+
+ 'star' => $input['star'],
+
+ 'type' => $input['type'],
+
+ 'order_code'=> $input['order_code'],
+
+ 'text' => $input['text'],
+
+ 'imgs' => !empty($input['imgs'])?implode(',',$input['imgs']):'',
+
+ 'farmer_id' => !empty($input['farmer_id'])?$input['farmer_id']:0,
+
+ ];
+
+ $res = $eva_model->dataAdd($insert);
+ //修改农场主的评分
+ $res = $eva_model->updateFarmerStar($input['farmer_id']);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:17
+ * @功能说明:用户评列表
+ */
+ public function userEvaluateList(){
+
+ $input = $this->_param;
+
+ $eva_model = new Evaluate();
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+
+ }
+
+ $data = $eva_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ if(!empty($v['order_info']['end_time'])){
+
+ $v['order_info']['end_time'] = date('Y-m-d H:i:s',$v['order_info']['end_time']);
+
+ }
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:21
+ * @功能说明:评价详情
+ */
+ public function evaluateInfo(){
+
+ $input = $this->_param;
+
+ $eva_model = new Evaluate();
+
+ $dis =[
+
+ 'id' => $input['id']
+ ];
+
+ $data = $eva_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:21
+ * @功能说明:评价详情
+ */
+ public function evaluateUpdate(){
+
+ $input = $this->_input;
+
+ $eva_model = new Evaluate();
+
+ $dis =[
+
+ 'id' => $input['id']
+ ];
+
+ $info = $eva_model->dataInfo($dis);
+
+ $data = $eva_model->dataUpdate($dis,$input);
+
+ if(!empty($input['status'])&&$input['status']==-1){
+ //修改农场主的评分
+ $res = $eva_model->updateFarmerStar($info['farmer_id']);
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-10 17:23
+ * @功能说明:待评价订单
+ */
+ public function noEvaluateOrderList(){
+
+ $input = $this->_param;
+
+ $eva_model = new Evaluate();
+
+ $model = $eva_model->getTypeModel($input['type']);
+
+ $where = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'type' => $input['type']
+ ];
+
+ $order_id = $eva_model->where($where)->where('status','>',-1)->column('order_id');
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ if($input['type']==2){
+
+ $dis[] = ['pay_type','>',1];
+
+ }else{
+
+ $dis[] = ['pay_type','=',7];
+ }
+
+ $dis[] = ['id','not in',$order_id];
+
+ $data = $model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ $farmer_model = new \app\farm\model\Farmer();
+
+ foreach ($data['data'] as &$v){
+
+ $farmer_id = !empty($v['farmer_id'])?$v['farmer_id']:0;
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id'=>$farmer_id],'title');
+
+ if(!empty($v['end_time'])){
+
+ $v['end_time'] = date('Y-m-d H:i:s',$v['end_time']);
+ }
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-11 10:11
+ * @功能说明:根据type获取对应物品的评价
+ */
+ public function goodsEvaluateList(){
+
+ $input = $this->_param;
+
+ $eva_model = new Evaluate();
+
+ $data = $eva_model->goodsEvaluateList($input['goods_id'],$input['type'],$input['is_goods']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-09 16:50
+ * @功能说明:模版列表
+ */
+ public function tmpList(){
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$this->_uniacid])->select()->toArray();
+
+ return $this->success($tmpl);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 15:56
+ * @功能说明:监控列表
+ */
+ public function monitorList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }else{
+ //我的菜地
+ $land_model = new LandOrder();
+
+ $claim_model= new ClaimOrder();
+
+ $monitor_text_model = new MonitorText();
+
+ $land_text_model = new LandText();
+
+ $land_id = $land_model->where(['user_id'=>$this->getUserId()])->where('pay_type','>',1)->column('land_id');
+
+ $obj_id = $land_text_model->where('land_id','in',$land_id)->where(['type'=>4])->column('obj_id');
+
+ $claim_id= $claim_model->where(['user_id'=>$this->getUserId()])->where('pay_type','>',1)->column('goods_id');
+
+ $obj_id_v2 = $monitor_text_model->where('obj_id','in',$claim_id)->where(['type'=>2])->column('monitor_id');
+
+ $monitor_id = array_merge($obj_id,$obj_id_v2);
+
+ $dis[] = ['a.id','in',$monitor_id];
+
+ }
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['a.title','like','%'.$input['title'].'%'];
+
+ }
+
+ $monitor_model = new Monitor();
+
+ $data = $monitor_model->farmerMonitorList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 16:31
+ * @功能说明:获取监控地址
+ */
+ public function getMonitorInfo(){
+
+ $input = $this->_param;
+
+ $monitor_model = new Monitor();
+
+ $data['url'] = $monitor_model->getVideoUrl($input['id']);
+ $data['info'] = $monitor_model->dataInfo(['id'=>$input['id']]);
+
+ $api = new YsCloudApi($this->_uniacid);
+
+ $data['token'] = $api->getToken();
+ Log::write('21');
+ Log::write($data);
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-12 11:01
+ * @功能说明:获取萤石云token
+ */
+ public function getYsToken(){
+
+ $api = new YsCloudApi($this->_uniacid);
+
+ $token = $api->getToken();
+
+ return $this->success($token);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-12 11:02
+ * @功能说明:旋转摄像头
+ */
+ public function ysStartTurn(){
+
+ $input = $this->_param;
+
+ $monitor_model = new Monitor();
+
+ $api = new YsCloudApi($this->_uniacid);
+
+ $monitor = $monitor_model->dataInfo(['id'=>$input['id']]);
+
+ $res = $api->startTurn($monitor['deviceSerial'],$input['direction'],$monitor['channelNo']);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-12 11:02
+ * @功能说明:停止旋转摄像头
+ */
+ public function ysStopTurn(){
+
+ $input = $this->_param;
+
+ $monitor_model = new Monitor();
+
+ $api = new YsCloudApi($this->_uniacid);
+
+ $monitor = $monitor_model->dataInfo(['id'=>$input['id']]);
+
+ $direction = !empty($input['direction'])?$input['direction']:0;
+
+ $res = $api->stopTurn($monitor['deviceSerial'],$direction,$monitor['channelNo']);
+
+ return $this->success($res);
+
+ }
+
+
+
+ public function haveStore()
+ {
+
+
+ $data = $this->getStoreInfo(2);
+
+ $res = !empty($data)?true:false;
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 17:34
+ * @功能说明:公益列表
+ */
+ public function welfareColumnList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $type = !empty($input['type'])?$input['type']:1;
+
+ $dis[] = ['type','=',$type];
+
+ $model = new WelfareColumn();
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $model->dataList($dis,10,'id,title,cover,create_time');
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 17:34
+ * @功能说明:公益列表
+ */
+ public function welfareColumnInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id'],
+
+ 'status' => 1
+ ];
+
+ $model = new WelfareColumn();
+
+ $data = $model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-06-15 16:29
+ * @功能说明:优惠券
+ */
+ public function couponList(){
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon_model = new Coupon();
+
+ if(empty($this->getUserId())){
+
+ return $this->success([]);
+
+ }
+
+ $have_get = $coupon_record_model->where(['user_id'=>$this->getUserId()])->column('coupon_id');
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['send_type','=',2];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['stock','>',0];
+
+ $dis[] = ['id','not in',$have_get];
+
+ $where = [];
+
+ $where[] = ['time_limit','=',2];
+
+ $where[] = ['end_time','>',time()];
+
+ $data = $coupon_model->where($dis)->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })->paginate(10)->toArray();
+
+ if(!empty($coupon['data'])){
+
+ foreach ($coupon['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-06-15 22:49
+ * @功能说明:用户获取卡券
+ */
+ public function userGetCoupon(){
+
+ $input = $this->_input;
+
+ $coupon_record_model = new CouponRecord();
+
+ $res = $coupon_record_model->recordAdd($input['coupon_id'],$this->getUserId(),1,1);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success(true);
+ }
+
+
+
+
+}
diff --git a/app/farm/controller/IndexBalance.php b/app/farm/controller/IndexBalance.php
new file mode 100755
index 0000000..9ae4ff1
--- /dev/null
+++ b/app/farm/controller/IndexBalance.php
@@ -0,0 +1,263 @@
+app = $app;
+
+ $this->model = new BalanceCard();
+
+ $this->balance_order = new BalanceOrder();
+
+ $this->water_model = new BalanceWater();
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:储值充值卡列表
+ */
+ public function cardList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 17:00
+ * @功能说明:充值余额
+ */
+ public function payBalanceOrder(){
+
+ $input = $this->_input;
+
+ if(!empty($input['card_id'])){
+
+ $dis = [
+
+ 'id' => $input['card_id'],
+
+ 'status' => 1
+ ];
+
+ $card = $this->model->dataInfo($dis);
+
+ if(empty($card)){
+
+ $this->errorMsg('充值卡已被下架');
+ }
+
+ }else{
+
+ $card = [
+
+ 'price' => $input['price'],
+
+ 'true_price' => $input['price'],
+
+ 'id' => 0,
+
+ 'integral' => 0,
+
+ 'member_level'=> 0,
+
+ 'title' => '自定义金额充值'
+ ];
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_code' => orderCode(),
+
+ 'pay_price' => $card['price'],
+
+ 'sale_price' => $card['price'],
+
+ 'true_price' => $card['true_price'],
+
+ 'card_id' => $card['id'],
+
+ 'title' => $card['title'],
+
+ 'integral' => $card['integral'],
+
+ 'pay_model' => $input['pay_model'],
+
+ 'member_level'=> $card['member_level'],
+//
+// 'phone' => $input['phone']
+
+ ];
+
+ $res = $this->balance_order->dataAdd($insert);
+
+ if($res==0){
+
+ $this->errorMsg('充值失败');
+
+ }
+
+ if($input['pay_model']==3){
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($insert['order_code'],$insert['pay_price'],'余额充值');
+
+ $arr['pay_list']= $jsApiParameters;
+
+ $arr['order_code']= $insert['order_code'];
+
+ }else{
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"储值",['type' => 'Balance' , 'out_trade_no' => $insert['order_code']],$insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 17:34
+ * @功能说明:充值订单列表
+ */
+ public function balaceOrder(){
+
+ $input = $this->_param;
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['pay_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->balance_order->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ $v['pay_time'] = date('Y-m-d H:i:s',$v['pay_time']);
+
+ }
+ }
+
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 18:00
+ * @功能说明:消费明细
+ */
+ public function payWater(){
+
+ $input = $this->_param;
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+// $dis[] = ['type','=',2];
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->water_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexClaim.php b/app/farm/controller/IndexClaim.php
new file mode 100755
index 0000000..1591bdd
--- /dev/null
+++ b/app/farm/controller/IndexClaim.php
@@ -0,0 +1,1754 @@
+app = $app;
+
+ $this->model = new Claim();
+
+ autoCancelOrder($this->_uniacid);
+
+ $collage_model = new CollageStart();
+
+ $collage_model->initAtv($this->payConfig());
+
+ $push_data = array(
+
+ 'action' => 'collageFailCancelOrder',
+
+ 'event' => 'collageFailCancelOrder',
+
+ 'pay_config' => $this->payConfig()
+
+ );
+ publisher(json_encode($push_data, true));
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 14:03
+ * @功能说明:认养轮播图
+ */
+ public function claimBanner()
+ {
+
+ $input = $this->_param;
+
+ $banner_model = new Banner();
+
+ $dis = [
+
+ 'type' => $input['type'],
+
+ 'status' => 1,
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $banner_model->where($dis)->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:42
+ * @功能说明:认养分类列表
+ */
+ public function claimCateList()
+ {
+
+ $input = $this->_param;
+
+ $cate_model = new LandCate();
+
+ $dis = [
+
+ 'type' => $input['type'],
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ $data = $cate_model->where($dis)->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:53
+ * @功能说明:认养列表
+ */
+ public function claimList()
+ {
+
+ $input = $this->_param;
+
+ $farmer_model = new Farmer();
+
+ $claim_order = new ClaimOrder();
+
+ $user_model = new User();
+
+ $input['sort'] = !empty($input['sort']) ? $input['sort'] : 1;
+
+ $dis[] = ['a.uniacid', '=', $this->_uniacid];
+
+ $dis[] = ['a.status', '=', 1];
+
+ $dis[] = ['a.end_time', '>', time()];
+
+ if (!empty($input['cate_id'])) {
+
+ $dis[] = ['b.cate_id', '=', $input['cate_id']];
+
+ $dis[] = ['b.type', '=', 3];
+ }
+
+ if (!empty($input['title'])) {
+
+ $dis[] = ['a.title', 'like', '%' . $input['title'] . '%'];
+
+ }
+
+ if (!empty($input['farmer_id'])) {
+
+ $dis[] = ['a.farmer_id', '=', $input['farmer_id']];
+
+ } else {
+
+ $id = $farmer_model->farmerId($this->_uniacid);
+
+ $dis[] = ['a.farmer_id', 'in', $id];
+
+ }
+
+ $lat = !empty($input['lat']) ? $input['lat'] : 0;
+
+ $lng = !empty($input['lng']) ? $input['lng'] : 0;
+
+// $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(PI()*(' . $lng . '- `lng`)/360),2)+COS(PI()*33.07078170776367/180)* COS(' . $lat . ' * PI()/180)*POW(SIN(PI()*(' . $lat . '- lat)/360),2))))*1000 as distance';
+ $alh = '0 as distance';
+
+ $data = $this->model->indexDataListV2($dis, $alh, $input['sort']);
+
+ if (!empty($data['data'])) {
+
+ foreach ($data['data'] as &$v) {
+
+ $v['count']['user_count'] = $claim_order->where(['claim_id' => $v['id']])->where('pay_type', '>', 1)->group('user_id')->count();
+
+ $order_user_id = $claim_order->where(['claim_id' => $v['id']])->where('pay_type', '>', 1)->group('user_id')->order('id desc')->limit(3)->column('user_id');
+
+ $v['count']['user_list'] = $user_model->where('id', 'in', $order_user_id)->field('avatarUrl')->select()->toArray();
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id' => $v['farmer_id']], 'title,cover');
+
+ $v['start_time'] = date('Y-m-d', $v['start_time']);
+
+ $v['end_time'] = date('Y-m-d', $v['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 10:34
+ * @功能说明:认养详情
+ */
+ public function claimInfo()
+ {
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $farmer_model = new Farmer();
+
+ $data['farmer_info'] = $farmer_model->dataInfo(['id' => $data['farmer_id']]);
+
+ $claim_text_model = new ClaimText();
+
+ $data['process'] = $claim_text_model->where(['claim_id' => $data['id']])->select()->toArray();
+
+ $mac_model = new Machine();
+ //仪器详情
+ $data['machine_info'] = $mac_model->getDataInfo($data['id'], 2);
+
+ $collage_model = new CollageStart();
+ //拼团列表
+ $data['collage_list'] = $collage_model->claimCollageLimit($data['id'], 3, $this->getUserId());
+ //用户正在发起的拼团
+ $data['user_start_collage'] = $collage_model->userCollageIngData($this->getUserId(), $data['id']);
+
+ $collage_model = new ClaimCollage();
+ //商品拼团活动
+ $data['collage_data'] = $collage_model->getAtvInfoIng($data['id'], $this->getUserId());
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 17:51
+ * @功能说明:认养拼团列表
+ */
+ public function claimCollageList()
+ {
+
+ $input = $this->_param;
+
+ $collage_model = new CollageStart();
+
+ $dis[] = ['end_time', '>', time()];
+
+ $dis[] = ['status', '=', 1];
+
+ $dis[] = ['claim_id', '=', $input['claim_id']];
+ //拼团
+ $data = $collage_model->claimCollageList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 17:53
+ * @功能说明:认养拼团详情
+ */
+ public function claimCollageInfo()
+ {
+
+ $input = $this->_param;
+
+ $collage_model = new CollageStart();
+
+ $join_model = new CollageJoin();
+
+ $order_model = new ClaimOrder();
+
+ $data = $collage_model->dataInfo(['id' => $input['id']]);
+
+ if (empty($data)) {
+
+ $this->errorMsg('拼团未找到');
+ }
+
+ $data['user_list'] = $join_model->collageUserAvatar($input['id'], 5);
+
+ $claim = $this->model->dataInfo(['id' => $data['claim_id']]);
+
+ $data['claim_title'] = $claim['title'];
+
+ $data['claim_cover'] = $claim['cover'];
+
+ $data['claim_price'] = $claim['price'];
+
+ $data['can_start'] = $collage_model->startAtvCheck($this->getUserId(), $data['atv_id']);
+ //是否还能发起该活动其他的拼团
+ $data['can_start'] = !empty($data['can_start']['code']) ? 0 : 1;
+ //是否能参与拼团
+ $data['can_join'] = $join_model->collageCanJoin($this->getUserId(), $data['id']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 10:05
+ * @功能说明:下单页信息
+ */
+ public function claimPayOrderInfo()
+ {
+
+ $input = $this->_param;
+
+ $order_model = new ClaimOrder();
+
+ $data = $order_model->payOrderInfo($input);
+
+ if (!empty($data['code'])) {
+
+ $this->errorMsg($data['msg']);
+ }
+
+ $farmer_model = new Farmer();
+
+ $arr['farmer_info'] = $farmer_model->dataInfo(['id' => $data['farmer_id']]);
+
+ $arr['claim_info'] = $data;
+
+ $address_model = new Address();
+
+ if (!empty($input['address_id'])) {
+
+ $arr['address'] = $address_model->dataInfo(['id' => $input['address_id']]);
+
+ } else {
+
+ $arr['address'] = $address_model->dataInfo(['user_id' => $this->getUserId(), 'status' => 1]);
+
+ }
+
+ $coupon_modle = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+ //可用优惠券数量
+ $canUseCoupon = $coupon_modle->canUseCoupon($this->getUserId(), $data['pay_price'], 3);
+
+ $arr['canUseCoupon'] = $coupon_record_model->where('id', 'in', $canUseCoupon)->sum('num');
+
+ $arr['pay_price'] = $data['pay_price'];
+
+ $arr['coupon_discount'] = $data['coupon_discount'];
+
+ $arr['coupon_id'] = $data['coupon_id'];
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 10:57
+ * @功能说明:认养下单
+ */
+ public function claimPayOrder()
+ {
+
+ $input = $this->_input;
+
+ $order_model = new ClaimOrder();
+
+ $data = $order_model->payOrderInfo($input, 1);
+
+ if (!empty($data['code'])) {
+
+ $this->errorMsg($data['msg']);
+ }
+
+ $address_model = new OrderAddress();
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'pay_type' => 1,
+
+ 'order_code' => orderCode(),
+
+ 'claim_code' => short_orderCode(),
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_price' => round($data['pay_price'], 2),
+
+ 'get_integral' => round($data['pay_price'], 2),
+
+ 'init_price' => round($data['init_price'], 2),
+
+ 'balance' => $input['pay_model'] == 2 ? round($data['pay_price'], 2) : 0,
+
+ 'goods_id' => $data['id'],
+
+ 'goods_name' => $data['title'],
+
+ 'goods_cover' => $data['cover'],
+
+ 'goods_price' => $data['price'],
+
+ 'breed' => $data['breed'],
+
+ 'cycle' => $data['cycle'],
+
+ 'start_time' => $data['start_time'],
+
+ 'end_time' => $data['end_time'],
+
+ 'harvest_text' => $data['harvest_text'],
+
+ 'harvest_cover' => $data['harvest_cover'],
+
+ 'name' => $input['claim_name'],
+
+ 'send_type' => $input['send_type'],
+
+ 'num' => $input['num'],
+
+ 'text' => $input['text'],
+
+ 'claim_id' => $data['id'],
+
+ 'farmer_id' => $data['farmer_id'],
+
+ 'source_id' => $data['source_id'],
+
+ 'send_cycle' => $data['send_cycle'],
+
+ 'send_times' => $data['send_times'],
+
+ 'unit' => $data['unit'],
+ //
+ 'over_time' => time() + $this->_config['over_time'] * 60,
+
+ 'pay_model' => $input['pay_model'],
+
+ 'coupon_id' => $data['coupon_id'],
+
+ 'discount_price' => $data['coupon_discount'],
+
+ 'is_collage' => !empty($input['collage_start_id']) || !empty($input['collage_join_id']) ? 1 : 0,
+
+ ];
+
+ Db::startTrans();
+
+ $earInfo = ClaimEarTag::where('status', 0)->find();
+ if ($earInfo && $data['unit'] == '头') {
+ $order_insert['ear_tag'] = $earInfo['id'];
+ $order_insert['ear_tag_code'] = $earInfo['code'];
+ }
+
+ $order_model = new ClaimOrder();
+
+ $res = $order_model->dataAdd($order_insert);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败1');
+
+ }
+
+ $order_id = $order_model->getLastInsID();
+
+ $order_insert['id'] = $order_id;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $address_model->orderAddressAdd($input['address_id'], $order_id, $input['send_type'], 2, $input);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败2');
+
+ }
+ //加销量减库存
+ $update = [
+
+ 'stock' => $data['stock'] - $input['num'],
+
+ 'sale_num' => $data['sale_num'] + $input['num'],
+
+ 'lock' => $data['lock'] + 1
+
+ ];
+
+ $res = $this->model->where(['id' => $data['id'], 'lock' => $data['lock']])->update($update);
+
+ $specInfo = ClaimSpec::find($input['spec_id']);
+ $specInfo['stock'] = $specInfo['stock'] + $input['num'];
+ $specInfo->save();
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败3');
+
+ }
+ //使用优惠券
+ if (!empty($data['coupon_id'])) {
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon_record_model->couponUse($data['coupon_id'], $order_id, 3);
+
+ }
+
+ $is_start = 0;
+ //发起拼团
+ if (!empty($data['collage_start_data'])) {
+
+ $start_model = new CollageStart();
+
+ $data['collage_join_data'] = $start_model->startCollage($order_insert, $data['collage_start_data']);
+
+ if (!empty($data['collage_join_data']['code'])) {
+
+ Db::rollback();
+
+ $this->errorMsg($data['collage_join_data']['msg']);
+ }
+
+ $is_start = 1;
+
+ }
+ //参与拼团
+ if (!empty($data['collage_join_data'])) {
+
+ $join_model = new CollageJoin();
+
+ $res = $join_model->joinCollage($order_insert, $data['collage_join_data'], $is_start);
+
+ if (!empty($res['code'])) {
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+ }
+
+ }
+
+ Db::commit();
+ //如果是0元
+ if ($order_insert['pay_price'] <= 0) {
+
+ $order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if ($input['pay_model'] == 2) {
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance = $user_model->where(['id' => $this->getUserId()])->value('balance');
+
+ if ($user_balance < $order_insert['pay_price']) {
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+
+ } elseif ($input['pay_model'] == 3) {
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'], $order_insert['pay_price'], '认养商品');
+
+ $arr['pay_list'] = $jsApiParameters;
+
+ $arr['order_code'] = $order_insert['order_code'];
+
+
+ } else {
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters = $pay_controller->createWeixinPay($this->payConfig(), $this->getUserInfo()['openid'], $this->_uniacid, "认养订单", ['type' => 'Claim', 'out_trade_no' => $order_insert['order_code']], $order_insert['pay_price']);
+
+ $arr['pay_list'] = $jsApiParameters;
+
+ }
+ $arr['order_code'] = $order_insert['order_code'];
+ $arr['create_time'] = date('Y-m-d H:i:s', time());
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 10:17
+ * @功能说明:认养重新下单
+ */
+ public function claimRePayOrder()
+ {
+
+ $input = $this->_input;
+
+ $order_model = new ClaimOrder();
+
+ $order_insert = $order_model->dataInfo(['id' => $input['id']]);
+
+ if ($order_insert['pay_type'] != 1) {
+
+ $this->errorMsg('订单状态错误');
+ }
+ //余额支付
+ if ($order_insert['pay_model'] == 2) {
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance = $user_model->where(['id' => $this->getUserId()])->value('balance');
+
+ if ($user_balance < $order_insert['pay_price']) {
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+
+ } elseif ($order_insert['pay_model'] == 3) {
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'], $order_insert['pay_price'], '认养商品');
+
+ $arr['pay_list'] = $jsApiParameters;
+
+ $arr['order_code'] = $order_insert['order_code'];
+
+ } else {
+
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters = $pay_controller->createWeixinPay($this->payConfig(), $this->getUserInfo()['openid'], $this->_uniacid, "认养订单", ['type' => 'Claim', 'out_trade_no' => $order_insert['order_code']], $order_insert['pay_price']);
+
+ $arr['pay_list'] = $jsApiParameters;
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:26
+ * @功能说明:用户下单列表
+ */
+ public function orderList()
+ {
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid', '=', $this->_uniacid];
+
+ $dis[] = ['user_id', '=', $this->getUserId()];
+
+ if (!empty($input['pay_type'])) {
+
+ $dis[] = ['pay_type', '=', $input['pay_type']];
+
+ }
+
+ if (!empty($input['order_code'])) {
+
+ $dis[] = ['order_code', 'like', '%' . $input['order_code'] . '%'];
+
+ }
+
+ $order_model = new ClaimOrder();
+
+ $farmer_model = new Farmer();
+
+ $eva_model = new Evaluate();
+
+ $data = $order_model->dataList($dis);
+
+ if (!empty($data['data'])) {
+
+ foreach ($data['data'] as &$v) {
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id' => $v['farmer_id']], 'title');
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id' => $v['id'],
+
+ 'type' => 1
+ ];
+
+ $have_eva = $eva_model->where($dis)->where('status', '>', -1)->find();
+ //是否已经评价
+ $v['have_eva'] = !empty($have_eva) ? 1 : 0;
+
+ }
+ }
+
+ $arr = [2 => 'claim_count', 3 => 'send_count'];
+
+ foreach ($arr as $key => $value) {
+
+ $where = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_type' => $key
+ ];
+
+ $data['count'][$value] = $order_model->where($where)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:52
+ * @功能说明:用户下单详情
+ */
+ public function orderInfo()
+ {
+
+ $input = $this->_param;
+
+ $farmer_model = new Farmer();
+
+ $source_model = new Source();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new ClaimOrder();
+
+ $data = $order_model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $data['create_time'] = date('Y-m-d H:i:s', $data['create_time']);
+
+ $data['pay_time'] = $data['pay_time'] > 0 ? date('Y-m-d H:i:s', $data['pay_time']) : 0;
+
+ $data['cancel_time'] = $data['cancel_time'] > 0 ? date('Y-m-d H:i:s', $data['cancel_time']) : 0;
+
+ $data['time_text'] = date('Y-m-d', $data['start_time']) . '~' . date('Y-m-d', $data['end_time']);
+ //农场信息
+ $data['farmer_info'] = $farmer_model->dataInfo(['id' => $data['farmer_id']]);
+ //溯源信息
+ $data['source'] = $source_model->dataInfo(['id' => $data['source_id']]);
+ //是否可以配送
+ $data['can_send'] = $data['pay_type'] > 1 && $data['end_time'] < time() ? 1 : 0;
+
+ $eva_model = new Evaluate();
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id' => $input['id'],
+
+ 'type' => 1
+ ];
+
+ $have_eva = $eva_model->where($dis)->where('status', '>', -1)->find();
+ //是否已经评价
+ $data['have_eva'] = !empty($have_eva) ? 1 : 0;
+
+ $address_order_model = new OrderAddress();
+
+ $address_model = new Address();
+
+ $data['address_info'] = $address_order_model->dataInfo(['order_id' => $input['id'], 'type' => 2]);
+
+ if (!empty($data['address_info']['address_id'])) {
+
+ $data['address_info'] = $address_model->dataInfo(['id' => $data['address_info']['address_id']]);
+
+ }
+
+ $mac_model = new Machine();
+ //仪器详情
+ $data['machine_info'] = $mac_model->getDataInfo($data['claim_id'], 2);
+
+ $send_tmpl_id = $this->model->where(['id' => $data['claim_id']])->value('send_tmpl_id');
+
+ $freightTemplate_model = new FreightTemplate();
+ //配送运费模版
+ $data['send_tmpl'] = $freightTemplate_model->dataInfo(['id' => $send_tmpl_id]);
+
+ if ($data['is_collage'] == 1) {
+
+ $collage_model = new CollageJoin();
+
+ $collage_info = $collage_model->dataInfo(['order_id' => $input['id']]);
+
+ if (!empty($collage_info)) {
+
+ $data['collage_status'] = $collage_info['status'];
+
+ $data['collage_discount_price'] = $data['init_price'] - $collage_info['price'];
+
+ $data['collage_discount_price'] = $data['collage_discount_price'] > 0 ? $data['collage_discount_price'] : 0;
+
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 13:42
+ * @功能说明:
+ */
+ public function cancelOrder()
+ {
+
+ $input = $this->_input;
+
+ $order_model = new ClaimOrder();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order = $order_model->dataInfo($dis);
+
+ if ($order['pay_type'] != 1) {
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $order_model->cancelOrder($order);
+
+ if (!empty($res['code'])) {
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:29
+ * @功能说明:养殖管理
+ */
+ public function breedList()
+ {
+
+ $input = $this->_param;
+
+ $breed_model = new Breed();
+
+ $car_model = new Car();
+
+ $dis[] = ['a.uniacid', '=', $this->_uniacid];
+
+ $dis[] = ['a.status', '=', 1];
+
+ $dis[] = ['b.type', '=', 5];
+
+ if (!empty($input['title'])) {
+
+ $dis[] = ['a.title', 'like', '%' . $input['title'] . '%'];
+ }
+
+ $dis[] = ['b.store_id', '=', $input['farmer_id']];
+
+ $data = $breed_model->indexDataList($dis);
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'type' => 1,
+
+ 'status' => 1,
+
+ 'farmer_id' => $input['farmer_id']
+ ];
+
+ $car = $breed_model->getCarList($this->getUserId(), $input['farmer_id']);
+
+ $data['count'] = $car['goods_num'];
+
+ $data['total_price'] = $car['price'];
+
+ if (!empty($data['data'])) {
+
+ foreach ($data['data'] as &$v) {
+
+ $dis['goods_id'] = $v['id'];
+
+ $v['car_num'] = $car_model->where($dis)->sum('goods_num');
+
+ $v['car_id'] = $car_model->where($dis)->value('id');
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 17:02
+ * @功能说明:养殖订单
+ */
+ public function breedOrder()
+ {
+
+ $input = $this->_input;
+
+ $breed_model = new Breed();
+
+ $order_model = new BreedOrder();
+
+ $claim_order_model = new ClaimOrder();
+
+ $framer_model = new Farmer();
+
+ $claim_order = $claim_order_model->dataInfo(['id' => $input['claim_order_id']]);
+
+ $pay_order = $breed_model->getCarList($this->getUserId(), $claim_order['farmer_id']);
+
+ $farmer = $framer_model->dataInfo(['id' => $claim_order['farmer_id'], 'status' => 2]);
+
+ if (empty($farmer)) {
+
+ $this->errorMsg('该农场主已被取消农场身份,无法下单');
+ }
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'order_code' => orderCode(),
+
+ 'user_id' => $this->getUserId(),
+
+ 'claim_order_id' => $input['claim_order_id'],
+
+ 'farmer_id' => $claim_order['farmer_id'],
+
+ 'pay_price' => $pay_order['price'],
+
+ 'get_integral' => $pay_order['price'],
+
+ 'text' => $input['text'],
+
+ 'pay_model' => $input['pay_model'],
+
+ 'balance' => $input['pay_model'] == 2 ? round($pay_order['price'], 2) : 0,
+ ];
+
+ Db::startTrans();
+
+ $res = $order_model->dataAdd($order_insert);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+
+ $order_id = $order_model->getLastInsID();
+
+ $order_goods_model = new BreedOrderGoods();
+
+ $res = $order_goods_model->orderAdd($pay_order['car_list'], $order_id);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+ //清空购物车
+ $car_model = new Car();
+
+ $dis = [
+
+ 'farmer_id' => $claim_order['farmer_id'],
+
+ 'user_id' => $this->getUserId(),
+
+ 'type' => 1,
+
+ 'status' => 1
+ ];
+
+ $car_model->where($dis)->delete();
+
+ Db::commit();
+ //如果是0元
+ if ($order_insert['pay_price'] <= 0) {
+
+ $order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if ($input['pay_model'] == 2) {
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance = $user_model->where(['id' => $this->getUserId()])->value('balance');
+
+ if ($user_balance < $order_insert['pay_price']) {
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+
+ } elseif ($input['pay_model'] == 3) {
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'], $order_insert['pay_price'], '养殖商品');
+
+ $arr['pay_list'] = $jsApiParameters;
+
+ $arr['order_code'] = $order_insert['order_code'];
+
+ } else {
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters = $pay_controller->createWeixinPay($this->payConfig(), $this->getUserInfo()['openid'], $this->_uniacid, "养殖订单", ['type' => 'Breed', 'out_trade_no' => $order_insert['order_code']], $order_insert['pay_price']);
+
+ $arr['pay_list'] = $jsApiParameters;
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 15:52
+ * @功能说明:养殖订单列表
+ */
+ public function breedOrderList()
+ {
+
+ $input = $this->_param;
+
+ $dis[] = ['pay_type', '>', 1];
+
+ $dis[] = ['claim_order_id', '=', $input['claim_order_id']];
+
+ $order_model = new BreedOrder();
+
+ $data = $order_model->dataList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 16:07
+ * @功能说明:养殖订单详情
+ */
+ public function breedOrderInfo()
+ {
+
+ $input = $this->_param;
+
+ $dis[] = ['id', '=', $input['id']];
+
+ $order_model = new BreedOrder();
+
+ $data = $order_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y-m-d H:i:s', $data['create_time']);
+
+ $data['pay_time'] = !empty($data['pay_time']) ? date('Y-m-d H:i:s', $data['pay_time']) : 0;
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:14
+ * @功能说明:配送订单列表
+ */
+ public function userSendOrderList()
+ {
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $data = $send_order_model->orderSendOrder($input['claim_order_id']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 13:53
+ * @功能说明:申请认养订单发货
+ */
+ public function sendOrderApply()
+ {
+
+ $input = $this->_input;
+
+ $order_model = new ClaimOrder();
+
+ $farmer_model = new Farmer();
+
+ $config_model = new Config();
+
+ $address_model = new Address();
+
+ $send_order_model = new SendOrder();
+
+ $order = $order_model->dataInfo(['id' => $input['order_id']]);
+
+ if ($order['pay_type'] < 2) {
+
+ $this->errorMsg('订单未支付');
+
+ }
+ //已经申请的配送次数
+ $send_count = $send_order_model->where(['order_id' => $input['order_id'], 'type' => 1])->where('pay_type', '>', 1)->count();
+
+ if ($send_count >= $order['send_times']) {
+
+ $this->errorMsg('已经到达配送次数上线');
+
+ }
+
+ $times = $send_order_model->where(['order_id' => $input['order_id'], 'type' => 1])->where('pay_time', '>', 0)->count();
+
+ $farmer = $farmer_model->dataInfo(['id' => $order['farmer_id'], 'status' => 2]);
+
+ if (empty($farmer)) {
+
+ $this->errorMsg('农场主未找到');
+ }
+
+
+ $send_price = $distance = 0;
+ //快递
+ if ($input['send_type'] == 2) {
+
+ $address = $address_model->dataInfo(['id' => $input['address_id']]);
+
+ if (empty($address)) {
+
+ $this->errorMsg('地址信息未找到');
+
+ }
+
+ $cliam_info = $this->model->dataInfo(['id' => $order['claim_id']]);
+
+ if (empty($cliam_info)) {
+
+ $this->errorMsg('认养信息被删除');
+
+ }
+
+ $goods_info = [
+
+ 'send_tmpl_id' => $cliam_info['send_tmpl_id'],
+
+ 'goods_num' => $input['send_num'],
+
+ 'total_weight' => $input['send_num'],
+ ];
+
+ $send_data = $config_model->getGoodsSendPrice($input['address_id'], $goods_info, 2, 2);
+
+ if (!empty($send_data['code'])) {
+
+ $this->errorMsg($send_data['msg']);
+ }
+
+ $send_price = $send_data['price'];
+
+ $send_tmpl_type = $send_data['type'];
+
+ } else {
+
+ $address['user_name'] = $input['user_name'];
+
+ $address['mobile'] = $input['mobile'];
+
+ }
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'order_id' => $input['order_id'],
+
+ 'pay_model' => $input['pay_model'],
+
+ 'user_id' => $order['user_id'],
+
+ 'farmer_id' => $order['farmer_id'],
+
+ 'pay_price' => $send_price,
+
+ 'get_integral' => $send_price,
+
+ 'order_code' => orderCode(),
+
+ 'text' => $input['text'],
+ //
+ 'over_time' => time() + $this->_config['over_time'] * 60,
+
+ 'type' => 1,
+
+ 'start_time' => $input['start_time'],
+
+ 'end_time' => $input['end_time'],
+
+ 'times' => $times + 1,
+
+ 'send_type' => $input['send_type'],
+
+ 'address' => $input['send_type'] == 2 ? $address['address'] . $address['address_info'] : '',
+
+ 'user_name' => $address['user_name'],
+
+ 'mobile' => $address['mobile'],
+
+ 'lng' => $input['send_type'] == 2 ? $address['lng'] : '',
+
+ 'lat' => $input['send_type'] == 2 ? $address['lat'] : '',
+
+ 'balance' => $input['pay_model'] == 2 ? $send_price : 0,
+
+ 'goods_num' => isset($send_tmpl_type) && $send_tmpl_type == 1 ? $input['send_num'] : 0,
+
+ 'weight' => isset($send_tmpl_type) && $send_tmpl_type == 2 ? $input['send_num'] : 0,
+
+ ];
+
+ $res = $send_order_model->dataAdd($order_insert);
+
+ if ($res == 0) {
+
+ $this->errorMsg('申请配送失败');
+ }
+ //如果是0元
+ if ($order_insert['pay_price'] <= 0) {
+
+ $send_order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if ($input['pay_model'] == 2) {
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance = $user_model->where(['id' => $this->getUserId()])->value('balance');
+
+ if ($user_balance < $order_insert['pay_price']) {
+
+ $this->errorMsg('余额不足');
+ }
+
+ $send_order_model->orderResult($order_insert['order_code'], $order_insert['order_code']);
+
+ return $this->success(true);
+
+ } elseif ($input['pay_model'] == 3) {
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'], $order_insert['pay_price'], '配送订单');
+
+ $arr['pay_list'] = $jsApiParameters;
+
+ $arr['order_code'] = $order_insert['order_code'];
+
+ } else {
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters = $pay_controller->createWeixinPay($this->payConfig(), $this->getUserInfo()['openid'], $this->_uniacid, "认养配送订单", ['type' => 'ClaimSend', 'out_trade_no' => $order_insert['order_code']], $order_insert['pay_price']);
+
+ $arr['pay_list'] = $jsApiParameters;
+
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 15:23
+ * @功能说明:配送订单下单详情
+ */
+ public function sendOrderPayInfo()
+ {
+
+ $input = $this->_param;
+
+ $order_model = new ClaimOrder();
+
+ $farmer_model = new Farmer();
+
+ $config_model = new Config();
+
+ $address_model = new Address();
+
+ $order = $order_model->dataInfo(['id' => $input['order_id']]);
+
+ $farmer = $farmer_model->dataInfo(['id' => $order['farmer_id']]);
+
+ if (empty($farmer)) {
+
+ $this->errorMsg('农场主未找到');
+ }
+
+ $address = $address_model->dataInfo(['id' => $input['address_id']]);
+
+ if (empty($address)) {
+
+ $this->errorMsg('地址信息未找到');
+
+ }
+ $cliam_info = $this->model->dataInfo(['id' => $order['claim_id']]);
+
+ $freightTemplate_model = new FreightTemplate();
+
+ $data['send_tmpl'] = $freightTemplate_model->dataInfo(['id' => $cliam_info['send_tmpl_id']]);
+
+ if (!empty($input['send_num'])) {
+
+ $goods_info = [
+
+ 'send_tmpl_id' => $cliam_info['send_tmpl_id'],
+
+ 'goods_num' => $input['send_num'],
+
+ 'total_weight' => $input['send_num'],
+ ];
+
+ $data['send_price'] = $config_model->getGoodsSendPrice($input['address_id'], $goods_info, 2);
+
+ if (!empty($data['send_price']['code'])) {
+
+ $this->errorMsg($data['send_price']['msg']);
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 15:10
+ * @功能说明:获取配送时间段
+ */
+ public function sendTime()
+ {
+
+ $config_model = new Config();
+
+ $send_config = new SendConfig();
+
+ $config = $config_model->dataInfo(['uniacid' => $this->_uniacid]);
+
+ $config['app_day'] = $config['app_day'] > 30 ? 30 : $config['app_day'];
+
+ $i = 0;
+ //预约的每一天
+ while ($i < $config['app_day']) {
+
+ $time = time() + 86400 * $i;
+
+ $arr['date'] = date('Y-m-d', $time);
+
+ $arr['week'] = changeWeek(date('w', $time));
+
+ $data['date'][] = $arr;
+
+ $i++;
+ }
+ //每天时间段
+ $data['time'] = $send_config->where(['uniacid' => $this->_uniacid, 'status' => 1])->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:57
+ * @功能说明:配送订单退款
+ */
+ public function sendOrderRefund()
+ {
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id' => $input['id']]);
+
+ if (empty($send_order)) {
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if ($send_order['pay_type'] != 2) {
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ Db::startTrans();
+
+ $res = $send_order_model->refundCash($send_order, $this->payConfig($this->_uniacid));
+
+ if (!empty($res['code'])) {
+
+ $this->errorMsg($res['msg']);
+ }
+
+ $send_order_model->dataUpdate(['id' => $send_order['id']], ['refund_time' => time(), 'pay_type' => -1, 'refund' => 1]);
+ //增加财务流水
+ $fin_water_model = new FinanceWater();
+
+ $res = $fin_water_model->addWater($input['id'], 11, 1, 1);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败1');
+ }
+
+ $res = $fin_water_model->dataUpdate(['order_id' => $send_order['id'], 'type' => 10], ['cash_status' => 1]);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败3');
+ }
+ Db::commit();
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 10:24
+ * @功能说明:配送订单收货
+ */
+ public function sendOrderReceiving()
+ {
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id' => $input['id']]);
+
+ if (empty($send_order)) {
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if ($send_order['pay_type'] != 3) {
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $send_order_model->sendOrderReceiving($send_order);
+
+ if (!empty($res['code'])) {
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 14:00
+ * @功能说明:配送订单详情
+ */
+ public function sendOrderInfo()
+ {
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $claim_order_model = new ClaimOrder();
+
+ $send_order = $send_order_model->dataInfo(['id' => $input['id']]);
+
+ $send_order['create_time'] = date('Y-m-d H:i:s', $send_order['create_time']);
+
+ $send_order['time_text'] = date('Y-m-d H:i', $send_order['start_time']) . '~' . date('H:i', $send_order['end_time']);
+
+ $send_order['pay_time'] = $send_order['pay_time'] > 0 ? date('Y-m-d H:i:s', $send_order['pay_time']) : 0;
+
+ $send_order['send_time'] = $send_order['send_time'] > 0 ? date('Y-m-d H:i:s', $send_order['send_time']) : 0;
+
+ $send_order['receiving_time'] = $send_order['receiving_time'] > 0 ? date('Y-m-d H:i:s', $send_order['receiving_time']) : 0;
+
+ $send_order['refund_time'] = $send_order['refund_time'] > 0 ? date('Y-m-d H:i:s', $send_order['refund_time']) : 0;
+
+ $send_order['claim_order'] = $claim_order_model->dataInfo(['id' => $send_order['order_id']]);
+
+ return $this->success($send_order);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-10 00:40
+ * @功能说明:可用的优惠券列表
+ */
+ public function couponList()
+ {
+
+ $input = $this->_param;
+
+ $coupon_model = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $order_model = new ClaimOrder();
+
+ $order_info = $order_model->payOrderInfo($input);
+
+ $coupon_id = $coupon_model->canUseCoupon($this->getUserId(), $order_info['pay_price'], 3);
+
+ $data = $coupon_record_model->where('id', 'in', $coupon_id)->order('id desc')->paginate(10)->toArray();
+
+ if (!empty($data['data'])) {
+
+ foreach ($data['data'] as &$v) {
+
+ $v['start_time'] = date('Y.m.d H:i', $v['start_time']) . ' - ' . date('Y.m.d H:i', $v['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 15:15
+ * @功能说明:用户认养拼团
+ */
+ public function userCollageLimit()
+ {
+
+ $input = $this->_param;
+
+ $collage_model = new CollageJoin();
+
+ $dis[] = ['a.user_id', '=', $this->getUserId()];
+
+ $dis[] = ['a.status', '=', 1];
+
+ $data = $collage_model->userCollageLimit($dis);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 15:15
+ * @功能说明:用户认养拼团列表
+ */
+ public function userCollageList()
+ {
+
+ $input = $this->_param;
+
+ $collage_model = new CollageJoin();
+
+ $dis[] = ['a.user_id', '=', $this->getUserId()];
+
+ if (!empty($input['status']) && $input['status'] == 2) {
+
+ $dis[] = ['a.status', '=', $input['status']];
+
+ } else {
+
+ $dis[] = ['a.status', 'in', [1, 3]];
+ }
+
+ $data = $collage_model->userCollagePage($dis);
+
+ $data['total_num'] = $collage_model->userCollageCount($this->getUserId());
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 16:12
+ * @功能说明:拼团商品列表
+ */
+ public function collageList()
+ {
+
+ $collage_model = new ClaimCollage();
+
+ $dis[] = ['a.uniacid', '=', $this->_uniacid];
+
+ $dis[] = ['a.status', '=', 1];
+
+ $dis[] = ['a.start_time', '<', time()];
+
+ $dis[] = ['a.end_time', '>', time()];
+
+ if (!empty($input['title'])) {
+
+ $dis[] = ['a.title', 'like', '%' . $input['title'] . '%'];
+ }
+
+ if (!empty($input['goods_name'])) {
+
+ $dis[] = ['b.title', 'like', '%' . $input['goods_name'] . '%'];
+ }
+
+ $data = $collage_model->adminDataList($dis);
+
+ if (!empty($data['data'])) {
+
+ foreach ($data['data'] as &$v) {
+
+ $v['time_text'] = lbGetDatesss($v['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+ public function getEarInfoList(){
+ $input = $this->_param;
+
+ $model = new ClaimEarTagLog();
+ $data = $model->getList($input);
+ return $this->success($data);
+ }
+
+}
diff --git a/app/farm/controller/IndexCoupon.php b/app/farm/controller/IndexCoupon.php
new file mode 100755
index 0000000..abbec5a
--- /dev/null
+++ b/app/farm/controller/IndexCoupon.php
@@ -0,0 +1,187 @@
+model = new Coupon();
+
+ $this->atv_model = new BagAtv();
+
+ $this->record_model = new CouponRecord();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-02 11:07
+ * @功能说明:正在进行中的福包活动
+ */
+ public function bagIngInfo(){
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['start_time','<',time()];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->atv_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('活动已结束');
+ }
+
+ $where = [
+
+ 'atv_id' => $data['id'],
+
+ 'user_id'=> $this->getUserId(),
+
+ 'status' => 1
+ ];
+ //查看自己是否领取过
+ $user_record = $this->record_model->dataInfo($where);
+
+ if(!empty($user_record)){
+ //已经领取
+ $data['active_status'] = 2;
+
+ }elseif ($data['user_num']<$data['have_num']){
+ //已经领完
+ $data['active_status'] = 3;
+
+ }else{
+ //进行中
+ $data['active_status'] = 1;
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-02 13:44
+ * @功能说明:新客户获取活动优惠券
+ */
+ public function getAtvCoupon(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->atv_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('活动已结束');
+ }
+
+ $where = [
+
+ 'atv_id' => $data['id'],
+
+ 'user_id'=> $this->getUserId(),
+
+ 'status' => 1
+ ];
+ //查看自己是否领取过
+ $user_record = $this->record_model->dataInfo($where);
+
+ if(empty($user_record)){
+
+ $this->errorMsg('你已经领取过了');
+ }
+ //添加领取记录
+ Db::startTrans();
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'get_user' => $this->getUserId(),
+
+ 'share_user'=> $input['share_user'],
+
+ 'atv_id' => $data['id'],
+
+ 'user_coupon'=> $data['user_coupon'],
+
+ 'user_coupon_num'=> $data['user_coupon_num'],
+
+ 'share_coupon'=> $data['share_coupon'],
+ ];
+
+ $res = $this->record_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('领取失败');
+ }
+
+ $id = $this->record_model->getLastInsID();
+
+ $coupon_record_model = new CouponRecord();
+ //给新客户发优惠券
+ $res = $coupon_record_model->recordAdd($data['user_coupon'],$insert['get_user'],$id);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexFarmer.php b/app/farm/controller/IndexFarmer.php
new file mode 100755
index 0000000..77fadc2
--- /dev/null
+++ b/app/farm/controller/IndexFarmer.php
@@ -0,0 +1,1751 @@
+model = new Farmer();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['type','=',1];
+
+ $cap_dis[] = ['status','in',[2,3]];
+
+ $this->farmer = $this->model->dataInfo($cap_dis);
+
+ $action = $this->request->action();
+
+ if(empty($this->farmer)&&!in_array($action,['sourceInfo'])){
+
+ $this->errorMsg('你还不是农场主');
+ }
+
+ $this->address_model = new Address();
+//
+ $this->land_model = new LandList();
+
+ $this->massif_model = new Massif();
+
+// $this->coupon_record_model = new CouponRecord();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-24 16:13
+ * @功能说明:农场主详情
+ */
+ public function farmerInfo(){
+
+ return $this->success($this->farmer);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-24 16:16
+ * @功能说明:编辑农场主
+ */
+ public function farmerUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $this->farmer['id']
+ ];
+
+ if(isset($input['imgs'])){
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+ }
+
+ if(isset($input['idcard_imgs'])){
+
+ $input['idcard_imgs'] = !empty($input['idcard_imgs'])?implode(',',$input['idcard_imgs']):'';
+
+ }
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:51
+ * @功能说明:土地列表
+ */
+ public function landList(){
+
+ $input = $this->_param;
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $data = $this->land_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:添加土地
+ */
+ public function landAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['farmer_id'] = $this->farmer['id'];
+
+ $res = $this->land_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:编辑土地
+ */
+ public function landUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->land_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:编辑土地
+ */
+ public function landStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $res = $this->land_model->where($dis)->update($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 18:05
+ * @功能说明:土地详情
+ */
+ public function landInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->land_model->landInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:43
+ * @功能说明:地块列表
+ */
+ public function massifList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->massif_model->dataList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:43
+ * @功能说明:地块列表下拉框
+ */
+ public function massifSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->massif_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:49
+ * @功能说明:添加地块
+ */
+ public function massifAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['farmer_id'] = $this->farmer['id'];
+
+ $data = $this->massif_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑地块
+ */
+ public function massifUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+ //删除
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $find = $this->land_model->landSomeFind($input['id'],1);
+
+ if($find==1){
+
+ $this->errorMsg('该地块服务正在被使用');
+ }
+
+ }
+
+ $data = $this->massif_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:地块详情
+ */
+ public function massifInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->massif_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:54
+ * @功能说明:种子列表
+ */
+ public function seedList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:54
+ * @功能说明:种子列表
+ */
+ public function seedSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:57
+ * @功能说明:添加种子
+ */
+ public function seedAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['farmer_id'] = $this->farmer['id'];
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑种子
+ */
+ public function seedUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $seed_model = new Seed();
+ //删除
+ if(isset($input['status'])&&in_array($input['status'],[-1,0])){
+
+ $find = $this->land_model->landSomeFind($input['id'],2);
+
+ if($find==1){
+
+ $this->errorMsg('该种子正在被使用');
+ }
+
+ }
+
+ $data = $seed_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 14:50
+ * @功能说明:编辑种子
+ */
+ public function seedInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $seed_model = new Seed();
+
+ $data = $seed_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 15:28
+ * @功能说明:认养管理列表
+ */
+ public function claimList(){
+
+ $input = $this->_param;
+
+ $claim_model = new Claim();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $claim_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:添加认养
+ */
+ public function claimAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['farmer_id'] = $this->farmer['id'];
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:认养详情
+ */
+ public function claimInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->dataInfo($dis);
+
+ $claim_text_model = new ClaimText();
+
+ $monitor_text_model= new MonitorText();
+
+ $monitor_model = new Monitor();
+ //流程
+ $res['process'] = $claim_text_model->where(['claim_id'=>$input['id']])->select()->toArray();
+ //监控
+ $res['monitor'] = $monitor_text_model->where(['obj_id'=>$input['id'],'type'=>2])->column('monitor_id');
+
+ $res['monitor'] = array_values($res['monitor']);
+
+ $res['monitor'] = $monitor_model->where('id','in',$res['monitor'])->where(['status'=>1])->select()->toArray();
+
+ $cate_model = new LandCate();
+ //分类名字
+ $res['cate_name'] = $cate_model->where(['id'=>$res['cate_id'],'type'=>2])->value('title');
+
+ $source_model = new Source();
+ //溯源名字
+ $res['source_name'] = $source_model->where(['id'=>$res['source_id']])->value('title');
+
+ $mac_model = new Machine();
+ //仪器名字
+ $res['machine_name'] = $mac_model->where(['id'=>$res['machine_id'],'status'=>1])->value('title');
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:编辑认养
+ */
+ public function claimUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:32
+ * @功能说明:编辑认养
+ */
+ public function claimStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $claim_model = new Claim();
+
+ $res = $claim_model->where($dis)->update($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:04
+ * @功能说明:溯源列表
+ */
+ public function sourceList(){
+
+ $input = $this->_param;
+
+ $source_model = new Source();
+
+// $source_text_model = new SourceText();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $data = $source_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:04
+ * @功能说明:溯源下拉框
+ */
+ public function sourceSelect(){
+
+ $input = $this->_param;
+
+ $source_model = new Source();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $data = $source_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:10
+ * @功能说明:添加溯源
+ */
+ public function sourceAdd(){
+
+ $input = $this->_input;
+
+ $source_model = new Source();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['farmer_id'] = $this->farmer['id'];
+
+ $res = $source_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:12
+ * @功能说明:编辑溯源
+ */
+ public function sourceUpdate(){
+
+ $input = $this->_input;
+
+ $source_model = new Source();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+ //删除
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $find = $this->land_model->landSomeFind($input['id'],3);
+
+ if($find==1){
+
+ $this->errorMsg('该溯源正在被使用');
+ }
+
+ }
+
+ $res = $source_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:12
+ * @功能说明:编辑溯源
+ */
+ public function sourceInfo(){
+
+ $input = $this->_param;
+
+ $source_model = new Source();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $source_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:29
+ * @功能说明:养殖管理
+ */
+ public function breedList(){
+
+ $input = $this->_param;
+
+ $breed_model = new Breed();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $data = $breed_model->dataList($dis,10);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:30
+ * @功能说明:添加养殖管理
+ */
+ public function breedAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['farmer_id'] = $this->farmer['id'];
+
+ $breed_model = new Breed();
+
+ $res = $breed_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:34
+ * @功能说明:编辑养殖管理
+ */
+ public function breedUpdate(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $breed_model = new Breed();
+
+ $res = $breed_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 10:34
+ * @功能说明:编辑养殖管理
+ */
+ public function breedInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $breed_model = new Breed();
+
+ $res = $breed_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:15
+ * @功能说明:申请提现
+ */
+ public function applyWallet(){
+
+ $input = $this->_input;
+
+ $wallet_model = new Wallet();
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ if($input['apply_price']>$this->farmer['cash']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ Db::startTrans();
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_code' => orderCode(),
+
+ 'farmer_id' => $this->farmer['id'],
+
+ 'pay_price' => $input['apply_price'],
+
+ 'text' => $input['text'],
+
+ 'true_price' => round($input['apply_price']*$config['cash_balance']/100,2),
+
+ 'balance' => $config['cash_balance'],
+ ];
+ //发起提现
+ $res = $wallet_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ $water_model = new FinanceWater();
+
+ $id = $wallet_model->getLastInsID();
+ //添加拒绝提现记录
+ $res = $water_model->addWater($id,7,1,1);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+ //执行记录
+ $res = $water_model->cashArrival($this->farmer['id']);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 15:06
+ * @功能说明:农场主财务详情
+ */
+ public function farmerFinanceInfo(){
+
+ $water_model = new FinanceWater();
+
+ $water_model->cashArrival($this->farmer['id']);
+ //余额
+ $data['cash'] = $this->model->where(['id'=>$this->farmer['id']])->value('cash');
+
+ $water_data = $water_model->getDayCash($this->farmer['id']);
+ //总金额
+ $data['total_cash'] = $water_data['income_cash'];
+ //冻结金额
+ $data['frozen_cash']= $water_model->where(['farmer_id'=>$this->farmer['id'],'add'=>1,'role_type'=>1])->where('cash_status','in',[0,1])->sum('price');
+
+ $data['frozen_cash']= round($data['frozen_cash'],2);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 16:35
+ * @功能说明:农场主流水记录
+ */
+ public function farmerFinanceList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $dis[] = ['role_type','=',1];
+
+ if(isset($input['add'])){
+
+ $dis[] = ['add','=',$input['add']];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $water_model = new FinanceWater();
+
+ $data = $water_model->dataList($dis,10);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 17:09
+ * @功能说明:农场主提现列表
+ */
+ public function walletList(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'farmer_id' => $this->farmer['id'],
+
+ 'is_show' => 1,
+
+ 'uniacid' => $this->_uniacid
+
+ ];
+
+ if(!empty($input['status'])){
+
+ $dis['status'] = $input['status'];
+ }
+
+ $wallet_model = new Wallet();
+
+ $data = $wallet_model->dataList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-31 15:11
+ * @功能说明:认养和土地分类
+ */
+ public function landAndClaimCate(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'a.status' => 1,
+
+ 'a.uniacid'=> $this->_uniacid,
+
+ 'a.type' => $input['type']
+ ];
+
+ $where = [
+
+ 'a.is_public' => 1,
+
+ 'b.farmer_id' => $this->farmer['id']
+ ];
+
+ $cate_model = new LandCate();
+
+ $data = $cate_model->alias('a')
+ ->join('lbfarm_land_cate_text b','a.id = b.cate_id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 15:52
+ * @功能说明:养殖订单列表
+ *
+ */
+
+ public function breedOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['pay_type','>',1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $order_model = new BreedOrder();
+
+ $data = $order_model->dataList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 15:16
+ * @功能说明:认养订单
+ */
+ public function claimOrderList(){
+
+ $input = $this->_param;
+
+ $order_model = new ClaimOrder();
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['pay_type','=',$input['pay_type']];
+
+ }else{
+
+ $dis[] = ['pay_type','>',-1];
+
+ }
+
+ $data = $order_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ $address_model = new OrderAddress();
+
+ foreach ($data['data'] as &$v){
+ //地址信息
+ $v['address_info'] = $address_model->dataInfo(['order_id'=>$v['id'],'type'=>2]);
+ }
+ }
+
+ $arr = [
+ //认养中
+ 2 => 'claim_ing',
+ //配送中
+ 3 => 'send_ing'
+ ];
+
+ foreach ($arr as $k=>$value){
+
+ $dis = [
+
+ 'pay_type' => $k,
+
+ 'farmer_id'=> $this->farmer['id']
+ ];
+
+ $data[$value] = $order_model->where($dis)->where('pay_time','>',0)->count();
+ }
+
+ return $this->success($data);
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 09:47
+ * @功能说明:发货订单发货
+ */
+ public function sendOrderSend(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $update = [
+
+ 'pay_type' => 3,
+
+ 'send_time'=> time(),
+
+ 'auto_receiving_time' => $this->_config['auto_hx_time']*86400+time()
+
+ ];
+
+ Db::startTrans();
+
+ $res = $send_order_model->dataUpdate(['id'=>$input['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('发货失败');
+ }
+
+ if($send_order['type']==1){
+
+ $claim_order_model = new ClaimOrder();
+
+ $claim_order_model->dataUpdate(['id'=>$send_order['order_id']],['pay_type'=>3]);
+ }
+
+ Db::commit();
+
+ return $this->success(true);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:14
+ * @功能说明:配送订单列表
+ */
+ public function farmerSendOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $dis[] = ['pay_time','>',0];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['pay_type','=',$input['pay_type']];
+ }
+
+ $send_order_model = new SendOrder();
+
+ $data = $send_order_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['time_text'] = date('Y-m-d H:i',$v['start_time']).'~'.date('H:i',$v['end_time']);
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ $v['pay_time'] = $v['pay_time']>0?date('Y-m-d H:i:s',$v['pay_time']):0;
+
+ $v['send_time'] = $v['send_time']>0?date('Y-m-d H:i:s',$v['send_time']):0;
+
+ $v['receiving_time'] = $v['receiving_time']>0?date('Y-m-d H:i:s',$v['receiving_time']):0;
+
+ $v['refund_time'] = $v['refund_time']>0?date('Y-m-d H:i:s',$v['refund_time']):0;
+ }
+ }
+
+ $arr = [
+ //待配送
+ 2 => 'no_send',
+ //配送中
+ 3 => 'send_ing'
+ ];
+
+ foreach ($arr as $k=>$value){
+
+ $dis = [
+
+ 'pay_type' => $k,
+
+ 'farmer_id'=> $this->farmer['id']
+ ];
+
+ $data[$value] = $send_order_model->where($dis)->where('pay_time','>',0)->count();
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 09:47
+ * @功能说明:配送订单收货
+ */
+ public function sendOrderPickup(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $send_order_model->sendOrderReceiving($send_order);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:26
+ * @功能说明:用户下单列表
+ */
+ public function landOrderList(){
+
+ $input = $this->_param;
+
+ $order_model = new LandOrder();
+
+ $farmer_model = new Farmer();
+
+ $order_model->orderInit($this->getUserId());
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['pay_type','=',$input['pay_type']];
+
+ }else{
+
+ $dis[] = ['pay_type','>',-1];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ $data = $order_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ $address_model = new OrderAddress();
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id'=>$v['farmer_id']],'title');
+
+ $v['end_time'] = date('Y-m-d H:i:s',$v['end_time']);
+ //地址信息
+ $v['address_info'] = $address_model->dataInfo(['order_id'=>$v['id'],'type'=>1]);
+
+ }
+ }
+
+ $arr = [1=>'no_pay_count',2=>'rent_count',3=>'send_count'];
+
+ foreach ($arr as $key => $value){
+
+ $where = [
+
+ 'farmer_id' => $this->farmer['id'],
+
+ 'pay_type' => $key
+ ];
+
+ $data['count'][$value] = $order_model->where($where)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 11:00
+ * @功能说明:仪器列表
+ */
+ public function machineSelect(){
+
+ $input = $this->_param;
+
+ $mac_model = new Machine();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $data = $mac_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 17:11
+ * @功能说明:生成二维码
+ */
+ public function getSourceQr(){
+
+ $input = $this->_input;
+
+ $uniacid = $this->_uniacid;
+
+ $key = 'sourcekey'.$input['id'];
+
+ $qr = getCache($key,$uniacid);
+
+ if(empty($qr)||!empty($input['is_update'])){
+
+ $data = longbingCreateWxCode($uniacid,$input,$input['page']);
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+ $qr = $data['qr_path'];
+ }
+
+ return $this->success($qr);
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 11:03
+ * @功能说明:订单列表
+ */
+ public function shopOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.farmer_id','=',$this->farmer['id']];
+
+ $dis[] = ['a.farmer_show','=',1];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }else{
+
+ $dis[] = ['a.pay_type','>',1];
+
+ }
+
+ $order_model = new ShopOrder();
+
+ $data = $order_model->indexDataList($dis,$where);
+
+ $arr = [
+ //未发货
+ 'no_send_count' => 2,
+ //已经发货
+ 'have_send_count'=> 3
+ ];
+
+ foreach ($arr as $ks=>$vs){
+
+ $map = [
+
+ 'farmer_id'=> $this->farmer['id'],
+
+ 'pay_type'=> $vs,
+
+ 'farmer_show' => 1
+ ];
+
+ $data[$ks] = $order_model->where($map)->count();
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function shopOrderInfo(){
+
+ $input = $this->_param;
+
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new ShopOrder();
+
+ $data = $order_model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $time_arr = ['create_time','pay_time','end_time','hx_time','over_time','cancel_time'];
+
+ foreach ($time_arr as $v){
+
+ $data[$v] = !empty($data[$v])?date('Y-m-d H:i:s',$data[$v]):$data[$v];
+
+ }
+
+ $data['distance'] = distance_text($data['distance']);
+
+ $end_time = date('H:i',$data['send_end_time'])=='00:00'?'24:00':date('H:i',$data['send_end_time']);
+ //配送时间
+ $data['user_send_time'] = date('Y-m-d H:i',$data['send_start_time']).'~'.$end_time;
+
+ $farmer_model = new Farmer();
+
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']],'title');
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 11:08
+ * @功能说明:地主商城订单发货
+ */
+ public function shopOrderSend(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new ShopOrder();
+
+ $order = $order_model->dataInfo($dis);
+
+ if(empty($order)||$order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+ $refund_model = new ShopRefund();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$input['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $config_model = new Config();
+
+ // $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $update = [
+
+ //'pay_type' => 3,
+
+// 'express_company' => $input['express_company'],
+//
+// 'express_code' => $input['express_code'],
+//
+// 'express_mobile' => $input['express_mobile'],
+//
+// 'express_user' => $input['express_user'],
+
+ // 'send_time' => time(),
+
+ 'video' => $input['video'],
+
+ //'hx_over_time' => time()+$config['auto_hx_time']*86400,
+
+ ];
+
+ $data = $order_model->dataUpdate($dis,$update);
+
+// $water_model = new FinanceWater();
+// //商城订单农场主获得运费
+// $water_model->addWater($order['id'],16,1,0);
+
+// $order = $order_model->dataInfo($dis);
+//
+// $order_model->sendOrderService($order);
+
+ return $this->success($data);
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:22
+ * @功能说明:监控列表
+ */
+ public function monitorSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $dis[] = ['farmer_id','=',$this->farmer['id']];
+
+ $monitor_model = new Monitor();
+
+ $data = $monitor_model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexGoods.php b/app/farm/controller/IndexGoods.php
new file mode 100755
index 0000000..67df423
--- /dev/null
+++ b/app/farm/controller/IndexGoods.php
@@ -0,0 +1,441 @@
+model = new ShopGoods();
+
+ $this->cate_model = new ShopGoodsCate();
+
+ $this->car_model = new Car();
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 11:57
+ * @功能说明:首页选择店铺列表
+ */
+ public function indexStoreList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['business_status','=',1];
+
+ if(!empty($input['store_name'])){
+
+ $dis[] = ['title','like','%'.$input['store_name'].'%'];
+ }
+
+ $lat = !empty($input['lat'])?$input['lat']:0;
+
+ $lng = !empty($input['lng'])?$input['lng']:0;
+
+ $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(3.1415926535898*('.$lat.'-lat)/360),2)+COS(3.1415926535898*'.$lat.'/180)* COS('.$lat.' * 3.1415926535898/180)*POW(SIN(3.1415926535898*('.$lng.'-lng)/360),2))))*1000 as distance';
+
+ $alhs = '(2 * 6378.137* ASIN(SQRT(POW(SIN(3.1415926535898*('.$lat.'-lat)/360),2)+COS(3.1415926535898*'.$lat.'/180)* COS('.$lat.' * 3.1415926535898/180)*POW(SIN(3.1415926535898*('.$lng.'-lng)/360),2))))*1000<20000';
+
+ $store_model = new Farmer();
+
+ $data = $store_model->dataDistanceList($dis,$alh,$alhs,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['distance'] = getDistances($v['lng'],$v['lat'],$lng,$lat);
+
+ $v['distance'] = $store_model->getDistanceAttr($v['distance']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:24
+ * @功能说明:选择门店
+ */
+ public function selectStore(){
+
+ $input = $this->_input;
+
+ $user_model = new User();
+
+ $res = $user_model->dataUpdate(['id'=>$this->getUserId()],['last_store_id'=>$input['store_id']]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 16:46
+ * @功能说明:分类列表
+ */
+ public function goodsIndex(){
+
+ $input = $this->_param;
+
+ $store_id = !empty($input['store_id'])?$input['store_id']:0;
+
+ $data['cate_id'] = $this->cate_model->shopCateList($this->_uniacid,$store_id);
+
+ if(!empty($store_id)){
+
+ $store_model = new Farmer();
+
+ $data['store_info'] = $store_model->dataInfo(['id'=>$store_id]);
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 13:47
+ * @功能说明:
+ */
+ public function haveSelectStoreId(){
+
+ return $this->success($this->getStoreInfo()['id']);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 15:27
+ * @功能说明:商品列表
+ */
+ public function goodsList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','=',1];
+
+ // $dis[] = ['a.index_show','=',1];
+
+ $dis[] = ['d.status','=',2];
+
+ $dis[] = ['d.business_status','=',1];
+
+ if(!empty($input['store_id'])){
+
+ $dis[] = ['b.store_id','=',$input['store_id']];
+ }
+
+ if(!empty($input['cate_id'])){
+
+ $dis[] = ['c.cate_id','=',$input['cate_id']];
+
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['a.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+ //商品信息
+ $data = $this->model->indexGoodsList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $where = [
+
+ 'type' => 5,
+
+ 'user_id' => $this->getUserId()
+ ];
+
+ $v['car_count'] = $this->car_model->where($where)->count();
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:46
+ * @功能说明:商品详情
+ */
+ public function goodsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $farm_model = new Farmer();
+
+ $where[] = ['id','in',$data['store']];
+
+ $data['store_info'] = $farm_model->dataInfo($where);
+
+ $spe_model = new ShopGoodsSpe();
+
+ $spe_price_model = new GoodsSpePrice();
+
+ $where = [
+
+ 'goods_id' => $input['id'],
+
+ 'status' => 1
+ ];
+
+ $data['spe_text'] = $spe_model->goodsSpe($where);
+
+ $data['spe_price'] = $spe_price_model->goodsSpePrice($where);
+
+ $kill_model = new SeckillList();
+
+ $integral_model = new IntegralList();
+ //秒杀活动
+ $data['kill_list'] = $kill_model->atvIng($input['id'],0,2);
+
+ if(!empty($data['spe_price'])){
+
+ foreach ($data['spe_price'] as &$v){
+ //查询是否有秒杀活动
+ $v['kill_atv'] = $kill_model->atvIng($input['id'],$v['id']);
+
+ if(empty($v['kill_atv'])){
+ //积分活动
+ $v['integral_atv'] = $integral_model->atvIng($input['id'],$v['id']);
+
+ }else{
+
+ $v['integral_atv'] = [];
+ }
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:07
+ * @功能说明:购物车信息
+ */
+ public function carInfo(){
+
+ $input = $this->_param;
+
+ $store_id = !empty($input['store_id'])?$input['store_id']:0;
+ //购物车信息
+ $car_info = $this->car_model->carPriceAndCount($this->getUserId(),$store_id,1);
+
+ return $this->success($car_info);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:46
+ * @功能说明:添加到购物车
+ */
+ public function addCar(){
+
+ $input = $this->_input;
+
+ $is_show_del = !empty($input['is_show_del'])?$input['is_show_del']:1;
+
+ if($is_show_del==1){
+
+ $this->car_model->where(['user_id'=>$this->getUserId(),'is_show'=>2])->delete();
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'farmer_id'=> $input['store_id'],
+
+ 'goods_id'=> $input['goods_id'],
+
+ 'spe_id' => $input['spe_id'],
+
+ 'type' => 5,
+
+ 'is_show' => !empty($input['is_show'])?$input['is_show']:1,
+
+ ];
+
+ $input['goods_num'] = !empty($input['goods_num'])?$input['goods_num']:1;
+
+ $info = $this->car_model->dataInfo($insert);
+ //增加数量
+ if(!empty($info)){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['goods_num'=>$info['goods_num']+$input['goods_num']]);
+
+ }else{
+ //添加到购物车
+ $insert['goods_num'] = $input['goods_num'];
+
+ $insert['status'] = 1;
+
+ $res = $this->car_model->dataAdd($insert);
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:54
+ * @功能说明:删除购物车
+ */
+ public function delCar(){
+
+ $input = $this->_input;
+
+ $info = $this->car_model->dataInfo(['id'=>$input['id']]);
+
+ $input['goods_num'] = !empty($input['goods_num'])?$input['goods_num']:1;
+ //加少数量
+ if($info['goods_num']>$input['goods_num']){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['goods_num'=>$info['goods_num']-$input['goods_num']]);
+
+ }else{
+
+ $res = $this->car_model->where(['id'=>$info['id']])->delete();
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 10:39
+ * @功能说明:
+ */
+ public function carUpdate(){
+
+ $input = $this->_input;
+
+ if(!empty($input['id'])){
+
+ $res = $this->car_model->where('id','in',$input['id'])->update(['status'=>$input['status']]);
+
+ }else{
+
+ $res = $this->car_model->where('user_id','=',$this->getUserId())->update(['status'=>$input['status']]);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:59
+ * @功能说明:批量删除购物车
+ */
+ public function delSomeCar(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'farmer_id'=> $this->getStoreInfo()['id'],
+
+ 'type' => 5,
+
+ ];
+
+ $res = $this->car_model->where($dis)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+}
diff --git a/app/farm/controller/IndexInfo.php b/app/farm/controller/IndexInfo.php
new file mode 100755
index 0000000..e9148ba
--- /dev/null
+++ b/app/farm/controller/IndexInfo.php
@@ -0,0 +1,148 @@
+model = new SystemInfo();
+
+ $this->info_model = new WelfareColumn();
+
+ $this->record_model = new InfoRecord();
+
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-22 15:13
+ * @功能说明:查看自己的系统公告
+ */
+ public function systemInfoList(){
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $count = $this->model->where($dis)->where(['status'=>0])->count();
+
+ $this->model->where($dis)->where(['status'=>0])->update(['status'=>1]);
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->model->dataList($dis);
+
+ $data['no_read_count'] = $count;
+
+ $data['operate_no_read_count'] = $this->record_model->noReadCount($this->getUserId(),$this->_uniacid);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-22 15:54
+ * @功能说明:运营公告
+ */
+ public function operateInfoList(){
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['type','=',3];
+
+ $dis[] = ['status','=',1];
+
+ $data = $this->info_model->dataList($dis);
+ //未读消息数量
+ $data['operate_no_read_count'] = $this->record_model->noReadCount($this->getUserId(),$this->_uniacid);
+
+ $where[] = ['uniacid','=',$this->_uniacid];
+
+ $where[] = ['user_id','=',$this->getUserId()];
+
+ $data['no_read_count'] = $this->model->where($where)->where(['status'=>0])->count();
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-22 16:16
+ * @功能说明:运营公告详情
+ */
+ public function operateInfoInfo(){
+
+ $input = $this->_param;
+
+ $data = $this->info_model->dataInfo(['id'=>$input['id']]);
+
+ $insert = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'uniacid' => $this->_uniacid,
+
+ 'info_id' => $input['id']
+ ];
+
+ $find = $this->record_model->dataInfo($insert);
+
+ if(empty($find)){
+
+ $this->record_model->dataAdd($insert);
+ }
+
+ return $this->success($data);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexLand.php b/app/farm/controller/IndexLand.php
new file mode 100755
index 0000000..7d024d1
--- /dev/null
+++ b/app/farm/controller/IndexLand.php
@@ -0,0 +1,1232 @@
+app = $app;
+
+ $this->model = new LandList();
+
+ $this->cate_model = new LandCate();
+
+ autoCancelOrder($this->_uniacid);
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:42
+ * @功能说明:认养分类列表
+ */
+ public function landCateList(){
+
+ $input = $this->_param;
+
+ $cate_model = new LandCate();
+
+ $dis = [
+
+ 'type' => 1,
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ $data = $cate_model->where($dis)->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:53
+ * @功能说明:土地列表
+ */
+ public function landList(){
+
+ $input = $this->_param;
+
+ $farmer_model = new Farmer();
+
+ $input['sort'] = !empty($input['sort'])?$input['sort']:1;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($input['cate_id'])){
+
+ $dis[] = ['b.cate_id','=',$input['cate_id']];
+
+ $dis[] = ['b.type','=',2];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['a.title','like','%'.$input['title'].'%'];
+
+ }
+
+ if(!empty($input['farmer_id'])){
+
+ $dis[] = ['a.farmer_id','=',$input['farmer_id']];
+
+ }else{
+
+ $id = $farmer_model->farmerId($this->_uniacid);
+
+ $dis[] = ['a.farmer_id','in',$id];
+
+ }
+
+ $lat = !empty($input['lat'])?$input['lat']:0;
+
+ $lng = !empty($input['lng'])?$input['lng']:0;
+
+ $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(PI()*('.$lng.'- `lng`)/360),2)+COS(PI()*33.07078170776367/180)* COS('.$lat.' * PI()/180)*POW(SIN(PI()*('.$lat.'- lat)/360),2))))*1000 as distance';
+
+ $data = $this->model->indexDataListV2($dis,$alh,$input['sort']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 10:34
+ * @功能说明:土地详情
+ */
+ public function landInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->landInfo($dis);
+
+ $farmer_model = new Farmer();
+ //农场主消息
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']],'mobile,title,cover');
+
+ $app_num = 0;
+
+ if(!empty($data['spe'])){
+
+ $order_model = new LandOrder();
+
+ foreach ($data['spe'] as &$v){
+
+ $dis = [
+
+ 'land_id' => $input['id'],
+
+ 'spe_id' => $v['id']
+ ];
+
+ $is_app = $order_model->where($dis)->where('pay_type','>=',1)->find();
+
+ $v['is_app'] = !empty($is_app)?1:0;
+
+ if($v['is_app']==1){
+
+ $app_num ++;
+ }
+
+ }
+
+ }
+
+ $data['spe_info'] = [
+ //总数量
+ 'all_num' => count($data['spe']),
+ //已被预约数量
+ 'app_num' => $app_num
+
+ ];
+
+ $mac_model = new Machine();
+ //仪器详情
+ $data['machine_info'] = $mac_model->getDataInfo($input['id']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-11 11:24
+ * @功能说明:土地预支付信息
+ */
+ public function landPayOrderInfo(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $farmer_model = new Farmer();
+
+ $data = $order_model->payOrderInfo($input);
+
+ if(!empty($data['code'])){
+
+ $this->errorMsg($data['msg']);
+ }
+
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['land']['farmer_id']],'title');
+
+ $address_model = new Address();
+
+ if(!empty($input['address_id'])){
+ //地址
+ $data['address']= $address_model->dataInfo(['id'=>$input['address_id']]);
+ }else{
+
+ $data['address'] = $address_model->dataInfo(['user_id'=>$this->getUserId(),'status'=>1]);
+ }
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $data['tmp_list'] = $tmpl_model->where(['uniacid'=>$this->_uniacid])->where('tmpl_name','in',['land_order','land_over'])->select()->toArray();
+
+ $coupon_modle = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+ //可用优惠券数量
+ $canUseCoupon = $coupon_modle->canUseCoupon($this->getUserId(),$data['init_price'],2);
+
+ $data['canUseCoupon'] = $coupon_record_model->where('id','in',$canUseCoupon)->sum('num');
+
+ return $this->success($data);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 10:57
+ * @功能说明:土地下单
+ */
+ public function landPayOrder(){
+
+ $input = $this->_input;
+
+ $address_model = new OrderAddress();
+
+ $order_model = new LandOrder();
+
+ $land_seed_model= new LandOrderSeed();
+
+ $pay_order = $order_model->payOrderInfo($input);
+
+ if(!empty($pay_order['code'])){
+
+ $this->errorMsg($pay_order['msg']);
+ }
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'pay_type' => 1,
+
+ 'order_code' => orderCode(),
+
+ 'user_id' => $this->getUserId(),
+
+ 'land_id' => $input['land_id'],
+
+ 'pay_price' => $pay_order['pay_price'],
+
+ 'get_integral' => $pay_order['pay_price'],
+
+ 'init_price' => $pay_order['init_price'],
+
+ 'farmer_id' => $pay_order['land']['farmer_id'],
+
+ 'goods_name' => $pay_order['land']['title'],
+
+ 'goods_cover' => $pay_order['land']['cover'],
+
+ 'massif_id' => $input['massif_id'],
+
+ 'spe_id' => $input['spe_id'],
+
+ 'spe_name' => $pay_order['spe']['spe_name'],
+
+ 'area' => $pay_order['spe']['area'],
+
+ 'land_price' => $pay_order['land_price'],
+
+ 'seed_price' => $pay_order['seed_price'],
+
+ 'cycle' => $input['cycle'],
+ //到期时间
+ 'end_time' => $input['cycle']*86400+time(),
+
+ 'rent_mobile' => $input['rent_mobile'],
+
+ 'rent_user_name'=> $input['rent_user_name'],
+
+ 'massif_price' => $pay_order['massif']['price'],
+
+ 'massif_title' => $pay_order['massif']['title'],
+
+ 'total_massif_price' => $pay_order['total_massif_price'],
+ //
+ 'over_time' => time()+$this->_config['over_time']*60,
+
+ 'send_type' => $input['send_type'],
+
+ 'text' => $input['text'],
+
+ 'balance' => $input['pay_model']==2?$pay_order['pay_price']:0,
+
+ 'pay_model' => $input['pay_model'],
+
+ 'coupon_id' => $pay_order['coupon_id'],
+
+ 'discount_price' => $pay_order['coupon_discount'],
+
+ ];
+
+ Db::startTrans();
+
+ $res = $order_model->dataAdd($order_insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+ $order_id = $order_model->getLastInsID();
+ //加销量
+ $this->model->where(['id'=>$input['land_id']])->update(['sale_num'=>Db::Raw('sale_num+1')]);
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $address_model->orderAddressAdd($input['address_id'],$order_id,$input['send_type'],1,$input);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+
+ if(!empty($pay_order['seed'])){
+
+ $res = $land_seed_model->orderSeedAdd($pay_order['seed'],$order_id);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+
+ }
+ }
+ //使用优惠券
+ if(!empty($pay_order['coupon_id'])){
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon_record_model->couponUse($pay_order['coupon_id'],$order_id,2);
+
+ }
+
+ Db::commit();
+ //如果是0元
+ if($order_insert['pay_price']<=0){
+
+ $order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if($input['pay_model']==2){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }elseif ($input['pay_model']==3){
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'],$order_insert['pay_price'],'土地商品');
+
+ $arr['pay_list']= $jsApiParameters;
+
+ $arr['order_code']= $order_insert['order_code'];
+
+ }else{
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"土地订单",['type' => 'Land' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ }
+
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 10:17
+ * @功能说明:土地重新下单
+ */
+ public function landRePayOrder(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $order_insert = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+ }
+ //余额支付
+ if($order_insert['pay_model']==2){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }elseif ($order_insert['pay_model']==3){
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'],$order_insert['pay_price'],'土地商品');
+
+ $arr['pay_list']= $jsApiParameters;
+
+ $arr['order_code']= $order_insert['order_code'];
+
+ }else{
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"土地订单",['type' => 'Land' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 18:03
+ * @功能说明:种子列表
+ */
+ public function seedList(){
+
+ $input = $this->_param;
+
+ $land_text_model = new LandText();
+
+ $obj = $land_text_model->where(['land_id'=>$input['land_id'],'type'=>2])->column('obj_id');
+
+ $dis[] = ['a.status','=',1];
+
+ $dis[] = ['a.id','in',$obj];
+ //查询当前季节
+ if(!empty($input['season'])){
+
+ $month = date('m',time());
+
+ $season = ceil($month/3);
+
+ $dis[] = ['b.season','=',$season];
+ }
+
+ $seed_model = new Seed();
+ //种子
+ $data = $seed_model->indexDataList($dis,$input['sort']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 18:17
+ * @功能说明:种子详情
+ */
+ public function seedInfo(){
+
+ $input = $this->_param;
+
+ $seed_model = new Seed();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+ //种子
+ $data = $seed_model->dataInfo($dis);
+
+ $land_text_model = new LandText();
+
+ $source_model = new Source();
+
+ $source_id = $land_text_model->where(['land_id'=>$input['land_id'],'obj_id'=>$input['id'],'type'=>2])->value('source_id');
+
+ $data['source'] = $source_model->dataInfo(['id'=>$source_id]);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:26
+ * @功能说明:用户下单列表
+ */
+ public function orderList(){
+
+
+ $input = $this->_param;
+
+ $order_model = new LandOrder();
+
+ $farmer_model = new Farmer();
+
+ $eva_model = new Evaluate();
+
+ $order_model->orderInit($this->getUserId());
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ $data = $order_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_info'] = $farmer_model->dataInfo(['id'=>$v['farmer_id']],'title');
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id'=> $v['id'],
+
+ 'type' => 2
+ ];
+
+ $have_eva = $eva_model->where($dis)->where('status','>',-1)->find();
+ //是否已经评价
+ $v['have_eva'] = !empty($have_eva)?1:0;
+
+ $v['end_time'] = date('Y-m-d H:i:s',$v['end_time']);
+
+ }
+ }
+
+ $arr = [2=>'rent_count',3=>'send_count'];
+
+ foreach ($arr as $key => $value){
+
+ $where = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_type'=> $key
+ ];
+
+ $data['count'][$value] = $order_model->where($where)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-28 11:52
+ * @功能说明:用户下单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $farmer_model = new Farmer();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order_model = new LandOrder();
+
+ $seed_model = new LandOrderSeed();
+
+ $data = $order_model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $data['time_text'] = date('Y-m-d H:i',$data['pay_time']).'~'.date('Y-m-d H:i',$data['end_time']);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['pay_time'] = $data['pay_time']>0?date('Y-m-d H:i:s',$data['pay_time']):0;
+
+ $data['end_time'] = $data['end_time']>0?date('Y-m-d H:i:s',$data['end_time']):0;
+
+ $data['cancel_time'] = $data['cancel_time']>0?date('Y-m-d H:i:s',$data['cancel_time']):0;
+ //农场信息
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']]);
+ //是否可以配送
+ $data['can_send'] = $data['pay_type']>1&&$data['end_time'] $this->getUserId(),
+
+ 'order_id'=> $input['id'],
+
+ 'type' => 2
+ ];
+
+ $have_eva = $eva_model->where($dis)->where('status','>',-1)->find();
+ //是否已经评价
+ $data['have_eva'] = !empty($have_eva)?1:0;
+ //种子列表
+ $data['seed'] = $seed_model->orderSeed($data['id']);
+
+ $address_order_model = new OrderAddress();
+
+ $address_model = new Address();
+
+ $data['address_info'] = $address_order_model->dataInfo(['order_id'=>$input['id'],'type'=>1]);
+
+ if(!empty($data['address_info'])){
+
+ $data['address_info'] = $address_model->dataInfo(['id'=>$data['address_info']['address_id']]);
+
+ }
+
+ $mac_model = new Machine();
+ //仪器详情
+ $data['machine_info'] = $mac_model->getDataInfo($data['land_id']);
+
+ $send_tmpl_id = $this->model->where(['id'=>$data['land_id']])->value('send_tmpl_id');
+
+ $freightTemplate_model = new FreightTemplate();
+
+ $data['send_tmpl'] = $freightTemplate_model->dataInfo(['id'=>$send_tmpl_id]);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 13:42
+ * @功能说明:
+ */
+ public function cancelOrder(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $order = $order_model->dataInfo($dis);
+
+ if($order['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $order_model->cancelOrder($order);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 13:53
+ * @功能说明:申请认养订单发货
+ */
+ public function sendOrderApply(){
+
+ $input = $this->_input;
+
+ $order_model = new LandOrder();
+
+ $farmer_model= new Farmer();
+
+ $send_order_model = new SendOrder();
+
+ $address_model = new Address();
+
+ $config_model = new Config();
+
+ $order = $order_model->dataInfo(['id'=>$input['order_id']]);
+
+ if($order['pay_type']<2){
+
+ $this->errorMsg('订单未支付');
+
+ }
+
+ $times = $send_order_model->where(['order_id'=>$input['order_id'],'type'=>2])->where('pay_time','>',0)->count();
+
+ $farmer= $farmer_model->dataInfo(['id'=>$order['farmer_id'],'status'=>2]);
+
+ if(empty($farmer)){
+
+ $this->errorMsg('农场主未找到');
+ }
+
+ $send_price = $distance = $send_tmpl_type = 0;
+ //快递
+ if($input['send_type']==2){
+
+ $address = $address_model->dataInfo(['id'=>$input['address_id']]);
+
+ if(empty($address)){
+
+ $this->errorMsg('地址信息未找到');
+
+ }
+
+ $land = $this->model->dataInfo(['id'=>$order['land_id']]);
+
+ if(empty($land)){
+
+ $this->errorMsg('土地信息被删除');
+
+ }
+
+ $goods_info = [
+
+ 'send_tmpl_id' => $land['send_tmpl_id'],
+
+ 'goods_num' => $input['send_num'],
+
+ 'total_weight' => $input['send_num'],
+ ];
+
+ $send_data = $config_model->getGoodsSendPrice($input['address_id'],$goods_info,2,2);
+
+ if(!empty($send_data['code'])){
+
+ $this->errorMsg($send_data['msg']);
+ }
+
+ $send_price = $send_data['price'];
+
+ $send_tmpl_type = $send_data['type'];
+
+ }else{
+
+ $address['user_name'] = $input['user_name'];
+
+ $address['mobile'] = $input['mobile'];
+
+ }
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'order_id' => $input['order_id'],
+
+ 'user_id' => $order['user_id'],
+
+ 'farmer_id' => $order['farmer_id'],
+
+ 'pay_price' => $send_price,
+
+ 'get_integral'=> $send_price,
+
+ 'order_code' => orderCode(),
+
+ 'text' => $input['text'],
+ //
+ 'over_time' => time()+$this->_config['over_time']*60,
+
+ 'type' => 2,
+
+ 'start_time' => $input['start_time'],
+
+ 'end_time' => $input['end_time'],
+
+ 'distance' => $distance,
+
+ 'times' => $times+1,
+
+ 'send_type' => $input['send_type'],
+
+ 'address' => $input['send_type']==2?$address['address'].$address['address_info']:'',
+
+ 'user_name' => $address['user_name'],
+
+ 'mobile' => $address['mobile'],
+
+ 'lng' => $input['send_type']==2?$address['lng']:'',
+
+ 'lat' => $input['send_type']==2?$address['lat']:'',
+
+ 'balance' => $input['pay_model']==2?$send_price:0,
+
+ 'pay_model' => $input['pay_model'],
+
+ 'goods_num' => isset($send_tmpl_type)&&$send_tmpl_type==1?$input['send_num']:0,
+
+ 'weight' => isset($send_tmpl_type)&&$send_tmpl_type==2?$input['send_num']:0,
+
+ ];
+
+ $res = $send_order_model->dataAdd($order_insert);
+
+ if($res==0){
+
+ $this->errorMsg('申请配送失败');
+ }
+ //如果是0元
+ if($order_insert['pay_price']<=0){
+
+ $send_order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if($input['pay_model']==2){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $send_order_model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }elseif ($input['pay_model']==3){
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'],$order_insert['pay_price'],'配送订单');
+
+ $arr['pay_list']= $jsApiParameters;
+
+ $arr['order_code']= $order_insert['order_code'];
+
+ }else{
+ //微信支付
+ $pay_controller = new \app\shop\controller\IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"认养配送订单",['type' => 'ClaimSend' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 15:23
+ * @功能说明:配送订单下单详情
+ */
+ public function sendOrderPayInfo(){
+
+ $input = $this->_param;
+
+ $order_model = new LandOrder();
+
+ $farmer_model= new Farmer();
+
+ $config_model= new Config();
+
+ $address_model = new Address();
+
+ $order = $order_model->dataInfo(['id'=>$input['order_id']]);
+
+ $farmer= $farmer_model->dataInfo(['id'=>$order['farmer_id']]);
+
+ if(empty($farmer)){
+
+ $this->errorMsg('农场主未找到');
+ }
+
+// $address = $address_model->dataInfo(['id'=>$input['address_id']]);
+//
+// if(empty($address)){
+//
+// $this->errorMsg('地址信息未找到');
+//
+// }
+
+ $land = $this->model->dataInfo(['id'=>$order['land_id']]);
+
+ if(empty($land)){
+
+ $this->errorMsg('土地信息被删除');
+
+ }
+
+ $freightTemplate_model = new FreightTemplate();
+
+ $data['send_tmpl'] = $freightTemplate_model->dataInfo(['id'=>$land['send_tmpl_id']]);
+ //计算运费
+ if(!empty($input['send_num'])){
+
+ $goods_info = [
+
+ 'send_tmpl_id' => $land['send_tmpl_id'],
+
+ 'goods_num' => $input['send_num'],
+
+ 'total_weight' => $input['send_num'],
+ ];
+
+ $data['send_price'] = $config_model->getGoodsSendPrice($input['address_id'],$goods_info,2);
+
+ if(!empty($data['send_price']['code'])){
+
+ $this->errorMsg($data['send_price']['msg']);
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:14
+ * @功能说明:配送订单列表
+ */
+ public function userSendOrderList(){
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $data = $send_order_model->orderSendOrder($input['land_order_id'],2);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 14:00
+ * @功能说明:配送订单详情
+ */
+ public function sendOrderInfo()
+ {
+
+ $input = $this->_param;
+
+ $send_order_model = new SendOrder();
+
+ $land_order_model = new LandOrder();
+
+ $seed_model = new LandOrderSeed;
+
+ $send_order = $send_order_model->dataInfo(['id' => $input['id']]);
+
+ $send_order['create_time'] = date('Y-m-d H:i:s', $send_order['create_time']);
+
+ $send_order['time_text'] = date('Y-m-d H:i', $send_order['start_time']) . '~' . date('H:i', $send_order['end_time']);
+
+ $send_order['pay_time'] = $send_order['pay_time'] > 0 ? date('Y-m-d H:i:s', $send_order['pay_time']) : 0;
+
+ $send_order['send_time'] = $send_order['send_time'] > 0 ? date('Y-m-d H:i:s', $send_order['send_time']) : 0;
+
+ $send_order['receiving_time'] = $send_order['receiving_time'] > 0 ? date('Y-m-d H:i:s', $send_order['receiving_time']) : 0;
+
+ $send_order['refund_time'] = $send_order['refund_time'] > 0 ? date('Y-m-d H:i:s', $send_order['refund_time']) : 0;
+
+ $send_order['land_order'] = $land_order_model->dataInfo(['id' => $send_order['order_id']]);
+
+ $send_order['land_order']['end_time'] = date('Y-m-d H:i:s',$send_order['land_order']['end_time']);
+ //种子列表
+ $send_order['land_order']['seed'] = $seed_model->orderSeed($send_order['order_id']);
+
+ return $this->success($send_order);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 17:57
+ * @功能说明:配送订单退款
+ */
+ public function sendOrderRefund(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ Db::startTrans();
+
+ $res = $send_order_model->refundCash($send_order,$this->payConfig($this->_uniacid));
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ $send_order_model->dataUpdate(['id'=>$send_order['id']],['refund_time'=>time(),'pay_type'=>-1,'refund'=>1]);
+ //增加财务流水
+ $fin_water_model = new FinanceWater();
+
+ $res = $fin_water_model->addWater($input['id'],13,1,1);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败1');
+ }
+
+ $res = $fin_water_model->dataUpdate(['order_id'=>$send_order['id'],'type'=>14],['cash_status'=>1]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败3');
+ }
+
+ Db::commit();
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 10:24
+ * @功能说明:配送订单收货
+ */
+ public function sendOrderReceiving(){
+
+ $input = $this->_input;
+
+ $send_order_model = new SendOrder();
+
+ $send_order = $send_order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($send_order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($send_order['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $res = $send_order_model->sendOrderReceiving($send_order);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-10 00:40
+ * @功能说明:可用的优惠券列表
+ */
+ public function couponList(){
+
+ $input = $this->_input;
+
+ $coupon_model = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $order_model = new LandOrder();
+
+ $order_info = $order_model->payOrderInfo($input);
+
+ $coupon_id = $coupon_model->canUseCoupon($this->getUserId(),$order_info['pay_price'],2);
+
+ $data = $coupon_record_model->where('id','in',$coupon_id)->order('id desc')->paginate(10)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexOrder.php b/app/farm/controller/IndexOrder.php
new file mode 100755
index 0000000..4c0a8ed
--- /dev/null
+++ b/app/farm/controller/IndexOrder.php
@@ -0,0 +1,959 @@
+model = new ShopOrder();
+
+ $this->app = $app;
+
+ $this->refund_model = new ShopRefund();
+
+ $this->order_goods_model = new ShopOrderGoods();
+
+ autoCancelOrder($this->_uniacid);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function orderList(){
+ //超时自动取消订单
+ $this->model->autoCancelOrder($this->_uniacid,$this->getUserId());
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ $data = $this->model->indexDataList($dis,$where);
+
+ $eva_model = new Evaluate();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $can_refund_num = is_array($v['order_goods'])?array_sum(array_column($v['order_goods'],'can_refund_num')):0;
+
+ if(!empty($v['add_price'])&&$v['add_price_refund']==0){
+
+ $can_refund_num+=1;
+ }
+ //是否可以申请退款
+ if(($v['pay_type']==7&&$v['can_refund_time']>time()&&$can_refund_num>0)||($v['pay_type']==2&&$can_refund_num>0)){
+
+ $v['can_refund'] = 1;
+
+ }else{
+
+ $v['can_refund'] = 0;
+ }
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id'=> $v['id'],
+
+ 'type' => 3
+ ];
+
+ $have_eva = $eva_model->where($dis)->where('status','>',-1)->find();
+ //是否已经评价
+ $v['have_eva'] = !empty($have_eva)?1:0;
+
+ }
+
+ }
+
+ $arr = [
+ //未支付
+ 'no_pay_count' => 1,
+ //未发货
+ 'no_send_count' => 2,
+ //已经发货
+ 'have_send_count'=> 3
+ ];
+
+ foreach ($arr as $ks=>$vs){
+
+ $map = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_type'=> $vs
+ ];
+
+ $data[$ks] = $this->model->where($map)->count();
+ }
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $time_arr = ['create_time','pay_time','end_time','hx_time','cancel_time'];
+
+ foreach ($time_arr as $v){
+
+ $data[$v] = !empty($data[$v])?date('Y-m-d H:i:s',$data[$v]):$data[$v];
+
+ }
+
+ $data['distance'] = distance_text($data['distance']);
+
+ $end_time = date('H:i',$data['send_end_time'])=='00:00'?'24:00':date('H:i',$data['send_end_time']);
+ //配送时间
+ $data['user_send_time'] = date('Y-m-d H:i',$data['send_start_time']).'~'.$end_time;
+ //剩余可申请退款数量
+ $can_refund_num = array_sum(array_column($data['order_goods'],'can_refund_num'));
+ //是否可以申请退款
+ if(($data['pay_type']==7&&$data['can_refund_time']>time()&&$can_refund_num>0)||($data['pay_type']==2&&$can_refund_num>0)){
+
+ $data['can_refund'] = 1;
+
+ }else{
+
+ $data['can_refund'] = 0;
+ }
+
+ $farmer_model = new Farmer();
+
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']],'title');
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id'=> $data['id'],
+
+ 'type' => 3
+ ];
+
+ $eva_model = new Evaluate();
+
+ $have_eva = $eva_model->where($dis)->where('status','>',-1)->find();
+ //是否已经评价
+ $data['have_eva'] = !empty($have_eva)?1:0;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:29
+ * @功能说明:退款订单详情
+ *
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $data = $this->refund_model->indexDataList($dis,$where);
+
+ $map = [
+
+ 'status' => 1,
+
+ 'user_id'=> $this->getUserId()
+ ];
+ //退款中数量
+ $data['ing_count'] = $this->refund_model->where($map)->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->refund_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-01 16:08
+ * @功能说明:配送方式
+ */
+ public function goodsSendType(){
+
+ $input = $this->_param;
+
+ $car_model = new Car();
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $list = $car_model->carList($this->getUserId(),1,0,$is_show);
+
+ $data['is_self'] = 0;
+
+ $data['is_send'] = 0;
+
+ if(!empty($list)){
+
+ foreach ($list as &$value){
+
+ $data['is_self'] = !empty($value['is_self'])?$value['is_self']:$data['is_self'];
+
+ $data['is_send'] = !empty($value['is_send'])?$value['is_send']:$data['is_send'];
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 09:43
+ * @功能说明:下单页面详情
+ */
+ public function payOrderInfo(){
+
+ $input = $this->_param;
+
+ $coupon_id = isset($input['coupon_id'])?$input['coupon_id']:0;
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $send_type = isset($input['send_type'])?$input['send_type']:2;
+
+ $no_i = isset($input['no_i'])?$input['no_i']:1;
+
+ $address_model = new Address();
+
+ $defult_address = $address_model->dataInfo(['user_id'=>$this->getUserId(),'status'=>1]);
+
+ $defult_address_id = !empty($defult_address)?$defult_address['id']:0;
+
+ $address_id = !empty($input['address_id'])?$input['address_id']:$defult_address_id;
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),0,$coupon_id,$address_id,$is_show,$send_type,$no_i);
+
+ if(!empty($input['address_id'])){
+ //默认地址
+ $order_info['address'] = $address_model->dataInfo(['id'=>$input['address_id']]);
+
+ }else{
+
+ $order_info['address'] = $defult_address;
+
+ }
+
+ $coupon_modle = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+ //可用优惠券数量
+ $canUseCoupon = $coupon_modle->canUseCoupon($this->getUserId(),$order_info['goods_price']);
+
+ $order_info['canUseCoupon'] = $coupon_record_model->where('id','in',$canUseCoupon)->sum('num');
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $data['tmp_list'] = $tmpl_model->where(['uniacid'=>$this->_uniacid])->where('tmpl_name','in',['shop_order','send_over'])->select()->toArray();
+
+ return $this->success($order_info);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 09:53
+ * @功能说明:下单
+ */
+ public function payOrder(){
+
+ $input = $this->_input;
+
+ $send_type = isset($input['send_type'])?$input['send_type']:2;
+
+ $coupon_id = !empty($input['coupon_id'])?$input['coupon_id']:0;
+
+ $address_id = isset($input['address_id'])?$input['address_id']:0;
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $no_i = isset($input['no_i'])?$input['no_i']:1;
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),0,$coupon_id,$address_id,$is_show,$send_type,$no_i);
+
+ $config_model = new Config();
+
+ $address_order_model = new OrderAddress();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $top_order_code = orderCode();
+
+ $kill_model = new SeckillList();
+ //校验秒杀活动
+ $res = $kill_model->userCheck($this->getUserId(),$order_info['kill_atv_id'],$is_show);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ Db::startTrans();
+ //按农场主生成多个订单
+ foreach ($order_info['order_goods'] as $value){
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'order_code' => orderCode(),
+
+ 'top_order_code' => $top_order_code,
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_price' => $value['pay_price'],
+
+ 'get_integral'=> $value['pay_price'],
+
+ 'true_price' => $value['pay_price'],
+
+ 'pay_type' => 1,
+
+ 'goods_price'=> $value['goods_price'],
+
+ 'farmer_id' => $value['farmer_id'],
+
+ 'store_id' => $value['farmer_id'],
+
+ 'init_price' => $value['init_price'],
+
+ 'init_goods_price' => $value['init_goods_price'],
+
+ 'text' => $input['text'],
+
+ 'over_time' => !empty($order_info['kill_atv_id'])?time()+$order_info['kill_over_time']*60:time()+$config['over_time']*60,
+
+ 'send_type' => $send_type,
+
+ 'discount' => $value['coupon_discount'],
+
+ 'freight' => $value['freight'],
+
+ 'distance' => $value['distance'],
+
+ 'balance' => $input['pay_model']==2?$value['pay_price']:0,
+
+ 'total_price' => $order_info['pay_price'],
+
+ 'send_start_time' => $input['start_time'],
+
+ 'send_end_time' => $input['end_time'],
+
+ 'pay_model' => $input['pay_model'],
+
+ 'kill_atv_id' => $order_info['kill_atv_id'],
+
+ 'kill_discount_price' => $value['kill_discount_price'],
+
+ 'integral' => $no_i==0?$value['integral']:0,
+
+ 'integral_discount_price' => $no_i==0?$value['integral_discount_price']:0,
+
+ ];
+ //下单
+ $res = $this->model->dataAdd($order_insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+ }
+
+ $order_id = $this->model->getLastInsID();
+ //添加下单地址
+ $res = $address_order_model->orderAddressAdd($input['address_id'],$order_id,$send_type,5,$input);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+
+ }
+
+ $order_insert['id'] = $order_id;
+
+ if(empty($order_info['order_goods'])){
+
+ $this->errorMsg('订单错误');
+ }
+ //添加到子订单
+ $res = $this->order_goods_model->orderGoodsAdd($value['goods_list'],$order_id,$this->getUserId(),$value['farmer_id'],$input['address_id']);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+ }
+ //使用优惠券
+ if(!empty($order_info['coupon_id'])){
+
+ $this->model->dataUpdate(['id'=>$order_id],['coupon_id'=>$coupon_id]);
+
+ }
+ //积分活动
+ $res = $this->model->marketingCheck($order_insert,$value['goods_list']);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+
+ }
+
+ }
+ //使用优惠券
+ if(!empty($order_info['coupon_id'])){
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon_record_model->couponUse($order_info['coupon_id']);
+
+ }
+
+ Db::commit();
+ //如果是0元
+ if($order_info['pay_price']<=0){
+
+ $this->model->orderResult($top_order_code,$top_order_code);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if($input['pay_model']==2){
+
+ $user_model = new \app\farm\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_info['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->model->orderResult($top_order_code,$top_order_code);
+
+ return $this->success(true);
+
+ }elseif ($input['pay_model']==3){
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($top_order_code,$order_info['pay_price'],'商场商品');
+
+ $arr['pay_list']= $jsApiParameters;
+
+ $arr['order_code']= $order_insert['order_code'];
+
+
+ }else{
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"商城",['type' => 'SchoolShop' , 'out_trade_no' => $top_order_code],$order_info['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 15:59
+ * @功能说明:重新支付
+ */
+ public function rePayOrder(){
+
+ $input = $this->_input;
+
+ $order_insert = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+ //余额支付
+ if($order_insert['pay_model']==2){
+
+ $user_model = new \app\massage\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }elseif ($order_insert['pay_model']==3){
+
+ $pay_model = new PayModel($this->payConfig());
+
+ $jsApiParameters = $pay_model->aliPay($order_insert['order_code'],$order_insert['pay_price'],'商场商品');
+
+ $arr['pay_list']= $jsApiParameters;
+
+ $arr['order_code']= $order_insert['order_code'];
+
+ }else{
+
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"商城",['type' => 'SchoolShop' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 16:38
+ * @功能说明:取消订单
+ */
+
+ public function cancelOrder(){
+
+ $input = $this->_input;
+
+ $order_insert = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ $res = $this->model->cancelOrder($order_insert);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 11:39
+ * @功能说明:申请退款
+ */
+ public function applyOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->model->dataInfo(['id'=>$input['order_id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($order['pay_type']<2&&$order['have_tx']!=0){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ if(empty($input['list'])){
+
+ $this->errorMsg('请选择商品');
+
+ }
+
+ if($order['can_refund_time']errorMsg('核销后24小时内才能申请退款哦');
+
+ }
+ //申请退款
+ $res = $this->refund_model->applyRefund($order,$input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:55
+ * @功能说明:取消退款
+ */
+ public function cancelRefundOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->refund_model->dataInfo(['id'=>$input['id']]);
+
+ if($order['status']!=1){
+
+ $this->errorMsg('订单已经审核');
+
+ }
+
+ Db::startTrans();
+
+ $res = $this->refund_model->dataUpdate(['id'=>$input['id']],['status'=>-1,'cancel_time'=>time()]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('取消失败');
+ }
+
+ if(!empty($order['order_goods'])){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ foreach ($order['order_goods'] as $v){
+
+ if(!empty($v['order_goods_id'])){
+
+ $num = $v['goods_num'];
+
+ $res = $order_goods_model->where(['id'=>$v['order_goods_id']])->update(['can_refund_num'=>Db::Raw("can_refund_num+$num")]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('取消失败');
+ }
+
+ }else{
+
+ $this->model->dataUpdate(['id'=>$order['order_id']],['add_price_refund'=>0]);
+
+ }
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-07 15:30
+ * @功能说明:刷新订单二维码
+ */
+ public function refreshQr(){
+
+ $input = $this->_input;
+
+ $qr_insert = [
+
+ 'id' => $input['id']
+ ];
+ //获取二维码
+ $qr = $this->model->orderQr($qr_insert,$this->_uniacid);
+
+ if(!empty($qr)){
+
+ $this->model->dataUpdate(['id'=>$input['id']],['qr'=>$qr]);
+
+ }
+
+ return $this->success($qr);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:14
+ * @功能说明:楼长核销订单
+ */
+ public function endOrder(){
+
+ $input = $this->_input;
+
+ $order_model= new ShopOrder();
+
+ $order = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+ //自提
+ if($order['send_type']==1&&$order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+ //快递
+ if($order['send_type']==2&&$order['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $refund_model = new ShopRefund();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $order_model->hxOrder($input['id'],$this->getUserId());
+
+ return $this->success($res);
+
+
+ }
+
+ public function getPayNumber(){
+
+ $input = $this->_input;
+
+ $number= $this->order_goods_model->getGoodsNumber(['a.goods_id'=>$input['id'],'b.user_id'=>$this->getUserId()] );
+
+ return $this->success(['number'=>$number]);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-10 00:40
+ * @功能说明:可用的优惠券列表
+ */
+ public function couponList(){
+
+ $input = $this->_param;
+
+ $coupon_model = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $send_type = isset($input['send_type'])?$input['send_type']:2;
+
+ $no_i = isset($input['no_i'])?$input['no_i']:1;
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),0,0,0,$is_show,$send_type,$no_i);
+
+ $coupon_id = $coupon_model->canUseCoupon($this->getUserId(),$order_info['goods_price'],1);
+
+ $data = $coupon_record_model->where('id','in',$coupon_id)->order('id desc')->paginate(10)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-16 14:42
+ * @功能说明:订阅消息通知
+ */
+ public function tmplList(){
+
+ $tmpl_model = new TmplConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $tmpl_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexReseller.php b/app/farm/controller/IndexReseller.php
new file mode 100755
index 0000000..7076a8d
--- /dev/null
+++ b/app/farm/controller/IndexReseller.php
@@ -0,0 +1,259 @@
+model = new DistributionList();
+
+ $this->user_model = new User();
+
+ $this->cash_model = new DistributionCash();
+
+ $dis = [
+
+ 'status' => 2,
+
+ 'user_id'=> $this->getUserId()
+ ];
+
+ $reseller = $this->model->dataInfo($dis);
+
+ if(empty($reseller)){
+
+ $this->errorMsg('你还不是分销商');
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 13:53
+ * @功能说明:分销中心
+ */
+ public function resellerInfo(){
+
+ $user = $this->user_model->dataInfo(['id'=>$this->getUserId()],'id,nickName,avatarUrl,fx_code,fx_cash');
+
+ if(empty($user['fx_code'])){
+
+ $user['fx_code'] = getCardCode();
+
+ $this->user_model->dataUpdate(['id'=>$user['id']],['fx_code'=>$user['fx_code']]);
+
+ }
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'status' => 1
+ ];
+
+ $user['notreceived_cash'] = $this->cash_model->where($dis)->sum('cash');
+
+ $wallet_model = new Wallet();
+
+ $user['wallet_price'] = $wallet_model->where(['user_id'=>$this->getUserId(),'type'=>5])->where('status','in',[1,2])->sum('pay_price');
+
+ return $this->success($user);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-27 18:00
+ * @功能说明:订单列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['status','>',-1];
+ }
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+ }
+
+ $data = $this->cash_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['source_info'] = $this->user_model->where(['id'=>$v['source_id']])->field('nickName,avatarUrl')->find();
+
+ $v['order_price'] = array_sum(array_column($v['order_goods'],'pay_price'));
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-28 14:23
+ * @功能说明:我的团队
+ */
+ public function myTeam(){
+
+ $input = $this->_param;
+
+ $data = $this->model->myTeam($this->getUserId(),$input['type']);
+
+ $data['one_count'] = $this->model->teamCount($this->getUserId());
+
+ $data['two_count'] = $this->model->teamCount($this->getUserId(),2);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:15
+ * @功能说明:申请提现
+ */
+ public function applyWallet(){
+
+ $input = $this->_input;
+
+ $wallet_model = new Wallet();
+
+ $user = $this->user_model->dataInfo(['id'=>$this->getUserId()]);
+
+ if($input['apply_price']>$user['fx_cash']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ Db::startTrans();
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_code' => orderCode(),
+
+ 'farmer_id' => 0,
+
+ 'pay_price' => $input['apply_price'],
+
+ 'text' => $input['text'],
+
+ 'true_price' => round($input['apply_price'],2),
+
+ 'balance' => 100,
+
+ 'type' => 5
+ ];
+ //发起提现
+ $res = $wallet_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ $res = $this->user_model->dataUpdate(['id'=>$this->getUserId(),'fx_cash'=>$user['fx_cash']],['fx_cash'=>$user['fx_cash']-$input['apply_price']]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-28 15:02
+ * @功能说明:提现记录
+ */
+ public function walletList(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'type' => 5
+ ];
+
+ if(!empty($input['status'])){
+
+ $dis['status'] = $input['status'];
+ }
+
+ $wallet_model = new Wallet();
+
+ $data = $wallet_model->dataList($dis);
+
+ return $this->success($data);
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexStore.php b/app/farm/controller/IndexStore.php
new file mode 100755
index 0000000..0b90ef7
--- /dev/null
+++ b/app/farm/controller/IndexStore.php
@@ -0,0 +1,963 @@
+model = new Farmer();
+
+ $this->user_model = new User();
+
+ $dis = [
+
+ 'type' => 2,
+
+ 'status' => 2,
+
+ 'user_id'=> $this->getUserId()
+ ];
+
+ $this->store = $this->model->dataInfo($dis);
+
+ if(empty($this->store)){
+
+ $this->errorMsg('你还不是地主');
+ }
+
+ $this->address_model = new Address();
+
+ $this->land_model = new LandList();
+
+ $this->massif_model = new Massif();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 13:53
+ * @功能说明:店铺详情
+ */
+ public function storeInfo(){
+
+ return $this->success($this->store);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 13:54
+ * @功能说明:修改店铺
+ */
+ public function storeUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $this->store['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:34
+ * @功能说明:商品分类列表
+ */
+ public function goodsCateList(){
+
+ $cate_model = new ShopGoodsCate();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['store_id','=',$this->store['id']];
+
+ $data = $cate_model->dataList($dis,20);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:03
+ * @功能说明:添加商品分类
+ */
+ public function goodsCateAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['store_id'] = $this->store['id'];
+
+ $cate_model = new ShopGoodsCate();
+
+ $res = $cate_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:06
+ * @功能说明:编辑商品分类
+ */
+ public function goodsCateUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $cate_model = new ShopGoodsCate();
+
+ $cate_info = $cate_model->dataInfo($dis);
+
+ if(empty($cate_info)){
+
+ $this->errorMsg('商品分类不存在');
+ }
+ //如果是删除
+ if(!empty($input['status'])&&$input['status']==-1&&$cate_info['goods_num']>0){
+
+ $this->errorMsg('该分类下存在商品,无法删除');
+
+ }
+
+ $res = $cate_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:08
+ * @功能说明:商品分类下拉框
+ */
+ public function goodsCateSelect(){
+
+ $cate_model = new ShopGoodsCate();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['store_id','=',$this->store['id']];
+
+ $data = $cate_model->where($dis)->where('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 15:06
+ * @功能说明:商品各个状态下的数量
+ */
+ public function goodsCount(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'store_id' => $this->store['id'],
+
+ 'status' => 1
+
+ ];
+
+ $goods_model = new ShopGoods();
+ //上架数量
+ $data['on_count'] = $goods_model->where($dis)->count();
+
+ $dis['status'] = 2;
+ //下架数量
+ $data['off_count'] = $goods_model->where($dis)->count();
+
+ $dis['status'] = 3;
+ //仓库数量
+ $data['house_count'] = $goods_model->where($dis)->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:08
+ * @功能说明:商品列表
+ */
+ public function goodsList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['store_id','=',$this->store['id']];
+
+ $dis[] = ['status','=',$input['status']];
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['goods_name','like','%'.$input['goods_name'].'%'];
+ }
+
+ $goods_model = new ShopGoods();
+
+ $data = $goods_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //创建时间
+ $v['create_time'] = date('Y/m/d',$v['create_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 10:44
+ * @功能说明:商品详情
+ */
+ public function goodsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $goods_model = new ShopGoods();
+
+ $data = $goods_model->dataInfo($dis);
+
+ $farmer_model = new Farmer();
+
+ $source_model = new Source();
+
+ $cate_model = new ShopGoodsCate();
+
+ $data['farmer_title'] = $farmer_model->where(['id'=>$data['farmer_id']])->value('title');
+
+ $data['source_title'] = $source_model->where(['id'=>$data['source_id']])->value('title');
+
+ $data['cate_title'] = $cate_model->where(['id'=>$data['cate_id']])->value('title');
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:32
+ * @功能说明:添加商品
+ */
+ public function goodsAdd(){
+
+ $input = $this->_input;
+ //0放入仓库 1提交审核
+ // $type = !empty($input['type'])?$input['type']:0;
+
+ unset($input['type']);
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['store_id']= $this->store['id'];
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+
+ $core = new WxSetting($this->_uniacid);
+
+ if(!empty($input['goods_name'])){
+
+ $rest = $core->wxContentRlue($input['goods_name']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('标题含有违法违规内容');
+ }
+
+ }
+
+
+ if(!empty($input['text'])){
+
+ $input['text'] = serialize($input['text']);
+ }
+
+// if(!empty($input['text'])){
+//
+// $rest = $core->wxContentRlue($input['text']);
+//
+// if($rest['errcode'] != 0){
+//
+// return $this->error('标题含有违法违规内容');
+// }
+//
+// }
+
+ $goods_model = new ShopGoods();
+
+ $id = $goods_model->dataAdd($input);
+
+ return $this->success(1);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-25 17:49
+ * @功能说明:编辑商品
+ */
+ public function goodsUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $core = new WxSetting($this->_uniacid);
+
+ if(!empty($input['goods_name'])){
+
+ $rest = $core->wxContentRlue($input['goods_name']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('标题含有违法违规内容');
+ }
+
+ }
+
+// if(!empty($input['text'])){
+//
+// $rest = $core->wxContentRlue($input['text']);
+//
+// if($rest['errcode'] != 0){
+//
+// return $this->error('标题含有违法违规内容');
+// }
+//
+// }
+
+ if(!empty($input['text'])){
+
+ $input['text'] = serialize($input['text']);
+ }
+
+ if(isset($input['imgs'])){
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+ }
+
+ $goods_model = new ShopGoods();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $goods_model->goodsUpdate($dis,$input);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 11:44
+ * @功能说明:商品上下家删除
+ */
+ public function goodsStatusUpdate(){
+
+ $input = $this->_input;
+
+ $goods_model = new ShopGoods();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $goods_model->dataUpdate($dis,['status'=>$input['status']]);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @param $input
+ * @功能说明:提交审核方法
+ * @author chenniang
+ * @DataTime: 2021-03-23 14:27
+ */
+ public function subGoodsShAction($goods_id){
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'cap_id' => $this->cap_info['id'],
+
+ 'order_code' => orderCode(),
+
+ 'status' => 1,
+
+ ];
+
+ $goods_sh_model = new ShopGoodsSh();
+
+ $goods_sh_model->dataAdd($insert);
+
+ $id = $goods_sh_model->getLastInsID();
+ //提交审核
+ $res = $goods_sh_model->subSh($id,$goods_id);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:31
+ * @功能说明:商品批量上下架
+ */
+ public function someGoodsUpdate(){
+
+ $input = $this->_input;
+
+ $goods_model = new ShopGoods();
+ //全选
+ if(!empty($input['all'])){
+
+ $res = $goods_model->where(['store_id'=>$this->store['id'],'status'=>$input['now_status']])->where('status','>',-1)->update(['status'=>$input['status']]);
+
+ }else{
+
+ $res = $goods_model->where('id','in',$input['goods_id'])->update(['status'=>$input['status']]);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-28 14:08
+ * @功能说明:添加商品时农场主下拉框
+ */
+ public function goodsFarmerSelect(){
+
+ $input = $this->_param;
+
+ $order_farmer = $this->model->goodsFarmerSelect($this->getUserId());
+
+ $map[] = ['id','in',$order_farmer];
+
+ $map[] = ['status','in',[2,3]];
+
+ $map[] = ['type','=',1];
+
+ $list = $this->model->where($map)->field('id,title')->select()->toArray();
+
+ return $this->success($list);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-28 14:22
+ * @功能说明:添加商品时溯源下拉框
+ */
+ public function goodsSourceSelect(){
+
+ $input = $this->_param;
+
+ $land_order_model = new LandOrder();
+
+ $source_model = new Source();
+
+ $id = $land_order_model->goodsSourceSelect($this->getUserId());
+
+ $map[] = ['id','in',$id];
+
+ $map[] = ['status','=',1];
+
+ $list = $source_model->where($map)->field('id,title')->order('id desc')->select()->toArray();
+
+ return $this->success($list);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 11:03
+ * @功能说明:订单列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.store_id','=',$this->store['id']];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }else{
+
+ $dis[] = ['a.pay_type','>=',1];
+
+ }
+
+ $order_model = new ShopOrder();
+
+ $data = $order_model->indexDataList($dis,$where);
+
+ $arr = [
+ 'no_pay_count' => 1,
+ //未发货
+ 'no_send_count' => 2,
+ //已经发货
+ 'have_send_count'=> 3
+ ];
+
+ foreach ($arr as $ks=>$vs){
+
+ $map = [
+
+ 'store_id'=> $this->store['id'],
+
+ 'pay_type'=> $vs
+ ];
+
+ $data[$ks] = $order_model->where($map)->count();
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 10:31
+ * @功能说明:分配订单给农场主
+ */
+ public function distributionOrderFarmer(){
+
+ $input = $this->_input;
+
+ $order_model = new ShopOrder();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $refund_model = new ShopRefund();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$input['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $order_model->dataUpdate($dis,['farmer_show'=>1]);
+
+ return $this->success($res);
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $order_model = new ShopOrder();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $order_model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $time_arr = ['create_time','pay_time','end_time','hx_time','over_time','cancel_time'];
+
+ foreach ($time_arr as $v){
+
+ $data[$v] = !empty($data[$v])?date('Y-m-d H:i:s',$data[$v]):$data[$v];
+
+ }
+
+ $data['distance'] = distance_text($data['distance']);
+ //配送时间
+ $data['user_send_time'] = date('Y-m-d H:i',$data['send_start_time']).'~'.date('H:i',$data['send_end_time']);
+
+ $farmer_model = new Farmer();
+
+ $data['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']],'title');
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:29
+ * @功能说明:退款订单详情
+ *
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $refund_model = new ShopRefund();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.store_id','=',$this->store['id']];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $data = $refund_model->indexDataList($dis,$where);
+
+ $map = [
+
+ 'status' => 1,
+
+ 'store_id'=> $this->store['id']
+ ];
+ //退款中数量
+ $data['ing_count'] = $refund_model->where($map)->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:21
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund(){
+
+ $input = $this->_input;
+
+ $refund_order_model = new ShopRefund();
+
+ $res = $refund_order_model->noPassRefund($input['id'],$this->getUserId());
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**\
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:28
+ * @功能说明:同意退款
+ */
+ public function passRefund(){
+
+ $input = $this->_input;
+
+ $refund_order_model = new ShopRefund();
+
+ $res = $refund_order_model->passOrder($input['id'],$input['price'],$this->payConfig(),$this->getUserId(),$input['text']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $refund_order_model = new ShopRefund();
+
+ $data = $refund_order_model->dataInfo($dis);
+
+ $order_model = new ShopOrder();
+
+ $data['pay_order_code'] = $order_model->where(['id'=>$data['order_id']])->value('order_code');
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:15
+ * @功能说明:申请提现
+ */
+ public function applyWallet(){
+
+ $input = $this->_input;
+
+ $wallet_model = new Wallet();
+
+ $config_model = new Config();
+
+ $user = $this->user_model->dataInfo(['id'=>$this->getUserId()]);
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ if($input['apply_price']>$user['wallet_cash']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ Db::startTrans();
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_code' => orderCode(),
+
+ 'store_id' => $this->store['id'],
+
+ 'pay_price' => $input['apply_price'],
+
+ 'text' => $input['text'],
+
+ 'true_price' => round($input['apply_price']*$config['cash_balance']/100,2),
+
+ 'balance' => $config['cash_balance'],
+
+ 'type' => 2,
+ ];
+ //发起提现
+ $res = $wallet_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ $water_model = new FinanceWater();
+
+ $id = $wallet_model->getLastInsID();
+ //添加提现记录
+ $res = $water_model->addWater($id,15,2,1);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ $id = $water_model->getLastInsID();
+ //执行记录
+ $res = $water_model->cashArrival(0,0,$id);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('申请失败');
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/controller/IndexUser.php b/app/farm/controller/IndexUser.php
new file mode 100755
index 0000000..7443348
--- /dev/null
+++ b/app/farm/controller/IndexUser.php
@@ -0,0 +1,999 @@
+model = new User();
+
+ $this->address_model = new Address();
+
+ $this->record_model = new CarAtvRecord();
+
+ $this->car_model = new Car();
+
+ $this->coupon_record_model = new CouponRecord();
+ //积分到账
+ // point_success($this->_uniacid);
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function index(){
+
+ if(empty($this->getUserId())){
+
+ return $this->success([]);
+
+ }
+
+ $data = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['type','=',1];
+
+ $cap_dis[] = ['status','in',[1,2,3,4]];
+
+ $farmer_model = new Farmer();
+ //查看是否是团长
+ $cap_info = $farmer_model->dataInfo($cap_dis);
+ //-1表示未申请团长,1申请中,2已通过,3取消,4拒绝
+ $data['farmer_status'] = !empty($cap_info)?$cap_info['status']:-1;
+
+ $data['sh_text'] = !empty($cap_info)?$cap_info['sh_text']:'';
+
+ $where[] = ['user_id','=',$this->getUserId()];
+
+ $where[] = ['status','in',[1,2,3,4]];
+
+ $distri_model = new DistributionList();
+
+ $fx = $distri_model->dataInfo($where);
+
+ $data['fx_status'] = !empty($fx)?$fx['status']:-1;
+
+ $data['fx_text'] = !empty($fx)?$fx['sh_text']:'';
+ //优惠券数
+ // $data['coupon_count'] = $this->coupon_record_model->couponCount($this->getUserId());
+ $water_model = new FinanceWater();
+ //冻结金额
+ $data['frozen_cash'] = $water_model->landordFrozenCash($this->getUserId());
+
+ $data['balance_cash']= round($data['balance'] - $data['wallet_cash'],2);
+
+ $data['balance'] += $data['frozen_cash'];
+
+ $data['balance'] = round($data['balance'],2);
+
+ $info_model = new SystemInfo();
+ //是否含有未读消息
+ $data['no_read_info'] = $info_model->userHaveNews($this->getUserId(),$this->_uniacid);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:54
+ * @功能说明:用户地址列表
+ */
+ public function addressList(){
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->address_model->dataList($dis,10);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:57
+ * @功能说明:用户地址详情
+ */
+ public function addressInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->address_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:58
+ * @功能说明:添加用户地址
+ */
+ public function addressAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $res = $this->address_model->dataAdd($input);
+
+ if($input['status']==1){
+
+ $id = $this->address_model->getLastInsID();
+
+ $this->address_model->updateOne($id);
+ }
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:58
+ * @功能说明:添加用户地址
+ */
+ public function addressUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->address_model->dataUpdate($dis,$input);
+
+ if(!empty($input['status'])&&$input['status']==1){
+
+ $this->address_model->updateOne($input['id']);
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 22:54
+ * @功能说明:获取默认地址
+ */
+ public function getDefultAddress(){
+
+ $address_model = new Address();
+
+ $address = $address_model->dataInfo(['user_id'=>$this->getUserId(),'status'=>1]);
+
+ return $this->success($address);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:13
+ * @功能说明:删除地址
+ */
+ public function addressDel(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->address_model->where($dis)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 13:56
+ * @功能说明:修改用户信息 授权微信信息等
+ */
+ public function userUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $this->getUserId()
+ ];
+
+ if(isset($input['coupon_atv_id'])){
+
+ unset($input['coupon_atv_id']);
+ }
+
+ if(isset($input['watermark'])){
+
+ unset($input['watermark']);
+ }
+
+ if(isset($input['openId'])){
+
+ unset($input['openId']);
+
+ }
+
+ if(isset($input['unionId'])){
+
+ unset($input['unionId']);
+
+ }
+ $res = $this->model->dataUpdate($dis,$input);
+
+ $user_info = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ setCache($this->autograph, $user_info, 7200, $this->_uniacid);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 14:08
+ * @功能说明:用户信息
+ */
+ public function userInfo(){
+
+ if(empty($this->getUserId())){
+
+ return $this->success([]);
+
+ }
+
+ $data = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['type','=',1];
+
+ $cap_dis[] = ['status','in',[1,2,3,4]];
+
+ $farmer_model = new \app\farm\model\Farmer();
+ //查看是否是团长
+ $cap_info = $farmer_model->dataInfo($cap_dis);
+ //-1表示未申请团长,1申请中,2已通过,3取消,4拒绝
+ $data['farmer_status'] = !empty($cap_info)?$cap_info['status']:-1;
+
+ $data['sh_text'] = !empty($cap_info)?$cap_info['sh_text']:'';
+
+ $data['balance_cash']= round($data['balance'] - $data['wallet_cash'],2);
+
+ $where[] = ['user_id','=',$this->getUserId()];
+
+ $where[] = ['status','in',[1,2,3,4]];
+
+ $distri_model = new DistributionList();
+
+ $fx = $distri_model->dataInfo($where);
+
+ $data['fx_status'] = !empty($fx)?$fx['status']:-1;
+
+ $data['fx_text'] = !empty($fx)?$fx['sh_text']:'';
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 13:35
+ * @功能说明:申请认证农场主
+ */
+ public function applyFarmer(){
+
+ $input = $this->_input;
+
+ $farmer_model = new Farmer();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','>',-1];
+
+ $cap_dis[] = ['type','=',1];
+
+ $cap_info = $farmer_model->dataInfo($cap_dis);
+
+ if(!empty($cap_info)&&in_array($cap_info['status'],[1,2,3])){
+
+ $this->errorMsg('你已经申请过农场主了,');
+ }
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['status'] = 1;
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+
+ $input['idcard_imgs'] = !empty($input['idcard_imgs'])?implode(',',$input['idcard_imgs']):'';
+
+ if(!empty($cap_info)&&$cap_info['status']==4){
+
+ $res = $farmer_model->dataUpdate(['id'=>$cap_info['id']],$input);
+
+ }else{
+
+ $res = $farmer_model->dataAdd($input);
+
+ }
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 10:43
+ * @功能说明:农场主详情
+ */
+ public function farmerInfo(){
+
+ if(empty($this->getUserId())){
+
+ return $this->success([]);
+
+ }
+
+ $farmer_model = new Farmer();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','>',-1];
+
+ $cap_dis[] = ['type','=',1];
+
+ $cap_info = $farmer_model->dataInfo($cap_dis);
+
+ return $this->success($cap_info);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-08 11:51
+ * @功能说明:用户优惠券列表
+ */
+ public function userCouponList(){
+
+ $input = $this->_param;
+
+ $this->coupon_record_model->initCoupon($this->_uniacid);
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'status' => $input['status'],
+
+ // 'is_show' => 1
+ ];
+
+ $data = $this->coupon_record_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ $v['use_time'] = date('Y.m.d H:i',$v['use_time']);
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 22:09
+ * @功能说明:删除优惠券
+ */
+ public function couponDel(){
+
+ $input = $this->_input;
+
+ $coupon = $this->coupon_record_model->dataInfo(['id'=>$input['coupon_id']]);
+
+ if($coupon['status']==1){
+
+ $this->errorMsg('待使用待卡券不能删除');
+ }
+
+ $res = $this->coupon_record_model->dataUpdate(['id'=>$input['coupon_id']],['is_show'=>0]);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:40
+ * @功能说明:生产二维码
+ */
+
+ public function atvQr(){
+
+ $input = $this->_input;
+
+ $key = 'atv_coupon'.$input['coupon_atv_id'];
+
+ $qr = getCache($key,$this->_uniacid);
+
+ if(empty($qr)){
+
+// $qr_insert = [
+//
+// 'coupon_atv_id' => $input['coupon_atv_id']
+// ];
+ //获取二维码
+ $qr = $this->model->orderQr($input,$this->_uniacid);
+
+ setCache($key,$qr,86400,$this->_uniacid);
+ }
+
+ return $this->success($qr);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-14 19:22
+ * @功能说明:授权手机号
+ */
+ public function reportPhone ()
+ {
+
+ $params = $this->_input;
+
+ $encryptedData = $params[ 'encryptedData' ];
+
+ $iv = $params[ 'iv' ];
+
+ $config = longbingGetAppConfig($this->_uniacid);
+
+ $appid = $config[ 'appid' ];
+
+ // $appsecret = $config[ 'app_secret' ];
+
+ $session_key = $this->model->where(['id'=>$this->getUserId()])->value('session_key');
+
+ if(empty($session_key)){
+
+ $this->errorMsg('need login',401);
+ }
+ $data = null;
+ // 解密
+ $errCode = decryptDataLongbing( $appid, $session_key, $encryptedData, $iv, $data );
+
+ if ( $errCode == 0 )
+ {
+ $data = json_decode( $data, true );
+
+ $phone = $data[ 'purePhoneNumber' ];
+
+ }
+ else
+ {
+ return $this->error( $errCode );
+ }
+
+ $res = $this->model->dataUpdate(['id'=>$this->getUserId()],['phone'=>$phone]);
+
+ $user_info = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ setCache($this->autograph, $user_info, 7200, $this->_uniacid);
+
+ return $this->success($phone);
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:46
+ * @功能说明:添加到购物车
+ */
+ public function addCar(){
+
+ $input = $this->_input;
+
+ $is_show_del = !empty($input['is_show_del'])?$input['is_show_del']:1;
+
+ if($is_show_del==1){
+
+ $this->car_model->where(['user_id'=>$this->getUserId(),'is_show'=>2])->delete();
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'farmer_id' => !empty($input['farmer_id'])?$input['farmer_id']:0,
+
+ 'goods_id'=> $input['goods_id'],
+
+ 'spe_id' => !empty($input['spe_id'])?$input['spe_id']:0,
+
+ 'type' => $input['type'],
+
+ 'is_show' => !empty($input['is_show'])?$input['is_show']:1,
+ ];
+
+ $info = $this->car_model->dataInfo($insert);
+ //增加数量
+ if(!empty($info)){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['goods_num'=>$info['goods_num']+$input['goods_num']]);
+
+ $id = $info['id'];
+
+
+ }else{
+ //添加到购物车
+ $insert['goods_num'] = $input['goods_num'];
+
+ $insert['status'] = 1;
+
+ $res = $this->car_model->dataAdd($insert);
+
+ $id = $this->car_model->getLastInsID();
+
+ }
+
+ return $this->success($id);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:54
+ * @功能说明:删除购物车
+ */
+ public function delCar(){
+
+ $input = $this->_input;
+
+ $info = $this->car_model->dataInfo(['id'=>$input['id']]);
+ //加少数量
+ if($info['goods_num']>$input['goods_num']){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['goods_num'=>$info['goods_num']-$input['goods_num']]);
+
+ }else{
+
+ $res = $this->car_model->where(['id'=>$info['id']])->delete();
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 10:39
+ * @功能说明:
+ */
+ public function carUpdate(){
+
+ $input = $this->_input;
+
+ $res = $this->car_model->where('id','in',$input['id'])->update(['status'=>$input['status']]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:59
+ * @功能说明:批量删除购物车
+ */
+ public function delSomeCar(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'type' => $input['type']
+
+ ];
+
+ $where = [];
+
+ if(!empty($input['id'])){
+
+ $where[] = ['id','in',$input['id']];
+ }
+
+ $res = $this->car_model->where($dis)->where($where)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-10 11:28
+ * @功能说明:用户消费流水记录
+ */
+ public function userConsumeWater(){
+
+ $input = $this->_param;
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ if(isset($input['add'])){
+
+ $dis[] = ['add','=',$input['add']];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $water_model = new BalanceWater();
+
+ $data = $water_model->indexList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-21 17:08
+ * @功能说明:申请分销商
+ */
+ public function applyReseller(){
+
+ $input = $this->_input;
+
+ $distribution_model = new DistributionList();
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $find = $distribution_model->dataInfo($dis);
+
+ if(!empty($find)&&in_array($find['status'],[1,2,3])){
+
+ $this->errorMsg('你已经申请');
+
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'user_name'=> $input['user_name'],
+
+ 'mobile' => $input['mobile'],
+
+ 'status' => 1,
+
+ ];
+
+ if(!empty($find)&&$find['status']==4){
+
+ $res = $distribution_model->dataUpdate(['id'=>$find['id']],$insert);
+
+ }else{
+
+ $res = $distribution_model->dataAdd($insert);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-26 14:07
+ * @功能说明:绑定分销商
+ */
+ public function bindReseller(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'fx_code' => $input['fx_code'],
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('邀请码无效');
+ }
+
+ if(!empty($this->getUserInfo()['pid'])){
+
+ $this->errorMsg('你已经绑定分销商');
+
+ }
+
+ $update = [
+
+ 'pid' => $data['id']
+ ];
+
+ $res = $this->model->dataUpdate(['id'=>$this->getUserId()],$update);
+
+ return $this->success($res);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:39
+ * @功能说明:分销商详情
+ */
+ public function resellerInfo(){
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','in',[1,2,3,4]];
+
+ $distribution_model = new DistributionList();
+
+ $cap_info = $distribution_model->dataInfo($cap_dis);
+
+ return $this->success($cap_info);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-23 11:38
+ * @功能说明:获取app下载地址
+ */
+ public function getAppDownloadQr(){
+
+ $data = getCode($this->_uniacid,'www.baidu.com');
+
+ return $this->success($data);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-14 11:55
+ * @功能说明:发送验证码
+ */
+ public function sendShortMsg(){
+
+ $input = $this->_input;
+ //验证码验证
+ $config = new Config();
+
+ $dis = [
+
+ 'uniacid' =>$this->_uniacid,
+
+ 'phone' => $input['phone']
+ ];
+
+ $find = $this->model->dataInfo($dis);
+
+ if(!empty($find)){
+
+ $this->errorMsg('该手机号已经被绑定');
+ }
+
+ $res = $config->sendSms($input['phone'],$this->_uniacid);
+
+ if(!empty($res['Message'])&&$res['Message']=='OK'){
+
+ return $this->success(1);
+
+ }else{
+
+ return $this->error($res['Message']);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-26 10:29
+ * @功能说明:判断用户手机号
+ */
+ public function bindUserPhone(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' =>$this->_uniacid,
+
+ 'phone' => $input['phone']
+ ];
+
+ $find = $this->model->dataInfo($dis);
+
+ if(!empty($find)){
+
+ $this->errorMsg('该手机号已经被绑定');
+ }
+
+ $short_code = getCache($input['phone'],$this->_uniacid);
+ //验证码验证手机号
+ if($input['short_code']!=$short_code){
+
+ return $this->error('验证码错误');
+
+ }
+
+ $res = $this->model->dataUpdate(['id'=>$this->getUserId()],$dis);
+
+ $user = $this->getUserInfo();
+
+ $user['phone'] = $input['phone'];
+
+ $key = 'longbing_user_autograph_' . $user['id'];
+
+ $key = md5($key);
+
+ setCache($key, $user, 7200, $this->_uniacid);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-26 15:45
+ * @功能说明:通过分销码查找分销商
+ */
+ public function fxcodeUser(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'is_fx' => 1,
+
+ 'fx_code' => $input['fx_code'],
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ if(!empty($data)){
+
+ $fx_model = new DistributionList();
+
+ $data['fx_name'] = $fx_model->where(['user_id'=>$data['id'],'status'=>2])->value('user_name');
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+}
diff --git a/app/farm/info/AdminMenu.php b/app/farm/info/AdminMenu.php
new file mode 100755
index 0000000..be79591
--- /dev/null
+++ b/app/farm/info/AdminMenu.php
@@ -0,0 +1,596 @@
+ $malls];
+
+
diff --git a/app/farm/info/DiyCompoents.php b/app/farm/info/DiyCompoents.php
new file mode 100755
index 0000000..e308bfd
--- /dev/null
+++ b/app/farm/info/DiyCompoents.php
@@ -0,0 +1,51 @@
+ "业务组件",
+
+ 'type' => 'shopCompoent',
+
+ 'data' =>[
+
+ json_decode($search, true),
+
+ json_decode($goods, true),
+
+ ]
+ ],
+];
\ No newline at end of file
diff --git a/app/farm/info/DiyDefaultCompoents.php b/app/farm/info/DiyDefaultCompoents.php
new file mode 100755
index 0000000..0508625
--- /dev/null
+++ b/app/farm/info/DiyDefaultCompoents.php
@@ -0,0 +1,276 @@
+ 2,
+ "title" => "商城",
+ "type" => "shop",
+ "data" => [
+ [
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/diy/admin/Module/functionPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "功能页面",
+ //小程序路径
+ "page" => "common_page"
+ ],[
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/shop/admin/AdminShopType/cateInfoPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商品分类页面",
+ //小程序路径
+ "page" => "/shop/pages/filter"
+ ],[
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/shop/admin/AdminShopGoods/goodsInfoPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商品详情页面",
+ //小程序路径
+ "page" => "/pages/shop/detail"
+ ],
+ ]
+ ],
+];
\ No newline at end of file
diff --git a/app/farm/info/DiyTabbar.php b/app/farm/info/DiyTabbar.php
new file mode 100755
index 0000000..539d278
--- /dev/null
+++ b/app/farm/info/DiyTabbar.php
@@ -0,0 +1,42 @@
+ 2 ,
+ //是否显示
+ 'is_show' => 1 ,
+ //图标
+ 'iconPath' => 'icon-shangcheng1',
+ //选中图标样式
+ 'selectedIconPath' => 'icon-shangcheng',
+ //那个页面 英文名称
+ 'pageComponents' => 'shopHome',
+ //名称
+ 'name' => '商城',
+ 'url' => '',
+ 'url_jump_way' => '0',
+ 'url_out' => '',
+ 'is_delete' => false ,
+ 'bind_compoents'=>[
+ 'base',
+ 'shopCompoent',
+ 'operate'
+ ],
+
+ 'bind_links' => [
+
+ 'shop'
+ ],
+ 'page'=> []
+ ],
+
+];
\ No newline at end of file
diff --git a/app/farm/info/FunctionPage.php b/app/farm/info/FunctionPage.php
new file mode 100755
index 0000000..8562ec4
--- /dev/null
+++ b/app/farm/info/FunctionPage.php
@@ -0,0 +1,86 @@
+'',
+
+ 'level'=>1,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城页面",
+ //小程序路径
+ "path" => "/pages/user/home?key=2&staff_id="
+ ],[
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城购物车",
+ //小程序路径
+ "path" => "/shop/pages/cart"
+ ],[
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城卡券列表",
+ //小程序路径
+ "path" => "/shop/pages/coupon/receive?staff_id="
+ ],
+
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城全部分类",
+ //小程序路径
+ "path" => "/shop/pages/cate"
+ ],
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城采购模版",
+ //小程序路径
+ "path" => "/shop/pages/purchase/list?staff_id="
+ ],
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城砍价列表页",
+ //小程序路径
+ "path" => "/shop/pages/bargain/list?staff_id="
+ ],
+
+
+
+];
+
+
+return $tmp;
\ No newline at end of file
diff --git a/app/farm/info/Info.php b/app/farm/info/Info.php
new file mode 100755
index 0000000..bf5746b
--- /dev/null
+++ b/app/farm/info/Info.php
@@ -0,0 +1,32 @@
+ 'farm',
+ //模块标题[必填]
+ 'title' =>'智慧农业',
+ //内容简介
+ 'desc' =>'',
+ //封面图标
+ 'icon' =>'',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => 'model',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'farm.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.80',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module'=> [],
+ // 应用依赖[可选],格式[[插件名, 应用唯一标识, 依赖版本, 对比方式]]
+ 'need_app' => [],
+ //订阅消息
+ 'tmpl_name'=>['pay_order','send_order','land_order','land_over']
+
+];
\ No newline at end of file
diff --git a/app/farm/info/PermissionFarm.php b/app/farm/info/PermissionFarm.php
new file mode 100755
index 0000000..399a62b
--- /dev/null
+++ b/app/farm/info/PermissionFarm.php
@@ -0,0 +1,105 @@
+saasKey = longbing_get_auth_prefix('AUTH_SHOP') ;
+ parent::__construct($uniacid, self::tabbarKey, self::adminMenuKey, $this->saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+
+ return true ;
+
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+
+ return false;
+
+
+ //代理管理端可以控制商城是否展示权限 , 这里需要判断权限
+ $pAuthConfig = $this->getPAuthConfig();
+ //必须平台授权才能使用
+
+ //dump($this->getAuthIsPlatformCheck());exit;
+ if($this->getAuthIsPlatformCheck()){
+ //根据授权而定
+ if ($pAuthConfig ){
+
+// dump($pAuthConfig);exit;
+ return $pAuthConfig['shop_switch'] ? true : false ;
+ }
+ }
+
+ return true;
+
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+
+ return true;
+ }
+
+ /**
+ * 添加商品数量
+ *
+ * @author shuixian
+ * @DataTime: 2019/12/19 19:02
+ */
+ public function getAddGoodsNumber(){
+ return $this->getAuthVaule( longbing_get_auth_prefix('AUTH_GOODS') , 4);
+
+ }
+}
\ No newline at end of file
diff --git a/app/farm/info/RadarMessage.php b/app/farm/info/RadarMessage.php
new file mode 100755
index 0000000..63f6b05
--- /dev/null
+++ b/app/farm/info/RadarMessage.php
@@ -0,0 +1,204 @@
+ "copy",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "咨询",
+ "item"=> "产品",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+ [
+ "sign"=> "view",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商城列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机,主动提供细致的商品讲解将大大有利于成交",
+ "operation"=> "正在查看",
+ "item"=> "商品",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_goods",
+ "field"=> "name",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商品分类列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+ [
+ "sign"=> "view",
+ "type"=> 19,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "订单商品已发货,系统订单号为:",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 20,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "自提商品已提货",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 21,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请等待管理员审核并注意查收",
+ "operation"=> "已申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 22,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "已取消申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 23,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "管理员拒绝退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 24,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请注意查收",
+ "operation"=> "退款成功",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已购买商品",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已参与拼团",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在预约订单中心查看详情",
+ "operation"=> "预约了",
+ "item"=> "服务",
+ "show_count"=> 0,
+ "table_name"=> "lb_appoint_record",
+ "field"=> "name,phone,project_id,start_time,remark",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+
+];
+
+return $radar_msg;
diff --git a/app/farm/info/Subscribe.php b/app/farm/info/Subscribe.php
new file mode 100755
index 0000000..2631956
--- /dev/null
+++ b/app/farm/info/Subscribe.php
@@ -0,0 +1,455 @@
+_uniacid);
+ if($permissson->pAuth()) {
+
+ $modelMenu = [
+ "title" => '商品服务',
+ "desc" => '',
+ "show" => true,
+ "row" => 4,
+ "list" => [
+ [
+ "title" => "我的收入",
+ "icon" => "icontixianguanli",
+ "link" => "/shop/pages/partner/income",
+ "linkType" => 4
+ ],
+ [
+ "title" => "订单管理",
+ "icon" => "iconwodedingdan",
+ "link" => "/shop/pages/order/list?target=staff",
+ "linkType" => 4
+ ],
+ [
+ "title" => "退款管理",
+ "icon" => "iconwodeshouhou",
+ "link" => "/shop/pages/refund/list?target=staff",
+ "linkType" => 4
+ ],
+ [
+ "title" => "推荐商品",
+ "icon" => "icontuijianshangpin",
+ "link" => "/shop/pages/staff/goods/push",
+ "linkType" => 4
+ ],
+ [
+ "title" => "卡券管理",
+ "icon" => "iconwodekaquan",
+ "link" => "/shop/pages/staff/coupon/list",
+ "linkType" => 4
+ ]
+ ]
+ ];
+
+ return [$modelMenu];
+ }
+ return [];
+
+ }
+
+ /**
+ * 名片展示页获取其他模块数据
+ *
+ * @param $params
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/24 14:24
+ */
+ public function onCardInfo($params)
+ {
+
+ //获取推荐商品 By.jingshuixian
+ $modelExtension = new CardExtension();
+ $goods_list = $modelExtension->cardExtensionList($params['staff_id'], $this->_uniacid);
+
+ $collage_model = new IndexShopCollage();
+ foreach ($goods_list as $key => $val) {
+ $goods_list[$key]['is_collage'] = 0;
+ $count = $collage_model->getCollage(['goods_id' => $val['id'], 'uniacid' => $this->_uniacid, 'status' => 1]);
+ if (!empty($count)) $goods_list[$key]['is_collage'] = 1;
+ }
+
+ return ['goods_list'=>$goods_list];
+ }
+
+ /**
+ * 客户获取列表查询
+ *
+ * @param $data
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/26 10:30
+ */
+ public function onStaffCustomerList($data)
+ {
+ // 商城订单
+ $orderCount = RadarOrder::where( [ [ 'pay_status', '=', 1 ],
+ [ 'order_status', '<>', 1 ],
+ [ 'user_id', '=', $data[ 'uid' ] ],
+ [ 'to_uid', '=', $data[ 'to_uid' ]],
+ [ 'refund_status', '=', 0 ] ]
+ )
+ ->count();
+
+ $returnData[ 'count' ] = $orderCount;
+ $returnData[ 'title' ] = "订单";
+
+ return [$returnData];
+ }
+
+
+ /**
+ * @param $data
+ * @功能说明:处理一下数据 主要是权限方面的
+ * @author chenniang
+ * @DataTime: 2020-12-16 16:21
+ */
+ public function onDiyModuleMenuShop($data){
+
+
+ if(!empty($data['data']['list'])){
+
+ foreach ($data['data']['list'] as $v){
+
+ if($v['icon']!='icontemplate'||$data['shop_auth']==true){
+
+ $arr[] = $v;
+ }
+
+ }
+ $data['data']['list'] = $arr;
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * 监听用户中心模块
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/18 14:04
+ */
+ public function onAddUcenterCompoent(){
+ $this->getUserId();
+
+ $user = longbingGetUserInfo($this->getUserId() , $this->_uniacid);
+
+ $last_staff_id = !empty($user['last_staff_id'])?$user['last_staff_id']:0;
+
+ $moduleMenuShopOrder = <<_uniacid);
+
+ $bargain_auth = $bargain_p->pAuth();
+
+ $bargain = $bargain_auth==true?',
+ {
+ "title": "我的砍价",
+ "icon": "iconkanjiajilu",
+ "link": {
+ "type": 2,
+ "url": "/shop/pages/bargain/record"
+ }
+ }':'';
+
+ $moduleMenuShop = <<_uniacid);
+ $compoentList = [] ;
+ if($permission->pAuth()){
+ $compoentList = [
+ json_decode($moduleMenuShopOrder, true),
+ json_decode($moduleMenuShop, true)
+ ] ;
+ }
+
+ return $compoentList ;
+ }
+
+
+
+ /**
+ * 监听代理管理端授权小程序事件
+ *
+ * @param $data
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/27 17:33
+ */
+ public function onAgentAppAuthEdit($config){
+
+
+ $returnArr = [] ;
+
+ $permission = new PermissionShop(0);
+ $shop_switch = [] ;
+ if($permission->sAuth() && $permission->infoConfig['auth_platform'] ) {
+
+ $shop_switch['formType'] = 'radio';
+ $shop_switch['name'] = 'shop_switch';
+
+ $shop_switch['value'] = $config ? $config[ $shop_switch['name'] ] : 0;
+ $shop_switch['title'] = $permission->info['title'];
+ $returnArr[] = $shop_switch;
+ }
+
+
+ $pay_shop = [] ;
+ if($permission->sAuth() && $permission->infoConfig['auth_platform'] ) {
+
+ $pay_shop['formType'] = 'radio';
+ $pay_shop['name'] = 'pay_shop';
+
+ $pay_shop['value'] = $config ? $config[ $pay_shop['name'] ] : 0;
+ $pay_shop['title'] = $permission->info['title'].'支付';
+ $returnArr[] = $pay_shop;
+ }
+
+ return $returnArr ;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/farm/info/UpdateSql.php b/app/farm/info/UpdateSql.php
new file mode 100755
index 0000000..e69de29
diff --git a/app/farm/model/AboutUs.php b/app/farm/model/AboutUs.php
new file mode 100755
index 0000000..92f1d9b
--- /dev/null
+++ b/app/farm/model/AboutUs.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Address.php b/app/farm/model/Address.php
new file mode 100755
index 0000000..0bf8324
--- /dev/null
+++ b/app/farm/model/Address.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Admin.php b/app/farm/model/Admin.php
new file mode 100755
index 0000000..e8741ff
--- /dev/null
+++ b/app/farm/model/Admin.php
@@ -0,0 +1,77 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/AdminRole.php b/app/farm/model/AdminRole.php
new file mode 100755
index 0000000..26af56d
--- /dev/null
+++ b/app/farm/model/AdminRole.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Article.php b/app/farm/model/Article.php
new file mode 100755
index 0000000..b753813
--- /dev/null
+++ b/app/farm/model/Article.php
@@ -0,0 +1,77 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BagAtv.php b/app/farm/model/BagAtv.php
new file mode 100755
index 0000000..d68f023
--- /dev/null
+++ b/app/farm/model/BagAtv.php
@@ -0,0 +1,252 @@
+insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($new_coupon)&&isset($share_coupon)){
+
+ $this->updateSome($id,$data['uniacid'],$new_coupon,$share_coupon);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:41
+ * @功能说明:添加优惠券
+ */
+ public function updateSome($id,$uniacid,$new,$share){
+
+ $coupon_model = new BagAtvCoupon();
+
+ $dis = [
+
+ 'atv_id' => $id
+ ];
+
+ $coupon_model->where($dis)->delete();
+
+ if(!empty($new)){
+
+ foreach ($new as $key=>$value){
+
+ $new[$key]['uniacid'] = $uniacid;
+
+ $new[$key]['atv_id'] = $id;
+
+ $new[$key]['type'] = 1;
+
+ }
+
+ $coupon_model->saveAll($new);
+ }
+
+ if(!empty($share)){
+
+ foreach ($share as $k=>$v){
+
+ $share[$k]['uniacid'] = $uniacid;
+
+ $share[$k]['atv_id'] = $id;
+
+ $share[$k]['type'] = 2;
+
+ }
+
+ $coupon_model->saveAll($share);
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['new_coupon'])){
+
+ $new_coupon = $data['new_coupon'];
+
+ unset($data['new_coupon']);
+ }
+
+ if(isset($data['share_coupon'])){
+
+ $share_coupon = $data['share_coupon'];
+
+ unset($data['share_coupon']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($new_coupon)&&isset($share_coupon)){
+
+ $this->updateSome($dis['id'],$data['uniacid'],$new_coupon,$share_coupon);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 18:15
+ * @功能说明:检查
+ */
+ public function changeData($data){
+
+ if(isset($data['imgs'])){
+
+ $data['img'] = !empty($data['imgs'])?implode(',',$data['imgs']):'';
+ }
+
+ $id = !empty($input['id'])?$input['id']:'';
+
+ $where[] = ['status','>',-1];
+
+ $where[] = ['uniacid','=',$data['uniacid']];
+
+ if(!empty($id)){
+
+ $where[] = ['id','<>',$id];
+
+ }
+
+ $list = $this->where($where)->select()->toArray();
+
+ if(!empty($list)){
+
+ foreach ($list as $value){
+
+ $res = is_time_cross($value['start_time'],$value['end_time'],$data['start_time'],$data['end_time']);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'该时间段已有活动'];
+ }
+
+ }
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-03-21 15:04
+ * @功能说明:正在进行的活动
+ */
+ public function activeIng($uniacid,$id = ''){
+
+ $dis[] = ['start_time','<',time()];
+
+ $dis[] = ['end_time','>',time()];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ if(!empty($id)){
+
+ $dis[] = ['id','<>',$id];
+ }
+
+ $data = $this->where($dis)->find();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BagAtvCoupon.php b/app/farm/model/BagAtvCoupon.php
new file mode 100755
index 0000000..7d6e046
--- /dev/null
+++ b/app/farm/model/BagAtvCoupon.php
@@ -0,0 +1,106 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-01 14:41
+ * @功能说明:添加优惠券
+ */
+ public function updateSome($id,$uniacid,$new,$share){
+
+
+
+
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BagRecord.php b/app/farm/model/BagRecord.php
new file mode 100755
index 0000000..31c6ec5
--- /dev/null
+++ b/app/farm/model/BagRecord.php
@@ -0,0 +1,95 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BagRecordCoupon.php b/app/farm/model/BagRecordCoupon.php
new file mode 100755
index 0000000..ebce1e7
--- /dev/null
+++ b/app/farm/model/BagRecordCoupon.php
@@ -0,0 +1,95 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BalanceCard.php b/app/farm/model/BalanceCard.php
new file mode 100755
index 0000000..be32f2f
--- /dev/null
+++ b/app/farm/model/BalanceCard.php
@@ -0,0 +1,108 @@
+where(['id'=>$data['member_level']])->value('title');
+
+ return !empty($title)?$title:'';
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BalanceOrder.php b/app/farm/model/BalanceOrder.php
new file mode 100755
index 0000000..035358f
--- /dev/null
+++ b/app/farm/model/BalanceOrder.php
@@ -0,0 +1,230 @@
+where(['id'=>$data['user_id']])->value('nickName');
+
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:31
+ * @功能说明:订单支付回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['status']==1){
+
+ $user_model = new User();
+
+ $water_model= new BalanceWater();
+
+ $user = $user_model->dataInfo(['id'=>$order['user_id']]);
+
+ Db::startTrans();
+
+ $update = [
+
+ 'transaction_id' => $transaction_id,
+
+ 'status' => 2,
+
+ 'pay_time' => time(),
+
+ 'now_balance' => $order['true_price']+$user['balance']
+
+ ];
+ //修改订单信息
+ $res = $this->dataUpdate(['id'=>$order['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+
+ $update = [
+
+ 'balance' => $order['true_price']+$user['balance'],
+
+ ];
+
+ if(!empty($order['member_level'])){
+
+ $update['member_level'] = $order['member_level'];
+ }
+ //修改用户余额
+ $res = $user_model->dataUpdate(['id'=>$order['user_id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ //添加余额流水
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'price' => $order['true_price'],
+
+ 'order_id'=> $order['id'],
+
+ 'add' => 1,
+
+ 'type' => 1,
+
+ 'before_balance' => $user['balance'],
+
+ 'after_balance' => $order['true_price']+$user['balance'],
+ ];
+
+ $res = $water_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ //增加积分
+ $ilog_model = new IntegralLog();
+
+ $ilog_model->integralUserAdd($order['user_id'],$order['integral'],$order['uniacid'],2,2,$order['id']);
+
+ if(!empty($order['member_level'])){
+
+ $member_model = new Member();
+
+ $order['member_title'] = $member_model->where(['id'=>$order['member_level']])->value('title');
+
+ $push_model = new PushMsgModel($order['uniacid']);
+
+ $push_model->sendMsg($order,16);
+ }
+
+ Db::commit();
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BalanceWater.php b/app/farm/model/BalanceWater.php
new file mode 100755
index 0000000..920b3f3
--- /dev/null
+++ b/app/farm/model/BalanceWater.php
@@ -0,0 +1,386 @@
+where(['id'=>$data['order_id']])->value('title');
+ //认养
+ }elseif($data['type']==2){
+
+ $order_model = new ClaimOrder();
+
+ $title = $order_model->where(['id'=>$data['order_id']])->value('goods_name');
+
+ //养殖订单
+ }elseif($data['type']==5){
+
+ $shop_order_model = new BreedOrderGoods();
+
+ $title = $shop_order_model->where(['order_id'=>$data['order_id']])->column('goods_name');
+
+ $title = !empty($title)?implode(',',$title):'';
+ //土地订单
+ }elseif($data['type']==4){
+
+ $order_model = new LandOrder();
+
+ $title = $order_model->where(['id'=>$data['order_id']])->value('spe_name');
+
+ }elseif($data['type']==7||$data['type']==11){
+
+ $order_model = new ShopOrderGoods();
+
+ $title = $order_model->where(['order_id'=>$data['order_id']])->column('goods_name');
+
+ $title = !empty($title)?implode(',',$title):'';
+ }
+
+ return $title;
+
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-05 09:56
+ * @功能说明:
+ */
+ public function sceneText($type){
+
+ switch ($type){
+
+ case 1:
+
+ $text = '购买储值卡';
+
+ break;
+ case 2:
+
+ $text = '认养订单';
+
+ break;
+
+ case 3:
+
+ $text = '认养配送订单';
+
+ break;
+
+ case 4:
+
+ $text = '配送订单退款';
+
+ break;
+
+ case 5:
+
+ $text = '养殖订单';
+
+ break;
+
+ case 6:
+
+ $text = '土地订单';
+
+ break;
+
+ case 7:
+
+ $text = '商城交易支付';
+
+ break;
+
+ case 8:
+
+ $text = '提现';
+
+ break;
+ case 9:
+
+ $text = '土地配送订单';
+
+ break;
+ case 10:
+
+ $text = '商城订单退款';
+
+ break;
+ case 11:
+
+ $text = '商城交易收入';
+
+ break;
+
+ case 12:
+
+ $text = '拒绝提现';
+
+ break;
+
+ case 13:
+
+ $text = '认养订单';
+
+ break;
+
+ default:
+
+ $text = '购买储值卡1';
+
+ break;
+
+ }
+
+ return $text;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+// if(){
+//
+// }
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function indexList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['after_balance'] = round($v['after_balance'],2);
+
+ $v['before_balance'] = round($v['before_balance'],2);
+
+ $add_text = $v['add']==1?'+':'-';
+
+ $buy_text = $v['add']==1?'退款':'消费';
+
+ if($v['type']==1){
+
+ $buy_text = '';
+ }
+
+ $scene_text = $this->sceneText($v['type']);
+
+ $v['text'] = $scene_text.$buy_text.'【'.$v['goods_title'].'】'.$add_text.'¥'.$v['price'].'现余额¥'.$v['after_balance'];
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 11:14
+ * @功能说明:增加流水并且修改用户余额
+ */
+ public function addWater($order,$type,$add=0){
+
+ $user_model = new \app\farm\model\User();
+
+ $water_model = new BalanceWater();
+
+ $user = $user_model->dataInfo(['id'=>$order['user_id']]);
+ //如果是平台
+ if(empty($user)){
+
+ return true;
+ }
+
+ $dis = [
+
+ 'id' => $user['id'],
+
+ 'lock' => $user['lock']
+
+ ];
+
+ $update = [
+
+ 'lock' => $user['lock']+1
+ ];
+
+ if($add==0){
+
+ $update['balance'] = $user['balance']-$order['pay_price'];
+ //地主提现或者退款
+ if(in_array($type,[8,10])){
+
+ $update['wallet_cash'] = $user['wallet_cash'] - $order['pay_price'];
+
+ $update['landlord_cash'] = $user['landlord_cash']- $order['pay_price'];
+ }
+ //如果总余额小于可提现余额 可提现余额也要减掉
+ if($update['balance']<$user['wallet_cash']){
+
+ $update['wallet_cash'] = $update['balance'];
+
+ $update['landlord_cash'] = $update['balance'];
+ }
+
+ }else{
+
+ $update['balance'] = $user['balance']+$order['pay_price'];
+ //地主收入 需要增加可提现余额
+ if($type==11||$type==12){
+
+ $update['wallet_cash'] = $user['wallet_cash']+$order['pay_price'];
+
+ $update['landlord_cash'] = $user['landlord_cash']+$order['pay_price'];
+
+ }
+
+ }
+ //修改用户余额
+ $res = $user_model->dataUpdate($dis,$update);
+
+ if($res==0){
+
+ return false;
+ }
+ //添加余额流水
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'price' => $order['pay_price'],
+
+ 'order_id'=> $order['id'],
+
+ 'add' => $add,
+
+ 'type' => $type,
+
+ 'before_balance' => $user['balance'],
+
+ 'after_balance' => $add==0?$user['balance']-$order['pay_price']:$user['balance']+$order['pay_price'],
+ ];
+
+ $res = $water_model->dataAdd($insert);
+
+ if($res==0){
+
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Banner.php b/app/farm/model/Banner.php
new file mode 100755
index 0000000..3ec8e66
--- /dev/null
+++ b/app/farm/model/Banner.php
@@ -0,0 +1,117 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-09 13:37
+ * @功能说明:详情
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-15 11:12
+ * @功能说明:编辑
+ */
+ public function updateSome($id,$data){
+
+ if(empty($data['type'])){
+
+ return false;
+ }
+
+ $text_model = new BannerText();
+
+ $text_model->where(['banner_id'=>$id,'type'=>$data['type']])->delete();
+
+ if(!empty($data['text_id'])){
+
+ foreach ($data['text_id'] as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'text_id' => $v,
+
+ 'banner_id'=> $id,
+
+ 'type' => $data['type']
+ ];
+ }
+
+ $text_model->saveAll($insert);
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BannerText.php b/app/farm/model/BannerText.php
new file mode 100755
index 0000000..a396f01
--- /dev/null
+++ b/app/farm/model/BannerText.php
@@ -0,0 +1,76 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-09 13:37
+ * @功能说明:详情
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Breed.php b/app/farm/model/Breed.php
new file mode 100755
index 0000000..180b7b1
--- /dev/null
+++ b/app/farm/model/Breed.php
@@ -0,0 +1,265 @@
+ 2,
+
+ 'a.goods_id' => $data['id'],
+
+ 'a.type' => 5
+ ];
+
+ $store_goods_model = new StoreGoods();
+
+ $list = $store_goods_model->alias('a')
+ ->join('lbfarm_farmer b','a.store_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title')
+ ->group('a.id')
+ ->order('a.id dsec')
+ ->column('b.id');
+
+ return array_values($list);
+ }
+
+
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:养殖列表
+ * @author chenniang
+ * @DataTime: 2022-07-12 17:57
+ */
+ public function breedList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_store b','a.id = b.goods_id','left')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(!empty($data['farmer_id'])){
+
+ $farmer = $data['farmer_id'];
+
+ unset($data['farmer_id']);
+ }
+
+ $res = $this->insert($data);
+
+ if(isset($farmer)){
+
+ $res = $this->getLastInsID();
+
+ $this->updateSome($res,$farmer,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(!empty($data['farmer_id'])){
+
+ $farmer = $data['farmer_id'];
+
+ unset($data['farmer_id']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($farmer)){
+
+ $this->updateSome($dis['id'],$farmer,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $data
+ * @param $uniacid
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-12 17:17
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $store_goods_model = new StoreGoods();
+
+ $res = $store_goods_model->addData($id,5,$uniacid,$data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-09 16:11
+ * @功能说明:列表
+ */
+ public function indexDataList($dis,$page=10){
+
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_store b','a.id = b.goods_id')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 17:05
+ * @功能说明:获取养殖购物车信息
+ */
+ public function getCarList($user_id,$farmer_id){
+
+ $dis = [
+
+ 'b.user_id' => $user_id,
+
+ 'b.farmer_id'=> $farmer_id,
+
+ 'a.status' => 1,
+
+ 'b.type' => 1,
+
+ 'c.type' => 5,
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_car b','a.id = b.goods_id')
+ ->join('lbfarm_v2_goods_store c','a.id = c.goods_id')
+ ->where($dis)
+ ->field('a.*,b.goods_num,b.goods_id,ROUND(a.price*b.goods_num,2) as all_price')
+ ->group('b.id')
+ ->order('b.id desc')
+ ->select()
+ ->toArray();
+
+ $arr['car_list'] = $data;
+
+ $arr['price'] = array_sum(array_column($data,'all_price'));
+
+ $arr['goods_num']= array_sum(array_column($data,'goods_num'));
+
+ return $arr;
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BreedOrder.php b/app/farm/model/BreedOrder.php
new file mode 100755
index 0000000..5ee7ed1
--- /dev/null
+++ b/app/farm/model/BreedOrder.php
@@ -0,0 +1,172 @@
+where(['order_id'=>$data['id']])->select()->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 15:39
+ * @功能说明:回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ $update = [
+
+ 'pay_time' => time(),
+
+ 'pay_type' => 7,
+
+ 'transaction_id' => $transaction_id
+ ];
+
+ $this->dataUpdate(['id'=>$order['id']],$update);
+ //扣除余额
+ if($order['balance']>0){
+
+ $water_model = new BalanceWater();
+
+ $res = $water_model->addWater($order,5,0);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ }
+ //添加流水
+ $water_model = new FinanceWater();
+
+ $water_model->addWater($order['id'],6,1,1);
+
+ $integral_model = new IntegralLog();
+
+ $integral_model->integralUserAdd($order['user_id'],$order['get_integral'],$order['uniacid'],2,7,$order['id']);
+
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/BreedOrderGoods.php b/app/farm/model/BreedOrderGoods.php
new file mode 100755
index 0000000..4892c12
--- /dev/null
+++ b/app/farm/model/BreedOrderGoods.php
@@ -0,0 +1,128 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 17:19
+ * @功能说明:
+ */
+ public function orderAdd($goods,$order_id){
+
+ foreach ($goods as $v){
+
+ $insert = [
+
+ 'uniacid' => $v['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'goods_id' => $v['goods_id'],
+
+ 'goods_name' => $v['title'],
+
+ 'goods_cover' => $v['cover'],
+
+ 'goods_num' => $v['goods_num'],
+
+ 'true_num' => $v['goods_num'],
+
+ 'goods_price' => $v['price'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Car.php b/app/farm/model/Car.php
new file mode 100755
index 0000000..2fdaa73
--- /dev/null
+++ b/app/farm/model/Car.php
@@ -0,0 +1,371 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-10 15:19
+ * @功能说明:获取购物车内的价格
+ */
+ public function carBreedPrice($user_id,$farmer_id){
+
+ $dis = [
+
+ 'a.user_id' => $user_id,
+
+ 'a.farmer_id' => $farmer_id,
+
+ 'a.type' => 1,
+
+ 'a.status' => 1
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_breed b','a.goods_id = b.id')
+ ->where($dis)
+ ->field('(a.goods_num*b.price) as total_price')
+ ->select()
+ ->toArray();
+
+ return array_sum(array_column($data,'total_price'));
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 17:21
+ * @功能说明:购物车价格
+ */
+ public function carPriceAndCount($user_id,$store_id,$is_car=0,$is_show=1,$no_i=1){
+ //查询积分活动
+ $integral_model = new IntegralList();
+
+ $kill_model = new SeckillList();
+ //选中
+ $list = $this->carList($user_id,$store_id,0,$is_show);
+ //所有 is_car0的时候也是选中
+ $data['list'] = $this->carList($user_id,$store_id,$is_car,$is_show);
+ //是否是秒杀商品
+ $have_kill = $kill_model->getBuyLimit($data['list']);
+
+ if(!empty($have_kill)){
+
+ $buy_limit = 0;
+
+ $no_i = 1;
+
+ $discount_add = 0;
+
+ }else{
+ $min = $integral_model->getBuyLimit($data['list']);
+ //获取是否允许原价购买 1允许 0不允许
+ $buy_limit = $min['buy_limit'];
+
+ $no_i = $buy_limit==1?$no_i:0;
+ //是否允许优惠活动叠加
+ $discount_add = $no_i==0?$min['discount_add']:1;
+
+ }
+ //积分抵扣掉的钱
+ $integral_discount_price = $kill_discount_price = 0;
+ //积分
+ $integral = 0;
+
+ if(!empty($data['list'])){
+
+ foreach ($data['list'] as &$vs){
+
+ $vs['member_discount'] = 100;
+
+ $vs['integral'] = $vs['i_price'] = $vs['integral_id'] = $vs['kill_atv_id'] = $v['integral_discount_price'] = 0;
+
+ $kill_list = $kill_model->atvIng($vs['goods_id'],$vs['spe_id']);
+ //秒杀
+ if(!empty($kill_list)){
+
+ $vs['true_price'] = $kill_list['price']*$vs['goods_num'];
+
+ $vs['kill_atv_id'] = $kill_list['id'];
+
+ $kill_discount_price = $vs['kill_discount_price'] = $vs['all_price'] - $vs['true_price'];
+
+ }else{
+ //查询正在进行中的积分活动
+ $info = $integral_model->atvIng($vs['goods_id'],$vs['spe_id']);
+
+ if(!empty($info)){
+ //使用积分抵扣掉的钱
+ $integral_discount_price += $vs['all_price'] - $info['price']*$vs['goods_num'];
+ //使用积分
+ $integral += $info['integral']*$vs['goods_num'];
+ //使用积分抵扣
+ if($buy_limit==0||$no_i==0){
+
+ $vs['true_price'] = $info['price']*$vs['goods_num'];
+
+ $vs['integral_id'] = $info['atv_id'];
+
+ }
+ }
+ }
+
+ $vs['kill_price'] = !empty($kill_list)?$kill_list['price']:0;
+
+ $vs['kill_end_time'] = !empty($kill_list)?$kill_list['end_time']:0;
+
+ $vs['integral'] = !empty($info['integral'])?$info['integral']:0;
+
+ $vs['i_price'] = !empty($info['price'])?$info['price']:0;
+
+ $vs['total_integral_discount_price'] = !empty($info['price'])?$vs['all_price'] - $info['price']*$vs['goods_num']:0;
+
+ $vs['total_integral'] = !empty($info['integral'])?$info['integral']*$vs['goods_num']:0;
+
+ }
+
+ }
+ //总的数量
+ $data['all_count'] = array_sum(array_column($data['list'],'goods_num'));
+
+ if($is_car==0){
+
+ $list = $data['list'];
+ }
+ //拼接订单
+ $data['list'] = $this->getFarmerCar($data['list']);
+
+ $data['kill_atv_id'] = !empty($kill_list)?$kill_list['id']:0;
+
+ $data['kill_over_time'] = !empty($kill_list)?$kill_list['over_time']:0;
+ //积分抵扣
+ $data['integral'] = $integral;
+ //积分抵扣多少钱
+ $data['integral_discount_price'] = round($integral_discount_price,2);
+ //
+ $data['kill_discount_price'] = round($kill_discount_price,2);
+
+ $data['buy_limit'] = $buy_limit;
+
+ $data['discount_add'] = $discount_add;
+
+ if(!empty($list)){
+
+ $data['car_price'] = round(array_sum(array_column($list,'true_price')),2);
+ //原价
+ $data['init_price'] = round(array_sum(array_column($list,'all_price')),2);;
+ //选中的数量
+ $data['car_count'] = array_sum(array_column($list,'goods_num'));
+
+ }else{
+
+ $data['init_price'] = 0;
+
+ $data['car_price'] = 0;
+
+ $data['car_count'] = 0;
+
+ $data['all_count'] = 0;
+
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-23 11:26
+ * @功能说明:转换成农场格式
+ */
+ public function getFarmerCar($car){
+
+ $farmer_model = new Farmer();
+
+ $arr = [];
+
+ foreach ($car as $value){
+
+ $arr[$value['farmer_id']]['goods_list'][] = $value;
+
+ $arr[$value['farmer_id']]['farmer_id'] = $value['farmer_id'];
+
+ }
+
+ foreach ($arr as &$vs){
+
+ $vs['farmer_info']= $farmer_model->dataInfo(['id'=>$vs['farmer_id']],'title,lng,lat,uniacid');
+
+ $vs['car_price'] = round(array_sum(array_column($vs['goods_list'],'true_price')),2);
+ //原价
+ $vs['init_price'] = round(array_sum(array_column($vs['goods_list'],'all_price')),2);
+
+ $vs['integral'] = round(array_sum(array_column($vs['goods_list'],'total_integral')),2);
+
+ $vs['integral_discount_price'] = round(array_sum(array_column($vs['goods_list'],'total_integral_discount_price')),2);
+
+ $vs['kill_discount_price'] = round(array_sum(array_column($vs['goods_list'],'kill_discount_price')),2);
+ //运费
+ $vs['freight'] = 0;
+
+ $vs['coupon_discount'] = 0;
+
+ }
+
+ return array_values($arr);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 17:35
+ * @功能说明:购物车列表
+ */
+ public function carList($user_id,$store_id=0,$all=0,$is_show=1){
+
+ $dis = [
+
+ 'a.user_id' => $user_id,
+
+ 'b.status' => 1,
+
+ 'a.type' => 5,
+
+ 'a.is_show' => $is_show,
+
+ 'e.status' => 2
+ ];
+
+ if($all==0){
+
+ $dis['a.status'] = 1;
+ }
+
+ if(!empty($store_id)){
+
+ $dis['d.store_id']= $store_id;
+ }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_goods b','a.goods_id = b.id')
+ ->join('lbfarm_v2_shop_spe_price c','a.spe_id = c.id','left')
+ ->join('lbfarm_v2_goods_store d','a.goods_id = d.goods_id AND d.type=1')
+ ->join('lbfarm_farmer e','d.store_id = e.id')
+ ->where($dis)
+ ->field('a.id,c.spe_id_1,b.send_tmpl_id,b.sale_num,b.true_sale_num,e.id as farmer_id,a.status,a.uniacid,a.goods_num,b.goods_name,b.cover,c.price,ROUND(c.price*a.goods_num,2) as all_price,ROUND(c.price*a.goods_num,2) as true_price,a.spe_id,a.goods_id,b.weight*a.goods_num as total_weight')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+
+ $v['all_sale_num'] = $v['sale_num']+$v['true_sale_num'];
+
+ $pec_id = explode('-',$v['spe_id_1']);
+
+ $spe_name = Db::name('lbfarm_v2_shop_spe')->where(['status'=>1])->where('id','IN',$pec_id)->column('title');
+
+ $v['spe_name'] = implode('-',$spe_name);
+
+ }
+
+ }
+
+ return $data;
+
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Claim.php b/app/farm/model/Claim.php
new file mode 100755
index 0000000..19b42c4
--- /dev/null
+++ b/app/farm/model/Claim.php
@@ -0,0 +1,382 @@
+ 1,
+
+ 'a.goods_id' => $data['id'],
+
+ 'a.type' => 3,
+
+ 'b.type' => 2,
+ ];
+
+ $goods_cate_model = new GoodsCate();
+
+ $list = $goods_cate_model->alias('a')
+ ->join('lbfarm_land_cate b','a.cate_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title')
+ ->group('a.id')
+ ->order('a.id dsec')
+ ->column('b.id');
+
+
+ return array_values($list);
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-01-26 15:16
+ */
+ public function getTextAttr($value,$data){
+
+ if(!empty($value)){
+
+ return @unserialize($value);
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 10:50
+ * @功能说明:轮播图转格式
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-06 15:24
+ * @功能说明:周期
+ */
+ public function getCycleAttr($value,$data){
+
+ if(isset($data['start_time'])&&isset($data['end_time'])){
+
+ $day = ceil(($data['end_time']-$data['start_time'])/86400);
+
+ return $day;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $g_data = $data;
+
+ if(isset($data['process'])){
+
+ unset($data['process']);
+ }
+
+ if(isset($data['monitor'])){
+
+ unset($data['monitor']);
+ }
+
+ if(isset($data['cate_id'])){
+
+ unset($data['cate_id']);
+ }
+
+ if(!empty($data['imgs'])){
+
+ $data['imgs'] = implode(',',$data['imgs']);
+ }
+
+ if(!empty($data['text'])){
+
+ $data['text'] = serialize($data['text']);
+ }
+
+ $data['create_time'] = time();
+
+ $data['spec_list'] = json_encode($data['spec_list']);
+ $data['harvest_list'] = json_encode($data['harvest_list']);
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$g_data);
+
+
+ if (!empty($data['spec_list'])){
+ $claimSpecModel = new ClaimSpec();
+ $claimSpecModel->claimSpecUpdate($data['spec_list'],$id);
+ }
+
+ if (!empty($data['harvest_list'])){
+ $claimHarvestModel = new ClaimHarvest();
+ $claimHarvestModel->claimHarvestUpdate($data['harvest_list'],$id);
+ }
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $g_data = $data;
+
+ if(isset($data['process'])){
+
+ unset($data['process']);
+ }
+
+ if(isset($data['monitor'])){
+
+ unset($data['monitor']);
+ }
+
+ if(isset($data['cate_id'])){
+
+ unset($data['cate_id']);
+ }
+
+ if(!empty($data['imgs'])){
+
+ $data['imgs'] = implode(',',$data['imgs']);
+ }
+
+ if(!empty($data['text'])){
+
+ $data['text'] = serialize($data['text']);
+ }
+
+ if (!empty($data['spec_list'])){
+ Log::write($data);
+ $data['spec_list'] = json_encode($data['spec_list']);
+ }
+
+ if (!empty($data['harvest_list'])){
+ Log::write($data);
+ $data['harvest_list'] = json_encode($data['harvest_list']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($g_data['process'])||isset($g_data['monitor'])){
+
+ $this->updateSome($dis['id'],$g_data);
+ }
+ $info = $this->where($dis)->find();
+ if (!empty($data['spec_list'])){
+ $claimSpecModel = new ClaimSpec();
+
+ $claimSpecModel->claimSpecUpdate($data['spec_list'],$info['id']);
+ }
+
+
+ if (!empty($data['harvest_list'])){
+ $claimHarvestModel = new ClaimHarvest();
+ $claimHarvestModel->claimHarvestUpdate($data['harvest_list'],$info['id']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 15:45
+ * @功能说明:添加关联
+ */
+ public function updateSome($id,$data){
+
+ $server = new \app\farm\server\Claim();
+
+ $claim_text_model = new ClaimText();
+
+ $monitor_text_model= new MonitorText();
+
+ $goods_cate_model = new GoodsCate();
+
+ $server->addObserver($goods_cate_model);
+
+ $server->addObserver($claim_text_model);
+
+ $server->addObserver($monitor_text_model);
+
+ $server->notify($id,$data);
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function indexDataList($dis,$alh,$sort=1){
+
+ switch ($sort){
+
+ case 1:
+ $order = 'id desc';
+
+ break;
+
+ case 2:
+
+ $order = 'sale_num desc,id desc';
+
+ break;
+
+ case 3:
+
+ $order = 'distance asc,id desc';
+
+ break;
+
+ }
+
+ $data = $this->where($dis)->field(['*',$alh])->order($order)->paginate(10)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 14:00
+ * @功能说明:前端土地列表
+ */
+ public function indexDataListV2($dis,$alh,$sort=1){
+
+ switch ($sort){
+
+ case 1:
+ $order = 'a.top desc';
+
+ break;
+
+ case 2:
+
+ $order = 'a.sale_num desc,a.id desc';
+
+ break;
+
+ case 3:
+
+ $order = 'a.distance asc,a.id desc';
+
+ break;
+ }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_cate b','a.id = b.goods_id','left')
+ ->where($dis)
+ ->field(['a.*',$alh])
+ ->group('a.id')
+ ->order($order)
+ ->paginate(10)->each(function ($item){
+
+ $claimSpecModel = new ClaimSpec();
+ $item['spec_list'] = $claimSpecModel->getList($item['id']);
+
+ $claimHarvestModel = new ClaimHarvest();
+ $item['harvest_list'] = $claimHarvestModel->getList($item['id']);
+
+ return $item;
+ })->toArray();
+
+ return $data;
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ $claimSpecModel = new ClaimSpec();
+
+ $data['spec_list'] = $claimSpecModel->getList($data['id']);
+
+ $claimHarvestModel = new ClaimHarvest();
+
+ $data['harvest_list'] = $claimHarvestModel->getList($data['id']);
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/farm/model/ClaimCollage.php b/app/farm/model/ClaimCollage.php
new file mode 100755
index 0000000..a32598c
--- /dev/null
+++ b/app/farm/model/ClaimCollage.php
@@ -0,0 +1,142 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:33
+ * @功能说明:
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim b','a.claim_id = b.id','left')
+ ->where($dis)
+ ->field('a.*,b.title as claim_title,b.price as init_price,b.cover as claim_cover')
+ ->group('a.id')
+ ->order('a.top desc,a.id')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 10:33
+ * @功能说明:
+ */
+ public function getAtvInfo($atv_id,$claim_id){
+
+ $data = $this->dataInfo(['id'=>$atv_id,'claim_id'=>$claim_id]);
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 11:16
+ * @功能说明:
+ */
+ public function getAtvInfoIng($claim_id,$user_id=0){
+
+ $dis[] = ['claim_id','=',$claim_id];
+
+ $dis[] = ['start_time','<',time()];
+
+ $dis[] = ['end_time','>',time()];
+
+ $dis[] = ['status','=',1];
+
+ $data = $this->dataInfo($dis);
+
+ if(!empty($data)){
+
+ $collage_model = new CollageStart();
+
+ $data['can_start'] = $collage_model->startAtvCheck($user_id,$data['id']);
+ //是否还能发起该活动其他的拼团
+ $data['can_start'] = !empty($data['can_start']['code'])?0:1;
+ }
+
+ return $data;
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ClaimEarTag.php b/app/farm/model/ClaimEarTag.php
new file mode 100755
index 0000000..c648b7f
--- /dev/null
+++ b/app/farm/model/ClaimEarTag.php
@@ -0,0 +1,43 @@
+where($where)->paginate(10)->toArray();
+ }
+ public function deleteEatTag($id){
+
+ return $this->where('id',$id)->delete();
+ }
+ public function addTag($data){
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+ return $id;
+ }
+ public function updateTag($data,$id){
+
+ $res = $this->where('id',$id)->update($data);
+ return $res;
+ }
+
+
+
+ public function getTagInfo($id){
+ return $this->find($id);
+ }
+
+}
diff --git a/app/farm/model/ClaimEarTagLog.php b/app/farm/model/ClaimEarTagLog.php
new file mode 100755
index 0000000..bea2b98
--- /dev/null
+++ b/app/farm/model/ClaimEarTagLog.php
@@ -0,0 +1,29 @@
+where($where)->order('id desc')->paginate(10)->toArray();
+ }
+
+ public function addTagLog($data){
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+ return $id;
+ }
+
+}
diff --git a/app/farm/model/ClaimHarvest.php b/app/farm/model/ClaimHarvest.php
new file mode 100755
index 0000000..5a6ac40
--- /dev/null
+++ b/app/farm/model/ClaimHarvest.php
@@ -0,0 +1,46 @@
+where(['claim_id'=>$claim_id])->select();
+ }
+
+ public function claimHarvestUpdate($claimSpecList,$claim_id){
+
+ $ids = [];
+
+ $claimSpecList = json_decode($claimSpecList,true);
+
+ Log::write($claimSpecList);
+ Log::write('11--');
+ foreach ($claimSpecList as $item) {
+ $info = $this->where(['id'=>$item['id']])->find();
+ if (!$info){
+ $info = new ClaimHarvest();
+ $info['claim_id'] = $claim_id;
+ }
+ $info['harvest_name'] = $item['harvest_name'];
+ $info['harvest'] = $item['harvest'];
+ $info->save();
+ array_push($ids,$info['id']);
+ }
+
+ $this->whereNotIn('id',$ids)->where('claim_id',$claim_id)->delete();
+
+ }
+
+ public function getSpecInfo($spec_id){
+ return $this->find($spec_id);
+ }
+
+}
diff --git a/app/farm/model/ClaimOrder.php b/app/farm/model/ClaimOrder.php
new file mode 100755
index 0000000..b77867f
--- /dev/null
+++ b/app/farm/model/ClaimOrder.php
@@ -0,0 +1,554 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis, $data)
+ {
+
+ $res = $this->where($dis)->update($data);;
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 15:45
+ * @功能说明:添加关联
+ */
+ public function updateSome($id, $data)
+ {
+
+ $server = new \app\farm\server\Claim();
+
+ $claim_text_model = new ClaimText();
+
+ $source_text_model = new LandSourceText();
+
+ $monitor_text_model = new MonitorText();
+
+ $server->addObserver($claim_text_model);
+
+ $server->addObserver($source_text_model);
+
+ $server->addObserver($monitor_text_model);
+
+ $server->notify($id, $data);
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis, $page = 10)
+ {
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis)
+ {
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data) ? $data->toArray() : [];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 15:39
+ * @功能说明:回调
+ */
+ public function orderResult($order_code, $transaction_id)
+ {
+
+ $order = $this->dataInfo(['order_code' => $order_code]);
+
+ if (!empty($order) && $order['pay_type'] == 1) {
+
+ $update = [
+
+ 'pay_time' => time(),
+
+ 'pay_type' => 2,
+
+ 'transaction_id' => $transaction_id
+ ];
+
+ Db::startTrans();
+
+ $this->dataUpdate(['id' => $order['id']], $update);
+ //扣除余额
+ if ($order['balance'] > 0) {
+
+ $water_model = new BalanceWater();
+
+ $res = $water_model->addWater($order, 2, 0);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ }
+ }
+ //添加流水
+ $water_model = new FinanceWater();
+
+ $water_model->addWater($order['id'], 1, 1, 1);
+
+ $integral_model = new IntegralLog();
+ //增加佣金
+ $integral_model->integralUserAdd($order['user_id'], $order['get_integral'], $order['uniacid'], 2, 5, $order['id'], 0, $order);
+ //分销
+ $cash_model = new DistributionCash();
+ //增加分销激励
+ $cash_model->addUserCash($order, 3);
+ //分销到账
+ $cash_model->cashArrival($order, 3);
+
+ $collage_model = new CollageStart();
+ //拼团
+ $collage_model->atvResult($order['id']);
+
+ Db::commit();
+
+ $sys_model = new PushMsgModel($order['uniacid']);
+
+ $sys_model->sendMsg($order, 8);
+
+ $sys_model->sendMsg($order, 10);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:超时自动退款
+ */
+ public function autoCancelOrder($uniacid, $user_id = 0)
+ {
+
+ $dis[] = ['uniacid', '=', $uniacid];
+
+ $dis[] = ['pay_type', '=', 1];
+
+ $dis[] = ['over_time', '<', time()];
+
+ if (!empty($user_id)) {
+
+ $dis[] = ['user_id', '=', $user_id];
+ }
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if (!empty($order)) {
+
+ foreach ($order as $value) {
+
+ $this->cancelOrder($value);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:退款
+ */
+ public function cancelOrder($order, $refund = 1, $payConfig = [])
+ {
+
+ Db::startTrans();
+
+ if ($refund == 2) {
+
+ $res = $this->refundCash($payConfig, $order);
+
+ if ($res != true) {
+
+ Db::rollback();
+
+ return ['code' => 500, 'msg' => '退款失败'];
+ }
+
+ } else {
+ //取消订单
+ $collage_model = new CollageStart();
+
+ $collage_model->cancelOrderAtvFail($order['id']);
+
+ }
+
+ $res = $this->dataUpdate(['id' => $order['id'], 'pay_type' => $refund], ['pay_type' => -1, 'cancel_time' => time(), 'ear_tag' => null, 'ear_tag_code' => null]);
+
+ if ($res != 1) {
+
+ Db::rollback();
+
+ return ['code' => 500, 'msg' => '取消失败'];
+ }
+
+ $claim_model = new Claim();
+
+ $claim = $claim_model->dataInfo(['id' => $order['goods_id']]);
+ //加销量减库存
+ $update = [
+
+ 'stock' => $claim['stock'] + $order['num'],
+
+ 'sale_num' => $claim['sale_num'] - $order['num'],
+
+ 'lock' => $claim['lock'] + 1
+
+ ];
+
+ $res = $claim_model->dataUpdate(['id' => $claim['id'], 'lock' => $claim['lock']], $update);
+
+ if ($res == 0) {
+
+ Db::rollback();
+
+ return ['code' => 500, 'msg' => '取消失败'];
+
+ }
+
+ $specInfo = ClaimSpec::find($order['spec_id']);
+ if ($specInfo) {
+ $specInfo['stock'] = $specInfo['stock'] + $order['num'];
+ $specInfo->save();
+ }
+
+ $earInfo = ClaimEarTag::find($order['ear_tag']);
+ if ($earInfo) {
+ $earInfo['status'] = 0;
+ $earInfo->save();
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 13:53
+ * @功能说明:退钱
+ */
+ public function refundCash($payConfig, $pay_order)
+ {
+
+ if ($pay_order['pay_price'] <= 0) {
+
+ return true;
+ }
+
+ $water_model = new FinanceWater();
+
+ $water_model->addWater($pay_order['id'], 2, 1, 1);
+
+ if ($pay_order['pay_model'] == 1) {
+ //微信退款
+ $response = orderRefundApi($payConfig, $pay_order['pay_price'], $pay_order['pay_price'], $pay_order['transaction_id']);
+ //如果退款成功修改一下状态
+ if (isset($response['return_code']) && isset($response['result_code']) && $response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS') {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no']) ? $response['out_refund_no'] : $pay_order['order_code'];
+
+ $this->dataUpdate(['id' => $pay_order['id']], ['out_refund_no' => $response['out_refund_no']]);
+
+ } else {
+ //失败就报错
+ $discption = !empty($response['err_code_des']) ? $response['err_code_des'] : $response['return_msg'];
+
+ return ['code' => 500, 'msg' => $discption];
+
+ }
+
+ } elseif ($pay_order['pay_model'] == 2) {
+
+ $data = [
+
+ 'user_id' => $pay_order['user_id'],
+
+ 'pay_price' => $pay_order['pay_price'],
+
+ 'id' => $pay_order['id'],
+
+ 'uniacid' => $pay_order['uniacid']
+ ];
+
+ $water_model = new \app\farm\model\BalanceWater();
+
+ $res = $water_model->addWater($data, 13, 1);
+
+ if ($res == 0) {
+
+ return false;
+
+ }
+
+ } else {
+ //支付宝
+ $pay_model = new PayModel($payConfig);
+
+ $res = $pay_model->aliRefund($pay_order['transaction_id'], $pay_order['pay_price']);
+
+ if (isset($res['alipay_trade_refund_response']['code']) && $res['alipay_trade_refund_response']['code'] == 10000) {
+
+ $this->dataUpdate(['id' => $pay_order['id']], ['out_refund_no' => $res['alipay_trade_refund_response']['out_trade_no']]);
+
+ } else {
+
+ return ['code' => 500, 'msg' => $res['alipay_trade_refund_response']['sub_msg']];
+
+ }
+
+ }
+
+ return true;
+ }
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:后台下单列表
+ * @author chenniang
+ * @DataTime: 2022-02-16 14:05
+ */
+ public function adminDataList($dis, $page = 10)
+ {
+
+ $data = $this->alias('a')
+ ->join('lbfarm_order_address b', 'a.id = b.order_id AND b.type=2', 'left')
+ ->where($dis)
+ ->field('a.*,b.user_name,b.mobile')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:后台下单列表
+ * @author chenniang
+ * @DataTime: 2022-02-16 14:05
+ */
+ public function adminDataSelect($dis, $page = 10)
+ {
+
+ $data = $this->alias('a')
+ ->join('lbfarm_order_address b', 'a.id = b.order_id AND b.type=2', 'left')
+ ->where($dis)
+ ->field('a.*,b.user_name,b.mobile')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-24 16:46
+ * @功能说明:预支付信息
+ */
+ public function payOrderInfo($input, $is_err = 0)
+ {
+
+ $claim_model = new Claim();
+
+ $data = $claim_model->dataInfo(['id' => $input['claim_id'], 'status' => 1]);
+
+ $input['num'] = !empty($input['num']) ? $input['num'] : 1;
+
+ $specModel = new ClaimSpec();
+
+ $specInfo = $specModel->getSpecInfo($input['spec_id']);
+ $data['stock'] = $specInfo['stock'];
+ $data['price'] = $specInfo['price'];
+
+
+ if (empty($data)) {
+
+ return ['code' => 500, 'msg' => '该产品已下架'];
+ }
+
+ if ($data['stock'] < $input['num'] && $is_err == 1) {
+
+ return ['code' => 500, 'msg' => '该产品库存不足'];
+ }
+
+ if ($data['end_time'] < time() && $is_err == 1) {
+
+ return ['code' => 500, 'msg' => '该产品认养期已结束'];
+
+ }
+
+ $data['pay_price'] = round($data['price'] * $input['num'], 2);
+
+ $pay_price = $data['init_price'] = $data['pay_price'];
+
+ if (!empty($input['coupon_id']) && empty($input['collage_start_id'])) {
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon = $coupon_record_model->dataInfo(['id' => $input['coupon_id'], 'is_claim' => 1, 'status' => 1]);
+
+ if (!empty($coupon) && $coupon['full'] <= $data['pay_price']) {
+
+ $data['pay_price'] -= $coupon['discount'];
+
+ } else {
+
+ $coupon = [];
+ }
+
+ }
+ //发起拼团
+ if (!empty($input['collage_start_id'])) {
+
+ $collage_model = new ClaimCollage();
+
+ $data['collage_start_data'] = $collage_model->getAtvInfo($input['collage_start_id'], $input['claim_id']);
+
+ if (!empty($data['collage_start_data'])) {
+
+ $data['pay_price'] = $data['collage_start_data']['price'];
+ }
+ //参与拼团
+ } elseif (!empty($input['collage_join_id'])) {
+
+ $collage_model = new CollageStart();
+
+ $data['collage_join_data'] = $collage_model->getAtvInfo($input['collage_join_id'], $input['claim_id']);
+
+ if (!empty($data['collage_join_data'])) {
+
+ $data['pay_price'] = $data['collage_join_data']['price'];
+ }
+
+ }
+
+ $data['pay_price'] = $data['pay_price'] > 0 ? $data['pay_price'] : 0;
+
+ $data['pay_price'] = round($data['pay_price'], 2);
+
+ $data['coupon_discount'] = !empty($coupon) ? $coupon['discount'] : 0;
+
+ $data['coupon_discount'] = $data['coupon_discount'] < $pay_price ? $data['coupon_discount'] : $pay_price;
+
+ $data['coupon_discount'] = round($data['coupon_discount'], 2);
+
+ $data['coupon_id'] = !empty($coupon) ? $coupon['id'] : 0;
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-09 17:45
+ * @功能说明:认养发送可配送提醒
+ */
+ public function claimSendNotice($uniacid)
+ {
+
+ $push_model = new PushMsgModel($uniacid);
+
+ $dis[] = ['pay_type', '>', 1];
+
+ $dis[] = ['have_notice', '=', 0];
+
+ $dis[] = ['end_time', '<', time()];
+
+ $list = $this->where($dis)->select()->toArray();
+
+ if (!empty($list)) {
+
+ foreach ($list as $value) {
+
+ $this->dataUpdate(['id' => $value['id']], ['have_notice' => 1]);
+
+ $push_model->sendMsg($value, 7);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+}
diff --git a/app/farm/model/ClaimSpec.php b/app/farm/model/ClaimSpec.php
new file mode 100755
index 0000000..1fcf22c
--- /dev/null
+++ b/app/farm/model/ClaimSpec.php
@@ -0,0 +1,47 @@
+where(['claim_id'=>$claim_id])->select();
+ }
+
+ public function claimSpecUpdate($claimSpecList,$claim_id){
+
+ $ids = [];
+
+ $claimSpecList = json_decode($claimSpecList,true);
+
+ Log::write($claimSpecList);
+ Log::write('11--');
+ foreach ($claimSpecList as $item) {
+ $info = $this->where(['id'=>$item['id']])->find();
+ if (!$info){
+ $info = new ClaimSpec();
+ $info['claim_id'] = $claim_id;
+ }
+ $info['spec_name'] = $item['spec_name'];
+ $info['price'] = $item['price'];
+ $info['stock'] = $item['stock'];
+ $info->save();
+ array_push($ids,$info['id']);
+ }
+
+ $this->whereNotIn('id',$ids)->where('claim_id',$claim_id)->delete();
+
+ }
+
+ public function getSpecInfo($spec_id){
+ return $this->find($spec_id);
+ }
+
+}
diff --git a/app/farm/model/ClaimText.php b/app/farm/model/ClaimText.php
new file mode 100755
index 0000000..2cae857
--- /dev/null
+++ b/app/farm/model/ClaimText.php
@@ -0,0 +1,103 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:07
+ * @功能说明:
+ */
+ public function eventClaim($id,$data){
+
+ $this->where(['claim_id'=>$id])->delete();
+
+ if(!empty($data['process'])){
+
+ foreach ($data['process'] as $k => $v){
+
+ $v['uniacid'] = $data['uniacid'];
+
+ $v['claim_id']= $id;
+
+ $this->insert($v);
+
+ }
+
+ }
+
+ return true;
+
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ClaimTraceability.php b/app/farm/model/ClaimTraceability.php
new file mode 100755
index 0000000..8a36c0d
--- /dev/null
+++ b/app/farm/model/ClaimTraceability.php
@@ -0,0 +1,87 @@
+where($where)->paginate(10)->each(function ($item) {
+ $ClaimTraceabilityOperationModel = new ClaimTraceabilityOperation();
+ $item['operations'] = $ClaimTraceabilityOperationModel->getList();
+ return $item;
+ })->toArray();
+ }
+
+ public function deleteTraceability($id)
+ {
+ $ClaimTraceabilityOperationModel = new ClaimTraceabilityOperation();
+ $ClaimTraceabilityOperationModel->where('traceability_id', $id)->delete();
+ return $this->where('id', $id)->delete();
+ }
+
+ public function addTraceability($data)
+ {
+ $data['traceability_operation'] = json_encode($data['traceability_operation']);
+
+ $number = 'TR' . date('Ymd') . rand(1000, 9999);
+ $data['traceability_code'] = $number;
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+ $operationids = [];
+ foreach (json_decode($data['traceability_operation'], true) as $v) {
+ $v['traceability_id'] = $id;
+ $ClaimTraceabilityOperationModel = new ClaimTraceabilityOperation();
+ if ($v['id']) {
+ $ClaimTraceabilityOperationModel->where('id', $v['id'])->update($v);
+ } else {
+ $v['id'] = $ClaimTraceabilityOperationModel->addData($v);
+ }
+ array_push($operationids, $v['id']);
+ }
+ $ClaimTraceabilityOperationModel->whereNotIn('id', $operationids)
+ ->where('traceability_id', $id)->delete();
+
+ return $id;
+ }
+
+ public function updateTraceability($data, $id)
+ {
+ $data['traceability_operation'] = json_encode($data['traceability_operation']);
+ $res = $this->where('id', $id)->update($data);
+
+ $operationids = [];
+ $ClaimTraceabilityOperationModel = new ClaimTraceabilityOperation();
+
+ foreach (json_decode($data['traceability_operation'], true) as $v) {
+ $v['traceability_id'] = $id;
+ if ($v['id']) {
+ $ClaimTraceabilityOperationModel->where('id', $v['id'])->update($v);
+ } else {
+ $v['id'] = $ClaimTraceabilityOperationModel->addData($v);
+ }
+ array_push($operationids, $v['id']);
+ }
+ $ClaimTraceabilityOperationModel->whereNotIn('id', $operationids)
+ ->where('traceability_id', $id)->delete();
+
+ return $res;
+ }
+
+}
diff --git a/app/farm/model/ClaimTraceabilityOperation.php b/app/farm/model/ClaimTraceabilityOperation.php
new file mode 100755
index 0000000..193c635
--- /dev/null
+++ b/app/farm/model/ClaimTraceabilityOperation.php
@@ -0,0 +1,38 @@
+select();
+ }
+
+ public function deleteData($traceability_id)
+ {
+ return $this->where('traceability_id', $traceability_id)->delete();
+ }
+
+ public function addData($data)
+ {
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+ return $id;
+ }
+
+ public function updateDatas($data, $id)
+ {
+
+ $res = $this->where('id', $id)->update($data);
+ return $res;
+ }
+
+}
diff --git a/app/farm/model/CollageJoin.php b/app/farm/model/CollageJoin.php
new file mode 100755
index 0000000..c05ed1c
--- /dev/null
+++ b/app/farm/model/CollageJoin.php
@@ -0,0 +1,354 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:33
+ * @功能说明:
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim b','a.claim_id = b.id','left')
+ ->where($dis)
+ ->field('a.*,b.title as claim_title')
+ ->group('a.id')
+ ->order('a.top desc,a.id')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 15:25
+ * @功能说明:用户拼团记录
+ */
+ public function userCollageLimit($dis,$limit=3){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim b','a.claim_id = b.id','left')
+ ->join('lbfarm_v2_claim_collage_start c','a.start_id = c.id','left')
+ ->where($dis)
+ ->field('a.*,b.title as claim_title,b.cover as claim_cover,c.end_time,c.success_num,c.have_order_num as have_num')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->limit($limit)
+ ->select()
+ ->toArray();
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+
+ $v['surplus_num'] = ($v['success_num'] - $v['have_num'])>0?$v['success_num'] - $v['have_num']:0;
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 14:50
+ * @功能说明:用户参与拼团的次数
+ */
+ public function userCollageCount($user_id){
+
+ $dis[] = ['a.user_id','=',$user_id];
+
+ $dis[] = ['a.status','>=',1];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim b','a.claim_id = b.id','left')
+ ->join('lbfarm_v2_claim_collage_start c','a.start_id = c.id','left')
+ ->where($dis)
+ ->field('a.*,b.title as claim_title,b.cover as claim_cover,c.end_time,c.success_num')
+ ->group('a.id')
+ ->count();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 15:25
+ * @功能说明:用户拼团记录
+ */
+ public function userCollagePage($dis,$limit=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim b','a.claim_id = b.id','left')
+ ->join('lbfarm_v2_claim_collage_start c','a.start_id = c.id','left')
+ ->where($dis)
+ ->field('a.*,b.title as claim_title,b.cover as claim_cover,c.end_time,c.success_num')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($limit)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['user_avatar'] = $this->collageUserAvatar($v['start_id'],4);
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 18:06
+ * @功能说明:拼团用户头像
+ */
+ public function collageUserAvatar($id,$limit=5){
+
+ $dis[] = ['a.start_id','=',$id];
+
+ $dis[] = ['a.status','>=',1];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_user_list b','a.user_id = b.id','left')
+ ->where($dis)
+ ->limit($limit)
+ ->column('b.avatarUrl');
+
+ return array_values($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-17 16:25
+ * @功能说明:参与拼团
+ */
+ public function joinCollage($order,$data,$is_start){
+
+ $collage_model = new ClaimCollage();
+
+ if(empty($data)||$data['end_time']500,'msg'=>'拼团已经结束'];
+
+ }
+
+ $collage = $collage_model->dataInfo(['id'=>$data['atv_id']]);
+
+ if(empty($collage)){
+
+ return ['code'=>500,'msg'=>'拼团已经结束'];
+
+ }
+
+ $dis = [
+
+ 'user_id' => $order['user_id'],
+
+ 'atv_id' => $data['atv_id'],
+
+ 'is_start'=> 0
+ ];
+ //校验参与次数
+ $count = $this->where($dis)->where('status','>',-1)->count();
+
+ if($collage['join_times']<=$count){
+
+ return ['code'=>500,'msg'=>'拼团超过参与次数'];
+ }
+
+ $dis = [
+
+ 'start_id' => $data['id']
+ ];
+
+ if($data['have_num']>=$data['success_num']){
+
+ return ['code'=>500,'msg'=>'超过拼团人数'];
+
+ }
+ //校验库存
+ $num = $this->where($dis)->where('status','>',-1)->sum('num');
+
+ if($num>=$collage['stock']){
+
+ return ['code'=>500,'msg'=>'超过活动库存'];
+
+ }
+
+ $dis['user_id'] = $order['user_id'];
+
+ $find = $this->where($dis)->where('status','>',-1)->find();
+
+ if(!empty($find)){
+
+ return ['code'=>500,'msg'=>'你已经参加过改拼团了'];
+ }
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'claim_id'=> $order['claim_id'],
+
+ 'price' => $collage['price'],
+
+ 'status' => 0,
+
+ 'order_id'=> $order['id'],
+
+ 'num' => $order['num'],
+
+ 'atv_id' => $data['atv_id'],
+
+ 'start_id'=> $data['id'],
+
+ 'is_start'=> $is_start,
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ $start_model = new CollageStart();
+
+ $start_model->where(['id'=>$data['id']])->update(['have_order_num'=>Db::Raw('have_order_num+1')]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 17:23
+ * @功能说明:用户是否还能参加该拼团
+ */
+ public function collageCanJoin($user_id,$start_id){
+
+ $find = $this->where(['user_id'=>$user_id,'start_id'=>$start_id])->where('status','in',[0,1,2])->find();
+
+ if(!empty($find)){
+
+ return 0;
+ }
+
+ $collage_model = new ClaimCollage();
+
+ $dis = [
+
+ 'b.id' => $start_id
+ ];
+
+ $data = $collage_model->alias('a')
+ ->join('lbfarm_v2_claim_collage_start b','a.id = b.atv_id')
+ ->where($dis)
+ ->field('b.atv_id,a.join_times')
+ ->find();
+
+ if(!empty($data)){
+
+ $data = $data->toArray();
+
+ $count = $this->where(['user_id'=>$user_id,'atv_id'=>$data['atv_id']])->where('status','in',[0,1,2])->count();
+
+ if($data['join_times']<=$count){
+
+ return 0;
+ }
+
+ }
+
+ return 1;
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/CollageStart.php b/app/farm/model/CollageStart.php
new file mode 100755
index 0000000..bb7864a
--- /dev/null
+++ b/app/farm/model/CollageStart.php
@@ -0,0 +1,450 @@
+=0?$data['success_num']-$data['have_num']:0;
+ }
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-01 15:33
+ * @功能说明:
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim b','a.claim_id = b.id','left')
+ ->where($dis)
+ ->field('a.*,b.title as claim_title')
+ ->group('a.id')
+ ->order('a.top desc,a.id')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 17:19
+ * @功能说明:认养拼团商品
+ */
+ public function claimCollageLimit($claim_id,$limit=3,$user_id=0){
+
+ $dis[] = ['end_time','>',time()];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['claim_id','=',$claim_id];
+
+ $data = $this->where($dis)->order('id desc')->limit($limit)->select()->toArray();
+
+ $user_model = new User();
+
+ $collage_model = new CollageJoin();
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+
+ $v['user_info'] = $user_model->dataInfo(['id'=>$v['user_id']],'nickName,avatarUrl');
+ //是否能参与拼团
+ $v['can_join'] = $collage_model->collageCanJoin($user_id,$v['id']);
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-16 17:19
+ * @功能说明:认养拼团商品
+ */
+ public function claimCollageList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ $user_model = new User();
+
+ $collage_model = new CollageJoin();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['user_info'] = $user_model->dataInfo(['id'=>$v['user_id']],'nickName,avatarUrl');
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-17 16:25
+ * @功能说明:发起拼团
+ */
+ public function startCollage($order,$atv){
+
+ $check = $this->startAtvCheck($order['user_id'],$atv['id']);
+
+ if(!empty($check['code'])){
+
+ return $check;
+ }
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'claim_id'=> $order['claim_id'],
+
+ 'end_time'=> time()+$atv['success_time']*60,
+
+ 'price' => $atv['price'],
+
+ 'success_num'=> $atv['success_num'],
+
+ 'status' => 0,
+
+ 'order_id'=> $order['id'],
+
+ 'atv_id' => $atv['id'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ $id = $this->getLastInsID();
+
+ $data= $this->dataInfo(['id'=>$id]);
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 10:33
+ * @功能说明:
+ */
+ public function getAtvInfo($atv_id,$claim_id){
+
+ $data = $this->dataInfo(['id'=>$atv_id,'claim_id'=>$claim_id]);
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 11:45
+ * @功能说明:活动回调
+ */
+ public function atvResult($order_id){
+
+ $join_model = new CollageJoin();
+
+ $data = $join_model->dataInfo(['order_id'=>$order_id]);
+
+ if(!empty($data)){
+
+ $this->dataUpdate(['order_id'=>$order_id,'status'=>0],['status'=>1]);
+
+ $join_model->dataUpdate(['order_id'=>$order_id,'status'=>0],['status'=>1]);
+
+ $this->where(['id'=>$data['id']])->update(['have_num'=>Db::Raw('have_num+1')]);
+
+ $this->atvSuccess($data['start_id']);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 11:47
+ * @功能说明:拼团活动成功
+ */
+ public function atvSuccess($id){
+
+ $data = $this->dataInfo(['id'=>$id,'status'=>1]);
+
+ if(!empty($data)){
+
+ $join_model = new CollageJoin();
+
+ $count = $join_model->where(['start_id'=>$id,'status'=>1])->count();
+
+ if($count>=$data['success_num']){
+
+ $this->dataUpdate(['id'=>$id],['status'=>2,'success_times'=>time()]);
+
+ $join_model->dataUpdate(['start_id'=>$id,'status'=>1],['status'=>2]);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 14:24
+ * @功能说明:取消订单
+ */
+ public function cancelOrderAtvFail($order_id){
+
+ $this->dataUpdate(['order_id'=>$order_id],['status'=>-1]);
+
+ $this->where(['order_id'=>$order_id])->update(['have_order_num'=>Db::Raw('have_order_num+1')]);
+
+ $join_model = new CollageJoin();
+
+ $join_model->dataUpdate(['order_id'=>$order_id],['status'=>-1]);
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 13:41
+ * @功能说明:活动失效
+ */
+ public function initAtv($payConfig){
+
+ $dis[] = ['end_time','<',time()];
+
+ $dis[] = ['status','=',1];
+
+ $list = $this->where($dis)->select()->toArray();
+
+ $join_model = new CollageJoin();
+
+ $order_model= new ClaimOrder();
+
+ if(!empty($list)){
+
+ foreach ($list as $value){
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$value['id']],['status'=>3]);
+
+ if($res!=0){
+
+ $data = $join_model->where(['status'=>1,'start_id'=>$value['id']])->select()->toArray();
+
+ $join_model->dataUpdate(['status'=>1,'start_id'=>$value['id']],['status'=>3]);
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $order = $order_model->dataInfo(['id'=>$v['order_id'],'pay_type'=>2]);
+
+ if(!empty($order)){
+ //订单退款
+ $order_model->cancelOrder($order,2,$payConfig);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ Db::commit();
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-18 15:47
+ * @功能说明:发起开团审核
+ */
+ public function startAtvCheck($user_id,$atv_id){
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'atv_id' => $atv_id
+ ];
+
+ $count = $this->where($dis)->where('status','in',[0,1])->count();
+
+ if(!empty($count)){
+
+ return ['code'=>500,'msg'=>'你有正在进行中或未付款的团'];
+ }
+
+ $collage_model = new ClaimCollage();
+
+ $data = $collage_model->dataInfo(['id'=>$atv_id,'status'=>1]);
+
+ if(empty($data)||$data['end_time']500,'msg'=>'活动已经结束'];
+
+ }
+
+ if($count>=$data['start_times']){
+
+ return ['code'=>500,'msg'=>'超过发起拼团次数'];
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $user_id
+ * @功能说明:获取用户正在发起中的拼团
+ * @author chenniang
+ * @DataTime: 2022-08-18 16:52
+ */
+ public function userCollageIngData($user_id,$claim_id){
+
+ $data = $this->dataInfo(['user_id'=>$user_id,'status'=>1,'claim_id'=>$claim_id]);
+
+ $collage_model = new CollageJoin();
+
+ if(!empty($data)){
+
+ $data['user_avatar'] = $collage_model->collageUserAvatar($data['id'],4);
+ }
+
+ return $data;
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Config.php b/app/farm/model/Config.php
new file mode 100755
index 0000000..d1ef679
--- /dev/null
+++ b/app/farm/model/Config.php
@@ -0,0 +1,462 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 14:12
+ * @功能说明:获取运费
+ */
+ public function getSendPrice($distance,$uniacid){
+
+ $config = $this->dataInfo(['uniacid'=>$uniacid]);
+
+ $y_distance = $distance - $config['start_distance'];
+
+ if($y_distance<0){
+
+ return $config['start_price'];
+
+ }else{
+
+ // return round($config['start_price']+$y_distance/$config['renew_distance']*$config['renew_price'],2);
+ return 0;
+ }
+
+ }
+
+
+ /**
+ * @param $address_id
+ * @param $goods_list
+ * @param int $type
+ * @功能说明:计算运费
+ * @author chenniang
+ * @DataTime: 2022-08-08 17:35
+ */
+ public function getTotalSendPrice($address_id,$goods_list,$type=1){
+
+ $address_model = new Address();
+
+ $address = $address_model->dataInfo(['id'=>$address_id]);
+
+ if(empty($address)){
+
+ return $type==1?0:['code'=>500,'msg'=>'地址信息错误'];
+ }
+
+ $frist_price = $frist_id = $addprice = 0;
+
+ if(!empty($goods_list)){
+
+ foreach ($goods_list as &$goods_info){
+ //获取
+ $tmpl_data = $this->getSendTmp($goods_info['send_tmpl_id'],$address,$type);
+
+ if((!empty($tmpl_data['code'])&&$tmpl_data['code']==500)||empty($tmpl_data)){
+
+ return $tmpl_data;
+ }
+
+ $tmpl = $tmpl_data['tmpl'];
+ //找到首费最大的模版
+ if($tmpl['start_price']>$frist_price){
+
+ $frist_price = $tmpl['start_price'];
+
+ $frist_id = $tmpl['id'];
+ }
+ //获取有多少个模版
+ if(empty($tmpl_arr[$tmpl['id']])){
+
+ $tmpl_arr[$tmpl['id']] = $tmpl;
+ }
+
+ $tmpl_unit = !empty($tmpl_arr[$tmpl['id']]['tmpl_unit'])?$tmpl_arr[$tmpl['id']]['tmpl_unit']:0;
+
+ $unit = $tmpl_data['type']==1?$goods_info['goods_num']:$goods_info['total_weight'];
+ //计算每个模版的重量或者件数
+ $tmpl_arr[$tmpl['id']]['tmpl_unit'] = $tmpl_unit+$unit;
+
+ }
+
+ foreach ($tmpl_arr as $tmpl){
+
+ if($tmpl['id']==$frist_id){
+ //1按件数 2按重量
+ $add_num = ($tmpl['tmpl_unit'] - $tmpl['start_num'])>0?$tmpl['tmpl_unit'] - $tmpl['start_num']:0;
+
+ }else{
+
+ $add_num = $tmpl['tmpl_unit'];
+
+ }
+
+ $add_num = $tmpl['add_num']>0?ceil($add_num/$tmpl['add_num']):0;
+
+ $price = $add_num*$tmpl['add_price'];
+
+ $addprice += $price;
+
+ // dump($addprice,$frist_price);exit;
+
+ }
+
+ }
+
+ // dump($addprice,$frist_price);exit;
+ return round($addprice+$frist_price,2);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-09 13:50
+ * @功能说明:获取模版
+ */
+ public function getSendTmp($send_tmpl_id,$address,$type){
+
+ $tmpl_model = new FreightTemplate();
+
+ $tmpl = $tmpl_model->dataInfo(['id'=>$send_tmpl_id]);
+
+ if(empty($tmpl)){
+
+ return $type==1?0:['code'=>500,'msg'=>'商品未管理模版'];
+ }
+
+ if(!empty($tmpl['config'])){
+
+ foreach ($tmpl['config'] as $value){
+
+ if(in_array($address['province'],$value['province'])){
+
+ $tmpl['tmpl'] = $value;
+
+ return $tmpl;
+
+ }
+
+ }
+
+ return $type==1?0:['code'=>500,'msg'=>'地址未在配送范围内'];
+
+ }else{
+
+ return $type==1?0:['code'=>500,'msg'=>'地址未在配送范围内'];
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 17:51
+ * @功能说明:获取商品运费信息
+ */
+ public function getGoodsSendPrice($address_id,$goods_info,$type=1,$data=1){
+
+ $tmpl_model = new FreightTemplate();
+
+ $address_model = new Address();
+
+ $tmpl = $tmpl_model->dataInfo(['id'=>$goods_info['send_tmpl_id']]);
+
+ if(empty($tmpl)){
+
+ return $type==1?0:['code'=>500,'msg'=>'商品未管理模版'];
+ }
+
+ $address = $address_model->dataInfo(['id'=>$address_id]);
+
+ if(empty($address)){
+
+ return $type==1?0:['code'=>500,'msg'=>'地址信息错误'];
+ }
+
+ if(!empty($tmpl['config'])){
+
+ foreach ($tmpl['config'] as $value){
+
+ if(in_array($address['province'],$value['province'])){
+ //1按件数 2按重量
+ $unit = $tmpl['type']==1?$goods_info['goods_num']:$goods_info['total_weight'];
+
+ $add_num = ($unit - $value['start_num'])>0?$unit - $value['start_num']:0;
+
+ $add_num = $value['add_num']>0?ceil($add_num/$value['add_num']):0;
+
+ $price = round($value['start_price']+$add_num*$value['add_price'],2);
+
+ if($data==1){
+
+ return $price;
+
+ }else{
+
+ return ['price'=>$price,'type'=>$tmpl['type']];
+
+ }
+
+ }
+
+ }
+
+ return $type==1?0:['code'=>500,'msg'=>'地址未在配送范围内'];
+
+ }else{
+
+ return $type==1?0:['code'=>500,'msg'=>'地址未在配送范围内'];
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 10:58
+ * @功能说明:获取天气情况,默认甘孜
+ */
+ public function getWeather($uniacid,$lat='30.04932',$lang='101.9625'){
+
+ $config = $this->dataInfo(['uniacid'=>$uniacid]);
+
+ $key = $lat.'-'.$lang;
+
+ $weather = getCache($key,$this->_uniacid);
+
+ if(empty($weather)){
+
+ $url = 'https://apis.map.qq.com/ws/geocoder/v1/?location='.$lat.','.$lang;
+
+ $url = $url.'&key='.$config['map_secret'];
+
+ $location = longbingCurl($url,[]);
+
+ $location = json_decode($location,true);
+
+ if(!empty($location['result']['address_component'])){
+
+ $location = $location['result']['address_component'];
+
+ if(!empty($location['province'])){
+
+ $province = $location['province'];
+
+ $city = $location['city'];
+
+ $county = $location['district'];
+
+ $url = 'https://wis.qq.com/weather/common?source=pc&weather_type=observe|forecast_24h|air&province='.$province.'&city='.$city.'&county='.$county;
+
+ $weather = file_get_contents($url);
+
+ $weather = @json_decode($weather,true);
+
+ setCache($key,$weather,7200,$this->_uniacid);
+ }
+
+ }
+
+ }
+
+ return $weather;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 11:16
+ * @功能说明:获取天气情况,默认甘孜
+ */
+ public function getPlaceWeather($province='四川',$city='甘孜'){
+
+ $key = $province.'-'.$city;
+
+ $weather = getCache($key,$this->_uniacid);
+
+ if(empty($weather)){
+
+ $url = 'https://wis.qq.com/weather/common?source=pc&province='.$province.'&city='.$city.'&weather_type=observe|forecast_24h';
+
+ $weather = file_get_contents($url);
+
+ $weather = @json_decode($weather,true);
+
+ setCache($key,$weather,7200,$this->_uniacid);
+ }
+
+ return $weather;
+
+ }
+
+
+
+
+
+
+ /**
+ * @param $str_phone
+ * @param $uniacid
+ * @功能说明:发送短信验证码
+ * @author chenniang
+ * @DataTime: 2022-03-14 10:43
+ */
+ public function sendSms($str_phone,$uniacid){
+
+ $dis = [
+
+ 'uniacid' => $uniacid
+ ];
+
+ $config = $this->dataInfo($dis);
+
+ $keyId = $config['short_id'];
+
+ $keySecret = $config['short_secret'];
+
+ $SignName = $config['short_sign'];
+
+ $TemplateCode = $config['short_code'];
+
+ if(empty($keyId)||empty($keySecret)||empty($TemplateCode)){
+
+ return false;
+ }
+
+ $code = mt_rand(100000,999999);
+
+ setCache($str_phone,$code,600,$uniacid);
+
+ AlibabaCloud::accessKeyClient($keyId, $keySecret)->regionId('cn-hangzhou') // replace regionId as you need
+ ->asDefaultClient();
+
+ try {
+ $result = AlibabaCloud::rpc()
+ ->product('Dysmsapi')
+ // ->scheme('https') // https | http
+ ->version('2017-05-25')
+ ->action('SendSms')
+ ->method('POST')
+ ->host('dysmsapi.aliyuncs.com')
+ ->options([
+ 'query' => [
+ 'RegionId' => "default",
+ 'PhoneNumbers' => $str_phone,
+ //必填项 签名(需要在阿里云短信服务后台申请)
+ 'SignName' => $SignName,
+ //必填项 短信模板code (需要在阿里云短信服务后台申请)
+ 'TemplateCode' => $TemplateCode,
+ //如果在短信中添加了${code} 变量则此项必填 要求为JSON格式
+ 'TemplateParam' => "{'code':$code}",
+ ],
+ ])
+ ->request();
+
+
+ return !empty($result)?$result->toArray():[];
+ } catch(Exception $e)
+ {}
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Coupon.php b/app/farm/model/Coupon.php
new file mode 100755
index 0000000..8b747ed
--- /dev/null
+++ b/app/farm/model/Coupon.php
@@ -0,0 +1,469 @@
+where(['coupon_id'=>$data['id']])->sum('num');
+
+ return $count;
+
+ }
+
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ // $data_data = $data;
+
+// if(isset($data['service'])){
+//
+// unset($data['service']);
+// }
+//
+// if(isset($data['member_level'])){
+//
+// unset($data['member_level']);
+// }
+//
+// if(isset($data['shop_goods'])){
+//
+// unset($data['shop_goods']);
+// }
+
+
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ // $this->updateSome($id,$data_data);
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ // $data_data = $data;
+
+// if(isset($data['service'])){
+//
+// unset($data['service']);
+// }
+//
+// if(isset($data['member_level'])){
+//
+// unset($data['member_level']);
+// }
+//
+// if(isset($data['shop_goods'])){
+//
+// unset($data['shop_goods']);
+// }
+//
+// if(isset($data['restaurant_goods'])){
+//
+// unset($data['restaurant_goods']);
+// }
+
+ $res = $this->where($dis)->update($data);
+
+ // $this->updateSome($dis['id'],$data_data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-11-01 15:40
+ */
+ public function updateSome($id,$data){
+
+ $server = new \app\shop\server\Coupon();
+
+ $s_model = new CouponService();
+
+ $coupon_member_model = new CouponMember();
+
+ $goods_model = new \app\shop\model\Goods();
+
+ $r_goods_model = new \app\restaurant\model\Goods();
+
+ $coupon_member_model->where(['coupon_id'=>$id])->delete();
+
+ $s_model->where(['coupon_id'=>$id])->delete();
+ //赛车服务
+ $server->addObserver($s_model);
+ //会员
+ $server->addObserver($coupon_member_model);
+ //商城商品
+ $server->addObserver($goods_model);
+ //
+ $server->addObserver($r_goods_model);
+
+ $res = $server->notify($id,$data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @param $id
+ * @param $uniacid
+ * @param $spe
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 13:35
+ */
+ public function updateSomev2($id,$uniacid,$goods,$member_level,$shop_goods){
+
+ $s_model = new CouponService();
+
+ $coupon_member_model = new CouponMember();
+
+ $s_model->where(['coupon_id'=>$id])->delete();
+
+ if(!empty($goods)){
+
+ foreach ($goods as $value){
+
+ $insert['uniacid'] = $uniacid;
+
+ $insert['coupon_id'] = $id;
+
+ $insert['goods_id'] = $value;
+
+ $s_model->dataAdd($insert);
+
+ }
+
+ }
+
+ if(!empty($shop_goods)){
+
+ foreach ($shop_goods as $value){
+
+ $insert['uniacid'] = $uniacid;
+
+ $insert['coupon_id'] = $id;
+
+ $insert['goods_id'] = $value;
+
+ $insert['scene'] = 2;
+
+ $s_model->dataAdd($insert);
+
+ }
+
+ }
+
+ $coupon_member_model->where(['coupon_id'=>$id])->delete();
+
+ if(!empty($member_level)){
+
+ foreach ($member_level as &$value){
+
+ $inserts['uniacid'] = $uniacid;
+
+ $inserts['coupon_id'] = $id;
+
+ $inserts['member_level'] = $value;
+
+ $coupon_member_model->dataAdd($inserts);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis,$filed='*'){
+
+ $data = $this->where($dis)->field($filed)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-09 23:22
+ * @功能说明:计算优惠券可以优惠多少钱
+ */
+
+ public function getDicountPrice($order_goods,$coupon_id=0){
+
+// $coupon_se_model = new CouponService();
+ //暂时没有商品限制 先注释
+// $goods_id = $coupon_se_model->where(['coupon_id'=>$coupon_id,'type'=>1,'scene'=>$scene])->column('goods_id');
+
+ $price = 0;
+
+ foreach ($order_goods as $v){
+
+ foreach ($v['goods_list'] as $vs){
+
+// if(in_array($vs['goods_list'],$goods_id)){
+
+ $price += $v['car_price'];
+ //暂时没有商品限制
+ $goods_id[] = $vs['goods_id'];
+// }
+
+ }
+ }
+
+ $data['discount'] = $price;
+
+ $data['goods_id'] = $goods_id;
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-09 23:37
+ * @功能说明:订单优惠券
+ */
+ public function orderCouponData($order_goods,$coupon_id,$scene=1){
+
+ if(empty($coupon_id)){
+
+ return $order_goods;
+ }
+
+ $coupon_record_model = new CouponRecord();
+
+ $info = $coupon_record_model->dataInfo(['id'=>$coupon_id]);
+ //是否被使用或者过期
+ if(empty($info)||$info['status']!=1){
+
+ return $order_goods;
+ }
+ //不支持商城
+ if($scene==1&&$info['is_shop']!=1){
+
+ return $order_goods;
+
+ }
+ //不支持土地
+ if($scene==2&&$info['is_land']!=1){
+
+ return $order_goods;
+
+ }
+ //不支持认养
+ if($scene==3&&$info['is_claim']!=1){
+
+ return $order_goods;
+
+ }
+ if($info['start_time']time()){
+ //是否满足满减条件
+ if($info['full']>$order_goods['car_price']){
+
+ return $order_goods;
+ }
+
+ $total_discount = 0;
+
+ foreach ($order_goods['list'] as $ks=> $vs){
+
+ $ks_discount = 0;
+
+ foreach ($vs['goods_list'] as &$v){
+
+ $bin = $v['true_price']/$order_goods['car_price'];
+ //该商品减去的折扣
+ $discount = $bin*$info['discount']<$v['true_price']?$bin*$info['discount']:$v['true_price'];
+ //总计折扣
+ $total_discount+=$discount;
+
+ $ks_discount +=$discount;
+
+ $v['true_price'] = round($v['true_price']-$discount,2);
+
+ }
+
+ $order_goods['list'][$ks]['coupon_discount'] = $ks_discount;
+
+ }
+
+ $total_discount = $info['full']>$info['discount']?$info['discount']:round($total_discount,2);
+
+ $order_goods['total_discount'] = round($total_discount,2);
+
+ $order_goods['coupon_id'] = $coupon_id;
+
+ }
+
+ return $order_goods;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 11:58
+ * @功能说明:用户可用的优惠券
+ */
+ public function canUseCoupon($user_id,$order_price,$type=1){
+
+ $coupon_model = new CouponRecord();
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'status' => 1
+ ];
+
+ switch ($type){
+
+ case 1:
+ //商城支持
+ $dis_type = 'is_shop';
+ break;
+ case 2:
+ //土地支持
+ $dis_type = 'is_land';
+
+ break;
+ case 3:
+ //认养支持
+ $dis_type = 'is_claim';
+
+ break;
+
+
+ }
+
+ $coupon_model->where($dis)->where('end_time','<',time())->update(['status'=>3]);
+
+ $dis[$dis_type] = 1;
+
+ $list = $coupon_model->where($dis)->where('full','<=',$order_price)->column('id');
+
+ return $list;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-28 10:50
+ * @功能说明:商城用户可以领取的优惠券
+ */
+ public function shopCanGetCoupon($uniacid,$user_id,$page=10){
+
+ $record_model = new CouponRecord();
+
+ $id = $record_model->where(['user_id'=>$user_id])->column('coupon_id');
+
+ $dis = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ 'send_type'=> 2
+
+ ];
+
+ $where[] = ['time_limit','=',1];
+
+ $where[] = ['end_time','>',time()];
+
+
+ $data = $this->where($dis)->where('id','not in',$id)->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/CouponRecord.php b/app/farm/model/CouponRecord.php
new file mode 100755
index 0000000..1c6b4cc
--- /dev/null
+++ b/app/farm/model/CouponRecord.php
@@ -0,0 +1,368 @@
+alias('a')
+ ->join('shequshop_school_cap_list b','a.cap_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,b.store_name,b.store_img,b.name,b.mobile')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台审核详情
+ */
+ public function adminDataInfo($dis){
+
+ $data = $this->alias('a')
+ ->join('shequshop_school_cap_list b','a.cap_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.store_name,b.store_img,b.school_name,b.mobile')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:审核中
+ */
+ public function shIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 00:02
+ * @功能说明:用户订单数
+ */
+ public function couponCount($user_id){
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->where($dis)->sum('num');
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-08 11:57
+ * @功能说明:初始化
+ */
+ public function initCoupon($uniacid){
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['end_time','<',time()];
+
+ $res = $this->dataUpdate($dis,['status'=>3]);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 15:36
+ * @功能说明:派发优惠券
+ */
+ public function recordAdd($coupon_id,$user_id,$num=1,$user_get=0,$record_id=0){
+
+ $coupon_model = new Coupon();
+
+ $coupon = $coupon_model->dataInfo(['id'=>$coupon_id]);
+ //用户自己领取的优惠券
+ if($user_get==1){
+
+ if($coupon['send_type']!=2){
+
+ return ['code'=>500,'msg'=>'优惠券已下架'];
+
+ }
+
+ if($coupon['stock']<$num){
+
+ return ['code'=>500,'msg'=>'库存不足'];
+ }
+ //判断是否领取过
+ $have = $this->dataInfo(['user_id'=>$user_id,'coupon_id'=>$coupon_id]);
+
+ if(!empty($have)){
+
+ return ['code'=>500,'msg'=>'你已经领取过了'];
+
+ }
+
+ }
+
+ $insert = [
+
+ 'uniacid' => $coupon['uniacid'],
+
+ 'user_id' => $user_id,
+
+ 'coupon_id' => $coupon_id,
+
+ 'title' => $coupon['title'],
+
+ 'type' => $coupon['type'],
+
+ 'full' => $coupon['full'],
+
+ 'discount' => $coupon['discount'],
+
+ 'rule' => $coupon['rule'],
+
+ 'text' => $coupon['text'],
+
+ 'is_shop' => $coupon['is_shop'],
+
+ 'is_land' => $coupon['is_land'],
+
+ 'is_claim' => $coupon['is_claim'],
+
+ 'num' => $num,
+
+ 'record_id' => $record_id,
+
+ 'start_time'=> $coupon['time_limit']==2?time():$coupon['start_time'],
+
+ 'end_time' => $coupon['time_limit']==2?time()+$coupon['day']*86400:$coupon['end_time'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res==0){
+
+ return $res;
+ }
+
+ if($coupon['send_type']==2){
+ //修改优惠券库存
+ $res = $coupon_model->dataUpdate(['id'=>$coupon_id,'i'=>$coupon['i']],['stock'=>$coupon['stock']-$num,'i'=>$coupon['i']+1]);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'领取失败'];
+
+ }
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-29 23:02
+ * @功能说明:退换优惠券
+ */
+ public function couponRefund($order_id){
+
+ $order_model = new Order();
+
+ $coupon_id = $order_model->where(['id'=>$order_id])->value('coupon_id');
+
+ if(!empty($coupon_id)){
+
+ $this->dataUpdate(['id'=>$coupon_id],['status'=>1,'use_time'=>0,'order_id'=>0]);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 09:34
+ * @功能说明:使用优惠券
+ */
+ public function couponUse($coupon_id,$order_id=0,$use_type=0){
+
+ $record = $this->dataInfo(['id'=>$coupon_id]);
+
+ if($record['num']>1){
+
+ $this->dataUpdate(['id'=>$coupon_id],['num'=>$record['num']-1]);
+
+ unset($record['id']);
+
+ if(isset($record['goods'])){
+
+ unset($record['goods']);
+ }
+
+ if(isset($record['shop_goods'])){
+
+ unset($record['shop_goods']);
+ }
+
+ if(isset($record['restaurant_goods'])){
+
+ unset($record['restaurant_goods']);
+ }
+
+ $record['pid'] = $coupon_id;
+
+ $record['num'] = 1;
+
+ $record['status'] = 2;
+
+ $record['use_time'] = time();
+
+ $record['order_id'] = $order_id;
+
+ $record['use_type'] = $use_type;
+
+ $this->insert($record);
+
+ $coupon_id = $this->getLastInsID();
+
+ }else{
+
+ $this->dataUpdate(['id'=>$coupon_id],['status'=>2,'use_time'=>time(),'order_id'=>$order_id,'use_type'=>$use_type]);
+
+ }
+ //带客有礼 给分享者发券
+ if(!empty($record['record_id'])){
+
+ $atv_model = new BagRecord();
+
+ $atv_info = $atv_model->dataInfo(['id'=>$record['record_id']]);
+
+ $res = $this->recordAdd($atv_info['share_coupon'],$atv_info['share_user']);
+ }
+
+ return $coupon_id;
+
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Evaluate.php b/app/farm/model/Evaluate.php
new file mode 100755
index 0000000..ae8c9cd
--- /dev/null
+++ b/app/farm/model/Evaluate.php
@@ -0,0 +1,338 @@
+getTypeModel($data['type'],2);
+
+ $info = $model->dataInfo(['id'=>$data['order_id']]);
+
+ $farmer_model = new \app\farm\model\Farmer();
+
+ $info['farmer_info'] = $farmer_model->dataInfo(['id'=>$data['farmer_id']],'title');
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 17:14
+ * @功能说明:转换图片格式
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+
+ }else{
+
+ return [];
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-10 17:37
+ * @功能说明:根据type获取模型
+ */
+ public function getTypeModel($type,$is_order=1){
+
+ switch ($type){
+
+ case 1:
+
+ $model = new ClaimOrder();
+
+ break;
+
+ case 2:
+
+ $model = new LandOrder();
+
+ break;
+
+ case 3:
+
+ $model = $is_order ==1?new ShopOrderGoods():new ShopOrder();
+
+ break;
+
+ default:
+
+ $model = new ClaimOrder();
+
+ break;
+
+ }
+
+ return $model;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-10 13:33
+ * @功能说明:评价管理
+ */
+ public function adminList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_farmer b','a.farmer_id = b.id','left')
+ ->join('lbfarm_user_list c','a.user_id = c.id','left')
+ ->where($dis)
+ ->field('a.*,b.title,c.nickName,c.avatarUrl')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-11 10:04
+ * @功能说明:根据type获取key
+ */
+ public function getObjKey($type){
+
+ switch ($type){
+
+ case 1:
+
+ $key = 'claim_id';
+
+ break;
+ case 2:
+
+ $key = 'land_id';
+
+ break;
+
+ case 3:
+
+ $key = 'goods_id';
+
+ break;
+ default:
+ $key = 'claim_id';
+
+ break;
+ }
+
+ return $key;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-11 09:53
+ * @功能说明:评价列表
+ */
+ public function goodsEvaluateList($goods_id,$type,$is_goods=0){
+
+ $order_model = $this->getTypeModel($type);
+
+ $key = $this->getObjKey($type);
+
+ $dis = [
+
+ // 'pay_type' => 7,
+
+ $key => $goods_id
+ ];
+
+ if($type==3){
+
+ $order_id = $order_model->where($dis)->column('order_id');
+
+ }else{
+
+ $order_id = $order_model->where($dis)->column('id');
+ }
+
+ $where[] = ['status','>',-1];
+
+ $where[] = ['order_id','in',$order_id];
+
+ $where[] = ['type','=',$type];
+
+ $dis_where = $where;
+
+ if($is_goods==1){
+
+ $where[] = ['star','>=',3];
+
+ }
+
+ if($is_goods==2){
+
+ $where[] = ['star','<',3];
+
+ }
+
+ $data = $this->dataList($where);
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['user_info'] = $user_model->where(['id'=>$v['user_id']])->field('nickName,avatarUrl')->find();
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+
+ }
+
+ $data['good_count'] = $this->where($dis_where)->where('star','>=',3)->count();
+
+ $data['bad_count'] = $this->where($dis_where)->where('star','<',3)->count();
+
+ $data['all_count'] = $this->where($dis_where)->count();
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @param $place_id
+ * @功能说明:修改场地的评分
+ * @author chenniang
+ * @DataTime: 2022-01-11 15:49
+ */
+ public function updateFarmerStar($farmer_id){
+
+ $dis[] = ['farmer_id','=',$farmer_id];
+
+ $dis[] = ['status','>',-1];
+
+ $find = $this->where($dis)->find();
+
+ $star = $this->where($dis)->avg('star');
+
+ $star = !empty($find)?$star:5;
+
+ $farmr_model = new Farmer();
+
+ $res = $farmr_model->dataUpdate(['id'=>$farmer_id],['star'=>$star]);
+
+ return $res;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Farmer.php b/app/farm/model/Farmer.php
new file mode 100755
index 0000000..16ef0e4
--- /dev/null
+++ b/app/farm/model/Farmer.php
@@ -0,0 +1,344 @@
+time()){
+
+ return 1;
+ }else{
+
+ return 0;
+ }
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:22
+ * @功能说明:
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:22
+ * @功能说明:
+ */
+ public function getIdcardImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataDistanceList($dis,$alh,$alhs=[],$page=10){
+
+ $data = $this->where($dis)->where($alhs)->field(['*',$alh])->order('distance asc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:26
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10,$where=[]){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_user_list b','a.user_id = b.id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis,$file='*'){
+
+ $data = $this->where($dis)->field($file)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 11:30
+ * @功能说明:检查用户是否是地主
+ */
+ public function landlordCheck($user_id){
+
+ $cap_dis[] = ['user_id','=',$user_id];
+
+ $cap_dis[] = ['type','=',1];
+
+ $cap_dis[] = ['status','in',[2,3]];
+
+ $farmer_model = new \app\farm\model\Farmer();
+ //查看是否是团长
+ $cap_info = $farmer_model->dataInfo($cap_dis);
+
+ $is_landlord = 1;
+
+ if(empty($cap_info)){
+
+ $order_model = new LandOrder();
+
+ $where[] = ['pay_type','>',1];
+
+ $where[] = ['user_id','=',$user_id];
+ //是否有土地订单
+ $order = $order_model->dataInfo($where);
+
+ if(empty($order)){
+
+ $is_landlord = 0;
+
+ }
+
+ }
+
+ $user_model = new User();
+
+ $user_model->dataUpdate(['id'=>$user_id],['is_landlord'=>$is_landlord]);
+
+ return $is_landlord;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 11:53
+ * @功能说明:初始化地主表
+ */
+ public function initLandLord($data,$uniacid){
+
+ $dis = [
+
+ 'type' => 2,
+
+ 'user_id' => $data['user_id'],
+
+ 'uniacid' => $uniacid
+ ];
+
+ $find = $this->dataInfo($dis);
+
+ if(empty($find)){
+
+ $dis['status'] = 2;
+
+ $dis['title'] = $data['title'];
+
+ $dis['cover'] = $data['cover'];
+
+ $dis['address'] = $data['address'];
+
+ $dis['lat'] = $data['lat'];
+
+ $dis['lng'] = $data['lng'];
+
+ $dis['desc'] = $data['desc'];
+
+ $dis['mobile'] = $data['mobile'];
+
+ $this->dataAdd($dis);
+
+ $user_model = new User();
+
+ $user_model->dataUpdate(['id'=>$data['user_id']],['is_landlord'=>1]);
+ }
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-10-21 15:21
+ * @功能说明:保留两位小数
+ */
+ public function getDistanceAttr($value){
+
+ if(!empty($value)){
+
+ if($value>1000){
+
+ $value = $value/1000;
+
+ $value = round($value,2);
+
+ $value = $value.'km';
+ }else{
+
+ $value = round($value,2);
+
+ $value = $value.'m';
+
+ }
+
+ return $value;
+
+ }
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-28 14:08
+ * @功能说明:添加商品时农场主下拉框
+ */
+ public function goodsFarmerSelect($user_id){
+
+ $land_order_model = new LandOrder();
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['pay_type','>',1];
+ //购买土地对农场主id
+ $order_farmer = $land_order_model->where($dis)->column('farmer_id');
+
+ $where[] = ['user_id','=',$user_id];
+
+ $where[] = ['status','in',[2,3]];
+ //如果自己是农场主
+ $farmer = $this->where($where)->column('id');
+
+ $order_farmer = array_merge($order_farmer,$farmer);
+
+ return $order_farmer;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-28 16:06
+ * @功能说明:
+ */
+ public function farmerId($uniacid){
+
+ $dis = [
+
+ 'status' => 2,
+
+ 'uniacid'=> $uniacid
+ ];
+
+ $id = $this->where($dis)->column('id');
+
+ return $id;
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/FinanceWater.php b/app/farm/model/FinanceWater.php
new file mode 100755
index 0000000..1d86264
--- /dev/null
+++ b/app/farm/model/FinanceWater.php
@@ -0,0 +1,872 @@
+getTypeData($data['type']);
+
+ return $text;
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 15:52
+ * @功能说明:
+ */
+ public function getTypeData($type){
+
+ switch ($type){
+
+ case 1:
+
+ $text = '认养订单收入';
+
+ break;
+ case 2:
+
+ $text = '认养订单退款';
+
+ break;
+ case 3:
+
+ $text = '土地订单收入';
+
+ break;
+
+ case 4:
+
+ $text = '土地订单退款';
+
+ break;
+ case 5:
+
+ $text = '养殖';
+
+ break;
+ case 6:
+
+ $text = '养殖订单收入';
+
+ break;
+ case 7:
+
+ $text = '提现';
+
+ break;
+ case 8:
+
+ $text = '商城订单收入';
+
+ break;
+ case 9:
+
+ $text = '商城退款';
+
+ break;
+ case 10:
+
+ $text = '认养配送订单收入';
+
+ break;
+ case 11:
+
+ $text = '认养配送订单退款';
+
+ break;
+ case 12:
+
+ $text = '提现拒绝';
+
+ break;
+
+ case 13:
+
+ $text = '土地配送订单退款';
+
+ break;
+
+ case 14:
+
+ $text = '土地配送订单收入';
+
+ break;
+
+ case 15://地主提现
+
+ $text = '提现';
+
+ break;
+ case 16:
+
+ $text = '商城订单运费';
+
+ break;
+ case 17:
+
+ $text = '商城订单运费退款';
+
+ break;
+ default:
+
+ $text = '';
+
+ break;
+ }
+
+ return $text;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 10:41
+ * @功能说明:获取用户消费信息
+ */
+ public function getUserCashData($user_id){
+
+ $where[] = ['user_id','=',$user_id];
+
+ $arr = [1,3,5,6,8,10,14,16];
+ //总收入
+ $total_cash = $this->where($where)->where('type','in',$arr)->sum('price');
+ //退款
+ $refund_cash= $this->where($where)->where('type','in',[2,4,9,11,13,17])->sum('price');
+
+ $data = [
+
+ 'total_cash' => round($total_cash,2),
+
+ 'refund_cash' => round($refund_cash,2),
+ //余额
+ 'cash' => round($total_cash-$refund_cash,2),
+
+ ];
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-28 14:08
+ * @功能说明:分销用户的消费状况
+ */
+ public function resellerCashData($user_id){
+
+ $where[] = ['user_id','=',$user_id];
+
+ $arr = [1,3,8];
+ //总收入
+ $total_cash = $this->where($where)->where('type','in',$arr)->sum('price');
+ //退款
+ $refund_cash= $this->where($where)->where('type','in',[2,4,9])->sum('price');
+
+ $data = [
+
+// 'total_cash' => round($total_cash,2),
+//
+// 'refund_cash' => round($refund_cash,2),
+ //余额
+ 'order_price' => round($total_cash-$refund_cash,2),
+
+ ];
+ //查付款的订单笔数
+ $list = [
+
+ 'land_order' => new LandOrder(),
+
+ 'claim_order'=> new ClaimOrder(),
+
+ 'shop_order' => new ShopOrder(),
+ ];
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['pay_type','>',1];
+
+ $num = 0;
+
+ foreach ($list as $k=>$value){
+
+ $num += $value->where($dis)->count();
+ }
+
+ $data['order_count'] = $num;
+
+ return $data;
+
+ }
+
+
+ /**
+ * @param $date
+ * @功能说明:获取指定日期的余额
+ * @author chenniang
+ * @DataTime: 2022-01-12 15:10
+ */
+ public function getDayCash($farmer_id,$type=1,$date='',$start_time='',$end_time='',$cash_status=''){
+
+ if($type==1){
+
+ $where[] = ['farmer_id','=',$farmer_id];
+
+ }else{
+
+ $where[] = ['store_id','=',$farmer_id];
+
+ }
+
+ $where[] = ['role_type','=',$type];
+
+ if(!empty($date)){
+
+ $date = strtotime($date)+86399;
+
+ $where[] = ['create_time','<',$date];
+
+ }elseif (!empty($start_time)&&!empty($end_time)){
+
+ $where[] = ['create_time','between',"$start_time,$end_time"];
+
+ }
+
+ if(!empty($cash_status)){
+
+ $where[] = ['cash_status','=',$cash_status];
+
+ }
+
+ $arr = [1,3,5,6,8,10,14,16];
+ //总收入
+ $total_cash = $this->where($where)->where('type','in',$arr)->sum('price');
+ //退款
+ $refund_cash= $this->where($where)->where('type','in',[2,4,9,11,13,17])->sum('price');
+ //提现
+ $wallet_cash= $this->where($where)->where('type','in',[7])->sum('price');
+
+ $wallet_refund_cash= $this->where($where)->where('type','in',[12])->sum('price');
+
+ $wallet_cash-=$wallet_refund_cash;
+
+ $data = [
+
+ 'total_cash' => round($total_cash,2),
+
+ 'refund_cash' => round($refund_cash,2),
+
+ 'wallet_cash' => round($wallet_cash,2),
+
+ 'income_cash' => round($total_cash-$refund_cash,2),
+ //余额
+ 'cash' => round($total_cash-$refund_cash-$wallet_cash,2),
+
+ ];
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-12 16:28
+ * @功能说明:获取指定日期的流水详情
+ */
+ //1认养 2认养退款 3土地 4土地退款 5养殖 6养殖管理 7提现 8商城 9商城退款 10 配送订单 11配送退款 12 拒绝提现 13土地配送订单退款 14土地配送订单 16商城订单运费 17 商城订单运费退款
+ public function getDateList($farmer_id,$date,$type=1,$cash_status=2){
+
+ if($type==1){
+
+ $dis = [
+
+ 'farmer_id' => $farmer_id
+ ];
+
+ $arr = [
+
+ 1 => 'claim_cash',
+
+ 3 => 'land_cash',
+
+ 7 => 'wallet_cash',
+
+ 6 => 'breed_cash',
+
+ 16 => 'shop_send_cash',
+
+ 10 => 'claim_send_cash',
+
+ 14 => 'land_send_cash',
+
+ 11 => 'claim_send_refund_cash',
+
+ 13 => 'land_send_refund_cash',
+
+ 12 => 'wallet_refund_cash',
+
+ ];
+ }else{
+ $arr = [
+
+ 7 => 'wallet_cash',
+
+ 8 => 'shop_cash',
+
+ 9 => 'shop_refund_cash',
+
+ 12 => 'wallet_refund_cash',
+
+
+ ];
+
+ $dis = [
+
+ 'store_id' => $farmer_id
+ ];
+
+ }
+
+ $dis['role_type'] = $type;
+
+ if(!empty($date)){
+
+ $dis['create_date'] = $date;
+
+ }
+
+ if(!empty($cash_status)){
+
+ $dis['cash_status'] = $cash_status;
+
+ }
+
+ foreach ($arr as $key=>$value){
+
+ $dis['type'] = $key;
+
+ $list[$value] = $this->where($dis)->sum('price');
+
+ }
+
+ if($type==1){
+
+ $list['claim_send_cash'] -= $list['claim_send_refund_cash'];
+
+ $list['land_send_cash'] -= $list['land_send_refund_cash'];
+ }
+
+ $list['wallet_cash'] -= $list['wallet_refund_cash'];
+
+
+ return $list;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 11:17
+ * @功能说明:添加流水
+ */
+ public function addWater($order_id,$type,$role_type=1,$cash_status=0){
+
+ $data = $this->getModel($type);
+
+ $order = $data['model']->dataInfo(['id'=>$order_id]);
+ //查询店铺的用户id
+ if($role_type==2&&!empty($order['store_id'])){
+
+ $farmer_model = new Farmer();
+
+ $landlord_id = $farmer_model->where(['id'=>$order['store_id']])->value('user_id');
+
+ }else{
+
+ $landlord_id = 0;
+ }
+ //商城订单需要减去运费
+ if($type==8){
+
+ $order['pay_price'] -= $order['freight'];
+ }
+ //商城退款需要减去运费
+ if($type==9){
+
+ $order['pay_price'] -= $order['car_price'];
+ }
+ //商城订单农场主获得运费
+ if($type==16){
+
+ $order['pay_price'] = $order['freight'];
+ }
+ //商城退款农场主退运费
+ if($type==17){
+
+ $order['pay_price'] = $order['car_price'];
+ }
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'role_type' => $role_type,
+
+ 'farmer_id' => !empty($order['farmer_id'])?$order['farmer_id']:0,
+
+ 'landlord_id' => $landlord_id,
+
+ 'store_id' => !empty($order['store_id'])?$order['store_id']:0,
+
+ 'price' => $order['pay_price'],
+
+ 'order_code' => $order['order_code'],
+
+ 'cash_time' => !empty($order['cash_time'])?$order['cash_time']:0,
+
+ 'cash_status' => $cash_status,
+
+ 'order_id' => $order_id,
+
+ 'type' => $type,
+
+ 'add' => $data['add'],
+
+ 'create_time' => time(),
+
+ 'create_date' => date('Y-m-d',time()),
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-08 16:25
+ * @功能说明:资金到账
+ */
+ public function cashArrival($farmer_id=0,$landlord_id=0,$id=0){
+
+ $dis[] = ['cash_status','=',1];
+
+ $dis[] = ['cash_time','<',time()];
+
+ $dis[] = ['price','<>',0];
+
+ if(!empty($farmer_id)){
+
+ $dis[] = ['farmer_id','=',$farmer_id];
+
+ }
+
+ if(!empty($landlord_id)){
+
+ $dis[] = ['landlord_id','=',$landlord_id];
+
+ }
+
+ if(!empty($id)){
+
+ $dis[] = ['id','=',$id];
+
+ }
+
+ $list = $this->where($dis)->select()->toArray();
+
+
+ if(!empty($list)){
+
+ $farmer_model = new Farmer();
+
+ $water_model = new BalanceWater();
+
+ foreach ($list as $value){
+
+ Db::startTrans();
+
+ $cash = $value['add']==1?$value['price']:$value['price']*-1;
+ //农场主
+ if($value['role_type']==1){
+
+ $farmer = $farmer_model->dataInfo(['id'=>$value['farmer_id']]);
+
+ if(!empty($farmer)){
+
+ $res = $farmer_model->dataUpdate(['id'=>$value['farmer_id'],'lock'=>$farmer['lock']],['cash'=>$farmer['cash']+$cash,'lock'=>$farmer['lock']+1]);
+ }
+
+ }else{
+
+ //地主
+ $order_data = [
+
+ 'uniacid' => $value['uniacid'],
+
+ 'user_id' => $value['landlord_id'],
+
+ 'id' => $value['id'],
+
+ 'pay_price'=> abs($cash),
+
+ ];
+
+ switch ($value['type']){
+
+ case 8://商城订单
+
+ $water_type = 11;
+
+ $add = 1;
+
+ break;
+ case 9://商城退款
+
+ $water_type = 10;
+
+ $add = 0;
+
+ break;
+ case 12://拒绝提现
+
+ $water_type = 12;
+
+ $add = 1;
+
+ break;
+ case 15://提现
+
+ $water_type = 8;
+
+ $add = 0;
+
+ break;
+
+ }
+
+ $res = $water_model->addWater($order_data,$water_type,$add);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ //给当前店铺加减金额
+ $farmer = $farmer_model->dataInfo(['id'=>$value['store_id']]);
+
+ if(!empty($farmer)){
+
+ $res = $farmer_model->dataUpdate(['id'=>$value['store_id'],'lock'=>$farmer['lock']],['cash'=>$farmer['cash']+$cash,'lock'=>$farmer['lock']+1]);
+ }
+
+ }
+
+ if(isset($res)&&$res==0){
+
+ Db::rollback();
+
+ }
+
+
+ $res = $this->dataUpdate(['id'=>$value['id'],'cash_status'=>1],['cash_status'=>2]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+
+ Db::commit();
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param $user_id
+ * @功能说明:地主冻结金额
+ * @author chenniang
+ * @DataTime: 2022-02-16 14:15
+ */
+ public function landordFrozenCash($user_id){
+
+ $this->cashArrival(0,$user_id);
+
+ $dis[] = ['landlord_id','=',$user_id];
+
+ $dis[] = ['role_type','=',2];
+
+ $dis[] = ['cash_status','in',[0,1]];
+
+ $cash = $this->where($dis)->where('type','=',8)->sum('price');
+
+ $refund_cash = $this->where($dis)->where('type','=',9)->sum('price');
+
+ return round($cash-$refund_cash,2);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-29 11:29
+ * @功能说明:更具type获取模型
+ */
+ public function getModel($type){
+
+ switch ($type){
+
+ case 1:
+
+ $data['model'] = new ClaimOrder();
+
+ $data['add'] = 1;
+
+ break;
+
+ case 2:
+
+ $data['model'] = new ClaimOrder();
+
+ $data['add'] = 0;
+
+ break;
+
+ case 3:
+
+ $data['model'] = new LandOrder();
+
+ $data['add'] = 1;
+
+ break;
+
+ case 6:
+
+ $data['model'] = new BreedOrder();
+
+ $data['add'] = 1;
+
+ break;
+
+ case 7:
+
+ $data['model'] = new Wallet();
+
+ $data['add'] = 0;
+
+ break;
+
+ case 8:
+
+ $data['model'] = new ShopOrder();
+
+ $data['add'] = 1;
+
+ break;
+ case 9:
+
+ $data['model'] = new ShopRefund();
+
+ $data['add'] = 0;
+
+ break;
+
+ case 10:
+ //认养配送订单
+ $data['model'] = new SendOrder();
+
+ $data['add'] = 1;
+
+ break;
+
+ case 11:
+ //认养订单退款
+ $data['model'] = new SendOrder();
+
+ $data['add'] = 0;
+
+ break;
+ case 12:
+ //拒绝提现
+ $data['model'] = new Wallet();
+
+ $data['add'] = 1;
+
+ break;
+ case 13:
+ //土地订单退款
+ $data['model'] = new SendOrder();
+
+ $data['add'] = 0;
+
+ break;
+ case 14:
+ //土地配送订单
+ $data['model'] = new SendOrder();
+
+ $data['add'] = 1;
+
+ break;
+
+ case 15:
+ //地主提现
+ $data['model'] = new Wallet();
+
+ $data['add'] = 0;
+
+ break;
+ case 16:
+ //商城订单农场主获得运费
+ $data['model'] = new ShopOrder();
+
+ $data['add'] = 1;
+
+ break;
+ case 17:
+ //商城订单农场主获得运费退款
+ $data['model'] = new ShopRefund();
+
+ $data['add'] = 0;
+
+ break;
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/GoodsCate.php b/app/farm/model/GoodsCate.php
new file mode 100755
index 0000000..2d3c641
--- /dev/null
+++ b/app/farm/model/GoodsCate.php
@@ -0,0 +1,126 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-12 16:16
+ * @功能说明:
+ */
+ public function addData($id,$type,$uniacid,$cate){
+
+ $this->where(['goods_id'=>$id,'type'=>$type])->delete();
+
+ if(!empty($cate)){
+
+ foreach ($cate as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $uniacid,
+
+ 'cate_id' => $v,
+
+ 'goods_id'=> $id,
+
+ 'type' => $type
+ ];
+
+ }
+
+ $this->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:07
+ * @功能说明:
+ */
+ public function eventClaim($id,$data){
+
+ $this->addData($id,3,$data['uniacid'],$data['cate_id']);
+
+ return true;
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/InfoRecord.php b/app/farm/model/InfoRecord.php
new file mode 100755
index 0000000..48b4174
--- /dev/null
+++ b/app/farm/model/InfoRecord.php
@@ -0,0 +1,110 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-22 16:03
+ * @功能说明:获取已读数量
+ */
+ public function noReadCount($user_id,$uniacid){
+
+ $dis = [
+
+ 'a.user_id' => $user_id,
+
+ 'b.status' => 1,
+
+ 'b.type' => 3
+ ];
+
+ $read_count = $this->alias('a')
+ ->join('lbfarm_v2_welfare_column b','a.info_id = b.id')
+ ->where($dis)
+ ->count();
+
+ $info_model = new WelfareColumn();
+
+ $info_count = $info_model->where(['uniacid'=>$uniacid,'status'=>1,'type'=>3])->count();
+
+ return ($info_count - $read_count)>0?$info_count - $read_count:0;
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandCate.php b/app/farm/model/LandCate.php
new file mode 100755
index 0000000..5b3826b
--- /dev/null
+++ b/app/farm/model/LandCate.php
@@ -0,0 +1,195 @@
+ $data['id'],
+
+ 'type' => $data['type']
+ ];
+
+ $list = $text_model->where($dis)->column('farmer_id');
+
+ return array_values($list);
+ }
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ if(isset($data['farmer_id'])){
+
+ $farmer_id = $data['farmer_id'];
+
+ unset($data['farmer_id']);
+
+ }
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($farmer_id)){
+
+
+ $this->updateSome($id,$data['uniacid'],$farmer_id,$data['type']);
+ }
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['farmer_id'])){
+
+ $farmer_id = $data['farmer_id'];
+
+ unset($data['farmer_id']);
+
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($farmer_id)){
+
+ $this->updateSome($dis['id'],$data['uniacid'],$farmer_id,$data['type']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:15
+ * @功能说明:
+ */
+ public function updateSome($id,$uniacid,$data,$type){
+
+ $text_model = new LandCateText();
+
+ $text_model->where(['cate_id'=>$id,'type'=>$type])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $uniacid,
+
+ 'cate_id' => $id,
+
+ 'farmer_id' => $v,
+
+ 'type' => $type
+ ];
+
+ }
+
+ $text_model->saveAll($insert);
+ }
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:47
+ * @功能说明:认养分类
+ */
+ public function claimCateList($dis){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_land_cate_text b','a.id = b.cate_id')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc.a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/farm/model/LandCateText.php b/app/farm/model/LandCateText.php
new file mode 100755
index 0000000..4e29c58
--- /dev/null
+++ b/app/farm/model/LandCateText.php
@@ -0,0 +1,77 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandCycle.php b/app/farm/model/LandCycle.php
new file mode 100755
index 0000000..96a7ca0
--- /dev/null
+++ b/app/farm/model/LandCycle.php
@@ -0,0 +1,111 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:15
+ * @功能说明:
+ */
+ public function eventLand($id,$uniacid,$data,$type){
+
+ $this->where(['uniacid'=>$uniacid])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $v = [
+
+ 'uniacid' => $uniacid,
+
+ 'lande_id' => $id,
+
+ ];
+
+ $this->insert($v);
+
+ }
+
+ }
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandList.php b/app/farm/model/LandList.php
new file mode 100755
index 0000000..b775f36
--- /dev/null
+++ b/app/farm/model/LandList.php
@@ -0,0 +1,477 @@
+ 1,
+
+ 'a.goods_id' => $data['id'],
+
+ 'a.type' => 2,
+
+ 'b.type' => 1,
+ ];
+
+ $goods_cate_model = new GoodsCate();
+
+ $list = $goods_cate_model->alias('a')
+ ->join('lbfarm_land_cate b','a.cate_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title')
+ ->group('a.id')
+ ->order('a.id dsec')
+ ->column('b.id');
+
+
+ return array_values($list);
+ }
+
+ }
+
+// /**
+// * @param $value
+// * @param $data
+// * @功能说明:
+// * @author chenniang
+// * @DataTime: 2022-01-26 15:16
+// */
+// public function getTextAttr($value,$data){
+//
+// if(!empty($value)){
+//
+//
+// return str_replace(" ","",getimgs($value));
+// }
+//
+// }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 10:50
+ * @功能说明:轮播图转格式
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-31 17:46
+ * @功能说明:获取最低价格
+ */
+ public function getMinPriceAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $spe_model = new LandSpe();
+
+ $price = $spe_model->where(['land_id'=>$data['id']])->min('price');
+
+ return $price;
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $g_data = $data;
+
+ $arr = ['massif', 'seed', 'monitor','spe','cycle'];
+
+ foreach ($arr as $vs){
+
+ if(key_exists($vs,$data)){
+
+ unset($data[$vs]);
+ }
+
+ }
+
+ if(!empty($data['imgs'])){
+
+ $data['imgs'] = implode(',',$data['imgs']);
+ }
+
+ if(!empty($data['cate_id'])){
+
+ $cate_id = $data['cate_id'];
+
+ unset($data['cate_id']);
+ }
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$g_data,$cate_id,$data['uniacid']);
+
+
+ return $id;
+
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $g_data = $data;
+
+ $arr = ['massif', 'seed', 'monitor','spe','cycle'];
+
+ foreach ($arr as $vs){
+
+ if(key_exists($vs,$data)){
+
+ unset($data[$vs]);
+ }
+
+ }
+
+ if(!empty($data['imgs'])){
+
+ $data['imgs'] = implode(',',$data['imgs']);
+ }
+
+ if(!empty($data['cate_id'])){
+
+ $cate_id = $data['cate_id'];
+
+ unset($data['cate_id']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ $this->updateSome($dis['id'],$g_data,$cate_id,$data['uniacid']);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 15:45
+ * @功能说明:添加关联
+ */
+ public function updateSome($id,$data,$cate,$uniacid){
+
+ $server = new \app\farm\server\Land();
+
+ $lan_text_model = new LandText();
+
+ $land_spe_model = new LandSpe();
+
+ $server->addObserver($lan_text_model);
+
+ $server->addObserver($land_spe_model);
+
+ $server->notify($id,$data);
+
+ $goods_cate_model = new GoodsCate();
+
+ $goods_cate_model->addData($id,2,$uniacid,$cate);
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 14:00
+ * @功能说明:前端土地列表
+ */
+ public function indexDataList($dis,$alh,$sort=1){
+
+ switch ($sort){
+
+ case 1:
+ $order = 'id desc';
+
+ break;
+
+ case 3:
+
+ $order = 'distance asc,id desc';
+
+ break;
+
+ case 2:
+
+ $order = 'sale_num desc,id desc';
+
+ break;
+
+ }
+
+ $data = $this->where($dis)->field(['*',$alh])->order($order)->paginate(10)->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 14:00
+ * @功能说明:前端土地列表
+ */
+ public function indexDataListV2($dis,$alh,$sort=1){
+
+ switch ($sort){
+
+ case 1:
+ $order = 'a.id desc';
+
+ break;
+
+ case 3:
+
+ $order = 'distance asc,a.id desc';
+
+ break;
+
+ case 2:
+
+ $order = 'a.sale_num desc,a.id desc';
+
+ break;
+
+ }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_cate b','a.id = b.goods_id','left')
+ ->where($dis)
+ ->field(['a.*',$alh])
+ ->group('a.id')
+ ->order($order)
+ ->paginate(10)
+ ->toArray();
+
+ return $data;
+
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-15 14:24
+ * @功能说明:土地详情
+ */
+ public function landInfo($dis){
+
+ $data = $this->dataInfo($dis);
+
+ $arr = [
+
+ 1 => [
+ 'type_name'=>'massif',
+
+ 'table' => new Massif()
+
+ ],
+ 2 => [
+
+ 'type_name'=> 'seed',
+
+ 'table' => new Seed()
+
+ ],
+ 4 => [
+ 'type_name'=> 'monitor',
+
+ 'table' => new Monitor()
+
+ ],
+ 5 => [
+
+ 'type_name'=>'cycle',
+
+ ]
+ ];
+
+ $source_model = new Source();
+
+ $land_text_model = new LandText();
+
+ foreach ($arr as $k=>$v){
+
+ if(empty($v['table'])){
+
+ $where = [
+
+ 'land_id' => $data['id'],
+
+ 'type' => $k,
+ ];
+
+ $obj = $land_text_model->where($where)->column('obj_id');
+
+ $data[$v['type_name']] = array_values($obj);
+
+ continue;
+ }
+
+ $where = [
+
+ 'b.land_id' => $data['id'],
+
+ 'b.type' => $k,
+
+ 'a.status' => 1
+ ];
+
+ $obj = $v['table']->alias('a')
+ ->join('lbfarm_land_text b','b.obj_id = a.id','right')
+ ->where($where)
+ ->field('a.*,b.source_id as s_id')
+ ->group('a.id')
+ ->order('b.id desc')
+ ->select()
+ ->toArray();
+
+ if(!empty($obj)){
+
+ foreach ($obj as $key => &$value){
+
+ if(!empty($value['s_id'])){
+
+ $value['source_name'] = $source_model->where(['id'=>$value['s_id'],'status'=>1])->value('title');
+
+ }
+
+ }
+
+ }
+
+ $data[$v['type_name']] = $obj;
+
+ }
+
+ $cate_model = new LandCate();
+
+ $data['cate_name'] = $cate_model->where(['id'=>$data['cate_id'],'status'=>1,'type'=>1])->value('title');
+
+ $land_spe = new LandSpe();
+ //规格
+ $data['spe'] = $land_spe->where(['land_id'=>$data['id']])->select()->toArray();
+
+ $mac_model = new Machine();
+
+ $data['machine_name'] = $mac_model->where(['id'=>$data['machine_id'],'status'=>1])->value('title');
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-02 16:36
+ * @功能说明:
+ */
+ public function landSomeFind($id,$type){
+
+ $dis = [
+
+ 'obj_id' => $id,
+
+ 'type' => $type,
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_land_text b','a.id = b.land_id')
+ ->where($dis)
+ ->where('a.status','>',-1)
+ ->find();
+
+ return !empty($data)?1:0;
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandOrder.php b/app/farm/model/LandOrder.php
new file mode 100755
index 0000000..889fa66
--- /dev/null
+++ b/app/farm/model/LandOrder.php
@@ -0,0 +1,677 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);;
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-21 17:04
+ * @功能说明:下单支付信息
+ */
+ public function payOrderInfo($input){
+
+ $spe_model = new LandSpe();
+
+ $massif_model = new Massif();
+
+ $seed_model = new Seed();
+
+ $land_model = new LandList();
+
+ $text_model = new LandText();
+
+ $data['land'] = $land_model->dataInfo(['id'=>$input['land_id']]);
+
+ if(empty($data['land'])){
+
+ return ['code'=>500,'msg'=>'该土地已下架'];
+
+ }
+
+ $dis = [
+
+ 'land_id' => $input['land_id'],
+
+ 'spe_id' => $input['spe_id']
+ ];
+
+ $find = $this->where($dis)->where('pay_type','>=',1)->find();
+
+ if(!empty($find)){
+
+ return ['code'=>500,'msg'=>'该规格已被预约'];
+
+ }
+ //规格
+ $spe = $spe_model->dataInfo(['id'=>$input['spe_id']]);
+
+ if(empty($spe)){
+
+ return ['code'=>500,'msg'=>'该规格已下架'];
+ }
+ $data['spe'] = $spe;
+ //地块
+ $massif = $massif_model->dataInfo(['id'=>$input['massif_id']]);
+
+ if(empty($massif)){
+
+ return ['code'=>500,'msg'=>'该地块已下架'];
+ }
+
+ $data['land_price'] = $spe['price'];
+
+ $data['cycle'] = $input['cycle'];
+
+ $data['total_massif_price'] = round($input['cycle']*$massif['price'],2);
+
+ $data['massif'] = $massif;
+
+ $data['seed_price'] = 0;
+
+ if(!empty($input['seed_data'])){
+
+ foreach ($input['seed_data'] as $v){
+
+ $seed = $seed_model->dataInfo(['id'=>$v['id']]);
+
+ if(empty($seed)){
+
+ return ['code'=>500,'msg'=>'该种子已下架'];
+ }
+ //溯源id
+ $seed['source_id'] = $text_model->where(['land_id'=>$input['land_id'],'type'=>2,'obj_id'=>$v['id']])->value('source_id');
+
+ $seed['num'] = $v['num'];
+
+ $data['seed_price'] += $seed['seed_price']*$v['num'];
+
+ $data['seed'][] = $seed;
+
+ }
+
+ }
+
+ $data['seed_price'] = round($data['seed_price'],2);
+ //支付价格
+ $data['pay_price'] = round($data['land_price']+$data['total_massif_price']+$data['seed_price'],2);
+
+ $pay_price = $data['init_price'] = $data['pay_price'];
+
+ if(!empty($input['coupon_id'])){
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon = $coupon_record_model->dataInfo(['id'=>$input['coupon_id'],'is_land'=>1,'status'=>1]);
+
+ if(!empty($coupon)&&$coupon['full']<=$data['pay_price']){
+
+ $data['pay_price'] -= $coupon['discount'];
+
+ }else{
+
+ $coupon = [];
+ }
+
+ }
+
+ $data['land_price'] = $data['land_price']>0?$data['land_price']:0;
+
+ $data['land_price'] = round($data['land_price'],2);
+
+ $data['coupon_discount'] = !empty($coupon)?$coupon['discount']:0;
+
+ $data['coupon_discount'] = $data['coupon_discount']<$pay_price?$data['coupon_discount']:$pay_price;
+
+ $data['coupon_discount'] = round($data['coupon_discount'],2);
+
+ $data['coupon_id'] = !empty($coupon)?$coupon['id']:0;
+
+ return $data;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 15:39
+ * @功能说明:毁掉
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ Db::startTrans();
+
+ $update = [
+
+ 'pay_time' => time(),
+
+ 'pay_type' => 2,
+
+ 'transaction_id' => $transaction_id
+ ];
+
+ $this->dataUpdate(['id'=>$order['id']],$update);
+ //扣除余额
+ if($order['balance']>0){
+
+ $water_model = new \app\farm\model\BalanceWater();
+
+ $res = $water_model->addWater($order,6,0);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ }
+ //添加流水
+ $water_model = new FinanceWater();
+
+ $water_model->addWater($order['id'],3,1,1);
+ //分销
+ $cash_model = new DistributionCash();
+
+ $cash_model->addUserCash($order,2);
+
+ Db::commit();
+
+ $order['pay_time'] = $update['pay_time'];
+ //发送订阅消息
+ $this->paySendService($order);
+
+ $sys_model = new PushMsgModel($order['uniacid']);
+
+ $sys_model->sendMsg($order,5);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发送订阅消息
+ */
+ public function paySendService($order){
+
+ $user_model = new User();
+ //获取用户的open_id
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'land/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$order['uniacid'],'tmpl_name'=>'land_order'])->find();
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+ return true;
+ }else{
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+ //模版类容
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+
+ return true;
+ }
+
+ $seed_model = new LandOrderSeed();
+
+ $seed_name = $seed_model->where(['order_id'=>$order['id']])->column('title');
+
+ $seed_name = !empty($seed_name)?implode(',',$seed_name):'';
+
+ $order['goods_name'] = mb_substr($order['goods_name'],0,10);
+
+ $seed_name = mb_substr($seed_name,0,10);
+ //发送内容
+ $send_data = array(
+
+ $key_worlds[1]=>array(
+ //商品名称
+ 'value'=> $order['order_code'],
+ ),
+ $key_worlds[2]=>array(
+ //种子明显
+ 'value'=> $order['goods_name'],
+ ),
+ $key_worlds[3]=>array(
+ //支付金额
+ 'value'=>!empty($seed_name)?$seed_name:'无',
+ ),
+ $key_worlds[4]=>array(
+ //商品价格
+ 'value'=>$order['pay_price'].'元',
+
+ ),
+ $key_worlds[5]=>array(
+ //支付时间
+ 'value'=>date('Y-m-d H:i:s',$order['pay_time']),
+ ),
+ );
+
+ // dump($send_data);exit;
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:超时自动退款
+ */
+ public function autoCancelOrder($uniacid,$user_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',1];
+
+ $dis[] = ['over_time','<',time()];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->cancelOrder($value);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:退款
+ */
+ public function cancelOrder($order){
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$order['id'],'pay_type'=>1],['pay_type'=>-1]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'取消失败'];
+ }
+
+ $land_model = new LandList();
+
+ $land_model->where(['id'=>$order['land_id']])->update(['sale_num'=>Db::Raw('sale_num-1')]);
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-14 09:55
+ * @功能说明:修改到期订单的状态
+ */
+ public function orderInit($user_id=0){
+
+ $dis[] = ['pay_type','=',2];
+
+ $dis[] = ['end_time','<',time()];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $list = $this->where($dis)->select()->toArray();
+
+ $integral_model = new IntegralLog();
+
+ $distributionCash_model = new DistributionCash();
+
+ if(!empty($list)){
+
+ foreach ($list as $value){
+
+ Db::startTrans();
+
+ $update = [
+
+ 'pay_type' => 7
+ ];
+
+ $this->dataUpdate(['id'=>$value['id']],$update);
+ //添加积分
+ $integral_model->integralUserAdd($value['user_id'],$value['get_integral'],$value['uniacid'],2,4,$value['id'],0,$value);
+ //分销
+ $res = $distributionCash_model->cashArrival($value,2);
+
+ if($res==false){
+
+ Db::rollback();
+ }
+
+ Db::commit();
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:后台下单列表
+ * @author chenniang
+ * @DataTime: 2022-02-16 14:05
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_order_address b','a.id = b.order_id AND b.type=1','left')
+ ->where($dis)
+ ->field('a.*,b.user_name,b.mobile')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:后台下单列表
+ * @author chenniang
+ * @DataTime: 2022-02-16 14:05
+ */
+ public function adminDataSelect($dis){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_order_address b','a.id = b.order_id AND b.type=1','left')
+ ->where($dis)
+ ->field('a.*,b.user_name,b.mobile')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-28 15:05
+ * @功能说明:添加商品时溯源下拉框
+ */
+ public function goodsSourceSelect($user_id){
+
+ $dis[] = ['a.user_id','=',$user_id];
+
+ $dis[] = ['a.pay_type','>',1];
+
+ $order_source = $this->alias('a')
+ ->join('lbfarm_land_order_seed b','a.id = b.order_id')
+ ->where($dis)
+ ->column('source_id');
+
+ $source_model = new Source();
+
+ $where[] = ['user_id','=',$user_id];
+
+ $where[] = ['status','in',[2,3]];
+
+ $where[] = ['type','=',1];
+
+ $farmer_model = new Farmer();
+ //如果自己是农场主
+ $farmer_id = $farmer_model->where($where)->value('id');
+
+ if(!empty($farmer_id)){
+
+ $dis = [
+
+ 'farmer_id' => $farmer_id,
+
+ 'status' => 1
+
+ ];
+
+ $source = $source_model->where($dis)->column('id');
+
+ $order_source = array_merge($order_source,$source);
+ }
+
+ return $order_source;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-09 17:45
+ * @功能说明:土地到期提醒
+ */
+ public function landOverService($uniacid){
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->dataInfo(['uniacid'=>$uniacid,'tmpl_name'=>'land_over']);
+
+ $push_model = new PushMsgModel($uniacid);
+
+ $dis[] = ['pay_type','>',1];
+
+ $dis[] = ['have_notice','=',0];
+
+ $dis[] = ['end_time','<',time()+10*86400];
+
+ $list = $this->where($dis)->select()->toArray();
+
+ if(!empty($list)){
+
+ foreach ($list as $value){
+
+ $this->dataUpdate(['id'=>$value['id']],['have_notice'=>1]);
+
+ if(!empty($tmpl)){
+
+ $this->overService($value,$tmpl);
+ }
+
+ $push_model->sendMsg($value,9);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发送订阅消息
+ */
+ public function overService($order,$tmpl){
+
+ $this->dataUpdate(['id'=>$order['id']],['have_notice'=>1]);
+
+ $user_model = new User();
+ //获取用户的open_id
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'land/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+ //模版类容
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+
+ return true;
+ }
+ //发送内容
+ $send_data = array(
+
+ $key_worlds[1]=>array(
+ //商品名称
+ 'value'=> $order['goods_name'],
+ ),
+ $key_worlds[2]=>array(
+ //到期时间
+ 'value'=> date('Y-m-d H:i',$order['end_time']),
+ ),
+ $key_worlds[3]=>array(
+ //商品价格
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[4]=>array(
+ //支付金额
+ 'value'=> '你的土地将到期,请注意管理',
+ )
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandOrderSeed.php b/app/farm/model/LandOrderSeed.php
new file mode 100755
index 0000000..0add490
--- /dev/null
+++ b/app/farm/model/LandOrderSeed.php
@@ -0,0 +1,272 @@
+where(['id'=>$data['seed_id']])->value('send_tmpl_id');
+
+ return $id;
+ }
+
+ }
+
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总重量
+ * @author chenniang
+ * @DataTime: 2022-08-04 11:23
+ */
+ public function getTotalWeightAttr($value,$data){
+
+ if(isset($data['output_value'])&&isset($data['area'])){
+
+ return round($data['output_value']*$data['area'],2);
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-14 10:11
+ * @功能说明:溯源
+ */
+ public function getSourceAttr($value,$data){
+
+ if(!empty($data['source_id'])){
+
+ $source_model = new Source();
+
+ $source = $source_model->dataInfo(['id'=>$data['source_id']]);
+
+ return $source;
+
+ }
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);;
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-21 16:52
+ * @功能说明:添加订单种子
+ */
+ public function orderSeedAdd($data,$order_id){
+
+ $seed_model = new Seed();
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $insert = [
+
+ 'uniacid' => $v['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'title' => $v['title'],
+
+ 'imgs' => !empty($v['imgs'][0])?$v['imgs'][0]:'',
+
+ 'output_value' => $v['output_value'],
+
+ 'month' => implode(',',$v['month']),
+
+ 'area' => $v['area'],
+
+ 'grow_cycle' => $v['grow_cycle'],
+
+ 'picking_cycle'=> $v['picking_cycle'],
+
+ 'seed_cycle' => $v['seed_cycle'],
+
+ 'seed_price' => $v['seed_price'],
+
+ 'num' => $v['num'],
+
+ 'seed_id' => $v['id'],
+
+ 'source_id' => $v['source_id'],
+
+ 'total_price' => round($v['num']*$v['seed_price'],2),
+
+ ];
+
+ $this->insert($insert);
+
+ $seed_model->updateSaleNum($v['id'],$v['num']);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-04 14:00
+ * @功能说明:获取配送飞
+ */
+ public function getSendPrice($address_id,$order_id,$times=0){
+
+ if($times>0){
+
+ return 0;
+ }
+
+ $list = $this->where(['order_id'=>$order_id])->field('*,num as goods_num')->select()->toArray();
+
+ $config_model = new Config();
+
+ $price = $config_model->getTotalSendPrice($address_id,$list,2);
+
+ return $price;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 15:39
+ * @功能说明:毁掉
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ $update = [
+
+ 'pay_time' => time(),
+
+ 'pay_type' => 2,
+
+ 'transaction_id' => $transaction_id
+ ];
+
+ $this->dataUpdate(['id'=>$order['id']],$update);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-11 16:02
+ * @功能说明:订单种子
+ */
+ public function orderSeed($order_id){
+
+ $data = $this->where(['order_id'=>$order_id])->select()->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandSourceText.php b/app/farm/model/LandSourceText.php
new file mode 100755
index 0000000..be89aee
--- /dev/null
+++ b/app/farm/model/LandSourceText.php
@@ -0,0 +1,111 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:07
+ * @功能说明:
+ */
+ public function eventClaim($id,$data){
+
+ $this->where(['obj_id'=>$id,'type'=>2])->delete();
+
+ if(!empty($data['source'])){
+
+ foreach ($data['source'] as $k => $v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'obj_id' => $id,
+
+ 'source_id'=> $v,
+
+ 'type' => 2
+ ];
+
+ }
+
+ $this->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandSpe.php b/app/farm/model/LandSpe.php
new file mode 100755
index 0000000..33ee993
--- /dev/null
+++ b/app/farm/model/LandSpe.php
@@ -0,0 +1,126 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:15
+ * @功能说明:
+ */
+ public function eventLand($id,$data){
+
+ $this->where(['land_id'=>$id])->delete();
+
+ if(!empty($data['spe'])){
+
+ foreach ($data['spe'] as $k=>$v){
+
+ $v['uniacid'] = $data['uniacid'];
+
+ $v['land_id'] = $id;
+
+ $this->insert($v);
+
+ }
+
+ }
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:47
+ * @功能说明:认养分类
+ */
+ public function claimCateList($dis){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_land_cate_text b','a.id = b.cate_id')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc.a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/LandText.php b/app/farm/model/LandText.php
new file mode 100755
index 0000000..634cec6
--- /dev/null
+++ b/app/farm/model/LandText.php
@@ -0,0 +1,143 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $data
+ * @功能说明:1地块服务 2关联种子 3关联溯源 4关联监控
+ * @author chenniang
+ * @DataTime: 2021-12-20 15:48
+ */
+ public function eventLand($id,$data){
+
+ $arr = [
+
+ 1 => 'massif',
+
+ 2 => 'seed',
+
+// 3 => 'source',
+
+ 4 => 'monitor',
+
+ 5 => 'cycle'
+ ];
+
+ foreach ($arr as $k=>$v){
+
+ if(key_exists($v,$data)){
+
+ $this->updateSome($id,$data['uniacid'],$data[$v],$k);
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-10 17:15
+ * @功能说明:1 地块服务 2关联种子 3关联溯源 4关联监控
+ *
+ *
+ */
+ public function updateSome($id,$uniacid,$data,$type){
+
+ $this->where(['uniacid'=>$uniacid,'type'=>$type,'land_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $uniacid,
+
+ 'land_id' => $id,
+
+ 'obj_id' => $v,
+
+ 'type' => $type,
+
+ // 'source_id' => $type==2?$v['source_id']:0,
+
+ ];
+
+ }
+
+ $this->saveAll($insert);
+ }
+
+ return true;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Machine.php b/app/farm/model/Machine.php
new file mode 100755
index 0000000..ebea079
--- /dev/null
+++ b/app/farm/model/Machine.php
@@ -0,0 +1,186 @@
+ $data['farmer_id'],
+
+ ];
+
+ $farmer_model = new Farmer();
+
+ $name = $farmer_model->where($dis)->where('status','in',[2,3])->value('title');
+
+ return $name;
+
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis,$file='*'){
+
+ $data = $this->where($dis)->field($file)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-21 17:58
+ * @功能说明:远程获取仪器的数据
+ */
+ public function getDataInfo($land_id,$type=1){
+
+ $model = $type==1?new LandList():new Claim();
+
+ $id = $model->where(['id'=>$land_id])->value('machine_id');
+
+ $data = $this->dataInfo(['id'=>$id]);
+
+ if(empty($data)){
+
+ return [];
+ }
+
+ $mac_model = new PospalApi();
+
+ $room = $mac_model->getRoomInfo($data['room_id']);
+
+ if($room['result']!='success'){
+
+ return [];
+ }
+
+ $server_time = $room['server_time'];
+
+ foreach ($room['channel'] as $key=>$value){
+
+ if(is_string($value)&&strpos($key,'field') !== false){
+
+ $arr[$key]['field'] = $key;
+
+ $arr[$key]['text'] = $value;
+
+ }
+
+ }
+
+ $last_value = json_decode($room['channel']['last_values'],true);
+
+ if(!empty($arr)){
+
+ foreach ($arr as $k=>$v){
+
+ $arr[$k]['value'] = isset($last_value[$v['field']])?$last_value[$v['field']]['value']:'';
+ }
+ }
+
+ $list['server_time'] = $server_time;
+
+ $list['data'] = array_values(array_values($arr));
+
+ return $list;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Massif.php b/app/farm/model/Massif.php
new file mode 100755
index 0000000..190fca4
--- /dev/null
+++ b/app/farm/model/Massif.php
@@ -0,0 +1,164 @@
+where(['massif_id'=>$data['id']])->select()->toArray();
+
+ return $list;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(!empty($data['service'])){
+
+ $service = $data['service'];
+
+ unset($data['service']);
+ }
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(!empty($service)){
+
+ $this->updateSome($id,$service,$data['uniacid']);
+
+ }
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-20 16:38
+ * @功能说明:
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $service_model = new MassifService();
+
+ $service_model->where(['massif_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $v['massif_id'] = $id;
+
+ $v['uniacid'] = $uniacid;
+
+ $service_model->insert($v);
+
+ }
+
+ }
+
+ return true;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(!empty($data['service'])){
+
+ $service = $data['service'];
+
+ unset($data['service']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($service)){
+
+ $this->updateSome($dis['id'],$service,$data['uniacid']);
+
+ }
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/MassifService.php b/app/farm/model/MassifService.php
new file mode 100755
index 0000000..4816b30
--- /dev/null
+++ b/app/farm/model/MassifService.php
@@ -0,0 +1,76 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Monitor.php b/app/farm/model/Monitor.php
new file mode 100755
index 0000000..f237bf0
--- /dev/null
+++ b/app/farm/model/Monitor.php
@@ -0,0 +1,168 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:07
+ * @功能说明:
+ */
+ public function eventClaim($id,$data){
+
+ $this->where(['obj_id'=>$id,'type'=>2])->delete();
+
+ if(!empty($data['monitor'])){
+
+ foreach ($data['monitor'] as $k => $v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'obj_id' => $id,
+
+ 'monitor_id'=> $v,
+
+ 'type' => 2
+ ];
+
+ }
+
+ $this->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 14:28
+ * @功能说明:获取监控地址
+ */
+ public function getVideoUrl($id){
+
+ $dis = [
+
+ 'id' => $id
+ ];
+
+ $data = $this->dataInfo($dis);
+ Log::write($data);
+ Log::write('122');
+ if(empty($data)){
+
+ return [];
+ }
+
+ $this->dataUpdate($dis,['iv'=>$data['iv']+1]);
+
+ $api = new YsCloudApi($data['uniacid']);
+
+ $url = $api->getVideoInfo($data['deviceSerial'],$data['channelNo']);
+ Log::write('获取视频地址:'.$url);
+ return $url;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-04-11 15:57
+ * @功能说明:农场监控列表
+ */
+ public function farmerMonitorList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_farmer b','a.farmer_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.address')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/farm/model/MonitorText.php b/app/farm/model/MonitorText.php
new file mode 100755
index 0000000..6ada2d6
--- /dev/null
+++ b/app/farm/model/MonitorText.php
@@ -0,0 +1,110 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 16:07
+ * @功能说明:
+ */
+ public function eventClaim($id,$data){
+
+ $this->where(['obj_id'=>$id,'type'=>2])->delete();
+
+ if(!empty($data['monitor'])){
+
+ foreach ($data['monitor'] as $k => $v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'obj_id' => $id,
+
+ 'monitor_id'=> $v,
+
+ 'type' => 2
+ ];
+
+ }
+
+ $this->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Node.php b/app/farm/model/Node.php
new file mode 100755
index 0000000..ef237f8
--- /dev/null
+++ b/app/farm/model/Node.php
@@ -0,0 +1,92 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/OrderAddress.php b/app/farm/model/OrderAddress.php
new file mode 100755
index 0000000..39d7c56
--- /dev/null
+++ b/app/farm/model/OrderAddress.php
@@ -0,0 +1,162 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-21 14:48
+ * @功能说明:添加订单地址
+ */
+ public function orderAddressAdd($address_id,$order_id,$send_type=2,$type=1,$address_data=[]){
+
+ $address_model = new Address();
+
+ if($send_type==2){
+
+ $address = $address_model->dataInfo(['id'=>$address_id]);
+
+ }else{
+
+ $address = $address_data;
+
+ }
+
+ if(empty($address)){
+
+ return ['code'=>500,'msg'=>'地址未找到'];
+ }
+
+ $insert = [
+
+ 'uniacid' => $address['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'user_name'=> !empty($address['user_name'])?$address['user_name']:'',
+
+ 'mobile' => !empty($address['mobile'])?$address['mobile']:'',
+
+ 'province' => !empty($address['province'])?$address['province']:'',
+
+ 'city' => !empty($address['city'])?$address['city']:'',
+
+ 'area' => !empty($address['area'])?$address['city']:'',
+
+ 'lng' => !empty($address['lng'])?$address['lng']:'',
+
+ 'lat' => !empty($address['lat'])?$address['lat']:'',
+
+ 'address' => !empty($address['address'])?$address['address']:'',
+
+ 'address_info' => !empty($address['address_info'])?$address['address_info']:'',
+
+ 'type' => $type,
+
+ 'send_type'=> $send_type,
+
+ 'address_id'=> $address_id,
+
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'下单失败'];
+
+ }
+
+ return $res;
+
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/PayConfig.php b/app/farm/model/PayConfig.php
new file mode 100755
index 0000000..eff0715
--- /dev/null
+++ b/app/farm/model/PayConfig.php
@@ -0,0 +1,83 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Role.php b/app/farm/model/Role.php
new file mode 100755
index 0000000..482659a
--- /dev/null
+++ b/app/farm/model/Role.php
@@ -0,0 +1,152 @@
+insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($node)){
+
+ $this->updateSome($node,$id,$data['uniacid']);
+ }
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-04 14:10
+ * @功能说明:添加权限节点
+ */
+ public function updateSome($data,$id,$uniacid){
+
+ $node_model = new Node();
+
+ $node_model->where(['role_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $data[$k]['uniacid'] = $uniacid;
+
+ $data[$k]['role_id'] = $id;
+
+ $data[$k]['auth'] = !empty($v['auth'])?implode(',',$v['auth']):'';
+
+ }
+
+ $node_model->saveAll($data);
+
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['node'])){
+
+ $node = $data['node'];
+
+ unset($data['node']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($node)){
+
+ $this->updateSome($node,$dis['id'],$data['uniacid']);
+
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Seed.php b/app/farm/model/Seed.php
new file mode 100755
index 0000000..e62914a
--- /dev/null
+++ b/app/farm/model/Seed.php
@@ -0,0 +1,323 @@
+ $data['id'],
+
+ 'type' => 1
+ ];
+
+ $list = $source_model->alias('a')
+ ->join('lbfarm_source b','b.id = a.source_id')
+ ->where($dis)
+ ->field('a.*,b.title')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 10:08
+ * @功能说明:月份
+ */
+ public function getMonthAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $month_model = new SeedMonth();
+
+ $list = $month_model->where(['seed_id'=>$data['id']])->column('month');
+
+ return array_values($list);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 16:54
+ * @功能说明:
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['imgs'] = !empty($data['imgs'])?implode(',',$data['imgs']):'';
+
+ $data['create_time'] = time();
+
+ if(isset($data['month'])){
+
+ $month = $data['month'];
+
+ unset($data['month']);
+ }
+
+ if(isset($data['source_id'])){
+
+ $source_id = $data['source_id'];
+
+ unset($data['source_id']);
+ }
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($month)){
+
+ $this->updateSome($month,$id,$data['uniacid']);
+ }
+
+ return $id;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 10:03
+ * @功能说明:添加种子月份
+ */
+ public function updateSome($data,$id,$uniacid,$seed=[]){
+
+ $month_model = new SeedMonth();
+
+ $month_model->where(['seed_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $season = ceil($v/3);
+
+ $insert[$k]=[
+
+ 'uniacid' => $uniacid,
+
+ 'seed_id' => $id,
+
+ 'month' => $v,
+
+ 'season' => $season
+ ];
+
+ }
+
+ $month_model->saveAll($insert);
+ }
+
+ $soruce_model = new LandSourceText();
+
+ $soruce_model->where(['obj_id'=>$id,'type'=>1])->delete();
+
+ if(!empty($seed)){
+
+ foreach ($seed as $key=>$value){
+
+ $insertdata[$key] = [
+
+ 'uniacid' => $uniacid,
+
+ 'obj_id' => $id,
+
+ 'source_id' => $value,
+
+ 'type' => 1
+ ];
+
+ }
+
+ $soruce_model->saveAll($insertdata);
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['month'])){
+
+ $month = $data['month'];
+
+ unset($data['month']);
+ }
+
+ if(isset($data['source_id'])){
+
+ $source_id = $data['source_id'];
+
+ unset($data['source_id']);
+ }
+
+ if(!empty($data['imgs'])){
+
+ $data['imgs'] = implode(',',$data['imgs']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($month)){
+
+ $this->updateSome($month,$dis['id'],$data['uniacid'],[]);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-01-07 10:31
+ * @功能说明:列表
+ */
+ public function indexDataList($dis,$sort,$page = 10){
+
+ switch ($sort){
+
+ case 1:
+
+ $order = 'a.id desc';
+
+ break;
+
+ default:
+
+ $order = 'a.sale_num desc,a.id desc';
+
+ break;
+
+ }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_seed_month b','a.id = b.seed_id','left')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order($order)
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-16 13:39
+ * @功能说明:修改库存
+ */
+ public function updateSaleNum($seed_id,$num,$type=1){
+ //加销量
+ if($type==1){
+
+ $res = $this->where(['id'=>$seed_id])->update(['sale_num'=>Db::Raw("sale_num+$num")]);
+
+ }else{
+
+ $res = $this->where(['id'=>$seed_id])->update(['sale_num'=>Db::Raw("sale_num-$num")]);
+
+ }
+
+ return $res;
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/SeedMonth.php b/app/farm/model/SeedMonth.php
new file mode 100755
index 0000000..1b0a83e
--- /dev/null
+++ b/app/farm/model/SeedMonth.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/SendConfig.php b/app/farm/model/SendConfig.php
new file mode 100755
index 0000000..4bcaefe
--- /dev/null
+++ b/app/farm/model/SendConfig.php
@@ -0,0 +1,83 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/SendOrder.php b/app/farm/model/SendOrder.php
new file mode 100755
index 0000000..7b61dee
--- /dev/null
+++ b/app/farm/model/SendOrder.php
@@ -0,0 +1,547 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);;
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 15:45
+ * @功能说明:添加关联
+ */
+ public function updateSome($id,$data){
+
+ $server = new \app\farm\server\Claim();
+
+ $claim_text_model = new ClaimText();
+
+ $source_text_model= new LandSourceText();
+
+ $monitor_text_model= new MonitorText();
+
+ $server->addObserver($claim_text_model);
+
+ $server->addObserver($source_text_model);
+
+ $server->addObserver($monitor_text_model);
+
+ $server->notify($id,$data);
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-16 15:39
+ * @功能说明:回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ $update = [
+
+ 'pay_time' => time(),
+
+ 'pay_type' => 2,
+
+ 'transaction_id' => $transaction_id
+ ];
+
+ $this->dataUpdate(['id'=>$order['id']],$update);
+ //扣除余额
+ if($order['balance']>0){
+
+ $water_model = new BalanceWater();
+
+ $type = $order['type']==1?3:9;
+
+ $res = $water_model->addWater($order,$type,0);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ }
+ //添加流水
+ $water_model = new FinanceWater();
+ //1认养 2土地
+ $water_type = $order['type']==1?10:14;
+
+ $water_model->addWater($order['id'],$water_type,1,0);
+
+ $this->paySendMsg($order);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 09:51
+ * @功能说明:公众号给农场主发送通知
+ */
+ public function paySendMsg($order){
+
+ $uniacid = $order['uniacid'];
+
+ $x_config = longbingGetAppConfig($uniacid);
+
+ if(empty($x_config['gzh_appid'])||empty($x_config['gzh_tplid'])){
+
+ return false;
+ }
+
+ $farmer_model = new Farmer();
+
+ $user_id = $farmer_model->where(['id'=>$order['farmer_id']])->value('user_id');
+
+ if(empty($user_id)){
+
+ return false;
+ }
+
+ $user_model = new User();
+
+ $openid = $user_model->where(['id'=>$user_id])->value('openid');
+
+ $access_token = longbingGetAccessToken($uniacid);
+
+ $page =$order['type']==1?"claim/pages/order/detail?id=".$order['id']."&tab=2¬ice=1":"land/pages/order/detail?id=".$order['id']."&tab=2¬ice=1";
+ //post地址
+ $url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token={$access_token}";
+
+ $data = [
+ //用户小程序openid
+ 'touser' => $openid,
+
+ 'mp_template_msg' => [
+ //公众号appid
+ 'appid' => $x_config['gzh_appid'],
+
+ "url" => "http://weixin.qq.com/download",
+ //公众号模版id
+ 'template_id' => $x_config['gzh_tplid'],
+
+ 'miniprogram' => [
+ //小程序appid
+ 'appid' => $x_config['appid'],
+ //跳转小程序地址
+ 'page' => $page,
+ ],
+ 'data' => array(
+
+// 'first' => array(
+//
+// 'value' => $store_name.'技师,您有一笔新的订单',
+//
+// 'color' => '#93c47d',
+// ),
+ //服务名称
+ 'keyword1' => array(
+
+ 'value' => $order['order_code'],
+
+ 'color' => '#93c47d',
+ ),
+ //下单人
+ 'keyword2' => array(
+ //内容
+ 'value' => date('Y-m-d H:i',$order['start_time']).'~'.date('Y-m-d H:i',$order['end_time']),
+
+ 'color' => '#0000ff',
+ ),
+ 'keyword3' => array(
+ //内容
+ 'value' => $order['text'],
+
+ 'color' => '#0000ff',
+ )
+
+ )
+ ],
+ ];
+
+ $data = json_encode($data);
+
+ $tmp = [
+
+ 'url' => $url,
+
+ 'data' => $data,
+ ];
+ $rest = lbCurlPost($tmp['url'], $tmp['data']);
+
+ $rest = json_decode($rest, true);
+
+ return $rest;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-09 13:45
+ * @功能说明:订单收货
+ */
+ public function sendOrderReceiving($order,$hx_user=0,$hx_admin=0,$hx_time=0){
+
+ $order_id = $order['id'];
+
+ $update = [
+
+ 'pay_type' => 7,
+
+ 'receiving_time' => !empty($hx_time)?$hx_time:time(),
+
+ 'hx_user' => $hx_user,
+
+ 'hx_admin' => $hx_admin
+ ];
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$order_id],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'收货失败'];
+ }
+
+ $water_model = new FinanceWater();
+
+ $water_type = $order['type']==1?10:14;
+
+ $dis = [
+
+ 'type' => $water_type,
+
+ 'order_id' => $order_id
+ ];
+ //将流水记录修改为可提现状态
+ $res = $water_model->dataUpdate($dis,['cash_status'=>1]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'收货失败1'];
+ }
+ //暂时只执行认养配送的
+ if($order['type']==1){
+
+ $order_model = $order['type']==1?new ClaimOrder():new LandOrder();
+ //有可能是自提
+ $order_model->dataUpdate(['id'=>$order['order_id']],['pay_type'=>3]);
+
+ $top_order = $order_model->dataInfo(['id'=>$order['order_id']]);
+
+ $count = $this->where(['order_id'=>$order['order_id'],'type'=>$order['type'],'pay_type'=>7])->count();
+
+ if($count>=$top_order['send_times']){
+
+ $order_model->dataUpdate(['id'=>$top_order['id']],['pay_type'=>7]);
+ }
+
+ }
+
+ $i_type = $order['type']==1?8:9;
+
+ $integral_model = new IntegralLog();
+ //赠送积分
+ $integral_model->integralUserAdd($order['user_id'],$order['get_integral'],$order['uniacid'],2,$i_type,$order['id']);
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:超时自动退款
+ */
+ public function autoCancelOrder($uniacid,$user_id=0){
+
+ $where[] = ['uniacid','=',$uniacid];
+
+ $where[] = ['pay_type','=',3];
+
+ $where[] = ['auto_receiving_time','<',time()];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $order = $this->where($where)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->sendOrderReceiving($value,0,0,$value['auto_receiving_time']);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:退款
+ */
+ public function cancelOrder($order){
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$order['id'],'pay_type'=>1],['pay_type'=>-1,'cancel_time'=>time()]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'取消失败'];
+ }
+
+ $claim_model = new Claim();
+
+ $claim = $claim_model->dataInfo(['id'=>$order['goods_id']]);
+ //加销量减库存
+ $update = [
+
+ 'stock' => $claim['stock'] +1,
+
+ 'sale_num' => $claim['sale_num']-1,
+
+ 'lock' => $claim['lock']+1
+
+ ];
+
+ $res = $claim_model->dataUpdate(['id'=>$claim['id'],'lock'=>$claim['lock']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'取消失败'];
+
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $order_id
+ * @param $type 1认养 2土地
+ * @功能说明:指定订单的配送订单
+ * @author chenniang
+ * @DataTime: 2022-02-16 14:37
+ */
+ public function orderSendOrder($order_id,$type=1,$page=10){
+
+ $dis[] = ['order_id','=',$order_id];
+
+ $dis[] = ['pay_time','>',0];
+
+ $dis[] = ['type','=',$type];
+
+ $send_order_model = new SendOrder();
+
+ $data = $send_order_model->dataList($dis,$page);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['time_text'] = date('Y-m-d H:i',$v['start_time']).'~'.date('H:i',$v['end_time']);
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ $v['pay_time'] = $v['pay_time']>0?date('Y-m-d H:i:s',$v['pay_time']):0;
+
+ $v['send_time'] = $v['send_time']>0?date('Y-m-d H:i:s',$v['send_time']):0;
+
+ $v['receiving_time'] = $v['receiving_time']>0?date('Y-m-d H:i:s',$v['receiving_time']):0;
+
+ $v['refund_time'] = $v['refund_time']>0?date('Y-m-d H:i:s',$v['refund_time']):0;
+ }
+ }
+ $dis = [
+
+ 'order_id' => $order_id,
+
+ 'type' => $type
+ ];
+ //已经申请的配送次数
+ $data['send_count'] = $send_order_model->where($dis)->where('pay_type','>',1)->count();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @param $order
+ * @功能说明:配送订单退款
+ * @author chenniang
+ * @DataTime: 2022-08-22 10:47
+ */
+ public function refundCash($send_order,$payConfig){
+
+ if($send_order['send_type']==1||$send_order['pay_price']<=0){
+
+ return true;
+
+ }
+
+ if($send_order['pay_model']==1){
+
+ $response = orderRefundApi($payConfig,$send_order['pay_price'],$send_order['pay_price'],$send_order['transaction_id']);
+
+ if ( isset( $response[ 'return_code' ] ) && isset( $response[ 'result_code' ] ) && $response[ 'return_code' ] == 'SUCCESS' && $response[ 'result_code' ] == 'SUCCESS' ) {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no'])?$response['out_refund_no']:$send_order['order_code'];
+
+ $this->dataUpdate(['id'=>$send_order['id']],['refund_code'=>$response['out_refund_no']]);
+
+ }else {
+ //失败就报错
+ $discption = !empty($response['err_code_des'])?$response['err_code_des']:$response['return_msg'];
+
+ return ['code'=>500,'msg'=>$discption];
+
+ }
+
+ }elseif ($send_order['pay_model']==2){
+
+ $water_model = new BalanceWater();
+
+ $res = $water_model->addWater($send_order,4,1);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'退款失败2'];
+
+ }
+ }else{
+ //支付宝
+ $pay_model = new PayModel($payConfig);
+
+ $res = $pay_model->aliRefund($send_order['transaction_id'],$send_order['pay_price']);
+
+ if(isset($res['alipay_trade_refund_response']['code'])&&$res['alipay_trade_refund_response']['code']==10000){
+
+ $this->dataUpdate(['id'=>$send_order['id']],['refund_code'=>$res['alipay_trade_refund_response']['out_trade_no']]);
+
+ }else{
+
+ return ['code'=>500,'msg'=> $res['alipay_trade_refund_response']['sub_msg']];
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ShopGoods.php b/app/farm/model/ShopGoods.php
new file mode 100755
index 0000000..26be5f1
--- /dev/null
+++ b/app/farm/model/ShopGoods.php
@@ -0,0 +1,602 @@
+ 1,
+
+ 'a.goods_id' => $data['id'],
+
+ 'b.status' => 1
+ ];
+
+ $list = $goods_cate_model->alias('a')
+ ->join('lbfarm_shop_goods_cate b','a.cate_id = b.id')
+ ->where($dis)
+ ->column('b.id');
+
+ return array_values($list);
+
+ }
+
+ }
+
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:获取分类
+ * @author chenniang
+ * @DataTime: 2022-07-13 17:28
+ */
+ public function getStoreAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $store_model = new StoreGoods();
+
+ $dis = [
+
+ 'a.type' => 1,
+
+ 'a.goods_id' => $data['id'],
+
+ 'b.status' => 2,
+
+ 'b.type' => 2,
+ ];
+
+ $list = $store_model->alias('a')
+ ->join('lbfarm_farmer b','a.store_id = b.id')
+ ->where($dis)
+ ->column('b.id');
+
+ return array_values($list);
+
+ }
+
+ }
+
+
+
+// public function getTextAttr($value,$data){
+//
+// if(!empty($value)){
+//
+// return @unserialize($value);
+// }
+//
+// }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-02 14:08
+ * @功能说明:虚拟销量+真实销量
+ */
+ public function getAllSaleCountAttr($value,$data){
+
+ if(isset($data['sale_num'])&&isset($data['true_sale_num'])){
+
+ return $data['sale_num']+$data['true_sale_num'];
+
+ }
+
+ }
+
+
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:12
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 15:13
+ * @功能说明:获取商品的最低价格
+ */
+ public function getShowPriceAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $spe_model = new GoodsSpePrice();
+
+ $list = $spe_model->where(['goods_id'=>$data['id']])->min('price');
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 15:13
+ * @功能说明:获取商品的最低价格
+ */
+ public function getShowInitPriceAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $spe_model = new GoodsSpePrice();
+
+ $list = $spe_model->where(['goods_id'=>$data['id']])->order('price,id desc')->value('original_price');
+
+ return $list;
+
+ }
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 15:13
+ * @功能说明:获取总库存
+ */
+ public function getAllStockAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $spe_model = new GoodsSpePrice();
+
+ $list = $spe_model->where(['goods_id'=>$data['id']])->sum('stock');
+
+ return $list;
+
+ }
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $cate_id = $data['cate_id'];
+
+ unset($data['cate_id']);
+
+ $store = $data['store'];
+
+ unset($data['store']);
+
+ unset($data['specsItem']);
+
+ unset($data['specsTable']);
+
+ $data['imgs'] = implode(',',$data['imgs']);
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$data['uniacid'],$store,$cate_id);
+
+ return $id;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $uniacid
+ * @param $spe
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 13:35
+ */
+ public function updateSome($id,$uniacid,$store,$cate){
+
+ $store_model = new StoreGoods();
+
+ $goods_cate_model = new GoodsCate();
+
+ $store_model->where(['type'=>1,'goods_id'=>$id])->delete();
+
+ $goods_cate_model->where(['type'=>1,'goods_id'=>$id])->delete();
+
+ if(!empty($store)){
+
+ foreach ($store as $ks=>$vs){
+
+ $insert[$ks] = [
+
+ 'goods_id' => $id,
+
+ 'uniacid' => $uniacid,
+
+ 'store_id' => $vs
+ ];
+
+ }
+
+ $store_model->saveAll($insert);
+ }
+
+ if(!empty($cate)){
+
+ foreach ($cate as $ks=>$vs){
+
+ $inserts[$ks] = [
+
+ 'goods_id' => $id,
+
+ 'uniacid' => $uniacid,
+
+ 'cate_id' => $vs
+ ];
+
+ }
+
+ $goods_cate_model->saveAll($inserts);
+ }
+
+
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function goodsUpdate($dis,$data){
+
+ $cate_id = $data['cate_id'];
+
+ unset($data['cate_id']);
+
+ $store = $data['store'];
+
+ unset($data['store']);
+
+ unset($data['specsItem']);
+
+ unset($data['specsTable']);
+
+ $data['imgs'] = implode(',',$data['imgs']);
+
+ $res = $this->where($dis)->update($data);
+
+ $this->updateSome($dis['id'],$data['uniacid'],$store,$cate_id);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-04 11:44
+ * @功能说明:
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-13 17:03
+ * @功能说明:商城列表
+ */
+ public function goodsList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_store b','a.id = b.goods_id AND b.type=1','left')
+ ->join('lbfarm_v2_goods_cate c','a.id = c.goods_id AND c.type=1','left')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-13 17:03
+ * @功能说明:商城列表
+ */
+ public function indexGoodsList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_store b','a.id = b.goods_id AND b.type=1')
+ ->join('lbfarm_v2_goods_cate c','a.id = c.goods_id AND c.type=1')
+ ->join('lbfarm_farmer d','b.store_id = d.id')
+ ->where($dis)
+ ->field('a.*,d.title as store_name,d.id as store_id,d.cover as store_cover')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:07
+ * @功能说明:增加|减少库存 增加|减少销量
+ */
+ public function setOrDelStock($goods_id,$spe_id,$num,$type=1,$refund = 0,$integral_id=0,$kill_atv_id=0){
+
+ if(empty($goods_id)){
+
+ return true;
+ }
+
+ $spe_model = new GoodsSpePrice();
+
+ $goods_info = $this->dataInfo(['id'=>$goods_id]);
+
+ $spe_info = $spe_model->dataInfo(['id'=>$spe_id]);
+ //退货
+ if($type==1){
+
+ $update = [
+
+ 'true_sale_num' => $goods_info['true_sale_num']-$num,
+
+ 'lock' => $goods_info['lock']+1,
+
+ ];
+ //如果是售后增加退款数量
+ if($refund==1){
+
+ $update['refund_num'] = $goods_info['refund_num']+$num;
+ }
+ //减销量 加退款数量
+ $res = $this->where(['id'=>$goods_id,'lock'=>$goods_info['lock']])->update($update);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+
+ //增加库存
+ $res = $spe_model->where(['id'=>$spe_id,'lock'=>$spe_info['lock']])->update(['stock'=>$spe_info['stock']+$num,'lock'=>$goods_info['lock']+1]);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+ //积分
+ if(!empty($integral_id)){
+
+ $integral_goods_model = new IntegralGoods();
+
+ $integral_goods_model->updateAtvStock($integral_id,$goods_id,$spe_id,$num,2);
+
+ }
+ //秒杀商品
+ if(!empty($kill_atv_id)){
+
+ $kill_model = new SeckillGoods();
+
+ $kill_model->updateAtvStock($kill_atv_id,$goods_id,$spe_id,$num,2);
+ }
+
+
+ }else{
+ //增加销量
+ $res = $this->where(['id'=>$goods_id,'lock'=>$goods_info['lock']])->update(['true_sale_num'=>$goods_info['true_sale_num']+$num,'lock'=>$goods_info['lock']+1]);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+
+ $now_stock = $spe_info['stock'] - $num;
+
+ if($now_stock<0){
+
+ return ['code'=>500,'msg'=>'库存不足'.$goods_info['goods_name']];
+
+ }
+ //减少库存
+ $res = $spe_model->where(['id'=>$spe_id,'lock'=>$spe_info['lock']])->update(['stock'=>$spe_info['stock']-$num,'lock'=>$goods_info['lock']+1]);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+ //积分
+ if(!empty($integral_id)){
+
+ $integral_goods_model = new IntegralGoods();
+
+ $res = $integral_goods_model->updateAtvStock($integral_id,$goods_id,$spe_id,$num);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+
+ }
+ //秒杀商品
+ if(!empty($kill_atv_id)){
+
+ $kill_model = new SeckillGoods();
+
+ $res = $kill_model->updateAtvStock($kill_atv_id,$goods_id,$spe_id,$num,1);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-25 17:19
+ * @功能说明:
+ */
+ public function saleIngCount($uniacid,$type=1){
+
+ $spe_price_model = new GoodsSpePrice();
+
+ $dis = [];
+
+ $dis[]= ['uniacid','=',$uniacid];
+
+ $sale_type = $type==2?0:1;
+
+ $sale_out_goods = $spe_price_model->getSellOut($uniacid,$sale_type);
+
+ switch ($type){
+
+ case 1:
+ $dis[] = ['status','=',1];
+ break;
+
+ case 2:
+
+ $dis[] = ['status','>',-1];
+ break;
+
+ case 3:
+ $dis[] = ['status','=',0];
+ break;
+
+ }
+
+ $dis[] = ['id','in',$sale_out_goods];
+
+ $data = $this->where($dis)->count();
+
+ return $data;
+ }
+
+
+
+
+}
diff --git a/app/farm/model/ShopGoodsCate.php b/app/farm/model/ShopGoodsCate.php
new file mode 100755
index 0000000..3a6590e
--- /dev/null
+++ b/app/farm/model/ShopGoodsCate.php
@@ -0,0 +1,138 @@
+where(['cate_id'=>$data['id']])->where('status','>',-1)->count();
+
+ return $num;
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-21 15:51
+ * @功能说明:获取商城分类信息
+ */
+ public function shopCateList($uniacid,$store_id=0){
+
+
+ $dis = [
+
+ 'a.uniacid' => $uniacid,
+
+ 'a.status' => 1,
+
+ ];
+
+ if(!empty($store_id)){
+
+ $dis['b.store_id'] = $store_id;
+
+ $dis['b.type'] = 2;
+ }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_goods_store b','a.id = b.goods_id','left')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ShopGoodsSpe.php b/app/farm/model/ShopGoodsSpe.php
new file mode 100755
index 0000000..b2d7719
--- /dev/null
+++ b/app/farm/model/ShopGoodsSpe.php
@@ -0,0 +1,90 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ShopOrder.php b/app/farm/model/ShopOrder.php
new file mode 100755
index 0000000..7dce539
--- /dev/null
+++ b/app/farm/model/ShopOrder.php
@@ -0,0 +1,1183 @@
+dataInfo(['id'=>$data['store_id'],'type'=>2]);
+
+ return $info;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 17:38
+ * @功能说明:
+ */
+ public function getFarmerInfoAttr($value,$data){
+
+ if(!empty($data['farmer_id'])){
+
+ $farmer_model= new Farmer();
+
+ $info = $farmer_model->dataInfo(['id'=>$data['farmer_id'],'type'=>1]);
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-10 17:08
+ * @功能说明:核销人
+ */
+ public function getHxUserNameAttr($value,$data){
+
+ if(isset($data['hx_user'])){
+
+ if(!empty($data['hx_user'])){
+
+ $user_model = new User();
+
+ $name = $user_model->where(['id'=>$data['hx_user']])->value('nickName');
+
+ return $name;
+
+ }else{
+
+ return '自动收货';
+ }
+
+ }
+
+ }
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:地址信息
+ * @author chenniang
+ * @DataTime: 2021-04-08 10:11
+ */
+ public function getAddressInfoAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $address_model = new OrderAddress();
+
+ $address_info = $address_model->dataInfo(['order_id'=>$data['id'],'type'=>5]);
+
+ return $address_info;
+ }
+
+
+ }
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总商品数量
+ * @author chenniang
+ * @DataTime: 2021-03-25 14:39
+ */
+ public function getAllGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $dis = [
+
+ 'order_id' => $data['id']
+ ];
+
+ $num = $order_goods_model->where($dis)->sum('goods_num');
+
+ return $num;
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:05
+ * @功能说明:子订单信息
+ */
+
+ public function getOrderGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $dis = [
+
+ 'order_id' => $data['id']
+ ];
+
+ $list = $order_goods_model->where($dis)->select()->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:40
+ * @功能说明:生产二维码
+ */
+ public function getQrAttr($value,$data){
+
+ if(!empty($value)){
+
+ return $value;
+ }
+
+ if(!empty($data['pay_type'])&&$data['pay_type']>1&&!empty($data['id'])&&!empty($data['uniacid'])){
+
+ $qr_insert = [
+
+ 'id' => $data['id']
+ ];
+
+ $qr = $this->orderQr($qr_insert,$data['uniacid']);
+
+ if(!empty($qr)){
+
+ $this->dataUpdate(['id'=>$data['id']],['qr'=>$qr]);
+
+ return $qr;
+ }
+
+ return '';
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-10-27 15:42
+ * @功能说明:订单自提码
+ */
+ public function orderQr($input,$uniacid){
+
+ $data = longbingCreateWxCode($uniacid,$input,'shop/pages/order/hexiao');
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+// $qr = $data['qr_path'];
+ $qr = '';
+
+ return $qr;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:23
+ * @功能说明:前端订单列表
+ */
+
+ public function indexDataList($dis,$mapor,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods b','a.id = b.order_id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods c','a.id = c.order_id')
+ ->join('lbfarm_order_address d','a.id = d.order_id AND d.type=5')
+ ->where($dis)
+ ->field('a.*,d.mobile,d.user_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataSelect($dis){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods c','a.id = c.order_id')
+ ->join('lbfarm_order_address d','a.id = d.order_id AND d.type=5')
+ ->where($dis)
+ ->field('a.*,d.mobile,d.user_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ if(!empty($data)){
+
+ $user_model = new User();
+
+ foreach ($data as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 14:33
+ * @功能说明:
+ */
+ public function datePrice($date,$uniacid,$cap_id=0,$end_time = '',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['transaction_id','<>',''];
+
+ $dis[] = ['auto_refund','=',0];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('pay_price');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 09:28
+ * @功能说明:计算用户下单时候的各类金额
+ */
+ public function payOrderInfo($user_id,$store_id,$coupon=0,$address_id=0,$is_show=1,$send_type=2,$no_i=1){
+
+ $car_model = new Car();
+ //获取购物车里面的信息
+ $car_list = $car_model->carPriceAndCount($user_id,$store_id,0,$is_show,$no_i);
+
+ $coupon = $car_list['discount_add']==1?$coupon:0;
+
+ $coupon_model = new Coupon();
+
+ $car_list = $coupon_model->orderCouponData($car_list,$coupon,1);
+
+ $config_model = new Config();
+
+ if(!empty($car_list['list'])){
+
+ foreach ($car_list['list'] as &$value){
+
+ if(!empty($address_id)&&$send_type==2){
+
+ $value['distance'] = 0;
+ //计算运费
+ $value['freight'] = $config_model->getTotalSendPrice($address_id,$value['goods_list']);
+
+ }else{
+
+ $value['distance'] = 0;
+
+ $value['freight'] = 0;
+
+ }
+
+ $value['distance_text'] = distance_text($value['distance']);
+ //商品总价格
+ $value['goods_price'] = round($value['car_price'] - $value['coupon_discount'],2);
+
+ // dump(2,$value['goods_price'],$value['freight']);exit;
+ //订单支付价
+ $value['pay_price'] = round($value['goods_price']+$value['freight'] ,2);
+
+ $value['init_goods_price'] = round($value['init_price'] ,2);
+ //订单总价格
+ $value['init_price'] = round($value['init_price']+$value['freight'] ,2);
+
+ }
+ }
+
+ $coupon = !empty($car_list['coupon_id'])?$coupon:0;
+
+ $data['coupon_id'] = $coupon;
+ //购物车列表
+ $data['order_goods'] = $car_list['list'];
+ //商品总价格
+ $data['coupon_discount'] = round(array_sum(array_column($car_list['list'],'coupon_discount')),2);
+
+ $data['goods_price'] = round(array_sum(array_column($car_list['list'],'goods_price')),2);
+
+ $data['init_price'] = round(array_sum(array_column($car_list['list'],'init_price')),2);
+
+ $data['init_goods_price'] = round(array_sum(array_column($car_list['list'],'init_goods_price')),2);
+
+ $data['pay_price'] = round(array_sum(array_column($car_list['list'],'pay_price')),2);
+
+ $data['freight'] = round(array_sum(array_column($car_list['list'],'freight')),2);
+
+ $data['integral'] = $car_list['integral'];
+
+ $data['integral_discount_price'] = $car_list['integral_discount_price'];
+
+ $data['kill_discount_price'] = $car_list['kill_discount_price'];
+
+ $data['discount_add'] = $car_list['discount_add'];
+
+ $data['buy_limit'] = $car_list['buy_limit'];
+
+ $data['car_count'] = $car_list['car_count'];
+
+ $data['kill_atv_id'] = $car_list['kill_atv_id'];
+
+ $data['kill_over_time']= $car_list['kill_over_time'];
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:31
+ * @功能说明:订单支付回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order_list = $this->whereOr(['top_order_code'=>$order_code,'order_code'=>$order_code])->select()->toArray();
+
+ if(!empty($order_list)){
+
+ foreach ($order_list as $order){
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ Db::startTrans();
+
+ $update = [
+
+ 'transaction_id' => $transaction_id,
+
+ 'pay_type' => 2,
+
+ 'pay_time' => time(),
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$order['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return false;
+
+ }
+ //扣除余额
+ if($order['balance']>0){
+
+ $water_model = new BalanceWater();
+
+ $res = $water_model->addWater($order,7,0);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ }
+ //添加流水
+ $water_model = new FinanceWater();
+
+ $water_model->addWater($order['id'],8,2,0);
+ //商城订单农场主获得运费
+ $water_model->addWater($order['id'],16,1,0);
+ //分销
+ $cash_model = new DistributionCash();
+
+ $cash_model->addUserCash($order);
+
+ Db::commit();
+ //发送订阅消息
+ $order['pay_time'] = $update['pay_time'];
+
+ $this->paySendService($order);
+
+ $sys_model = new PushMsgModel($order['uniacid']);
+
+ $sys_model->sendMsg($order,3);
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发送订阅消息
+ */
+ public function sendOrderService($order){
+ //获取用户的open_id
+ $user_model = new User();
+
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'shop/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where([['uniacid','=',$order['uniacid']],['tmpl_name','=','send_order'],['tmpl_id','<>',0]])->find();
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+
+ return true;
+
+ }else{
+
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+// //模版类容
+// $key_worlds = $tmpl['kidList'];
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+ return true;
+ }
+ $order['express_company'] = $service_model::strToUtf8($order['express_company']);
+ //发送内容
+ $send_data = array(
+ $key_worlds[1]=>array(
+ //发货时间物流公司
+ 'value'=>date('Y-m-d H:i:s',$order['send_time']),
+ ),
+ $key_worlds[2]=>array(
+ //订单编号
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[3]=>array(
+ //物流编号
+ 'value'=>$order['express_code'],
+ ),
+ $key_worlds[4]=>array(
+ //
+ 'value'=>$order['express_company'],
+ )
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+ }
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发送订阅消息
+ */
+ public function paySendService($order){
+
+ $user_model = new User();
+ //获取用户的open_id
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'shop/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$order['uniacid'],'tmpl_name'=>'pay_order'])->find();
+
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+ return true;
+ }else{
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+// //模版类容
+// $key_worlds = $tmpl['kidList'];
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+
+ return true;
+ }
+
+ $goods_names = implode(',',array_column($order['order_goods'],'goods_name'));
+
+// $goods_name = msubstr($goods_names,0,18);
+ $goods_name = mb_substr($goods_names,0,18);
+ //发送内容
+ $send_data = array(
+
+ $key_worlds[1]=>array(
+ //商品名称
+ 'value'=> $goods_name,
+ //'value'=>'圣女果小番茄--物流、自提,圣女果小番茄圣女果小番茄',
+ ),
+ $key_worlds[2]=>array(
+ //商品价格
+ 'value'=>$order['pay_price'].'元',
+ ),
+ $key_worlds[3]=>array(
+ //支付金额
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[4]=>array(
+ //支付时间
+ 'value'=>date('Y-m-d H:i:s',$order['pay_time']),
+ ),
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+
+ return true;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:31
+ * @功能说明:团长冻结资金
+ */
+ public function capFrozenPrice($cap_id,$total=0,$toDay=0){
+
+ $dis[] = ['cap_id','=',$cap_id];
+
+ if($total==0){
+
+ $dis[] = ['have_tx','=',0];
+ }
+
+ $dis[] = ['pay_type','>',1];
+
+ if($toDay==1){
+ //当日
+ $price = $this->where($dis)->whereDay('create_time')->sum('cap_price');
+
+ }else{
+
+ $price = $this->where($dis)->sum('cap_price');
+
+ }
+
+ return round($price,2);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:31
+ * @功能说明:团长冻结资金
+ */
+ public function capFrozenCount($cap_id,$total=0,$toDay=0){
+
+ $dis[] = ['cap_id','=',$cap_id];
+
+ if($total==0){
+
+ $dis[] = ['have_tx','=',0];
+ }
+
+ $dis[] = ['pay_type','>',1];
+
+ if($toDay==1){
+ //当日
+ $price = $this->where($dis)->whereDay('create_time')->count();
+
+ }else{
+
+ $price = $this->where($dis)->count();
+
+ }
+
+ return $price;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:41
+ * @功能说明:团长佣金到账
+ */
+ public function capArrPrice($uniacid,$user_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',7];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $dis[] = ['have_tx','=',0];
+
+ $dis[] = ['can_refund_time','<',time()];
+
+ $order = $this->where($dis)->field('id,get_integral,user_id,uniacid,can_refund_time')->select()->toArray();
+
+ if(!empty($order)){
+
+ $refund_model = new ShopRefund();
+
+ $integral_model = new IntegralLog();
+
+ $distributionCash_model = new DistributionCash();
+
+
+ foreach ($order as $value){
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$value['id'],'status'=>1]);
+
+ if(empty($refund_order)){
+
+ Db::startTrans();
+ //修改订单状态
+ $res = $this->where(['id'=>$value['id'],'have_tx'=>0])->update(['have_tx'=>1]);
+ //增加用户积分
+ if($res==1){
+
+ $integral_model->integralUserAdd($value['user_id'],$value['get_integral'],$value['uniacid'],2,1,$value['id'],$value['can_refund_time'],$value);
+
+ $res = $distributionCash_model->cashArrival($value,1);
+
+ if($res==false){
+
+ Db::rollback();
+ }
+
+ }
+
+ Db::commit();
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:15
+ * @功能说明:核销订单
+ */
+ public function hxOrder($order_id,$cap_id=0,$uniacid=1,$time = 0){
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$uniacid]);
+
+ $update = [
+
+ 'hx_time' => !empty($time)?$time:time(),
+
+ 'pay_type'=> 7,
+
+ 'hx_user' => $cap_id,
+ //可申请退款的时间
+ 'can_refund_time' => time()+$config['can_tx_time']*3600
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$order_id],$update);
+ //修改佣金到账状态
+ $water_model = new FinanceWater();
+
+ $dis[] = ['type','in',[8,15,16]];
+
+ $dis[] = ['order_id','=',$order_id];
+
+ $res = $water_model->dataUpdate($dis,['cash_status'=>1,'cash_time'=>$update['can_refund_time']]);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:超时自动退款
+ */
+ public function autoCancelOrder($uniacid,$user_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',1];
+
+ $dis[] = ['over_time','<',time()];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->cancelOrder($value,1);
+
+ }
+
+ }
+ //自动核销订单
+ $this->autoHxOrder($uniacid);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-19 13:27
+ * @功能说明:自动核销订单
+ */
+ public function autoHxOrder($uniacid){
+ //仅限快递
+// $dis[] = ['send_type','=',2];
+ //已经发货
+ $dis[] = ['pay_type','=',3];
+
+ $dis[] = ['hx_over_time','<',time()];
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->hxOrder($value['id'],0,$uniacid,$value['hx_over_time']);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:退款
+ */
+ public function cancelOrder($order,$auto_refund=0){
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$order['id'],'pay_type'=>1],['pay_type'=>-1,'auto_refund'=>$auto_refund,'cancel_time'=>time()]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'取消失败'];
+ }
+
+ $goods_model = new ShopGoods();
+ //退换库存
+ foreach ($order['order_goods'] as $v){
+
+ $res = $goods_model->setOrDelStock($v['goods_id'],$v['spe_id'],$v['goods_num'],1,0,0,$v['kill_atv_id']);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+
+ }
+
+ }
+// //退换优惠券
+// $coupon_model = new CouponRecord();
+//
+// $coupon_model->couponRefund($order['id'],2);
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-03 11:11
+ * @功能说明:检查营销活动
+ */
+ public function marketingCheck($data,$list){
+ //使用积分
+ if($data['integral']>0){
+
+ $user_model = new User();
+
+ $i_log = new IntegralLog();
+
+ $integral_model = new IntegralList();
+
+ $user = $user_model->dataInfo(['id'=>$data['user_id']]);
+ //检查用户积分
+ if($user['integral']<$data['integral']){
+
+ return ['code'=>500,'msg'=>'积分不足'];
+ }
+
+ foreach ($list as $value){
+
+ if(!empty($value['integral_id'])){
+
+ $atv = $integral_model->dataInfo(['id'=>$value['integral_id']]);
+
+ if(empty($atv)){
+
+ return ['code'=>500,'msg'=>'积分活动已下架'.$value['integral_id']];
+
+ }
+
+ $num = $integral_model->getAtvNum($value['integral_id'],$data['user_id']);
+
+ if($num>$atv['user_limit']){
+
+ return ['code'=>500,'msg'=>'该积分活动限购'.$atv['user_limit'].'次'];
+
+ }
+
+ }
+
+ }
+ //抵扣积分
+ $res = $i_log->integralUserAdd($data['user_id'],$data['integral']*-1,$data['uniacid'],2,3,$data['id'],0,$data);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'积分抵扣失败'];
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发货发送订阅消息
+ */
+ public function orderSendService($order){
+
+ $user_model = new User();
+ //获取用户的open_id
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'shop/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$order['uniacid'],'tmpl_name'=>'send_order'])->find();
+
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+
+ return true;
+ }else{
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+ //模版类容
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+
+ return true;
+ }
+ //发送内容
+ $send_data = array(
+
+ $key_worlds[1]=>array(
+ //商品名称
+ 'value'=> date('Y-m-d H:i:s',$order['send_time']),
+ ),
+ $key_worlds[2]=>array(
+ //订单编号
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[3]=>array(
+ //物流编号
+ 'value'=>$order['express_code'],
+ ),
+ $key_worlds[4]=>array(
+ //物流公司
+ 'value'=>$order['express_company'],
+ ),
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+}
diff --git a/app/farm/model/ShopOrderGoods.php b/app/farm/model/ShopOrderGoods.php
new file mode 100755
index 0000000..2a0d5e7
--- /dev/null
+++ b/app/farm/model/ShopOrderGoods.php
@@ -0,0 +1,284 @@
+orderRefundIng($data['id']);
+
+ return $res;
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:获取退款的数量
+ * @author chenniang
+ * @DataTime: 2021-04-12 10:46
+ */
+ public function getRefundNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $refund_model = new ShopRefund();
+
+ $num = $refund_model->refundNum($data['id']);
+
+ return $num;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataSelect($dis){
+
+ $data = $this->where($dis)->order('id desc')->select()->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:12
+ * @功能说明:添加商品子订单
+ */
+ public function orderGoodsAdd($order_goods,$order_id,$user_id,$store_id,$address_id=0){
+
+ $goods_model = new ShopGoods();
+
+ $car_model = new Car();
+
+ $config_model= new Config();
+
+ foreach ($order_goods as $v){
+// //限购
+// if($v['is_limit']==2){
+// //已购数量
+// $buy_num = $this->getGoodsNumber(['b.user_id'=>$user_id,'a.goods_id'=>$v['goods_id']]);
+//
+// if($v['limit']<$buy_num+$v['goods_num']){
+//
+// return ['code'=>500,'msg'=>$v['name'].'超出限购数量,限购数量'.$v['limit']];
+// }
+//
+// }
+ if(!empty($address_id)){
+
+ $res = $config_model->getGoodsSendPrice($address_id,$v,2);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+
+ }
+ //校验
+ $insert = [
+
+ 'uniacid' => $v['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'user_id' => $user_id,
+
+ 'pay_type' => 1,
+
+ 'goods_name' => $v['goods_name'],
+
+ 'goods_cover' => $v['cover'],
+
+ 'spe_name' => $v['spe_name'],
+
+ 'goods_price' => $v['price'],
+
+ 'pay_price' => $v['true_price'],
+
+ 'singe_pay_price'=> $v['true_price']/$v['goods_num'],
+
+ 'goods_num' => $v['goods_num'],
+
+ 'can_refund_num' => $v['goods_num'],
+
+ 'spe_id' => $v['spe_id'],
+
+ 'goods_id' => $v['goods_id'],
+
+ 'integral' => !empty($v['integral_id'])?$v['integral']:0,
+
+ 'i_price' => !empty($v['integral_id'])?$v['i_price']:0,
+
+ 'integral_id' => $v['integral_id'],
+
+ 'kill_atv_id' => $v['kill_atv_id'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'下单失败'];
+ }
+
+ //减少库存 增加销量
+ $res = $goods_model->setOrDelStock($v['goods_id'],$v['spe_id'],$v['goods_num'],0,0,0,$v['kill_atv_id']);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+ //删除购物车
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'status' => 1,
+
+ 'goods_id'=> $v['goods_id'],
+
+ 'spe_id' => $v['spe_id'],
+
+ 'farmer_id' => $store_id
+ ];
+
+ $res = $car_model->where($dis)->delete();
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @return float
+ * 获取历史商品件数
+ */
+ public function getGoodsNumber($dis){
+
+ //取消订单的不算 chen
+ $num = $this->alias('a')
+ ->join('longbing_card_v2_shop_order_list b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->group('a.id')
+ ->sum('a.goods_num');
+
+
+ $order_id = $this->alias('a')
+ ->join('longbing_card_v2_shop_order_list b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->column('b.id');
+
+ $order_refund_goods = new RefundOrderGoods();
+ //申请退款成功的
+ $refund_num = $order_refund_goods->where('order_id','in',$order_id)->where(['status'=>2])->sum('goods_num');
+
+ return $num - $refund_num;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ShopRefund.php b/app/farm/model/ShopRefund.php
new file mode 100755
index 0000000..73c4010
--- /dev/null
+++ b/app/farm/model/ShopRefund.php
@@ -0,0 +1,933 @@
+where(['id'=>$data['refund_user']])->value('username');
+
+ }else{
+
+ $model = new \app\farm\model\User();
+
+ $info = $model->where(['id'=>$data['refund_user']])->value('nickName');
+
+ }
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 17:38
+ * @功能说明:
+ */
+ public function getStoreInfoAttr($value,$data){
+
+ if(!empty($data['store_id'])){
+
+ $farmer_model= new Farmer();
+
+ $info = $farmer_model->dataInfo(['id'=>$data['store_id'],'type'=>2]);
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 16:48
+ * @功能说明:
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总商品数量
+ * @author chenniang
+ * @DataTime: 2021-03-25 14:39
+ */
+ public function getAllGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new ShopRefundGoods();
+
+ $dis = [
+
+ 'refund_id' => $data['id']
+ ];
+
+ $num = $order_goods_model->where($dis)->sum('goods_num');
+
+ return $num;
+ }
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:16
+ * @功能说明:收货信息
+ */
+ public function getAddressInfoAttr($value,$data){
+
+ if(!empty($data['order_id'])){
+
+ $address_model = new OrderAddress();
+
+ $info = $address_model->dataInfo(['order_id'=>$data['order_id']]);
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:16
+ * @功能说明:收货信息
+ */
+ public function getOrderGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $goods_model = new ShopRefundGoods();
+
+ $info = $goods_model->dataSelect(['refund_id'=>$data['id']]);
+
+ return $info;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->alias('a')
+
+ ->join('lbfarm_shop_refund_order_goods c','a.id = c.refund_id')
+ ->join('lbfarm_shop_order d','a.order_id = d.id')
+ ->join('lbfarm_order_address e','a.order_id = e.order_id AND type = 5','left')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,e.mobile,d.order_code as pay_order_code,e.user_name,d.pay_price')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:46
+ * @功能说明:小程序退款列表
+ */
+ public function indexDataList($dis,$where=[],$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_refund_order_goods c','a.id = c.refund_id')
+ ->join('lbfarm_shop_order d','a.order_id = d.id')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,d.order_code as pay_order_code')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:退款中
+ */
+ public function refundIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:37
+ * @功能说明:通过退款
+ */
+ public function passOrder($id,$price,$payConfig,$refund_user=0,$text='',$id_admin=0){
+
+ $refund_order= $this->dataInfo(['id'=>$id]);
+
+ $order_model = new ShopOrder();
+
+ $pay_order = $order_model->dataInfo(['id'=>$refund_order['order_id']]);
+
+ if($refund_order['status']!=1){
+
+ return ['code'=>500,'msg'=>'订单状态错误'];
+ }
+
+ $update = [
+
+ 'refund_user' => $refund_user,
+
+ 'status' => 2,
+
+ 'refund_time' => time(),
+
+ 'refund_price'=> $price,
+
+ 'pay_price' => $price,
+
+ 'refund_text' => $text,
+
+ 'refund_user_admin' => $id_admin
+ ];
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$refund_order['id']],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试'];
+
+ }
+ //修改退款子订单的退款状态
+ $order_refund_goods = new ShopRefundGoods();
+
+ $res = $order_refund_goods->dataUpdate(['refund_id'=>$id],['status'=>2]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试1'.$res];
+
+ }
+
+ $goods_model = new ShopGoods();
+
+ //退换库存
+ foreach ($refund_order['order_goods'] as $v){
+
+ $res = $goods_model->setOrDelStock($v['goods_id'],$v['spe_id'],$v['goods_num'],1,1,0,$v['kill_atv_id']);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+
+ }
+
+ }
+
+ $res = $order_model->dataUpdate(['id'=>$refund_order['order_id']],['true_price'=>$pay_order['true_price']-$price]);
+ //查看货是否退完了
+ $refund_success = $this->checkRefundNum($refund_order['order_id']);
+ //退完了 就修改订单状态
+ if($refund_success==1){
+
+ $res = $order_model->dataUpdate(['id'=>$refund_order['order_id']],['pay_type'=>-1]);
+ //退换优惠券
+ $coupon_model = new CouponRecord();
+//
+// $coupon_model->couponRefund($pay_order['id'],2);
+// if($res==0){
+//
+// Db::rollback();
+//
+// return ['code'=>500,'msg'=>'退款失败,请重试2'];
+//
+// }
+
+ }
+
+ $pay_order = $order_model->dataInfo(['id'=>$refund_order['order_id']]);
+
+ $refund_order= $this->dataInfo(['id'=>$id]);
+
+
+ $res = $this->refundCash($payConfig,$pay_order,$price,$refund_order);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>$res['msg']];
+ }
+
+ if($res!=true){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试3'];
+ }
+
+ Db::commit();
+
+ $sys_model = new PushMsgModel($refund_order['uniacid']);
+
+ $sys_model->sendMsg($refund_order,6);
+
+ return true;
+
+ }
+
+ /**
+ * @param $payConfig
+ * @param $pay_order
+ * @param $price
+ * @param int $refund_id
+ * @功能说明:退钱
+ * @author chenniang
+ * @DataTime: 2021-07-12 20:31
+ */
+ public function refundCash($payConfig,$pay_order,$price,$refund_order){
+
+ if($price<=0){
+
+ return true;
+ }
+
+ $water_model = new FinanceWater();
+ //说明订单已经完成
+ if($pay_order['type']=-1){
+ //将流水状态修改为可入账
+ $water_model->dataUpdate(['order_id'=>$pay_order['id'],'type'=>8],['cash_status'=>1]);
+ //增加退款流水
+ $water_model->addWater($refund_order['id'],9,2,1);
+ //如果有运费将运费也改为可入账
+ $water_model->dataUpdate(['order_id'=>$pay_order['id'],'type'=>16],['cash_status'=>1]);
+ //增加运费退款流水
+ $water_model->addWater($refund_order['id'],17,1,1);
+
+ }else{
+
+ $water_model->addWater($refund_order['id'],9,2,0);
+
+ $water_model->addWater($refund_order['id'],17,1,0);
+
+ }
+
+ $water_model->cashArrival();
+
+ if($pay_order['pay_model']==1){
+ //微信退款
+ $response = orderRefundApi($payConfig,$pay_order['pay_price'],$price,$pay_order['transaction_id']);
+ //如果退款成功修改一下状态
+ if ( isset( $response[ 'return_code' ] ) && isset( $response[ 'result_code' ] ) && $response[ 'return_code' ] == 'SUCCESS' && $response[ 'result_code' ] == 'SUCCESS' ) {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no'])?$response['out_refund_no']:$pay_order['order_code'];
+
+ $this->dataUpdate(['id'=>$refund_order['id']],['out_refund_no'=>$response['out_refund_no']]);
+
+ }else {
+ //失败就报错
+ $discption = !empty($response['err_code_des'])?$response['err_code_des']:$response['return_msg'];
+
+ return ['code'=>500,'msg'=> $discption];
+
+ }
+
+ }elseif($pay_order['pay_model']==2){
+
+
+ $data = [
+
+ 'user_id' => $pay_order['user_id'],
+
+ 'pay_price'=> $price,
+
+ 'id' => $refund_order['id'],
+
+ 'uniacid' => $pay_order['uniacid']
+ ];
+
+ $water_model = new \app\farm\model\BalanceWater();
+
+ $res = $water_model->addWater($data,10,1);
+
+ if($res==0){
+
+ return false;
+
+ }
+
+
+
+ }else{
+ //支付宝
+ $pay_model = new PayModel($payConfig);
+
+ $res = $pay_model->aliRefund($pay_order['transaction_id'],$pay_order['pay_price']);
+
+ if(isset($res['alipay_trade_refund_response']['code'])&&$res['alipay_trade_refund_response']['code']==10000){
+
+ $this->dataUpdate(['id'=>$pay_order['id']],['out_refund_no'=>$res['alipay_trade_refund_response']['out_trade_no']]);
+
+ }else{
+
+ return ['code'=>500,'msg'=> $res['alipay_trade_refund_response']['sub_msg']];
+
+ }
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:29
+ * @功能说明:检查改订单款退完了没
+ */
+ public function checkRefundNum($order_id,$status=2){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $order_refund_goods_model = new ShopRefundGoods();
+
+ $dis = [
+
+ 'order_id' => $order_id
+ ];
+
+ $goods_num = $order_goods_model->where($dis)->sum('goods_num');
+
+ if($status==2){
+
+ $dis['status'] = 2;
+
+ $refund_num= $order_refund_goods_model->where($dis)->sum('goods_num');
+ }else{
+
+ $refund_num= $order_refund_goods_model->where($dis)->where('status','in',[1,2])->sum('goods_num');
+ }
+
+ return $refund_num>=$goods_num?1:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 15:38
+ * @功能说明:该天的退款
+ */
+ public function datePrice($date,$uniacid,$cap_id=0,$end_time='',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('refund_price');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 13:33
+ * @功能说明:申请退款
+ */
+ public function applyRefund($order,$input){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $refund_price = 0;
+
+ $integral = 0;
+
+ Db::startTrans();
+
+ $list = $input['list'];
+
+ foreach ($list as $k=>$value){
+
+ $order_goods = $order_goods_model->dataInfo(['id'=>$value['id']]);
+
+ if(empty($order_goods)){
+
+ return ['code'=>500,'msg'=>'商品未找到'];
+ }
+
+ if($value['num']>$order_goods['can_refund_num']||$value['num']==0){
+
+ return ['code'=>500,'msg'=>'退款数量错误'];
+
+ }
+ //退款金额
+ $refund_price += $order_goods['singe_pay_price']*$value['num'];
+
+
+ $list[$k]['goods_id'] = $order_goods['goods_id'];
+
+ $list[$k]['goods_name'] = $order_goods['goods_name'];
+
+ $list[$k]['goods_cover'] = $order_goods['goods_cover'];
+
+ $list[$k]['spe_name'] = $order_goods['spe_name'];
+
+ $list[$k]['spe_id'] = $order_goods['spe_id'];
+
+ $list[$k]['goods_price'] = $order_goods['goods_price'];
+
+ $list[$k]['kill_atv_id'] = $order_goods['kill_atv_id'];
+
+ $res = $order_goods_model->where(['id'=>$value['id']])->update(['can_refund_num'=>$order_goods['can_refund_num']-$value['num']]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ }
+
+// if($refund_price<=0){
+//
+// Db::rollback();
+//
+// return ['code'=>500,'msg'=>'退款金额至少为0.01元'];
+// }
+
+ $refund_price = round($refund_price,2);
+
+ $refund_price = $refund_price<=$order['pay_price']?$refund_price:$order['pay_price'];
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'store_id' => $order['store_id'],
+
+ 'user_id' => $order['user_id'],
+
+ 'farmer_id' => $order['farmer_id'],
+
+ 'order_code' => orderCode(),
+
+ 'apply_price'=> $refund_price,
+
+ 'order_id' => $order['id'],
+
+ 'text' => $input['text'],
+
+ 'imgs' => !empty($input['imgs'])?implode(',',$input['imgs']):''
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ $refund_id = $this->getLastInsID();
+
+ $refund_goods_model = new ShopRefundGoods();
+
+ foreach ($list as $value){
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'order_id' => $order['id'],
+
+ 'refund_id' => $refund_id,
+
+ 'order_goods_id' => $value['id'],
+
+ 'goods_id' => $value['goods_id'],
+
+ 'goods_name' => $value['goods_name'],
+
+ 'goods_cover' => $value['goods_cover'],
+
+ 'spe_name' => $value['spe_name'],
+
+ 'spe_id' => $value['spe_id'],
+
+ 'goods_num' => $value['num'],
+
+ 'goods_price' => $value['goods_price'],
+
+ 'kill_atv_id' => $value['kill_atv_id'],
+
+ 'status' => 1
+ ];
+
+ $res = $refund_goods_model->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ }
+ //查看货是否退完了
+ $refund_success = $this->checkRefundNum($order['id'],1);
+ //退完并且未发货 就退运费
+ if($refund_success==1&&$order['pay_type']<3){
+
+ $refund_price += $order['freight'];
+
+ $refund_price = $refund_price<=$order['pay_price']?$refund_price:$order['pay_price'];
+
+ $this->dataUpdate(['id'=>$refund_id],['apply_price'=>$refund_price,'car_price'=>$order['freight']]);
+
+ }
+
+ Db::commit();
+
+ return $refund_id;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 09:23
+ * @功能说明:获取订单已经退款的数量
+ */
+ public function refundNum($order_goods_id){
+
+ $dis = [
+
+ 'b.order_goods_id' => $order_goods_id,
+
+ 'a.status' => 2
+ ];
+
+ $num = $this->alias('a')
+ ->join('lbfarm_shop_refund_order_goods b','a.id = b.refund_id')
+ ->where($dis)
+ ->group('b.order_goods_id')
+ ->sum('b.goods_num');
+
+ return $num;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 09:23
+ * @功能说明:获取订单已经退款的数量
+ */
+ public function orderRefundIng($order_goods_id){
+
+ $dis = [
+
+ 'b.order_goods_id' => $order_goods_id,
+
+ 'a.status' => 1
+ ];
+
+ $num = $this->alias('a')
+ ->join('lbfarm_shop_refund_order_goods b','a.id = b.refund_id')
+ ->where($dis)
+ ->group('b.order_goods_id')
+ ->find();
+
+ return !empty($num)?1:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 12:04
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund($refund_id,$refund_user=0,$is_admin=0){
+
+ $dis = [
+
+ 'id' => $refund_id
+ ];
+
+ $refund_order = $this->dataInfo($dis);
+
+ if($refund_order['status']!=1){
+
+ return ['code'=>500,'msg'=>'退款状态错误'];
+
+ }
+
+ $update = [
+
+ 'status' => 3,
+
+ 'refund_time' => time(),
+
+ 'refund_user' => $refund_user,
+
+ 'refund_user_admin' => $is_admin
+
+ ];
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate($dis,$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试1'];
+
+ }
+ //修改退款子订单的退款状态
+ $order_refund_goods = new ShopRefundGoods();
+
+ $res = $order_refund_goods->dataUpdate(['refund_id'=>$refund_id],['status'=>3]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试2'];
+
+ }
+ //查询通支付订单未退款对售后订单
+ $where[] = ['order_id','=',$refund_order['order_id']];
+
+ $where[] = ['status','=',1];
+
+ $where[] = ['car_price','>',0];
+
+ $find = $this->dataInfo($where);
+
+ if(!empty($find)){
+
+ $apply_price = $find['apply_price'] - $find['car_price'];
+
+ $apply_price = $apply_price>0?$apply_price:0;
+
+ $update = [
+
+ 'apply_price' => $apply_price,
+
+ 'car_price' => 0
+ ];
+
+ $this->dataUpdate(['id'=>$find['id']],$update);
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/ShopRefundGoods.php b/app/farm/model/ShopRefundGoods.php
new file mode 100755
index 0000000..218ef6f
--- /dev/null
+++ b/app/farm/model/ShopRefundGoods.php
@@ -0,0 +1,116 @@
+where(['id'=>$data['order_goods_id']])->sum('singe_pay_price');
+
+ return $price;
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataSelect($dis){
+
+ $data = $this->where($dis)->order('id desc')->select()->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Source.php b/app/farm/model/Source.php
new file mode 100755
index 0000000..e775d0b
--- /dev/null
+++ b/app/farm/model/Source.php
@@ -0,0 +1,160 @@
+where(['source_id'=>$data['id']])->select()->toArray();
+
+ return $list;
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(!empty($data['stage'])){
+
+ $stage= $data['stage'];
+
+ unset($data['stage']);
+ }
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(!empty($stage)){
+
+ $this->updateSome($id,$stage,$data['uniacid']);
+ }
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(!empty($data['stage'])){
+
+ $stage = $data['stage'];
+
+ unset($data['stage']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($stage)){
+
+ $this->updateSome($dis['id'],$stage,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-14 17:14
+ * @功能说明:
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $source_text_model = new SourceText();
+
+ $source_text_model->where(['source_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $v['uniacid'] = $uniacid;
+
+ $v['source_id'] = $id;
+
+ $source_text_model->insert($v);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/SourceText.php b/app/farm/model/SourceText.php
new file mode 100755
index 0000000..f4286b3
--- /dev/null
+++ b/app/farm/model/SourceText.php
@@ -0,0 +1,101 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/SystemInfo.php b/app/farm/model/SystemInfo.php
new file mode 100755
index 0000000..7484561
--- /dev/null
+++ b/app/farm/model/SystemInfo.php
@@ -0,0 +1,331 @@
+returnMsg($type,$data);
+ //商城订单需要获取第一个封面图
+ if(in_array($type,[3,4,6])){
+
+ $data['goods_cover'] = !empty($data['order_goods'][0]['goods_cover'])?$data['order_goods'][0]['goods_cover']:'';
+ }
+
+ $insert = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'user_id' => $data['user_id'],
+
+ 'order_code' => !empty($data['order_code'])?$data['order_code']:'',
+
+ 'goods_cover'=> !empty($data['goods_cover'])?$data['goods_cover']:'',
+
+ 'type' => $type,
+
+ 'obj_id' => $data['id'],
+
+ 'msg' => $arr['msg'],
+
+ 'title' => $arr['title'],
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ return $res;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-23 17:29
+ * @功能说明:用户是否有未读消息
+ */
+ public function userHaveNews($user_id,$uniacid){
+
+ $record_model = new InfoRecord();
+
+ $operate_no_read_count = $record_model->noReadCount($user_id,$uniacid);
+
+ $where[] = ['uniacid','=',$uniacid];
+
+ $where[] = ['user_id','=',$user_id];
+
+ $no_read_count = $this->where($where)->where(['status'=>0])->count();
+
+ return $operate_no_read_count>0||$no_read_count>0?1:0;
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/User.php b/app/farm/model/User.php
new file mode 100755
index 0000000..dcf98eb
--- /dev/null
+++ b/app/farm/model/User.php
@@ -0,0 +1,140 @@
+where(['id'=>$data['member_level']])->value('title');
+
+ return !empty($title)?$title:'';
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $data['create_date'] = date('Y-m-d',time());
+
+ $data['year'] = date('Y',time());
+
+ $data['month'] = date('m',time());
+
+ $data['week'] = date('W',time());
+
+ $data['status'] = 1;
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->where($dis)->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis,$field='*'){
+
+ $data = $this->where($dis)->field($field)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-10-27 15:42
+ * @功能说明:订单自提码
+ */
+ public function orderQr($input,$uniacid){
+
+ $data = longbingCreateWxCode($uniacid,$input,$input['page']);
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+ $qr = $data['qr_path'];
+
+ return $qr;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/Wallet.php b/app/farm/model/Wallet.php
new file mode 100755
index 0000000..c829e91
--- /dev/null
+++ b/app/farm/model/Wallet.php
@@ -0,0 +1,227 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 14:33
+ * @功能说明:
+ */
+ public function datePrice($date,$uniacid,$cap_id,$end_time='',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('true_cash');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 16:06
+ * @功能说明:
+ */
+ public function adminList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_coach_list b','a.coach_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.coach_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:36
+ * @功能说明:团长提现
+ */
+ public function capCash($cap_id,$status=2,$type=0){
+
+ $dis = [
+
+
+ 'coach_id' => $cap_id,
+
+ 'status' => $status
+ ];
+
+ if(!empty($type)){
+
+ $dis['type'] = $type;
+ }
+
+ $price = $this->where($dis)->sum('apply_price');
+
+ return round($price,2);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:36
+ * @功能说明:团长提现
+ */
+ public function capCashCount($cap_id,$status=2){
+
+ $dis = [
+
+
+ 'cap_id' => $cap_id,
+
+ 'status' => $status
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/model/WelfareColumn.php b/app/farm/model/WelfareColumn.php
new file mode 100755
index 0000000..2e0235e
--- /dev/null
+++ b/app/farm/model/WelfareColumn.php
@@ -0,0 +1,140 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$field='*'){
+
+ $data = $this->where($dis)->field($field)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/farm/route/route.php b/app/farm/route/route.php
new file mode 100755
index 0000000..4c76a66
--- /dev/null
+++ b/app/farm/route/route.php
@@ -0,0 +1,909 @@
+_observer[] = $observer;
+ }
+
+ /**
+ * @purpose: 从注册树中移除观察者
+ * @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
+ * @return mixed
+ */
+ public function removeObserver($key)
+ {
+ unset($this->_observer[$key]);
+ }
+
+ /**
+ * @purpose: 广播通知以注册的观察者,对注册树进行遍历,让每个对象实现其接口提供的操作
+ * @return mixed
+ */
+ public function notify($uniacid,$userid)
+ {
+ if(!empty($this->_observer)){
+
+ foreach ($this->_observer as $observer) {
+
+ $data[] = $observer->autoCancelOrder($uniacid,$userid);
+ }
+
+ }
+
+ return !empty($data)?$data:[];
+
+ }
+
+
+
+
+
+}
diff --git a/app/farm/server/Claim.php b/app/farm/server/Claim.php
new file mode 100755
index 0000000..7b3a0f0
--- /dev/null
+++ b/app/farm/server/Claim.php
@@ -0,0 +1,67 @@
+_observer[] = $observer;
+ }
+
+ /**
+ * @purpose: 从注册树中移除观察者
+ * @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
+ * @return mixed
+ */
+ public function removeObserver($key)
+ {
+ unset($this->_observer[$key]);
+ }
+
+ /**
+ * @purpose: 广播通知以注册的观察者,对注册树进行遍历,让每个对象实现其接口提供的操作
+ * @return mixed
+ */
+ public function notify($id,$data)
+ {
+ if(!empty($this->_observer)){
+
+ foreach ($this->_observer as $observer) {
+
+ $data[] = $observer->eventClaim($id,$data);
+ }
+
+ }
+
+ return !empty($data)?$data:[];
+
+ }
+
+
+
+
+
+}
diff --git a/app/farm/server/Land.php b/app/farm/server/Land.php
new file mode 100755
index 0000000..4ec9c4d
--- /dev/null
+++ b/app/farm/server/Land.php
@@ -0,0 +1,67 @@
+_observer[] = $observer;
+ }
+
+ /**
+ * @purpose: 从注册树中移除观察者
+ * @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
+ * @return mixed
+ */
+ public function removeObserver($key)
+ {
+ unset($this->_observer[$key]);
+ }
+
+ /**
+ * @purpose: 广播通知以注册的观察者,对注册树进行遍历,让每个对象实现其接口提供的操作
+ * @return mixed
+ */
+ public function notify($id,$data)
+ {
+ if(!empty($this->_observer)){
+
+ foreach ($this->_observer as $observer) {
+
+ $data[] = $observer->eventLand($id,$data);
+ }
+
+ }
+
+ return !empty($data)?$data:[];
+
+ }
+
+
+
+
+
+}
diff --git a/app/im/TLSSigAPIv2.php b/app/im/TLSSigAPIv2.php
new file mode 100755
index 0000000..37a3d8f
--- /dev/null
+++ b/app/im/TLSSigAPIv2.php
@@ -0,0 +1,212 @@
+sdkappid = $sdkappid;
+ $this->key = $key;
+ }
+ /**
+ * 用于 url 的 base64 encode
+ * '+' => '*', '/' => '-', '=' => '_'
+ * @param string $string 需要编码的数据
+ * @return string 编码后的base64串,失败返回false
+ * @throws \Exception
+ */
+ private function base64_url_encode($string) {
+ static $replace = Array('+' => '*', '/' => '-', '=' => '_');
+ $base64 = base64_encode($string);
+ if ($base64 === false) {
+ throw new \Exception('base64_encode error');
+ }
+ return str_replace(array_keys($replace), array_values($replace), $base64);
+ }
+ /**
+ * 用于 url 的 base64 decode
+ * '+' => '*', '/' => '-', '=' => '_'
+ * @param string $base64 需要解码的base64串
+ * @return string 解码后的数据,失败返回false
+ * @throws \Exception
+ */
+ private function base64_url_decode($base64) {
+ static $replace = Array('+' => '*', '/' => '-', '=' => '_');
+ $string = str_replace(array_values($replace), array_keys($replace), $base64);
+ $result = base64_decode($string);
+ if ($result == false) {
+ throw new \Exception('base64_url_decode error');
+ }
+ return $result;
+ }
+ /**
+ * 使用 hmac sha256 生成 sig 字段内容,经过 base64 编码
+ * @param $identifier 用户名,utf-8 编码
+ * @param $curr_time 当前生成 sig 的 unix 时间戳
+ * @param $expire 有效期,单位秒
+ * @param $base64_userbuf base64 编码后的 userbuf
+ * @param $userbuf_enabled 是否开启 userbuf
+ * @return string base64 后的 sig
+ */
+ private function hmacsha256($identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled) {
+ $content_to_be_signed = "TLS.identifier:" . $identifier . "\n"
+ . "TLS.sdkappid:" . $this->sdkappid . "\n"
+ . "TLS.time:" . $curr_time . "\n"
+ . "TLS.expire:" . $expire . "\n";
+ if (true == $userbuf_enabled) {
+ $content_to_be_signed .= "TLS.userbuf:" . $base64_userbuf . "\n";
+ }
+ return base64_encode(hash_hmac( 'sha256', $content_to_be_signed, $this->key, true));
+ }
+ /**
+ * 生成签名。
+ *
+ * @param $identifier 用户账号
+ * @param int $expire 过期时间,单位秒,默认 180 天
+ * @param $userbuf base64 编码后的 userbuf
+ * @param $userbuf_enabled 是否开启 userbuf
+ * @return string 签名字符串
+ * @throws \Exception
+ */
+ private function __genSig($identifier, $expire, $userbuf, $userbuf_enabled) {
+ $curr_time = time();
+ $sig_array = Array(
+ 'TLS.ver' => '2.0',
+ 'TLS.identifier' => strval($identifier),
+ 'TLS.sdkappid' => intval($this->sdkappid),
+ 'TLS.expire' => intval($expire),
+ 'TLS.time' => intval($curr_time)
+ );
+ $base64_userbuf = '';
+ if (true == $userbuf_enabled) {
+ $base64_userbuf = base64_encode($userbuf);
+ $sig_array['TLS.userbuf'] = strval($base64_userbuf);
+ }
+ $sig_array['TLS.sig'] = $this->hmacsha256($identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled);
+ if ($sig_array['TLS.sig'] === false) {
+ throw new \Exception('base64_encode error');
+ }
+ $json_str_sig = json_encode($sig_array);
+ if ($json_str_sig === false) {
+ throw new \Exception('json_encode error');
+ }
+ $compressed = gzcompress($json_str_sig);
+ if ($compressed === false) {
+ throw new \Exception('gzcompress error');
+ }
+ return $this->base64_url_encode($compressed);
+ }
+ /**
+ * 生成签名
+ *
+ * @param $identifier 用户账号
+ * @param int $expire 过期时间,单位秒,默认 180 天
+ * @return string 签名字符串
+ * @throws \Exception
+ */
+ public function genSig($identifier, $expire=86400*180) {
+ return $this->__genSig($identifier, $expire, '', false);
+ }
+ /**
+ * 带 userbuf 生成签名。
+ * @param $identifier 用户账号
+ * @param int $expire 过期时间,单位秒,默认 180 天
+ * @param string $userbuf 用户数据
+ * @return string 签名字符串
+ * @throws \Exception
+ */
+ public function genSigWithUserBuf($identifier, $expire, $userbuf) {
+ return $this->__genSig($identifier, $expire, $userbuf, true);
+ }
+ /**
+ * 验证签名。
+ *
+ * @param string $sig 签名内容
+ * @param string $identifier 需要验证用户名,utf-8 编码
+ * @param int $init_time 返回的生成时间,unix 时间戳
+ * @param int $expire_time 返回的有效期,单位秒
+ * @param string $userbuf 返回的用户数据
+ * @param string $error_msg 失败时的错误信息
+ * @return boolean 验证是否成功
+ * @throws \Exception
+ */
+ private function __verifySig($sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg) {
+ try {
+ $error_msg = '';
+ $compressed_sig = $this->base64_url_decode($sig);
+ $pre_level = error_reporting(E_ERROR);
+ $uncompressed_sig = gzuncompress($compressed_sig);
+ error_reporting($pre_level);
+ if ($uncompressed_sig === false) {
+ throw new \Exception('gzuncompress error');
+ }
+ $sig_doc = json_decode($uncompressed_sig);
+ if ($sig_doc == false) {
+ throw new \Exception('json_decode error');
+ }
+ $sig_doc = (array)$sig_doc;
+ if ($sig_doc['TLS.identifier'] !== $identifier) {
+ throw new \Exception("identifier dosen't match");
+ }
+ if ($sig_doc['TLS.sdkappid'] != $this->sdkappid) {
+ throw new \Exception("sdkappid dosen't match");
+ }
+ $sig = $sig_doc['TLS.sig'];
+ if ($sig == false) {
+ throw new \Exception('sig field is missing');
+ }
+ $init_time = $sig_doc['TLS.time'];
+ $expire_time = $sig_doc['TLS.expire'];
+ $curr_time = time();
+ if ($curr_time > $init_time+$expire_time) {
+ throw new \Exception('sig expired');
+ }
+ $userbuf_enabled = false;
+ $base64_userbuf = '';
+ if (isset($sig_doc['TLS.userbuf'])) {
+ $base64_userbuf = $sig_doc['TLS.userbuf'];
+ $userbuf = base64_decode($base64_userbuf);
+ $userbuf_enabled = true;
+ }
+ $sigCalculated = $this->hmacsha256($identifier, $init_time, $expire_time, $base64_userbuf, $userbuf_enabled);
+ if ($sig != $sigCalculated) {
+ throw new \Exception('verify failed');
+ }
+ return true;
+ } catch (\Exception $ex) {
+ $error_msg = $ex->getMessage();
+ return false;
+ }
+ }
+ /**
+ * 带 userbuf 验证签名。
+ *
+ * @param string $sig 签名内容
+ * @param string $identifier 需要验证用户名,utf-8 编码
+ * @param int $init_time 返回的生成时间,unix 时间戳
+ * @param int $expire_time 返回的有效期,单位秒
+ * @param string $error_msg 失败时的错误信息
+ * @return boolean 验证是否成功
+ * @throws \Exception
+ */
+ public function verifySig($sig, $identifier, &$init_time, &$expire_time, &$error_msg) {
+ $userbuf = '';
+ return $this->__verifySig($sig, $identifier, $init_time, $expire_time, $userbuf, $error_msg);
+ }
+ /**
+ * 验证签名
+ * @param string $sig 签名内容
+ * @param string $identifier 需要验证用户名,utf-8 编码
+ * @param int $init_time 返回的生成时间,unix 时间戳
+ * @param int $expire_time 返回的有效期,单位秒
+ * @param string $userbuf 返回的用户数据
+ * @param string $error_msg 失败时的错误信息
+ * @return boolean 验证是否成功
+ * @throws \Exception
+ */
+ public function verifySigWithUserBuf($sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg) {
+ return $this->__verifySig($sig, $identifier, $init_time, $expire_time, $userbuf, $error_msg);
+ }
+}
\ No newline at end of file
diff --git a/app/im/common.php b/app/im/common.php
new file mode 100755
index 0000000..e987826
--- /dev/null
+++ b/app/im/common.php
@@ -0,0 +1,112 @@
+getUser(['id' => $user_id ,'uniacid' => $uniacid]);
+ if(empty($user)) return null;
+ setCacheUser($user_id ,$user ,3600,$uniacid);
+ return $user;
+}
+
+////返回数据处理
+//function getWxApiReturnData($result)
+//{
+// if(isset($result['data']['page'])) $result['data']['current_page'] = $result['data']['page'];unset($result['data']['page']);
+// if(isset($result['data']['page_count'])) $result['data']['current_page'] = $result['data']['page_count'];unset($result['data']['page_count']);
+// if(isset($result['data']['total'])) $result['data']['current_page'] = $result['data']['total'];unset($result['data']['total']);
+// if(isset($result['data']['total_page'])) $result['data']['current_page'] = $result['data']['total_page'];unset($result['data']['total_page']);
+// return $result;
+//}
+
+//获取chat
+function longbingGetChatById($chat_id ,$uniacid)
+{
+ //设置key
+ $key = 'longbing_card_chat_new_' . $chat_id;
+ //从缓存中获取数据
+ $chat = getCache($key ,$uniacid);
+ //判断缓存数据是否存在
+ if(empty($chat))
+ {
+ //生成chat操作模型
+ $chat_model = new ImChat();
+ //获取数据
+ $chat = $chat_model->getChatById($chat_id);
+ if(!empty($chat)) setCache($key ,$chat ,$uniacid);
+ }
+ return $chat;
+}
+
+//获取chat
+function longbingGetChat($user_id ,$customer_id ,$uniacid = 7777 ,$is_create = true)
+{
+ //判断用户和客户是否是同一人
+ if(empty($user_id) || empty($customer_id) || in_array($user_id, [$customer_id])) return false;
+ //查找数据
+ $chat_model = new ImChat();
+ $chat = $chat_model->getChat($user_id ,$customer_id ,$uniacid);
+ if(isset($chat['id'])){
+ $key = 'longbing_card_chat_new_' . $chat['id'];
+ setCache($key ,$chat ,$uniacid);
+ }
+ //如果数据不存在
+ if(empty($chat) && $is_create){
+ //判断用户是否存在
+ $user = longbingGetUser($user_id ,$uniacid);
+ if(empty($user)) return false;
+ //判断客户是否存在
+ $customer = longbingGetUser($customer_id ,$uniacid);
+ if(empty($customer)) return false;
+ //生成chat数据
+ $chat_data = array(
+ 'user_id' => $user_id,
+ 'target_id' => $customer_id,
+ 'uniacid' => $uniacid
+ );
+ if($chat_model->createChat($chat_data)){
+ $chat = longbingGetChat($user_id ,$customer_id ,$uniacid);
+ }
+ }
+ if(isset($chat['chat_id'])) $chat['id'] = $chat['chat_id'];
+ return $chat;
+}
+
+/**
+ * 腾讯聊天签名方法
+ *
+ * @param $sdkappid
+ * @param $key
+ * @param $user_id
+ * @return mixed
+ * @author shuixian
+ * @DataTime: 2019/12/10 11:29
+ */
+function longbing_publics_tim_genSig($sdkappid, $key,$user_id){
+ require_once 'TLSSigAPIv2.php';
+ $TLSSigAPIv2 = new \Tencent\TLSSigAPIv2($sdkappid, $key);
+ return $TLSSigAPIv2->genSig($user_id);
+}
\ No newline at end of file
diff --git a/app/im/controller/BaseMessage.php b/app/im/controller/BaseMessage.php
new file mode 100755
index 0000000..cf11d97
--- /dev/null
+++ b/app/im/controller/BaseMessage.php
@@ -0,0 +1,50 @@
+ $action ,
+ 'status' => $status ,
+ 'message'=> $message ,
+ 'data' => $data,
+ 'time' => time()
+ ]
+ );
+
+ $server->push($client_id , $dataStr) ;
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/im/controller/Car.php b/app/im/controller/Car.php
new file mode 100755
index 0000000..b996cf1
--- /dev/null
+++ b/app/im/controller/Car.php
@@ -0,0 +1,178 @@
+socket, '127.0.0.1', $port) or die("socket_bind() fail:" . socket_strerror(socket_last_error()) . "/n");
+ //$ex = socket_listen($this->socket, 4) or die("socket_listen() fail:" . socket_strerror(socket_last_error()) . "/n");
+
+// return $ex;
+ return $socket;
+}
+
+
+
+
+
+//abc处理读取到的卡(4字节);
+function abc($ret)
+{
+ $len = $ret[4];
+
+ if($len < 14)
+ {
+ //printf('无效数据');
+ return ;
+ }
+ //
+ $count = $ret[9];
+
+ $count = ($count - 3) / 4;
+ //
+ for($i=0; $i<$count; $i++)
+ {
+ $idx = 10 + ($i * 4);
+
+ $card = sprintf("%02X%02X%02X%02X", $ret[$idx+0], $ret[$idx+1], $ret[$idx+2], $ret[$idx+3]);//这是获取到的卡数据(按文档意思可能会读到多张卡,处理这个$card就可以了)
+ $card = sprintf("%02X%02X%02X", $ret[$idx+0], $ret[$idx+1], $ret[$idx+2]);//这是获取到的卡数据(按文档意思可能会读到多张卡,处理这个$card就可以了)
+
+ printf('card['.$i.']>>'.$card.' | ');
+
+// $post_data['data'] = 'card['.$i.']>>'.$card.' | ';
+
+ $card_id = $card;
+
+ $card = 'card['.$i.']>>'.$card.' | ';
+
+ $url = 'https://car.cncnconnect.com/massage/admin/Tcp/getInfo?card_id='.$card_id.'&time='.msectime();
+
+ $a = file_get_contents($url);
+
+// printf(json_encode($a));
+
+ }
+}
+
+
+function msectime() {
+
+ list($msec,$sec) = explode(' ', microtime());
+
+ $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
+
+ return $msectime;
+}
+
+function crulGetData($url, $post, $method, $header=1){
+// $this->_errno = NULL;
+// $this->_error = NULL;
+ $ch = curl_init($url);
+
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+ if($post != NULL)
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION,true);
+ curl_setopt($ch, CURLOPT_AUTOREFERER,true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 120);
+
+ if($header)
+ curl_setopt($ch, CURLOPT_HEADER, false);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+ 'Content-type: application/json',
+ )
+ );
+ $result = curl_exec($ch);
+ return $result;
+}
+
+
+
+
+
+function accept($socket)
+{
+ return socket_accept($socket);
+}
+
+function close()
+{
+ if($this->socket == 0) return;
+ socket_close($this->socket);
+ $this->socket = 0;
+}
+
+function recv_bytes($cs, $len = 1024)
+{
+ $ret = recv($cs, $len);
+
+ $bytes = string_to_bytes($ret);
+ return $bytes;
+}
+function recv($cs, $len = 1024)
+{
+
+
+ $ret = socket_read($cs, $len) or die("/n");
+
+ return $ret;
+}
+
+
+function string_to_bytes($str)
+{
+ $bytes = array();
+ for($i=0; $i
\ No newline at end of file
diff --git a/app/im/controller/Im.php b/app/im/controller/Im.php
new file mode 100755
index 0000000..705c9f4
--- /dev/null
+++ b/app/im/controller/Im.php
@@ -0,0 +1,624 @@
+user_id = $this->getUserId();
+ $this->user = $this->getUserInfo();
+ }
+
+ //获取客户列表
+ public function listCustomer()
+ {
+ //获取参数列表
+ $param = $this->_param;
+ //获取用户列表
+ $user_id = $this->user_id;
+ //判断用户是否存在
+ if(empty($user_id)) return $this->error('not login ,please login again.');
+
+
+ //生成分页信息
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 10
+ );
+ //获取分页信息
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+ //生成查询模型
+ $chat_model = new ImChat();
+ //生成消息查询模型
+ $message_model = new ImMessage();
+ //生成用户查询模型
+// $user_model = new ImUser();
+ //生成查询
+ $page_config['total'] = $chat_model->listChatCount($user_id ,$this->_uniacid );
+ $chats = $chat_model->listChat($user_id ,$this->_uniacid ,$page_config);
+ $data = [];
+ if(!empty($chats))
+ {
+ foreach($chats as $key => $value)
+ {
+ //获取客户信息
+ $customer_id = null;
+ if(!in_array($value['user_id'], [$user_id])) $customer_id = $value['user_id'];
+ if(!in_array($value['target_id'], [$user_id])) $customer_id = $value['target_id'];
+ if(empty($customer_id)) continue;
+ //获取客户信息
+// $value['customer'] = $user_model->getUser(['id' => $customer_id]);
+ $customer = longbingGetUser($customer_id ,$this->_uniacid);
+ if(!empty($customer['is_staff']))
+ {
+ $customer_info = longbingGetUserInfo($customer_id ,$this->_uniacid);
+ if(isset($customer_info['is_staff']) && !empty($customer_info['is_staff']))
+ {
+ if(!empty($customer_info['avatar'])) {
+ $customer_info = transImagesOne($customer_info ,['avatar'] ,$this->_uniacid);
+ }
+ //是员工 就用员工头像 By.jingshuixian
+ //if(!empty($customer_info['avatar'])) $customer['avatarUrl'] = $customer_info['avatar'];
+ }
+ }
+ $value['customer'] = $customer;
+ if(empty($value['customer'])) continue;
+
+ //获取最后一条消息
+ $lastmessage = $message_model->lastMessage(['chat_id' => $value['id']]);
+ //如果最后一条消息是图片
+ if(isset($lastmessage['message_type']) && !in_array($lastmessage['message_type'], ['text' ])) $lastmessage['content'] = lang($lastmessage['message_type']);
+ $value['lastmessage'] = $lastmessage;
+ //获取未读消息总数
+ $not_rear_message_count = $message_model->listMessageCount(['chat_id' => $value['id'] ,'user_id' => $customer_id ,'target_id' => $user_id ,'status' => 1]);
+
+ //未读消息总数
+ $value['not_read_message_count'] = $not_rear_message_count;
+ //获取时间
+ if(isset($value['update_time']) && !empty($value['update_time'])) $value['time'] = date('Y-m-d H:i:s', $value['update_time']);
+ //判断用户是否存在头像
+ if(!isset($value['customer']['avatarUrl']) || empty($value['customer']['avatarUrl'])) $value['customer']['avatarUrl'] = $this->defaultImage['avatar'];
+ //判断客户是否是员工
+ if(isset($value['customer']['is_staff']) && !empty($value['customer']['is_staff']))
+ {
+ //获取员工信息
+ $user_info = longbingGetUserInfo($customer_id ,$this->_uniacid);
+ if(isset($user_info['is_staff']) && !empty($user_info['is_staff']) && isset($user_info['name']) && !empty($user_info['name'])){
+ $value['customer']['nickName'] = $user_info['name'];
+ }
+ }
+ $data[] = $value;
+ }
+ }
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ $result = $page_config;
+ $result['data'] = $data;
+
+ //总计未读数
+ $result['unReadMessageCount'] = ImService::getUnReadMessageCount($this->user_id);
+
+ //数据处理
+ return $this->success($result);
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 15:58
+ * @功能说明:新版获取用户列表信息
+ */
+ public function listCustomerV2(){
+
+ //获取参数列表
+ $param = $this->_param;
+ //获取用户列表
+ $user_id = $this->user_id;
+ //判断用户是否存在
+ if(empty($user_id)) return $this->error('not login ,please login again.');
+ //初始化朋友列表,兼容老数据
+ ImMessageFriendService::initOldFriendList($this->_uniacid , $user_id) ;
+
+ $result = ImMessageFriendService::getFriendList($this->_uniacid , $user_id , $param['page_count'] ) ;
+ //总计未读数
+ $result['unReadMessageCount'] = ImService::getUnReadMessageCount($this->user_id);
+ //数据处理
+ return $this->success($result);
+
+
+ }
+
+ //获取未读消息列表
+ public function listNotReadMessage()
+ {
+ //获取参数
+ $param = $this->_param;
+ $user_id = $this->user_id;
+ if(!isset($param['chat_id']) || !isset($param['target_id'])) return $this->error(lang('not chat id ,please check param'));
+ if(isset($param['target_id']) && !isset($param['chat_id']) && !empty($param['target_id']))
+ {
+ //获取chat数据
+ $chat = longbingGetChat($user_id ,$param['target_id'] ,$this->_uniacid);
+ if(isset($chat['id'])) $param['chat_id'] = $chat['id'];
+ }
+ //判断chat_id参数是否存在
+ if(!isset($param['chat_id'])) return $this->error('not chat id ,please check param');
+ //if(!isset($param['user_id'])) return $this->error('not user id ,please check param');
+ $chat_id = $param['chat_id'];
+ //获取客户关系
+ $chat = longbingGetChatById($chat_id ,$this->_uniacid);
+ //判断数据是否存在
+ if(empty($chat)) return $this->error('not the chat ,please check chat id');
+ $customer_id = $chat['user_id'];
+ if(in_array($customer_id, [$this->user_id])) $customer_id = $chat['target_id'];
+ $user_id = $this->user_id;
+ //生成查询模型
+ $message_model = new ImMessage();
+ //查询数据
+ $messages = $message_model->listNotReadMessage(['chat_id' => $chat_id ,'target_id' => $user_id]);
+
+ $result['data'] = [];
+ if(!empty($page_config['total'])){
+ foreach($messages as $key => $val)
+ {
+ if(isset($val['create_time']) && !empty($val['create_time'])) $val['time'] = date('Y-m-d H:i:s', $val['create_time']);
+ $result['data'][] = $val;
+ }
+
+ }
+ if(isset($this->user['qr_path'])) $this->user = transImagesOne ( $this->user, ['qr_path'] );
+ $result['user'] = $this->user;
+ $customer = getUser($customer_id ,$this->_uniacid);
+
+
+ if(isset($customer['qr_path'])) $customer = transImagesOne ( $customer, ['qr_path'] );
+ $result['customer'] = $customer;
+ return $this->success($result);
+ }
+
+ //获取消息列表
+ public function listMessage()
+ {
+ $user = longbingGetUser($this->user_id ,$this->_uniacid);
+ //获取参数
+ $param = $this->_param;
+ $chat_id = null;
+ $customer_id = null;
+ $chat = null;
+ //判断参数是否存在
+ if(isset($param['chat_id'])) $chat_id = $param['chat_id'];
+ if(isset($param['customer_id'])) $customer_id = $param['customer_id'];
+ if(empty($chat_id) && empty($customer_id)) $this->error(lang('not customer id,please check param'));
+ //参数处理(兼容处理)
+ $result = [];
+ if(!empty($chat_id))
+ {
+ $chat = longbingGetChatById($chat_id ,$this->_uniacid);
+ }
+ else{
+ $chat = longbingGetChat($this->user_id ,$customer_id ,$this->_uniacid ,true);
+ }
+ //生成分页信息
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 20
+ );
+
+
+ //获取分页信息
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+ if(!empty($chat))
+ {
+ $customer_id = $chat['user_id'];
+ if(empty($chat_id)) $chat_id = $chat['chat_id'];
+ if(in_array($customer_id, [$this->user_id])) $customer_id = $chat['target_id'];
+ //生成消息查询模型
+ $message_model = new ImMessage();
+ //获取查询总数
+ $page_config['total'] = $message_model->listMessageCount(['chat_id' => $chat_id]);
+ //生成分页数据
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ //生成返回数据
+ }else{
+ $page_config['total'] = 0;
+ $page_config['total_page'] = 0;
+ }
+ $result = $page_config;
+ $result['data'] = [];
+ //获取客户信息
+ $customer = longbingGetUser($customer_id ,$this->_uniacid);
+ if(empty($customer)) return $this->error(lang('user not exist.'));
+ //获取头像
+ if(isset($customer['avatarUrl'])) {
+ $customer = transImagesOne ( $customer, ['avatarUrl'] ,$this->_uniacid);
+ }else{
+ $customer['avatarUrl'] = $this->defaultImage['avatarUrl'];
+ }
+ //判断客户是否是员工
+ if(!empty($customer['is_staff']))
+ {
+ $customer_info = longbingGetUserInfo($customer_id ,$this->_uniacid);
+ if(isset($customer_info['is_staff']) && !empty($customer_info['is_staff']))
+ {
+ if(!empty($customer_info['avatar'])) {
+ $customer_info = transImagesOne($customer_info ,['avatar'] ,$this->_uniacid);
+ }
+ if(!empty($customer_info['avatar'])) $customer['avatarUrl'] = $customer_info['avatar'];
+ }
+ }
+ //获取客户电话号码和微信号码
+ $customer['wechat'] = null;
+ $phone = null;
+ $user_info_model = new UserInfo();
+ //获取微信和电话号码
+ $user_info = $user_info_model->getUserPhone($customer_id ,$this->_uniacid);
+ if(isset($user_info['phone']) && !empty($user_info['phone'])) $phone = $user_info['phone'];
+ if(isset($user_info['wechat']) && !empty($user_info['wechat'])) $customer['wechat'] = $user_info['wechat'];
+ if(empty($phone)){
+ $user_phone_model = new UserPhone();
+ $user_phone = $user_phone_model->getUserPhone($customer_id ,$this->_uniacid);
+ if(isset($user_phone['phone']) && !empty($user_phone['phone'])) $phone = $user_phone['phone'];
+ }
+ //判断聊天者是否是客户
+ $customer['is_customer'] = false;
+ $collection_model = new ImClient();
+ if(!empty($collection_model->isCustomer($this->user_id , $customer_id ,$this->_uniacid))) $customer['is_customer'] = true;
+ //判断客户是否是员工
+ if(isset($customer['is_staff']) && !empty($customer['is_staff']))
+ {
+ $customer_info = longbingGetUserInfo($customer_id ,$this->_uniacid);
+ if(isset($customer_info['is_staff']) && !empty($customer_info['is_staff']) && isset($customer_info['name']) && !empty($customer_info['name'])){
+ $customer['nickName'] = $customer_info['name'];
+ //生成第一条默认返回数据
+ $result['data'][] = array(
+ 'chat_id' => $chat['id'],
+ 'user_id' => $customer_id,
+ 'target_id' => $this->user_id,
+ 'status' => 2,
+ 'uniacid' => $this->_uniacid,
+ 'message_type' => 'welcome',
+ 'content' => lang('Hello, I am ') . $customer['nickName'] . lang(', May I help you? Please contact me!')
+ );
+ }
+ }
+ $customer['phone'] = $phone;
+
+ if(!empty($page_config['total'])){
+
+ $msgwhere[] = ['chat_id','=',$chat_id];
+ //自己发送的
+ $msgwhere[] = ['is_show','<>',2];
+
+ $msgwhere[] = ['user_id','=',$this->getUserId()];
+
+ $msgwhere[] = ['deleted','=',0];
+
+ $whereT[] = ['deleted','=',0];
+ //自己接受的
+ $whereT[] = ['target_id','=',$this->getUserId()];
+
+ $whereT[] = ['target_is_show','<>',2];
+
+ $whereT[] = ['chat_id','=',$chat_id];
+
+ foreach($message_model->listMessageV2($msgwhere ,$page_config,$whereT) as $key => $val)
+ {
+ if(isset($val['create_time']) && !empty($val['create_time'])) $val['time'] = date('Y-m-d H:i:s', $val['create_time']);
+ $result['data'][] = $val;
+ }
+
+ //dump($this->getUserId(),$chat['user_id'],$msgwhere,$result['data']);exit;
+
+ }
+// if(isset($this->user['qr_path'])) $this->user = transImagesOne ( $this->user, ['qr_path'] );
+
+ //判断用户是否是员工
+ if(!empty($user['is_staff']))
+ {
+ $user_info = longbingGetUserInfo($this->user_id ,$this->_uniacid);
+ if(isset($user_info['is_staff']) && !empty($user_info['is_staff']))
+ {
+ if(!empty($user_info['avatar'])) {
+ $user_info = transImagesOne($user_info ,['avatar'] ,$this->_uniacid);
+ }
+ if(!empty($user_info['avatar'])) $user['avatarUrl'] = $user_info['avatar'];
+ }
+ }
+
+ //默认头像处理
+
+ //没有头像就给一个默认头像
+ $customer['avatarUrl'] = empty($customer['avatarUrl']) ? LongbingDefault::$avatarImgUrl : $customer['avatarUrl'];
+ $user['avatarUrl'] = empty($user['avatarUrl']) ? LongbingDefault::$avatarImgUrl : $user['avatarUrl'];
+
+ $result['user'] = $user;
+
+ $result['customer'] = $customer;
+ //阅读所有消息
+ $result['readMessageNumber'] = ImService::readMessage($this->_uniacid ,$this->user_id , $customer_id);
+
+
+ return $this->success($result);
+ }
+
+ //标记已读消息
+ public function readMessage()
+ {
+ $param = $this->_param ;
+ $message_model = new ImMessage();
+ $count = 0 ;
+ if ( isset($param['id']) ) {
+ $id = $param['id'] ;
+ $message = $message_model->find($id);
+ if($message){
+ ImService::readMessage($this->_uniacid ,$this->user_id , $message['user_id'] ) ;
+ }
+
+ }
+
+ return $this->success(['count' => $count ] );
+
+ }
+
+ //获取常用话术
+ public function listReply()
+ {
+ //获取用户信息
+ $user_id = $this->user_id;
+ //生成话术分类查询模型
+ $reply_type_model = new ImReplyType();
+ //生成快速回复话术查询模型
+ $reply_model = new ImMyReply();
+ //获取自定义话术
+ $my_replys = $reply_model->listReply(['uniacid' => $this->_uniacid ,'user_id' => $user_id ,'status' => 1]);
+ $result[] = ['title' => lang('my reply') , 'data' => $my_replys ,'is_myself' => true];
+ //获取types
+ $types = $reply_type_model->listAllType(['uniacid' => $this->_uniacid ,'status' => 1]);
+ foreach($types as $type)
+ {
+ $data['title'] = $type['title'];
+ $data['data'] = $reply_model->listReply(['uniacid' => $this->_uniacid ,'user_id' => 0 ,'status' => 1 ,'type' => $type['id']]);
+ $data['is_myself'] = false;
+ $result[] = $data;
+ }
+ return $this->success($result);
+ }
+
+ //创建和更新常用话术
+ public function addReply()
+ {
+ //获取参数
+ $input = $this->_input;
+ $param = $this->_param;
+ if(!isset($input['content'])) return $this->error('content is not exist ,please check .');
+ $is_create = true;
+ if(isset($input['id']) && !empty($input['id'])) $is_create = false;
+ //获取用户信息
+ $user_id = $this->user_id;
+ //生成快速回复话术查询模型
+ $my_reply_model = new ImMyReply();
+ if($is_create)
+ {
+ //创建
+ $result = $my_reply_model->createReply(['uniacid' => $this->_uniacid ,'status' => 1 ,'content' => $input['content'] ,'user_id' => $user_id]);
+ }else{
+ //修改
+ $result = $my_reply_model->updateReply(['id' =>$param['id'] , 'uniacid' => $this->_uniacid ,'user_id' => $user_id] ,['content' => $input['content']]);
+ }
+
+ //获取自定义话术
+ return $this->success($result);
+ }
+
+ //删除常用话术
+ public function delReply()
+ {
+ $param = $this->_param;
+ $user_id = $this->user_id;
+ if(!isset($param['id'])) return $this->error('reoly id is not exist ,please check .');
+ //生成快速回复话术查询模型
+ $my_reply_model = new ImMyReply();
+ //删除话术
+ $result = $my_reply_model->deleteReply(['id' =>$param['id'] ,'uniacid' => $this->_uniacid ,'user_id' => $user_id]);
+
+ return $this->success($result);
+
+ }
+
+ /**
+ * 腾讯IM签名
+ *
+ * @author shuixian
+ * @DataTime: 2019/12/10 11:30
+ */
+ public function getTimUserSig(){
+ //需要远程获取和加密
+ $sdkappid = 1400288706 ;
+ $key = 'd31548b81e57bf823e12d240e4cce237e09f666bdff3fc325eb4bc386e62832d' ;
+ $user_id = $this->_param['user_id'];
+ $userSig = longbing_publics_tim_genSig($sdkappid , $key , $user_id );
+
+ $result = ['user_id'=>$user_id , 'userSig' => $userSig] ;
+
+ return $this->success($result);
+ }
+
+
+ /**
+ * 保存聊天信息
+ *
+ * @return \think\Response
+ * @author shuixian
+ * @DataTime: 2019/12/11 9:29
+ */
+ public function sendMessage(){
+ //获取参数列表
+
+ //{type: "text", content: "456789", target_id: 14, uniacid: "8890", user_id: 20} //发消息
+ //{"action":"getUnReadMessageCount","status":true,"message":"","data":{"count":2}} // 获取未读消息树
+ $param = $this->_param;
+
+ //获取房间ID
+
+ $chat_id = ImService::getChatId($this->_uniacid , $this->user_id, $param['target_id']);
+ //还需要校验参数合法新
+
+ $value['message_type'] = $param['message_type'];
+ $value['chat_id'] = $chat_id;//需要获取和判断
+ $value['user_id'] = $this->user_id;
+ $value['target_id'] = $param['target_id']; //需要判断接收用户的合法性
+ $value['content'] = $param['content'];
+ $value['status'] = 1;
+ $value['uniacid'] = $this->_uniacid;
+ $value['create_time'] = time();
+ $value['update_time'] = time();
+ $value['is_show'] = 1;
+
+ $result = ImService::addMessage($value);
+
+ if($result){
+ $value['id'] = $result ;
+
+ ImService::sendImMessageTmpl($this->_uniacid , $value['user_id'] , $value['target_id']) ;
+
+
+ return $this->success( $value );
+ }else{
+ $this->error('');
+ }
+
+ }
+
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020/1/15 13:13
+ * @功能说明:获取目标客户发送的消息数量
+ */
+ public function getCustomerUnReadMessageCount(){
+
+
+ $param = $this->_param ;
+
+ $user_id = $this->user_id;
+
+ $target_id = 0 ;
+
+ $count = 0 ;
+
+ if (isset($param['target_id'])) {
+
+ $target_id = $param['target_id'];
+
+ $count = ImService::getUnReadMessageCountByUserIdAndTargetId( $target_id , $user_id);
+
+ }
+
+ $data[] = ['action'=> 'getCustomerUnReadMessageCount' , 'data' => ['count' => $count, 'user_id' => $user_id , 'target_id' => $target_id ] ] ;
+
+ $data[] = ['action' => 'getUnReadMessageCount' , 'data' => ['count' => ImService::getUnReadMessageCount($user_id) ] ] ;
+
+ $message_model = new ImMessage();
+
+ $messageList = $message_model->where( [ ['user_id' , '=' ,$target_id ] ,[ 'target_id' , '=' , $user_id ] , ['status', '=' , 1]] )->select();
+
+ foreach ($messageList as $item ){
+
+ $data[] = ['action' => 'getNewMessage' , 'data' => $item ] ;
+ }
+
+ $key = 'message'.$user_id.'-'.$target_id;
+ //获取撤回消息
+ $cancel_msg = getCache($key,$this->_uniacid);
+
+ $data[] = ['action' => 'getCancelMessage' , 'data' => $cancel_msg ] ;
+
+ setCache($key,[],0,$this->_uniacid);
+
+ return $this->success( $data ) ;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-05-26 17:33
+ * @功能说明:修改消息状态 1都可见 2删除对方可见 撤回都不可见
+ */
+ public function updateMsgStatus(){
+
+ $input = $this->_input;
+
+ $message_model = new ImMessage();
+
+ $info = $message_model->where(['id'=>$input['id']])->find()->toArray();
+ //撤回只有送人课操作
+ if($input['is_show']==-1){
+
+ $update['is_show'] = -1;
+
+ if($info['target_is_show']==1){
+
+ $update['target_is_show'] = -1;
+ }
+
+ }
+ //删除
+ if($input['is_show']==2){
+ //判断我是否是发送者
+ if($info['user_id']==$this->getUserId()){
+
+ $update['is_show'] = 2;
+
+ }else{
+
+ $update['target_is_show'] = 2;
+
+ }
+
+ }
+
+ $res = $message_model->where(['id'=>$input['id']])->update($update);
+
+ $data = $message_model->where(['id'=>$input['id']])->find();
+
+ if(!empty($data)){
+
+ $data = $data->toArray();
+
+ $key = 'message'.$data['target_id'].'-'.$data['user_id'];
+
+ setCache($key,$data,0,$this->_uniacid);
+
+ }
+
+ return $this->success( $res ) ;
+
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/im/controller/Index.php b/app/im/controller/Index.php
new file mode 100755
index 0000000..ec3e746
--- /dev/null
+++ b/app/im/controller/Index.php
@@ -0,0 +1,10 @@
+getUser($user_id ,$uniacid);
+ //判断用户是否存在
+ if(empty($user)) {
+ return $server->push($client_id ,json_encode(['action' => 'login' ,'status' => false ,'message'=> lang('login error') ,'data' =>[]]));
+ }
+ //设置用户连接数据
+ $user['client_id'] = $client_id;
+ $cache_user = $this->setCacheUser($user_id ,$user ,$uniacid);
+ //设置用户连接
+ $cache_connect = $this->setConnect($client_id ,['user_id' => $user_id ,'uniacid' => $uniacid]);
+ //判断缓存是否插入成功
+ if(empty($cache_user) || empty($cache_connect)) $server->push($client_id ,json_encode(lang('login error')));
+ //返回登陆成功
+ $server->push($client_id ,json_encode(['action' => 'login' ,'status' => true ,'message'=> 'login success.' ,'data' =>$user]));
+ }
+
+ //检查登录
+ public function checkLogin($client_id ,$data = [])
+ {
+ $result = false;
+ //获取连接信息
+ $connect = $this->getConnect($client_id);
+ //如果没有登录
+ if(empty($connect) || !isset($connect['user_id']) || !isset($connect['uniacid']))
+ {
+ $user_id = null;
+ $uniacid = '7777';
+ //判断用户id是否存在
+ if(!isset($data['user_id'])) return $result;
+ //获取用户id
+ $user_id = $data['user_id'];
+
+ //获取uniacid
+ if(isset($data['uniacid'])) $uniacid = $data['uniacid'];
+ //获取用户数据
+ $user = $this->getUser($user_id ,$uniacid);
+ //判断用书是否存在
+
+ if(empty($user)) return $result;
+ //设置用户连接数据
+ $user['client_id'] = $client_id;
+ $cache_user = $this->setCacheUser($user_id ,$user ,$uniacid);
+ //设置用户连接
+ $cache_connect = $this->setConnect($client_id ,['user_id' => $user_id ,'uniacid' => $uniacid]);
+
+ //判断缓存是否插入成功
+ if(!empty($cache_user) && !empty($cache_connect)) $result = true;
+ }else{
+ $result = true;
+ }
+ return $result;
+ }
+
+ //退出
+ public function logout($client_id)
+ {
+ $this->delConnect($client_id);
+ }
+ //发送消息
+ public function sendMessage($server ,$client_id ,$data)
+ {
+ //登录检查
+ if(!$this->checkLogin($client_id ,$data['data'])){
+ $server->push($client_id ,json_encode(['action' => 'login' ,'status' => false ,'message'=> 'login error ,please check login param.' ,'data' =>[]]));
+ return;
+ }
+ //获取用户是否登录
+ $connect = $this->getConnect($client_id);
+ $user = null;
+ if(empty($connect) || !isset($connect['user_id']) || !isset($connect['uniacid']))
+ {
+ return;
+ }else{
+ $user = $this->getUser($connect['user_id'] ,$connect['uniacid']);
+ }
+
+ //判断用户是否存在
+ if(empty($user)) return ;
+ //判断连接是否正确
+ if(!isset($user['client_id']) || !in_array($user['client_id'], [$client_id]))
+ {
+ $user['client_id'] = $client_id;
+ $this->setCacheUser($connect['user_id'], $user ,'ws');
+ }
+ //检查消息
+ $value['message_type'] = 'text';
+ $value['status'] = 1;
+ $value['user_id'] = $connect['user_id'];
+ $value['uniacid'] = $connect['uniacid'];
+ $value['create_time'] = time();
+ if(isset($data['data'])){
+ $data = $data['data'];
+ }else{
+ return;
+ }
+ //判断接受者是否存在
+ if(isset($data['target_id'])) {
+ $value['target_id'] = $data['target_id'];
+ }else{
+ return ;
+ }
+ //判断数据类型是否存在
+ if(isset($data['type'])) $value['message_type'] = $data['type'];
+ //判断状态是否存在
+ if(isset($data['status'])) $value['status'] = $data['status'];
+ //判断发送者是否存在
+ if(isset($data['user_id'])) $value['user_id'] = $data['user_id'];
+ //判断uniacid是否存在
+ if(isset($data['uniacid'])) $value['uniacid'] = $data['uniacid'];
+ if(isset($data['chat_id']))
+ {
+ $value['chat_id'] = $data['chat_id'];
+ }else{
+// $data = $this->getChat($value['user_id'], $value['target_id'] ,$data['uniacid']);
+ $value['chat_id'] = $this->getChatId($value['user_id'], $value['target_id'] ,$data['uniacid'] ,true);
+ //$server->push($client_id , json_encode($value ,true));die;
+ }
+ //判断发送消息是否存在
+ if(isset($data['content'])) {
+ $value['content'] = $data['content'];
+ }else{
+ return ;
+ }
+
+ //检查数据(防止伪造数据的存在)
+ $target = $this->getUser($value['target_id'] ,$value['uniacid']);
+ //判断用户是否存在
+ if(empty($target)) return;
+ //存储数据
+// $push_data = array(
+// 'action' => 'addMessage',
+// 'event' => 'asyncAddMessage',
+// 'message' => $value
+// );
+// $i = 1000000;
+// while($i>0)
+// {
+// publisher(json_encode($push_data ,true));
+// $i = $i -1;
+// }
+// publisher(json_encode($push_data ,true));
+ $resultAddMsg = false ;
+
+
+ //随机模拟发送消息失败情况
+ /*mt_srand();
+ $demoError = mt_rand(0, 1);
+
+ if($demoError){
+ if(isset($value['chat_id']) && !empty($value['chat_id'])) $resultAddMsg = asyncAddMessage($value);
+ }*/
+
+ if(isset($value['chat_id']) && !empty($value['chat_id'])) $resultAddMsg = asyncAddMessage($value);
+
+ //By.jingshuixian 如果消息存储失败,直接返回
+ if(!$resultAddMsg){
+ $server->push($client_id ,json_encode(['action' => 'sendMessage' ,'status' => $resultAddMsg,'data' => $value] ,true));
+ return false ;
+ }
+
+ //判断用户是否登录
+ if(isset($target['client_id'])) {
+ $value['time'] = date('Y-m-d H:i:s', time());
+ try{
+ $server->push($target['client_id'] , json_encode(['action' => 'getNewMessage' ,'status' => $resultAddMsg , 'data' => $value] ,true));
+ }catch (Exception $e){
+ //echo "$server->push error" ;
+ }
+
+ //向消息接受者发送未读消息数量
+ //$this->getCustomerUnReadMessageCount($server ,$target['client_id'] ,['target_id' => $data['user_id']]);
+ $this->getCustomer($server ,$target['client_id'] ,['data' => ['user_id' => $value['target_id'] ,'target_id' => $value['user_id'] ,'uniacid' => $value['uniacid']]]);
+ $this->getCustomerUnReadMessageCount($server ,$target['client_id'] ,['data' => ['user_id' => $value['target_id'] ,'target_id' => $value['user_id'] ,'uniacid' => $value['uniacid']]]);
+ $this->getUnReadMessageCount($server ,$target['client_id'] ,['data' => ['user_id' => $value['target_id'] ,'target_id' => $value['user_id'] ,'uniacid' => $value['uniacid']]]);
+ }else{
+ //发送服务通知
+// $push_data = array(
+// 'action' => 'sendMessageWxServiceNotice',
+// 'event' => 'longbingSendMessageWxServiceNotice',
+// 'message' => $value
+// );
+// publisher(json_encode($push_data ,true));
+ longbingSendMessageWxServiceNotice($value);
+
+ }
+ $value['status'] = 1;
+ $value['creat_time'] = time();
+ $value['time'] = date('Y-m-d H:i:s', time());
+ $server->push($client_id ,json_encode(['action' => 'sendMessage' ,'status' => $resultAddMsg,'data' => $value] ,true));
+ //存储数据
+// $push_data = array(
+// 'action' => 'addMessage',
+// 'event' => 'asyncAddMessage',
+// 'message' => $value
+// );
+// publisher(json_encode($push_data ,true) ,1000);
+ //发送用户总的未读数据获取用户
+
+ }
+ //获取用户缓存
+ function getCacheUser($user_id ,$uniacid = '7777')
+ {
+ $key = 'longbing_ws_card_user_' . $user_id;
+ if(!hasCache($key ,$uniacid)) return null;
+ return getCache($key ,$uniacid);
+ }
+
+ //设置用户缓存数据
+ function setCacheUser($user_id ,$value ,$uniacid = '7777')
+ {
+ $key = 'longbing_ws_card_user_' . $user_id;
+ return setCache ( $key, $value, 3600, $uniacid);
+ }
+
+ //获取用户信息
+ function getUser($user_id ,$uniacid ='7777')
+ {
+ //判断缓存是否存在
+ $user = $this->getCacheUser($user_id ,$uniacid);
+ if(!empty($user)) return $user;
+// //生成查询类
+// $user_model = new ImUser();
+// //获取数据
+// $user = $user_model->getUser(['id' => $user_id ,'uniacid' => $uniacid]);
+ $user = longbingGetUser($user_id ,$uniacid);
+ if(empty($user)) return null;
+ $this->setCacheUser($user_id ,$user ,$uniacid);
+ return $user;
+ }
+ //获取当前连接状态
+ function getConnect($client_id ,$uniacid = 'ws')
+ {
+ $key = $this->connect_name . $client_id;
+ $connect = getCache($key ,$uniacid);
+ return $connect;
+ }
+ //设置连接状态
+ function setConnect($client_id ,$value , $uniacid = 'ws')
+ {
+ $key = $this->connect_name . $client_id;
+ return setCache ( $key, $value, 3600, $uniacid);
+ }
+ //注销连接
+ function delConnect($client_id ,$uniacid = 'ws')
+ {
+ $key = $this->connect_name . $client_id;
+ $connect = $this->getConnect($client_id ,$uniacid);
+ if(empty($connect) || !isset($connect['user_id']) || !isset($connect['uniacid'])) return false;
+ $user = $this->getUser($connect['user_id'] ,$connect['uniacid']);
+ if(isset($user['client_id'])){
+ unset($user['client_id']);
+ $this->setCacheUser($connect['user_id'],$user, $connect['uniacid']);
+ }
+ delCache($key ,$uniacid);
+ }
+ //获取所有chat
+ function getChats($user_id ,$uniacid = '7777' ,$is_update = false)
+ {
+// $key = $this->chat_name . $user_id;
+// $chats = [];
+// //判断是否更新
+// if($is_update)
+// {
+// $chat_model = new ImChat();
+// $chats_data = $chat_model->listChatAll($user_id ,$uniacid);
+// foreach($chats_data as $chat)
+// {
+// if(!isset($chat['chat_id']) || !isset($chat['user_id']) || !isset($chat['target_id'])) continue;
+// $customer_id = $chat['user_id'];
+// if(!in_array($chat['user_id'], [$user_id])) $customer_id = $chat['target_id'];
+// $chats[$customer_id] = $chat['chat_id'];
+// }
+// if(!empty($chats)) $this->setChat($user_id ,$chats ,$uniacid);
+// }else{
+// if(hasCache($key ,$uniacid)){
+// $chats = getCache($key ,$uniacid);
+// }else{
+// $chats = $this->getChats($user_id ,$uniacid ,true);
+// }
+// }
+// return $chats;
+ $key = $this->chat_name . $user_id;
+ $chats = [];
+ if(hasCache($key ,$uniacid)){
+ $chats = getCache($key ,$uniacid);
+ }
+ return $chats;
+ }
+ //获取用户与客户的chat
+ function getChatId($user_id ,$customer_id ,$uniacid ,$is_create = false)
+ {
+// //获取chats
+// $chats = $this->getChats($user_id ,$uniacid);
+// $chat_id = null;
+// //判断数据是否存在
+// if(!isset($chats[$customer_id])){
+// $this->createChat(['user_id' => $user_id ,'target_id' => $customer_id ,'uniacid' => $uniacid ,'create_time' => time()]);
+// $chat_id = $this->getChatId($user_id ,$customer_id ,$uniacid);
+// }else{
+// $chat_id = $this->getChats($user_id ,$uniacid)[$customer_id];
+// }
+// //返回数据
+// return $chat_id;
+ //获取chats
+ $chats = $this->getChats($user_id ,$uniacid);
+ $chat_id = null;
+ //判断数据是否存在
+ if(!isset($chats[$customer_id])){
+ //从数据库中查询数据
+ $chat = $this->getChat($user_id, $customer_id ,$uniacid);
+ if(empty($chat))
+ {
+ if(!empty($is_create)){
+ $chat_id = $this->createChat(['user_id' => $user_id ,'target_id' => $customer_id ,'uniacid' => $uniacid ,'create_time' => time()]);
+// $chat_id = $this->getChatId($user_id ,$customer_id ,$uniacid);
+ }
+ }else{
+ $chats[$customer_id] = $chat['chat_id'];
+ $this->setChat($user_id, $chats ,$uniacid);
+ }
+
+ }else{
+ $chat_id = $this->getChats($user_id ,$uniacid)[$customer_id];
+ }
+ //返回数据
+ return $chat_id;
+ }
+
+ //获取chat
+ function getChat($user_id ,$customer_id ,$uniacid = '7777')
+ {
+ $chat_model = new ImChat();
+ $chat = $chat_model->getChat($user_id ,$customer_id ,$uniacid);
+ return $chat;
+ }
+
+ //设置Chat
+ function setChat($user_id ,$value ,$uniacid ='7777')
+ {
+ $key = $this->chat_name . $user_id;
+ return setCache($key, $value, 60, $uniacid);
+ }
+
+ //创建Chat
+ function createChat($data)
+ {
+ $chat_model = new ImChat();
+ $result = $chat_model->createChat($data);
+ //$this->getChats($data['user_id'] ,$data['uniacid'] ,true);
+ return $result;
+ }
+
+ //获取客户列表
+ function listCustomer($data)
+ {
+ //获取参数列表
+ $param = $this->$data;
+ //获取用户列表
+ $user_id = $param['user_id'];
+ //判断用户是否存在
+ if(empty($user_id)) return $this->error('not login ,please login again.');
+ //生成分页信息
+ $page_config = array(
+ 'page' => 1,
+ 'page_count' => 10
+ );
+ //获取分页信息
+ if(isset($param['page']) && $param['page'] > 0) $page_config['page'] = $param['page'];
+ if(isset($param['page_count']) && $param['page_count'] > 0) $page_config['page_count'] = $param['page_count'];
+ //生成查询模型
+ $chat_model = new ImChat();
+ //生成消息查询模型
+ $message_model = new ImMessage();
+ //生成用户查询模型
+// $user_model = new ImUser();
+ //生成查询
+ $page_config['total'] = $chat_model->listChatCount($user_id);
+ $chats = $chat_model->listChat($user_id ,$page_config);
+ if(!empty($chats))
+ {
+ foreach($chats as $key => $value)
+ {
+ $lastmessage = $message_model->lastMessage(['chat_id' => $value['id']]);
+ $value['lastmessage'] = $lastmessage;
+ $customer_id = null;
+ if(!in_array($value['user_id'], [$user_id])) $customer_id = $value['user_id'];
+ if(!in_array($value['target_id'], [$user_id])) $customer_id = $value['target_id'];
+// $value['customer'] = $user_model->getUser(['id' => $customer_id]);
+ $value['customer'] = longbingGetUser($customer_id ,$value['uniacid']);
+ $chats[$key] = $value;
+ }
+ }
+ $page_config['total_page'] = (int)($page_config['total'] / $page_config['page_count']);
+ if(($page_config['total'] % $page_config['page_count']) > 0) $page_config['total_page'] = $page_config['total_page'] + 1;
+ $result = $page_config;
+ $result['chats'] = $chats;
+ return $this->success($result);
+ }
+
+ //获取未读消息总数
+ public function getUnReadMessageCount($server ,$client_id ,$data)
+ {
+ //登录检查
+ if(!$this->checkLogin($client_id ,$data['data'])){
+ $server->push($client_id ,json_encode(['action' => 'login' ,'status' => false ,'message'=> 'login error ,please check login param.' ,'data' =>[]]));
+ return;
+ }
+ //获取用户是否登录
+ $connect = $this->getConnect($client_id);
+ $user = null;
+ if(empty($connect) || !isset($connect['user_id']) || !isset($connect['uniacid']))
+ {
+ return;
+ }else{
+ $user = $this->getUser($connect['user_id'] ,$connect['uniacid']);
+ }
+ //判断用户是否存在
+ if(empty($user)) return ;
+ //判断连接是否正确
+ if(!isset($user['client_id']) || !in_array($user['client_id'], [$client_id]))
+ {
+ $user['client_id'] = $client_id;
+ $this->setCacheUser($connect['user_id'], $user ,'ws');
+ }
+ //获取未读消息总数
+ $message_model = new ImMessage();
+// $server->push($client_id ,json_encode($user));
+ $count = $message_model->listMessageCount(['target_id' => $user['id'] ,'status' => 1]);
+// $count = $message_model->listMessageCount(['status' => 1]);
+ $server->push($client_id ,json_encode(['action' => 'getUnReadMessageCount' ,'status' => true ,'message'=> '' ,'data' =>['count' => $count]]));
+ return;
+ }
+ //获取用户未读消息数
+ public function getCustomerUnReadMessageCount($server ,$client_id ,$data)
+ {
+ //登录检查
+ if(!$this->checkLogin($client_id ,$data['data'])){
+ $server->push($client_id ,json_encode(['action' => 'login' ,'status' => false ,'message'=> 'login error ,please check login param.' ,'data' =>[]]));
+ return;
+ }
+ if(!isset($data['data']['target_id'])) return;
+ $customer_id = $data['data']['target_id'];
+ //获取用户是否登录
+ $connect = $this->getConnect($client_id);
+ $user = null;
+ if(empty($connect) || !isset($connect['user_id']) || !isset($connect['uniacid']))
+ {
+ return;
+ }else{
+ $user = $this->getUser($connect['user_id'] ,$connect['uniacid']);
+ }
+ //判断用户是否存在
+ if(empty($user)) return ;
+ //判断连接是否正确
+ if(!isset($user['client_id']) || !in_array($user['client_id'], [$client_id]))
+ {
+ $user['client_id'] = $client_id;
+ $this->setCacheUser($connect['user_id'], $user ,'ws');
+ }
+ //获取未读消息总数
+ $message_model = new ImMessage();
+ $chat_id = $this->getChatId($user['id'] ,$customer_id ,$user['uniacid'] ,true);
+ if(empty($chat_id)) return;
+ $count = $message_model->listMessageCount(['user_id' => $customer_id,'target_id' => $user['id'] ,'status' => 1]);
+// $count = $message_model->listMessageCount(['status' => 1]);
+ $server->push($client_id ,json_encode(['action' => 'getCustomerUnReadMessageCount' ,'status' => true ,'message'=> '' ,'data' =>['count' => $count ,'target_id' => $customer_id ,'user_id' => $user['id']]]));
+ return;
+ }
+ //获取客户信息
+ public function getCustomer($server ,$client_id ,$data)
+ {
+ //登录检查
+ if(!$this->checkLogin($client_id ,$data['data'])){
+ $server->push($client_id ,json_encode(['action' => 'login' ,'status' => false ,'message'=> 'login error ,please check login param.' ,'data' =>[]]));
+ return;
+ }
+ if(!isset($data['data'])) return;
+ if(!isset($data['data']['user_id'])) return;
+ if(!isset($data['data']['target_id'])) return;
+ if(!isset($data['data']['uniacid'])) return;
+ $user_id = $data['data']['user_id'];
+ $customer_id = $data['data']['target_id'];
+ $uniacid = $data['data']['uniacid'];
+ //生成关系操作类
+ $chat_model = new ImChat();
+ //获取chat_id
+ $chat_id = $this->getChatId($user_id ,$customer_id ,$uniacid ,true);
+ if(empty($chat_id)) return;
+ //获取数据
+ $chat = $chat_model->getChatById($chat_id);
+ if(empty($chat)) return;
+ //获取客户信息
+ $customer = $this->getUser($customer_id ,$uniacid);
+ $chat['customer'] = $customer;
+ $chat['time'] = date('Y-m-d H:i:s', time());
+ if(isset($chat['update'])) $chat['time'] = date('Y-m-d H:i:s', $chat['update']);
+
+ $message_model = new ImMessage();
+ //获取最后一条消息
+ $last_message = $message_model->lastMessage(['chat_id' => $chat_id]);
+ $chat['lastmessage'] = $last_message;
+ //获取未读客户数据数量
+ $not_rear_message_count = $message_model->listMessageCount(['chat_id' => $chat_id ,'user_id' => $customer_id ,'target_id' =>$user_id ,'status' => 1]);
+ $chat['not_read_message_count'] = $not_rear_message_count;
+ //返回数据
+ $server->push($client_id ,json_encode(['action' => 'getCustomer' ,'status' => true ,'data' => $chat ,'message' => ''] ,true));
+ }
+
+ //检查链接是否正常
+ public function checkWs($server ,$client_id ,$data)
+ {
+ if(!isset($data['data']['check']) || !in_array($data['data']['check'], ['78346+SJDHFA.longbing'])) return ;
+// $server->push($client_id ,json_encode(['action' => 'checkWs' ,'status' => true ,'message'=> '' ,'data' =>['check' => '78346+SJDHFA.longbing']]));
+ $server->push($client_id ,json_encode(['action' => 'checkWs' ,'status' => true ,'message' => '' ,'data' => ['check' => '78346+SJDHFA.longbing']]));
+ }
+ //标记消息已读
+ public function readMessage($server ,$client_id ,$data)
+ {
+ //登录检查
+ if(!$this->checkLogin($client_id ,$data['data'])){
+ $server->push($client_id ,json_encode(['action' => 'login' ,'status' => false ,'message'=> 'login error ,please check login param.' ,'data' =>[]]));
+ return;
+ }
+ //获取用户是否登录
+ $connect = $this->getConnect($client_id);
+ $user = null;
+ if(empty($connect) || !isset($connect['user_id']) || !isset($connect['uniacid']))
+ {
+ return;
+ }else{
+ $user = $this->getUser($connect['user_id'] ,$connect['uniacid']);
+ }
+ //判断用户是否存在
+ if(empty($user)) return ;
+ //判断连接是否正确
+ if(!isset($user['client_id']) || !in_array($user['client_id'], [$client_id]))
+ {
+ $user['client_id'] = $client_id;
+ $this->setCacheUser($connect['user_id'], $user ,'ws');
+ }
+
+
+ if(!isset($data['data']['target_id'])) return ;
+ $target_id = $data['data']['target_id'];
+ if(isset($data['data']['uniacid'])) $uniacid = $data['data']['uniacid'];
+ if(isset($user['uniacid'])) $uniacid = $user['uniacid'];
+ $user_id = $user['id'];
+ $chat_id = $this->getChatId($user_id, $target_id ,$uniacid , true);
+ if(empty($chat_id)) return;
+ //设置已读数据
+ $message_model = new ImMessage();
+ $message_model->readMessage(['chat_id' => $chat_id ,'user_id' => $target_id ,'target_id' => $user_id ,'deleted' => 0]);
+ //发数据给自己
+ $this->getCustomer($server ,$client_id ,['data' => ['user_id' => $user_id ,'target_id' => $target_id,'uniacid' => $uniacid]]);
+ //
+ $this->getUnReadMessageCount($server ,$client_id ,['data' => ['user_id' => $user_id,'target_id' => $target_id ,'uniacid' => $uniacid]]);
+
+ }
+
+}
diff --git a/app/im/controller/MessageHandlerV2.php b/app/im/controller/MessageHandlerV2.php
new file mode 100755
index 0000000..5f92706
--- /dev/null
+++ b/app/im/controller/MessageHandlerV2.php
@@ -0,0 +1,220 @@
+ 401, 'error' => '请登录系统!'] ;
+
+ //发送消息
+ public function sendMessage($server ,$client_id ,$data)
+ {
+
+ //检查登录
+ $user_id = $this->checkLogin($server ,$client_id ,$data);
+ if(!$user_id){
+ return $this->sendLogin($server , $client_id ) ;
+ }
+
+
+ $uniacid = $data['data']['uniacid'];
+ $target_id = $data['data']['target_id']; //接收消息用户id
+ $content = $data['data']['content'];
+
+
+ if( isset($data['data']['id']) && $data['data']['id'] > 0 ) { //
+
+ $message = $data['data'] ;
+ $message_type = $data['data']['message_type'];
+ }else{
+
+ $chat_id = ImService::getChatId($uniacid, $user_id, $target_id);
+ $message_type = $data['data']['type'];
+ $message['message_type'] = $message_type; //
+ $message['status'] = 1; //消息状态 1=>未读消息 2=>已读 3=>已撤销 4=>已删除
+ $message['user_id'] = $user_id; //发送消息用户id
+ $message['target_id'] = $target_id; //接收消息用户id
+ $message['content'] = $content; // 消息内容
+ $message['uniacid'] = $uniacid; //平台ID
+ $message['chat_id'] = $chat_id; // 房间ID
+ $message['create_time'] = time();
+ $message['update_time'] = time();
+
+
+ ImService::addMessage($message);
+ }
+
+
+ $pushTargetClientId = intval( $this->getClientIdByUserId($target_id) ) ;
+
+ //客户在线
+ if($pushTargetClientId){
+
+ $this->sendServerMsg($server , $pushTargetClientId , 'getNewMessage' ,true,'', $message );
+ $this->getUnReadMessageCount($server , $pushTargetClientId , ['data'=>['user_id' => $target_id ] ] );
+ $this->getCustomerUnReadMessageCount($server , $pushTargetClientId , ['data'=>['user_id' => $target_id ,'target_id' => $user_id ] ] );
+
+ }else{
+ //发送服务通知给客户
+ //员工姓名,必须为中文,不能带有数字和符号
+ //$name = LongbingUserInfoService::getNameByUserId($user_id);
+ //ImService::sendTmplMsg($uniacid,$target_id,[ $name , '有未读私信' , LongbingTime::getChinaNowTime()] , 'pages/user/home' );
+ }
+
+
+
+ $this->sendServerMsg($server , $client_id , 'sendMessage' ,true,'', $message );
+ $this->getUnReadMessageCount($server , $client_id , ['data'=>['user_id' => $user_id ] ] );
+
+ //给员工发通知消息
+
+ //$note = new LongbingServiceNotice($uniacid);
+ //$note->sendImMessageServiceNoticeToStaff($target_id , $content) ;
+
+ }
+
+ //获取未读消息总数
+ public function getUnReadMessageCount($server ,$client_id ,$data)
+ {
+ $user_id = $data['data']['user_id'] ;
+ $count = ImService::getUnReadMessageCount($user_id);
+
+ $this->sendServerMsg($server ,$client_id , 'getUnReadMessageCount' , true,'', ['count' => $count ] ) ;
+ }
+
+ //查询目标客户,给我发送的消息数量
+ public function getCustomerUnReadMessageCount($server ,$client_id ,$data)
+ {
+
+ if (isset($data['data']['target_id']) && isset($data['data']['user_id'])) {
+
+ $user_id = $data['data']['user_id'];
+ $target_id = $data['data']['target_id'];
+
+ $count = ImService::getUnReadMessageCountByUserIdAndTargetId( $target_id , $user_id);
+
+ $this->sendServerMsg($server, $client_id, 'getCustomerUnReadMessageCount', true, '', ['count' => $count, 'user_id' => $user_id , 'target_id' => $target_id ]);
+
+ }
+ }
+
+
+ //登陆
+ public function login($server ,$client_id ,$data)
+ {
+
+ //登录失败
+ $user_id = $this->checkLogin($server ,$client_id ,$data);
+ if(!$user_id){
+ return $this->sendLogin($server , $client_id ) ;
+ }
+
+ $this->updateClentAndUserIdCache($client_id , $user_id);
+
+ $this->sendServerMsg($server ,$client_id , 'login' , true ) ;
+
+ //用户登录成功,给客户发未读消息数量
+ $this->getUnReadMessageCount($server , $client_id , ['data'=>['user_id' => $user_id ] ] );
+
+ }
+
+
+ //检查登录
+ public function checkLogin( $server ,$client_id ,$data ){
+
+ if(isset($data['data']['token'])){
+
+ $token = $data['data']['token'];
+ $uniacid = $data['data']['uniacid'] ;
+ $user = getCache($token , $uniacid );
+
+ if(empty($user)){
+ return false ;
+ }
+
+ return $user['id'] ;
+
+ }else{
+ echo json_encode($data);
+ }
+
+ return false ;
+
+ }
+
+ //发送登录提示消息信息
+ public function sendLogin( $server ,$client_id ){
+
+ $this->sendServerMsg($server, $client_id ,'login',false,'',$this->noLogin);
+
+ }
+
+
+ //更新缓存客户和用户ID
+ public function updateClentAndUserIdCache($client_id , $user_id){
+ //缓存客户端对应的用户ID
+ $key = $this->connect_name . $client_id;
+ setCache ( $key, $user_id, 3600, $this->uniacid_wss );
+
+ //缓存用户登录对应的客户端ID
+ $key = $this->connect_user_name . $user_id;
+ setCache ( $key, $client_id, 3600, $this->uniacid_wss );
+ }
+
+ //根据用户ID获取 $client_id
+ public function getClientIdByUserId($userId){
+
+ $key = $this->connect_user_name . $userId;
+ $client_id = getCache( $key , $this->uniacid_wss ) ;
+
+ return $client_id;
+ }
+
+ //退出
+ public function logout($client_id)
+ {
+ $key = $this->connect_name . $client_id;
+ $user_id = getCache( $key , $this->uniacid_wss ) ;
+
+ //删除客户对应的用户ID
+ delCache($key ,$this->uniacid_wss);
+
+ //删除用户对应的客户ID
+ $key = $this->connect_user_name . $user_id;
+ delCache($key ,$this->uniacid_wss);
+
+ }
+
+
+ //检查链接是否正常
+ public function checkWs($server ,$client_id ,$data)
+ {
+
+ //检查登录
+ $user_id = $this->checkLogin($server ,$client_id ,$data);
+ if(!$user_id){
+ return $this->sendLogin($server , $client_id ) ;
+ }
+ $this->updateClentAndUserIdCache($client_id , $user_id) ;
+
+ $this->sendServerMsg($server, $client_id ,'checkWsOk');
+
+ }
+
+}
diff --git a/app/im/controller/PushServer.php b/app/im/controller/PushServer.php
new file mode 100755
index 0000000..b7f7d9b
--- /dev/null
+++ b/app/im/controller/PushServer.php
@@ -0,0 +1,147 @@
+init();
+ $this->register();
+ //设置
+// self::initServer();
+ //注册事件
+ //连接客户端
+ self::$server->on("open" ,[$this , "onOpen"]);
+ //发送消息
+ self::$server->on('message' ,[$this ,'onMessage']);
+ //关闭连接
+ self::$server->on('close' ,[$this ,'onClose']);
+ //异步
+ self::$server->on('task' ,[$this ,'onTask']);
+ //启动时运行
+ self::$server->on('workerStart' ,[$this ,'onWorkerStart']);
+
+ }
+ //获取
+ public static function getInstance()
+ {
+ if(!self::$instance instanceof self)
+ {
+ self::$instance = new self();
+ }
+ return self::$instance;
+ }
+
+ protected function init()
+ {
+ $this->config = Config::get('swoole');
+ }
+
+ public function register()
+ {
+ $this->isWebsocket = Config::get('swoole.websocket.enabled');
+ $this->createSwooleServer();
+ }
+
+ public function boot(Route $route)
+ {
+ $this->commands(ServerCommand::class);
+ if ($this->isWebsocket) {
+ $route->group(function () use ($route) {
+ $route->get('socket.io/', '@upgrade');
+ $route->post('socket.io/', '@reject');
+ })->prefix(Controller::class)->middleware(Middleware::class);
+ }
+ }
+
+ /**
+ * Create swoole server.
+ */
+ protected function createSwooleServer()
+ {
+ $server = $this->isWebsocket ? WebsocketServer::class : HttpServer::class;
+ $config = $this->config;
+ $host = Config::get('swoole.server.host');
+ $port = Config::get('swoole.server.port');
+ $socketType = Config::get('swoole.server.socket_type', SWOOLE_SOCK_TCP);
+ $mode = Config::get('swoole.server.mode', SWOOLE_PROCESS);
+ self::$server = new $server($host, $port, $mode, $socketType);
+ $options = Config::get('swoole.server.options');
+ self::$server->set($options);
+ }
+
+
+ //启动服务器
+ public function start()
+ {
+ self::$server->start();
+ }
+
+ //客户端连接上后执行的方法
+ public function onOpen($server ,$req)
+ {
+ self::$server->push($req->fd ,json_encode(['action' => 'connect' ,'status' => true ,'data' => [] ,'message' => 'connect success.'] ,true));
+ }
+
+ //客户端连接上后执行的方法
+ public function onMessage($server ,$frame)
+ {
+ self::$server->reload();//重新加载代码
+ $data = json_decode($frame->data ,true);
+ $result = null;
+ if(method_exists($this->messageHandler, $data['action']))
+ {
+ $result = call_user_func([$this->messageHandler, $data['action']] ,self::$server ,$frame->fd ,$data);
+ }
+ }
+ //异步
+ public function onTask($server ,$frame)
+ {
+
+ }
+
+ //关闭连接
+ public function onClose($server ,$fd)
+ {
+ call_user_func([$this->messageHandler, 'logout'] ,$fd);
+ }
+ //onWorkerStart
+ public function onWorkerStart()
+ {
+ // 加载框架里面的文件
+ require __DIR__ . '/../../../vendor/autoload.php';
+ $http = ( new App() )->http;
+ $response = $http->run();
+ $this->messageHandler = new MessageHandlerV2();
+ }
+ //发送消息
+ public function sendMessage($fd ,$data){
+ self::$server->push($fd ,$data);
+ }
+}
diff --git a/app/im/controller/Some.php b/app/im/controller/Some.php
new file mode 100755
index 0000000..45b81ca
--- /dev/null
+++ b/app/im/controller/Some.php
@@ -0,0 +1,612 @@
+redis)||$this->redis->ping()!=true){
+
+ $this->redis = new Redis();
+
+ $this->redis->connect($host,$port);
+
+ if(!empty($password)){
+
+ $this->redis->auth($password); //设置密码
+ }
+
+// $connect_status = $this->redis->ping();
+
+// if($connect_status != "+PONG")
+// if($connect_status != true)
+// {
+// $this->redis->connect($host,$port);
+//
+// if(!empty($password)){
+//
+// $this->redis->auth($password); //设置密码
+// }
+//
+// }
+
+ }
+
+ }
+
+ /**
+ * @param $ws
+ * @param $request
+ * @功能说明:建立连接回调(智能物料)
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function mOnOpen($data,$fd) {
+
+ $room_key = $data['room_key'];
+
+ $uid = !empty($data['user_id'])?$data['user_id']:0;
+
+ $target_id= !empty($data['target_id'])?$data['target_id']:0;
+
+ $uniacid = !empty($data['uniacid'])?$data['uniacid']:0;
+ //是否是群主
+ $leader =!empty($data['presenter'])?$data['presenter']:0;
+ //1是文件 2是宣传册
+ $type = !empty($data['type'])?$data['type']:1;
+ //加入房间域
+ $this->redis->hset($room_key,$uid,$fd);
+ //加入组集合
+ $this->redis->sadd('group', $room_key);
+ //如果是群主
+ if($leader==1){
+
+ $key = $room_key.'-leader';
+ //群主
+ $this->redis->set($key,$uid,86400);
+
+ }
+
+ $bIm_model = new BrochureIm();
+
+ $dis = [
+
+ 'user_id' => $uid,
+
+ 'room_key' => $room_key,
+
+ 'brochure_id' => $target_id,
+
+ 'type' => $type,
+ ];
+
+ $find = $bIm_model->dataInfo($dis);
+
+ $room_status = $bIm_model->where(['room_key'=>$room_key,'leader'=>1])->value('status');
+
+ $room_status = !empty($room_status)?$room_status:1;
+
+ if(empty($find)){
+
+ $key = $room_key.'-leader';
+ //群主
+ $user_id = $this->redis->get($key);
+
+ $user_info = new UserInfo();
+
+ $user_id = !empty($user_id)?$user_id:0;
+
+ $company_id = $user_info->where(['fans_id'=>$user_id])->value('company_id');
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $uid,
+
+ 'room_key' => $room_key,
+
+ 'brochure_id' => $target_id,
+
+ 'leader' => $leader,
+
+ 'type' => $type,
+
+ 'company_id' => !empty($company_id)?$company_id:0,
+
+ 'status' => $room_status
+
+ ];
+
+ $bIm_model->dataAdd($insert);
+ }else{
+
+ $bIm_model->dataUpdate($dis,['status'=>$room_status]);
+
+ }
+
+ }
+
+
+ /**
+ * @param $ws
+ * @param $frame
+ * @功能说明:接受消息回调(智能物料)
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function mOnMessage($ws, $data,$fd) {
+
+ $room_key = $data['data']['room_key'];
+ //获取房间
+ $room = $this->redis->hGetAll($room_key);
+
+ if(!empty($room)){
+
+ foreach ($room as $k => $vv) {
+ //投递消息
+ $ws->push($vv, json_encode($data));
+
+ }
+
+ }
+
+ }
+
+
+ /**
+ * @param $ws
+ * @param $data
+ * @param $fd
+ * @功能说明:保存音频
+ * @author chenniang
+ * @DataTime: 2021-08-10 17:25
+ */
+ public function addVideo($ws, $data,$fd){
+
+ $room_key = $data['data']['room_key'];
+
+ $uniacid = !empty($data['data']['uniacid'])?$data['data']['uniacid']:0;
+
+ $video = FILE_UPLOAD_PATH.$data['data']['video'];
+
+ if(!empty($data['data']['video'])){
+
+ $im_video_model = new ImVideo();
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'room_key' => $room_key,
+
+ 'video' => $video,
+
+ ];
+
+ $im_video_model->dataAdd($insert);
+
+ }
+
+ }
+
+
+
+ /**
+ * @param $ws
+ * @param $frame
+ * @功能说明:接受消息回调(智能物料)
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function onLogin($ws, $data,$fd) {
+
+ $room_key = $data['data']['room_key'];
+
+// $room_key = '20210802093606035000000350';
+ //获取房间
+ $room = $this->redis->hgetall($room_key);
+
+ if(!empty($room)){
+
+ $user_model = new IndexUser();
+
+ $bIm_model = new BrochureIm();
+
+ $user_id = array_keys($room);
+
+ $key = $room_key.'-leader';
+ //获取群组的用户id
+ $leader_id = $this->redis->get($key);
+
+ if(!empty($leader_id)){
+
+ $user_key = array_search($leader_id,$user_id);
+
+ if(is_numeric($user_key)&&array_key_exists($user_key,$user_id)){
+
+ unset($user_id[$user_key]);
+ }
+
+ }
+
+ $user = $user_model->where('id','in',$user_id)->field('nickName,avatarUrl')->select()->toArray();
+
+ $list['data']['user'] = $user;
+
+ $list['action'] = $data['action'];
+
+ $list['data']['room_key'] = $room_key;
+
+ $list['data']['count'] = count($user_id);
+
+ $dis = [
+
+ 'room_key' => $room_key,
+
+ 'leader' => 1
+ ];
+ //演示状态
+ $list['data']['is_start'] = $bIm_model->where($dis)->value('status');
+
+ foreach ($room as $k => $vv) {
+ //投递消息
+ $ws->push($vv, json_encode($list));
+
+ }
+
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-28 16:50
+ * @功能说明:开始演示
+ */
+ public function startAction($ws, $data,$fd){
+
+ $room_key = $data['data']['room_key'];
+
+ $bIm_model = new BrochureIm();
+
+ $dis = [
+
+ 'room_key' => $room_key,
+
+// 'leader' => 1
+ ];
+ //修改演示状态
+ $bIm_model->dataUpdate($dis,['status'=>2]);
+
+ $bIm_model->dataUpdate(['room_key'=>$room_key],['time_long'=>0,'update_time'=>time()]);
+
+ $room = $this->redis->hGetAll($room_key);
+
+ $list['data']['is_start'] = 2;
+
+ $list['data']['room_key'] = $room_key;
+
+ $list['action'] = $data['action'];
+
+ if(!empty($room)){
+
+ foreach ($room as $k=>$vv){
+ //投递消息
+ $ws->push($vv, json_encode($list));
+ }
+
+ }
+
+ }
+
+
+ /**
+ * @param $serv
+ * @param $task_id
+ * @param $worker_id
+ * @param $data
+ * @功能说明:完成异步任务回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function onTask($serv, $task_id, $worker_id, $data) {
+
+ //返回字符串给worker进程——>触发onFinish
+ return "success";
+ }
+
+
+ /**
+ * @param $serv
+ * @param $task_id
+ * @param $data
+ * @功能说明:完成任务投递回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:16
+ */
+ public function onFinish($serv, $task_id, $data) {
+ //task_worker进程将任务处理结果发送给worker进程
+ echo "完成任务{$task_id}投递 处理结果:{$data}";
+ }
+
+
+ /**
+ * @param $ws
+ * @param $fd
+ * @功能说明:关闭连接回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:16
+ */
+ public function onClose($ws, $fd) {
+ //退出并删除多余的分组fd
+ $group = $this->redis->sMembers('group');
+
+ foreach ($group as $v) {
+
+ $fangjian = $this->redis->hgetall($v);
+
+ foreach ($fangjian as $k => $vv) {
+
+ if ($fd == $vv) {
+
+ $this->redis->hdel($v, $vv);
+
+ }
+ }
+ }
+// echo "{$fd}关闭了连接1";
+ }
+
+
+ /**
+ * @param $ws
+ * @param $fd
+ * @功能说明:解散群
+ * @author chenniang
+ * @DataTime: 2021-07-27 18:04
+ */
+ public function allLoginOut($ws,$data,$fd){
+
+ $room_key = $data['data']['room_key'];
+
+ $fangjian = $this->redis->hgetall($room_key);
+
+ $im_model = new BrochureIm();
+
+ $data['action'] = 'mOnMessage';
+
+ $data['data']['message_type'] = 2;
+ //给剩下的人发消息
+ $this->mOnMessage($ws,$data,$fd);
+
+ $bIm_model = new BrochureIm();
+
+ $dis = [
+
+ 'room_key' => $room_key,
+
+ ];
+ //修改演示状态
+ $bIm_model->where($dis)->update(['status'=>3]);
+
+ if(!empty($fangjian)){
+
+ foreach ($fangjian as $k => $vv) {
+
+ $this->redis->Hdel($room_key,$k);
+
+ $dis = [
+
+ 'user_id' => $k,
+
+ 'room_key'=> $room_key
+ ];
+
+ $find = $im_model->dataInfo($dis);
+
+ if(!empty($find)&&$find['status']>1){
+
+ $time_long = time()-$find['update_time'];
+
+ $im_model->dataUpdate($dis,['time_long'=>$time_long+$find['time_long']]);
+
+ }
+
+ }
+ //删除房间
+ @$this->redis->sRem('group',$room_key);
+ }
+
+
+// if(!empty($data['data']['url'])){
+//
+// $url = $data['data']['url'];
+// //合并录音
+// $im_model->addAudio($room_key,$url);
+// }
+
+
+ }
+
+ /**
+ * @param $ws
+ * @param $fd
+ * @功能说明:退出
+ * @author chenniang
+ * @DataTime: 2021-07-23 17:44
+ */
+ public function loginOut($ws, $fd){
+
+ $im_model = new BrochureIm();
+ //退出并删除多余的分组fd
+ $group = $this->redis->sMembers('group');
+
+ if(!empty($group)){
+
+ foreach ($group as $v) {
+
+ $fangjian = $this->redis->hgetall($v);
+
+ $data['data']['room_key'] = $v;
+
+ if(!empty($fangjian)){
+
+ foreach ($fangjian as $k => $vv) {
+
+ if ($fd == $vv) {
+
+ $this->redis->Hdel($v,$k);
+
+ $dis = [
+
+ 'user_id' => $k,
+
+ 'room_key'=> $v
+ ];
+
+ $find = $im_model->dataInfo($dis);
+
+ if(!empty($find)&&$find['status']>1){
+
+ $time_long = time()-$find['update_time'];
+
+ $im_model->dataUpdate($dis,['time_long'=>$time_long+$find['time_long']]);
+
+ }
+
+ $data['action'] = 'onLogin';
+ //给剩下的人发消息
+ $this->onLogin($ws,$data,$fd);
+
+ }
+
+ }
+
+ }else{
+
+ @$this->redis->sRem('group',$v);
+ }
+
+
+ }
+
+ }
+
+
+
+
+ }
+
+
+
+ /**
+ * @param $ws
+ * @param $fd
+ * @功能说明:退出
+ * @author chenniang
+ * @DataTime: 2021-07-23 17:44
+ */
+ public function loginOutV2($ws, $fd){
+
+ $im_model = new BrochureIm();
+ //退出并删除多余的分组fd
+ $group = $this->redis->sMembers('group');
+
+ foreach ($group as $v) {
+
+ $fangjian = $this->redis->hgetall($v);
+
+ $key = $v.'-leader';
+ //获取群组的用户id
+ $leader_id = $this->redis->get($key);
+ //当前用户的id
+ $user_id = array_search($fd,$fangjian);
+ //如果是群组则全部退出
+ $is_all = !empty($user_id)&&$leader_id==$user_id?1:0;
+
+ $data['data']['room_key'] = $v;
+ //修改房间状态
+ if($is_all==1){
+
+ $start_key = $v.'-is_start';
+
+ $this->redis->set($start_key,0);
+
+ $data['action'] = 'mOnMessage';
+
+ $data['data']['message_type'] = 2;
+ //给剩下的人发消息
+ $this->mOnMessage($ws,$data,$fd);
+
+ }
+
+ if(!empty($fangjian)){
+
+ foreach ($fangjian as $k => $vv) {
+
+ if ($fd == $vv||$is_all==1) {
+
+ $this->redis->hdel($v, $k);
+
+
+ $dis = [
+
+ 'user_id' => $k,
+
+ 'room_key'=> $v
+ ];
+
+ $find = $im_model->dataInfo($dis);
+
+ if(!empty($find)){
+
+ $time_long = time()-$find['update_time'];
+
+ $im_model->dataUpdate($dis,['time_long'=>$time_long+$find['time_long']]);
+
+ }
+
+ }
+
+ }
+
+ }else{
+
+ @$this->redis->sRem('group',$v);
+
+ }
+ //如果是群主断开链接
+ if($is_all==0){
+
+ $data['action'] = 'onLogin';
+ //给剩下的人发消息
+ $this->onLogin($ws,$data,$fd);
+
+ }
+
+ }
+
+ }
+
+}
+
diff --git a/app/im/controller/Tcp.php b/app/im/controller/Tcp.php
new file mode 100755
index 0000000..d7efa17
--- /dev/null
+++ b/app/im/controller/Tcp.php
@@ -0,0 +1,82 @@
+redis)){
+
+ $this->redis = new Redis();
+
+ $this->redis ->connect('127.0.0.1',6379);
+ }
+
+
+ //创建Server对象,监听 127.0.0.1:9501 端口
+ $server = new \Swoole\Server('127.0.0.1', 9501);
+
+// $this->server->set(array(
+//
+// 'reactor_num' => 2, //reactor thread num
+//
+// 'worker_num' => 4, //worker process num
+//
+// 'backlog' => 128, //listen backlog
+//
+// 'max_request' => 50,
+//
+// 'dispatch_mode' => 1,
+//
+//// 'daemonize' => 1
+//
+// ));
+
+
+//监听连接进入事件
+ $server->on('Connect', function ($server, $fd) {
+ echo "Client: Connect.\n";
+ });
+
+//监听数据接收事件
+ $server->on('Receive', function ($server, $fd, $reactor_id, $data) {
+ $server->send($fd, "Server: {$data}");
+ });
+
+//监听连接关闭事件
+ $server->on('Close', function ($server, $fd) {
+ echo "Client: Close.\n";
+ });
+
+//启动服务器
+ $server->start();
+
+
+ }
+
+}
+
+
+new Tcp();
\ No newline at end of file
diff --git a/app/im/controller/WebsocketTest.php b/app/im/controller/WebsocketTest.php
new file mode 100755
index 0000000..9e464db
--- /dev/null
+++ b/app/im/controller/WebsocketTest.php
@@ -0,0 +1,142 @@
+key = '122345446';
+
+ if(empty($this->redis)){
+
+ $this->redis = new Redis();
+
+ $this->redis ->connect('127.0.0.1',6379);
+ }
+
+
+ $this->server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
+
+ $this->server->set(array(
+
+ 'reactor_num' => 2, //reactor thread num
+
+ 'worker_num' => 4, //worker process num
+
+ 'backlog' => 128, //listen backlog
+
+ 'max_request' => 50,
+
+ 'dispatch_mode' => 1,
+
+// 'daemonize' => 1
+
+ ));
+
+
+ $this->server->on('open', function (swoole_websocket_server $server, $request) {
+
+ //加入房间域
+ $this->redis->hset($this->key,$request->fd,$request->fd);
+ //加入组集合
+ $this->redis->sadd('group', $this->key);
+
+ });
+
+
+
+
+
+ $this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
+ // echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
+
+ $group = $this->redis->sMembers('group');
+
+ foreach ($group as $v) {
+
+ $fangjian = $this->redis->hGetAll($v);
+
+ foreach ($fangjian as $k => $vv) {
+
+ $server->push($vv, count($fangjian).$frame->fd);
+
+ }
+
+ }
+
+
+ });
+
+
+
+
+ $this->server->on('close', function ($server, $fd) {
+
+ $this->redis->hdel($this->key, 2);
+
+ //echo "client {$fd} closed\n";
+ //退出并删除多余的分组fd
+ $group = $this->redis->sMembers('group');
+
+ foreach ($group as $v) {
+
+ $fangjian = $this->redis->hgetall($v);
+
+ foreach ($fangjian as $k => $vv) {
+
+// if ($fd == $vv) {
+
+ $this->redis->hdel($v, $vv);
+// }
+ }
+ }
+
+ });
+
+
+
+
+//
+ $this->server->on('request', function ($request, $response) {
+ // 接收http请求从get获取message参数的值,给用户推送
+ // $this->server->connections 遍历所有websocket连接用户的fd,给所有用户推送
+ foreach ($this->server->connections as $fd) {
+ // 需要先判断是否是正确的websocket连接,否则有可能会push失败
+ if ($this->server->isEstablished($fd)) {
+ $this->server->push($fd, '11');
+ }
+ }
+ });
+
+ $this->server->start();
+ }
+
+
+
+
+
+}
+
+
+new WebsocketTest();
\ No newline at end of file
diff --git a/app/im/controller/Ws.php b/app/im/controller/Ws.php
new file mode 100755
index 0000000..3386ca4
--- /dev/null
+++ b/app/im/controller/Ws.php
@@ -0,0 +1,197 @@
+key = '1223454461';
+ // 加载框架里面的文件
+ require __DIR__ . '/../../../vendor/autoload.php';
+
+ $http = ( new App() )->http;
+
+ $response = $http->run();
+
+ $this->ws = new Server("0.0.0.0", Config::get('swoole.server.mport'));
+
+ $this->ws->set([
+ //worker进程数
+ 'worker_num' => 4,
+ //task进程数
+ 'task_worker_num' => 4,
+ //listen backlog
+ 'backlog' => 128,
+
+ 'max_request' => 50,
+ //心跳检测 每隔多少秒,遍历一遍所有的连接
+ 'heartbeat_check_interval' => 30,
+ //心跳检测 最大闲置时间,超时触发close并关闭
+ 'heartbeat_idle_time' => 65,
+ // 总开关,用来开启tcp_keepalive
+ 'open_tcp_keepalive' => 1,
+ // 4s没有数据传输就进行检测
+ 'tcp_keepidle' => 10,
+ // 4s没有数据传输就进行检测
+ 'tcp_keepcount' => 10,
+ // 1s探测一次,即每隔1s给客户端发一个包(然后客户端可能会回一个ack的包,如果服务端收到了这个ack包,那么说明这个连接是活着的)'tcp_keepcount' => 5,
+ // 探测的次数,超过5次后客户端还没有回ack包,那么close此连接
+ 'tcp_keepinterval' => 5,
+
+ 'log_file' => '/www/wwwroot/swoole.log',
+
+ 'daemonize' => 1
+ ]);
+
+
+
+ $this->ws->on("open", [$this, 'onOpen']);
+
+ $this->ws->on("message", [$this, 'onMessage']);
+
+ $this->ws->on("task", [$this, 'onTask']);
+
+ $this->ws->on("finish", [$this, 'onFinish']);
+
+ $this->ws->on("close", [$this, 'onClose']);
+
+ $this->ws->on('workerStart' ,[$this ,'onWorkerStart']);
+
+ $this->ws->start();
+ }
+
+
+ public function onWorkerStart()
+ {
+
+ $this->messageHandler = new Some();
+
+ }
+ /**
+ * @param $ws
+ * @param $request
+ * @功能说明:建立连接回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function onOpen($ws, $request) {
+
+ $request->get['action'] = !empty($request->get['action'])?$request->get['action']:'mOnOpen';
+
+ if(method_exists($this->messageHandler, $request->get['action']))
+ {
+// try{
+ call_user_func([$this->messageHandler, $request->get['action']] , $request->get,$request->fd);
+
+// }catch(Exception $e) {
+//
+// }
+ }
+
+ // echo FILE_UPLOAD_PATH;
+
+
+ }
+
+
+ /**
+ * @param $ws
+ * @param $frame
+ * @功能说明:接受消息回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function onMessage($ws, $frame) {
+
+ $data = @json_decode($frame->data,true);
+
+ if(is_array($data)){
+
+ if(method_exists($this->messageHandler, $data['action']))
+ {
+// try{
+
+ call_user_func([$this->messageHandler, $data['action']] ,$ws,$data,$frame->fd);
+
+// }catch(Exception $e) {
+//
+// }
+ }
+
+ }
+
+
+ }
+
+
+
+ /**
+ * @param $serv
+ * @param $task_id
+ * @param $worker_id
+ * @param $data
+ * @功能说明:完成异步任务回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:17
+ */
+ public function onTask($serv, $task_id, $worker_id, $data) {
+
+ //返回字符串给worker进程——>触发onFinish
+ return "success";
+ }
+
+
+ /**
+ * @param $serv
+ * @param $task_id
+ * @param $data
+ * @功能说明:完成任务投递回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:16
+ */
+ public function onFinish($serv, $task_id, $data) {
+ //task_worker进程将任务处理结果发送给worker进程
+ echo "完成任务{$task_id}投递 处理结果:{$data}";
+ }
+
+
+ /**
+ * @param $ws
+ * @param $fd
+ * @功能说明:关闭连接回调
+ * @author chenniang
+ * @DataTime: 2021-07-02 18:16
+ */
+ public function onClose($ws, $fd) {
+
+// try{
+
+ call_user_func([$this->messageHandler, 'loginOut'] ,$ws, $fd);
+
+// }catch(Exception $e) {
+//
+// }
+
+// echo "{$fd}关闭了连接1";
+ }
+}
+
+$obj = new Ws();
\ No newline at end of file
diff --git a/app/im/controller/net.php b/app/im/controller/net.php
new file mode 100755
index 0000000..42317d3
--- /dev/null
+++ b/app/im/controller/net.php
@@ -0,0 +1,82 @@
+socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
+
+ socket_bind($this->socket, $ip, $port);
+ $ex = socket_listen($this->socket, 4);
+ //socket_bind($this->socket, '127.0.0.1', $port) or die("socket_bind() fail:" . socket_strerror(socket_last_error()) . "/n");
+ //$ex = socket_listen($this->socket, 4) or die("socket_listen() fail:" . socket_strerror(socket_last_error()) . "/n");
+
+ return $ex;
+ }
+
+ function accept()
+ {
+ return socket_accept($this->socket);
+ }
+
+ function close()
+ {
+ if($this->socket == 0) return;
+ socket_close($this->socket);
+ $this->socket = 0;
+ }
+
+ function send_bytes($cs, $bytes)
+ {
+ $str = $this->bytes_to_string($arr);
+ $ex = $this->send($cs, $str);
+ return $ex;
+ }
+
+ function recv_bytes($cs, $len = 1024)
+ {
+ $ret = $this->recv($cs, $len);
+ $bytes = $this->string_to_bytes($ret);
+ return $bytes;
+ }
+
+ function send($cs, $msg)
+ {
+ $ex = socket_write($cs, $msg);
+ return $ex;
+ }
+
+ function recv($cs, $len = 1024)
+ {
+ $ret = socket_read($cs, $len);
+ return $ret;
+ }
+
+ ///accessibility
+
+ function bytes_to_string($bytes)
+ {
+ $str = '';
+ for($i=0; $i
\ No newline at end of file
diff --git a/app/im/controller/test.php b/app/im/controller/test.php
new file mode 100755
index 0000000..9ec6944
--- /dev/null
+++ b/app/im/controller/test.php
@@ -0,0 +1,61 @@
+listen('192.168.1.55', 50000);
+
+while(true) {
+ $cs = $net->accept();
+
+ while($cs) {
+
+ try{
+ $ret = $net->recv_bytes($cs, 1024);
+ abc($ret);
+ //println($ret);
+ }
+ catch (Exception $e)
+ {
+ //printf('cs close');
+ break;
+ }
+ }
+}
+$net->close();
+
+
+//abc处理读取到的卡(4字节);
+function abc($ret)
+{
+ $len = $ret[4];
+ if($len < 14)
+ {
+ //printf('无效数据');
+ return ;
+ }
+ //
+ $count = $ret[9];
+ $count = ($count - 3) / 4;
+ //
+ for($i=0; $i<$count; $i++)
+ {
+ $idx = 10 + ($i * 4);
+ $card = sprintf("%02X%02X%02X%02X", $ret[$idx+0], $ret[$idx+1], $ret[$idx+2], $ret[$idx+3]);//这是获取到的卡数据(按文档意思可能会读到多张卡,处理这个$card就可以了)
+ printf('card['.$i.']>>'.$card.' | ');
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/app/im/event.php b/app/im/event.php
new file mode 100755
index 0000000..1558ca5
--- /dev/null
+++ b/app/im/event.php
@@ -0,0 +1,5 @@
+ 'im',
+ //模块标题[必填]
+ 'title' =>'即时通讯',
+ //内容简介
+ 'desc' =>'',
+ //封面图标
+ 'icon' =>'',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => 'model',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'im.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.2',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module' => [
+ ['admin', 'admin.longbing.module', '1.0.0']
+ ],
+ // 应用依赖[可选],格式[[插件名, 应用唯一标识, 依赖版本, 对比方式]]
+ 'need_app' => [],
+
+ //订阅消息
+ 'tmpl_name'=>['im_msg']
+
+];
\ No newline at end of file
diff --git a/app/im/info/PermissionIm.php b/app/im/info/PermissionIm.php
new file mode 100755
index 0000000..6d40f5c
--- /dev/null
+++ b/app/im/info/PermissionIm.php
@@ -0,0 +1,71 @@
+saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+ return true ;
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+ return true;
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/im/info/Subscribe.php b/app/im/info/Subscribe.php
new file mode 100755
index 0000000..77c0aa4
--- /dev/null
+++ b/app/im/info/Subscribe.php
@@ -0,0 +1,82 @@
+ '话术库管理',
+ "icon" => 'iconhuashuku',
+ "link" => '/admin/pages/speech/index',
+ "linkType"=> '4',
+
+ ];
+
+ return [$toolsMenu];
+ }
+
+
+ /**
+ * 员工 客户获取列表查询
+ *
+ * @param $data
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/26 10:30
+ */
+ public function onStaffCustomerList($data)
+ {
+ // 聊天数量
+ $map1 = [ [ 'user_id', '=', $data[ 'uid' ] ], [ 'target_id', '=', $data['to_uid'] ] ];
+ $map2 = [ [ 'target_id', '=', $data[ 'uid' ] ], [ 'user_id', '=', $data['to_uid'] ] ];
+ $messageCount = RadarMessage::whereOr( [ $map1, $map2 ] )->count();
+
+ $msgData[ 'count' ] = $messageCount;
+ $msgData[ 'title' ] = "聊天";
+
+ // 通话数量
+ $phoneCount = CardCount::where( [ [ 'user_id', '=', $data[ 'uid' ] ], [ 'to_uid', '=', $data['to_uid'] ],
+ [ 'sign', '=', 'copy' ], [ 'type', 'in', [ 2, 3, 11 ] ] ]
+ )->count();
+
+
+ $phoneData[ 'count' ] = $phoneCount;
+ $phoneData[ 'title' ] = "通话";
+
+ return [$msgData , $phoneData];
+ }
+
+}
\ No newline at end of file
diff --git a/app/im/info/UpdateSql.php b/app/im/info/UpdateSql.php
new file mode 100755
index 0000000..27de0eb
--- /dev/null
+++ b/app/im/info/UpdateSql.php
@@ -0,0 +1,30 @@
+ '欢迎使用ThinkPHP',
+ 'data type error' => '数据类型错误',
+ 'test' => '你好啊',
+ 'picture' => '图片',
+ 'audio' => '音频',
+ 'vedio' => '视频',
+ 'Hello, I am ' => '您好,我是',
+ ', May I help you? Please contact me!' => ',有什么可以帮到您的吗?记得联系我!',
+ 'not chat id ,please check param' => '没有关系数据,请检查传入参数。',
+ 'my reply' => '自定义话术',
+ 'login error' => '登陆失败',
+];
\ No newline at end of file
diff --git a/app/im/middleware.php b/app/im/middleware.php
new file mode 100755
index 0000000..f046e10
--- /dev/null
+++ b/app/im/middleware.php
@@ -0,0 +1,5 @@
+createRow($data);
+ }
+
+ //更新
+ public function updateChart($filter ,$data)
+ {
+ $filter['deleted'] = 0;
+ return $this->updateRow($filter ,$data);
+ }
+
+ //获取列表
+ public function listChart($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->where($filter)->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //获取总数
+ public function listChartCount($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->where($filter)->count();
+ }
+
+ //获取详情
+ public function getChart($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->getRow($filter);
+ }
+
+ //删除
+ public function delChart($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->delRow($filter);
+ }
+
+ //真删除
+ public function destoryChart($filter)
+ {
+ return $this->destoryRow($filter);
+ }
+}
diff --git a/app/im/model/ImChat.php b/app/im/model/ImChat.php
new file mode 100755
index 0000000..a1001ab
--- /dev/null
+++ b/app/im/model/ImChat.php
@@ -0,0 +1,122 @@
+hasOne('ImCustomer' ,)
+// }
+ //创建
+ public function createChat($data)
+ {
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ if(!empty($result)) $result = $this->id;
+ return $result;
+ }
+
+ //更新
+ public function updateChat($filter ,$data)
+ {
+ $filter['deleted'] = 0;
+ return $this->updateRow($filter ,$data);
+ }
+
+ //获取列表
+ public function listChat($user_id , $uniacid,$page_config)
+ {
+
+
+
+
+
+ $start_row = 0;
+ $page_count = 10;
+ if(isset($page_config['page_count']) && !empty($page_config['page_count']) && $page_config['page_count'] > 0) $page_count = $page_config['page_count'];
+ if(isset($page_config['page']) && !empty($page_config['page']) && $page_config['page'] > 0) $start_row = ($page_config['page'] -1) * $page_count;
+ $result = $this->where(function ($query) use ($user_id) {
+ $query->whereOr(['target_id' => $user_id , 'user_id' => $user_id]) ;
+ })
+ ->where(['deleted' => 0 ,'uniacid' => $uniacid])
+ ->order('update_time', 'desc')
+ ->limit($start_row,$page_count)
+ ->select();
+
+// $result = $this->where(['deleted' => 0])
+// ->where(function($query) use($user_id) {
+// $query->
+// })
+// ->limit($start_row,$page_count)
+// ->select();
+
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //获取总数
+ public function listChatCount($user_id , $uniacid)
+ {
+ return $this->where(function ($query) use ($user_id) {
+ $query->whereOr(['target_id' => $user_id , 'user_id' => $user_id]) ;
+ })
+ ->where(['deleted' => 0 ,'uniacid' => $uniacid])
+ ->count();
+ }
+ //获取所有
+ public function listChatAll($user_id ,$uniacid)
+ {
+ $result = $this->where(function ($query) use ($user_id) {
+ $query->whereOr(['target_id' => $user_id] , ['user_id' => $user_id]) ;
+ })
+ ->where(['deleted' => 0 ,'uniacid' => $uniacid])
+ ->field('id as chat_id,user_id,target_id')
+ ->select();
+
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //获取单个Chat
+ public function getChat($user_id ,$target_id ,$uniacid)
+ {
+ //查询条件1
+ $where = [
+ ['user_id' , '=' ,$user_id],
+ ['target_id' ,'=' , $target_id],
+ ];
+ $whereOr = [
+ ['user_id' , '=' ,$target_id],
+ ['target_id' ,'=' , $user_id],
+ ];
+ $result = $this->where(function ($query) use($where, $whereOr){
+ $query->whereOr([$where,$whereOr]);
+ })
+ ->where(['uniacid' => $uniacid ,'deleted' => 0])
+ ->field('id as chat_id,user_id,target_id')
+ ->find();
+ return $result;
+ }
+ //通过id获取chat
+ public function getChatById($chat_id)
+ {
+ $result = $this->where(['id' => $chat_id])->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //删除
+ public function delChat($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->updateChat($filter ,['deleted' => 0]);
+ }
+ //真删除
+ public function destroyChat($filter)
+ {
+ return $this->destroyRow($filter);
+ }
+}
diff --git a/app/im/model/ImClient.php b/app/im/model/ImClient.php
new file mode 100755
index 0000000..4c2e146
--- /dev/null
+++ b/app/im/model/ImClient.php
@@ -0,0 +1,24 @@
+ $customer_id,
+ 'to_uid' => $user_id,
+ 'uniacid' => $uniacid,
+ 'intention' => 1
+ );
+
+ $result = $this->where($filter)->count();
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/im/model/ImMessage.php b/app/im/model/ImMessage.php
new file mode 100755
index 0000000..731eeba
--- /dev/null
+++ b/app/im/model/ImMessage.php
@@ -0,0 +1,124 @@
+createRow($data);
+ }
+
+ //修改聊天消息
+ public function updateMessage($filter ,$data)
+ {
+ $filter['deleted'] = 0;
+ return $this->updateRow($filter ,$data);
+ }
+
+ //标记已读消息
+ public function readMessage($filter)
+ {
+ $filter['status'] = 1;
+ return $this->updateMessage($filter ,['status' => 2]);
+ }
+
+ //撤销消息
+ public function recallMessage($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->updateMessage($filter, ['status' => 3]);
+ }
+
+ //查询聊天消息列表
+ public function listMessage($filter ,$page_config)
+ {
+ $start_row = 0;
+ $page_count = 10;
+ if(isset($page_config['page_count']) && !empty($page_config['page_count']) && $page_config['page_count'] > 0) $page_count = $page_config['page_count'];
+ if(isset($page_config['page']) && !empty($page_config['page']) && $page_config['page'] > 0) $start_row = ($page_config['page'] -1) * $page_count;
+// $filter['deleted'] = 0;
+ $result = $this->where($filter)
+ ->where(['deleted'=>0])
+ ->order('id desc')
+ ->limit($start_row ,$page_count)
+ ->select();
+ if(!empty($result))
+ {
+ $result = $result->toArray();
+ $result = array_reverse($result);
+ }
+ return $result;
+ }
+
+ //查询聊天消息列表
+ public function listMessageV2($filter ,$page_config,$dis)
+ {
+ $start_row = 0;
+ $page_count = 10;
+ if(isset($page_config['page_count']) && !empty($page_config['page_count']) && $page_config['page_count'] > 0) $page_count = $page_config['page_count'];
+ if(isset($page_config['page']) && !empty($page_config['page']) && $page_config['page'] > 0) $start_row = ($page_config['page'] -1) * $page_count;
+// $filter['deleted'] = 0;
+ $result = $this->where($filter)
+ ->whereOr(function ($query) use ($dis){
+ $query->where($dis);
+ })
+ ->order('id desc')
+ ->limit($start_row ,$page_count)
+ ->select();
+ if(!empty($result))
+ {
+ $result = $result->toArray();
+ $result = array_reverse($result);
+ }
+ return $result;
+ }
+
+
+ //获取聊天消息总量
+ public function listMessageCount($filter)
+ {
+ $filter['deleted'] = 0;
+ $count = $this->where($filter)->count();
+ return $count;
+ }
+
+ //删除聊天消息
+ public function delMessage($filter)
+ {
+ $filter['deleted'] = 0;
+ return $this->deleteRow($filter);
+ }
+
+ //查询最后一条消息
+ public function lastMessage($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->where($filter)->order('create_time', 'desc')->field(['create_time' ,'content' ,'message_type'])->find();
+ return $result;
+ }
+ //获取未读消息列表
+ public function listNotReadMessage($filter)
+ {
+ $filter['deleted'] = 0;
+ $filter['status'] = 1;
+ $result = $this->where($filter)
+ ->order('create_time' ,'asc')
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ $this->updateMessage($filter, ['status' =>2]);
+ return $result;
+ }
+
+ //真删除
+ public function destroyMessage($filter)
+ {
+ return $this->destoryRow($filter);
+ }
+}
diff --git a/app/im/model/ImMessageFriend.php b/app/im/model/ImMessageFriend.php
new file mode 100755
index 0000000..9cfe67f
--- /dev/null
+++ b/app/im/model/ImMessageFriend.php
@@ -0,0 +1,11 @@
+where('content','like', '%' . $value . '%');
+ }
+ public function searchUserIdAttr($query, $value, $data)
+ {
+ $query->where('user_id','=', $value);
+ }
+ public function searchUniacidAttr($query, $value, $data)
+ {
+ $query->where('uniacid','=', $value);
+ }
+ public function type()
+ {
+ return $this->hasOne('ImReplyType' ,'id' ,'type');
+ }
+ //创建话术
+ public function createReply($data)
+ {
+ $data['create_time'] = time();
+ $result = $this->save($data);
+ return !empty($result);
+ }
+
+ //更新话术
+ public function updateReply($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ //获取话术列表
+ public function listReply($filter)
+ {
+ $result = $this->where($filter)
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //获取话术列表(分页)
+ public function listReplys($filter ,$page_config)
+ {
+ $result = $this->with(['type'])
+ ->withSearch(['content' ,'user_id' ,'uniacid'] ,$filter)
+ ->order('top' ,'desc')
+ ->page($page_config['page'] ,$page_config['page_count'])
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //获取话术总数
+ public function getReplyCount($filter)
+ {
+ $result = $this->withSearch(['content' ,'user_id' ,'uniacid'] ,$filter)->count();
+ if(empty($result)) $result = 0;
+ return $result;
+ }
+
+ //删除话术
+ public function deleteReply($filter)
+ {
+ return $this->destoryReply($filter);
+ }
+
+ //删除(真删除)
+ public function destoryReply($filter)
+ {
+ $result = $this->where($filter)->delete();
+ return !empty($result);
+ }
+}
\ No newline at end of file
diff --git a/app/im/model/ImReplyType.php b/app/im/model/ImReplyType.php
new file mode 100755
index 0000000..a0f5050
--- /dev/null
+++ b/app/im/model/ImReplyType.php
@@ -0,0 +1,74 @@
+where('title','like', '%' . $value . '%');
+ }
+
+ public function searchUniacidAttr($query, $value, $data)
+ {
+ $query->where('uniacid','=', $value );
+ }
+
+ public function reply()
+ {
+ return $this->belongsTo('ImMyReply' ,'id' ,'type');
+ }
+ //创建话术
+ public function createType($data)
+ {
+ $data['create_time'] = time();
+ return $this->save($data);
+ }
+ //更新话术
+ public function updateType($filter ,$data)
+ {
+ $data['update_time'] = time();
+ $result = $this->where($filter)->update($data);
+ return !empty($result);
+ }
+
+ //获取话术列表
+ public function listType($filter ,$page_config = ['page' => 1 ,'page_count' => 20])
+ {
+ $result = $this->withSearch(['title' ,'uniacid'] ,$filter)
+ ->page($page_config['page'] ,$page_config['page_count'])
+ ->order('top desc, id desc')
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+ //获取话术列表
+ public function getTypeCount($filter)
+ {
+ $result = $this->withSearch(['title' ,'uniacid'] ,$filter)
+ ->count();
+ if(empty($result)) $result = 0;
+ return $result;
+ }
+
+ //删除话术
+ public function delType($filter)
+ {
+ $result = $this->where($filter)->delete();
+ return !empty($result);
+ }
+
+ public function listAllType($filter)
+ {
+ $result = $this->where($filter)
+ ->order('top' ,'desc')
+ ->select();
+ if(empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+}
diff --git a/app/im/model/ImSystemReply.php b/app/im/model/ImSystemReply.php
new file mode 100755
index 0000000..e439619
--- /dev/null
+++ b/app/im/model/ImSystemReply.php
@@ -0,0 +1,38 @@
+createRow($data);
+ }
+ //更新话术
+ public function updateReply($filter ,$data)
+ {
+ return $this->updateRow($filter ,$data);
+ }
+
+ //获取话术列表
+ public function listReply($filter)
+ {
+ $filter['deleted'] = 0;
+ $result = $this->where($filter)
+ ->select();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+
+ //删除话术
+ public function delReply($filter)
+ {
+ return $this->deleteRow($filter);
+ }
+
+}
diff --git a/app/im/model/ImUser.php b/app/im/model/ImUser.php
new file mode 100755
index 0000000..02f2b38
--- /dev/null
+++ b/app/im/model/ImUser.php
@@ -0,0 +1,19 @@
+where($filter)->find();
+ if(!empty($result)) $result = $result->toArray();
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/app/im/provider.php b/app/im/provider.php
new file mode 100755
index 0000000..d89f234
--- /dev/null
+++ b/app/im/provider.php
@@ -0,0 +1,5 @@
+where($where)->order('is_read desc , update_time desc' )->paginate($page_count);
+ foreach ($friendList as $key => &$friend ){
+
+ $friendId = $friend['friend_id'] ;
+
+ $customer = longbingGetUser($friendId , $uniacid );
+
+ //判断客户是否是员工
+ if(isset($customer['is_staff']) && !empty($customer['is_staff']))
+ {
+ $customer_info = longbingGetUserInfo($friendId , $uniacid );
+ if(isset($customer_info['is_staff']) && !empty($customer_info['is_staff']))
+ {
+ if(!empty($customer_info['avatar'])) {
+ $customer_info = transImagesOne($customer_info ,['avatar'] , $uniacid );
+ }
+ //是员工 就用员工头像 By.jingshuixian
+ if(!empty($customer_info['avatar'])) $customer['avatarUrl'] = $customer_info['avatar'];
+
+ $customer['nickName'] = empty($customer_info['name']) ? $customer['nickName'] : $customer_info['name'];
+ }
+ }
+
+ //没有头像就给一个默认头像
+ $customer['avatarUrl'] = empty($customer['avatarUrl']) ? LongbingDefault::$avatarImgUrl : $customer['avatarUrl'];
+
+ $friend['customer'] = $customer ;
+
+ $friend['target_id'] = $friendId ;
+
+ $friend['not_read_message_count'] = self::notReadCount($friend) ;
+
+ $last_msg = self::getLastMsg($friend);
+ //兼容老数据格式
+ $friend['lastmessage'] = [
+
+ 'message_type' => !empty($last_msg)?$last_msg['message_type']:'text',
+
+ 'content' => !empty($last_msg)?$last_msg['content']:'',
+
+ 'is_show' => !empty($last_msg)?$last_msg['is_show']:1,
+
+ 'is_self' => !empty($last_msg)&&$last_msg['user_id'] == $friend['user_id']?1:0
+
+ ];
+
+ $friend['time'] = date('Y-m-d H:i:s', $friend['update_time']);
+
+ }
+
+ return empty($friendList) ? [] : $friendList->toArray() ;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-05-27 16:10
+ * @功能说明:后去最后一条消息(除开自己删除的)
+ *
+ *
+ */
+ public static function getLastMsg($friend){
+
+ $message_model = new ImMessage();
+ //自己接收的
+ $dis = [
+
+ 'user_id' => $friend['friend_id'],
+
+ 'target_id' => $friend['user_id']
+ ];
+
+ $where = [];
+ //自己发送的
+ $where[] = ['user_id','=',$friend['user_id']];
+
+ $where[] = ['target_id','=',$friend['target_id']];
+ //要除开删除的
+ $where[] = ['is_show','<>',2];
+
+// $where[] = ['target_is_show','<>',2];
+
+ $last_msg = $message_model->where($dis)->where('target_is_show','<>',2)->whereOr(function ($query) use ($where) {
+ $query->where($where);
+ })->order('create_time desc')->find();
+
+
+ return !empty($last_msg)?$last_msg->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-05-27 16:38
+ * @功能说明:未读消息读数量
+ */
+ public static function notReadCount($friend){
+
+ $message_model = new ImMessage();
+ //自己接收的
+ $dis = [
+
+ 'user_id' => $friend['friend_id'],
+
+ 'target_id' => $friend['user_id'],
+
+ 'status' => 1,
+
+ 'target_is_show' => 1
+
+ ];
+
+ $count = $message_model->where($dis)->count();
+
+ return $count;
+ }
+
+ /**
+ * @param $uniacid
+ * @param $userId
+ * @功能说明:老数据转移到新数据上
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 14:52
+ */
+ public static function initOldFriendList($uniacid , $userId){
+ $imMessageFriend = new ImMessageFriend() ;
+
+ $where[] = ['uniacid' , '=' , $uniacid ] ;
+ $where[] = ['user_id' , '=' , $userId ] ;
+ $friendCount = $imMessageFriend->where($where)->count();
+
+ if(! $friendCount){ //没有好友就用message数据导入好友列表
+ $imMessage = new ImMessage() ;
+
+
+ $whereIm[] = ['uniacid' , '=' , $uniacid ] ;
+ $whereIm[] = ['status' ,'in' , [ 1,2] ] ;
+
+ $whereOr[] = ['user_id' ,'=' ,$userId ] ;
+ $whereOr[] = ['target_id' ,'=' ,$userId ] ;
+
+ $chat_ids = $imMessage->where($whereIm)->where(function ($query) use($whereOr) {
+ $query->whereOr($whereOr);
+ })->distinct(true)->field('chat_id')->select();
+
+ $friendData = [] ;
+ foreach ($chat_ids as $key => $item) {
+
+ if ($item) {
+
+ $chat_id = $item['chat_id'];
+ $message = $imMessage->where([['uniacid', '=', $uniacid], ['chat_id', '=', intval($chat_id)], ['status', 'in', [1,2] ]])->where(function ($query) use ($whereOr) {
+ $query->whereOr($whereOr);
+ })->order('id desc')->find();
+
+ //这里代码和 updateFriendByMessage 里的代码,大部分是重复的,只是一个批量插入和一个此插入
+ if ($message) {
+
+ $friendId = $message['user_id'] != $userId ? $message['user_id'] : $message['target_id'];
+ //判断用户是否存在
+ if( !LongbingUserService::isUser($uniacid , $friendId) ) continue ;
+
+ $friendItem['user_id'] = $userId;
+
+ $friendItem['friend_id'] = $friendId;
+
+ $friendItem['uniacid'] = $uniacid;
+ //获取最后一条消息内容
+ $whereOr = [];
+
+ $whereOr[] = ['user_id', '=', $userId];
+
+ $whereOr[] = ['target_id', '=', $userId];
+
+ $friendItem['message_type'] = $message['message_type'];
+
+ $friendItem['lastmessage'] = in_array( $message['message_type'] , ['image' , 'picture' ]) ? '[图片]' :$message['content'];
+
+ $friendItem['create_time'] = $message['create_time'];
+
+ $friendItem['update_time'] = $message['update_time'];
+
+ $friendItem['is_show'] = $message['is_show'];
+
+ $notReadMessageCount = $imMessage->where([
+ ['uniacid', '=', $uniacid],
+ ['user_id', '=', $friendId],
+ ['target_id', '=', $userId],
+ ['status', '=', 1]
+ ])->count();
+
+ $friendItem['not_read_message_count'] = $notReadMessageCount;
+
+ $friendItem['is_read'] = $notReadMessageCount ? 1 : 0 ;
+
+ $friendData[] = $friendItem;
+
+ }
+
+ }
+ }
+
+ $inserCount = $imMessageFriend->insertAll($friendData);
+
+ return $inserCount;
+
+ }
+
+
+ return false ;
+
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 15:03
+ * @功能说明:根据消息数据更新好友信息
+ */
+ public static function updateFriendByMessage( ImMessage $message ){
+
+ if ($message) {
+
+ $userId = $message['user_id'] ;
+ $friendId = $message['target_id'] ;
+ $uniacid = $message['uniacid'] ;
+
+ self::updateFriendByUserIdAndFriend($uniacid , $userId , $friendId ) ;
+ self::updateFriendByUserIdAndFriend($uniacid , $friendId , $userId ) ;
+
+
+ }
+
+ return false ;
+
+ }
+
+ /**
+ * @param ImMessage $message
+ * @功能说明:更新用户好友的关系和未读数据信息
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 16:47
+ */
+ public static function updateFriendByUserIdAndFriend( $uniacid , $userId , $friendId){
+
+ //判断用户是否存在
+ if( !LongbingUserService::isUser($uniacid , $userId) && !LongbingUserService::isUser( $uniacid , $friendId) ) return false ;
+
+ $imMessage = new ImMessage() ;
+ $imMessageFriend = new ImMessageFriend() ;
+
+ $friendItem['user_id'] = $userId;
+ $friendItem['friend_id'] = $friendId;
+ $friendItem['uniacid'] = $uniacid;
+
+ //获取最后一条消息内容
+ $message = ImMessageService::getLastMessage( $uniacid , $userId , $friendId ) ;
+ if($message){
+
+ $friendItem['message_type'] = $message['message_type'];
+ $friendItem['lastmessage'] = in_array( $message['message_type'] , ['image' ,'picture' ]) ? '[图片]' : $message['content'];
+ $friendItem['create_time'] = $message['create_time'];
+ $friendItem['update_time'] = $message['update_time'];
+
+ }else{
+ $friendItem['message_type'] = '';
+ $friendItem['lastmessage'] = '';
+ $friendItem['create_time'] = time();
+ $friendItem['update_time'] = time();
+ }
+
+ //更新我的未读消息
+ $notReadMessageCount = $imMessage->where([
+ ['uniacid', '=', $uniacid],
+ ['user_id', '=',$friendId ],
+ ['target_id', '=', $userId ],
+ ['status', '=', 1]
+ ])->count();
+
+ $friendItem['not_read_message_count'] = $notReadMessageCount;
+
+ $friendItem['is_read'] = $notReadMessageCount ? 1 : 0 ;
+
+ //判断 消息发送人好友关系
+ $oneFriend = self::getOneByUserIdAndFriendId($userId,$friendId);
+ if($oneFriend){
+ $friendItem['id'] = $oneFriend['id'];
+
+ $friendItem['create_time'] = $oneFriend['create_time'];
+
+ return $imMessageFriend->update( $friendItem );
+ }else{
+ return $imMessageFriend->insert( $friendItem );
+ }
+
+
+
+ }
+
+ /**
+ * @param $userId
+ * @param $friendId
+ * @功能说明:判断是否是好友关系
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 15:12
+ */
+ public static function isFriend($userId , $friendId){
+
+ $imMessageFriend = new ImMessageFriend() ;
+ $where[] = ['user_id' ,'=' ,$userId ] ;
+ $where[] = ['friend_id' ,'=' ,$friendId ] ;
+
+ $count = $imMessageFriend->where($where)->count();
+
+ return $count ? true : false;
+ }
+
+ /**
+ * @param $userId
+ * @param $friendId
+ * @功能说明:更新用户ID和朋友ID获取好友关系数据
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 15:14
+ */
+ public static function getOneByUserIdAndFriendId($userId , $friendId){
+
+ $imMessageFriend = new ImMessageFriend() ;
+ $where[] = ['user_id' ,'=' ,$userId ] ;
+ $where[] = ['friend_id' ,'=' ,$friendId ] ;
+
+ return $imMessageFriend->where($where)->find() ;
+ }
+
+
+ /**
+ * @param $uniacid
+ * @param $userId
+ * @param $friendId
+ * @功能说明:处理好友的已读情况
+ * @author jingshuixian
+ * @DataTime: 2020/1/16 17:23
+ */
+ public static function readMessage($uniacid , $userId , $friendId){
+ $imMessageFriend = new ImMessageFriend() ;
+ $count = $imMessageFriend->where([ ['uniacid' , '=', $uniacid ] , ['user_id' , '=' ,$userId ] , ['friend_id' , '=' , $friendId ] ])->update([ 'is_read' => 0 , 'not_read_message_count' => 0 ]) ;
+
+ return $count;
+ }
+
+}
\ No newline at end of file
diff --git a/app/im/service/ImMessageService.php b/app/im/service/ImMessageService.php
new file mode 100755
index 0000000..f95a64f
--- /dev/null
+++ b/app/im/service/ImMessageService.php
@@ -0,0 +1,51 @@
+where([['uniacid', '=', $uniacid] , ['status', 'in', [1,2] ]])->whereOr(function ($query) use ($whereOr1) {
+ $query->where($whereOr1);
+ })->whereOr(function ($query) use ($whereOr2) {
+ $query->where($whereOr2);
+ })->order('id desc')->find();
+
+ return $message ;
+
+ }
+}
\ No newline at end of file
diff --git a/app/im/service/ImService.php b/app/im/service/ImService.php
new file mode 100755
index 0000000..90a9c38
--- /dev/null
+++ b/app/im/service/ImService.php
@@ -0,0 +1,244 @@
+insertGetId( $data );
+ if($result){
+ //修改时间chat
+ $chat_model = new ImChat();
+ $chat_model->updateChat(['id' => $data['chat_id']] ,[]);
+
+ //修改朋友表数据
+ ImMessageFriendService::updateFriendByMessage($message_model->find($result));
+
+
+ }
+
+ return $result;
+
+
+ }
+
+ /**
+ * @param $uniacid
+ * @param $user_id
+ * @param $customer_id
+ * @功能说明:获取聊天房间ID
+ * @author jingshuixian
+ * @DataTime: 2020/1/13 17:01
+ */
+ public static function getChatId($uniacid , $user_id ,$target_id )
+ {
+ $chat_model = new ImChat();
+
+ //查询条件
+ $where = [
+ ['user_id' , '=' ,$user_id],
+ ['target_id' ,'=' , $target_id],
+ ];
+ $whereOr = [
+ ['user_id' , '=' ,$target_id],
+ ['target_id' ,'=' , $user_id],
+ ];
+ $chatId = $chat_model->where(function ($query) use($where, $whereOr){
+ $query->whereOr([$where,$whereOr]);
+ })
+ ->where(['uniacid' => $uniacid ,'deleted' => 0])
+ ->field('id as chat_id,user_id,target_id')
+ ->value('id');
+
+
+ if(empty($chatId))
+ {
+ $chatData= (['user_id' => $user_id ,'target_id' => $target_id ,'uniacid' => $uniacid ,'create_time' => time()]);
+ $chatId = $chat_model->createChat($chatData);
+ }
+
+ return $chatId;
+ }
+
+ /**
+ * @param $userId
+ * @功能说明:获取未读消息数量
+ * @author jingshuixian
+ * @DataTime: 2020/1/13 17:22
+ */
+ public static function getUnReadMessageCount($userId){
+
+ $message_model = new ImMessage();
+ $count = $message_model->listMessageCount(['target_id' => $userId ,'status' => 1]);
+
+ return $count;
+ }
+
+ /**
+ * @param $userId
+ * @param $target_id
+ * @功能说明:根据用户ID和目标用户ID获取未读消息数量
+ * @author jingshuixian
+ * @DataTime: 2020/1/15 12:10
+ */
+ public static function getUnReadMessageCountByUserIdAndTargetId($userId , $target_id ){
+
+ $message_model = new ImMessage();
+ $count = $message_model->listMessageCount(['user_id'=> $userId ,'target_id' => $target_id ,'status' => 1]);
+
+ return $count;
+ }
+
+ /**
+ * @param $uniacid
+ * @param $chat_id
+ * @param $user_id
+ * @功能说明: 更新消息未读信息,返回修改数量
+ * @author jingshuixian
+ * @DataTime: 2020/1/14 9:54
+ */
+ public static function readMessage($uniacid , $user_id , $friendId){
+
+ $message_model = new ImMessage();
+
+ $count = $message_model->where([
+ ['uniacid' , '=' , $uniacid] ,
+ ['user_id' , '=' , $friendId ] ,
+ ['target_id' , '=' , $user_id ]
+
+ ])->update([ 'status' => 2 ]) ;
+
+ //处理未读消息数据
+ ImMessageFriendService::readMessage( $uniacid , $user_id , $friendId ) ;
+
+
+ return $count ;
+ }
+
+
+ /**
+ * @param $uniacid
+ * @param $userId
+ * @param $data
+ * @param string $page
+ * @功能说明:发送模板消息
+ * @author jingshuixian
+ * @DataTime: 2020/1/14 13:42
+ */
+ public static function sendTmplMsg($uniacid , $userId ,$data , $page='' , $tmpl_name = 'im_msg'){
+
+ $openid = LongbingUserService::getUserOpenId($userId);
+
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$uniacid,'tmpl_name'=>$tmpl_name])->find();
+
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+ return true;
+ }else{
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+
+ $service_model = new WxTmpl( $uniacid );
+
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+
+ //发送内容
+ $send_data = [];
+ foreach ($key_worlds as $key => $item ){
+ $send_data[$item]['value'] = $data[$key -1 ] ;
+ }
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($uniacid);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+ return true;
+ }
+
+ /**
+ * @param $uniacid
+ * @param $user_id
+ * @param $target_id
+ * @功能说明:发送聊天通知信息
+ * @author jingshuixian
+ * @DataTime: 2020/2/27 11:49
+ */
+ public static function sendImMessageTmpl($uniacid , $user_id , $target_id , $message = ''){
+
+
+
+
+ if(LongbingUserInfoService::isStraffByUserId($user_id) && !LongbingUserInfoService::isStraffByUserId($target_id)) //发送者是员工并且接收者是普通用户,员工回复消息,通知用户采用订阅消息
+ {
+
+
+ $message = '有未读私信' ;
+
+ $name= $name = LongbingUserInfoService::getNameByUserId($user_id);
+
+
+ ImService::sendTmplMsg($uniacid , $target_id , [ $name , $message , LongbingTime::getChinaNowTime()] , 'pages/user/home' );
+
+ }else //发送者是普通用户,消息接收人是员工
+ {
+
+
+ $count = self::getUnReadMessageCount($target_id);
+
+ $message = '有' . $count .'条未读私信' ;
+
+ $notice = new LongbingServiceNotice($uniacid);
+
+ $name = LongbingUserService::getUserNickNameOpenId($user_id);
+
+ $notice->sendImMessageServiceNoticeToStaff($target_id ,$message , $name);
+
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/im/view/index/index.html b/app/im/view/index/index.html
new file mode 100755
index 0000000..e69de29
diff --git a/app/index/common.php b/app/index/common.php
new file mode 100755
index 0000000..888647c
--- /dev/null
+++ b/app/index/common.php
@@ -0,0 +1,32 @@
+fetch('index');
+ }
+}
diff --git a/app/index/controller/Login.php b/app/index/controller/Login.php
new file mode 100755
index 0000000..8c9d5f0
--- /dev/null
+++ b/app/index/controller/Login.php
@@ -0,0 +1,420 @@
+request = $app->request;
+ //获取param
+ $this->_param = $this->request->param();
+
+ $this->_input = json_decode($this->request->getInput(), true);
+ //获取uniacid
+ if (!isset($this->_param['i']) || !$this->_param['i']) {
+
+ return $this->error('need uniacid',400);
+ }
+
+ $this->uniacid = $this->_param['i'];
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 10:06
+ * @功能说明:小程序用户登陆接口
+ */
+ function index()
+ {
+ $input = $this->_param;
+
+ if (!isset($this->_param['code']) || !$this->_param['code']) {
+
+ return $this->error(['code' => 400, 'error' => 'need code']);
+
+ }
+
+ $cap_id = !empty($input['cap_id'])?$input['cap_id']:0;
+
+ $code = $this->_param['code'];
+ // 是否是微擎
+ $config = longbingGetAppConfig($this->uniacid);
+
+ $appid = $config['appid'];
+
+ $appsecret = $config['appsecret'];
+ // 从微信获取openid等
+ $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appid}&secret={$appsecret}&js_code={$code}&grant_type=authorization_code";
+
+ $arrContextOptions = array(
+
+ "ssl"=>array(
+
+ "verify_peer" => false,
+
+ "verify_peer_name"=> false,
+ ),
+ );
+
+ $info = file_get_contents($url ,false, stream_context_create($arrContextOptions));
+
+ $info = @json_decode($info, true);
+ // 微信端返回错误
+ if (isset($info['errcode'])) {
+
+ return $this->error($info['errcode'] . ', errmsg: ' . $info['errmsg']);
+
+ }
+ if (!isset($info['session_key'])) {
+
+ return $this->error('session_key not exists','402');
+
+ }
+
+ if(empty($info['openid'])){
+
+ return $this->error('openid not exists');
+
+ }
+
+ $user_model = new User();
+
+ $dis = [
+
+ 'openid' => $info['openid'],
+
+ 'uniacid' => $this->uniacid
+
+ ];
+
+ $user_info = $user_model->dataInfo($dis);
+
+ if(empty($user_info)){
+
+ try {
+
+ $insert = [
+
+ 'uniacid' => $this->uniacid,
+
+ 'openid' => $info['openid'],
+
+ 'cap_id' => $cap_id,
+
+ 'session_key' => $info['session_key'],
+
+
+ ];
+
+ if(!empty($input['pid'])){
+
+ $insert['pid'] = $input['pid'];
+ }
+
+ $user_model->dataAdd($insert);
+
+ }catch(Exception $e)
+ {}
+
+ // $user_id = $user_model->getLastInsID();
+
+ $user_info = $user_model->dataInfo($insert);
+
+
+ }else{
+
+ $user_model->dataUpdate(['id'=>$user_info['id']],['session_key'=>$info['session_key']]);
+ }
+
+ $key = 'longbing_user_autograph_' . $user_info['id'];
+
+ $key = md5($key);
+
+ setCache($key, $user_info, 7200, $this->uniacid);
+
+ $arr = [
+
+ 'data' => $user_info,
+
+ 'autograph' => $key
+ ];
+
+ return $this->success($arr);
+
+ }
+
+ //返回成功
+ public function success($data, $code = 200)
+ {
+ $result['data'] = $data;
+ $result['code'] = $code;
+ $result['sign'] = null;
+
+ return $this->response($result, 'json', $code);
+ }
+
+ //返回错误数据
+ public function error($msg, $code = 400)
+ {
+ $result['error'] = $msg;
+ $result['code'] = $code;
+ return $this->response($result, 'json', $code);
+ }
+
+ //response
+ protected function response($data, $type = 'json', $code = 200)
+ {
+ return Response::create($data, $type)->code($code);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 10:06
+ * @功能说明:微信登陆
+ */
+ function appLogin()
+ {
+ $input = $this->_input;
+
+ $uniacid = $this->uniacid;
+
+ $input = $input['data'];
+
+ $cap_id = !empty($input['cap_id'])?$input['cap_id']:0;
+
+ $user_model = new User();
+
+ $dis = [
+
+ 'unionid' => $input['unionId'],
+
+ ];
+
+ $user_info = $user_model->dataInfo($dis);
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'nickName' => $input['nickName'],
+
+ 'avatarUrl'=> $input['avatarUrl'],
+
+ 'unionid' => $input['unionId'],
+
+ 'gender' => $input['gender'],
+
+ 'city' => $input['city'],
+
+ 'province' => $input['province'],
+
+ 'country' => $input['country'],
+
+ 'openid' => $input['openId'],
+
+ 'app_openid' => $input['openId'],
+
+ 'push_id' => !empty($input['push_id'])?$input['push_id']:'',
+
+ 'cap_id' => $cap_id,
+
+ 'last_login_type' => 1,
+
+ ];
+
+ if(empty($user_info)){
+
+ if(!empty($input['pid'])){
+
+ $insert['pid'] = $input['pid'];
+ }
+
+ $user_model->dataAdd($insert);
+
+ $user_id = $user_model->getLastInsID();
+
+ }else{
+
+ $user_id = $user_info['id'];
+
+ $user_model->dataUpdate(['id'=>$user_id],$insert);
+
+ }
+
+ $user_info = $user_model->dataInfo(['id'=>$user_id]);
+
+ $key = 'longbing_user_autograph_' . $user_info['id'];
+
+ $key = md5($key);
+
+ setCache($key, $user_info, 7200, $this->uniacid);
+
+ $arr = [
+
+ 'data' => $user_info,
+
+ 'autograph' => $key
+ ];
+
+ return $this->success($arr);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 10:06
+ * @功能说明:ios登陆
+ */
+ function iosLogin()
+ {
+ $input = $this->_input;
+
+ $uniacid = $this->uniacid;
+
+ $input = $input['data'];
+
+ $cap_id = !empty($input['cap_id'])?$input['cap_id']:0;
+
+ $user_model = new User();
+
+ $dis = [
+
+ 'openid' => $input['openId'],
+
+ ];
+
+ $user_info = $user_model->dataInfo($dis);
+
+ $familyName = !empty($input['fullName']['familyName'])?$input['fullName']['familyName']:'';
+
+ $giveName = !empty($input['fullName']['giveName'])?$input['fullName']['giveName']:'';
+
+ $name = !empty($familyName.$giveName)?$familyName.$giveName:'默认用户';
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'nickName' => $name,
+
+ 'avatarUrl'=> 'https://lbqny.migugu.com/admin/farm/default-user.png',
+
+// 'unionid' => $input['unionId'],
+//
+// 'gender' => $input['gender'],
+//
+// 'city' => $input['city'],
+//
+// 'province' => $input['province'],
+//
+// 'country' => $input['country'],
+
+ 'openid' => $input['openId'],
+
+ //'app_openid' => $input['openId'],
+
+ 'push_id' => !empty($input['push_id'])?$input['push_id']:'',
+
+ 'cap_id' => $cap_id,
+
+ 'last_login_type' => 1,
+
+ ];
+
+ if(empty($user_info)){
+
+ if(!empty($input['pid'])){
+
+ $insert['pid'] = $input['pid'];
+ }
+
+ $user_model->dataAdd($insert);
+
+ $user_id = $user_model->getLastInsID();
+
+ }else{
+
+ $user_id = $user_info['id'];
+
+ $user_model->dataUpdate(['id'=>$user_id],$insert);
+
+ }
+
+ $user_info = $user_model->dataInfo(['id'=>$user_id]);
+
+ $key = 'longbing_user_autograph_' . $user_info['id'];
+
+ $key = md5($key);
+
+ setCache($key, $user_info, 7200, $this->uniacid);
+
+ $arr = [
+
+ 'data' => $user_info,
+
+ 'autograph' => $key
+ ];
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-10 18:30
+ * @功能说明:
+ */
+ public function getConfig(){
+
+ $config = longbingGetAppConfig($this->uniacid);
+
+ $data['login_protocol'] = $config['login_protocol'];
+
+ $data['app_text'] = $config['app_text'];
+
+ $data['app_logo'] = $config['app_logo'];
+
+ $data['ios_login'] = $config['ios_login'];
+
+ $data['information_protection'] = $config['information_protection'];
+
+ $data['app_banner'] = $config['app_banner'];
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+}
diff --git a/app/index/event.php b/app/index/event.php
new file mode 100755
index 0000000..509392b
--- /dev/null
+++ b/app/index/event.php
@@ -0,0 +1,5 @@
+ '欢迎使用ThinkPHP',
+ 'data type error' => '数据类型错误',
+ 'test' => '你好啊',
+ 'picture' => '图片',
+ 'audio' => '音频',
+ 'vedio' => '视频',
+ 'Hello, I am ' => '您好,我是',
+ ', May I help you? Please contact me!' => ',有什么可以帮到您的吗?记得联系我!',
+ 'not chat id ,please check param' => '没有关系数据,请检查传入参数。',
+ 'my reply' => '自定义话术',
+ 'login error' => '登陆失败',
+ 'invalid appid, hints: [ req_id: EIEEn_4ce-R.HZBA ]' => 'AppId填写错误, 请检查后充填',
+ 'invalid appsecret, view more at http://t.cn/RAEkdVq, hints: [ req_id: fIEEs.5ce-IRwLUa ]' => 'AppSecret填写错误, 请检查后充填',
+];
\ No newline at end of file
diff --git a/app/index/middleware.php b/app/index/middleware.php
new file mode 100755
index 0000000..2d8dd6b
--- /dev/null
+++ b/app/index/middleware.php
@@ -0,0 +1,5 @@
+
+
+
+
+
+
+
+
+ 登录 - 后台管理中心
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/install/controller/Index.php b/app/install/controller/Index.php
new file mode 100755
index 0000000..d2993a4
--- /dev/null
+++ b/app/install/controller/Index.php
@@ -0,0 +1,48 @@
+'123895549b6d11e9a5c4db13993d64a2',
+// 'admin_id' => '123895549b6d11e9a5c4db13993d64a1',
+// 'modular_id'=> '8888',
+// 'create_time' => null,
+// 'update_time' => null,
+// 'delete_time' => null,
+// 'deleted' => '0',
+// 'uniacid' => '8888'
+// ];
+// AdminUserService::bindAppAdmin($appAdminData) ;
+
+ file_put_contents($lockPath,time());
+
+ echo ' install ok ;' ;
+ }else{
+ echo ' install no ;' ;
+ }
+
+
+
+ }
+}
diff --git a/app/install/controller/install.lock b/app/install/controller/install.lock
new file mode 100755
index 0000000..45fe28f
--- /dev/null
+++ b/app/install/controller/install.lock
@@ -0,0 +1 @@
+1686622682
\ No newline at end of file
diff --git a/app/install/route/route.php b/app/install/route/route.php
new file mode 100755
index 0000000..0bb9e60
--- /dev/null
+++ b/app/install/route/route.php
@@ -0,0 +1,9 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-11 13:53
+ * @功能说明:登陆
+ */
+ public function login(){
+
+// $input = $this->_input;
+
+ initLogin();
+
+ $input = json_decode( $this->request->getInput(), true );
+
+ //dump($input);exit;
+
+ $dis = [
+
+ // 'uniacid' => $this->_uniacid,
+
+ 'username'=> $input['username']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ if(empty($data)){
+
+ return $this->error('该用户不存在', 400);
+
+ }
+
+ if($data['passwd']!=checkPass($input['passwd'])){
+
+
+ return $this->error('密码错误', 400);
+ }
+
+ $result['user'] = $data;
+
+ $result['token'] = uuid();
+
+ if (empty($result['token'])) {
+
+ return $this->error('系统错误', 400);
+ }
+ //添加缓存数据
+ setUserForToken($result['token'], $data, 99999999);
+
+ return $this->success($result);
+
+ }
+
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', 200 );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminAtv.php b/app/massage/controller/AdminAtv.php
new file mode 100755
index 0000000..dfd35d4
--- /dev/null
+++ b/app/massage/controller/AdminAtv.php
@@ -0,0 +1,441 @@
+model = new CarAtvList();
+
+ $this->content_model = new CarAtvContent();
+
+ $this->record_model = new CarAtvRecord();
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:内容列表
+ */
+ public function contentList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->content_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:内容列表
+ */
+ public function contentSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $data = $this->content_model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:详情
+ */
+ public function contentInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->content_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:添加活动详情
+ */
+ public function contentAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->content_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:编辑活动详情
+ */
+ public function contentUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ if(isset($input['status'])&&in_array($input['status'],[-1,0])){
+
+ $find = $this->model->atvContentIng($input['id']);
+
+ if(!empty($find)){
+
+ $this->errorMsg('该内容正在被使用');
+ }
+
+ }
+
+ $data = $this->content_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:内容列表
+ */
+ public function atvList(){
+
+ $input = $this->_param;
+
+ $this->model->initAtv();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['atv_status','=',$input['status']];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:详情
+ */
+ public function atvInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:添加活动详情
+ */
+ public function atvAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:编辑活动详情
+ */
+ public function atvUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $info = $this->model->dataInfo($dis);
+
+ if(isset($input['atv_num'])&&$input['atv_num']<$info['have_num']){
+
+ $this->errorMsg('报名人数不能小于已经报名人数,已报名'.$info['have_num']);
+ }
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ if(!empty($input['atv_s_time'])&&!empty($input['atv_e_time'])){
+ //同步活动报名时间
+ $update = [
+
+ 'start_time' => $input['atv_s_time'],
+
+ 'end_time' => $input['atv_e_time'],
+ ];
+
+ $this->record_model->dataUpdate(['atv_id'=>$input['id']],$update);
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 15:41
+ * @功能说明:用户报名列表
+ */
+ public function recordList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['b.atv_status','=',$input['status']];
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $dis[] = ['a.pay_time','between',"{$input['start_time']},{$input['end_time']}"];
+ }
+
+ if(!empty($input['id'])){
+
+ $dis[] = ['a.atv_id','=',$input['id']];
+ }
+
+ $data = $this->record_model->atvRecordList($dis,$input['limit'],[],$input['rank']);
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ $driver_model = new CarDriver();
+
+ $page = ($data['current_page']-1)*$data['per_page'];
+
+ foreach ($data['data'] as $k=>&$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ $v['phone'] = $user_model->where(['id'=>$v['user_id']])->value('phone');
+
+ $v['avatarUrl'] = $user_model->where(['id'=>$v['user_id']])->value('avatarUrl');
+
+ $v['user_name'] = $driver_model->where(['user_id'=>$v['user_id']])->value('user_name');
+
+// $v['game_info']['top'] = $v['pay_type']==7?$page+$k+1:0;
+
+ $v['game_info']['top'] = $this->record_model->getRecordTop($v);
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 15:46
+ * @功能说明:报名详情
+ */
+ public function recordInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data['record_info'] = $this->record_model->dataInfo($dis);
+
+ $data['record_info']['create_time'] = date('Y-m-d H:i:s',$data['record_info']['create_time']);
+
+ $atv_model = new CarAtvList();
+
+ $driver_model = new CarDriver();
+
+ $data['atv_info'] = $atv_model->dataInfo(['id'=>$data['record_info']['atv_id']]);
+
+ $user_model = new User();
+
+ $data['record_info']['nickName'] = $user_model->where(['id'=>$data['record_info']['user_id']])->value('nickName');
+
+ $data['record_info']['avatarUrl'] = $user_model->where(['id'=>$data['record_info']['user_id']])->value('avatarUrl');
+
+ $data['record_info']['phone'] = $user_model->where(['id'=>$data['record_info']['user_id']])->value('phone');
+
+ $data['record_info']['user_name'] = $driver_model->where(['user_id'=>$data['record_info']['user_id']])->value('user_name');
+
+ $data['record_info']['game_info']['top'] = $this->record_model->getRecordTop($data['record_info']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:编辑
+ */
+ public function recordUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->record_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-20 10:30
+ * @功能说明:比赛情况列表
+ */
+ public function gameList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.have_game','=',1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['b.nickName','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['major'])){
+
+ $dis[] = ['a.major','=',$input['major']];
+ }
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['a.start_time','between',"{$input['start_time']},{$input['end_time']}"];
+ }
+
+ $game_model = new CarGame();
+
+ $data = $game_model->topRecordList($dis,$input['limit']);
+
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminBalance.php b/app/massage/controller/AdminBalance.php
new file mode 100755
index 0000000..0b51d95
--- /dev/null
+++ b/app/massage/controller/AdminBalance.php
@@ -0,0 +1,203 @@
+model = new BalanceCard();
+
+ $this->order_model = new BalanceOrder();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:储值充值卡列表
+ */
+ public function cardList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加充值卡
+ */
+ public function cardAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑充值卡
+ */
+ public function cardUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:充值卡详情
+ */
+ public function cardInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:储值订单列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['order_code','like','%'.$input['order_code'].'%'];
+
+ }
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['pay_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->order_model->dataList($dis,$input['limit']);
+
+
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:充值订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->order_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+}
diff --git a/app/massage/controller/AdminCoupon.php b/app/massage/controller/AdminCoupon.php
new file mode 100755
index 0000000..a315041
--- /dev/null
+++ b/app/massage/controller/AdminCoupon.php
@@ -0,0 +1,239 @@
+model = new Coupon();
+
+ $this->atv_model = new CouponAtv();
+
+ $this->record_model = new CouponRecord();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:优惠券列表
+ */
+ public function couponList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['status','>',-1];
+
+ }
+
+ if(isset($input['send_type'])){
+
+ $dis[] = ['send_type','=',$input['send_type']];
+
+ }
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加优惠券
+ */
+ public function couponAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑优惠券
+ */
+ public function couponUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+
+ $input['uniacid'] = $this->_uniacid;
+ //删除优惠券 需要判断该优惠券是否正在参加活动
+ if(isset($input['status'])&&$input['status']==-1){
+
+ $atv_record_model = new CouponAtvRecord();
+
+ $have_atv = $atv_record_model->couponIsAtv($input['id']);
+
+ if($have_atv==true){
+
+ $this->errorMsg('该优惠券正在参加活动,只有等用户发起等活动结束后才能删除');
+ }
+
+ }
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:优惠券详情
+ */
+ public function couponInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 19:19
+ * @功能说明:活动详情
+ */
+ public function couponAtvInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->atv_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 19:22
+ * @功能说明:活动编辑
+ */
+ public function couponAtvUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->atv_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 16:26
+ * @功能说明:后台派发卡劵
+ */
+ public function couponRecordAdd(){
+
+ $input = $this->_input;
+
+ foreach ($input['user'] as $value){
+
+ $res = $this->record_model->recordAdd($input['coupon_id'],$value['id'],$value['num']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminDriver.php b/app/massage/controller/AdminDriver.php
new file mode 100755
index 0000000..192569a
--- /dev/null
+++ b/app/massage/controller/AdminDriver.php
@@ -0,0 +1,647 @@
+model = new CarDriver();
+
+ $this->car_type_model = new CarType();
+//
+ $this->trophy_model = new CarTrophy();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function driverList(){
+
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['user_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['mobile','like','%'.$input['name'].'%'];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit'],$where);
+
+ $list = [
+
+ '0'=>'all',
+
+ 1=>'ing',
+
+ 2=>'pass',
+
+ 4=>'nopass'
+ ];
+
+ foreach ($list as $k=> $value){
+
+ $dis_s = [];
+
+ $dis_s[] =['uniacid','=',$this->_uniacid];
+
+ if(!empty($k)){
+
+ $dis_s[] = ['status','=',$k];
+
+ }else{
+
+ $dis_s[] = ['status','>',-1];
+
+ }
+
+ $data[$value] = $this->model->where($dis_s)->count();
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:车手详情
+ */
+ public function driverInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $user_model = new User();
+
+ $data['nickName'] = $user_model->where(['id'=>$data['user_id']])->value('nickName');
+
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-03 00:15
+ * @功能说明:审核(2通过,3取消,4拒绝)
+ */
+ public function driverUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ if(!empty($input['status'])&&in_array($input['status'],[2,4])){
+
+ $input['sh_time'] = time();
+ }
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:53
+ * @功能说明:奖杯列表
+ */
+ public function trophyList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->trophy_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:53
+ * @功能说明:奖杯列表
+ */
+ public function trophySelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['user_id'])){
+
+ $user_t_model = new CarUserTrophy();
+
+ $id = $user_t_model->where(['user_id'=>$input['user_id']])->column('trophy_id');
+
+ $dis[] = ['id','in',$id];
+ }
+
+ $data = $this->trophy_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加奖杯
+ */
+ public function trophyAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->trophy_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑奖杯
+ */
+ public function trophyUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->trophy_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:奖杯详情
+ */
+ public function trophyInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->trophy_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:53
+ * @功能说明:车型列表
+ */
+ public function cartypeSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $data = $this->car_type_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:53
+ * @功能说明:车型列表
+ */
+ public function cartypeList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->car_type_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加车型
+ */
+ public function cartypeAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->car_type_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑车型
+ */
+ public function cartypeUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+ //删除
+ if(isset($input['status'])&&in_array($input['status'],[-1,0])){
+
+ $goods_model = new Goods();
+
+ $goods = $goods_model->carTypeHave($input['id']);
+
+ if(!empty($goods)){
+
+ $this->errorMsg('产品:'.$goods['title'].' 正在使用该车型,无法删除或下架');
+ }
+
+ $atv_model = new CarAtvList();
+
+ $atv = $atv_model->where(['car_type_id'=>$input['id']])->where('status','>',-1)->find();
+
+ if(!empty($atv)){
+
+ $atv = $atv->toArray();
+
+ $this->errorMsg('活动:'.$atv['title'].' 正在使用该车型,无法删除或下架');
+ }
+
+ }
+
+ $res = $this->car_type_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:车型详情
+ */
+ public function cartypeInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->car_type_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 18:46
+ * @功能说明:提现列表
+ */
+ public function walletList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.type','=',$input['type']];
+
+ if(!empty($input['code'])){
+
+ $dis[] = ['a.code','like','%'.$input['code'].'%'];
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+ }
+
+ $data = $this->wallet_model->adminList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 18:57
+ * @功能说明:提现详情
+ */
+ public function walletInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->wallet_model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 18:58
+ * @功能说明:通过提现申请
+ */
+ public function walletPass(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->wallet_model->dataInfo($dis);
+
+ if($data['status']!=1){
+
+ $this->errorMsg('申请已审核');
+ }
+
+ $update = [
+
+ 'sh_time' => time(),
+
+ //'text' => !empty($input['text'])?$input['text']:'',
+
+ 'status' => 2,
+
+ 'online' => $input['online'],
+
+ 'true_price'=> $data['apply_price']
+ ];
+
+ Db::startTrans();
+
+ $res = $this->wallet_model->dataUpdate(['id'=>$input['id'],'status'=>1],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('打款失败');
+
+ }
+ //线上转账
+ if($input['online']==1){
+
+ $user_model = new \app\massage\model\User();
+
+ $openid = $user_model->where(['id'=>$data['user_id']])->value('openid');
+
+ if(empty($openid)){
+
+ return $this->error('用户信息错误,未获取到openid');
+ }
+ //微信相关模型
+ $wx_pay = new WxPay($this->_uniacid);
+ //微信提现
+ $res = $wx_pay->crteateMchPay($this->payConfig(),$openid,$update['true_price']);
+
+ if($res['result_code']=='SUCCESS'&&$res['return_code']=='SUCCESS'){
+
+ if(!empty($res['payment_no'])){
+
+ $this->wallet_model->dataUpdate(['id'=>$input['id']],['payment_no'=>$res['payment_no']]);
+ }
+
+ }else{
+
+ Db::rollback();
+
+ return $this->error(!empty($res['err_code_des'])?$res['err_code_des']:'你还未该权限');
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:03
+ * @功能说明:决绝提现
+ */
+ public function walletNoPass(){
+
+ $input = $this->_input;
+
+ $info = $this->wallet_model->dataInfo(['id'=>$input['id']]);
+
+ if($info['status']==2){
+
+ $this->errorMsg('已同意打款');
+ }
+
+ if($info['status']==3){
+
+ $this->errorMsg('已拒绝打款');
+ }
+
+ Db::startTrans();
+
+
+ $update = [
+
+ 'sh_time' => time(),
+
+ //'text' => !empty($input['text'])?$input['text']:'',
+
+ 'status' => 3,
+
+ ];
+
+ $res = $this->wallet_model->dataUpdate(['id'=>$input['id'],'status'=>1],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('打款失败');
+
+ }
+
+ $cap_info = $this->model->dataInfo(['id'=>$info['coach_id']]);
+
+ if($info['type']==1){
+
+ $res = $this->model->dataUpdate(['id'=>$info['coach_id']],['service_price'=>$cap_info['service_price']+$info['total_price']]);
+ }else{
+
+ $res = $this->model->dataUpdate(['id'=>$info['coach_id']],['car_price'=>$cap_info['car_price']+$info['total_price']]);
+
+ }
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('审核失败');
+
+ }
+
+ Db::commit();
+
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminExcel.php b/app/massage/controller/AdminExcel.php
new file mode 100755
index 0000000..ce2863d
--- /dev/null
+++ b/app/massage/controller/AdminExcel.php
@@ -0,0 +1,287 @@
+model = new Model();
+
+ $this->order_goods_model = new OrderGoods();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['b.goods_name','like','%'.$input['goods_name'].'%'];
+ }
+ //手机号搜索
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['a.mobile','like','%'.$input['mobile'].'%'];
+ }
+
+ if(!empty($input['pay_type'])){
+ //订单状态搜索
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+ //除开删除的
+ $dis[] = ['a.is_show','=',1];
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+ }
+
+ $data = $this->model->adminDataSelect($dis,$input['limit']);
+
+ $name = '订单列表';
+
+ $header=[
+ '订单ID',
+ '产品',
+ '产品价格',
+ '数量',
+ '下单人',
+ '手机号',
+// '服务项目费用',
+ '实收金额',
+ '系统订单号',
+ '付款订单号',
+ '下单时间',
+ '支付方式',
+ '状态',
+ ];
+
+ $new_data = [];
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = $v['goods_name'];
+
+ $info[] = $v['goods_price'];
+
+ $info[] = $v['num'];
+
+ $info[] = $v['nickName'];
+
+ $info[] = $v['mobile'];
+
+// $info[] = $v['init_service_price'];
+
+ $info[] = $v['pay_price'];
+
+ $info[] = $v['order_code'];
+
+ $info[] = $v['transaction_id'];
+
+ $info[] = date('Y-m-d H:i:s',$v['create_time']);
+
+ $info[] = !empty($v['balance'])?'余额支付':'微信支付';
+
+ $info[] = $this->orderStatusText($v['pay_type']);
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data,'',1);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 16:32
+ * @功能说明:
+ */
+ public function orderStatusText($status){
+
+ switch ($status){
+
+ case 1:
+ return '待支付';
+
+ break;
+ case 2:
+ return '待签到';
+
+ break;
+ case 3:
+ return '待核销';
+
+ break;
+ case 7:
+ return '已完成';
+
+ break;
+ case -1:
+ return '已取消';
+
+ break;
+
+ }
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 13:37
+ * @功能说明:财务数据统计导出
+ */
+ public function dateCount(){
+
+ $input = $this->_param;
+
+ $cap_id = $input['cap_id'];
+
+ $date_model = new Date();
+
+ $wallet_model = new Wallet();
+
+ $cap_model = new Cap();
+
+ $date_model->dataInit($this->_uniacid);
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['date_str','between',"$start_time,$end_time"];
+ }
+
+ $date_list = $date_model->dataList($dis,100000);
+ //店铺名字
+ $store_name = $cap_model->where(['id'=>$cap_id])->value('store_name');
+ //开始时间结束时间
+ if(!empty($start_time)){
+
+ $date_list['start_time'] = $start_time;
+
+ $date_list['end_time'] = $end_time;
+
+ }else{
+
+ $date_list['start_time'] = $date_model->where(['uniacid'=>$this->_uniacid])->min('date_str');
+
+ $date_list['end_time'] = $date_model->where(['uniacid'=>$this->_uniacid])->max('date_str');
+
+ }
+
+ if(!empty($date_list['data'])){
+
+ foreach ($date_list['data'] as $k=>$v){
+ //订单金额
+ $date_list['data'][$k]['order_price'] = $this->model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+ //退款金额
+ $date_list['data'][$k]['refund_price'] = $this->refund_order_model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+ //提现金额
+ $date_list['data'][$k]['wallet_price'] = $wallet_model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+
+ }
+
+ }
+
+ $name = $store_name.'财务报表';
+
+ $header=[
+ '收支时间',
+ '订单收入',
+ '订单退款',
+ '提现(元)',
+ ];
+
+ $new_data = [];
+
+ foreach ($date_list['data'] as $v){
+
+ $info = array();
+
+ $info[] = $v['date'];
+
+ $info[] = $v['order_price'];
+
+ $info[] = $v['refund_price'];
+
+ $info[] = $v['wallet_price'];
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($date_list);
+
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminOrder.php b/app/massage/controller/AdminOrder.php
new file mode 100755
index 0000000..a24687b
--- /dev/null
+++ b/app/massage/controller/AdminOrder.php
@@ -0,0 +1,629 @@
+model = new Order();
+
+ $this->order_goods_model = new OrderGoods();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function orderList(){
+
+
+ $input = $this->_param;
+ //超时自动取消订单
+// $this->model->autoCancelOrder($this->_uniacid);
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['b.goods_name','like','%'.$input['goods_name'].'%'];
+ }
+
+ //手机号搜索
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['a.mobile','like','%'.$input['mobile'].'%'];
+ }
+
+ if(!empty($input['pay_type'])){
+ //订单状态搜索
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+// //除开删除的
+ $dis[] = ['a.is_show','=',1];
+
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+ }
+
+ $data = $this->model->adminDataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $user_model = new User();
+
+ $data['nickName'] = $user_model->where(['id'=>$data['user_id']])->value('nickName');
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->refund_order_model->dataInfo($dis);
+
+ $data['pay_order_code'] = $this->model->where(['id'=>$data['order_id']])->value('order_code');
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ $user_model = new User();
+
+ $data['nickName'] = $user_model->where(['id'=>$data['user_id']])->value('nickName');
+
+ $data['mobile'] = $this->model->where(['id'=>$data['order_id']])->value('mobile');
+
+ return $this->success($data);
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:44
+ * @功能说明:退款订单列表
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+ }
+ //订单状态搜索
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['order_code'])){
+
+ $where[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ $where[] = ['d.order_code','like','%'.$input['order_code'].'%'];
+ }
+
+ $data = $this->refund_order_model->adminDataList($dis,$input['limit'],$where);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:21
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund(){
+
+ $input = $this->_input;
+
+ $res = $this->refund_order_model->noPassRefund($input['id']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**\
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:28
+ * @功能说明:同意退款
+ */
+ public function passRefund(){
+
+ $input = $this->_input;
+
+ $res = $this->refund_order_model->passOrder($input['id'],$input['price'],$this->payConfig(),0,$input['text']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:16
+ * @功能说明:评价列表
+ */
+ public function commentList(){
+
+ $input = $this->_param;
+
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','>',-1];
+
+ if(!empty($input['star'])){
+
+ $dis[] = ['a.star','=',$input['star']];
+ }
+
+ if(!empty($input['coach_name'])){
+
+ $dis[] = ['d.coach_name','like','%'.$input['coach_name'].'%'];
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ $data = $this->comment_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:31
+ * @功能说明:编辑评价
+ */
+ public function commentUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->comment_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:53
+ * @功能说明:评价标签列表
+ */
+ public function commentLableList(){
+
+ $input = $this->_param;
+
+ $lable_model = new Lable();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $lable_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:56
+ * @功能说明:添加评价标签
+ */
+ public function commentLableAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $lable_model = new Lable();
+
+ $res = $lable_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:57
+ * @功能说明:编辑评价标签
+ */
+ public function commentLableUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $lable_model = new Lable();
+
+ $res = $lable_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 18:59
+ * @功能说明:评价标签详情
+ */
+ public function commentLableInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $lable_model = new Lable();
+
+ $res = $lable_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 10:27
+ * @功能说明:提示列表
+ */
+ public function noticeList(){
+
+ $input = $this->_param;
+
+ $notice_model = new NoticeList();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+ }
+
+ if(isset($input['have_look'])){
+
+ $dis[] = ['have_look','=',$input['have_look']];
+
+ }else{
+
+ $dis[] = ['have_look','>',-1];
+
+ }
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+ }
+
+ $data = $notice_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 10:38
+ * @功能说明:未查看的数量
+ */
+ public function noLookCount(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['have_look','=',0];
+
+ $notice_model = new NoticeList();
+
+ $data = $notice_model->where($dis)->count();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 10:41
+ * @功能说明:全部已读
+ */
+ public function allLook(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['have_look','=',0];
+
+ $notice_model = new NoticeList();
+
+ $data = $notice_model->dataUpdate($dis,['have_look'=>1]);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 10:28
+ * @功能说明:
+ */
+ public function noticeUpdate(){
+
+ $input = $this->_input;
+
+ $notice_model = new NoticeList();
+
+ $data = $notice_model->dataUpdate(['id'=>$input['id']],$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-11 16:26
+ * @功能说明:订单打印
+ */
+ public function orderPrinter(){
+
+ $input = $this->_input;
+
+ $printer_model = new Printer();
+
+ $res = $printer_model->printer($input['id'],0,$input['type']);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 15:25
+ * @功能说明:后台数据统计
+ */
+ public function dataStatistics(){
+
+ $input = $this->_input;
+
+ $car_order_model = new Order();
+
+ $record_model = new CarAtvRecord();
+
+ $shop_order_model = new \app\shop\model\Order();
+
+ $restaurant_order_model = new \app\restaurant\model\Order();
+
+ $dis[] =['pay_type','>',1];
+
+ $dis[] =['uniacid','=',$this->_uniacid];
+
+ $car_order_price = $car_order_model->where($dis)->sum('pay_price');
+
+ $record_price = $record_model->where($dis)->sum('pay_price');
+
+ $data['car_price'] = round($car_order_price+$record_price,2);
+
+ $shop_price = $shop_order_model->where($dis)->sum('true_price');
+
+ $restaurant_price = $restaurant_order_model->where($dis)->sum('true_price');
+
+ $data['shop_price'] = round($shop_price,2);
+
+ $data['restaurant_price'] = round($restaurant_price,2);
+
+ $data['all_price'] = round($car_order_price+$record_price+$shop_price+$restaurant_price,2);
+
+ $arr['price'] = $data;
+
+ while ($input['date_start_time']<=$input['date_end_time']){
+
+ $date[] = date('Y-m-d',$input['date_start_time']);
+
+ $input['date_start_time'] +=86400;
+
+ }
+
+ if(!empty($date)){
+
+ foreach ($date as $k=> $value){
+
+ $dis = [];
+
+ $dis[] =['pay_type','>',1];
+
+ $dis[] =['uniacid','=',$this->_uniacid];
+
+ $car_order_price = $car_order_model->where($dis)->whereDay('pay_time',$value)->sum('pay_price');
+
+ $record_price = $record_model->where($dis)->whereDay('pay_time',$value)->sum('pay_price');
+
+ $arr['date'][$k]['car_price']= round($car_order_price+$record_price,2);
+
+ $shop_price = $shop_order_model->where($dis)->whereDay('pay_time',$value)->sum('true_price');
+
+ $restaurant_price = $restaurant_order_model->where($dis)->whereDay('pay_time',$value)->sum('true_price');
+
+ $arr['date'][$k]['shop_price'] = round($shop_price,2);
+
+ $arr['date'][$k]['restaurant_price'] = round($restaurant_price,2);
+
+ $arr['date'][$k]['all_price'] = round($car_order_price+$record_price+$shop_price+$restaurant_price,2);
+
+ $arr['date'][$k]['date'] = $value;
+
+ }
+
+ }
+
+ $arr['date'] = array_values($arr['date']);
+
+ $dis[] =['pay_type','>',1];
+
+ $dis[] =['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['start_time'])){
+
+ $dis[] =['pay_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ if($input['type']==1){
+
+ $arr['order_list'] = $car_order_model->where($dis)->field('id,order_code,pay_price,pay_time')->order('id desc')->paginate($input['limit'])->toArray();
+
+ }elseif($input['type']==2){
+
+ $arr['order_list'] = $shop_order_model->where($dis)->field('id,order_code,true_price as pay_price,pay_time')->order('id desc')->paginate($input['limit'])->toArray();
+
+ }else{
+
+ $arr['order_list'] = $restaurant_order_model->where($dis)->field('id,order_code,true_price as pay_price,pay_time')->order('id desc')->paginate($input['limit'])->toArray();
+
+ }
+
+ return $this->success($arr);
+
+ }
+
+
+}
diff --git a/app/massage/controller/AdminPrinter.php b/app/massage/controller/AdminPrinter.php
new file mode 100755
index 0000000..490b8d7
--- /dev/null
+++ b/app/massage/controller/AdminPrinter.php
@@ -0,0 +1,120 @@
+model = new Model();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:详情
+ */
+ public function printerList(){
+
+ $input = $this->_param;
+
+// $dis = [
+//
+// 'uniacid' => $this->_uniacid
+// ];
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:28
+ * @功能说明:详情
+ */
+ public function printerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:编辑
+ */
+ public function printerAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 13:29
+ * @功能说明:编辑
+ */
+ public function printerUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminService.php b/app/massage/controller/AdminService.php
new file mode 100755
index 0000000..40570a0
--- /dev/null
+++ b/app/massage/controller/AdminService.php
@@ -0,0 +1,148 @@
+model = new Goods();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:商品列表
+ */
+ public function serviceList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['status','>',-1];
+
+ }
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:审核详情
+ */
+ public function serviceInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-03 00:27
+ * @功能说明:添加
+ */
+ public function serviceAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-03 00:27
+ * @功能说明:添加
+ */
+ public function serviceUpdate(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/AdminSetting.php b/app/massage/controller/AdminSetting.php
new file mode 100755
index 0000000..fae5059
--- /dev/null
+++ b/app/massage/controller/AdminSetting.php
@@ -0,0 +1,554 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function configInfo(){
+
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:14
+ * @功能说明:编辑配置
+ */
+ public function configUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:15
+ * @功能说明:banner列表
+ */
+ public function bannerList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $banner_model = new Banner();
+
+ $data = $banner_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:18
+ * @功能说明:添加banner
+ */
+ public function bannerAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:20
+ * @功能说明:编辑banner
+ */
+ public function bannerUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:27
+ * @功能说明:banner详情
+ */
+ public function bannerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataInfo($dis);
+
+ return $this->success($res);
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:53
+ * @功能说明:支付配置详情
+ */
+ public function payConfigInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $pay_model = new PayConfig();
+
+ $data = $pay_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:55
+ * @功能说明:编辑支付配置
+ */
+ public function payConfigUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+
+ if(isset($input['cert_path'])&&isset($input['key_path'])){
+
+ if(!strstr($input['cert_path'],FILE_UPLOAD_PATH)){
+
+ $input['cert_path'] = FILE_UPLOAD_PATH.$input['cert_path'];
+
+ }
+ if(!strstr($input['key_path'],FILE_UPLOAD_PATH)){
+
+ $input['key_path'] = FILE_UPLOAD_PATH.$input['key_path'];
+ }
+ }
+
+ $pay_model = new PayConfig();
+
+ $data = $pay_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-31 15:16
+ * @功能说明:修改密码
+ */
+ public function updatePass(){
+
+ $input = $this->_input;
+
+ $admin = new \app\shop\model\Admin();
+
+ $update = [
+
+ 'passwd' => checkPass($input['pass']),
+ ];
+
+ $res = $admin->dataUpdate(['uniacid'=>$this->_uniacid],$update);
+
+
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function msgConfigInfo(){
+
+ $msg_model = new MsgConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $msg_model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:14
+ * @功能说明:编辑配置
+ */
+ public function msgConfigUpdate(){
+
+ $input = $this->_input;
+
+ $msg_model = new MsgConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $msg_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:09
+ * @功能说明:评价标签列表
+ */
+ public function lableList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $lable_model = new Lable();
+
+ $data = $lable_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:09
+ * @功能说明:评价标签详情
+ */
+ public function lableInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $lable_model = new Lable();
+
+ $data = $lable_model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:09
+ * @功能说明:添加评价标签
+ */
+ public function lableAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $lable_model = new Lable();
+
+ $data = $lable_model->dataAdd($input);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:09
+ * @功能说明:编辑评价标签
+ */
+ public function lableUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+
+ $lable_model = new Lable();
+
+ $data = $lable_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 18:46
+ * @功能说明:车费配置详情
+ */
+ public function carConfigInfo(){
+
+ $car_model = new CarPrice();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $car_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 18:46
+ * @功能说明:车费配置详情
+ */
+ public function carConfigUpdate(){
+
+ $input = $this->_input;
+
+ $car_model = new CarPrice();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $car_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:27
+ * @功能说明:新闻列表
+ */
+ public function articleList(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['type','=',$input['type']];
+ }
+
+ $data = $article_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:37
+ * @功能说明:添加文章
+ *
+ */
+ public function articleAdd(){
+
+ $input = $this->_input;
+
+ $article_model = new Article();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $article_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:编辑文章
+ */
+ public function articleUpdate(){
+
+ $input = $this->_input;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $article_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:文章详情
+ */
+ public function articleInfo(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $article_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:50
+ * @功能说明:文章下拉框
+ */
+ public function articleSelect(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $res = $article_model->where($dis)->field('id,title')->select()->toArray();
+
+ return $this->success($res);
+
+ }
+
+
+
+}
diff --git a/app/massage/controller/AdminUser.php b/app/massage/controller/AdminUser.php
new file mode 100755
index 0000000..22ff721
--- /dev/null
+++ b/app/massage/controller/AdminUser.php
@@ -0,0 +1,261 @@
+model = new Model();
+
+ $this->order_goods_model = new OrderGoods();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 10:24
+ * @功能说明:用户列表
+ */
+ public function userList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //是否授权
+ if(!empty($input['type'])){
+
+ if($input['type']==1){
+
+ $dis[] = ['nickName','=',''];
+
+ }else{
+
+ $dis[] = ['nickName','<>',''];
+
+ }
+
+ }
+
+ if(isset($input['role'])){
+
+ $dis[] = ['role','=',$input['role']];
+ }
+
+ $where = [];
+
+ if(!empty($input['nickName'])){
+
+ $where[] = ['nickName','like','%'.$input['nickName'].'%'];
+
+ $where[] = ['phone','like','%'.$input['nickName'].'%'];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['create_time','between',"$start_time,$end_time"];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit'],$where);
+
+
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 14:39
+ * @功能说明:编辑员工
+ */
+ public function userUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-28 23:03
+ * @功能说明:佣金记录
+ */
+ public function commList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+ }
+
+ if(!empty($input['top_name'])){
+
+ $dis[] = ['c.nickName','like','%'.$input['top_name'].'%'];
+
+ }
+
+ $comm_model = new Commission();
+
+ $data = $comm_model->recordList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 15:02
+ * @功能说明:用户所有获得的奖杯
+ */
+ public function userTrophy(){
+
+ $input = $this->_param;
+
+ $user_trophy_model = new CarUserTrophy();
+
+ $dis = [
+
+ 'a.user_id' => $input['user_id'],
+
+ 'a.status' => 1,
+
+ 'b.status' => 1
+
+ ];
+
+ $data = $user_trophy_model->alias('a')
+ ->join('shequshop_car_trophy b','a.trophy_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title,b.cover')
+ ->select()
+ ->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 15:04
+ * @功能说明:用户添加奖杯
+ */
+ public function userTrophyAdd(){
+
+ $input = $this->_input;
+
+ $user_trophy_model = new CarUserTrophy();
+
+ foreach ($input['user_id'] as $value){
+
+ foreach ($input['trophy_id'] as $v){
+
+ $dis = [
+
+ 'user_id' => $value,
+
+ 'trophy_id'=> $v,
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $find = $user_trophy_model->where($dis)->where('status','>',-1)->find();
+ //增加
+ if($input['add']==1){
+
+ if(empty($find)){
+
+ $user_trophy_model->dataAdd($dis);
+ }
+
+ }else{
+ //减少
+ if(!empty($find)){
+
+ $user_trophy_model->dataUpdate($dis,['status'=>-1]);
+ }
+
+ }
+
+ }
+
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-20 16:00
+ * @功能说明:修改用户积分
+ */
+ public function userIntegralUpdate(){
+
+ $input = $this->_input;
+
+ $log_model = new IntegralLog();
+
+ $type = $input['integral']>0?12:13;
+
+ $res = $log_model->integralUserAdd($input['user_id'],$input['integral'],$this->_uniacid,2,$type);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/Index.php b/app/massage/controller/Index.php
new file mode 100755
index 0000000..e569890
--- /dev/null
+++ b/app/massage/controller/Index.php
@@ -0,0 +1,899 @@
+model = new Goods();
+
+ $this->banner_model = new Banner();
+
+ $this->car_model = new Car();
+
+ $this->game_model = new CarGame();
+
+ $this->record_model = new CarAtvRecord();
+
+ $this->driver_model = new CarDriver();
+
+ $this->atv_model = new CarAtvList();
+
+ $this->atv_model->initAtv();
+
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:20
+ * @功能说明:首页
+ */
+ public function index(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $data['banner'] = $this->banner_model->where($dis)->field('id,img,link')->order('top desc,id desc')->select()->toArray();
+ //所有专业车手
+// $user_id = $this->driver_model->where(['status'=>2])->column('user_id');
+
+ $where[] = ['a.have_game','=',1];
+
+ $where[] = ['a.major','=',1];
+
+ $where[] = ['a.type','=',2];
+
+ $speed_record = $this->game_model->topRecordList($where,3);
+ //普通组车手成绩
+ $data['speed_record'] = $speed_record['data'];
+
+ $atv_dis = [
+
+ 'uniacid' => $this->_uniacid,
+ //查询已经结束的
+ 'atv_status' => 3,
+
+ 'status' => 1
+ ];
+ //查询最近的一个结束的活动
+ $atv = $this->atv_model->where($atv_dis)->order('atv_e_time desc')->find();
+
+ if(!empty($atv)){
+
+ $atv = $atv->toArray();
+
+ $i_dis = [
+
+ 'a.atv_id' => $atv['id'],
+
+// 'a.status' => 2
+ ];
+ //积分排行榜
+ $data['integral']['record'] = $this->record_model->integralRecordList($i_dis,4);
+
+ $data['integral']['record'] = $data['integral']['record']['data'];
+ //时间
+ $data['integral']['time'] = date('Y.m.d',$atv['atv_s_time']).'-'.date('Y.m.d',$atv['atv_e_time']);
+
+ $data['integral']['atv_id'] = $atv['id'];
+ }
+
+ $atv_diss[] = ['uniacid','=',$this->_uniacid];
+
+ $atv_diss[] = ['status','=',1];
+
+ $atv_diss[] = ['app_s_time','<',time()];
+
+ $atv_diss[] = ['app_e_time','>',time()];
+
+ $data['atv'] = $this->atv_model->where($atv_diss)->order('app_s_time')->find();
+
+ if(!empty($data['atv'])){
+
+ $data['atv'] = $data['atv']->toArray();
+
+ $data['atv']['time'] = date('Y.m.d',$data['atv']['atv_s_time']).'-'.date('Y.m.d',$data['atv']['atv_e_time']);
+
+ }
+
+ $article_model = new Article();
+
+ $arr = [
+ //热点
+ '1' => 'hot_article',
+ //赛事
+ '2' => 'game_article',
+
+ ];
+ //获取热点文章和赛事文章
+ foreach ($arr as $k=>$value){
+
+ $dis = [
+
+ 'type' => $k,
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $data[$value] = $article_model->where($dis)->order('top desc,id desc')->limit(3)->select()->toArray();
+
+ }
+
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 14:31
+ * @功能说明:比赛成绩排行版
+ */
+ public function resultTopList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.have_game','=',1];
+ //1普通组 2专业组
+ $dis[] = ['a.major','=',$input['type']];
+ //预约的不算
+ $dis[] = ['a.type','=',2];
+
+ if(!empty($input['time'])){
+
+ $data = $this->game_model->timeTopRecordList($dis,10,$input['time']);
+
+ }else{
+
+ $data = $this->game_model->topRecordList($dis,10);
+
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 14:52
+ * @功能说明:所有已经完成的活动
+ */
+ public function successAtvList(){
+
+ $input = $this->_param;
+
+ $atv_dis[] = ['uniacid','=',$this->_uniacid];
+
+ $atv_dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $atv_dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['atv_status'])){
+
+ $atv_dis[] = ['atv_status','=',$input['atv_status']];
+ }
+
+ $atv = $this->atv_model->where($atv_dis)->order('atv_s_time ,id desc')->paginate(10)->toArray();
+
+ if(!empty($atv['data'])){
+
+ foreach ($atv['data'] as &$v){
+
+ $v['time'] = date('Y.m.d',$v['atv_s_time']).'-'.date('Y.m.d',$v['atv_e_time']);
+
+ $v['app_status'] = 1;
+ //已经开始
+ if($v['app_s_time']0?$v['surplus_num']:0;
+
+ }
+
+ }
+
+ return $this->success($atv);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-28 17:43
+ * @功能说明:赛事积分排行榜
+ */
+ public function integralRecordList(){
+
+ $input = $this->_param;
+
+ $where[] = ['a.uniacid','=',$this->_uniacid];
+
+ $where[] = ['a.atv_id','=',$input['atv_id']];
+ //报名记录情况
+ $data = $this->record_model->integralRecordList($where,10);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 14:55
+ * @功能说明:活动详情
+ */
+
+ public function atvInfo(){
+
+ $this->record_model->autoCancelRecord();
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->atv_model->dataInfo($dis);
+ //活动时间
+ $data['atv_time'] = date('Y.m.d H:i',$data['atv_s_time']).' - '.date('Y.m.d H:i',$data['atv_e_time']);
+ //报名时间
+ $data['app_time'] = date('Y.m.d H:i',$data['app_s_time']).' - '.date('Y.m.d H:i',$data['app_e_time']);
+
+ $where[] = ['a.uniacid','=',$this->_uniacid];
+
+ $where[] = ['a.atv_id','=',$input['id']];
+
+ $where[] = ['a.pay_type','>',1];
+ //报名记录情况
+ $data['record_list'] = $this->record_model->integralRecordList($where,10);
+
+ $re_where[] = ['atv_id','=',$input['id']];
+
+ $re_where[] = ['user_id','=',$this->getUserId()];
+
+ $re_where[] = ['pay_type','>',0];
+
+ $have_app = $this->record_model->dataInfo($re_where);
+ //自己是否已经报名
+ $data['have_app'] = !empty($have_app)?1:0;
+ //
+ $content_model = new CarAtvContent();
+ //报名内容
+ $data['content_text'] = $content_model->where('id','in',$data['content'])->where(['status'=>1])->select()->toArray();
+
+ $data['app_status'] = 1;
+ //已经开始
+ if($data['app_s_time']success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 15:01
+ * @功能说明:报名活动
+ */
+ public function appAtv(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['atv_id'],
+
+ 'status' => 1
+ ];
+
+ $atv = $this->atv_model->dataInfo($dis);
+
+ if(empty($atv)){
+
+ $this->errorMsg('活动已下架');
+ }
+ //已经报名人数
+ $where[] = ['atv_id','=',$input['atv_id']];
+ //去掉已经删除的
+ $where[] = ['pay_type','>',0];
+
+ $where[] = ['user_id','=',$this->getUserId()];
+ //查询自己有没有报名过
+ $user_num = $this->record_model->where($where)->count();
+
+ if(!empty($user_num)){
+
+ $this->errorMsg('你已报名或有报名订单未支付');
+
+ }
+ //防止并发做了一个简单的锁
+ if($atv['have_num']>=$atv['atv_num']){
+
+ $this->errorMsg('报名人数已满');
+
+ }
+
+ $car_type_model = new CarType();
+
+ $car_type = $car_type_model->dataInfo(['id'=>$atv['car_type_id']]);
+
+ if(empty($car_type)){
+
+ $this->errorMsg('车型不存在');
+ }
+ //查询自己是否是专业车手
+ $is_major = $this->driver_model->dataInfo(['user_id'=>$this->getUserId(),'status'=>2]);
+
+ $is_major = !empty($is_major)?1:0;
+ //判断车手身份
+ if($is_major==1&&$car_type['major']==0){
+
+ $this->errorMsg('只有普通车手才能报名');
+ }
+ //判断车手身份
+ if($is_major==0&&$car_type['norm']==0){
+
+ $this->errorMsg('只有专业车手才能报名');
+ }
+
+// $config = new Config();
+//
+// $member_config_model = new \app\member\model\Config();
+
+ // $member_config = $member_config_model->configInfo(['uniacid'=>$this->_uniacid]);
+
+ Db::startTrans();
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'atv_id' => $input['atv_id'],
+
+ 'start_time' => $atv['atv_s_time'],
+
+ 'end_time' => $atv['atv_e_time'],
+
+ 'content' => $input['content'],
+
+ 'order_code' => orderCode(),
+
+ 'pay_price' => $atv['pay_price'],
+
+ 'balance' => !empty($input['is_balance'])?$atv['pay_price']:0,
+
+ 'over_time' => time()+3600,
+
+ 'car_type_id'=> $atv['car_type_id'],
+
+ 'number' => $atv['number'],
+ //付费获得的积分
+ // 'get_integral'=> empty($input['is_balance'])?floor($atv['pay_price']*$member_config['integral_cash']):0,
+
+ ];
+
+ $res = $this->record_model->dataAdd($insert);
+
+ if(empty($res)){
+
+ Db::rollback();
+
+ $this->errorMsg('报名失败,请重试');
+
+ }
+
+ $res = $this->atv_model->dataUpdate(['id'=>$insert['atv_id'],'have_num'=>$atv['have_num']],['have_num'=>$atv['have_num']+1]);
+
+ if(empty($res)){
+
+ Db::rollback();
+
+ $this->errorMsg('报名失败,请重试');
+
+ }
+
+ Db::commit();
+ //0元支付
+ if($insert['pay_price']<=0){
+
+ $this->record_model->dataResult($insert['order_code'],$insert['order_code']);
+
+ return $this->success([]);
+
+ }
+
+ if(!empty($insert['balance'])){
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$insert['user_id']]);
+
+ if($user['balance']<$insert['balance']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->record_model->dataResult($insert['order_code'],$insert['order_code']);
+
+ return $this->success([]);
+
+
+ }else{
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"carAtvApp",['type' => 'carAtvApp' , 'out_trade_no' => $insert['order_code']],$insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+// $id = $this->record_model->getLastInsID();
+
+ $arr['record'] = $this->record_model->dataInfo(['order_code'=>$insert['order_code']]);
+
+ return $this->success($arr);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 10:25
+ * @功能说明:报名记录重新支付
+ */
+ public function atvRecordRePay(){
+
+ $input = $this->_input;
+
+ $record = $this->record_model->dataInfo(['id'=>$input['record_id']]);
+
+ if($record['pay_type']!=1){
+
+ $this->errorMsg('订单已经失效');
+ }
+
+ if(!empty($record['balance'])){
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$record['user_id']]);
+
+ if($user['balance']<$record['balance']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->record_model->dataResult($record['order_code'],$record['order_code']);
+
+ return $this->success([]);
+
+
+ }else{
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"carAtvApp",['type' => 'carAtvApp' , 'out_trade_no' => $record['order_code']],$record['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 15:57
+ * @功能说明:文章列表
+ */
+ public function articleList(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ if(!empty($input['type'])){
+
+ $dis['type'] = $input['type'];
+ }
+
+ $data = $article_model->dataList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 16:02
+ * @功能说明:文章详情
+ */
+ public function articleInfo(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $article_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y.m.d H:i',$data['create_time']);
+
+ $article_model->dataUpdate(['id'=>$input['id']],['iv'=>$data['iv']+1]);
+
+ return $this->success($data);
+
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 14:16
+ * @功能说明:获取配置信息
+ */
+ public function configInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo($dis);
+
+ return $this->success($config);
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:07
+ * @功能说明:购物车信息
+ */
+ public function carInfo(){
+
+ $input = $this->_param;
+ //购物车信息
+ $car_info = $this->car_model->carPriceAndCount($this->getUserId(),1);
+
+ return $this->success($car_info);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-23 09:48
+ * @功能说明:再来一单
+ */
+ public function onceMoreOrder(){
+
+ $input = $this->_input;
+
+ $order_model = new Order();
+
+ $order = $order_model->dataInfo(['id'=>$input['order_id']]);
+
+ $coach = $this->coach_model->dataInfo(['id'=>$order['coach_id']]);
+
+ if($coach['status']!=2||$coach['is_work']==0){
+
+ $this->errorMsg('技师未上班');
+ }
+ //清空购物车
+ $this->car_model->where(['user_id'=>$this->getUserId(),'coach_id'=>$order['coach_id']])->delete();
+
+ Db::startTrans();
+
+ foreach ($order['order_goods'] as $v){
+
+ $ser = $this->model->dataInfo(['id'=>$v['goods_id']]);
+
+ if(empty($ser)||$ser['status']!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('服务已经下架');
+ }
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'uniacid' => $this->_uniacid,
+
+ 'coach_id' => $order['coach_id'],
+
+ 'service_id'=> $v['goods_id'],
+
+ 'num' => $v['num']
+ ];
+
+ $res = $this->car_model->dataAdd($dis);
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:46
+ * @功能说明:添加到购物车
+ */
+ public function addCar(){
+
+ $input = $this->_input;
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'goods_id' => $input['goods_id'],
+
+ ];
+
+ $info = $this->car_model->dataInfo($insert);
+ //增加数量
+ if(!empty($info)){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['num'=>$info['num']+$input['num']]);
+
+ }else{
+ //添加到购物车
+ $insert['num'] = $input['num'];
+
+ $insert['status'] = 1;
+
+ $res = $this->car_model->dataAdd($insert);
+
+ $id = $this->car_model->getLastInsID();
+
+ return $this->success($id);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:54
+ * @功能说明:删除购物车
+ */
+ public function delCar(){
+
+ $input = $this->_input;
+
+ $info = $this->car_model->dataInfo(['id'=>$input['id']]);
+ //加少数量
+ if($info['num']>$input['num']){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['num'=>$info['num']-$input['num']]);
+
+ }else{
+
+ $res = $this->car_model->where(['id'=>$info['id']])->delete();
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 10:39
+ * @功能说明:
+ */
+ public function carUpdate(){
+
+ $input = $this->_input;
+
+ $res = $this->car_model->where('id','in',$input['id'])->update(['status'=>$input['status']]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:59
+ * @功能说明:批量删除购物车
+ */
+ public function delSomeCar(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+// 'coach_id'=> $input['coach_id'],
+
+ ];
+
+ $res = $this->car_model->where($dis)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:16
+ * @功能说明:评价列表
+ */
+ public function commentList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($input['coach_id'])){
+
+ $dis[] = ['d.id','=',$input['coach_id']];
+ }
+
+ if(!empty($input['coach_name'])){
+
+ $dis[] = ['d.coach_name','like','%'.$input['coach_name'].'%'];
+ }
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ $comment_model = new Comment();
+
+ $data = $comment_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/IndexBalance.php b/app/massage/controller/IndexBalance.php
new file mode 100755
index 0000000..216e253
--- /dev/null
+++ b/app/massage/controller/IndexBalance.php
@@ -0,0 +1,270 @@
+model = new BalanceCard();
+
+ $this->balance_order = new BalanceOrder();
+
+ $this->water_model = new BalanceWater();
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-04 19:09
+ * @功能说明:储值充值卡列表
+ */
+ public function cardList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['title','like','%'.$input['name'].'%'];
+
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $level = new Level();
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ $v['member_title']= $level->where(['id'=>$v['member_level']])->value('title');
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 17:00
+ * @功能说明:充值余额
+ */
+ public function payBalanceOrder(){
+
+ $input = $this->_input;
+
+ if(!empty($input['card_id'])){
+
+ $dis = [
+
+ 'id' => $input['card_id'],
+
+ 'status' => 1
+ ];
+
+ $card = $this->model->dataInfo($dis);
+
+ if(empty($card)){
+
+ $this->errorMsg('充值卡已被下架');
+ }
+
+ }else{
+
+ $card = [
+
+ 'price' => $input['price'],
+
+ 'true_price' => $input['price'],
+
+ 'id' => 0,
+
+ 'member_level'=> 0,
+
+ 'title' => '自定义金额充值'
+ ];
+ }
+
+
+ $user_model = new User();
+
+ $level_model= new Level();
+
+ $user = $user_model->dataInfo(['id'=>$this->getUserId()]);
+
+ $user_level_discount = $level_model->where(['id'=>$user['member_level']])->value('discount');
+
+ $user_level_discount = !empty($user_level_discount)?$user_level_discount:0;
+
+ $member_level_dicount= $level_model->where(['id'=>$card['member_level']])->value('discount');
+
+ $member_level_dicount= !empty($member_level_dicount)?$member_level_dicount:0;
+
+ $card['member_level']= $member_level_dicount>$user_level_discount?$card['member_level']:0;
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_code' => orderCode(),
+
+ 'pay_price' => $card['price'],
+
+ 'sale_price' => $card['price'],
+
+ 'true_price' => $card['true_price'],
+
+ 'card_id' => $card['id'],
+
+ 'title' => $card['title'],
+
+ 'member_level'=> $card['member_level'],
+
+ 'phone' => $input['phone']
+
+ ];
+
+ $res = $this->balance_order->dataAdd($insert);
+
+ if($res==0){
+
+ $this->errorMsg('充值失败');
+
+ }
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"储值",['type' => 'Balance' , 'out_trade_no' => $insert['order_code']],$insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 17:34
+ * @功能说明:充值订单列表
+ */
+ public function balaceOrder(){
+
+ $input = $this->_param;
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['pay_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->balance_order->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ $v['pay_time'] = date('Y-m-d H:i:s',$v['pay_time']);
+
+ }
+ }
+
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 18:00
+ * @功能说明:消费明细
+ */
+ public function payWater(){
+
+ $input = $this->_param;
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+// $dis[] = ['type','=',2];
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['create_time','between',"{$input['start_time']},{$input['end_time']}"];
+
+ }
+
+ $data = $this->water_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/IndexCoach.php b/app/massage/controller/IndexCoach.php
new file mode 100755
index 0000000..f72cbbc
--- /dev/null
+++ b/app/massage/controller/IndexCoach.php
@@ -0,0 +1,580 @@
+model = new Coach();
+
+ $this->order_model = new Order();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','in',[2,3]];
+
+ $this->cap_info = $this->model->dataInfo($cap_dis);
+
+ if(empty($this->cap_info)){
+
+ $this->errorMsg('你还不是技师');
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-08 11:39
+ * @功能说明:技师首页
+ */
+ public function coachIndex(){
+
+ $data = $this->cap_info;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:59
+ * @功能说明:修改技师信息
+ */
+ public function coachUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $this->cap_info['id']
+ ];
+
+ if(!empty($input['id_card'])){
+
+ $input['id_card'] = implode(',',$input['id_card']);
+ }
+
+ if(!empty($input['license'])){
+
+ $input['license'] = implode(',',$input['license']);
+ }
+
+ if(!empty($input['self_img'])){
+
+ $input['self_img'] = implode(',',$input['self_img']);
+ }
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function index(){
+
+ $data = $this->getUserInfo();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.coach_id','=',$this->cap_info['id']];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if($input['pay_type']==5){
+
+ $dis[] = ['a.pay_type','in',[3,4,5]];
+
+ }else{
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ $order_model = new Order();
+
+ $data = $order_model->indexDataList($dis,$where);
+ //待接单数量
+ $data['agent_order_count'] = $order_model->where(['coach_id'=>$this->cap_info['id'],'pay_type'=>2])->count();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 23:11
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['order_id']
+ ];
+
+ $data = $this->order_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 13:33
+ * @功能说明:团长审核提现
+ */
+ public function applyWallet(){
+
+ $input = $this->_input;
+
+ if(empty($input['apply_price'])||$input['apply_price']<0.01){
+
+ $this->errorMsg('提现费最低一分');
+ }
+ //服务费
+ if($input['apply_price']>$this->cap_info['service_price']&&$input['type']==1){
+
+ $this->errorMsg('余额不足');
+ }
+ //车费
+ if($input['apply_price']>$this->cap_info['car_price']&&$input['type']==2){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $coach_level = $this->model->getCoachLevel($this->cap_info['id'],$this->_uniacid);
+
+ // dump($coach_level);exit;
+ //车费没有服务费
+ $balance = !empty($coach_level)&&$input['type']==1?$coach_level['balance']:100;
+
+ $key = 'cap_wallet'.$this->getUserId();
+
+ $value = getCache($key);
+
+ if(!empty($value)){
+
+ $this->errorMsg('网络错误,请刷新重试');
+
+ }
+ //加一个锁防止重复提交
+ incCache($key,1,$this->_uniacid);
+
+ Db::startTrans();
+
+ if($input['type']==1){
+ //减佣金
+ $res = $this->model->dataUpdate(['id'=>$this->cap_info['id']],['service_price'=>$this->cap_info['service_price']-$input['apply_price']]);
+
+ }else{
+
+ $res = $this->model->dataUpdate(['id'=>$this->cap_info['id']],['car_price'=>$this->cap_info['car_price']-$input['apply_price']]);
+
+ }
+
+ if($res!=1){
+
+ Db::rollback();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $this->errorMsg('申请失败');
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'coach_id' => $this->cap_info['id'],
+
+ 'total_price' => $input['apply_price'],
+
+ 'balance' => $balance,
+
+ 'apply_price' => round($input['apply_price']*$balance/100,2),
+
+ 'service_price' => round($input['apply_price']-$input['apply_price']*$balance/100,2),
+
+ 'code' => orderCode(),
+
+ 'text' => $input['text'],
+
+ 'type' => $input['type'],
+
+ ];
+
+ $wallet_model = new Wallet();
+ //提交审核
+ $res = $wallet_model->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $this->errorMsg('申请失败');
+ }
+
+ Db::commit();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:14
+ * @功能说明:楼长核销订单
+ */
+ public function hxOrder(){
+
+ $input = $this->_input;
+
+ $order_model= new Order();
+
+ $order = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($order['pay_type']!=5){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ if($order['coach_id']!=$this->cap_info['id']){
+
+ $this->errorMsg('你不是该订单的楼长');
+
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $order_model->hxOrder($order,$this->cap_info['id']);
+
+ return $this->success($res);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 13:38
+ * @功能说明:团长端佣金信息
+ */
+ public function capCashInfo(){
+
+ $this->order_model->coachBalanceArr($this->_uniacid);
+
+ $key = 'cap_wallet'.$this->getUserId();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $wallet_model = new Wallet();
+ //可提现佣金
+ $data['cap_cash'] = $this->cap_info['service_price'];
+ //累计提现
+ $data['extract_total_price'] = $wallet_model->capCash($this->cap_info['id'],2,1);
+ //提现中
+ $data['extract_ing_price'] = $wallet_model->capCash($this->cap_info['id'],1,1);
+
+ $dis = [
+
+ 'pay_type' => 7,
+
+ 'coach_id' => $this->cap_info['id'],
+
+ 'have_tx' => 0
+ ];
+ //未到账
+ $data['no_received'] = $this->order_model->where($dis)->sum('service_price');
+
+ $data['coach_level'] = $this->model->getCoachLevel($this->cap_info['id'],$this->_uniacid);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 13:38
+ * @功能说明:团长端佣金信息
+ */
+ public function capCashInfoCar(){
+
+ $key = 'cap_wallet'.$this->getUserId();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $wallet_model = new Wallet();
+ //可提现佣金
+ $data['cap_cash'] = $this->cap_info['car_price'];
+ //累计提现
+ $data['extract_total_price'] = $wallet_model->capCash($this->cap_info['id'],2,2);
+ //提现中
+ $data['extract_ing_price'] = $wallet_model->capCash($this->cap_info['id'],1,2);
+
+ $dis = [
+
+ 'pay_type' => 7,
+
+ 'coach_id' => $this->cap_info['id'],
+
+ 'have_tx' => 0
+ ];
+ //未到账
+ $data['no_received'] = $this->order_model->where($dis)->sum('car_price');
+
+ $data['coach_level'] = $this->model->getCoachLevel($this->cap_info['id'],$this->_uniacid);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:39
+ * @功能说明:团长提现记录
+ */
+ public function capCashList(){
+
+ $wallet_model = new Wallet();
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'coach_id' => $this->cap_info['id']
+ ];
+
+ if(!empty($input['status'])){
+
+ $dis['status'] = $input['status'];
+ }
+
+ $dis['type'] = $input['type'];
+ //提现记录
+ $data = $wallet_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+ //累计提现
+ $data['extract_total_price'] = $wallet_model->capCash($this->cap_info['id'],2,$input['type']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-08 17:09
+ * @功能说明:报警
+ */
+ public function police(){
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'coach_id'=> $this->cap_info['id'],
+
+ 'user_id' => $this->cap_info['user_id'],
+
+ 'text' => '正在发出求救信号,请及时查看技师正在服务的订单地址和电话,确认报警信息'
+ ];
+
+
+ $police_model = new Police();
+
+ $res = $police_model->dataAdd($insert);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 22:34
+ * @功能说明:技师修改订单信息)
+ */
+ public function updateOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->order_model->dataInfo(['id'=>$input['order_id']]);
+
+ $update = $this->order_model->coachOrdertext($input);
+
+ Db::startTrans();
+ //核销订单
+ if($input['type']==7){
+
+ if($order['pay_type']!=6){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $this->order_model->hxOrder($order,$this->cap_info['id']);
+
+ $res = $this->order_model->dataUpdate(['id'=>$input['order_id']],$update);
+
+ }else{
+
+// dump($update);exit;
+
+ $res = $this->order_model->dataUpdate(['id'=>$input['order_id']],$update);
+ //拒绝接单
+ if($input['type']==-1){
+
+ if($order['pay_type']!=2){
+
+ Db::rollback();
+
+ $this->errorMsg('已接单');
+
+ }
+
+ if($order['pay_price']>0){
+
+ $refund_model = new RefundOrder();
+
+ $res = $refund_model->refundCash($this->payConfig(),$order,$order['pay_price']);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+
+ }
+
+ if($res!=true){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败,请重试2');
+
+ }
+ }
+
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/IndexGoods.php b/app/massage/controller/IndexGoods.php
new file mode 100755
index 0000000..f38db87
--- /dev/null
+++ b/app/massage/controller/IndexGoods.php
@@ -0,0 +1,308 @@
+model = new Goods();
+
+// $this->cate_model = new GoodsCate();
+
+ $this->car_model = new Car();
+
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 16:46
+ * @功能说明:分类列表
+ */
+ public function cateList(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ 'cap_id' => $this->getCapInfo()['id']
+ ];
+
+ $data = $this->cate_model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:19
+ * @功能说明:商品列表
+ */
+ public function goodsList(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ //商品信息
+ $data = $this->model->dataList($dis,10);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:07
+ * @功能说明:购物车信息
+ */
+ public function carInfo(){
+ //购物车信息
+ $car_info = $this->car_model->carPriceAndCount($this->getUserId(),$this->getCapInfo()['id'],1);
+
+ return $this->success($car_info);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:46
+ * @功能说明:商品详情
+ */
+ public function goodsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 11:57
+ * @功能说明:首页选择楼长列表
+ */
+ public function indexCapList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['business_status','=',1];
+
+ if(!empty($input['store_name'])){
+
+ $dis[] = ['store_name','like','%'.$input['store_name'].'%'];
+ }
+
+ $lat = !empty($input['lat'])?$input['lat']:0;
+
+ $lng = !empty($input['lng'])?$input['lng']:0;
+
+ $alh = '(2 * 6378.137* ASIN(SQRT(POW(SIN(3.1415926535898*('.$lat.'-lat)/360),2)+COS(3.1415926535898*'.$lat.'/180)* COS('.$lat.' * 3.1415926535898/180)*POW(SIN(3.1415926535898*('.$lng.'-lng)/360),2))))*1000 as distance';
+
+ $alhs = '(2 * 6378.137* ASIN(SQRT(POW(SIN(3.1415926535898*('.$lat.'-lat)/360),2)+COS(3.1415926535898*'.$lat.'/180)* COS('.$lat.' * 3.1415926535898/180)*POW(SIN(3.1415926535898*('.$lng.'-lng)/360),2))))*1000<20000';
+
+ $cap_model = new Cap();
+
+ $data = $cap_model->dataList($dis,$alh,$alhs,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['distance'] = getDistances($v['lng'],$v['lat'],$lng,$lat);
+
+ $v['distance'] = $cap_model->getDistanceAttr($v['distance']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:24
+ * @功能说明:选择楼长
+ */
+ public function selectCap(){
+
+ $input = $this->_input;
+
+ $user_model = new User();
+
+ $res = $user_model->dataUpdate(['id'=>$this->getUserId()],['cap_id'=>$input['cap_id']]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:46
+ * @功能说明:添加到购物车
+ */
+ public function addCar(){
+
+ $input = $this->_input;
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'cap_id' => $this->getCapInfo()['id'],
+
+ 'goods_id'=> $input['goods_id'],
+
+ 'spe_id' => $input['spe_id']
+
+ ];
+
+ $info = $this->car_model->dataInfo($insert);
+ //增加数量
+ if(!empty($info)){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['goods_num'=>$info['goods_num']+$input['goods_num']]);
+
+ }else{
+ //添加到购物车
+ $insert['goods_num'] = $input['goods_num'];
+
+ $insert['status'] = 1;
+
+ $res = $this->car_model->dataAdd($insert);
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:54
+ * @功能说明:删除购物车
+ */
+ public function delCar(){
+
+ $input = $this->_input;
+
+ $info = $this->car_model->dataInfo(['id'=>$input['id']]);
+ //加少数量
+ if($info['goods_num']>$input['goods_num']){
+
+ $res = $this->car_model->dataUpdate(['id'=>$info['id']],['goods_num'=>$info['goods_num']-$input['goods_num']]);
+
+ }else{
+
+ $res = $this->car_model->where(['id'=>$info['id']])->delete();
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 10:39
+ * @功能说明:
+ */
+ public function carUpdate(){
+
+ $input = $this->_input;
+
+ $res = $this->car_model->where('id','in',$input['id'])->update(['status'=>$input['status']]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 14:59
+ * @功能说明:批量删除购物车
+ */
+ public function delSomeCar(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'cap_id' => $this->getCapInfo()['id'],
+
+ ];
+
+ $res = $this->car_model->where($dis)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+}
diff --git a/app/massage/controller/IndexOrder.php b/app/massage/controller/IndexOrder.php
new file mode 100755
index 0000000..8fc5658
--- /dev/null
+++ b/app/massage/controller/IndexOrder.php
@@ -0,0 +1,1010 @@
+model = new Order();
+
+ $this->refund_model = new RefundOrder();
+
+ $this->order_goods_model = new OrderGoods();
+
+// $this->model->coachBalanceArr($this->_uniacid);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 00:26
+ * @功能说明:天数
+ */
+ public function dayText(){
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $start_time = strtotime(date('Y-m-d',time()));
+
+ // $start_time = $start_time+$config['max_day']*86400;
+
+ $i=0;
+
+ while ($i<$config['max_day']){
+
+ $str = $start_time+$i*86400;
+
+ $data[$i]['dat_str'] = $str;
+
+ $data[$i]['dat_text'] = date('m-d',$str);
+
+ $data[$i]['week'] = changeWeek(date('w',$str));
+
+ $i++;
+
+ }
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-09 14:41
+ * @功能说明:时间段
+ */
+ public function timeText(){
+
+ $input = $this->_param;
+
+ $config_model = new Config();
+
+ $coach_model = new Coach();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $coach = $coach_model->dataInfo(['id'=>$input['coach_id']]);
+
+ $end_time = strtotime($coach['end_time'])- strtotime(date("Y-m-d",time()))+strtotime(date("Y-m-d",$input['day']));
+
+ $start_time = strtotime($coach['start_time'])-strtotime(date("Y-m-d",time()))+strtotime(date("Y-m-d",$input['day']));
+
+ $i = 0;
+
+ $data = [];
+
+ $time = $start_time;
+
+ while ($time<$end_time){
+
+ $time = $start_time+$config['time_unit']*$i*60;
+ //时间戳
+ $data[$i]['time_str'] = $time;
+
+ $data[$i]['time_text']= date('H:i',$time);
+
+ $where = [];
+
+ $where[] = ['coach_id','=',$input['coach_id']];
+
+ $where[] = ['start_time','<=',$time];
+
+ $where[] = ['end_time','>=',$time];
+
+ $where[] = ['pay_type','not in',[-1]];
+
+ $order = $this->model->dataInfo($where);
+
+ if(!empty($order)){
+
+ $data[$i]['status'] = 0;
+
+ }else{
+
+ $data[$i]['status'] = 1;
+
+ }
+
+ $data[$i]['status'] = $timesuccess($data);
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function orderList(){
+ //超时自动取消订单
+ $this->model->autoCancelOrder($this->_uniacid,$this->getUserId());
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ $dis[] = ['a.is_show','=',1];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ $data = $this->model->indexDataList($dis,$where);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $can_refund_num = is_array($v['order_goods'])?array_sum(array_column($v['order_goods'],'can_refund_num')):0;
+ //是否可以申请退款
+// if(($v['pay_type']==7&&$v['can_tx_date']>time()&&$can_refund_num>0)||(in_array($v['pay_type'],[2,3,4,5,6])&&$can_refund_num>0)){
+ if((in_array($v['pay_type'],[2])&&$can_refund_num>0)){
+
+ $v['can_refund'] = 1;
+
+ }else{
+
+ $v['can_refund'] = 0;
+ }
+
+ }
+
+ }
+ //查询待支付订单待条数
+ $dis = [
+
+ 'pay_type' => 1,
+
+ 'user_id' => $this->getUserId()
+ ];
+
+ $data['no_pay_count'] = $this->model->where($dis)->count();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ // $data['order_end_time'] -= time();
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['pay_time'] = date('Y-m-d H:i:s',$data['pay_time']);
+
+ $data['hx_time'] = date('Y-m-d H:i:s',$data['hx_time']);
+ //剩余可申请退款数量
+ $can_refund_num = array_sum(array_column($data['order_goods'],'can_refund_num'));
+ //是否可以申请退款
+ if((in_array($data['pay_type'],[2])&&$can_refund_num>0)){
+
+ $data['can_refund'] = 1;
+
+ }else{
+
+ $data['can_refund'] = 0;
+ }
+
+ $data['over_time'] -= time();
+
+ $data['over_time'] = $data['over_time']>0?$data['over_time']:0;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:29
+ * @功能说明:退款订单详情
+ *
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $data = $this->refund_model->indexDataList($dis,$where);
+ //待接单数量
+ $data['ing_count'] = $this->refund_model->where(['user_id'=>$this->getUserId(),'status'=>1])->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->refund_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 09:43
+ * @功能说明:下单页面详情
+ */
+ public function payOrderInfo(){
+
+ $input = $this->_param;
+
+ $coupon = !empty($input['coupon_id'])?$input['coupon_id']:0;
+
+ $coupon_modle = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),$coupon);
+ //可用优惠券数量
+ $canUseCoupon = $coupon_modle->canUseCoupon($this->getUserId());
+
+ $order_info['canUseCoupon'] = $coupon_record_model->where('id','in',$canUseCoupon)->sum('num');
+
+// $car_model = new CarPrice();
+//
+// $dis = [
+//
+// 'uniacid' => $this->_uniacid
+// ];
+//
+// $order_info['car_config'] = $car_model->dataInfo($dis);
+
+ return $this->success($order_info);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-10 00:40
+ * @功能说明:可用的优惠券列表
+ */
+ public function couponList(){
+
+ $input = $this->_param;
+
+ $coupon_model = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon_id = $coupon_model->canUseCoupon($this->getUserId());
+
+ $data = $coupon_record_model->where('id','in',$coupon_id)->order('id desc')->paginate(10)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 09:53
+ * @功能说明:下单
+ */
+ public function payOrder(){
+
+ $input = $this->_input;
+
+ $coupon_record_model = new CouponRecord();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $coupon_id = !empty($input['coupon_id'])?$input['coupon_id']:0;
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),$coupon_id);
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ Db::startTrans();
+
+ $member_config_model = new \app\member\model\Config();
+
+ $member_config = $member_config_model->configInfo(['uniacid'=>$this->_uniacid]);
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'over_time' => time()+$config['over_time']*60,
+
+ 'order_code' => orderCode(),
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_price' => $order_info['pay_price'],
+
+ 'init_price' => $order_info['init_goods_price'],
+
+ 'balance' => !empty($input['is_balance'])?$order_info['pay_price']:0,
+
+ 'discount' => $order_info['discount'],
+
+ 'pay_type' => 1,
+
+ 'mobile' => $input['mobile'],
+
+ 'total_circle'=> $order_info['total_circle'],
+ //付费获得的积分
+ 'get_integral'=> empty($input['is_balance'])?floor($order_info['pay_price']*$member_config['integral_cash']):0,
+ //备注
+// 'text' => $input['text'],
+
+// 'can_tx_time' => $config['can_tx_time'],
+
+ ];
+ //下单
+ $res = $this->model->dataAdd($order_insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+ }
+
+ $order_id = $this->model->getLastInsID();
+ //使用优惠券
+ if(!empty($coupon_id)){
+
+ $coupon_id = $coupon_record_model->couponUse($coupon_id,$order_id);
+
+ $this->model->dataUpdate(['id'=>$order_id],['coupon_id'=>$coupon_id]);
+
+ }
+ //添加到子订单
+ $res = $this->order_goods_model->orderGoodsAdd($order_info['order_goods'],$order_id,$this->getUserId());
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $code = $res['code']==50001?50001:400;
+
+ $this->errorMsg($res['msg'],$code);
+ }
+
+ Db::commit();
+ //如果是0元
+ if($order_insert['pay_price']<=0){
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if(!empty($input['is_balance'])){
+
+ $user_model = new User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"anmo",['type' => 'Massage' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 15:59
+ * @功能说明:重新支付
+ */
+ public function rePayOrder(){
+
+ $input = $this->_input;
+
+ $order_insert = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+ //余额支付
+ if(!empty($order_insert['balance'])){
+
+ $user_model = new User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"anmo",['type' => 'Massage' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 13:44
+ * @功能说明:核销订单
+ */
+ public function hxOrder(){
+
+ $input = $this->_input;
+
+ $record = $this->model->dataInfo(['id'=>$input['order_id']]);
+
+ if($record['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ $user_model = new User();
+
+ $user_role = $user_model->where(['id'=>$this->getUserId()])->value('role');
+
+ if($user_role!=1){
+
+ $this->errorMsg('管理员才有核销权限');
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$record['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ Db::startTrans();
+
+ $res = $this->model->hxOrder($record,$this->getUserId());
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('核销失败');
+
+ }
+
+ $game_model = new CarGame();
+ //清空当前使用卡
+ $game_model->dataUpdate(['now_card_id'=>$input['card_id']],['now_card_id'=>'']);
+ //判断类型 专业组还是普通
+ $car_type_model = new CarType();
+
+ $type = $car_type_model->getType($record['order_goods'][0]['car_type_id'],$record['user_id']);
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $record['user_id'],
+
+ 'record_id' => $record['id'],
+
+ 'card_id' => $input['card_id'],
+
+ 'now_card_id' => $input['card_id'],
+
+ 'type' => 2,
+
+ 'major' => $type,
+
+ 'car_type_id' => $record['order_goods'][0]['car_type_id'],
+
+
+ ];
+ //添加比赛记录标 准备开始比赛
+ $res = $game_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('核销失败');
+
+ }
+ //查询是否正在排队
+ $line_model = new CarLineUp();
+
+ $dis = [
+
+ 'order_id' => $record['id'],
+
+ 'type' => 1
+ ];
+
+ $line_model->dataUpdate($dis,['status'=>2]);
+ //如果有需要到账的积分
+ if(!empty($record['get_integral'])&&$record['have_tx']==0){
+
+ $integral_model = new \app\member\model\Integral();
+
+ $integral_model->integralUserAdd($record['user_id'],$record['get_integral'],$record['uniacid'],2,9,$record['id']);
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 16:38
+ * @功能说明:取消订单
+ */
+
+ public function cancelOrder(){
+
+ $input = $this->_input;
+
+ $order_insert = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ $res = $this->model->cancelOrder($order_insert);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 11:39
+ * @功能说明:申请退款
+ */
+ public function applyOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->model->dataInfo(['id'=>$input['order_id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($order['pay_type']<2){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ if(empty($input['list'])){
+
+ $this->errorMsg('请选择商品');
+
+ }
+ //申请退款
+ $res = $this->refund_model->applyRefund($order,$input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:55
+ * @功能说明:取消退款
+ */
+ public function cancelRefundOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->refund_model->dataInfo(['id'=>$input['id']]);
+
+ if($order['status']!=1){
+
+ $this->errorMsg('订单已经审核');
+
+ }
+
+ Db::startTrans();
+
+ $res = $this->refund_model->dataUpdate(['id'=>$input['id']],['status'=>-1,'cancel_time'=>time()]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('取消失败');
+ }
+
+ if(!empty($order['order_goods'])){
+
+ $order_goods_model = new OrderGoods();
+
+ foreach ($order['order_goods'] as $v){
+
+ if(!empty($v['order_goods_id'])){
+
+ $num = $v['num'];
+
+ $res = $order_goods_model->where(['id'=>$v['order_goods_id']])->update(['can_refund_num'=>Db::Raw("can_refund_num+$num")]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('取消失败');
+ }
+
+ }
+
+ }
+
+ }
+
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-07 15:30
+ * @功能说明:刷新订单二维码
+ */
+ public function refreshQr(){
+
+ $input = $this->_input;
+
+// $qr_insert = [
+//
+// 'id' => $input['id']
+// ];
+
+ $user_model = new User();
+ //获取二维码
+ $qr = $user_model->orderQr($input,$this->_uniacid);
+
+ if(!empty($qr)){
+
+ $this->model->dataUpdate(['id'=>$input['id']],['qr'=>$qr]);
+
+ }
+
+ return $this->success($qr);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 00:18
+ * @功能说明:评价标签
+ */
+ public function lableList(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $lable_model = new Lable();
+
+ $res = $lable_model->where($dis)->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 14:01
+ * @功能说明:添加评价
+ */
+ public function addComment(){
+
+ $input = $this->_input;
+
+ $order = $this->model->dataInfo(['id'=>$input['order_id']]);
+
+ if($order['is_comment']==1){
+
+ $this->errorMsg('你已经评价过了');
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id'=> $input['order_id'],
+
+ 'star' => $input['star'],
+
+ 'text' => $input['text'],
+
+ 'coach_id'=> $order['coach_id'],
+
+ ];
+
+ Db::startTrans();
+
+ $comment_model = new Comment();
+
+ $coach_model = new Coach();
+
+ $comment_lable_model = new CommentLable();
+
+ $lable_model = new Lable();
+
+ $res = $comment_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('评价失败');
+ }
+
+ $comment_id = $comment_model->getLastInsID();
+
+ if(!empty($input['lable'])){
+
+ foreach ($input['lable'] as $value){
+
+ $title = $lable_model->where(['id'=>$value])->value('title');
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'comment_id' => $comment_id,
+
+ 'lable_id' => $value,
+
+ 'lable_title'=> $title,
+
+ ];
+
+ $comment_lable_model->dataAdd($insert);
+ }
+
+ }
+
+ $all_count = $comment_model->where(['coach_id'=>$order['coach_id']])->count();
+
+ $all_star = $comment_model->where(['coach_id'=>$order['coach_id']])->sum('star');
+
+ $now_star = round($all_star/$all_count,1);
+
+ $now_star = $now_star>5?5:$now_star;
+
+ $coach_model->dataUpdate(['id'=>$order['coach_id']],['star'=>$now_star]);
+
+ $res = $this->model->dataUpdate(['id'=>$order['id']],['is_comment'=>1]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('评价失败');
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 18:35
+ * @功能说明:删除订单
+ */
+ public function delOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order['pay_type']!=-1){
+
+ $this->errorMsg('只有取消的订单才能删除');
+ }
+
+ $res = $this->model->dataUpdate(['id'=>$input['id']],['is_show'=>0]);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/IndexUser.php b/app/massage/controller/IndexUser.php
new file mode 100755
index 0000000..8260704
--- /dev/null
+++ b/app/massage/controller/IndexUser.php
@@ -0,0 +1,1465 @@
+model = new User();
+
+ $this->address_model = new Address();
+
+ $this->record_model = new CarAtvRecord();
+
+ $this->coupon_record_model = new CouponRecord();
+ //积分到账
+ point_success($this->_uniacid);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 15:41
+ * @功能说明:用户报名列表
+ */
+ public function userAtvRecord(){
+
+ $atv_model = new CarAtvList();
+
+ $atv_model->initAtv();
+
+// $this->record_model->autoCancelRecord($this->getUserId());
+
+ $input = $this->_param;
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+ //去除没有取消的
+// $dis[] = ['a.status','>',-1];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['b.atv_status','=',$input['status']];
+ }
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['b.atv_s_time','between',"{$input['start_time']},{$input['end_time']}"];
+ }
+
+ if(!empty($input['record_status'])){
+
+ $dis[] = ['a.pay_type','=',7];
+ }
+
+ $data = $this->record_model->atvRecordList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$vs){
+
+ $vs['day_text'] = date('Y.m.d',$vs['start_time']).' - '.date('Y.m.d',$vs['end_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 15:46
+ * @功能说明:报名详情
+ */
+ public function recordInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data['record_info'] = $this->record_model->dataInfo($dis);
+
+ $data['record_info']['create_time'] = date('Y-m-d H:i:s',$data['record_info']['create_time']);
+
+ $data['record_info']['hx_time'] = date('Y-m-d H:i:s',$data['record_info']['hx_time']);
+
+ $atv_model = new CarAtvList();
+
+ $data['atv_info'] = $atv_model->dataInfo(['id'=>$data['record_info']['atv_id']]);
+
+ $data['game_info']['top'] = $this->record_model->getRecordTop($data['record_info']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-20 09:54
+ * @功能说明:不支付就调用这个状态
+ */
+ public function payCancelRecord(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $record_info = $this->record_model->dataInfo($dis);
+
+ $res = $this->record_model->cancelRecord($record_info,2);
+
+ return $this->success($res);
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function index(){
+
+ $data = $this->getUserInfo();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','in',[1,2,3,4]];
+
+ $driver_model = new CarDriver();
+ //查看是否是团长
+ $cap_info = $driver_model->dataInfo($cap_dis);
+ //-1表示未申请团长,1申请中,2已通过,3取消,4拒绝
+ $data['driver_status'] = !empty($cap_info)?$cap_info['status']:-1;
+
+ $data['sh_text'] = !empty($cap_info)?$cap_info['sh_text']:'';
+ //优惠券数
+ $data['coupon_count'] = $this->coupon_record_model->couponCount($this->getUserId());
+
+ $data['balance'] = $this->model->where(['id'=>$this->getUserId()])->sum('balance');
+
+ $data['integral']= $this->model->where(['id'=>$this->getUserId()])->sum('integral');
+
+ $member_level = $this->model->where(['id'=>$this->getUserId()])->value('member_level');
+
+ $data['balance'] = round($data['balance'] ,2);
+ //查看荣誉杯
+ $user_trophy_model = new CarUserTrophy();
+
+ $data['user_trophy'] = $user_trophy_model->userTrophy($this->getUserId());
+
+ $level_model = new Level();
+
+ $data['member_level_info'] = $level_model->levelInfo(['id'=>$member_level]);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 10:08
+ * @功能说明:取消预约
+ */
+ public function cancelAtvRecord(){
+
+ $input = $this->_input;
+
+ $record = $this->record_model->dataInfo(['id'=>$input['record_id']]);
+
+ if(!in_array($record['pay_type'],[1,2])){
+
+ $this->errorMsg('状态错误');
+ }
+
+ if($record['end_time']errorMsg('活动已经结束');
+ }
+
+ Db::startTrans();
+
+ $res = $this->record_model->cancelRecord($record);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+ }
+
+ //已经支付 需要退款
+ if($record['pay_type']>1&&$record['pay_price']>0){
+ //微信支付
+ if($record['balance']<=0){
+ //微信退款
+ $response = orderRefundApi($this->payConfig(),$record['pay_price'],$record['pay_price'],$record['transaction_id']);
+ //如果退款成功修改一下状态
+ if ( isset( $response[ 'return_code' ] ) && isset( $response[ 'result_code' ] ) && $response[ 'return_code' ] == 'SUCCESS' && $response[ 'result_code' ] == 'SUCCESS' ) {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no'])?$response['out_refund_no']:$record['order_code'];
+
+ $this->record_model->dataUpdate(['id'=>$record['id']],['refund_code'=>$response['out_refund_no']]);
+
+ }else {
+
+ //失败就报错
+ $discption = !empty($response['err_code_des'])?$response['err_code_des']:$response['return_msg'];
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=> $discption];
+
+ }
+ }else{
+
+ //余额
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$record['user_id']]);
+
+ $balance = $user['balance'] + $record['pay_price'];
+
+ $res = $user_model->dataUpdate(['id'=>$record['user_id'],'balance'=> $user['balance']],['balance'=>$balance]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('退款失败');
+ }
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 13:45
+ * @功能说明:活动预约核销码
+ */
+ public function atvRecordQr(){
+
+ $input = $this->_input;
+
+ $key = 'atv_app_qr'.$input['record_id'];
+
+ $qr = getCache($key,$this->_uniacid);
+
+ if(empty($qr)){
+ //获取二维码
+ $qr = $this->model->orderQr($input,$this->_uniacid);
+
+ setCache($key,$qr,86400,$this->_uniacid);
+ }
+
+ return $this->success($qr);
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 13:44
+ * @功能说明:核销活动预约
+ */
+ public function hxAtvRecord(){
+
+ $input = $this->_input;
+
+ $record = $this->record_model->dataInfo(['id'=>$input['record_id']]);
+
+ if($record['pay_type']!=3){
+
+ $this->errorMsg('报名状态错误');
+
+ }
+
+ $user_role = $this->model->where(['id'=>$this->getUserId()])->value('role');
+
+ if($user_role!=1){
+
+ $this->errorMsg('管理员才有核销权限');
+ }
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$record['uniacid']]);
+
+ $atv_model = new CarAtvList();
+
+ $integral_time = $atv_model->where(['id'=>$record['atv_id']])->value('integral_time');
+
+ Db::startTrans();
+
+ $update = [
+
+ 'hx_user' => $this->getUserId(),
+
+ 'pay_type'=> 7,
+
+ 'hx_time' => time(),
+ //可申请退款的时间
+ 'can_refund_time'=> time()+$integral_time*3600
+
+ ];
+
+ $res = $this->record_model->dataUpdate(['id'=>$input['record_id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('核销失败');
+
+ }
+
+ $game_model = new CarGame();
+ //清空当前使用卡
+ $game_model->dataUpdate(['now_card_id'=>$input['card_id']],['now_card_id'=>'']);
+ //判断类型 专业组还是普通
+ $car_type_model = new CarType();
+
+ $type = $car_type_model->getType($record['car_type_id'],$record['user_id']);
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $record['user_id'],
+
+ 'record_id' => $record['id'],
+
+ 'card_id' => $input['card_id'],
+
+ 'now_card_id' => $input['card_id'],
+ //比赛类型
+ 'major' => $type,
+
+ 'car_type_id' => $record['car_type_id'],
+
+ 'atv_id' => $record['atv_id'],
+ ];
+ //添加比赛记录标 准备开始比赛
+ $res = $game_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('核销失败');
+
+ }
+ //修改签到信息
+ //查询是否正在排队
+ $line_model = new CarLineUp();
+
+ $dis = [
+
+ 'order_id' => $record['id'],
+
+ 'type' => 2
+ ];
+
+ $line_model->dataUpdate($dis,['status'=>2]);
+// //如果有需要到账的积分
+// if(!empty($record['get_integral'])&&$record['have_tx']==0){
+//
+// $integral_model = new \app\member\model\Integral();
+//
+// $integral_model->integralUserAdd($record['user_id'],$record['get_integral'],$record['uniacid'],2,8,$record['id']);
+//
+// }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:54
+ * @功能说明:用户地址列表
+ */
+ public function addressList(){
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->address_model->dataList($dis,10);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:57
+ * @功能说明:用户地址详情
+ */
+ public function addressInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->address_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:58
+ * @功能说明:添加用户地址
+ */
+ public function addressAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $res = $this->address_model->dataAdd($input);
+
+ if($input['status']==1){
+
+ $id = $this->address_model->getLastInsID();
+
+ $this->address_model->updateOne($id);
+ }
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:58
+ * @功能说明:添加用户地址
+ */
+ public function addressUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->address_model->dataUpdate($dis,$input);
+
+ if(!empty($input['status'])&&$input['status']==1){
+
+ $this->address_model->updateOne($input['id']);
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 22:54
+ * @功能说明:获取默认地址
+ */
+ public function getDefultAddress(){
+
+ $address_model = new Address();
+
+// dump(['user_id'=>$this->getUserId(),'status'=>1]);exit;
+
+ $address = $address_model->dataInfo(['user_id'=>$this->getUserId(),'status'=>1]);
+
+ return $this->success($address);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:13
+ * @功能说明:删除地址
+ */
+ public function addressDel(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->address_model->where($dis)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 13:56
+ * @功能说明:修改用户信息 授权微信信息等
+ */
+ public function userUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $this->getUserId()
+ ];
+
+ if(!empty($input['coupon_atv_id'])&&empty($this->getUserInfo()['nickName'])&&!empty($input['nickName'])){
+
+ $coupon_atv_model = new CouponAtv();
+
+ $coupon_atv_model->invUser($this->getUserId(),$input['coupon_atv_id']);
+ }
+
+ if(isset($input['coupon_atv_id'])){
+
+ unset($input['coupon_atv_id']);
+ }
+
+ if(isset($input['watermark'])){
+
+ unset($input['watermark']);
+ }
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ $user_info = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ setCache($this->autograph, $user_info, 7200, $this->_uniacid);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 14:08
+ * @功能说明:用户信息
+ */
+ public function userInfo(){
+
+ $data = $this->getUserInfo();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','in',[1,2,3,4]];
+
+ $driver_model = new CarDriver();
+ //查看是否是团长
+ $cap_info = $driver_model->dataInfo($cap_dis);
+ //-1表示未申请团长,1申请中,2已通过,3取消,4拒绝
+ $data['driver_status'] = !empty($cap_info)?$cap_info['status']:-1;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:39
+ * @功能说明:团长详情
+ */
+ public function coachInfo(){
+
+ $order_model = new Order();
+
+ $order_model->coachBalanceArr($this->_uniacid);
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','in',[1,2,3,4]];
+
+ $cap_info = $this->coach_model->dataInfo($cap_dis);
+
+
+ return $this->success($cap_info);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 13:35
+ * @功能说明:申请认证车手
+ */
+ public function carApply(){
+
+ $input = $this->_input;
+
+ $driver_model = new CarDriver();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','>',-1];
+
+ $cap_info = $driver_model->dataInfo($cap_dis);
+
+ if(!empty($cap_info)&&in_array($cap_info['status'],[1,2,3])){
+
+ $this->errorMsg('你已经申请过车手了了,');
+ }
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['user_id'] = $this->getUserId();
+
+ $input['status'] = 1;
+
+
+ if(!empty($cap_info)&&$cap_info['status']==4){
+
+ $res = $driver_model->dataUpdate(['id'=>$cap_info['id']],$input);
+
+ }else{
+
+ $res = $driver_model->dataAdd($input);
+
+ }
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 10:43
+ * @功能说明:车手详情
+ */
+ public function carInfo(){
+
+ $driver_model = new CarDriver();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','>',-1];
+
+ $cap_info = $driver_model->dataInfo($cap_dis);
+
+ return $this->success($cap_info);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-08 11:51
+ * @功能说明:用户优惠券列表
+ */
+ public function userCouponList(){
+
+ $input = $this->_param;
+
+ $this->coupon_record_model->initCoupon($this->_uniacid);
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'status' => $input['status'],
+
+ 'is_show' => 1
+ ];
+
+ $data = $this->coupon_record_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-16 22:09
+ * @功能说明:删除优惠券
+ */
+ public function couponDel(){
+
+ $input = $this->_input;
+
+ $coupon = $this->coupon_record_model->dataInfo(['id'=>$input['coupon_id']]);
+
+ if($coupon['status']==1){
+
+ $this->errorMsg('待使用待卡券不能删除');
+ }
+
+ $res = $this->coupon_record_model->dataUpdate(['id'=>$input['coupon_id']],['is_show'=>0]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 19:45
+ * @功能说明:优惠券活动详情
+ */
+ public function couponAtvInfo(){
+
+ $input = $this->_input;
+
+ $atv_record_model = new CouponAtvRecord();
+
+ $atv_record_list_model = new CouponAtvRecordList();
+
+ $atv_model = new CouponAtv();
+
+ if(empty($input['id'])){
+
+ $dis_where[] = ['status','=',1];
+
+ $dis_where[] = ['end_time','<',time()];
+ //修改过期状态
+ $atv_record_model->dataUpdate($dis_where,['status'=>3]);
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'status' => 1
+ ];
+ //查询有没有进行中的活动
+ $atv_ing = $atv_record_model->dataInfo($dis);
+
+ if(empty($atv_ing)){
+
+ $atv_ing = $this->couponAtvAdd();
+ }
+ //
+ if(empty($atv_ing)){
+
+ $atv_ing = $atv_record_model->where(['user_id'=>$this->getUserId()])->order('id desc')->find();
+
+ $atv_ing = !empty($atv_ing)?$atv_ing->toArray():[];
+ }
+
+ if(empty($atv_ing)){
+
+ $this->errorMsg('你没有可以进行的活动');
+ }
+
+ }else{
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+ //查询有没有进行中的活动
+ $atv_ing = $atv_record_model->dataInfo($dis);
+ }
+
+ $atv = $atv_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $atv_ing['atv_num'] = $atv['atv_num'];
+
+ $atv_ing['end_time'] -= time();
+
+ $atv_ing['end_time'] = $atv_ing['end_time']>0?$atv_ing['end_time']:0;
+
+ $data['atv_info'] = $atv_ing;
+ //邀请记录
+ $data['record_list'] = $atv_record_list_model->dataList(['a.record_id'=>$atv_ing['id']],50);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 16:29
+ * @功能说明:发起优惠券活动
+ */
+ public function couponAtvAdd(){
+
+ $atv_model = new CouponAtv();
+
+ $atv_record_model = new CouponAtvRecord();
+
+ $atv_record_coupon_model = new CouponAtvRecordCoupon();
+
+ $atv_config = $atv_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+
+ if($atv_config['status']==0){
+
+ return [];
+ }
+
+ if($atv_config['start_time']>time()||$atv_config['end_time']getUserId()];
+
+ $where[] = ['status','<>',3];
+
+ $count = $atv_record_model->where($where)->count();
+
+ if($count>=$atv_config['atv_num']){
+
+ return [];
+
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'atv_id' => $atv_config['id'],
+
+ 'atv_start_time' => $atv_config['start_time'],
+
+ 'atv_end_time' => $atv_config['end_time'],
+
+ 'inv_user_num' => $atv_config['inv_user_num'],
+
+ 'inv_time' => $atv_config['inv_time'],
+
+ 'start_time' => time(),
+
+ 'end_time' => time()+$atv_config['inv_time']*3600,
+
+ 'inv_user' => $atv_config['inv_user'],
+
+ 'to_inv_user' => $atv_config['to_inv_user'],
+
+ 'share_img' => $atv_config['share_img'],
+
+ ];
+
+ Db::startTrans();
+
+ $res = $atv_record_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('发起活动失败');
+ }
+
+ $record_id = $atv_record_model->getLastInsID();
+ //记录该活动需要派发那些券
+ foreach ($atv_config['coupon'] as $value){
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'atv_id' => $atv_config['id'],
+
+ 'record_id' => $record_id,
+
+ 'coupon_id' => $value['coupon_id'],
+
+ 'num' => $value['num'],
+
+ ];
+
+ $res = $atv_record_coupon_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('发起活动失败');
+ }
+
+ }
+
+ Db::commit();
+
+ $record = $atv_record_model->dataInfo(['id'=>$record_id]);
+
+ return $record;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:40
+ * @功能说明:生产二维码
+ */
+
+ public function atvQr(){
+
+ $input = $this->_input;
+
+ $key = 'atv_coupon'.$input['coupon_atv_id'];
+
+ $qr = getCache($key,$this->_uniacid);
+
+ if(empty($qr)){
+
+// $qr_insert = [
+//
+// 'coupon_atv_id' => $input['coupon_atv_id']
+// ];
+ //获取二维码
+ $qr = $this->model->orderQr($input,$this->_uniacid);
+
+ setCache($key,$qr,86400,$this->_uniacid);
+ }
+
+ return $this->success($qr);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-14 19:22
+ * @功能说明:授权手机号
+ */
+ public function reportPhone ()
+ {
+
+ $params = $this->_input;
+
+ $encryptedData = $params[ 'encryptedData' ];
+
+ $iv = $params[ 'iv' ];
+
+ $config = longbingGetAppConfig($this->_uniacid);
+
+ $appid = $config[ 'appid' ];
+
+ // $appsecret = $config[ 'app_secret' ];
+
+ $session_key = $this->model->where(['id'=>$this->getUserId()])->value('session_key');
+
+ if(empty($session_key)){
+
+ $this->errorMsg('need login',401);
+ }
+ $data = null;
+ // 解密
+ $errCode = decryptDataLongbing( $appid, $session_key, $encryptedData, $iv, $data );
+
+ if ( $errCode == 0 )
+ {
+ $data = json_decode( $data, true );
+
+ $phone = $data[ 'purePhoneNumber' ];
+
+ }
+ else
+ {
+ return $this->error( $errCode );
+ }
+
+ $res = $this->model->dataUpdate(['id'=>$this->getUserId()],['phone'=>$phone]);
+
+ $user_info = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ setCache($this->autograph, $user_info, 7200, $this->_uniacid);
+
+ return $this->success($phone);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 10:16
+ * @功能说明:查询有成绩对日期
+ */
+ public function resultDate(){
+
+ $game_model = new CarGame();
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'have_game' => 1
+ ];
+
+ $data = $game_model->where($dis)->order('id desc')->column('day');
+
+ $data = array_values($data);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 10:29
+ * @功能说明:根据日期获取比赛车型
+ */
+ public function resultCarType(){
+
+ $params = $this->_param;
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+// 'status' => 2,
+
+ 'day' => $params['day']
+ ];
+
+ $game_model = new CarGame();
+
+ $data = $game_model->where($dis)->order('id desc')->group('car_type_id')->field('car_type_id')->select()->toArray();
+
+ if(!empty($data)){
+
+ $car_type_model = new CarType();
+
+ foreach ($data as &$v){
+
+ $v['car_type_title'] = $car_type_model->where(['id'=>$v['car_type_id']])->value('title');
+
+ }
+
+ }
+
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 10:33
+ * @功能说明:个人成绩
+ */
+ public function userResult(){
+
+ $params = $this->_param;
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'car_type_id' => $params['car_type_id'],
+
+ ];
+
+ if(!empty($params['atv_id'])){
+
+ $dis['atv_id'] = $params['atv_id'];
+ }
+
+ $game_model = new CarGame();
+ //累计积分
+ $data['integral'] = $this->record_model->where($dis)->whereTime('start_time',$params['day'])->sum('integral');
+
+ $dis['day'] = $params['day'];
+ //最快圈速
+ $data['best_result'] = $game_model->where($dis)->min('best_time');
+
+ $data['best_result'] = game_time($data['best_result']);
+ //累计时长
+ $data['total_time'] = $game_model->where($dis)->sum('total_time');
+
+ $data['total_time'] = game_time($data['total_time']);
+ //累计圈数
+ $data['num'] = $game_model->where($dis)->sum('have_num');
+ //用户类型 (1普通 2专业)
+ $data['user_type'] = $game_model->where($dis)->value('major');
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 11:39
+ * @功能说明:我的排队信息
+ */
+
+ public function myLineUp(){
+
+ $params = $this->_param;
+
+ $line_model = new CarLineUp();
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'order_id' => $params['order_id'],
+
+ 'type' => $params['type'],
+
+ 'status' => 0
+ ];
+
+ $data = $line_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('你暂无排队信息');
+ }
+ //排队号码
+ $arr['code'] = $data['code'];
+
+ $where[] = ['uniacid','=',$data['uniacid']];
+
+ $where[] = ['status','=',0];
+
+ $where[] = ['create_time','<',$data['create_time']];
+
+ $where[] = ['id','<>',$data['id']];
+
+ $count = $line_model->where($where)->count();
+ //前面有多少人
+ $arr['count'] = $count;
+
+ $time = $line_model->where($where)->sum('number');
+
+ $time = $time*120;
+ //预计等待时间
+ $arr['time'] = intval($time/60);
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 13:22
+ * @功能说明:签到
+ */
+ public function signUp(){
+
+ $params = $this->_input;
+ //查询是否正在排队
+ $line_model = new CarLineUp();
+
+ $order_model= $params['type']==1?new Order():$this->record_model;
+
+ $order = $order_model->dataInfo(['id'=>$params['order_id']]);
+
+ if($order['pay_type']!=2){
+
+ $this->errorMsg('状态错误');
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理');
+
+ }
+
+ Db::startTrans();
+
+ $update = [
+
+ 'sign_time' => time(),
+
+ 'pay_type' => 3
+ ];
+
+ $res = $order_model->dataUpdate(['id'=>$params['order_id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('签到失败');
+ }
+ //排队号码
+ $code = $line_model->where(['uniacid'=>$this->_uniacid])->max('code');
+
+ $code++;
+ //需要跑的圈数
+ $number = $params['type']==1?$order['order_goods'][0]['circle']*$order['order_goods'][0]['num']:$order['number'];
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $order['user_id'],
+
+ 'code' => $code,
+
+ 'number' => $number,
+
+ 'order_id'=> $order['id'],
+
+ 'type' => $params['type']
+ ];
+
+ $res = $line_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('签到失败');
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 14:11
+ * @功能说明:取消签到
+ */
+ public function cancelSignUp(){
+
+ $params = $this->_input;
+ //查询是否正在排队
+ $line_model = new CarLineUp();
+
+ $dis = [
+
+ 'order_id' => $params['order_id'],
+
+ 'type' => $params['type']
+ ];
+
+ Db::startTrans();
+
+ $line_model->dataUpdate($dis,['status'=>-1]);
+
+ $order_model= $params['type']==1?new Order():$this->record_model;
+
+ $update = [
+
+ 'sign_time' => 0,
+
+ 'pay_type' => 2
+ ];
+
+ $res = $order_model->dataUpdate(['id'=>$params['order_id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->errorMsg('签到失败');
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 09:48
+ * @功能说明:根据手机号获取银豹的会员列表
+ */
+ public function popalMemberByPhone(){
+
+ $input = $this->_param;
+ //先同步到本地
+ $this->model->synMemberList($this->_uniacid);
+
+ $member_model = new SynMember();
+
+ if(empty($input['phone'])){
+
+ $phone = $member_model->where(['user_id'=>$this->getUserId()])->value('phone');
+
+ }else{
+
+ $phone = $input['phone'];
+ }
+
+ $dis['phone'] = $phone;
+
+ $data = $member_model->dataList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['is_select'] = $v['user_id']==$this->getUserId()?1:0;
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 10:13
+ * @功能说明:同步会员
+ */
+ public function bindMember(){
+
+ $input = $this->_input;
+
+ $user = $this->model->dataInfo(['id'=>$this->getUserId()]);
+
+ $res = $this->model->getMemberInfoOne($user,$input['uid']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 11:20
+ * @功能说明:同步会员积分余额
+ */
+ public function synMemberCash(){
+
+ $res = $this->model->synMemberCash($this->_uniacid,$this->getUserId());
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/controller/IndexWxPay.php b/app/massage/controller/IndexWxPay.php
new file mode 100755
index 0000000..313ee1d
--- /dev/null
+++ b/app/massage/controller/IndexWxPay.php
@@ -0,0 +1,181 @@
+app = $app;
+ }
+
+
+ /**
+ * @param $paymentApp
+ * @param $openid
+ * @param $uniacid
+ * @param $body
+ * @param $attach
+ * @param $totalprice
+ * @throws \WxPayException
+ * 支付
+ */
+ public function createWeixinPay($paymentApp , $openid , $uniacid , $body , $attach,$totalprice){
+ global $_GPC, $_W;
+ $setting['mini_appid'] = $paymentApp['app_id'];
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+ define('WX_APPID', $setting['mini_appid']);
+ define('WX_MCHID', $setting['mini_mid']);
+ define('WX_KEY', $setting['mini_apicode']);
+ define('WX_APPSECRET', $setting['mini_appsecrept']);
+ define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+ define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+ define('WX_CURL_PROXY_HOST', '0.0.0.0');
+ define('WX_CURL_PROXY_PORT', 0);
+ define('WX_REPORT_LEVENL', 0);
+
+
+ require_once PAY_PATH . "/weixinpay/lib/WxPay.Api.php";
+ require_once PAY_PATH . "/weixinpay/example/WxPay.JsApiPay.php";
+
+ $tools = new \JsApiPay();
+ $input = new \WxPayUnifiedOrder();
+
+ $input->SetBody($body);
+ $input->SetAttach(json_encode($attach));
+ $input->SetOut_trade_no($attach['out_trade_no']);
+ $input->SetTotal_fee($totalprice *100);
+ $input->SetTime_start(date("YmdHis"));
+
+ $param_arr=[
+ 'i' => $uniacid,
+ 't' => $_GPC['t'],
+ 'v' => $_GPC['v'],
+ 'n' => APP_MODEL_NAME
+ ];
+ $reply_path=json_encode($param_arr);
+ //需要判断 是否是微擎的版本
+ if(defined('IS_WEIQIN')){
+ $path = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?params=".$reply_path;
+ $paths = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?ck=789";
+ $a = file_get_contents($paths);
+ if($a != 1){
+ $this->errorMsg('发起支付失败');
+ }
+ }else{
+ $path = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?params=".$reply_path;
+ $paths = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?ck=789";
+ $a = file_get_contents($paths);
+ if($a != 1){
+ $this->errorMsg('发起支付失败');
+ }
+
+ }
+ $this ->lb_logOutput('BaseApiPath:-----'.$path);
+ $input->SetNotify_url($path);
+ $input->SetTrade_type("JSAPI");
+ $input->SetOpenid($openid);
+ $order = \WxPayApi::unifiedOrder($input);
+ if(!empty($order['return_code'])&&$order['return_code'] == 'FAIL'){
+ $this->errorMsg($order['return_msg']);
+ }
+ $jsApiParameters = $tools->GetJsApiParameters($order);
+
+ $jsApiParameters = json_decode($jsApiParameters, true) ;
+ if (!empty($jsApiParameters['return_code']))
+ $this->errorMsg( '发起支付失败');
+
+ return $jsApiParameters;
+ }
+
+
+
+
+ /**
+ * @param $data
+ * @param int $flag
+ * @return void|null
+ * 打印数据
+ */
+
+ public function lb_logOutput($data,$flag=0) {
+ if($flag==0){
+ return ;
+ }
+ //数据类型检测
+ if (is_array($data)) {
+ $data = json_encode($data);
+ }
+ $filename = "./".date("Y-m-d").".log";
+ $str = date("Y-m-d H:i:s")." $data"."\r\n";
+ file_put_contents($filename, $str, FILE_APPEND|LOCK_EX);
+ return null;
+ }
+
+ /**
+ * 支付回调
+ */
+
+ public function returnPay(){
+
+
+ $this->lb_logOutput("in--mingpianNotify");
+ $xmlData = file_get_contents('php://input');
+ if(empty($xmlData)){
+ $xmlData = 'empty xmlData';
+ }
+ $this->lb_logOutput('xmlData in mingpian:-----'.$xmlData);
+
+ $this->lb_logOutput("in-mingpian2");
+ global $_GPC;
+ $xmlData = file_get_contents('php://input');
+ $this->lb_logOutput('in-mingpian-$xmlData:-----'.$xmlData);
+ //获取配置
+
+ if(defined( 'IS_WEIQIN' )){
+ $uniacid=$_GPC['i'];
+ }else{
+ $uniacid = $_GET['i'];
+ }
+
+ $paymentApp = $this->payConfig($uniacid);
+ // dump($paymentApp);exit;
+ $this->lb_logOutput('in-mingpian-uniacid:-----'.$uniacid);
+
+ $setting['mini_appid'] = $paymentApp['app_id'];
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+
+ define('WX_APPID', $setting['mini_appid']);
+ define('WX_MCHID', $setting['mini_mid']);
+ define('WX_KEY', $setting['mini_apicode']);
+ define('WX_APPSECRET', $setting['mini_appsecrept']);
+ define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+ define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+ define('WX_CURL_PROXY_HOST', '0.0.0.0');
+ define('WX_CURL_PROXY_PORT', 0);
+ define('WX_REPORT_LEVENL', 0);
+ require_once PAY_PATH.'/weixinpay/lib/WxOrderNotify.php';
+ $WxPay = new \WxOrderNotify($this->app);
+ $WxPay->Handle(false);
+ }
+
+
+
+
+
+}
diff --git a/app/massage/controller/Tcp.php b/app/massage/controller/Tcp.php
new file mode 100755
index 0000000..44c298b
--- /dev/null
+++ b/app/massage/controller/Tcp.php
@@ -0,0 +1,275 @@
+model = new Service();
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-29 16:25
+ * @功能说明:远程获取信息
+ */
+ public function getInfo(){
+
+ //获取param
+ $input= $this->request->param();
+
+ if(!empty($input['card_id'])&&!empty($input['time'])){
+
+ $info = \think\facade\Db::name('shequshop_car_atv_speed_test')->where(['card_id'=>$input['card_id']])->find();
+
+ $insert = [
+
+ 'card_id' => $input['card_id'],
+
+ 'time' => date('Y-m-d H:i:s',time()),
+
+ 'uniacid' => 1,
+
+ 'time_str'=> time()
+ ];
+
+ if(empty($info)){
+
+ \think\facade\Db::name('shequshop_car_atv_speed_test')->insert($insert);
+
+ }else{
+
+ \think\facade\Db::name('shequshop_car_atv_speed_test')->where(['id'=>$info['id']])->update($insert);
+ //如果两次信号间隔时间小于30秒 不记录
+ if(time()-$info['time_str']<30){
+
+ echo 2;exit;
+
+ }
+
+ }
+
+ }else{
+
+ echo true;exit;
+
+ }
+
+ $card_id = $input['card_id'];
+
+ $dis = [
+
+ 'now_card_id' => $card_id
+ ];
+
+ $game = \think\facade\Db::name('shequshop_car_game')->where($dis)->find();
+
+ //当前绑卡的比赛
+ if(!empty($game)){
+
+ $dis = [
+
+ 'record_id' => $game['id'],
+
+ 'end_time' => 0
+ ];
+ //查看是开始还是结束
+ $is_start = \think\facade\Db::name('shequshop_car_atv_speed')->where($dis)->find();
+
+ $c_time = time()-$game['last_time'];
+ //如果两个信号接受时间未超过40秒 不记录信息
+ if($c_time<30){
+
+ echo false;exit;
+ }
+ //开始
+ if(empty($is_start)){
+
+ $insert = [
+
+ 'uniacid' => $game['uniacid'],
+
+ 'record_id' => $game['id'],
+
+ 'user_id' => $game['user_id'],
+
+ 'start_time' => $input['time'],
+
+ ];
+
+ \think\facade\Db::name('shequshop_car_atv_speed')->insert($insert);
+
+ }else{
+
+// //如果两个信号接受时间未超过40秒 不记录信息
+// if($c_time<40){
+//
+// echo false;exit;
+// }
+
+ $time = $input['time'] - $is_start['start_time'];
+ //结束
+ $update = [
+
+ 'end_time' => $input['time'],
+
+ 'time' => $time,
+
+ ];
+
+ \think\facade\Db::name('shequshop_car_atv_speed')->where(['id'=>$is_start['id']])->update($update);
+
+ if($time<$game['best_time']||$game['best_time']==0){
+
+ $update_game = [
+
+ 'best_time' => $time
+ ];
+
+ }
+
+ $total_time = $game['total_time']+$time;
+
+ $game['have_num']++;
+
+ $update_game['total_time'] = $total_time;
+
+ $update_game['have_game'] = 1;
+
+ $update_game['status'] = 2;
+
+ $update_game['have_num'] = $game['have_num'];
+ //修改最好成绩
+ \think\facade\Db::name('shequshop_car_game')->where(['id'=>$game['id']])->update($update_game);
+ //第二圈开始
+ $insert = [
+
+ 'uniacid' => $game['uniacid'],
+
+ 'record_id' => $game['id'],
+
+ 'user_id' => $game['user_id'],
+
+ 'start_time' => $input['time'],
+
+ ];
+
+ \think\facade\Db::name('shequshop_car_atv_speed')->insert($insert);
+
+ }
+
+ $update = [
+
+ 'last_time' => intval($input['time']/1000),
+
+ ];
+
+ if(empty($game['start_time'])){
+
+ $update['start_time'] = intval($input['time']/1000);
+
+ $update['day'] = date('Y-m-d',time());
+ }
+ //修改最后接受信息时间
+ \think\facade\Db::name('shequshop_car_game')->where(['id'=>$game['id']])->update($update);
+
+ }
+
+
+ echo true;exit;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-28 14:53
+ * @功能说明:
+ */
+ public function gameList(){
+
+ $dis = [
+
+ 'uniacid' => 1,
+
+ 'have_game' => 1
+
+ ];
+
+ $data = \think\facade\Db::name('shequshop_car_game')->where($dis)->field('best_time,start_time,user_id')->order('start_time desc,best_time')->limit(50)->select()->toArray();
+
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+
+ $v['user_name'] = \think\facade\Db::name('massage_service_user_list')->where(['id'=>$v['user_id']])->value('nickName');
+
+ $v['start_time'] = date('m-d H:i:s',$v['start_time']);
+
+ $v['best_time'] = game_time($v['best_time']);
+
+ }
+
+ }
+
+ $count = count($data);
+
+ View::assign('data', $data);
+
+ View::assign('count', $count);
+
+ return View::fetch();
+
+ echo json_encode($datas);exit;
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/massage/info/AdminMenu.php b/app/massage/info/AdminMenu.php
new file mode 100755
index 0000000..be79591
--- /dev/null
+++ b/app/massage/info/AdminMenu.php
@@ -0,0 +1,596 @@
+ $malls];
+
+
diff --git a/app/massage/info/DiyCompoents.php b/app/massage/info/DiyCompoents.php
new file mode 100755
index 0000000..e308bfd
--- /dev/null
+++ b/app/massage/info/DiyCompoents.php
@@ -0,0 +1,51 @@
+ "业务组件",
+
+ 'type' => 'shopCompoent',
+
+ 'data' =>[
+
+ json_decode($search, true),
+
+ json_decode($goods, true),
+
+ ]
+ ],
+];
\ No newline at end of file
diff --git a/app/massage/info/DiyDefaultCompoents.php b/app/massage/info/DiyDefaultCompoents.php
new file mode 100755
index 0000000..0508625
--- /dev/null
+++ b/app/massage/info/DiyDefaultCompoents.php
@@ -0,0 +1,276 @@
+ 2,
+ "title" => "商城",
+ "type" => "shop",
+ "data" => [
+ [
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/diy/admin/Module/functionPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "功能页面",
+ //小程序路径
+ "page" => "common_page"
+ ],[
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/shop/admin/AdminShopType/cateInfoPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商品分类页面",
+ //小程序路径
+ "page" => "/shop/pages/filter"
+ ],[
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/shop/admin/AdminShopGoods/goodsInfoPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商品详情页面",
+ //小程序路径
+ "page" => "/pages/shop/detail"
+ ],
+ ]
+ ],
+];
\ No newline at end of file
diff --git a/app/massage/info/DiyTabbar.php b/app/massage/info/DiyTabbar.php
new file mode 100755
index 0000000..539d278
--- /dev/null
+++ b/app/massage/info/DiyTabbar.php
@@ -0,0 +1,42 @@
+ 2 ,
+ //是否显示
+ 'is_show' => 1 ,
+ //图标
+ 'iconPath' => 'icon-shangcheng1',
+ //选中图标样式
+ 'selectedIconPath' => 'icon-shangcheng',
+ //那个页面 英文名称
+ 'pageComponents' => 'shopHome',
+ //名称
+ 'name' => '商城',
+ 'url' => '',
+ 'url_jump_way' => '0',
+ 'url_out' => '',
+ 'is_delete' => false ,
+ 'bind_compoents'=>[
+ 'base',
+ 'shopCompoent',
+ 'operate'
+ ],
+
+ 'bind_links' => [
+
+ 'shop'
+ ],
+ 'page'=> []
+ ],
+
+];
\ No newline at end of file
diff --git a/app/massage/info/FunctionPage.php b/app/massage/info/FunctionPage.php
new file mode 100755
index 0000000..8562ec4
--- /dev/null
+++ b/app/massage/info/FunctionPage.php
@@ -0,0 +1,86 @@
+'',
+
+ 'level'=>1,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城页面",
+ //小程序路径
+ "path" => "/pages/user/home?key=2&staff_id="
+ ],[
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城购物车",
+ //小程序路径
+ "path" => "/shop/pages/cart"
+ ],[
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城卡券列表",
+ //小程序路径
+ "path" => "/shop/pages/coupon/receive?staff_id="
+ ],
+
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城全部分类",
+ //小程序路径
+ "path" => "/shop/pages/cate"
+ ],
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城采购模版",
+ //小程序路径
+ "path" => "/shop/pages/purchase/list?staff_id="
+ ],
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城砍价列表页",
+ //小程序路径
+ "path" => "/shop/pages/bargain/list?staff_id="
+ ],
+
+
+
+];
+
+
+return $tmp;
\ No newline at end of file
diff --git a/app/massage/info/Info.php b/app/massage/info/Info.php
new file mode 100755
index 0000000..9b4d89f
--- /dev/null
+++ b/app/massage/info/Info.php
@@ -0,0 +1,32 @@
+ 'massage',
+ //模块标题[必填]
+ 'title' =>'商城',
+ //内容简介
+ 'desc' =>'',
+ //封面图标
+ 'icon' =>'',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => 'model',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'shop.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.82',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module'=> [],
+ // 应用依赖[可选],格式[[插件名, 应用唯一标识, 依赖版本, 对比方式]]
+ 'need_app' => [],
+ //订阅消息
+ 'tmpl_name'=>['pay_order','send_order']
+
+];
\ No newline at end of file
diff --git a/app/massage/info/PermissionShop.php b/app/massage/info/PermissionShop.php
new file mode 100755
index 0000000..f157129
--- /dev/null
+++ b/app/massage/info/PermissionShop.php
@@ -0,0 +1,106 @@
+saasKey = longbing_get_auth_prefix('AUTH_SHOP') ;
+ parent::__construct($uniacid, self::tabbarKey, self::adminMenuKey, $this->saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+ if(!$this->getAuthIsSaasCheck()){
+ return true ;
+ }
+ return $this->sassValue == 1 ? true : false;
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+ if (!$this->sAuth()) {
+ return false;
+ };
+
+ //代理管理端可以控制商城是否展示权限 , 这里需要判断权限
+ $pAuthConfig = $this->getPAuthConfig();
+ //必须平台授权才能使用
+
+ //dump($this->getAuthIsPlatformCheck());exit;
+ if($this->getAuthIsPlatformCheck()){
+ //根据授权而定
+ if ($pAuthConfig ){
+
+// dump($pAuthConfig);exit;
+ return $pAuthConfig['shop_switch'] ? true : false ;
+ }
+ }
+
+ return true;
+
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+
+ return true;
+ }
+
+ /**
+ * 添加商品数量
+ *
+ * @author shuixian
+ * @DataTime: 2019/12/19 19:02
+ */
+ public function getAddGoodsNumber(){
+ return $this->getAuthVaule( longbing_get_auth_prefix('AUTH_GOODS') , 4);
+
+ }
+}
\ No newline at end of file
diff --git a/app/massage/info/RadarMessage.php b/app/massage/info/RadarMessage.php
new file mode 100755
index 0000000..63f6b05
--- /dev/null
+++ b/app/massage/info/RadarMessage.php
@@ -0,0 +1,204 @@
+ "copy",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "咨询",
+ "item"=> "产品",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+ [
+ "sign"=> "view",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商城列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机,主动提供细致的商品讲解将大大有利于成交",
+ "operation"=> "正在查看",
+ "item"=> "商品",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_goods",
+ "field"=> "name",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商品分类列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+ [
+ "sign"=> "view",
+ "type"=> 19,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "订单商品已发货,系统订单号为:",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 20,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "自提商品已提货",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 21,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请等待管理员审核并注意查收",
+ "operation"=> "已申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 22,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "已取消申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 23,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "管理员拒绝退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 24,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请注意查收",
+ "operation"=> "退款成功",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已购买商品",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已参与拼团",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在预约订单中心查看详情",
+ "operation"=> "预约了",
+ "item"=> "服务",
+ "show_count"=> 0,
+ "table_name"=> "lb_appoint_record",
+ "field"=> "name,phone,project_id,start_time,remark",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+
+];
+
+return $radar_msg;
diff --git a/app/massage/info/UpdateSql.php b/app/massage/info/UpdateSql.php
new file mode 100755
index 0000000..c9c9c47
--- /dev/null
+++ b/app/massage/info/UpdateSql.php
@@ -0,0 +1,2144 @@
+顶级规格 其他=>上级规格id',
+ `uniacid` int(10) NOT NULL,
+ `status` int(3) NOT NULL DEFAULT '1',
+ `create_time` int(11) NOT NULL DEFAULT '0',
+ `update_time` int(11) NOT NULL DEFAULT '0',
+ `image` varchar(2000) DEFAULT NULL COMMENT '子规格图片地址',
+ `is_img` tinyint(1) unsigned DEFAULT '0' COMMENT '0.子规格无图 1.子规格有图',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `{$prefix}lbfarm_v2_shop_spe_price` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `goods_id` int(10) NOT NULL,
+ `spe_id_1` varchar(100) NOT NULL DEFAULT '',
+ `spe_id_2` varchar(100) NOT NULL DEFAULT '',
+ `price` decimal(10,2) NOT NULL DEFAULT '0.00',
+ `stock` int(10) NOT NULL DEFAULT '0',
+ `uniacid` int(10) NOT NULL,
+ `status` int(3) NOT NULL DEFAULT '1',
+ `create_time` int(11) NOT NULL DEFAULT '0',
+ `update_time` int(11) NOT NULL DEFAULT '0',
+ `original_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '原价',
+ `cost_price` double(10,2) DEFAULT '0.00' COMMENT '成本价',
+ `lock` int(11) DEFAULT '0',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `{$prefix}lbfarm_v2_signin` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `uniacid` int(11) DEFAULT NULL,
+ `cover` varchar(255) DEFAULT '' COMMENT '背景图',
+ `integral` decimal(10,2) DEFAULT '0.00',
+ `text` varchar(625) DEFAULT '',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `{$prefix}lbfarm_v2_signin_record` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `uniacid` int(11) DEFAULT NULL,
+ `user_id` int(11) DEFAULT NULL,
+ `integral` decimal(10,2) DEFAULT '0.00',
+ `create_time` bigint(11) DEFAULT '0',
+ `create_date` varchar(32) DEFAULT '',
+ `status` tinyint(3) DEFAULT '0',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `{$prefix}lbfarm_v2_system_info` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `uniacid` int(11) DEFAULT NULL,
+ `user_id` int(11) DEFAULT '0',
+ `type` tinyint(3) DEFAULT '1',
+ `obj_id` int(11) DEFAULT '0',
+ `msg` varchar(625) DEFAULT '',
+ `status` tinyint(3) DEFAULT '1',
+ `create_time` bigint(11) DEFAULT '0',
+ `title` varchar(255) DEFAULT '',
+ `order_code` varchar(64) DEFAULT '',
+ `goods_cover` varchar(255) DEFAULT '',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `{$prefix}lbfarm_v2_welfare_column` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `uniacid` int(11) DEFAULT NULL,
+ `title` varchar(64) DEFAULT '',
+ `cover` varchar(255) DEFAULT '',
+ `top` int(11) DEFAULT '0',
+ `status` tinyint(3) DEFAULT '1',
+ `create_time` bigint(11) DEFAULT '0',
+ `content` text,
+ `type` tinyint(3) DEFAULT '1' COMMENT '1公益栏目 2系统公告 3运营公告',
+ `sub_title` varchar(625) DEFAULT '',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CREATE TABLE IF NOT EXISTS `{$prefix}lbfarm_v2_seckill_info` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `uniacid` int(11) DEFAULT '0',
+ `user_id` int(11) DEFAULT '0',
+ `kill_id` int(11) DEFAULT '0',
+ `status` tinyint(3) DEFAULT '1',
+ `goods_id` int(11) DEFAULT '0',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+updateSql;
+
+
+
+
+return $sql;
\ No newline at end of file
diff --git a/app/massage/lang/zh-cn.php b/app/massage/lang/zh-cn.php
new file mode 100755
index 0000000..d94b055
--- /dev/null
+++ b/app/massage/lang/zh-cn.php
@@ -0,0 +1,15 @@
+ '未找到退款订单',
+ 'not find order' => '未找到订单',
+ 'status is error' => '状态错误',
+ 'Too little money' => '体现金额不得小于平台最低提现金额',
+ 'no profit' => '未找到佣金记录',
+ 'Insufficient amount' => '佣金不足',
+ 'no data' => '未找到记录',
+ 'not data' => '未找到记录',
+ 'Only offline package can be cancelled' => '只有线下福包才能核销',
+ 'The coupon has expired'=> '福包已过期',
+ 'not find card' => '名片没有找到',
+ 'no config of pay' => '未配置支付信息',
+];
\ No newline at end of file
diff --git a/app/massage/model/Address.php b/app/massage/model/Address.php
new file mode 100755
index 0000000..1e3964c
--- /dev/null
+++ b/app/massage/model/Address.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Admin.php b/app/massage/model/Admin.php
new file mode 100755
index 0000000..a41f557
--- /dev/null
+++ b/app/massage/model/Admin.php
@@ -0,0 +1,75 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Article.php b/app/massage/model/Article.php
new file mode 100755
index 0000000..ebec0eb
--- /dev/null
+++ b/app/massage/model/Article.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/BalanceCard.php b/app/massage/model/BalanceCard.php
new file mode 100755
index 0000000..21a4677
--- /dev/null
+++ b/app/massage/model/BalanceCard.php
@@ -0,0 +1,93 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/BalanceOrder.php b/app/massage/model/BalanceOrder.php
new file mode 100755
index 0000000..4c09846
--- /dev/null
+++ b/app/massage/model/BalanceOrder.php
@@ -0,0 +1,256 @@
+where(['id'=>$data['user_id']])->value('nickName');
+
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:31
+ * @功能说明:订单支付回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['status']==1){
+
+ $user_model = new User();
+
+ $water_model= new BalanceWater();
+
+ $user = $user_model->dataInfo(['id'=>$order['user_id']]);
+
+ Db::startTrans();
+
+ $update = [
+
+ 'transaction_id' => $transaction_id,
+
+ 'status' => 2,
+
+ 'pay_time' => time(),
+
+ 'now_balance' => $order['true_price']+$user['balance']
+
+ ];
+ //修改订单信息
+ $res = $this->dataUpdate(['id'=>$order['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+
+ $update = [
+
+ 'balance' => $order['true_price']+$user['balance'],
+
+ 'member_level' => $order['member_level'],
+
+ 'vip_time' => $user['vip_time']==0?time():0
+
+ ];
+ //修改用户余额
+ $res = $user_model->dataUpdate(['id'=>$order['user_id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ //添加余额流水
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'price' => $order['true_price'],
+
+ 'order_id'=> $order['id'],
+
+ 'add' => 1,
+
+ 'type' => 1,
+
+ 'before_balance' => $user['balance'],
+
+ 'after_balance' => $order['true_price']+$user['balance'],
+ ];
+
+ $res = $water_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ //给会员权益
+ if(!empty($order['member_level'])){
+
+ $rights_model = new Rights();
+
+ $rights_model->giveRights($order['member_level'],$order['user_id'],$order['id']);
+
+ }
+
+ Db::commit();
+ //向银豹同步会员
+ if(!empty($order['member_level'])){
+
+ $level_model = new Level();
+
+ $api_model = new PospalApi();
+
+ $level = $level_model->levelInfo(['id'=>$order['member_level']]);
+
+ $nickName = $user_model->where(['id'=>$order['user_id']])->value('nickName');
+
+ $insert = [
+
+ 'categoryName' => $level['title'],
+
+ 'discount' => $level['discount'],
+
+ 'number' => time().rand(1,100),
+
+ 'name' => !empty($nickName)?$nickName:$order['phone'],
+
+ 'phone' => $order['phone'],
+
+ ];
+
+ $res = $api_model->addMember($insert);
+
+ if($res['status']!='success'){
+ //修改订单信息
+ $this->dataUpdate(['id'=>$order['id']],['error_msg'=>$res['messages'][0]]);
+ }else{
+
+ $this->dataUpdate(['id'=>$order['id']],['have_syn'=>1]);
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/BalanceWater.php b/app/massage/model/BalanceWater.php
new file mode 100755
index 0000000..3847289
--- /dev/null
+++ b/app/massage/model/BalanceWater.php
@@ -0,0 +1,221 @@
+where(['id'=>$data['order_id']])->value('title');
+ //认养
+ }elseif($data['type']==2){
+
+ $order_model = new ClaimOrder();
+
+ $title = $order_model->where(['id'=>$data['order_id']])->column('goods_name');
+ //养殖
+ }elseif($data['type']==3){
+
+ $shop_order_model = new BreedOrderGoods();
+
+ $title = $shop_order_model->where(['order_id'=>$data['order_id']])->column('goods_name');
+
+ $title = !empty($title)?implode(',',$title):'';
+ //土地
+ }elseif($data['type']==4){
+
+ $shop_order_model = new LandOrder();
+
+ $title = $shop_order_model->where(['id'=>$data['order_id']])->column('massif_title');
+
+ }
+
+ return $title;
+
+ }
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+// if(){
+//
+// }
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function indexList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $add_text = $v['add']==1?'+':'-';
+
+ $buy_text = $v['add']==1?'退款':'消费';
+
+ if($v['type']==1){
+
+ $buy_text = '';
+ }
+
+ $scene_text = $this->sceneText($v['type']);
+
+ $v['text'] = $scene_text.$buy_text.'【'.$v['goods_title'].'】'.$add_text.'¥'.$v['price'].'现余额¥'.$v['after_balance'];
+
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-05 09:56
+ * @功能说明:
+ */
+ public function sceneText($type){
+
+ switch ($type){
+
+ case 1:
+
+ $text = '购买储值卡';
+
+ break;
+ case 2:
+
+ $text = '认养订单';
+
+ break;
+
+ case 3:
+
+ $text = '养殖订单';
+
+ break;
+
+ case 4:
+
+ $text = '土地订单';
+
+ break;
+
+ default:
+
+ $text = '购买储值卡1';
+
+ break;
+
+ }
+
+ return $text;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Banner.php b/app/massage/model/Banner.php
new file mode 100755
index 0000000..9f97f12
--- /dev/null
+++ b/app/massage/model/Banner.php
@@ -0,0 +1,75 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Car.php b/app/massage/model/Car.php
new file mode 100755
index 0000000..3af94f1
--- /dev/null
+++ b/app/massage/model/Car.php
@@ -0,0 +1,153 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 17:21
+ * @功能说明:购物车价格
+ */
+ public function carPriceAndCount($user_id,$is_car=0){
+
+ $list = $this->carList($user_id);
+
+ $data['list'] = $this->carList($user_id,$is_car);
+
+ if(!empty($list)){
+
+ $data['car_price'] = round(array_sum(array_column($list,'all_price')),2);
+
+ $data['total_circle'] = round(array_sum(array_column($list,'total_circle')),2);
+
+ $data['car_count'] = array_sum(array_column($list,'num'));
+
+ $data['total_discount'] = 0;
+
+ $data['coupon_id'] = 0;
+
+ }else{
+
+ $data['car_price'] = 0;
+
+ $data['car_count'] = 0;
+
+ $data['total_discount'] = 0;
+
+ $data['coupon_id'] = 0;
+
+ $data['total_circle'] = 0;
+
+ }
+
+ return $data;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 17:35
+ * @功能说明:购物车列表
+ */
+ public function carList($user_id,$all=0){
+
+ $dis = [
+
+ 'a.user_id' => $user_id,
+
+
+ 'b.status' => 1,
+
+ //'c.cap_id' => $cap_id
+ ];
+
+ if($all==0){
+
+ $dis['a.status'] = 1;
+ }
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_goods b','a.goods_id = b.id')
+ ->where($dis)
+ ->field('a.id,a.goods_id,a.status,a.uniacid,a.num,b.title,b.cover,b.price,ROUND(b.price*a.num,2) as all_price,ROUND(b.price*a.num,2) as true_price,ROUND(b.number*a.num,2) as total_circle,b.number as circle ')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarAtvContent.php b/app/massage/model/CarAtvContent.php
new file mode 100755
index 0000000..262d4a9
--- /dev/null
+++ b/app/massage/model/CarAtvContent.php
@@ -0,0 +1,97 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+// $data = $this->alias('a')
+// ->join('massage_service_user_list b','a.user_id = b.id')
+// ->where($dis)
+// ->where(function ($query) use ($mapor){
+// $query->whereOr($mapor);
+// })
+// ->field('a.*,b.nickName')
+// ->group('a.id')
+// ->order('a.id desc')
+// ->paginate($page)
+// ->toArray();
+
+
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarAtvList.php b/app/massage/model/CarAtvList.php
new file mode 100755
index 0000000..7418cc2
--- /dev/null
+++ b/app/massage/model/CarAtvList.php
@@ -0,0 +1,217 @@
+where(['atv_id'=>$data['id']])->column('content_id');
+
+ return array_values($content);
+ }
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(isset($data['content'])){
+
+ $content = $data['content'];
+
+ unset($data['content']);
+ }
+
+ $res = $this->insert($data);
+
+ if(!empty($content)){
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$content,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-23 18:06
+ * @功能说明:根据活动时间修改活动状态
+ */
+ public function initAtv(){
+
+ $this->where('atv_s_time','>',time())->update(['atv_status'=>1]);
+
+ $this->where('atv_e_time','<',time())->update(['atv_status'=>3]);
+
+ $this->where('atv_s_time','<',time())->where(['atv_status'=>1])->update(['atv_status'=>2]);
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-15 11:22
+ * @功能说明:
+ */
+ public function updateSome($id,$content,$uniacid){
+
+ Db::name('shequshop_car_atv_content_content')->where(['atv_id'=>$id])->delete();
+
+ if(!empty($content)){
+
+ foreach ($content as $value){
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'content_id' => $value,
+
+ 'atv_id' => $id
+ ];
+
+ Db::name('shequshop_car_atv_content_content')->insert($insert);
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-20 10:02
+ * @功能说明:判断报名内容是否在使用
+ */
+ public function atvContentIng($content_id){
+
+ $dis[] = ['a.status','>',-1];
+
+ $dis[] = ['b.content_id','=',$content_id];
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_atv_content_content b','a.id = b.atv_id')
+ ->where($dis)
+ ->find();
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['content'])){
+
+ $content = $data['content'];
+
+ unset($data['content']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($content)){
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($data['id'],$content,$data['uniacid']);
+ }
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+// $data = $this->alias('a')
+// ->join('massage_service_user_list b','a.user_id = b.id')
+// ->where($dis)
+// ->where(function ($query) use ($mapor){
+// $query->whereOr($mapor);
+// })
+// ->field('a.*,b.nickName')
+// ->group('a.id')
+// ->order('a.id desc')
+// ->paginate($page)
+// ->toArray();
+
+
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarAtvRecord.php b/app/massage/model/CarAtvRecord.php
new file mode 100755
index 0000000..af3316b
--- /dev/null
+++ b/app/massage/model/CarAtvRecord.php
@@ -0,0 +1,632 @@
+where(['id'=>$data['hx_user']])->value('nickName');
+
+ return $name;
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 16:21
+ * @功能说明:赛事信息
+ */
+ public function getGameInfoAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $game_model = new CarGame();
+
+ $dis = [
+
+ 'type' => 1,
+
+ 'record_id' => $data['id']
+ ];
+
+ $list = $game_model->dataInfo($dis);
+
+ if(!empty($list)){
+
+ $list['best_time'] = game_time($list['best_time']);
+
+ $list['total_time'] = game_time($list['total_time']);
+
+ }
+
+ return $list;
+
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:转换时间
+ * @author chenniang
+ * @DataTime: 2021-09-26 1 4:11
+ */
+ public function getTimeTextAttr($value,$data){
+
+ if(!empty($data['start_time'])&&!empty($data['end_time'])){
+
+ $time = date('Y.m.d H:i',$data['start_time']).'-'.date('Y.m.d H:i',$data['end_time']);
+
+ return $time;
+ }
+
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-15 14:31
+ * @功能说明:获取活动内容
+ */
+ public function getContentAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $content = Db::name('shequshop_car_atv_record_content')->where(['record_id'=>$data['id']])->select()->toArray();
+
+ return array_values($content);
+ }
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(isset($data['content'])){
+
+ $content = $data['content'];
+
+ unset($data['content']);
+ }
+
+ $res = $this->insert($data);
+
+ if(!empty($content)){
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$content,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-15 11:22
+ * @功能说明:
+ */
+ public function updateSome($id,$content,$uniacid){
+
+ Db::name('shequshop_car_atv_record_content')->where(['record_id'=>$id])->delete();
+
+ if(!empty($content)){
+
+ foreach ($content as $value){
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'content_id' => $value['content_id'],
+
+ 'content_key' => $value['content_key'],
+
+ 'content_value' => $value['content_value'],
+
+ 'content_type' => $value['content_type'],
+
+ 'record_id' => $id
+ ];
+
+ Db::name('shequshop_car_atv_record_content')->insert($insert);
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['content'])){
+
+ $content = $data['content'];
+
+ unset($data['content']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($content)){
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($data['id'],$content,$data['uniacid']);
+ }
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:成绩排行版
+ */
+ public function topRecordList($dis,$page=10,$mapor=[]){
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order('a.result asc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:成绩排行版(可根据时间)
+ */
+ public function timeTopRecordList($dis,$page=10,$time = 1,$mapor=[]){
+
+
+ switch ($time){
+
+ case 1:
+
+ $time_text = 'day';
+
+ break;
+ case 2:
+
+ $time_text = 'week';
+
+ break;
+ case 3:
+
+ $time_text = 'month';
+
+ break;
+ case 4:
+
+ $time_text = 'year';
+
+ break;
+ }
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->join('shequshop_car_game c','a.id = c.record_id')
+ ->where($dis)
+ ->whereTime('a.start_time',$time_text)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.nickName')
+ ->group('a.id')
+ ->order('c.best_time asc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:积分排行榜
+ */
+ public function integralRecordList($dis,$page=10,$mapor=[]){
+
+// $data = $this->alias('a')
+// ->join('massage_service_user_list b','a.user_id = b.id')
+// ->where($dis)
+// ->where(function ($query) use ($mapor){
+// $query->whereOr($mapor);
+// })
+// ->field('a.*,b.nickName,b.avatarUrl')
+// ->group('a.id')
+// ->order('a.integral desc,a.id desc')
+// ->paginate($page)
+// ->toArray();
+
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->join('shequshop_car_game c','a.id = c.record_id','left')
+ ->where($dis)
+ ->where('a.pay_type','>',1)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,c.best_time as best_time,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order(['a.integral desc','a.pay_type desc','c.best_time','a.id desc'])
+ ->paginate($page)
+ ->toArray();
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:记录列表
+ */
+ public function recordList($dis,$page=10,$mapor=[]){
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.nickName')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-19 17:58
+ * @功能说明:获取排名
+ */
+ public function getRecordTop($record){
+
+ $dis = [
+
+ 'a.atv_id' => $record['atv_id']
+ ];
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_game c','a.id = c.record_id')
+ ->where($dis)
+ ->field('a.id')
+ ->group('a.id')
+ ->order(['a.integral desc','a.pay_type desc','c.best_time','a.id desc'])
+ ->select()
+ ->toArray();
+
+ $top = 0;
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ if($v['id']==$record['id']){
+
+ $top = $k+1;
+ }
+ }
+ }
+
+ return $top;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:记录列表
+ */
+ public function atvRecordList($dis,$page=10,$mapor=[],$rank = 2){
+
+ $top = $rank==2?'a.integral':'a.integral desc';
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_atv_list b','a.atv_id = b.id')
+ ->join('shequshop_car_game c','a.id = c.record_id','left')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.title,b.cover,b.atv_num,b.atv_status,c.best_time as best_time,c.major')
+ ->group('a.id')
+ ->order([$top,'a.pay_type desc','c.best_time','a.id desc'])
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 16:44
+ * @功能说明:支付回调
+ */
+ public function dataResult($order_code,$transaction_id){
+
+ $data = $this->dataInfo(['order_code'=>$order_code]);
+
+ if($data['pay_type']==1){
+ //由于时效性问题 报名数量放到回调里面处理
+// $atv_model = new CarAtvList();
+//
+// $atv = $atv_model->dataInfo(['id'=>$data['atv_id']]);
+// //报名已经满了
+// if($atv['atv_num']<=$atv['have_num']){
+//
+// $this
+//
+//
+// //不再执行
+// return true;
+// }
+//
+//
+// $atv_model->where(['id'=>$data['atv_id']])->update(['have_num'=>Db::raw("have_num+1")]);
+
+ $update = [
+
+ 'pay_type' => 2,
+
+ 'pay_time' => time(),
+
+ 'transaction_id' => $transaction_id
+ ];
+
+ $this->dataUpdate(['id'=>$data['id']],$update);
+ //余额扣除
+ if($data['balance']>0){
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$data['user_id']]);
+
+ $balance = $user['balance'] - $data['balance'];
+
+ $user_model->dataUpdate(['id'=>$data['user_id']],['balance'=>$balance]);
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 17:19
+ * @功能说明:取消超时未支付的
+ */
+ public function autoCancelRecord($user_id=0){
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+
+ }else{
+
+ $dis[] = ['over_time','<',time()];
+
+ }
+
+ $dis[] = ['pay_type','=',1];
+
+ $list = $this->where($dis)->select()->toArray();
+
+ if(!empty($list)){
+
+ foreach ($list as $value){
+
+ Db::startTrans();
+
+ $res = $this->cancelRecord($value,1);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+ }
+
+ Db::commit();
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 17:19
+ * @功能说明:取消超时未支付的
+ */
+ public function cancelRecord($record,$auto_refund=0){
+
+ $atv_model = new CarAtvList();
+
+ $update = [
+
+ 'pay_type' => -1,
+
+ 'refund_time' => time(),
+
+ 'auto_refund' => $auto_refund,
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$record['id']],$update);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'取消失败1'];
+ }
+
+ $atv = $atv_model->dataInfo(['id'=>$record['atv_id']]);
+
+ $res = $atv_model->dataUpdate(['id'=>$record['atv_id']],['have_num'=>$atv['have_num']-1]);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'取消失败'];
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 15:06
+ * @功能说明:积分到账
+ */
+ public function pointSuccess($uniacid){
+
+ $dis = [
+
+ 'pay_type' => 7,
+
+ 'have_tx' => 0,
+
+ 'uniacid' => $uniacid
+
+ ];
+
+ $order = $this->where($dis)->field('id,integral,user_id,uniacid')->select()->toArray();
+
+ if(!empty($order)){
+
+ $integral_model = new \app\member\model\Integral();
+
+ foreach ($order as $value){
+
+ //修改订单状态
+ $res = $this->where(['id'=>$value['id'],'have_tx'=>0])->update(['have_tx'=>1]);
+ //增加用户积分
+ if($res==1){
+
+ $integral_model->integralUserAdd($value['user_id'],$value['integral'],$value['uniacid'],2,8,$value['id']);
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarDriver.php b/app/massage/model/CarDriver.php
new file mode 100755
index 0000000..a3d6f08
--- /dev/null
+++ b/app/massage/model/CarDriver.php
@@ -0,0 +1,95 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$mapor=[]){
+
+// $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.nickName,avatarUrl')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarGame.php b/app/massage/model/CarGame.php
new file mode 100755
index 0000000..2244d73
--- /dev/null
+++ b/app/massage/model/CarGame.php
@@ -0,0 +1,209 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:成绩排行版
+ */
+ public function topRecordList($dis,$page=10,$mapor=[]){
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order('a.best_time asc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-16 13:57
+ * @功能说明:成绩排行版(可根据时间)
+ */
+ public function timeTopRecordList($dis,$page=10,$time = 1,$mapor=[]){
+
+ switch ($time){
+
+ case 1:
+
+ $time_text = 'today';
+
+ break;
+ case 2:
+
+ $time_text = 'week';
+
+ break;
+ case 3:
+
+ $time_text = 'month';
+
+ break;
+ case 4:
+
+ $time_text = 'year';
+
+ break;
+ }
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->where($dis)
+ ->whereTime('a.start_time',$time_text)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order('a.best_time asc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarLineUp.php b/app/massage/model/CarLineUp.php
new file mode 100755
index 0000000..7043704
--- /dev/null
+++ b/app/massage/model/CarLineUp.php
@@ -0,0 +1,83 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarPrice.php b/app/massage/model/CarPrice.php
new file mode 100755
index 0000000..6b4ce3b
--- /dev/null
+++ b/app/massage/model/CarPrice.php
@@ -0,0 +1,83 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarRecordContent.php b/app/massage/model/CarRecordContent.php
new file mode 100755
index 0000000..ca94ddf
--- /dev/null
+++ b/app/massage/model/CarRecordContent.php
@@ -0,0 +1,97 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+// $data = $this->alias('a')
+// ->join('massage_service_user_list b','a.user_id = b.id')
+// ->where($dis)
+// ->where(function ($query) use ($mapor){
+// $query->whereOr($mapor);
+// })
+// ->field('a.*,b.nickName')
+// ->group('a.id')
+// ->order('a.id desc')
+// ->paginate($page)
+// ->toArray();
+
+
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarTrophy.php b/app/massage/model/CarTrophy.php
new file mode 100755
index 0000000..048df28
--- /dev/null
+++ b/app/massage/model/CarTrophy.php
@@ -0,0 +1,81 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarType.php b/app/massage/model/CarType.php
new file mode 100755
index 0000000..a39d412
--- /dev/null
+++ b/app/massage/model/CarType.php
@@ -0,0 +1,125 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $user
+ * @功能说明:判断类型 专业还是普通
+ * @author chenniang
+ * @DataTime: 2021-09-28 16:55
+ */
+ public function getType($id,$user_id){
+
+ $data = $this->dataInfo(['id'=>$id]);
+ //如果动过数据库 一律判断为普通
+ if(empty($data)){
+
+ return 1;
+ }
+ //如果即选过 专业和普通 就判断用户当前身份
+ if(!empty($data['major'])&&!empty($data['norm'])){
+
+ $driver_model = new CarDriver();
+
+ $user = $driver_model->dataInfo(['user_id'=>$user_id,'status'=>2]);
+
+ if(!empty($user)){
+
+ return 2;
+
+ }else{
+
+ return 1;
+ }
+
+ }else{
+ //就根据车型身份勾选来
+
+ $res = !empty($data['major'])?2:1;
+
+ return $res;
+
+ }
+
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarTypeConnect.php b/app/massage/model/CarTypeConnect.php
new file mode 100755
index 0000000..41c1121
--- /dev/null
+++ b/app/massage/model/CarTypeConnect.php
@@ -0,0 +1,81 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CarUserTrophy.php b/app/massage/model/CarUserTrophy.php
new file mode 100755
index 0000000..d43cf33
--- /dev/null
+++ b/app/massage/model/CarUserTrophy.php
@@ -0,0 +1,108 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-26 16:10
+ * @功能说明:用户荣誉杯
+ */
+ public function userTrophy($user_id){
+
+ //查看荣誉杯
+ $dis = [
+
+ 'a.user_id' => $user_id,
+
+ 'a.status' => 1,
+
+ 'b.status' => 1,
+ ];
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_trophy b','a.trophy_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title,b.cover')
+ ->select()
+ ->toArray();
+
+
+ return $data;
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Comment.php b/app/massage/model/Comment.php
new file mode 100755
index 0000000..9089985
--- /dev/null
+++ b/app/massage/model/Comment.php
@@ -0,0 +1,287 @@
+ $data['order_id']
+ ];
+
+ $list = $order_goods_model->where($dis)->select()->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-05 23:32
+ * @功能说明:标签列表
+ */
+ public function getLableTextAttr($vaule,$data){
+
+ if(!empty($data['id'])){
+
+ $lable_model = new Lable();
+
+ $dis = [
+
+ 'b.comment_id' => $data['id'],
+
+ 'a.status' => 1
+
+ ];
+ $list = $lable_model->alias('a')
+ ->join('massage_service_comment_lable b','a.id = b.lable_id')
+ ->where($dis)
+ ->column('a.title');
+
+ return array_values($list);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_order_list b','a.order_id = b.id')
+ ->join('massage_service_order_goods_list c','a.order_id = c.order_id')
+ ->join('massage_service_coach_list d','b.coach_id = d.id')
+ ->join('massage_service_user_list e','a.user_id = e.id')
+ ->where($dis)
+ ->field('a.*,e.nickName,e.avatarUrl,c.goods_name,c.goods_cover,c.num,c.price,d.coach_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 09:51
+ * @功能说明:公众号楼长端新订单通知
+ */
+ public function sendMsg($order){
+
+ $cap_model = new Cap();
+
+ $cap_id = $order['cap_id'];
+
+ $uniacid = $order['uniacid'];
+ //获取楼长openid
+ $openid = $cap_model->capOpenid($cap_id);
+
+ $store_name = $cap_model->where(['id'=>$cap_id])->value('store_name');
+
+ $access_token = longbingGetAccessToken($uniacid);
+
+ $config = $this->dataInfo(['uniacid'=>$uniacid]);
+
+ $page = "master/pages/order/list";
+ //post地址
+ $url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token={$access_token}";
+
+ $x_config = longbingGetAppConfig($uniacid);
+
+ $goods_data = '';
+
+ $num = count($order['order_goods'])-1;
+
+ foreach ($order['order_goods'] as $k=>$v){
+
+ $icon = $k==$num?'':',';
+
+ $goods_data .= $v['goods_name'].'x'.$v['goods_num'].$icon;
+ }
+
+ $order_text = !empty($order['text'])?','.$order['text']:'';
+
+ $address_data = $order['address_info'];
+
+ $data = [
+ //用户小程序openid
+ 'touser' => $openid,
+
+ 'mp_template_msg' => [
+ //公众号appid
+ 'appid' => $config['app_id'],
+
+ "url" => "http://weixin.qq.com/download",
+ //公众号模版id
+ 'template_id' => $config['tmp_id'],
+
+ 'miniprogram' => [
+ //小程序appid
+ 'appid' => $x_config['appid'],
+ //跳转小程序地址
+ 'page' => $page,
+ ],
+ 'data' => array(
+
+ 'first' => array(
+
+ 'value' => $store_name.'商家,您有一笔新订单',
+
+ 'color' => '#93c47d',
+ ),
+
+ 'keyword1' => array(
+
+ 'value' => $order['order_code'],
+
+ 'color' => '#93c47d',
+ ),
+ 'keyword2' => array(
+ //内容
+ 'value' => $goods_data.$order_text,
+
+ 'color' => '#0000ff',
+ ),
+ 'keyword3' => array(
+ //内容
+ 'value' => $order['pay_price'].'元',
+
+ 'color' => '#0000ff',
+ ),
+ 'keyword4' => array(
+ //内容
+ 'value' => '送货上门',
+
+ 'color' => '#0000ff',
+ ),
+ 'keyword5' => array(
+
+ 'value' => $address_data['user_name'].','.$address_data['mobile'].','.$address_data['address'].$address_data['address_info'],
+
+ 'color' => '#45818e',
+ ),
+ 'remark' => array(
+ //内容
+ 'value' => $order['order_text'],
+
+ 'color' => '#0000ff',
+ ),
+ )
+ ],
+ ];
+
+
+ $data = json_encode($data);
+
+ $tmp = [
+
+ 'url' => $url,
+
+ 'data' => $data,
+ ];
+ $rest = lbCurlPost($tmp['url'], $tmp['data']);
+
+ $rest = json_decode($rest, true);
+
+ return $rest;
+
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CommentLable.php b/app/massage/model/CommentLable.php
new file mode 100755
index 0000000..5629ee0
--- /dev/null
+++ b/app/massage/model/CommentLable.php
@@ -0,0 +1,88 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Commission.php b/app/massage/model/Commission.php
new file mode 100755
index 0000000..3361b2d
--- /dev/null
+++ b/app/massage/model/Commission.php
@@ -0,0 +1,354 @@
+goodsList(['a.commission_id'=>$data['id']]);
+
+ return $list;
+
+ }
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-25 23:24
+ * @功能说明:记录
+ */
+ public function recordList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.user_id = b.id')
+ ->join('massage_service_user_list c','a.top_id = c.id')
+ ->join('massage_service_order_list d','a.order_id = d.id')
+ ->where($dis)
+ ->field('a.*,b.nickName,c.nickName as top_name,d.order_code,d.pay_type,d.pay_price,d.transaction_id')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-25 23:34
+ * @功能说明:佣金到账
+ */
+ public function successCash($order_id){
+
+ $data = $this->dataInfo(['order_id'=>$order_id]);
+
+ if(!empty($data)&&$data['status']==1){
+
+ $res = $this->dataUpdate(['id'=>$data['id']],['status'=>2]);
+
+ if($res==0){
+
+ return $res;
+ }
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$data['top_id']]);
+
+ $res = $user_model->where(['id'=>$data['top_id'],'balance'=>$user['balance']])->update(['balance'=>$user['balance']+$data['cash'],'cash'=>$user['cash']+$data['cash']]);
+
+ if($res==0){
+
+ return $res;
+ }
+
+ }
+
+ return 1;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-26 23:39
+ * @功能说明:添加佣金
+ */
+ public function commissionAdd($order){
+
+ $user_model = new User();
+ //上级
+ $top = $user_model->where(['id'=>$order['user_id']])->value('pid');
+
+ if(!empty($top)){
+
+ $ser_model = new Service();
+
+ $com_mdoel = new Commission();
+
+ $com_goods_mdoel = new CommissionGoods();
+
+ foreach ($order['order_goods'] as $v){
+ //查看是否有分销
+ $ser = $ser_model->dataInfo(['id'=>$v['goods_id']]);
+
+ if(!empty($ser['com_balance'])){
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'top_id' => $top,
+
+ 'order_id'=> $order['id'],
+
+ 'order_code' => $order['order_code'],
+
+ ];
+
+ $find = $com_mdoel->dataInfo($insert);
+
+ $cash = $v['true_price']*$ser['com_balance']/100*$v['num'];
+
+ if(empty($find)){
+
+ $insert['cash'] = $cash;
+
+ $com_mdoel->dataAdd($insert);
+
+ $id = $com_mdoel->getLastInsID();
+
+ }else{
+
+ $id = $find['id'];
+
+ $update = [
+
+ 'cash' => $find['cash']+$cash
+ ];
+ //加佣金
+ $com_mdoel->dataUpdate(['id'=>$find['id']],$update);
+
+ }
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'order_goods_id' => $v['id'],
+
+ 'commission_id' => $id,
+
+ 'cash' => $cash,
+
+ 'num' => $v['num'],
+
+ 'balance' => $ser['com_balance']
+ ];
+ //添加到自订单记录表
+ $res = $com_goods_mdoel->dataAdd($insert);
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-28 14:35
+ * @功能说明:佣金到账
+ */
+ public function successCommission($order_id){
+
+ $comm = $this->dataInfo(['order_id'=>$order_id,'status'=>1]);
+
+ if(!empty($comm)){
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$comm['top_id']]);
+
+ if(!empty($user)){
+
+ $update = [
+
+ 'balance' => $user['balance']+$comm['cash'],
+
+ 'cash' => $user['cash']+$comm['cash'],
+ ];
+
+ $user_model->dataUpdate(['id'=>$comm['top_id']],$update);
+
+ $this->dataUpdate(['id'=>$comm['id']],['status'=>2,'cash_time'=>time()]);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-28 14:48
+ * @功能说明:退款的时候要减去分销
+ */
+ public function refundComm($refund_id){
+
+ $refund_model = new RefundOrder();
+
+ $com_goods_mdoel = new CommissionGoods();
+
+ $refund_order = $refund_model->dataInfo(['id'=>$refund_id]);
+
+ if(!empty($refund_order)){
+ //查询这笔等待有无佣金
+ $comm = $this->dataInfo(['order_id'=>$refund_order['order_id'],'status'=>1]);
+
+ if(!empty($comm)){
+
+ foreach ($refund_order['order_goods'] as $v){
+
+ $comm_goods = $com_goods_mdoel->dataInfo(['commission_id'=>$comm['id'],'order_goods_id'=>$v['order_goods_id']]);
+
+ $comm_goods_cash = $comm_goods['cash']/$comm_goods['num'];
+
+ $true_num = $comm_goods['num'] - $v['num'];
+
+ $true_num = $true_num>0?$true_num:0;
+
+ $update = [
+
+ 'num' => $true_num,
+
+ 'cash'=> $comm_goods_cash*$true_num
+ ];
+
+ $com_goods_mdoel->dataUpdate(['id'=>$comm_goods['id']],$update);
+
+
+ }
+
+ $total_cash = $com_goods_mdoel->where(['commission_id'=>$comm['id']])->sum('cash');
+
+ $update = [
+
+ 'cash' => $total_cash,
+
+ 'status' => $total_cash>0?1:-1
+ ];
+
+ $this->dataUpdate(['id'=>$comm['id']],$update);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CommissionGoods.php b/app/massage/model/CommissionGoods.php
new file mode 100755
index 0000000..a217951
--- /dev/null
+++ b/app/massage/model/CommissionGoods.php
@@ -0,0 +1,99 @@
+alias('a')
+ ->join('massage_service_order_goods_list b','a.order_goods_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.goods_name,b.goods_cover,b.true_price')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Config.php b/app/massage/model/Config.php
new file mode 100755
index 0000000..b726504
--- /dev/null
+++ b/app/massage/model/Config.php
@@ -0,0 +1,84 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Coupon.php b/app/massage/model/Coupon.php
new file mode 100755
index 0000000..224dda3
--- /dev/null
+++ b/app/massage/model/Coupon.php
@@ -0,0 +1,628 @@
+where(['coupon_id'=>$data['id']])->sum('num');
+
+ return $count;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 01:54
+ * @功能说明:
+ */
+ public function getServiceAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $ser_model = new Goods();
+
+ $dis = [
+
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $data['id'],
+
+ 'b.type' => 0,
+
+ 'b.scene' => 1
+ ];
+
+ $list = $ser_model->alias('a')
+ ->join('massage_service_coupon_goods b','b.goods_id = a.id')
+ ->where($dis)
+ ->field('a.id,a.title,a.price,b.goods_id,a.cover')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 01:54
+ * @功能说明:
+ */
+ public function getShopGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $ser_model = new \app\shop\model\Goods();
+
+ $dis = [
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $data['id'],
+
+ 'b.type' => 0,
+
+ 'b.scene' => 2
+
+ ];
+
+ $list = $ser_model->alias('a')
+ ->join('massage_service_coupon_goods b','b.goods_id = a.id')
+ ->where($dis)
+ ->field('a.id,a.name,b.goods_id,a.cover')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 01:54
+ * @功能说明:
+ */
+ public function getRestaurantGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $ser_model = new \app\restaurant\model\Goods();
+
+ $dis = [
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $data['id'],
+
+ 'b.type' => 0,
+
+ 'b.scene' => 3
+
+ ];
+
+ $list = $ser_model->alias('a')
+ ->join('massage_service_coupon_goods b','b.goods_id = a.id')
+ ->where($dis)
+ ->field('a.id,a.title,b.goods_id,a.cover')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 01:54
+ * @功能说明:
+ */
+ public function getMemberLevelAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $level_model = new Level();
+
+ $dis = [
+
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $data['id'],
+ ];
+
+ $list = $level_model->alias('a')
+ ->join('longbing_card_v2_coupon_connect b','b.member_level = a.id')
+ ->where($dis)
+ ->field('a.id,a.title')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->column('a.id');
+
+ return array_values($list);
+
+ }
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $data_data = $data;
+
+ if(isset($data['service'])){
+
+ unset($data['service']);
+ }
+
+ if(isset($data['member_level'])){
+
+ unset($data['member_level']);
+ }
+
+ if(isset($data['shop_goods'])){
+
+ unset($data['shop_goods']);
+ }
+
+ if(isset($data['restaurant_goods'])){
+
+ unset($data['restaurant_goods']);
+ }
+
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$data_data);
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $data_data = $data;
+
+ if(isset($data['service'])){
+
+ unset($data['service']);
+ }
+
+ if(isset($data['member_level'])){
+
+ unset($data['member_level']);
+ }
+
+ if(isset($data['shop_goods'])){
+
+ unset($data['shop_goods']);
+ }
+
+ if(isset($data['restaurant_goods'])){
+
+ unset($data['restaurant_goods']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ $this->updateSome($dis['id'],$data_data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-11-01 15:40
+ */
+ public function updateSome($id,$data){
+
+ $server = new \app\shop\server\Coupon();
+
+ $s_model = new CouponService();
+
+ $coupon_member_model = new CouponMember();
+
+ $goods_model = new \app\shop\model\Goods();
+
+ $r_goods_model = new \app\restaurant\model\Goods();
+
+ $coupon_member_model->where(['coupon_id'=>$id])->delete();
+
+ $s_model->where(['coupon_id'=>$id])->delete();
+ //赛车服务
+ $server->addObserver($s_model);
+ //会员
+ $server->addObserver($coupon_member_model);
+ //商城商品
+ $server->addObserver($goods_model);
+ //
+ $server->addObserver($r_goods_model);
+
+ $res = $server->notify($id,$data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @param $id
+ * @param $uniacid
+ * @param $spe
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 13:35
+ */
+ public function updateSomev2($id,$uniacid,$goods,$member_level,$shop_goods){
+
+ $s_model = new CouponService();
+
+ $coupon_member_model = new CouponMember();
+
+ $s_model->where(['coupon_id'=>$id])->delete();
+
+ if(!empty($goods)){
+
+ foreach ($goods as $value){
+
+ $insert['uniacid'] = $uniacid;
+
+ $insert['coupon_id'] = $id;
+
+ $insert['goods_id'] = $value;
+
+ $s_model->dataAdd($insert);
+
+ }
+
+ }
+
+ if(!empty($shop_goods)){
+
+ foreach ($shop_goods as $value){
+
+ $insert['uniacid'] = $uniacid;
+
+ $insert['coupon_id'] = $id;
+
+ $insert['goods_id'] = $value;
+
+ $insert['scene'] = 2;
+
+ $s_model->dataAdd($insert);
+
+ }
+
+ }
+
+ $coupon_member_model->where(['coupon_id'=>$id])->delete();
+
+ if(!empty($member_level)){
+
+ foreach ($member_level as &$value){
+
+ $inserts['uniacid'] = $uniacid;
+
+ $inserts['coupon_id'] = $id;
+
+ $inserts['member_level'] = $value;
+
+ $coupon_member_model->dataAdd($inserts);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis,$filed='*'){
+
+ $data = $this->where($dis)->field($filed)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-09 23:22
+ * @功能说明:计算优惠券可以优惠多少钱
+ */
+
+ public function getDicountPrice($order_goods,$coupon_id,$scene=1){
+
+// $coupon_se_model = new CouponService();
+ //暂时没有商品限制 先注释
+// $goods_id = $coupon_se_model->where(['coupon_id'=>$coupon_id,'type'=>1,'scene'=>$scene])->column('goods_id');
+
+ $price = 0;
+
+ foreach ($order_goods as $v){
+
+ foreach ($v as $vs){
+
+// if(in_array($vs['goods_list'],$goods_id)){
+
+ $price += $v['true_price'];
+ //暂时没有商品限制
+ $goods_id[] = $vs['goods_id'];
+// }
+
+ }
+ }
+
+ $data['discount'] = $price;
+
+ $data['goods_id'] = $goods_id;
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-09 23:37
+ * @功能说明:订单优惠券
+ */
+ public function orderCouponData($order_goods,$coupon_id,$scene=1){
+
+ if(empty($coupon_id)){
+
+ return $order_goods;
+ }
+
+ $coupon_record_model = new CouponRecord();
+
+ $info = $coupon_record_model->dataInfo(['id'=>$coupon_id]);
+ //是否被使用或者过期
+ if(empty($info)||$info['status']!=1){
+
+ return $order_goods;
+ }
+
+ if($info['start_time']time()){
+
+ $p_coupon_id = !empty($info['pid'])?$info['pid']:$coupon_id;
+
+ $can_discount_price = $this->getDicountPrice($order_goods['list'],$p_coupon_id,$scene);
+ //是否满足满减条件
+ if($info['full']>$can_discount_price['discount']||$can_discount_price['discount']==0){
+
+ return $order_goods;
+ }
+
+ $total_discount = 0;
+
+ foreach ($order_goods['list'] as $vs){
+
+ foreach ($vs as &$v){
+ //如果该商品可以使用优惠券
+ if(in_array($v['goods_id'],$can_discount_price['goods_id'])){
+
+ $bin = $v['true_price']/$can_discount_price['discount'];
+ //该商品减去的折扣
+ $discount = $bin*$info['discount']<$v['true_price']?$bin*$info['discount']:$v['true_price'];
+ //总计折扣
+ $total_discount+=$discount;
+
+ $v['true_price'] = round($v['true_price']-$discount,2);
+
+ }
+
+ }
+
+ }
+
+ $total_discount = $info['full']>$info['discount']?$info['discount']:round($total_discount,2);
+
+ $order_goods['total_discount'] = round($total_discount,2);
+
+ $order_goods['coupon_id'] = $coupon_id;
+
+ }
+
+ return $order_goods;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 11:58
+ * @功能说明:用户可用的优惠券
+ */
+ public function canUseCoupon($user_id,$type=1,$is_show=1,$no_i=1,$table_id=0){
+
+ $coupon_model = new CouponRecord();
+
+ $coupon_model->where(['user_id'=>$user_id,'status'=>1])->where('end_time','<',time())->update(['status'=>3]);
+
+ $list = $coupon_model->where(['user_id'=>$user_id,'status'=>1])->order('id desc')->select()->toArray();
+
+ if($type==1){
+
+ $car_model = new Car();
+ //获取购物车里面的信息
+ $car_list = $car_model->carPriceAndCount($user_id,1);
+
+ }else{
+
+ if($type==2){
+
+ $car_model = new \app\shop\model\Car();
+ //获取购物车里面的信息
+ $car_list = $car_model->carPriceAndCount($user_id,1,1,$is_show,$no_i);
+ }else{
+
+ $car_model = new \app\restaurant\model\Car();
+
+ $car_list = $car_model->carPriceAndCount($user_id,2,$table_id);
+
+ }
+
+ }
+
+ $car_list = $car_list['list'];
+
+ $data = [];
+
+ if(!empty($list)){
+
+ foreach ($list as &$v){
+
+ if($v['start_time']time()){
+
+ $id = !empty($v['pid'])?$v['pid']:$v['id'];
+
+ $info = $this->getDicountPrice($car_list,$id,$type);
+
+ if($v['full']<=$info['discount']&&$info['discount']>0){
+
+ $data[] = $v['id'];
+
+ }
+ }
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-28 10:50
+ * @功能说明:商城用户可以领取的优惠券
+ */
+ public function shopCanGetCoupon($uniacid,$user_id,$page=10){
+
+ $record_model = new CouponRecord();
+
+ $id = $record_model->where(['user_id'=>$user_id])->column('coupon_id');
+
+ $dis = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ 'send_type'=> 2
+
+ ];
+
+ $where[] = ['time_limit','=',1];
+
+ $where[] = ['end_time','>',time()];
+
+
+ $data = $this->where($dis)->where('id','not in',$id)->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponAtv.php b/app/massage/model/CouponAtv.php
new file mode 100755
index 0000000..ec4b8b1
--- /dev/null
+++ b/app/massage/model/CouponAtv.php
@@ -0,0 +1,356 @@
+ 1,
+
+ 'b.atv_id' => $data['id']
+ ];
+
+ $list = $coupom_model->alias('a')
+ ->join('massage_service_coupon_atv_coupon b','b.coupon_id = a.id')
+ ->where($dis)
+ ->field('a.*,b.num,b.coupon_id')
+ ->group('b.coupon_id')
+ ->order('a.top desc,id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+
+ $service = $data['coupon'];
+
+ unset($data['coupon']);
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$data['uniacid'],$service);
+
+ return $id;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+
+// $data['update_time'] = time();
+
+ if(isset($data['coupon'])){
+
+ $service = $data['coupon'];
+
+ unset($data['coupon']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($service)){
+
+ $id = $this->where($dis)->value('id');
+
+ $this->updateSome($id,$data['uniacid'],$service);
+ }
+
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $uniacid
+ * @param $spe
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 13:35
+ */
+ public function updateSome($id,$uniacid,$coupon){
+
+ $s_model = new CouponAtvCoupon();
+
+ $s_model->where(['atv_id'=>$id])->delete();
+
+ if(!empty($coupon)){
+
+ foreach ($coupon as $value){
+
+ $insert['uniacid'] = $uniacid;
+
+ $insert['atv_id'] = $id;
+
+ $insert['coupon_id'] = $value['id'];
+
+ $insert['num'] = $value['num'];
+
+ $s_model->dataAdd($insert);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->insert($dis);
+
+ $data = $this->where($dis)->find();
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 17:52
+ * @功能说明:优惠券活动邀请新用户
+ */
+ public function invUser($user_id,$record_id){
+
+ $atv_record_model = new CouponAtvRecord();
+
+ $atv_record_list_model = new CouponAtvRecordList();
+
+ $record = $atv_record_model->dataInfo(['id'=>$record_id]);
+
+ Db::startTrans();
+
+ if(!empty($record)&&$record['end_time']>time()&&$record['status']==1){
+
+ $insert = [
+
+ 'uniacid' => $record['uniacid'],
+
+ 'user_id' => $record['user_id'],
+
+ 'to_inv_id'=> $user_id,
+
+ 'record_id'=> $record_id
+
+ ];
+ //添加邀请者记录
+ $res = $atv_record_list_model->dataAdd($insert);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'登陆失败,请刷新重试'];
+ }
+ //新用户获得卡券
+ if($record['to_inv_user']==1&&!empty($record['coupon'])){
+
+ $res = $this->giveAtvCoupon($record_id,$user_id);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+ }
+
+ }
+ //检查任务是否完成
+ $res = $this->recordSuccess($record_id);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+ }
+
+ }
+
+ Db::commit();
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 00:07
+ * @功能说明:给用户获得卡券
+ */
+ public function giveAtvCoupon($record_id,$user_id){
+
+ $atv_record_model = new CouponAtvRecord();
+
+ $record_model = new CouponRecord();
+
+ $atv_record_coupon_model = new CouponAtvRecordCoupon();
+
+ $record = $atv_record_model->dataInfo(['id'=>$record_id]);
+
+ foreach ($record['coupon'] as $value){
+ //派发卡券
+// $num = $value['stock']>=$value['num']?$value['num']:$value['stock'];
+
+ $num = $value['num'];
+
+ if($num>0){
+
+ $res = $record_model->recordAdd($value['coupon_id'],$user_id,$num);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'登陆失败,请刷新重试'];
+ }
+ //添加派发记录
+ $insert = [
+
+ 'uniacid' => $record['uniacid'],
+
+ 'user_id' => $user_id,
+
+ 'atv_id' => $record['atv_id'],
+
+ 'coupon_id' => $value['coupon_id'],
+
+ 'num' => $value['num'],
+
+ 'status' => 2,
+
+ 'success_num' => $num
+
+ ];
+
+ $res = $atv_record_coupon_model->dataAdd($insert);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'登陆失败,请刷新重试'];
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 23:46
+ * @功能说明:获得成功
+ */
+ public function recordSuccess($record_id){
+
+ $atv_record_list_model = new CouponAtvRecordList();
+
+ $atv_record_model = new CouponAtvRecord();
+ //已经邀请多少人了
+ $have_num = $atv_record_list_model->where(['record_id'=>$record_id])->count();
+
+ $record = $atv_record_model->dataInfo(['id'=>$record_id]);
+ //如果成功
+ if($have_num>=$record['inv_user_num']){
+ //修改获得状态
+ $res = $atv_record_model->dataUpdate(['id'=>$record['id'],'status'=>1],['status'=>2]);
+
+ if($res==0){
+
+ return ['code'=>500,'msg'=>'登陆失败,请刷新重试'];
+ }
+
+ if($record['inv_user']==1){
+ //给发起者派送卡券
+ $res = $this->giveAtvCoupon($record_id,$record['user_id']);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponAtvCoupon.php b/app/massage/model/CouponAtvCoupon.php
new file mode 100755
index 0000000..ec68096
--- /dev/null
+++ b/app/massage/model/CouponAtvCoupon.php
@@ -0,0 +1,216 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:审核中
+ */
+ public function shIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 15:23
+ * @功能说明:通过
+ */
+ public function subSh($id,$goods_id){
+
+ $goods_list_model = new GoodsShList();
+
+ $goods_model = new Goods();
+
+ $list = $goods_model->where('id','in',$goods_id)->select()->toArray();
+
+ Db::startTrans();
+
+ foreach ($list as $value){
+
+ $insert = [
+
+ 'uniacid' => $value['uniacid'],
+
+ 'sh_id' => $id,
+
+ 'goods_id' => $value['id'],
+
+ 'goods_name' => $value['goods_name'],
+
+ 'cover' => $value['cover'],
+
+ 'imgs' => !empty($value['imgs'])?implode(',',$value['imgs']):'',
+
+ 'text' => $value['text'],
+
+ 'cate_id' => $value['cate_id'],
+
+ ];
+ //添加到审核商品表
+ $res = $goods_list_model->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+
+ $goods_sh_id = $goods_list_model->getLastInsID();
+
+ if(!empty($value['spe'])){
+
+ foreach ($value['spe'] as $v){
+
+ $insert = [
+
+ 'uniacid' => $v['uniacid'],
+
+ 'sh_goods_id' => $goods_sh_id,
+
+ 'title' => $v['title'],
+
+ 'stock' => $v['stock'],
+
+ 'price' => $v['price'],
+
+ 'spe_id' => $v['id'],
+
+ ];
+ //添加审核规格表
+ $res = Db::name('shequshop_school_goods_sh_spe')->insert($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+
+ }
+
+ }
+
+ }
+ //将商品状态改为审核中
+ $goods_model->where('id','in',$goods_id)->update(['status'=>4]);
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 00:02
+ * @功能说明:用户订单数
+ */
+ public function couponCount($user_id){
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->where($dis)->count();
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponAtvRecord.php b/app/massage/model/CouponAtvRecord.php
new file mode 100755
index 0000000..41d5fa6
--- /dev/null
+++ b/app/massage/model/CouponAtvRecord.php
@@ -0,0 +1,199 @@
+ $data['id'],
+
+ 'a.user_id' => 0,
+
+ // 'b.status' => 1
+ ];
+
+ $list = $list_model->alias('a')
+ ->join('massage_service_coupon b','a.coupon_id = b.id')
+ ->where($dis)
+ ->where('b.status','>',-1)
+ ->field('a.*,b.title,b.stock,b.i')
+ ->group('a.coupon_id')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-19 10:47
+ * @功能说明:判断卡券是否参加活动
+ */
+ public function couponIsAtv($coupon_id){
+
+ $dis_where[] = ['status','=',1];
+
+ $dis_where[] = ['end_time','<',time()];
+ //修改过期状态
+ $this->dataUpdate($dis_where,['status'=>3]);
+
+ $dis = [
+ //活动进行中
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $coupon_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('massage_service_coupon_atv_record_coupon b','a.id = b.record_id')
+ ->where($dis)
+ ->count();
+
+ return !empty($data)?true:false;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:审核中
+ */
+ public function shIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 00:02
+ * @功能说明:用户订单数
+ */
+ public function couponCount($user_id){
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->where($dis)->count();
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponAtvRecordCoupon.php b/app/massage/model/CouponAtvRecordCoupon.php
new file mode 100755
index 0000000..e080bb8
--- /dev/null
+++ b/app/massage/model/CouponAtvRecordCoupon.php
@@ -0,0 +1,127 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:审核中
+ */
+ public function shIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 00:02
+ * @功能说明:用户订单数
+ */
+ public function couponCount($user_id){
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->where($dis)->count();
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponAtvRecordList.php b/app/massage/model/CouponAtvRecordList.php
new file mode 100755
index 0000000..e300fc8
--- /dev/null
+++ b/app/massage/model/CouponAtvRecordList.php
@@ -0,0 +1,120 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:审核中
+ */
+ public function shIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','b.id = a.to_inv_id')
+ ->where($dis)
+ ->field('b.nickName,b.avatarUrl,b.id,a.create_time')
+ ->group('b.id')
+ ->paginate($page)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponMember.php b/app/massage/model/CouponMember.php
new file mode 100755
index 0000000..d6258a5
--- /dev/null
+++ b/app/massage/model/CouponMember.php
@@ -0,0 +1,101 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-01 15:43
+ * @功能说明:优惠券
+ */
+ public function eventCoupon($id,$data){
+
+ if(!empty($data['member_level'])){
+
+ foreach ($data['member_level'] as $value){
+
+ $insert['uniacid'] = $data['uniacid'];
+
+ $insert['coupon_id'] = $id;
+
+ $insert['member_level'] = $value;
+
+ $this->dataAdd($insert);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponRecord.php b/app/massage/model/CouponRecord.php
new file mode 100755
index 0000000..af7d0fa
--- /dev/null
+++ b/app/massage/model/CouponRecord.php
@@ -0,0 +1,534 @@
+ 1,
+
+ 'b.coupon_id' => $id,
+
+ 'b.type' => 1,
+
+ 'b.scene' => 1,
+
+
+ ];
+
+ $list = $ser_model->alias('a')
+ ->join('massage_service_coupon_goods b','b.goods_id = a.id')
+ ->where($dis)
+ ->field('a.id,a.title,a.price,b.goods_id')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 01:54
+ * @功能说明:
+ */
+ public function getShopGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $id = !empty($data['pid'])?$data['pid']:$data['id'];
+
+ $ser_model = new \app\shop\model\Goods();
+
+ $dis = [
+
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $id,
+
+ 'b.type' => 1,
+
+ 'b.scene' => 2,
+
+ ];
+
+ $list = $ser_model->alias('a')
+ ->join('massage_service_coupon_goods b','b.goods_id = a.id')
+ ->where($dis)
+ ->field('a.id,a.name,b.goods_id')
+ ->group('a.id')
+ ->order('a.top desc,a.id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 01:54
+ * @功能说明:
+ */
+ public function getRestaurantGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $id = !empty($data['pid'])?$data['pid']:$data['id'];
+
+ $ser_model = new \app\restaurant\model\Goods();
+
+ $dis = [
+
+ 'a.status' => 1,
+
+ 'b.coupon_id' => $id,
+
+ 'b.type' => 1,
+
+ 'b.scene' => 3,
+
+ ];
+
+ $list = $ser_model->alias('a')
+ ->join('massage_service_coupon_goods b','b.goods_id = a.id')
+ ->where($dis)
+ ->field('a.id,a.title,b.goods_id')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10,$where=[]){
+
+ $data = $this->alias('a')
+ ->join('shequshop_school_cap_list b','a.cap_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,b.store_name,b.store_img,b.name,b.mobile')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台审核详情
+ */
+ public function adminDataInfo($dis){
+
+ $data = $this->alias('a')
+ ->join('shequshop_school_cap_list b','a.cap_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.store_name,b.store_img,b.school_name,b.mobile')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:审核中
+ */
+ public function shIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-06 00:02
+ * @功能说明:用户订单数
+ */
+ public function couponCount($user_id){
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->where($dis)->sum('num');
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-08 11:57
+ * @功能说明:初始化
+ */
+ public function initCoupon($uniacid){
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['end_time','<',time()];
+
+ $res = $this->dataUpdate($dis,['status'=>3]);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-12 15:36
+ * @功能说明:派发优惠券
+ */
+ public function recordAdd($coupon_id,$user_id,$num=1,$user_get=0){
+
+ $coupon_model = new Coupon();
+
+ $coupon = $coupon_model->dataInfo(['id'=>$coupon_id]);
+ //用户自己领取的优惠券
+ if($user_get==1){
+
+ if($coupon['send_type']!=2){
+
+ return ['code'=>500,'msg'=>'优惠券已下架'];
+
+ }
+
+ $user_model = new User();
+
+ $user_info = $user_model->dataInfo(['id'=>$user_id]);
+
+ $level = $coupon['member_level'];
+
+ if(!in_array($user_info['member_level'],$level)){
+
+ $level_model = new Level();
+
+ $level_title = $level_model->where('id','in',$level)->column('title');
+
+ $level_title = !empty($level_title)?implode(',',$level_title):'';
+
+ return ['code'=>50002,'msg'=>'只有'.$level_title.'等级的会员才能领取'];
+
+ }
+
+ if($coupon['stock']<$num){
+
+ return ['code'=>500,'msg'=>'库存不足'];
+ }
+ //判断是否领取过
+ $have = $this->dataInfo(['user_id'=>$user_id,'coupon_id'=>$coupon_id]);
+
+ if(!empty($have)){
+
+ return ['code'=>500,'msg'=>'你已经领取过了'];
+
+ }
+
+ }
+
+
+ $insert = [
+
+ 'uniacid' => $coupon['uniacid'],
+
+ 'user_id' => $user_id,
+
+ 'coupon_id' => $coupon_id,
+
+ 'title' => $coupon['title'],
+
+ 'type' => $coupon['type'],
+
+ 'full' => $coupon['full'],
+
+ 'discount' => $coupon['discount'],
+
+ 'rule' => $coupon['rule'],
+
+ 'text' => $coupon['text'],
+
+ 'num' => $num,
+
+ 'start_time'=> $coupon['time_limit']==1?time():$coupon['start_time'],
+
+ 'end_time' => $coupon['time_limit']==1?time()+$coupon['day']*86400:$coupon['end_time'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res==0){
+
+ return $res;
+ }
+
+ $record_id = $this->getLastInsID();
+
+ if($coupon['send_type']==2){
+ //修改优惠券库存
+ $res = $coupon_model->dataUpdate(['id'=>$coupon_id,'i'=>$coupon['i']],['stock'=>$coupon['stock']-$num,'i'=>$coupon['i']+1]);
+
+ if($res==0){
+
+ return $res;
+ }
+ }
+
+
+ $list = [
+
+ 1 => $coupon['service'],
+
+ 2 => $coupon['shop_goods'],
+
+ 3 => $coupon['restaurant_goods'],
+ ];
+
+ $coupon_goods_model = new CouponService();
+ //给优惠券添加限用商品等
+ foreach ($list as $ks=>$vs){
+
+ if(!empty($vs)){
+
+ foreach ($vs as $vv){
+
+ $insert = [
+
+ 'uniacid' => $coupon['uniacid'],
+
+ 'type' => 1,
+
+ 'goods_id' => $vv['goods_id'],
+
+ 'coupon_id'=> $record_id,
+
+ 'scene' => $ks
+ ];
+
+ $res = $coupon_goods_model->insert($insert);
+
+ }
+
+ }
+
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-29 23:02
+ * @功能说明:退换优惠券
+ */
+ public function couponRefund($order_id){
+
+ $order_model = new Order();
+
+ $coupon_id = $order_model->where(['id'=>$order_id])->value('coupon_id');
+
+ if(!empty($coupon_id)){
+
+ $this->dataUpdate(['id'=>$coupon_id],['status'=>1,'use_time'=>0,'order_id'=>0]);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-13 09:34
+ * @功能说明:使用优惠券
+ */
+ public function couponUse($coupon_id,$order_id){
+
+ $record = $this->dataInfo(['id'=>$coupon_id]);
+
+ if($record['num']>1){
+
+ $this->dataUpdate(['id'=>$coupon_id],['num'=>$record['num']-1]);
+
+ unset($record['id']);
+
+ if(isset($record['goods'])){
+
+ unset($record['goods']);
+ }
+
+ if(isset($record['shop_goods'])){
+
+ unset($record['shop_goods']);
+ }
+
+ if(isset($record['restaurant_goods'])){
+
+ unset($record['restaurant_goods']);
+ }
+
+ $record['pid'] = $coupon_id;
+
+ $record['num'] = 1;
+
+ $record['status'] = 2;
+
+ $record['use_time'] = time();
+
+ $record['order_id'] = $order_id;
+
+ $this->insert($record);
+
+ $coupon_id = $this->getLastInsID();
+
+ }else{
+
+ $this->dataUpdate(['id'=>$coupon_id],['status'=>2,'use_time'=>time(),'order_id'=>$order_id]);
+
+ }
+
+ return $coupon_id;
+
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/CouponService.php b/app/massage/model/CouponService.php
new file mode 100755
index 0000000..57c7223
--- /dev/null
+++ b/app/massage/model/CouponService.php
@@ -0,0 +1,161 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function goodsUpdate($dis,$data){
+
+ $spe = $data['spe'];
+
+ unset($data['spe']);
+
+ $res = $this->where($dis)->update($data);
+
+ $this->updateSome($dis['id'],$data['uniacid'],$spe);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $uniacid
+ * @param $spe
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 13:35
+ */
+ public function updateSome($id,$uniacid,$coach){
+
+ $spe_model = new GoodsSpe();
+
+ $spe_model->where(['goods_id'=>$id])->delete();
+
+ if(!empty($spe)){
+
+ foreach ($spe as $value){
+
+ $value['uniacid'] = $uniacid;
+
+ $value['goods_id'] = $id;
+
+ $spe_model->dataAdd($value);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-01 15:43
+ * @功能说明:优惠券
+ */
+ public function eventCoupon($id,$data){
+
+ if(!empty($data['service'])){
+
+ foreach ($data['service'] as $value){
+
+ $insert['uniacid'] = $data['uniacid'];
+
+ $insert['coupon_id'] = $id;
+
+ $insert['goods_id'] = $value;
+
+ $this->dataAdd($insert);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Goods.php b/app/massage/model/Goods.php
new file mode 100755
index 0000000..2733f9a
--- /dev/null
+++ b/app/massage/model/Goods.php
@@ -0,0 +1,358 @@
+ 0,
+
+ 'goods_id' => $data['id']
+ ];
+
+ $list = $car_connect_type->where($dis)->column('type_id');
+
+ return array_values($list);
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-12 14:17
+ * @功能说明:判断该车型是否在使用
+ */
+ public function carTypeHave($car_type_id){
+
+ $dis [] = ['a.status','>',-1];
+
+ $dis [] = ['b.type_id','>',$car_type_id];
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_cartype_connect b','a.id = b.goods_id')
+ ->where($dis)
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:12
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:12
+ * @功能说明:
+ */
+ public function getCreateTimeTextAttr($value,$data){
+
+ if(!empty($data['create_time'])){
+
+ return date('Y-m-d H:i:s',$data['create_time']);
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-22 10:46
+ * @功能说明:添加车型
+ */
+ public function updateSome($car_type,$id,$uniacid){
+
+ $car_connect_type = new CarTypeConnect();
+
+ $dis = [
+
+ 'order_goods_id' => 0,
+
+ 'goods_id' => $id
+ ];
+
+ $car_connect_type->where($dis)->delete();
+
+ if(!empty($car_type)){
+
+ foreach ($car_type as $k=> $value){
+
+ $insert[$k]['goods_id'] = $id;
+
+ $insert[$k]['uniacid'] = $uniacid;
+
+ $insert[$k]['type_id'] = $value;
+
+ }
+
+ $car_connect_type->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(isset($data['car_type'])){
+
+ $car_type = $data['car_type'];
+
+ unset($data['car_type']);
+ }
+
+// $data['imgs'] = !empty($data['imgs'])?implode(',',$data['imgs']):'';
+
+ $res = $this->insert($data);
+
+ if(!empty($car_type)){
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($car_type,$id,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['car_type'])){
+
+ $car_type = $data['car_type'];
+
+ unset($data['car_type']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($car_type)){
+
+ $this->updateSome($car_type,$data['id'],$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+
+
+
+// /**
+// * @author chenniang
+// * @DataTime: 2020-09-29 11:05
+// * @功能说明:编辑
+// */
+// public function dataUpdate($dis,$data){
+//
+// $res = $this->where($dis)->update($data);
+//
+// return $res;
+//
+// }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function indexDataList($dis,$page,$sort){
+
+ $data = $this->where($dis)->order("$sort,id desc")->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-07 10:21
+ * @功能说明:服务技师列表
+ */
+ public function serviceCoachList($dis){
+
+ $data = $this->alias('a')
+ ->join('massage_service_service_coach b','a.id = b.ser_id')
+ ->where($dis)
+ ->field(['a.*'])
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:07
+ * @功能说明:增加|减少库存 增加|减少销量
+ */
+ public function setOrDelStock($goods_id,$num,$type=2){
+
+ if(empty($goods_id)){
+
+ return true;
+ }
+
+ $goods_info = $this->dataInfo(['id'=>$goods_id]);
+ //退货
+ if($type==1){
+
+ $update = [
+
+ 'true_sale' => $goods_info['true_sale']-$num,
+
+ 'total_sale'=> $goods_info['total_sale']-$num,
+
+ 'lock' => $goods_info['lock']+1,
+
+ ];
+ //如果是售后增加退款数量
+// if($refund==1){
+//
+// $update['refund_num'] = $goods_info['refund_num']+$num;
+// }
+ //减销量 加退款数量
+ $res = $this->where(['id'=>$goods_id,'lock'=>$goods_info['lock']])->update($update);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+
+ }else{
+
+ $update = [
+
+ 'true_sale' => $goods_info['true_sale']+$num,
+
+ 'total_sale'=> $goods_info['total_sale']+$num,
+
+ 'lock' => $goods_info['lock']+1,
+
+ ];
+
+ //增加销量
+ $res = $this->where(['id'=>$goods_id,'lock'=>$goods_info['lock']])->update($update);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'提交失败'];
+ }
+
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/GoodsSpe.php b/app/massage/model/GoodsSpe.php
new file mode 100755
index 0000000..ae28c92
--- /dev/null
+++ b/app/massage/model/GoodsSpe.php
@@ -0,0 +1,75 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Lable.php b/app/massage/model/Lable.php
new file mode 100755
index 0000000..2fecfd4
--- /dev/null
+++ b/app/massage/model/Lable.php
@@ -0,0 +1,94 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Machine.php b/app/massage/model/Machine.php
new file mode 100755
index 0000000..f3c94f6
--- /dev/null
+++ b/app/massage/model/Machine.php
@@ -0,0 +1,91 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('status desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:08
+ * @功能说明:开启默认
+ */
+ public function updateOne($id){
+
+ $user_id = $this->where(['id'=>$id])->value('user_id');
+
+ $res = $this->where(['user_id'=>$user_id])->where('id','<>',$id)->update(['status'=>0]);
+
+ return $res;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/NoticeList.php b/app/massage/model/NoticeList.php
new file mode 100755
index 0000000..0f5c2b5
--- /dev/null
+++ b/app/massage/model/NoticeList.php
@@ -0,0 +1,105 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Order.php b/app/massage/model/Order.php
new file mode 100755
index 0000000..aa88197
--- /dev/null
+++ b/app/massage/model/Order.php
@@ -0,0 +1,1018 @@
+ $data['id'],
+
+ 'page' => 'mine/pages/order/hexiao'
+
+ ];
+ //获取二维码
+ $value = $user_model->orderQr($input,$data['uniacid']);
+
+ $this->dataUpdate(['id'=>$input['id']],['qr'=>$value]);
+
+ }
+
+ return $value;
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-28 14:12
+ * @功能说明:核销人姓名
+ */
+ public function getHxUserNameAttr($value,$data){
+
+ if(!empty($data['hx_user'])){
+
+ $user_model = new User();
+
+ $name = $user_model->where(['id'=>$data['hx_user']])->value('nickName');
+
+ return $name;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-27 16:21
+ * @功能说明:赛事信息
+ */
+ public function getGameInfoAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $game_model = new CarGame();
+
+ $dis = [
+
+ 'type' => 2,
+
+ 'record_id' => $data['id']
+ ];
+
+ $list = $game_model->dataInfo($dis);
+
+ return $list;
+
+ }
+
+ }
+
+
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总商品数量
+ * @author chenniang
+ * @DataTime: 2021-03-25 14:39
+ */
+ public function getAllGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new OrderGoods();
+
+ $dis = [
+
+ 'order_id' => $data['id']
+ ];
+
+ $num = $order_goods_model->where($dis)->sum('num');
+
+ return $num;
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:05
+ * @功能说明:子订单信息
+ */
+
+ public function getOrderGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new OrderGoods();
+
+ $dis = [
+
+ 'order_id' => $data['id']
+ ];
+
+ $list = $order_goods_model->where($dis)->select()->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:23
+ * @功能说明:前端订单列表
+ */
+
+ public function indexDataList($dis,$mapor,$page=10){
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_order_goods b','a.id = b.order_id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+ }
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_order_goods b','a.id = b.order_id')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataSelect($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('shequshop_car_order_goods b','a.id = b.order_id')
+ ->where($dis)
+ ->field('a.*,b.goods_id,b.goods_name,b.goods_price,b.num')
+ ->group('a.id,b.goods_id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ if(!empty($data)){
+
+ $user_model = new User();
+
+ foreach ($data as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 14:33
+ * @功能说明:
+ */
+ public function datePrice($date,$uniacid,$cap_id=0,$end_time = '',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['transaction_id','<>',''];
+
+ $dis[] = ['auto_refund','=',0];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('pay_price');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 09:28
+ * @功能说明:计算用户下单时候的各类金额
+ */
+ public function payOrderInfo($user_id,$coupon=0){
+
+ $car_model = new Car();
+
+ $coupon_model = new Coupon();
+ //获取购物车里面的信息
+ $car_list = $car_model->carPriceAndCount($user_id);
+
+ $car_list = $coupon_model->orderCouponData($car_list,$coupon);
+
+ $goods_price = $car_list['car_price'];
+
+ $data['coupon_id'] = $car_list['coupon_id'];
+ //购物车列表
+ $data['order_goods'] = $car_list['list'];
+ //优惠券优惠
+ $data['discount'] = $car_list['total_discount'];
+ //总圈速
+ $data['total_circle'] = $car_list['total_circle'];
+ //商品总价格
+ $data['init_goods_price'] = round($goods_price,2);
+
+ $data['goods_price'] = round($goods_price-$data['discount'],2);
+ //订单支付价
+ $data['pay_price'] = round($data['goods_price'] ,2);
+
+ $data['car_count'] = $car_list['car_count'];
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-09 17:43
+ * @功能说明:计算车费
+ */
+ public function getCarPrice($coach_id,$lat,$lng,$car_type=1){
+
+ if($car_type==0){
+
+ return 0;
+ }
+
+ $coach_model = new Coach();
+
+ $coach = $coach_model->dataInfo(['id'=>$coach_id]);
+
+ $config_model = new CarPrice();
+
+ $config = $config_model->dataInfo(['uniacid'=>$coach['uniacid']]);
+ //起步距离
+ $start = $config['start_distance'];
+ //起步价
+ $start_price = $config['start_price'];
+ //每公里多少钱
+ $to_price = $config['distance_price'];
+
+ $distance = getDistances($coach['lng'],$coach['lat'],$lng,$lat);
+
+ $distance = $distance/1000;
+ //多少公里内免费
+ if($distance<$config['distance_free']){
+
+ return 0;
+ }
+ //超过起步距离
+ if($distance>$start){
+
+ $to_price = round($distance - $start,2)*$to_price;
+
+ $total = $to_price+$start_price;
+
+ return round($total*2,2);
+
+ }else{
+
+ return round($start_price*2,2);
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:31
+ * @功能说明:订单支付回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->dataInfo(['order_code'=>$order_code]);
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ Db::startTrans();
+
+ $update = [
+
+ 'transaction_id' => $transaction_id,
+
+ 'pay_type' => 2,
+
+ 'pay_time' => time(),
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$order['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return false;
+
+ }
+ //扣除余额
+ if($order['balance']>0){
+
+ $user_model = new User();
+
+ $water_model = new BalanceWater();
+
+ $user = $user_model->dataInfo(['id'=>$order['user_id']]);
+ //修改用户余额
+ $res = $user_model->dataUpdate(['id'=>$order['user_id']],['balance'=>$user['balance']-$order['pay_price']]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return false;
+
+ }
+ //添加余额流水
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'price' => $order['pay_price'],
+
+ 'order_id'=> $order['id'],
+
+ 'add' => 0,
+
+ 'type' => 2,
+
+ 'before_balance' => $user['balance'],
+
+ 'after_balance' => $user['balance']-$order['pay_price'],
+ ];
+
+ $res = $water_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return false;
+
+ }
+ }
+
+ //分销
+// $comm_model = new Commission();
+//
+// $comm_model->commissionAdd($order);
+
+ Db::commit();
+
+// $notice_model = new NoticeList();
+// //增加后台提醒
+// $notice_model->dataAdd($order['uniacid'],$order['id']);
+ //打印
+ $print_model = new Printer();
+
+ $print_model->printer($order['id'],1,1);
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:31
+ * @功能说明:团长冻结资金
+ */
+ public function capFrozenPrice($cap_id,$total=0,$toDay=0){
+
+ $dis[] = ['cap_id','=',$cap_id];
+
+ if($total==0){
+
+ $dis[] = ['have_tx','=',0];
+ }
+
+ $dis[] = ['pay_type','>',1];
+
+ if($toDay==1){
+ //当日
+ $price = $this->where($dis)->whereDay('create_time')->sum('cap_price');
+
+ }else{
+
+ $price = $this->where($dis)->sum('cap_price');
+
+ }
+
+ return round($price,2);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:31
+ * @功能说明:团长冻结资金
+ */
+ public function capFrozenCount($cap_id,$total=0,$toDay=0){
+
+ $dis[] = ['cap_id','=',$cap_id];
+
+ if($total==0){
+
+ $dis[] = ['have_tx','=',0];
+ }
+
+ $dis[] = ['pay_type','>',1];
+
+ if($toDay==1){
+ //当日
+ $price = $this->where($dis)->whereDay('create_time')->count();
+
+ }else{
+
+ $price = $this->where($dis)->count();
+
+ }
+
+ return $price;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:41
+ * @功能说明:团长佣金到账
+ */
+ public function capArrPrice($uniacid,$cap_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',7];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ $dis[] = ['have_tx','=',0];
+
+// $dis[] = ['hx_time','<',time()-86400];
+ $dis[] = ['hx_time','<',time()-60];
+
+ $order = $this->where($dis)->field('id,cap_price,cap_id')->select()->toArray();
+
+ if(!empty($order)){
+
+ $cap_model = new Cap();
+
+ $refund_model = new RefundOrder();
+
+ foreach ($order as $value){
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$value['id'],'status'=>1]);
+
+ if(empty($refund_order)){
+ //修改订单状态
+ $res = $this->where(['id'=>$value['id'],'have_tx'=>0])->update(['have_tx'=>1]);
+ //增加团长佣金
+ if($res==1){
+
+ $cap_cash = $value['cap_price'];
+
+ $cap_model->where(['id'=>$cap_id])->update(['cap_cash'=>Db::raw("cap_cash+$cap_cash")]);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:15
+ * @功能说明:核销订单
+ */
+ public function hxOrder($order,$cap_id=0){
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$order['uniacid']]);
+
+ $update = [
+
+ 'hx_time' => time(),
+
+ 'pay_type' => 7,
+
+ 'hx_user' => $cap_id,
+ //可申请退款的时间
+ 'can_refund_time'=> time()+$config['can_tx_time']*3600
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$order['id']],$update);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:超时自动退款
+ */
+ public function autoCancelOrder($uniacid,$user_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',1];
+
+ $dis[] = ['over_time','<',time()];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->cancelOrder($value);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:退款
+ */
+ public function cancelOrder($order){
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$order['id'],'pay_type'=>1],['pay_type'=>-1]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'取消失败'];
+ }
+
+// $goods_model = new Service();
+// //退换库存
+// foreach ($order['order_goods'] as $v){
+//
+// $res = $goods_model->setOrDelStock($v['goods_id'],$v['num'],1);
+//
+// if(!empty($res['code'])){
+//
+// Db::rollback();
+//
+// return $res;
+//
+// }
+//
+// }
+ //退换优惠券
+ $coupon_model = new CouponRecord();
+
+ $coupon_model->couponRefund($order['id']);
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-10 18:04
+ * @功能说明:检查技师时间
+ */
+ public function checkTime($order,$start_time){
+
+ $service_model = new Service();
+
+ $coach_model = new Coach();
+
+ $order_model = new Order();
+
+ $total_long = 0;
+
+ foreach ($order['order_goods'] as $v){
+
+ $time_long = $service_model->where(['id'=>$v['service_id']])->value('time_long');
+
+ $total_long+=$time_long*$v['num'];
+
+ }
+
+ $end_time = $start_time+$total_long*60;
+
+ $coach = $coach_model->dataInfo(['id'=>$order['coach_id']]);
+
+ $all_day = 1;
+ //判断不是全体24小时上班
+ if($coach['start_time']!='00:00'||$coach['end_time']!='24:00'){
+
+ $all_day = 0;
+
+ }
+ //判断是否隔夜
+ $s_day = date('Y-m-d',$start_time);
+
+ $e_day = date('Y-m-d',$end_time);
+ //全天不判断
+ if($all_day==0){
+ //说明是隔天
+ if($s_day!=$e_day){
+
+ return ['code'=>500,'msg'=>'不在技师服务时间内,技师服务时间:'.$coach['start_time'].'-'.$coach['end_time']];
+
+ }
+ //教练上班时间
+ $coach_start_time = strtotime($coach['start_time'])-strtotime(date('Y-m-d',time()))+strtotime(date('Y-m-d',$start_time));
+ //教练下班时间
+ $coach_end_time = strtotime($coach['end_time'])-strtotime(date('Y-m-d',time()))+strtotime(date('Y-m-d',$start_time));
+
+ if($start_time<$coach_start_time||$end_time>$coach_end_time){
+
+ return ['code'=>500,'msg'=>'不在技师服务时间内,技师服务时间:'.$coach['start_time'].'-'.$coach['end_time']];
+
+ }
+
+ }
+ //检查该时间段是否被预约
+ $where[] = ['coach_id','=',$order['coach_id']];
+
+ $where[] = ['pay_type','not in',[-1]];
+
+ $where[] = ['end_time','>',time()];
+
+ $order_list = $order_model->where($where)->field('id,start_time,end_time')->select()->toArray();
+
+ if(!empty($order_list)){
+
+ foreach ($order_list as $value){
+ //判断两个时间段是否有交集
+ $res = is_time_cross($start_time,$end_time,$value['start_time'],$value['end_time']);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'该技师该时间段已经被预约:'.date('Y-m-d H:i',$value['start_time']).'-'.date('Y-m-d H:i',$value['end_time'])];
+
+ }
+
+ }
+
+ }
+
+ $arr = [
+
+ 'end_time' => $end_time,
+
+ 'time_long'=> $total_long
+ ];
+
+ return $arr;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 22:39
+ * @功能说明:技师修改订单信息
+ */
+ public function coachOrdertext($input){
+
+ $update['pay_type'] = $input['type'];
+
+ switch ($input['type']){
+
+ case 3:
+
+ $update['receiving_time'] = time();
+
+ break;
+ case 4:
+
+ $update['serout_time'] = time();
+
+ break;
+ case 5:
+
+ $update['arrive_time'] = time();
+
+ $update['arrive_img'] = $input['arrive_img'];
+
+ $update['arr_lng'] = !empty($input['arr_lng'])?$input['arr_lng']:0;
+
+ $update['arr_lat'] = !empty($input['arr_lat'])?$input['arr_lat']:0;
+
+ $update['arr_address']= !empty($input['arr_address'])?$input['arr_address']:'';
+
+
+ break;
+ case 6:
+
+ $update['start_service_time'] = time();
+
+ break;
+
+ case 7:
+
+ $update['order_end_time'] = time();
+
+ $update['end_lng'] = !empty($input['end_lng'])?$input['end_lng']:0;
+
+ $update['end_lat'] = !empty($input['end_lat'])?$input['end_lat']:0;
+
+ $update['end_address']= !empty($input['end_address'])?$input['end_address']:'';
+
+ $update['end_img'] = !empty($input['end_img'])?$input['end_img']:'';
+
+ break;
+ case -1:
+
+ $update['coach_refund_time'] = time();
+
+ break;
+
+ }
+
+ return $update;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-11 23:18
+ * @功能说明:技师佣金到账
+ */
+ public function coachBalanceArr($uniacid){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',7];
+
+ $dis[] = ['have_tx','=',0];
+
+// $dis[] = ['can_tx_date','<',time()];
+
+ $order = $this->where($dis)->field('id,coach_id,service_price,car_price,true_service_price,true_car_price')->select()->toArray();
+
+ if(!empty($order)){
+
+ $refund_model = new RefundOrder();
+
+ $coach_model = new Coach();
+
+ $comm_model = new Commission();
+
+ foreach ($order as $value){
+
+ $refund_order = $refund_model->dataInfo(['order_id'=>$value['id'],'status'=>1]);
+
+ if(empty($refund_order)){
+
+ Db::startTrans();
+ //分销佣金
+ $comm_model->successCash($value['id']);
+ //修改订单状态
+ $res = $this->where(['id'=>$value['id'],'have_tx'=>0])->update(['have_tx'=>1]);
+ //增加团长佣金
+ if($res!=0){
+
+ $cap_cash = $value['true_service_price'];
+
+ $car_cash = $value['true_car_price'];
+
+ $res = $coach_model->where(['id'=>$value['coach_id']])->update(['service_price'=>Db::raw("service_price+$cap_cash"),'car_price'=>Db::raw("car_price+$car_cash")]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+
+ }else{
+
+ Db::rollback();
+ }
+
+ Db::commit();
+
+ }
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/OrderAddress.php b/app/massage/model/OrderAddress.php
new file mode 100755
index 0000000..79c42bf
--- /dev/null
+++ b/app/massage/model/OrderAddress.php
@@ -0,0 +1,137 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 10:34
+ * @功能说明:添加下单地址
+ */
+ public function orderAddressAdd($address_id,$order_id){
+
+ if(empty($address_id)){
+
+ return ['code'=>500,'msg'=>'请选择下单地址'];
+ }
+
+ $address_model = new Address();
+
+ $address = $address_model->dataInfo(['id'=>$address_id]);
+
+ if(empty($address)){
+
+ return ['code'=>500,'msg'=>'下单地址已删除'];
+
+ }
+
+ $insert = [
+
+ 'uniacid' => $address['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'user_name'=> $address['user_name'],
+
+ 'mobile' => $address['mobile'],
+
+ 'province' => $address['province'],
+
+ 'city' => $address['city'],
+
+ 'area' => $address['area'],
+
+ 'lng' => $address['lng'],
+
+ 'lat' => $address['lat'],
+
+ 'address' => $address['address'],
+
+ 'address_info' => $address['address_info'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'下单失败'];
+
+ }
+
+ return $res;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/OrderGoods.php b/app/massage/model/OrderGoods.php
new file mode 100755
index 0000000..0720a22
--- /dev/null
+++ b/app/massage/model/OrderGoods.php
@@ -0,0 +1,260 @@
+refundNum($data['id']);
+
+ return $num;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataSelect($dis){
+
+ $data = $this->where($dis)->order('id desc')->select()->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:12
+ * @功能说明:添加商品子订单
+ */
+ public function orderGoodsAdd($order_goods,$order_id,$user_id){
+
+ $goods_model = new Goods();
+
+ $car_model = new Car();
+
+ foreach ($order_goods as $v){
+
+// $ser_status = $goods_model->where(['id'=>$v['goods_id']])->value('status');
+
+ $goods = $goods_model->dataInfo(['id'=>$v['goods_id']]);
+
+ if($goods['status']!=1){
+
+ return ['code'=>500,'msg'=>'商品已经下架'];
+ }
+
+ $res = $this->checkIdentity($goods,$user_id);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+
+ $insert = [
+
+ 'uniacid' => $v['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'user_id' => $user_id,
+
+ 'pay_type' => 1,
+
+ 'goods_name' => $v['title'],
+
+ 'goods_cover' => $v['cover'],
+
+ 'goods_price' => $v['price'],
+
+ 'true_price' => round($v['true_price']/$v['num'],5),
+
+ 'pay_price' => round($v['true_price'],2),
+
+ 'num' => $v['num'],
+
+ 'can_refund_num' => $v['num'],
+
+ 'goods_id' => $v['goods_id'],
+
+ 'circle' => $goods['number'],
+
+ 'car_type_id' => $goods['car_type_id'],
+
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'下单失败'];
+ }
+
+ $order_goods_id = $this->getLastInsID();
+
+ $this->updateSome($v,$order_goods_id);
+ }
+ //删除购物车
+ $res = $car_model->where(['user_id'=>$user_id,'status'=>1])->delete();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-23 17:33
+ * @功能说明:检查购买者身份
+ */
+ public function checkIdentity($goods,$user_id){
+
+ $driver_model = new CarDriver();
+ //查看是否是专业赛车手
+ $info = $driver_model->dataInfo(['user_id'=>$user_id,'status'=>2]);
+
+ $car_type_model = new CarType();
+
+ $car_type = $car_type_model->dataInfo(['id'=>$goods['car_type_id']]);
+
+ if(!empty($info)&&empty($car_type['major'])){
+
+ return ['code'=>500,'msg'=>$goods['title'].'只有普通车手可购买'];
+ }
+
+ if(empty($info)&&empty($car_type['norm'])){
+
+ return ['code'=>50001,'msg'=>$goods['title'].'只有专业车手可购买'];
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-22 10:46
+ * @功能说明:添加车型
+ */
+ public function updateSome($order_goods,$order_goods_id){
+
+ $car_connect_type = new CarTypeConnect();
+
+
+ $car_type = $car_connect_type->where(['order_goods_id'=>0,'goods_id'=>$order_goods['goods_id']])->column('type_id');
+
+ if(!empty($car_type)){
+
+ foreach ($car_type as $k=> $value){
+
+ $insert[$k]['goods_id'] = $order_goods['goods_id'];
+
+ $insert[$k]['uniacid'] = $order_goods['uniacid'];
+
+ $insert[$k]['order_goods_id'] = $order_goods_id;
+
+ $insert[$k]['type_id'] = $value;
+
+ }
+
+ $car_connect_type->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/PayConfig.php b/app/massage/model/PayConfig.php
new file mode 100755
index 0000000..e9f97b1
--- /dev/null
+++ b/app/massage/model/PayConfig.php
@@ -0,0 +1,83 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Printer.php b/app/massage/model/Printer.php
new file mode 100755
index 0000000..0bab135
--- /dev/null
+++ b/app/massage/model/Printer.php
@@ -0,0 +1,442 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-11 09:25
+ * @功能说明:订单打印
+ */
+ public function userOrder($id){
+
+ $order_model = new Order();
+ //订单信息
+ $order = $order_model->dataInfo(['id'=>$id]);
+
+ $brs = " ";
+
+ $orderInfo = ''.'订单小票'.' ';
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+
+ $orderInfo .= '服务/数量/价格'.$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+
+ foreach ($order['order_goods'] as $v) {
+
+ $v['goods_name'] = mb_convert_encoding($v['goods_name'], "UTF-8", "auto");
+
+ $orderInfo .= $v['goods_name'].$brs;
+
+ $orderInfo .= ' X'.$v['num'].' '.round($v['true_price']*$v['num'],2).'元'.$brs;
+// $orderInfo .= round($v['true_price']*$v['num'],2).'元'.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ }
+
+
+ $coach_model = new Coach();
+
+ $address_model = new OrderAddress();
+
+ $coach_name = $coach_model->where(['id'=>$order['coach_id']])->value('coach_name');
+
+ $user_name = $address_model->where(['order_id'=>$order['id']])->value('user_name');
+
+ $orderInfo .= '预约技师:'.$coach_name.$brs;
+
+ $orderInfo .= '下单人:'.$user_name.$brs;
+
+ $time = date('Y-m-d H:i',$order['start_time']).'-'.date('Y-m-d H:i',$order['end_time']);
+
+ $orderInfo .= '预约时间:'.$time.$brs;
+
+ $orderInfo .= '预约金额:'.round($order['pay_price'],2).$brs;
+
+ $orderInfo .= '付款时间:'.date('Y-m-d H:i',$order['pay_time']).$brs;
+
+ return $orderInfo;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-11 10:20
+ * @功能说明:打印
+ */
+ public function orderPrinter($orderInfo,$aotu=1,$type=1){
+
+ $dis = [
+
+ 'status' => 1,
+ ];
+
+ if($aotu==1){
+
+ $dis['auto'] =1;
+ }
+
+ if($type==1){
+
+ $dis['is_car'] = 1;
+
+ }elseif($type==2){
+
+ $dis['is_shop'] = 1;
+
+ }else{
+
+ $dis['is_restaurant'] = 1;
+
+ }
+
+ $printer_config = $this->where($dis)->select()->toArray();
+
+ if(!empty($printer_config)){
+
+ foreach ($printer_config as $value){
+
+ $value['ukey'] = $value['api_key'];
+
+ $value['sn'] = $value['printer_key'];
+ //用户小票
+ $res = \longbingcore\printer\Printer::FeiePrintMsg($value,$orderInfo,'Open_printMsg',$value['user_ticket_num']);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-12 09:57
+ * @功能说明:打印
+ *
+ * type 1赛车 2商城 3 餐饮
+ */
+ public function printer($id,$aotu=1,$type=1){
+
+ if($type==1){
+
+ $user_order = $this->carOrder($id);
+
+ }elseif ($type==2){
+
+ $user_order = $this->shopOrder($id);
+
+ }else{
+
+ $user_order = $this->restaurantOrder($id);
+
+ }
+ //打印
+ $res = $this->orderPrinter($user_order,$aotu,$type);
+
+ return $res;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-11 09:25
+ * @功能说明:商城订单打印
+ */
+ public function shopOrder($id){
+
+ $order_model = new \app\shop\model\Order();
+ //订单信息
+ $order = $order_model->dataInfo(['id'=>$id]);
+
+ $brs = " ";
+
+ $orderInfo = ''.'商城订单小票'.' ';
+
+ $orderInfo .= '订单号:'.$order['order_code'].$brs;
+
+ $orderInfo .= '下单时间:'.date('Y-m-d H:i:s',$order['create_time']).$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+ $orderInfo .= '商品/规格/数量/价格'.$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+ foreach ($order['order_goods'] as $v) {
+
+ $v['goods_name'] = mb_convert_encoding($v['goods_name'], "UTF-8", "auto");
+
+ $orderInfo .= $v['goods_name'].$brs;
+
+ $orderInfo .= '【'.$v['spe_name'].'】'.$brs;
+
+ $orderInfo .= ' X'.$v['goods_num'].' '.round($v['pay_price'],2).'元'.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ }
+ $orderInfo .= '--------------------------------'.$brs;
+
+ if($order['send_type']==1){
+
+ $orderInfo .= '配送方式:自提'.$brs;
+
+ }else{
+
+ $orderInfo .= '配送方式:快递'.$brs;
+
+ $orderInfo .= '物流费:'.$order['freight'].$brs;
+
+ $orderInfo .= ''.$brs;
+
+ $orderInfo .= ''.$brs;
+ }
+
+ $orderInfo .= '原价:'.$order['init_price'].$brs;
+
+ $orderInfo .= '优惠:'.round($order['init_price']-$order['pay_price'],2).$brs;
+
+ $orderInfo .= '实付:'.$order['pay_price'].$brs;
+
+ $address_model = new OrderAddress();
+
+ $user = $address_model->dataInfo(['order_id'=>$order['id'],'type'=>2]);
+ //自提
+ $orderInfo .= $user['address'].$user['address_info'].$brs;
+
+ $orderInfo .= $user['user_name'].' '.$user['mobile'].$brs;
+
+ $orderInfo .= '备注:'.$order['text'].$brs;
+
+ return $orderInfo;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-11 09:25
+ * @功能说明:餐饮订单打印
+ */
+ public function restaurantOrder($id){
+
+ $order_model = new \app\restaurant\model\Order();
+ //订单信息
+ $order = $order_model->dataInfo(['id'=>$id]);
+
+ $table_model = new Table();
+
+ $table_title = $table_model->where(['id'=>$order['table_id']])->value('title');
+
+ $brs = " ";
+
+ $orderInfo = ''.'餐饮订单小票'.' ';
+
+ $orderInfo .= '订单号:'.$order['order_code'].$brs;
+
+ $orderInfo .= '人数:'.$order['user_num'].$brs;
+
+ $orderInfo .= '桌号:'.$table_title.$brs;
+
+ $orderInfo .= '下单时间:'.date('Y-m-d H:i:s',$order['create_time']).$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+ $orderInfo .= '商品/规格/数量/价格'.$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+ foreach ($order['order_goods'] as $v) {
+
+ $v['goods_name'] = mb_convert_encoding($v['goods_name'], "UTF-8", "auto");
+
+ $orderInfo .= $v['goods_name'].$brs;
+
+ $orderInfo .= '【'.$v['spe_name'].'】'.$brs;
+
+ $orderInfo .= ' X'.$v['goods_num'].' '.round($v['pay_price'],2).'元'.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ }
+ $orderInfo .= '--------------------------------'.$brs;
+
+ $orderInfo .= '原价:'.$order['init_price'].$brs;
+
+ $orderInfo .= '优惠:'.round($order['init_price']-$order['pay_price'],2).$brs;
+
+ $orderInfo .= '实付:'.$order['pay_price'].$brs;
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$order['user_id']]);
+
+ $orderInfo .= $user['nickName'].' '.$user['phone'].$brs;
+
+ $orderInfo .= '备注:'.$order['text'].$brs;
+
+ return $orderInfo;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-11 09:25
+ * @功能说明:赛车订单打印
+ */
+ public function carOrder($id){
+
+ $order_model = new Order();
+ //订单信息
+ $order = $order_model->dataInfo(['id'=>$id]);
+
+ $brs = " ";
+
+ $orderInfo = ''.'赛车订单小票'.' ';
+
+ $orderInfo .= '订单号:'.$order['order_code'].$brs;
+
+ $orderInfo .= '下单时间:'.date('Y-m-d H:i:s',$order['create_time']).$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+ $orderInfo .= '商品/数量/价格'.$brs;
+
+ $orderInfo .= '--------------------------------'.$brs;
+
+ foreach ($order['order_goods'] as $v) {
+
+ $v['goods_name'] = mb_convert_encoding($v['goods_name'], "UTF-8", "auto");
+
+ $orderInfo .= $v['goods_name'].$brs;
+
+ $orderInfo .= ' X'.$v['num'].' '.round($v['pay_price'],2).'元'.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ $orderInfo .= ''.$brs;
+
+ }
+ $orderInfo .= '--------------------------------'.$brs;
+
+ $orderInfo .= '原价:'.$order['init_price'].$brs;
+
+ $orderInfo .= '优惠:'.round($order['init_price']-$order['pay_price'],2).$brs;
+
+ $orderInfo .= '实付:'.$order['pay_price'].$brs;
+
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['id'=>$order['user_id']]);
+
+ $orderInfo .= $user['nickName'].' '.$user['phone'].$brs;
+
+ $orderInfo .= '备注:'.$order['text'].$brs;
+
+ return $orderInfo;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/RefundOrder.php b/app/massage/model/RefundOrder.php
new file mode 100755
index 0000000..2c07b21
--- /dev/null
+++ b/app/massage/model/RefundOrder.php
@@ -0,0 +1,795 @@
+where(['id'=>$data['user_id']])->value('nickName');
+
+ return $nickName;
+ }
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 16:48
+ * @功能说明:
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总商品数量
+ * @author chenniang
+ * @DataTime: 2021-03-25 14:39
+ */
+ public function getAllGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new RefundOrderGoods();
+
+ $dis = [
+
+ 'refund_id' => $data['id']
+ ];
+
+ $num = $order_goods_model->where($dis)->sum('num');
+
+ return $num;
+ }
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:16
+ * @功能说明:收货信息
+ */
+ public function getOrderGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $goods_model = new RefundOrderGoods();
+
+ $info = $goods_model->dataSelect(['refund_id'=>$data['id']]);
+
+ return $info;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->alias('a')
+ ->join('massage_service_refund_order_goods c','a.id = c.refund_id')
+ ->join('shequshop_car_order d','a.order_id = d.id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,d.order_code as pay_order_code,d.pay_price')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:46
+ * @功能说明:小程序退款列表
+ */
+ public function indexDataList($dis,$where=[],$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_refund_order_goods c','a.id = c.refund_id','left')
+ ->join('shequshop_car_order d','a.order_id = d.id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,d.order_code as pay_order_code')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:退款中
+ */
+ public function refundIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:37
+ * @功能说明:通过退款
+ */
+ public function passOrder($id,$price,$payConfig,$refund_user=0,$text=''){
+
+ $refund_order= $this->dataInfo(['id'=>$id]);
+
+ $order_model = new Order();
+
+ $pay_order = $order_model->dataInfo(['id'=>$refund_order['order_id']]);
+
+ if($refund_order['status']!=1){
+
+ return ['code'=>500,'msg'=>'订单状态错误'];
+ }
+
+ $update = [
+
+ 'status' => 2,
+
+ 'refund_time' => time(),
+
+ 'refund_price'=> $price,
+
+ 'refund_text' => $text
+ ];
+
+// $comm_model = new Commission();
+
+ Db::startTrans();
+ //分销佣金
+// $comm_model->refundComm($id);
+
+
+ $res = $this->dataUpdate(['id'=>$refund_order['id']],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试'];
+
+ }
+ //修改退款子订单的退款状态
+ $order_refund_goods = new RefundOrderGoods();
+
+ $res = $order_refund_goods->dataUpdate(['refund_id'=>$id],['status'=>2]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试1'.$res];
+
+ }
+
+
+
+ $order_update = [];
+
+// if($refund_order['apply_price']>0){
+
+// //服务费占总退款的比例
+// $ser_bin = $refund_order['service_price']/$refund_order['apply_price'];
+// //扣除退款后的服务费
+// $coach_price = $pay_order['true_service_price'] - $price*$ser_bin;
+//
+// $coach_price = $coach_price>0?round($coach_price,2):0;
+//
+// $order_update = [
+//
+//
+// 'true_service_price'=> $coach_price,
+//
+//
+// ];
+// }
+
+ //查看货是否退完了
+ $refund_success = $this->checkRefundNum($refund_order['order_id']);
+ //退完了 就修改订单状态
+ if($refund_success==1){
+
+ $order_update['pay_type'] = -1;
+
+ if(!empty($pay_order['pay_type'])&&$pay_order['pay_type']<=3){
+ //退换优惠券
+ $coupon_model = new CouponRecord();
+
+ $coupon_model->couponRefund($pay_order['id']);
+ }
+
+ }
+
+ if(!empty($order_update)){
+
+ $res = $order_model->dataUpdate(['id'=>$refund_order['order_id']],$order_update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试2'];
+
+ }
+
+ }
+
+ //退款
+ if($price>0){
+
+ $res = $this->refundCash($payConfig,$pay_order,$price,$id);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>$res['msg']];
+ }
+
+ if($res!=true){
+
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试2'];
+ }
+
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $payConfig
+ * @param $pay_order
+ * @param $price
+ * @param int $refund_id
+ * @功能说明:退钱
+ * @author chenniang
+ * @DataTime: 2021-07-12 20:31
+ */
+ public function refundCash($payConfig,$pay_order,$price,$refund_id=0){
+
+ $order_model = new Order();
+
+ if(empty($pay_order['balance'])){
+ //微信退款
+ $response = orderRefundApi($payConfig,$pay_order['pay_price'],$price,$pay_order['transaction_id']);
+ //如果退款成功修改一下状态
+ if ( isset( $response[ 'return_code' ] ) && isset( $response[ 'result_code' ] ) && $response[ 'return_code' ] == 'SUCCESS' && $response[ 'result_code' ] == 'SUCCESS' ) {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no'])?$response['out_refund_no']:$pay_order['order_code'];
+
+ if(!empty($refund_id)){
+
+ $this->dataUpdate(['id'=>$refund_id],['out_refund_no'=>$response['out_refund_no']]);
+
+ }else{
+
+ $order_model->dataUpdate(['id'=>$pay_order['id']],['coach_refund_code'=>$response['out_refund_no']]);
+ }
+
+
+ }else {
+ //失败就报错
+ $discption = !empty($response['err_code_des'])?$response['err_code_des']:$response['return_msg'];
+
+ return ['code'=>500,'msg'=> $discption];
+
+ }
+
+ }else{
+
+ $user_model = new User();
+
+ $water_model = new BalanceWater();
+
+ $user = $user_model->dataInfo(['id'=>$pay_order['user_id']]);
+ //修改用户余额
+ $res = $user_model->dataUpdate(['id'=>$pay_order['user_id']],['balance'=>$price+$user['balance']]);
+
+ if($res==0){
+
+ return false;
+
+ }
+ //添加余额流水
+ $insert = [
+
+ 'uniacid' => $pay_order['uniacid'],
+
+ 'user_id' => $pay_order['user_id'],
+
+ 'order_id'=> $pay_order['id'],
+
+ 'price' => $price,
+
+ 'add' => 1,
+
+ 'type' => 2,
+
+ 'before_balance' => $user['balance'],
+
+ 'after_balance' => $price+$user['balance'],
+ ];
+
+ $res = $water_model->dataAdd($insert);
+
+ if($res==0){
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:29
+ * @功能说明:检查改订单款退完了没
+ */
+ public function checkRefundNum($order_id){
+
+ $order_goods_model = new OrderGoods();
+
+ $order_refund_goods_model = new RefundOrderGoods();
+
+ $order_model = new Order();
+
+ $dis = [
+
+ 'order_id' => $order_id
+ ];
+
+ $goods_num = $order_goods_model->where($dis)->sum('num');
+
+ $dis['status'] = 2;
+
+ $refund_num= $order_refund_goods_model->where($dis)->sum('num');
+
+ return $refund_num>=$goods_num?1:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 15:38
+ * @功能说明:该天的退款
+ */
+ public function datePrice($date,$uniacid,$cap_id=0,$end_time='',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('refund_price');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 13:33
+ * @功能说明:申请退款
+ */
+ public function applyRefund($order,$input){
+
+ $order_goods_model = new OrderGoods();
+
+ $refund_price = 0;
+
+ Db::startTrans();
+
+ $list = $input['list'];
+
+
+ foreach ($list as $k=>$value){
+
+ if(!empty($value['id'])){
+
+ $order_goods = $order_goods_model->dataInfo(['id'=>$value['id']]);
+
+
+ if(empty($order_goods)){
+
+ return ['code'=>500,'msg'=>'商品未找到'];
+ }
+
+ if($value['num']>$order_goods['can_refund_num']||$value['num']==0){
+
+ return ['code'=>500,'msg'=>'退款数量错误'];
+
+ }
+ //退款金额
+ $refund_price += $order_goods['true_price']*$value['num'];
+
+ $list[$k]['goods_id'] = $order_goods['goods_id'];
+
+ $list[$k]['goods_name'] = $order_goods['goods_name'];
+
+ $list[$k]['goods_cover'] = $order_goods['goods_cover'];
+
+ $list[$k]['goods_price'] = $order_goods['goods_price'];
+
+ $list[$k]['circle'] = $order_goods['circle'];
+
+ $res = $order_goods_model->where(['id'=>$value['id']])->update(['can_refund_num'=>$order_goods['can_refund_num']-$value['num']]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+ }
+ }
+
+ $car_price = 0;
+
+ if($refund_price<=0){
+
+// Db::rollback();
+//
+// return ['code'=>500,'msg'=>'退款金额至少为0.01元'];
+ }
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'total_circle' => $order['total_circle'],
+
+ 'order_code' => orderCode(),
+
+ 'apply_price'=> round($refund_price,2),
+
+ 'service_price'=> $refund_price,
+
+ 'order_id' => $order['id'],
+
+ 'text' => $input['text'],
+
+ 'car_price' => $car_price,
+
+ 'imgs' => !empty($input['imgs'])?implode(',',$input['imgs']):'',
+
+ 'balance' => !empty($order['balance'])?$refund_price:0,
+
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ $refund_id = $this->getLastInsID();
+
+ $refund_goods_model = new RefundOrderGoods();
+
+ foreach ($list as $value){
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'order_id' => $order['id'],
+
+ 'refund_id' => $refund_id,
+
+ 'order_goods_id' => $value['id'],
+
+ 'goods_id' => $value['goods_id'],
+
+ 'goods_name' => $value['goods_name'],
+
+ 'goods_cover' => $value['goods_cover'],
+
+ 'num' => $value['num'],
+
+ 'goods_price' => $value['goods_price'],
+
+ 'circle' => $value['circle'],
+
+ 'status' => 1,
+ ];
+
+ $res = $refund_goods_model->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $refund_id;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 09:23
+ * @功能说明:获取订单已经退款的数量
+ */
+ public function refundNum($order_goods_id){
+
+ $dis = [
+
+ 'b.order_goods_id' => $order_goods_id,
+
+ 'a.status' => 2
+ ];
+
+ $num = $this->alias('a')
+ ->join('massage_service_refund_order_goods b','a.id = b.refund_id')
+ ->where($dis)
+ ->group('b.order_goods_id')
+ ->sum('b.num');
+
+ return $num;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 12:04
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund($refund_id){
+
+ $dis = [
+
+ 'id' => $refund_id
+ ];
+
+ $refund_order = $this->dataInfo($dis);
+
+ if($refund_order['status']!=1){
+
+ return ['code'=>500,'msg'=>'退款状态错误'];
+
+ }
+
+ $update = [
+
+ 'status' => 3,
+
+ 'refund_time' => time()
+
+ ];
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate($dis,$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试'];
+
+ }
+ //修改退款子订单的退款状态
+ $order_refund_goods = new RefundOrderGoods();
+
+ $res = $order_refund_goods->dataUpdate(['refund_id'=>$refund_id],['status'=>3]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试'];
+
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/RefundOrderGoods.php b/app/massage/model/RefundOrderGoods.php
new file mode 100755
index 0000000..f76f422
--- /dev/null
+++ b/app/massage/model/RefundOrderGoods.php
@@ -0,0 +1,89 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataSelect($dis){
+
+ $data = $this->where($dis)->order('id desc')->select()->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/SynMember.php b/app/massage/model/SynMember.php
new file mode 100755
index 0000000..3d0a2ab
--- /dev/null
+++ b/app/massage/model/SynMember.php
@@ -0,0 +1,185 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 14:33
+ * @功能说明:
+ */
+ public function datePrice($date,$uniacid,$cap_id,$end_time='',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('true_cash');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 16:06
+ * @功能说明:
+ */
+ public function adminList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_coach_list b','a.coach_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.coach_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:36
+ * @功能说明:团长提现
+ */
+ public function capCash($cap_id,$status=2,$type=0){
+
+ $dis = [
+
+ 'coach_id' => $cap_id,
+
+ 'status' => $status
+ ];
+
+ if(!empty($type)){
+
+ $dis['type'] = $type;
+ }
+
+ $price = $this->where($dis)->sum('apply_price');
+
+ return round($price,2);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:36
+ * @功能说明:团长提现
+ */
+ public function capCashCount($cap_id,$status=2){
+
+ $dis = [
+
+
+ 'cap_id' => $cap_id,
+
+ 'status' => $status
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/User.php b/app/massage/model/User.php
new file mode 100755
index 0000000..0ba8d09
--- /dev/null
+++ b/app/massage/model/User.php
@@ -0,0 +1,553 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page,$mapor=[]){
+
+ $data = $this->where($dis)->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-10-27 15:42
+ * @功能说明:订单自提码
+ */
+ public function orderQr($input,$uniacid){
+
+ $data = longbingCreateWxCode($uniacid,$input,$input['page']);
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+ $qr = $data['qr_path'];
+
+ return $qr;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-27 15:14
+ * @功能说明:向银豹同步积分和余额
+ */
+ public function synBalanceAndPoint($user){
+
+ if(empty($user['customer_uid'])){
+
+ return false;
+ }
+ //余额
+ $balance = $this->where(['id'=>$user['id']])->value('balance');
+ //积分
+ $integral= $this->where(['id'=>$user['id']])->value('integral');
+
+ if($balance<=0||$integral<=0){
+
+ return false;
+ }
+
+ $data = [
+
+ 1 => $balance,
+
+ 2 => $integral
+ ];
+
+ $log = new Log();
+
+ $api = new PospalApi();
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$user['id']],['balance'=>0,'integral'=>0]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'同步失败'];
+ }
+ //增加日志
+ foreach ($data as $k=>$v){
+
+ if(!empty($v)){
+
+ $insert = [
+
+ 'uniacid' => $user['uniacid'],
+
+ 'user_id' => $user['id'],
+
+ 'customer_uid' => $user['customer_uid'],
+
+ 'type' => $k,
+
+ 'value' => $v,
+
+ ];
+
+ $log->dataAdd($insert);
+ }
+
+ }
+ //修改银豹的积分余额
+ $res = $api->updateMemberCash($user['customer_uid'],$balance,$integral);
+
+ if($res['status']){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>$res['messages'][0]];
+
+ }
+
+ Db::commit();
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 13:51
+ * @功能说明:同步会员到本地
+ */
+ public function synMemberList($uniacid=1,$update=0){
+
+ $key = 'syn_member';
+
+ $lock = getCache($key,$uniacid);
+
+ setCache($key,1,60,$uniacid);
+
+ if(!empty($lock)&&$update==0){
+
+ return false;
+ }
+
+ $api_model = new PospalApi();
+
+ $member_model = new SynMember();
+
+ $check = 1;
+
+ $post_data = [];
+
+ $member_model->where(['uniacid'=>$uniacid])->delete();
+
+ while ($check==1){
+
+ $data = $api_model->getMemberList($post_data);
+
+ if($data['status']!='success'){
+
+ return [];
+ }
+
+ $pageSize = $data['data']['pageSize'];
+
+ $count = count($data['data']['result']);
+ //可能有第二页
+ if($count>=$pageSize){
+
+ $post_data = $data['postBackParameter'];
+
+ }else{
+
+ $check = 0;
+ }
+
+ if(!empty($data['data']['result'])){
+
+ foreach ($data['data']['result'] as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uid' => $v['customerUid'],
+
+ 'member_name' => $v['categoryName'],
+
+ 'number' => $v['number'],
+
+ 'name' => $v['name'],
+
+ 'phone' => $v['phone'],
+
+ 'discount' => $v['discount'],
+
+ 'balance' => $v['balance'],
+
+ 'point' => $v['point'],
+
+ ];
+
+
+ }
+
+ $member_model->saveAll($insert);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-08 16:46
+ * @功能说明:同步会员余额积分
+ */
+ public function synMemberCash($uniacid,$user_id){
+ //查询所有
+ $this->synMemberList($uniacid,1);
+
+ $member_model = new SynMember();
+
+ $dis = [
+
+ 'uid' => $user_id
+ ];
+
+ $data = $member_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ return ['code'=>500,'msg'=>'请先绑定会员'];
+
+ }
+
+ if(empty($data['balance'])&&empty($data['point'])){
+
+ return ['code'=>500,'msg'=>'你暂无可同步的余额和积分'];
+
+ }
+
+ $api_model = new PospalApi();
+
+ Db::startTrans();
+ //扣除银豹平台的余额积分
+ $res = $api_model->updateMemberCash($user_id,$data['balance']*-1,$data['point']*-1);
+
+ if($res['status']!='success'){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>$res['messages'][0]];
+
+ }
+
+ $res = $member_model->dataUpdate($dis,['balance'=>0,'point'=>0]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'同步失败'];
+
+ }
+ //给用户加余额积分
+ $user_model = new User();
+
+ $user = $user_model->dataInfo(['customer_uid'=>$user_id]);
+
+ $update = [
+
+ 'balance' => $user['balance']+$data['balance'],
+
+ ];
+
+ $res = $user_model->dataUpdate(['customer_uid'=>$user_id],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'同步失败'];
+
+ }
+ //增加余额日志
+ if(!empty($data['balance'])){
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $user['id'],
+
+ 'type' => 5,
+
+ 'add' => 1,
+
+ 'price' => $data['balance'],
+
+ 'before_balance' => $user['balance'],
+
+ 'after_balance' => $user['balance']+$data['balance']
+ ];
+
+ $water_model = new BalanceWater();
+
+ $water_model->dataAdd($insert);
+ }
+ //增加积分日志
+ if(!empty($data['point'])){
+
+ $i_model = new Integral();
+
+ $i_model->integralUserAdd($user['id'],$data['point'],$uniacid,2,7);
+
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-27 16:08
+ * @功能说明:初次同步会员信息
+ */
+ public function getMemberInfoOne($user,$member_code){
+
+// if(!empty($user['customer_uid'])){
+//
+// return ['code'=>500,'msg'=>'你已经同步过了'];
+// }
+
+ Db::startTrans();
+
+ $member_model = new SynMember();
+
+ $member_model->where(['user_id'=>$user['id']])->update(['user_id'=>0]);
+
+ $member = $member_model->dataInfo(['uid'=>$member_code]);
+
+ if(empty($member)){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'未找到会员'];
+
+ }
+
+ if(!empty($member['user_id'])){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'该会员卡正在被别人使用'];
+
+ }
+
+ $member_model->where(['uid'=>$member_code])->update(['user_id'=>$user['id']]);
+
+ $level_model = new Level();
+ //会员等级
+ $level = $level_model->levelInfo(['title'=>$member['member_name']]);
+
+ $update = [
+
+ 'member_id' => $member['number'],
+
+ 'customer_uid' => $member['uid'],
+
+ 'member_level' => !empty($level)?$level['id']:0,
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$user['id']],$update);
+ //给会员权益
+ if(!empty($level['id'])){
+
+ $rights_model = new Rights();
+
+ $rights_model->giveRights($level['id'],$user['id']);
+
+ }
+
+ Db::commit();
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-27 16:24
+ * @功能说明:同步会员 修改积分余额
+ */
+ public function getMemberCashAndPoint($user){
+
+ if(empty($user['customer_uid'])){
+
+ return false;
+ }
+
+ $api = new PospalApi();
+ //根据会员号获取会员信息
+ $member = $api->getMemberCode($user['customer_uid']);
+
+ if(empty($member['data'])){
+
+ return false;
+ }
+
+ $update = [
+
+ 'pal_balance' => $member['data']['balance'],
+
+ 'pal_point' => $member['data']['point'],
+ ];
+
+ $res = $this->dataUpdate(['id'=>$user['id']],$update);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-27 16:40
+ * @功能说明:向银豹同步会员信息 然后银豹再向本地同步会员
+ */
+ public function synMember($user){
+ //向银豹同步
+ $this->synBalanceAndPoint($user);
+ //银豹向本地同步
+ $this->getMemberCashAndPoint($user);
+
+ return true;
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/model/Wallet.php b/app/massage/model/Wallet.php
new file mode 100755
index 0000000..ce4a96a
--- /dev/null
+++ b/app/massage/model/Wallet.php
@@ -0,0 +1,206 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 14:33
+ * @功能说明:
+ */
+ public function datePrice($date,$uniacid,$cap_id,$end_time='',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('true_cash');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 16:06
+ * @功能说明:
+ */
+ public function adminList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('massage_service_coach_list b','a.coach_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.coach_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:36
+ * @功能说明:团长提现
+ */
+ public function capCash($cap_id,$status=2,$type=0){
+
+ $dis = [
+
+
+ 'coach_id' => $cap_id,
+
+ 'status' => $status
+ ];
+
+ if(!empty($type)){
+
+ $dis['type'] = $type;
+ }
+
+ $price = $this->where($dis)->sum('apply_price');
+
+ return round($price,2);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:36
+ * @功能说明:团长提现
+ */
+ public function capCashCount($cap_id,$status=2){
+
+ $dis = [
+
+
+ 'cap_id' => $cap_id,
+
+ 'status' => $status
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/massage/route/route.php b/app/massage/route/route.php
new file mode 100755
index 0000000..e3a808b
--- /dev/null
+++ b/app/massage/route/route.php
@@ -0,0 +1,512 @@
+model = new model();
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 11:21
+ * @功能说明:会员配置详情
+ */
+ public function configInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->configInfo($dis);
+
+ if(!empty($data['commission_user'])){
+
+ $data['commission_user'] = array_values(explode(',',$data['commission_user']));
+
+ }
+
+ if(empty($data)){
+
+ $this->errorMsg('数据未找到');
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:24
+ * @功能说明:配置编辑
+ */
+ public function configUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ if(!empty($input['commission_user'])){
+
+ $input['commission_user'] = implode(',',$input['commission_user']);
+ }
+// dump($input);exit;
+ $data = $this->model->configUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-10 09:43
+ * @功能说明:佣金下拉框
+ */
+ public function commissionSelect(){
+
+ $level_model = new Level();
+
+ $dis = [
+
+ 'status' => 1,
+
+ 'uniacid'=> $this->_uniacid
+ ];
+
+ $level = $level_model->where($dis)->field(['top'=>'value','title'=>'name'])->select()->toArray();
+
+ $arr = [
+
+ ['value'=>1000,'name'=>'全部'],
+
+ ['value'=>888,'name'=>'员工'],
+
+ ['value'=>777,'name'=>'普通用户'],
+
+ ];
+
+ $arr = array_merge($arr,$level);
+
+ return $this->success($arr);
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/controller/AdminLevel.php b/app/member/controller/AdminLevel.php
new file mode 100755
index 0000000..bbd2ae7
--- /dev/null
+++ b/app/member/controller/AdminLevel.php
@@ -0,0 +1,372 @@
+model = new model();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-26 16:48
+ * @功能说明:远程同步会员等级
+ */
+ public function synLevel(){
+
+ $api = new PospalApi();
+
+ $data = $api->getMemberLevel();
+
+ if($data['status']!='success'){
+
+ $this->errorMsg($data['messages'][0]);
+ }
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as $k=> &$v){
+
+ $insert['uniacid'] = $this->_uniacid;
+
+ $insert['title'] = $v['name'];
+
+ $insert['discount']= $v['discount'];
+
+ $insert['is_point']= $v['isPoint'];
+
+ $insert['status'] = $v['enable'];
+
+ $insert['uid'] = $v['uid'];
+
+ $find = $this->model->where(['uid'=>$v['uid']])->find();
+
+ if(empty($find)){
+
+ $this->model->insert($insert);
+
+ }else{
+
+ $this->model->where(['uid'=>$v['uid']])->update($insert);
+ }
+
+ }
+
+ }
+
+ return $this->success(true);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 10:49
+ * @功能说明:会员等级列表
+ */
+ public function levelList(){
+
+ $rights_model = new Rights();
+
+ $rights_model->initData($this->_uniacid);
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ // 'type' => $type
+ ];
+
+ $data = $this->model->levelList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-28 10:22
+ * @功能说明:会员等级下拉框
+ */
+ public function levelSelectV2(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $data = $this->model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 11:21
+ * @功能说明:会员等级详情
+ */
+ public function levelInfo(){
+
+// $rights_model = new Rights();
+
+// $rights_model->initData($this->_uniacid);
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->levelInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('数据未找到');
+ }
+ //权益模型
+ $rights = new RightsRelation();
+ //优惠券
+ $coupon_model= new Coupon();
+
+ $dis = [
+
+ 'member_id' => $data['id']
+ ];
+ //优惠券
+ $data['coupon'] = $coupon_model->where($dis)->select()->toArray();
+
+ $data['coupon'] = array_values($data['coupon']);
+
+ if(!empty($data['coupon'])){
+
+ $coupon_models = new \app\massage\model\Coupon();
+
+ foreach ($data['coupon'] as &$vs){
+
+ $vs['title'] = $coupon_models->where(['id'=>$vs['coupon_id']])->value('title');
+ }
+
+
+ }
+// $dis['type'] = 1;
+ //权益
+ $data['rights'] = $rights->where($dis)->column('rights_id');
+
+ $data['rights'] = array_values($data['rights']);
+
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:24
+ * @功能说明:
+ */
+ public function levelUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->model->levelUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-17 13:42
+ * @功能说明:会员商品
+ */
+ public function memberGoods(){
+
+ $input = $this->_param;
+// //商品
+// $data['goods'] = $this->model->memberGoods($this->_uniacid,$input['id']);
+// //储值
+// $data['stored'] = $this->model->storedSelect($this->_uniacid,$input['id']);
+ //自定义权益
+ $data['rights'] = $this->model->memberRights($this->_uniacid,1);
+ //默认权益
+ $data['defult_rights'] = $this->model->memberRights($this->_uniacid);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-22 18:08
+ * @功能说明:上下架
+ */
+
+ public function statusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['status'] = $input['status']==1?0:1;
+
+ Db::startTrans();
+
+ $level = $this->model->levelInfo($dis);
+
+ if($level['type']==0){
+
+ $code = $this->model->checkStatus($input['id'],$input['status']);
+
+ if($code['code']!=200){
+
+ $this->errorMsg($code['msg']);
+
+ }
+ }
+
+ $data = $this->model->where($dis)->update($input);
+
+ Db::commit();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-29 09:58
+ * @功能说明:等级下拉框
+ */
+ public function levelSelect(){
+
+ $dis = [
+
+ 'a.uniacid' => $this->_uniacid,
+
+ 'a.use_type'=> 1,
+
+ 'c.status' => 1
+ ];
+
+ $model = new Rights();
+
+ $data = $model->goodsLevelSelect($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 14:31
+ * @功能说明:会员等级列表选择
+ */
+ public function memberLevelSelect(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+
+ ];
+
+ $data = $this->model->where($dis)->order('top')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-07 14:45
+ * @功能说明:会员优惠券下拉框
+ */
+ public function memberCouponSelect(){
+
+ $input = $this->_param;
+
+ $coupon_model = new AdminCoupon();
+
+ $dis = [
+
+ 'status' => 1,
+
+ 'uniacid'=> $this->_uniacid,
+
+ 'send_type'=>2
+ ];
+
+ $where = [];
+
+ if(!empty($input['title'])){
+
+ $where[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $coupon_model->where($dis)->where($where)->order('top desc')->paginate($input['limit'])->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/controller/AdminMember.php b/app/member/controller/AdminMember.php
new file mode 100755
index 0000000..c4fd4f0
--- /dev/null
+++ b/app/member/controller/AdminMember.php
@@ -0,0 +1,450 @@
+model = new model();
+
+ $this->level_model = new Level();
+
+ $this->growth_model = new Growth();
+
+ $this->integral_model = new Integral();
+
+ $this->store_order_model = new StoredOrder();
+
+ $this->user_model = new User();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 10:49
+ * @功能说明:会员列表
+ */
+
+ public function memberList(){
+
+ $input = $this->_param;
+
+ // $this->model->memberInit($this->_uniacid);
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ //$member_growth = $this->level_model->memberGrowth($this->_uniacid);
+ //创建时间搜索
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['vip_time','between',"$start_time,$end_time"];
+ }
+ //等级搜索
+ if(!empty($input['level'])){
+
+ $dis[] = ['member_level','=',$input['level']];
+
+ }else{
+
+ $dis[] = ['member_level','>',0];
+
+ }
+ $where = [];
+ //昵称搜索
+ if(!empty($input['name'])){
+
+ $where[] = ['nickName','like','%'.$input['name'].'%'];
+
+ $where[] = ['phone','like','%'.$input['name'].'%'];
+
+ $where[] = ['id','=',$input['name']];
+
+
+ }
+ //储值查询
+ if(!empty($input['start_price'])&&!empty($input['end_price'])){
+
+ $start_price = $input['start_price'];
+
+ $end_price = $input['end_price'];
+
+ $dis[] = ['balance','between',"$start_price,$end_price"];
+
+ }
+
+ $data = $this->user_model->dataList($dis,$input['limit'],$where);
+
+ if(!empty($data['data'])){
+
+ $level_model = new Level();
+
+ foreach ($data['data'] as &$v){
+
+ $v['level_title'] = $level_model->where(['id'=>$v['member_level']])->value('title');
+
+ $list_form = $this->model->listForm($v['id']);
+
+ $v['order_price'] = $list_form['price'];
+
+ $v['order_count'] = $list_form['count'];
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 11:21
+ * @功能说明:会员等级详情
+ */
+ public function memberInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $level_model = new Level();
+
+ //用户信息
+ $data['user_info'] = $this->user_model->dataInfo($dis);
+
+ $data['user_info']['level_title'] = $level_model->where(['id'=> $data['user_info']['member_level']])->value('title');
+ //统计信息
+ $data['form_list'] = $this->model->listForm($input['id']);
+
+ $dis = [
+
+ 'user_id' => $input['id'],
+
+ ];
+
+ if($input['type']==1){
+ //积分记录
+ $data['data_list'] = $this->integral_model->integralList($dis,$input['limit']);
+
+ }elseif($input['type']==2){
+
+ $balance_model = new BalanceWater();
+ //储值明细
+ $data['data_list'] = $balance_model->indexList($dis,$input['limit']);
+
+ }
+
+ return $this->success($data);
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:24
+ * @功能说明:
+ */
+ public function statusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $member = $this->model->getMemberInfo($dis);
+
+ $status = $member['status']==1?0:1;
+
+ $data = $this->model->memberUpdate($dis,['status'=>$status]);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-29 10:14
+ * @功能说明:会员权限
+ */
+ public function memberAuth(){
+
+ $persisson = new PermissionMember($this->_uniacid);
+
+ $auth = $persisson->pAuth();
+
+ return $this->success($auth);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 15:41
+ * @功能说明:修改成长值
+ */
+ public function updateGrowth(){
+
+ $input = $this->_input;
+
+ $member = $this->model->memberInfo(['a.id'=>$input['id']]);
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $member['user_id'],
+
+ 'controller' => $this->_user['admin_id'],
+
+ 'growth_add' => $input['growth'],
+
+ 'growth_before' => $member['growth'],
+
+ 'growth_after' => $input['growth'],
+
+ 'status' => 2,
+
+ 'type' => 1,
+
+ 'controller_type' => 1
+ ];
+ //添加记录
+ $this->growth_model->growthAdd($insert);
+
+ $order = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $member['user_id'],
+
+ 'to_uid' => 0
+ ];
+ //给用户修改成长值
+ $res = $this->level_model->upUserRightsEnd(['growth'=>$input['growth']],$order);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-09-09 14:36
+ * @return \think\Response
+ * descption:佣金流水列表
+ */
+ public function waterList(){
+
+ $input = $this->_param;
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.nickName','like',"%{$input['name']}%"];
+
+ $where[] = ['g.phone','like',"%{$input['name']}%"];
+ }
+
+ if(!empty($input['thing_type'])){
+
+ $dis[] = ['a.thing_type','=',$input['thing_type']];
+
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+
+ }
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.thing_type','in',[1,2,3]];
+
+ $water_model = new \app\shop\model\AdminSellingWater();
+
+ $data = $water_model->storedWaterList($dis,$where,$this->_param['limit']);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-24 14:29
+ * @功能说明:出库导出
+ */
+ public function memberListExcel(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $where1 = [];
+ //创建时间搜索
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+ //等级搜索
+ if(!empty($input['level'])){
+
+ $growth_section = $this->level_model->getGrowth($input['level']);
+
+ $start_growth = $growth_section['start_growth'];
+
+ $end_growth = !empty($growth_section['end_growth'])?$growth_section['end_growth']-1:$growth_section['end_growth'];
+
+ $dis[] = !empty($end_growth)?['a.growth','between',"$start_growth,$end_growth"]:['a.growth','>',"$start_growth"];
+
+ }
+ $where = [];
+ //昵称搜索
+ if(!empty($input['name'])){
+
+ $where[] = ['b.nickName','like','%'.$input['name'].'%'];
+
+ $where[] = ['b.id','=',$input['name']];
+
+ }
+ //储值查询
+ if(!empty($input['start_price'])&&!empty($input['end_price'])){
+
+ $start_price = $input['start_price'];
+
+ $end_price = $input['end_price'];
+
+ $dis[] = ['a.stored','between',"$start_price,$end_price"];
+
+ }
+
+ $data = $this->model->memberList($dis,$where1,$where,100000000);
+
+ $name ='会员列表';
+
+ $header=[
+ 'ID',
+ '手机号码',
+ '用户昵称',
+ '会员等级',
+ '订单数量',
+ '消费金额',
+ '可用积分',
+ '当前成长值',
+ '储值余额',
+ '成为会员时间',
+ '会员有效期',
+
+ ];
+
+
+ $new_data = [];
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as $v){
+
+ if(!empty($v['level_content'])){
+
+ $over_time = !empty($v['over_time'])?date('Y-m-d H:i:s',$v['over_time']):'终生有效';
+ }else{
+
+ $over_time = '';
+ }
+
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = !empty($v['member_phone'])?$v['member_phone']:'';
+
+ $info[] = $v['nickName'];
+
+ $info[] = $v['level_content'];
+
+ $info[] = $v['order_num'];
+
+ $info[] = $v['price'];
+
+ $info[] = $v['integral'];
+
+ $info[] = $v['growth'];
+
+ $info[] = $v['stored'];
+
+ $info[] = !empty($v['level_content'])?date('Y-m-d H:i:s',$v['create_time']):'';
+
+ $info[] = $over_time;
+
+ $new_data[] = $info;
+
+ }
+
+ }
+
+ $excel_model = new Excel();
+ //返回数据
+ $fileName = $excel_model->excelExport($name,$header,$new_data);
+
+ return $this->success(1);
+
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/controller/AdminRights.php b/app/member/controller/AdminRights.php
new file mode 100755
index 0000000..02e76a5
--- /dev/null
+++ b/app/member/controller/AdminRights.php
@@ -0,0 +1,148 @@
+model = new model();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 10:49
+ * @功能说明:权益列表
+ */
+ public function rightsList(){
+
+ $this->model->initData($this->_uniacid);
+
+ $input = $this->_param;
+
+ $dis[] = [
+
+ 'uniacid' ,'=', $this->_uniacid
+ ];
+
+ $dis[] = ['status' ,'>', -1];
+
+ $data = $this->model->rightsList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 14:16
+ * @功能说明:添加权益
+ */
+ public function rightsAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->rightsAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 11:21
+ * @功能说明:权益详情
+ */
+ public function rightsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->rightsInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('数据未找到');
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:24
+ * @功能说明:
+ */
+ public function rightsUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->rightsUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:24
+ * @功能说明:上下架
+ */
+ public function rightsStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->rightsUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/controller/AdminStored.php b/app/member/controller/AdminStored.php
new file mode 100755
index 0000000..eaf7d6e
--- /dev/null
+++ b/app/member/controller/AdminStored.php
@@ -0,0 +1,334 @@
+model = new model();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-09 10:35
+ * @功能说明:列表
+ */
+ public function storedList(){
+
+ $input = $this->_input;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->model->storedList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-09 10:41
+ * @功能说明:储值添加
+ */
+ public function storedAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->storedAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 11:21
+ * @功能说明:会员配置详情
+ */
+ public function storedInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->storedInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('数据未找到');
+ }
+
+ $coupon_model = new StoredCoupon();
+
+ $data['coupon'] = $coupon_model->where(['stored_id'=>$input['id']])->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:24
+ * @功能说明:配置编辑
+ */
+ public function storedUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->model->storedUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-09 13:39
+ * @功能说明:下拉框
+ */
+ public function storedSelect(){
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $data = $this->model->storedSelect($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-16 11:09
+ * @功能说明:员工扣款
+ */
+ public function staffDeduction(){
+
+ $input = $this->_input;
+
+ $member_model = new Member();
+ //查看会员信息
+ $member_info = $member_model->memberUpdateInfo(['user_id'=>$input['id']]);
+
+ $type = !empty($input['type'])?$input['type']:1;
+ //判断余额
+ if($input['price']>$member_info['stored']&&$type!=4){
+
+ $this->errorMsg('储值不足');
+ }
+
+ $order_model = new StoredOrder();
+
+ $res = $order_model->desStore($input['price'],$input['content'],$member_info,$type,$this->_user['admin_id']);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-12-01 11:23
+ * @功能说明:用户提现记录
+ */
+ public function userCashList()
+ {
+ $input = $this->_input;
+
+ $cash_model = new CashRecord();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['b.nickName','like','%'.$input['name'].'%'];
+ }
+
+
+ $data = $cash_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-30 19:08
+ * @功能说明:同意申请打款
+ */
+ public function cashPass(){
+
+ $input = $this->_input;
+
+ $cash_model = new CashRecord();
+
+ $record = $cash_model->dataInfo(['id'=>$input['id']]);
+
+ if($record['status']!=1){
+
+ $this->errorMsg('状态错误');
+ }
+
+ $update = [
+
+ 'status' => 2,
+
+ 'hx_time'=> time(),
+
+ 'hx_user'=> $this->_user['admin_id'],
+
+ 'type' => $input['type']
+ ];
+ Db::startTrans();
+
+ $res = $cash_model->where(['id'=>$input['id']])->update($update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('审核失败');
+
+ }
+
+ if($input['type']==1){
+
+ $openid = Db::name('longbing_card_user')->where(['id'=>$record['user_id']])->value('openid');
+ //微信相关模型
+ $wx_pay = new WxPay($this->_uniacid);
+ //微信提现
+ $res = $wx_pay->crteateMchPay($openid,$record['true_price']);
+
+ if($res['result_code']=='SUCCESS'&&$res['return_code']=='SUCCESS'){
+ //if(1==1){
+
+ }else{
+
+ Db::rollback();
+
+ return $this->error(!empty($res['err_code_des'])?$res['err_code_des']:'你还未该权限');
+
+ }
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-30 19:08
+ * @功能说明:不同意申请打款
+ */
+ public function cashNoPass(){
+
+ $input = $this->_input;
+
+ $cash_model = new CashRecord();
+
+ $record = $cash_model->dataInfo(['id'=>$input['id']]);
+
+ if($record['status']!=1){
+
+ $this->errorMsg('状态错误');
+ }
+
+ $update = [
+
+ 'status' => -1,
+
+ 'hx_time'=> time(),
+
+ 'hx_user'=> $this->_user['admin_id']
+
+ ];
+
+ Db::startTrans();
+
+ $res = $cash_model->where(['id'=>$input['id']])->update($update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('审核失败');
+
+ }
+
+ $member_model= new Member();
+
+ $order_model = new StoredOrder();
+
+ $member_info = $member_model->memberUpdateInfo(['user_id'=>$record['user_id']]);
+
+ $record_id = $input['id'];
+ //添加提现记录并且退还余额
+ $res = $order_model->desStore($record['true_price'],'',$member_info,8,$this->_user['admin_id'],'',$record_id);
+
+ if($res!=1){
+
+ $this->errorMsg('申请失败');
+ }
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/controller/IndexMember.php b/app/member/controller/IndexMember.php
new file mode 100755
index 0000000..a761139
--- /dev/null
+++ b/app/member/controller/IndexMember.php
@@ -0,0 +1,275 @@
+model = new model();
+
+ $this->config_model = new Config();
+
+ $this->level_model = new Level();
+
+ $this->rights_model = new Rights();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-06 17:52
+ * @功能说明:个人中心的会员信息
+ */
+ public function userMember(){
+
+ $persisson = new PermissionMember($this->_uniacid);
+
+ $auth = $persisson->pAuth();
+
+ $config = $this->config_model->configInfo(['uniacid'=>$this->_uniacid]);
+ //权限
+ $data['auth'] = $config['status']==1?$auth:false;
+ //会员等级
+ $data['level'] = $this->level_model->getUserLevel($this->getUserId(),$this->_uniacid);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 09:41
+ * @功能说明:会员信息
+ */
+ public function memberInfo(){
+ //用户会员相关信息
+ $data['user_info'] = $this->model->userInfo($this->getUserId(),$this->_uniacid);
+ //权益模型
+ $rights_model = new Rights();
+ //当前等级的id
+ $level_id = !empty($data['user_info']['now_level']['id'])?$data['user_info']['now_level']['id']:0;
+ //权益
+ $data['rights'] = $rights_model->memberRights($level_id,$this->_uniacid);
+ //配置
+ $data['config'] = $this->config_model->configInfo(['uniacid'=>$this->_uniacid]);
+ //plus会员
+ $data['plus'] = $this->level_model->getPlusLvel($this->_uniacid);
+
+ $store_model = new Stored();
+
+ $goods_model = new Goods();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+ //储值套餐
+ $store = $store_model->storedInfo($dis);
+
+ $data['is_store'] = !empty($store)?1:0;
+ //可以购买的商品
+ $can_bug = $goods_model->getCanBuyGoods($this->getUserId(),$this->_uniacid);
+
+ $data['is_goods'] = !empty($can_bug)?1:0;
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 15:26
+ * @功能说明:等级详情
+ */
+ public function levelInfo(){
+
+ $dis = [
+
+ 'b.id' => $this->getUserId()
+
+ ];
+ $level_model = new Level();
+
+ $growth_model= new Growth();
+ //用户信息
+ $user_info = $this->model->memberInfoIndex($dis);
+ //下一级会员等级
+ $next_level = $level_model->getMemberLevel($this->_uniacid,$user_info['growth']);
+ //下一等级的成长值
+ $next_growth = !empty($next_level)?$next_level['growth']:$user_info['growth'];
+ //当前数据
+ $data['growth'][0] = [
+
+ 'data' => $user_info['growth'],
+
+ 'name' => '当前成长值',
+
+ 'rate' => round($user_info['growth']/$next_growth*100,2)
+
+ ];
+ //下一级
+ $data['growth'][1] = [
+
+ 'data' => $next_growth-$user_info['growth'],
+
+ 'name' => '升级',
+
+ 'rate' => round(($next_growth-$user_info['growth'])/$next_growth*100,2)
+ ];
+ //待结算金额
+ $data['settled_growth'] = $growth_model->settledGrowth($this->_uniacid,$this->getUserId());
+ //下级标题
+ $data['next_level_title'] = !empty($next_level)?$next_level['title']:'';
+ //配置
+ $data['config'] = $this->config_model->configInfo(['uniacid'=>$this->_uniacid]);
+
+ $now_level = $level_model->getUserLevel($this->getUserId(),$this->_uniacid);
+
+ $data['top'] = !empty($now_level)?$now_level['top']:0;
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 16:59
+ * @功能说明:会员等级列表
+ */
+ public function levelList(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ $user_model = new User();
+ //等级列表
+ $data = $this->level_model->where($dis)->order('top')->select()->toArray();
+ //当前等级
+ $now_level = $user_model->where(['id'=>$this->getUserId()])->value('member_level');
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>&$v){
+ //下一级的成长值
+ $v['next_growth'] = !empty($data[$k+1]['growth'])?$data[$k+1]['growth']:'';
+ //当前等级
+ $v['now_level'] = !empty($now_level)&&$v['id']==$now_level?1:0;
+ //权益
+ $v['rights'] = $this->rights_model->memberRights($v['id'],$v['uniacid']);
+
+ }
+
+ }
+
+ $list['data'] = $data;
+ //配置
+ $list['config'] = $this->config_model->configInfo(['uniacid'=>$this->_uniacid]);
+
+ return $this->success($list);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 16:54
+ * @功能说明:权益详情
+ */
+ public function rightsInfo(){
+
+ $input = $this->_input;
+
+ $data = $this->rights_model->rightsInfo(['id'=>$input['id']]);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 16:57
+ * @功能说明:会员配置
+ */
+ public function memberConfig(){
+
+ $data = $this->config_model->configInfo(['uniacid'=>$this->_uniacid]);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-10 17:52
+ * @功能说明:会员二维码
+ */
+ public function memberQr(){
+
+ $input = $this->_input;
+
+ // $qr = getCache($this->getUserId()."-member_qr",$this->_uniacid);
+
+// if(empty($qr)){
+
+ $input['id'] = $this->getUserId();
+
+ $data = longbingCreateWxCode($this->_uniacid,$input,$input['page']);
+
+ $data = transImagesOne($data ,['qr_path'] ,$this->_uniacid);
+
+ $qr = $data['qr_path'];
+
+ // setCache($this->getUserId()."-member_qr",$qr,864000,$this->_uniacid);
+// }
+ return $this->success($qr);
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/controller/IndexStored.php b/app/member/controller/IndexStored.php
new file mode 100755
index 0000000..b5c5519
--- /dev/null
+++ b/app/member/controller/IndexStored.php
@@ -0,0 +1,340 @@
+model = new model();
+
+ $this->config_model = new Config();
+
+ $this->level_model = new Level();
+
+ $this->rights_model = new Rights();
+
+ $this->order_model = new StoredOrder();
+
+ $this->member_model = new Member();
+
+ $this->share_coupon_model = new ShareCoupon();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-10 17:44
+ * @功能说明:储值列表
+ */
+ public function storedList(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $data = $this->model->storedList($dis,10);
+
+ $member_model = new Member();
+
+ $data['user_info'] = $member_model->userInfo($this->getUserId(),$this->_uniacid);
+
+ $overlord = new PermissionOverlord($this->_uniacid);
+
+ $data['user_info']['overlord_auth'] = $overlord->pAuth();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 17:46
+ * @功能说明:储值详情
+ */
+ public function storedInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->storedInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-10 17:50
+ * @功能说明:
+ */
+ public function payOrder(){
+
+ $input = $this->_input;
+ //分享人
+ $share_id = !empty($input['share_id'])?$input['share_id']:0;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->model->storedInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('充值卡已下架');
+ }
+ //下单
+ $order = $this->order_model->addOrder($data,$this->getUserId(),$input['staff_id'],$share_id);
+
+ $pay_controller = new IndexWxPay($this->app);
+
+ $user = $this->getUserInfo();
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$user['openid'],$this->_uniacid,"储值充值",['type' => 'storedPay' , 'out_trade_no' => $order['order_code']],$order['pay_price']);
+
+ return $this->success($jsApiParameters);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-15 16:23
+ * @功能说明:
+ */
+ public function storedMemberInfo(){
+
+ $input = $this->_input;
+
+ $dis= [
+
+ 'b.id' => $input['id']
+ ];
+
+ $data = $this->member_model->memberInfoIndex($dis);
+ //说明是plus会员
+ if($data['over_time']>time()){
+
+ $data['member_title'] = $this->level_model->where(['top'=>999,'uniacid'=>$this->_uniacid])->value('title');
+
+ }else{
+ //普通会员
+ $level = $this->level_model->getUserLevel($input['id'],$this->_uniacid);
+
+ $data['member_title'] = !empty($level)?$level['title']:'';
+ }
+ //电话
+ $data['member_phone'] = Db::name('longbing_card_user_phone')->where(['user_id'=>$input['id']])->value('phone');
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-16 11:09
+ * @功能说明:员工扣款
+ */
+ public function staffDeduction(){
+
+ $input = $this->_input;
+
+ if($this->getUserInfo()['is_staff']!=1){
+
+ $this->errorMsg('只有员工才能扣款哦');
+ }
+
+ if(!isset($input['time'])||$input['time']+600errorMsg('支付码已过期,请重新生成');
+
+ }
+ //查看会员信息
+ $member_info = $this->member_model->memberUpdateInfo(['user_id'=>$input['id']]);
+ //判断余额
+ if($input['price']>$member_info['stored']){
+
+ $this->errorMsg('储值不足');
+ }
+
+ $res = $this->order_model->desStore($input['price'],$input['content'],$member_info,2,$this->getUserId());
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-16 15:31
+ * @功能说明:储值记录
+ */
+ public function orderList(){
+
+ $input = $this->_input;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $dis[] = ['status','=',2];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+
+ }
+
+ $data = $this->order_model->recordList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-30 18:32
+ * @功能说明:申请提现
+ */
+ public function applyTx(){
+
+ $input = $this->_input;
+ //查看会员信息
+ $member_info = $this->member_model->memberUpdateInfo(['user_id'=>$this->getUserId()]);
+ //判断余额
+ if($input['price']>$member_info['stored']||$input['price']>$member_info['cash_stored']){
+
+ $this->errorMsg('储值不足');
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'apply_price' => $input['price'],
+
+ 'true_price' => $input['price'],
+
+ 'create_time' => time(),
+
+ 'status' => 1,
+
+ 'wx_code' => $input['wx_code']
+ ];
+
+ $cash_model = new CashRecord();
+
+ Db::startTrans();
+
+ $res = $cash_model->insert($insert);
+
+ if($res!=1){
+
+ $this->errorMsg('申请失败');
+ }
+
+ $record_id = $cash_model->getLastInsID();
+ //添加提现记录并且减掉余额
+ $res = $this->order_model->desStore($insert['apply_price'],'',$member_info,7,$this->getUserId(),'',$record_id);
+
+ if($res!=1){
+
+ $this->errorMsg('申请失败');
+ }
+
+ Db::commit();
+
+ return $this->success(1);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-12-01 11:23
+ * @功能说明:用户提现记录
+ */
+ public function userCashList()
+ {
+ $input = $this->_input;
+
+ $cash_model = new CashRecord();
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['b.nickName','like','%'.$input['name'].'%'];
+ }
+
+ $data = $cash_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/member/info/AdminMenu.php b/app/member/info/AdminMenu.php
new file mode 100755
index 0000000..ab6bfcb
--- /dev/null
+++ b/app/member/info/AdminMenu.php
@@ -0,0 +1,615 @@
+ $menu];
+
+
diff --git a/app/member/info/Info.php b/app/member/info/Info.php
new file mode 100755
index 0000000..3cf0a69
--- /dev/null
+++ b/app/member/info/Info.php
@@ -0,0 +1,35 @@
+ 'member',
+ //模块标题[必填]
+ 'title' =>'等级会员',
+ //内容简介
+ 'desc' =>'新用户成本高?存量用户分层服务,最大化企业收益',
+ //封面图标
+ 'icon' =>'data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABTAAD/4QOJaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OURDMDUxMzY2ODMxMTFFQTkzMDFBQjU5OTE3MDVEM0IiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTc4NUQ2ODFEODgxMTFFQUE0NzhEMTBFREY1RDFGRTgiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTc4NUQ2ODBEODgxMTFFQUE0NzhEMTBFREY1RDFGRTgiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MmZkNWUzNzMtNzFkNS05ZjQyLTkyYWYtZWMwY2EwYmU4YjRkIiBzdFJlZjpkb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6MDY5OTM5YTUtODNiMy0xMWVhLTk0YTAtY2JjNzZlNGQ2OGMyIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQAAgEBAQIBAgICAgMCAgIDAwMCAgMDBAMDAwMDBAUEBAQEBAQFBQYGBwYGBQgICQkICAwLCwsMDAwMDAwMDAwMDAECAgIEBAQIBQUICwkHCQsNDQ0NDQ0NDAwMDAwNDQwMDAwMDA0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgAPAA8AwERAAIRAQMRAf/EAJ8AAQACAwEBAAAAAAAAAAAAAAAICQUGBwQBAQEAAwADAQAAAAAAAAAAAAAAAgMGAQQFBxAAAQIEAwYDBQMNAAAAAAAAAQIDABEEBRIGByExIhMUCEEyFVFCFhcJklMYcWJyIzNjc4OTJEUoGREAAgECAwUFBAsAAAAAAAAAAAECEQMhBAUxQWESE/BRobEUcYHRBpHB4SIyQsLiQyQW/9oADAMBAAIRAxEAPwCXne93wZ9zvny52WyXN635LoHnKWlpaVxTQuYaVhVU1KkyK0uETQg7AmWzFMn6Xoui27NtSmqzeOO7gi2MSOsaAkIAQAgBAGWyZnrOeXb61c7FdKq0V7Bm3V0jy2XB7QSgiYO4g7CNhiq9YhcjyzSa4gmp/wBTLp+EzrZU/wAyOq9Kw8scnDyuZ6ryZYJYeHBu5m3Dg4Yxv+YXqqfxUr+3tu4kOTEgrG3JiAEAIAQAgBACZlACAM5prp9mPNefbTly0Nc243ipbp6ZJ8qSs8TiyNyUJBUo+ABinM5iNq25y2JBsuD0a0dyfkjTa1ZatLCBTW1lKHHy2lLlS+RN2odlvU4qaj7Nw2AR8kzmbneuOctr8OBS2bP0tN92n7IjrVZwOlpvu0/ZEKsESfqmdsFNetP0Z9s9KlN2y4jDektoAVVWwn9oqQ2qp1bf0CqflEav5Y1NwudGTwls4P7fMnBld8b8sEAIA2HSnUzNGTdRLTmazOJbuVoe5zGMYm1hSShxtY2EpWhSkmRnIxRmstG9bduWxhotv0M1+yfn/SWnzXZErcSptYrLYCF1NNWMpm5SqGwFUyMJ2YgQdxj5TnshOxd6cvp713lLVDC9rXddkvVHLte/R0rtnu9ofLN2sNSsLqKeZPLcBATiSqRG4EKBBG4m7U9LnlpJN1i9jDVD5kLu1yFmbuDvWQLLS1NcuwUrj1wvzeE0Cahl1DTlOCDOYK5YtxUCBsE4X9KuW8vG9JpczwW/2imBxb6mveJRWPLNXpzYXUu3q805bzFUJIUmht9Qkg0/8R9J2z8qD7VAj2PlvSHOSvz/AArZxff7F5koxK8435YIAQAgDr3Zt3VX/S3U1FZNdTl25ltnMVtSZ42QeF9oTlzWpkp9omnZOY8nWNLjmrdPzLY/q9jOJKpLfWbtT1DvGoSNUtDsx0ludzdQrRd5PFhmpbrkSXVMrDaxNYkpQICkrGMcW7K5PVLcLfp83FvleHCm7tuw2EE9zPLe6/I/a321mgo32btqHmfEsPYeF2pSnDzlJPEKemCpJB2rUfDErDKEZ6nmavC3Hy+L8BtZX/f79ebpe6u5XGpcrK+vecqKyrdViceedUVLWo+JJM43luCjFRiqJFh5IkBACAEAIA7/ANp31A9QtL8uVVjVbW8x2NxanqGheqVUy6J9fnLToQ5wLO1SCnftBBKp+Dqug28zJTryy8yLjU5drhrTnTP+pFfma+uhdXWEJZp0TDFJTInyqdlJnJKAfykzJmSTHqZLJwsW1bhsXjxOUqGox2jkQAgDK55ybfcu5yuliubJYuFoqnqSraPg4wsoJB8QZTBGwjaIqsXo3IKcdjVQYqLQIAQAgBACANq+Tmevk38ddIr0D1P0rqfHqOVzcWHfg93FuxbN8dX1kOt0q/epUVJf/VL/AAl+qjreq+ZPTt4fSuXh5MhyfVeZw+TyYf1ksM+DDGT+WPVUwp0uP6e1PeQhUgsZTjbExACAEAIA2rRv5N/HVJ8dep/D+L+59K5XUT93Fzfcn5sPFLdtjq5zrcj6VObiGWqf6v8A4Xf8b8rfTPzuj6Kf9Xm8z+bzf3kfMP7Pqd/Vr76/DwpwKcan/9k=',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => $model,
+ //跳转链接[type=app时必填]
+ 'appUrl' => '/app/vip/list',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'marketing.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.21',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module' => [],
+ // 插件依赖[可选],格式[[插件名, 插件唯一标识, 依赖版本, 对比方式]]
+ 'need_plugin' => [],
+];
\ No newline at end of file
diff --git a/app/member/info/PermissionMember.php b/app/member/info/PermissionMember.php
new file mode 100755
index 0000000..e51b824
--- /dev/null
+++ b/app/member/info/PermissionMember.php
@@ -0,0 +1,127 @@
+saasKey = longbing_get_auth_prefix('AUTH_MEMBER');
+
+ parent::__construct($uniacid, self::tabbarKey, self::adminMenuKey, $this->saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+
+
+
+ if(!$this->getAuthIsSaasCheck()){
+
+ return true ;
+ }
+
+ return $this->sassValue > 0 ? true : false;
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+
+ if (!$this->sAuth()) {
+ return false;
+ };
+
+ if(!$this->getAuthIsPlatformCheck()){
+ return true ;
+ }
+
+
+ $pAuthConfig = $this->getPAuthConfig();
+
+
+
+ if (!$pAuthConfig || $pAuthConfig['member_switch'] == 0) {
+ return false;
+ }
+
+ try {
+ $all_count = Db::name('longbing_cardauth2_auth_app')->where(['app_name'=>'member'])->count('count');
+ } catch (\Exception $exception) {
+ return false;
+ }
+
+
+ if ($all_count > $this->getSaasValue()) {
+ return false;
+ }
+
+
+
+ try {
+ $cardauth2= Db::name('longbing_cardauth2_auth_app')->where(['modular_id' => $this->uniacid,'app_name'=>'member'])->find();
+ } catch (\Exception $exception) {
+ return false;
+ }
+
+
+
+ if (!$cardauth2|| $cardauth2['sign'] < time() || $cardauth2['count'] < 1||md5('ndvjnfjvnjnv'.$cardauth2['create_time'])==$cardauth2['sign_data']) {
+ return false;
+ }
+
+
+ return true;
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/member/info/Subscribe.php b/app/member/info/Subscribe.php
new file mode 100755
index 0000000..8b4481f
--- /dev/null
+++ b/app/member/info/Subscribe.php
@@ -0,0 +1,163 @@
+sAuth() && $permission->infoConfig['auth_platform'] ) {
+
+ $auth_switch['formType'] = 'radio';
+
+ $auth_switch['name'] = 'member_switch';
+
+ $auth_switch['value'] = $config ? $config[ $auth_switch['name'] ] : 0;
+
+ $auth_switch['title'] = $permission->info['title'];
+
+ return [ $auth_switch ];
+
+ }
+
+ }
+
+
+ /**
+ * 监听用户中心模块
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/18 14:04
+ */
+// public function onAddUcenterCompoent(){
+// $last_staff_id = '#last_staff_id#' ;
+//
+// $moduleMenuShop = <<_uniacid);
+// $compoentList = [] ;
+// if( $this->_uniacid == 0 || $permission->pAuth()){
+// $compoentList = [
+// json_decode($moduleMenuShop, true)
+// ] ;
+// }
+//
+//
+//
+// return $compoentList ;
+// }
+
+ /**
+ * @param $item
+ * @功能说明:监听支付菜单数据获取
+ * @author jingshuixian
+ * @DataTime: 2020/1/7 17:02
+ */
+// public function onDiyModuleMenuPayqr($item){
+// $last_staff_id = UserService::getLastStaffId($this->_uniacid,$this->getUserId()) ;
+//
+//
+// $list = [
+// [
+// "title" =>"去付款",
+// "icon" => "iconwodedingdan1",
+// "link"=> [
+// "type"=> 2,
+// "url"=> "/pay/pages/home?staff_id=".$last_staff_id
+// ]
+// ]
+// ] ;
+// $item['data']['list'] = $list ;
+// return $item;
+//
+// }
+
+}
\ No newline at end of file
diff --git a/app/member/info/UpdateSql.php b/app/member/info/UpdateSql.php
new file mode 100755
index 0000000..a5cf205
--- /dev/null
+++ b/app/member/info/UpdateSql.php
@@ -0,0 +1,166 @@
+alias('a')
+ ->join('longbing_card_user b','a.user_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-11-30 19:09
+ * @功能说明:详情
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Config.php b/app/member/model/Config.php
new file mode 100755
index 0000000..2b325c9
--- /dev/null
+++ b/app/member/model/Config.php
@@ -0,0 +1,308 @@
+insert($data);
+
+ return $res;
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function configInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->configAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ $data['growth_title'] = !empty($data['growth_title'])?$data['growth_title']:'成长值';
+
+ $data['integral_title'] = !empty($data['integral_title'])?$data['integral_title']:'积分';
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function configUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-17 17:04
+ * @功能说明:储值下单的分销
+ */
+ public function storeOrderCommission($order){
+
+ $uniacid = $order['uniacid'];
+
+ $dis = [
+
+ 'uniacid' => $uniacid
+ ];
+
+ $config = $this->configInfo($dis);
+
+ if(empty($order['share_id'])){
+
+ return true;
+ }
+ //查看是否有权限
+ $auth = $this->userAuthCommission($uniacid,$order['share_id']);
+
+ if($auth==1){
+
+ $water_model = new IndexSellingWater();
+
+ $cash_model = new IndexSellingProfit();
+
+ $pay_price = $config['commission_price_type']==1?$config['commission_price']:round($config['commission_balance']*$order['pay_price']/100,2);
+
+ $data = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'source_id' => $order['user_id'],
+
+ 'user_id' => $order['share_id'],
+
+ 'goods_id' => $order['stored_id'],
+
+ 'type' => 1,
+
+ 'title' => $order['title'],
+
+ 'img' => '',
+
+ 'price' => $order['pay_price'],
+
+ 'extract' => $config['commission_price_type']==1?0:$config['commission_balance'],
+
+ 'waiting' => 2,
+
+ 'status' => 1,
+
+ 'goods_id' => $order['stored_id'],
+
+ 'buy_number'=> 1,
+
+ 'extract_cash' => $pay_price,
+
+ 'selling_type' => $config['commission_price_type'],
+
+ 'order_id' => $order['id'],
+
+ 'thing_type'=> 1
+
+ ];
+
+ $res = $water_model->waterAdd($data);
+
+ if($res == 1){
+
+ $id = $water_model->getLastInsID();
+
+ $water = $water_model->waterInfo(['id'=>$id]);
+
+ $cash_model->incOrDecCash($water);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-17 17:35
+ * @功能说明:获取用户是否是不是有权限分销
+ */
+ public function userAuthCommission($uniacid,$user_id){
+
+ $dis = [
+
+ 'uniacid' => $uniacid
+ ];
+
+ $config = $this->configInfo($dis);
+
+ $auth = 0;
+
+ if(in_array($config['commission_type'],[1,3])&&!empty($config['commission_user'])){
+ //用户信息
+ $user = Db::name('longbing_card_user')->where(['id'=>$user_id])->find();
+
+ $level_model = new Level();
+ //用户的等级
+ $user_level = $level_model->getUserLevel($user_id,$uniacid);
+
+ $user_level = !empty($user_level)?$user_level['top']:0;
+ //可以获取佣金的角色
+ $author = explode(',',$config['commission_user']);
+
+ foreach ($author as &$value){
+ //所有
+ if($value==1000){
+
+ $auth = 1;
+ }
+ //员工 或者用户
+ if(($value==888&&$user['is_staff']==1||($value==777&&$user['is_staff']==0))){
+
+ $auth =1;
+ }
+ //会员等级
+ if($value==$user_level){
+
+ $auth =1;
+
+ }
+
+ }
+ }
+
+ return $auth;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-18 09:22
+ * @功能说明:人工扣款佣金
+ */
+ public function controllerCommission($order){
+
+ $uniacid = $order['uniacid'];
+
+ $dis = [
+
+ 'uniacid' => $uniacid
+ ];
+
+ $config = $this->configInfo($dis);
+
+ $top_id = Db::name('longbing_card_user')->where(['id'=>$order['user_id']])->value('pid');
+
+ if(in_array($config['commission_type'],[2,3])&&$config['commission_Manual_status']==1&&!empty($top_id)){
+
+ $water_model = new IndexSellingWater();
+
+ $cash_model = new IndexSellingProfit();
+
+ $pay_price = round($config['commission_Manual_balance']*$order['pay_price']/100,2);
+
+ $data = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'source_id' => $order['user_id'],
+
+ 'user_id' => $top_id,
+
+ 'goods_id' => $order['stored_id'],
+
+ 'type' => 1,
+
+ 'title' => $order['title'],
+
+ 'img' => '',
+
+ 'price' => $order['pay_price'],
+
+ 'extract' => $config['commission_Manual_balance'],
+
+ 'waiting' => 2,
+
+ 'status' => 1,
+
+ 'goods_id' => $order['stored_id'],
+
+ 'buy_number'=> 1,
+
+ 'extract_cash' => $pay_price,
+
+ 'selling_type' => 0,
+
+ 'order_id' => $order['id'],
+
+ 'thing_type'=> $order['controller_type']==2?2:3
+
+ ];
+
+ $res = $water_model->waterAdd($data);
+
+ if($res == 1){
+
+ $id = $water_model->getLastInsID();
+
+ $water = $water_model->waterInfo(['id'=>$id]);
+
+ $cash_model->incOrDecCash($water);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Coupon.php b/app/member/model/Coupon.php
new file mode 100755
index 0000000..e9615b1
--- /dev/null
+++ b/app/member/model/Coupon.php
@@ -0,0 +1,105 @@
+where(['member_id'=>$level_id])->delete();
+
+ if(!empty($coupon)){
+
+ array_walk($coupon, function ($value, $key) use (&$coupon, $level_id,$data) {
+
+ $coupon[$key] = [
+ //等级id
+ 'member_id' => $level_id,
+
+ 'uniacid' => $data['uniacid'],
+
+ 'coupon_id' => $value['coupon_id'],
+
+ 'num' => $value['num'],
+
+ ];
+
+ });
+ //添加
+ $res = $this->saveAll($coupon);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-08 16:30
+ * @功能说明:添加用户的优惠券
+ */
+ public function insertCoupon($level,$order){
+
+ if($level['coupon_switch']!=1){
+
+ return true;
+ }
+
+ $dis = [
+
+ 'a.member_id' => $level['id']
+ ];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_coupon b','a.coupon_id = b.id')
+ ->where($dis)
+ ->group('a.coupon_id')
+ ->field('b.*,a.num as coupon_num')
+ ->select()
+ ->toArray();
+
+ $record_model = new IndexCouponRecord();
+
+ if(!empty($data)){
+
+ foreach ($data as $coupon){
+
+ for ($i=0;$i<$coupon['coupon_num'];$i++){
+
+ if(!isset($order['staff_id'])&&isset($order['to_uid'])){
+
+ $order['staff_id'] = $order['to_uid'];
+ }
+ //领取优惠券
+ $record_model->insertRecord($coupon,$order);
+
+ }
+
+ }
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/DiscountGoods.php b/app/member/model/DiscountGoods.php
new file mode 100755
index 0000000..06ac250
--- /dev/null
+++ b/app/member/model/DiscountGoods.php
@@ -0,0 +1,172 @@
+where(['goods_id'=>$goods_id])->delete();
+
+ foreach ($data as $k=>$v){
+
+ $data[$k]['uniacid'] = $uniacid;
+
+ $data[$k]['goods_id'] = $goods_id;
+
+ }
+
+ $res = $this->saveAll($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @param $goods_id
+ * @功能说明:商品折扣
+ * @author chenniang
+ * @DataTime: 2020-07-29 15:10
+ */
+
+ public function goodsDiscount($goods_id){
+
+ $dis = [
+
+ 'goods_id' => $goods_id
+ ];
+
+ $data = $this->where($dis)->select()->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 17:06
+ * @功能说明:用户会员的折扣
+ */
+ public function userGoodsDiscount($goods_id,$user_id,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ $level_model = new Level();
+ //会员当前的等级
+ $user_level = $level_model->getUserLevel($user_id,$uniacid);
+
+ $member_id = !empty($user_level)?$user_level['id']:0;
+
+ $dis = [
+
+ 'goods_id' => $goods_id,
+
+ 'member_id'=> $member_id
+ ];
+
+ $data = $this->where($dis)->find();
+ //折扣
+ $discount = !empty($data)&&$config['status']==1?$data['discount']/10:1;
+
+ return $discount;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-03 17:39
+ * @功能说明:是不是会员商品
+ */
+ public function isMemberGoods($goods_id,$user_id,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ $level_model = new Level();
+ //会员当前的等级
+ $user_level = $level_model->getUserLevel($user_id,$uniacid);
+
+ $member_id = !empty($user_level)?$user_level['id']:0;
+
+ $dis = [
+
+ 'goods_id' => $goods_id,
+
+ 'member_id'=> $member_id
+ ];
+
+ $data = $this->where($dis)->find();
+ //折扣
+ $data = !empty($data)&&$config['status']==1?1:0;
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-10 11:45
+ * @功能说明:会员商品
+ */
+ public function isMember($is_member,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ $persisson = new PermissionMember($uniacid);
+
+ $auth = $persisson->pAuth();
+
+ return $auth==true&&$config['status']==1?$is_member:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-02-01 10:57
+ * @功能说明:会员折扣
+ */
+ public function eventDiscount($where){
+ //会员商品折扣
+ $data['discount'] = $this->userGoodsDiscount($where['goods_id'],$where['user_id'],$where['uniacid']);
+ //是不是会员折扣商品
+ $data['is_goods_member'] = $this->isMemberGoods($where['goods_id'],$where['user_id'],$where['uniacid']);
+
+ $data['name'] = 'member_discount';
+
+ $data['member_discount'] = $data['discount'];
+
+ return $data;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Goods.php b/app/member/model/Goods.php
new file mode 100755
index 0000000..365ef87
--- /dev/null
+++ b/app/member/model/Goods.php
@@ -0,0 +1,350 @@
+insert($data);
+
+ return $res;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function levelInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $order
+ * @功能说明:会员商品支付回调
+ * @author chenniang
+ * @DataTime: 2020-07-29 15:59
+ */
+ public function payResult($order){
+
+ if($order['is_member']==1){
+
+ $order_goods_model = new IndexShopOrderGoods();
+
+ $order_item = $order_goods_model->orderGoodsInfo([ 'order_id' => $order[ 'id' ] ]);
+
+ foreach ( $order_item as $index => $item ) {
+
+ if($item['is_member']==1){
+
+ $this->getGrowth($item['goods_id'],$order['id'],$order['uniacid'],$order['user_id']);
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $goods_id
+ * @功能说明:获取会员商品对类型
+ * @author chenniang
+ * @DataTime: 2020-09-14 09:31
+ */
+ public function getGoodsType($goods_id){
+
+ $dis = [
+
+ 'a.goods_id' => $goods_id
+
+ ];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_member_level b','a.member_id = b.id')
+ ->where($dis)
+ ->field('b.*')
+ ->find();
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-29 15:31
+ * @功能说明:支付回调
+ */
+ public function getGrowth($goods_id,$order_id,$uniacid,$user_id){
+
+ $member_model = new Member();
+
+ $growth_model = new Growth();
+
+ $dis = [
+
+ 'a.goods_id' => $goods_id
+
+ ];
+
+ $growth = $this->alias('a')
+ ->join('longbing_card_member_level b','a.member_id = b.id')
+ ->where($dis)
+ ->value('growth');
+
+ if(is_numeric($growth)&&$growth>0){
+
+ $member_info = $member_model->getMemberInfo(['user_id'=>$user_id,'uniacid'=>$uniacid]);
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $user_id,
+
+ 'growth_add' => $growth,
+
+ 'growth_after' => $member_info['growth']+$growth,
+
+ 'growth_before' => $member_info['growth'],
+
+ 'create_time'=> time(),
+
+ 'order_id' => $order_id,
+
+ 'goods_id' => $goods_id,
+
+ 'type' => 0
+
+ ];
+
+ $growth_model->insert($insert);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 10:19
+ * @功能说明:更新会员
+ */
+ public function ordertypeUpdate($order){
+ //普通会员
+ if(!empty($order['level_top'])){
+
+ $this->giveOrderGrowth($order);
+ }
+ //pul会员
+ if(!empty($order['over_time'])){
+
+ $member_model = new Member();
+ //获取用户会员信息(没有则创建)
+ $user_info = $member_model->memberUpdateInfo(['user_id'=>$order['user_id'],'uniacid'=>$order['uniacid']]);
+ //1是plus会员,给会员过期时间
+ if($user_info['over_time']where(['id'=>$user_info['id']])->update($row);
+
+ }
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 09:49
+ * @功能说明:给会员对成长值
+ */
+
+ public function giveOrderGrowth($order){
+
+ $growth_model = new Growth();
+
+ $level_model = new Level();
+
+ $member_model = new Member();
+
+ $order_goods_model = new IndexShopOrderGoods();
+
+ $level_data = $level_model->where(['top'=>$order['level_top'],'uniacid'=>$order['uniacid']])->find();
+
+ if(!empty($level_data)){
+
+ $level_data = $level_data->toArray();
+ //当前会员对信息
+ $member_info = $member_model->getMemberInfo(['user_id'=>$order['user_id'],'uniacid'=>$order['uniacid']]);
+ //子订单
+ $order_item = $order_goods_model->orderGoodsInfo([ 'order_id' => $order[ 'id' ] ]);
+
+ foreach ( $order_item as $index => $item ) {
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $order['user_id'],
+
+ 'growth_add' => $level_data['growth'],
+
+ 'growth_after' => $member_info['growth']+$level_data['growth'],
+
+ 'growth_before' => $member_info['growth'],
+
+ 'create_time'=> time(),
+
+ 'order_id' => $order['id'],
+
+ 'goods_id' => $item['goods_id'],
+
+ 'type' => 0
+
+ ];
+
+ $growth_model->insert($insert);
+
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 09:41
+ * @功能说明:获取可以买的商品
+ */
+ public function getCanBuyGoods($uid,$uniacid){
+
+ $level_model = new Level();
+
+ $level = $level_model->getUserLevel($uid,$uniacid);
+
+ $member_model = new Member();
+ //看他是不是永久的plus会员
+ if(!empty($level)&&$level['top']==999){
+
+ $over_time = $member_model->where(['user_id'=>$uid])->value('over_time');
+
+ if($over_time==-1){
+
+ return [];
+ }
+
+ }
+
+ if(!empty($level)){
+
+ $top_level = $level_model->getSonLevel($level,$uniacid,1);
+
+ }else{
+
+ $top_level = $level_model->getAllLevel($uniacid);
+
+ }
+
+ if(!empty($top_level)){
+
+ $dis[] = ['a.member_id','in',$top_level];
+
+ $dis[] = ['a.uniacid','=',$uniacid];
+
+ $dis[] = ['b.is_member','=',1];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_goods b','a.goods_id = b.id')
+ ->where($dis)
+ ->column('b.id');
+
+ }
+
+ return !empty($data)?$data:[];
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 13:48
+ * @功能说明:获取商品的会员等级
+ */
+ public function getGoodsLevel($goods_id){
+
+ $dis = [
+
+ 'a.goods_id' => $goods_id
+
+ ];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_member_level b','a.member_id = b.id')
+ ->where($dis)
+ ->field('b.*')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Growth.php b/app/member/model/Growth.php
new file mode 100755
index 0000000..e333f27
--- /dev/null
+++ b/app/member/model/Growth.php
@@ -0,0 +1,310 @@
+insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 16:35
+ * @功能说明:列表
+ */
+ public function growthList($dis,$page){
+
+ $data = $this->where($dis)->order(['update_time desc','id desc'])->paginate($page)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ if($v['controller_type']==0){
+
+ $v['controller_name'] = '系统核算';
+
+ $icon = $v['growth_add']>0?'+':'-';
+
+ $growth_add = $v['growth_add']>0?$v['growth_add']:$v['growth_add']*-1;
+
+ $refund = $v['refund']==1?'(已退款)':'';
+
+ $boj = $this->returnObj($v['type']);
+
+ $v['text'] = $boj.'成长值'.$icon.$growth_add.',现成长值 '.$v['growth_after'].$refund;
+
+ }else{
+
+ $v['controller_name'] = Db::name('longbing_admin')->where(['admin_id'=>$v['controller']])->value('account');
+
+ $v['text'] = '成长值'.$v['growth_before'].',修改为 '.$v['growth_after'];
+
+ }
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 15:17
+ * @功能说明:返回一个对象
+ */
+ public function returnObj($type){
+
+
+ switch ($type){
+ //购买会员商品
+ case 0:
+ return '购买会员获得';
+
+ break;
+ //会员购买商品
+ case 1:
+ return '消费获得';
+
+ break;
+ //购买储值套餐赠送
+ case 2:
+ return '购买储值套餐赠送';
+
+ break;
+ default:
+ return '消费获得';
+
+ break;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function growthInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function growthUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 16:29
+ * @功能说明:
+ */
+ public function settledGrowth($uniacid,$user_id){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['growth_add','>',0];
+
+ $dis[] = ['is_del','=',0];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['refund','=',0];
+
+ $data = $this->where($dis)->sum('growth_add');
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 10:21
+ * @功能说明:每日领取的积分
+ */
+ public function dayGrowth($user_id,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ if($config['growth_limit']==1){
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'refund' => 0,
+
+ 'type' => 1
+ ];
+
+ $growth = $this->where($dis)->where('status','>',0)->whereDay('create_time')->sum('growth_add');
+
+ $re_growth = $config['growth_day_max'] - $growth;
+
+ $re_growth = $re_growth>0?$re_growth:0;
+
+ return intval($re_growth);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 10:47
+ * @功能说明:增加用户的成长值记录
+ */
+ public function addUserGrowth($uniacid,$user_id,$growth,$order_id = 0,$type=0,$status = 1){
+
+ if(!empty(intval($growth))){
+
+ $member_model = new Member();
+
+ $member_info = $member_model->getMemberInfo(['user_id'=>$user_id,'uniacid'=>$uniacid]);
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $user_id,
+
+ 'growth_add' => intval($growth),
+
+ 'growth_before' => intval($member_info['growth']),
+
+ 'growth_after' => intval($member_info['growth']+$growth),
+
+ 'order_id' => $order_id,
+
+ 'type' => $type,
+
+ 'status' => $status,
+
+ ];
+
+ $res = $this->growthAdd($insert);
+
+ return $res;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 11:07
+ * @功能说明:给用户加成长值
+ */
+ public function incUserGrowth($order_id,$user_id,$uniacid){
+
+ $member_model = new Member();
+
+ $dis = [
+
+ 'order_id' => $order_id,
+
+ 'status' => 1
+ ];
+
+ $info = $this->where($dis)->select()->toArray();
+
+ if(!empty($info)){
+
+ foreach ($info as &$value){
+
+ $member_info = $member_model->getMemberInfo(['user_id'=>$user_id,'uniacid'=>$uniacid]);
+
+ $growth = $value['growth_add'];
+
+ $update = [
+ //修改状态
+ 'status' => 2,
+ //当前
+ 'growth_before' => intval($member_info['growth']),
+ //修改后对
+ 'growth_after' => intval($member_info['growth']+$growth),
+
+ ];
+
+ $this->growthUpdate(['id'=>$value['id']],$update);
+
+ if(is_numeric($growth)&&$growth>0){
+
+ $dis = [
+
+ 'user_id' => $user_id
+
+ ];
+
+ $member_model->incDecGrowth($dis,$growth,'growth');
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Integral.php b/app/member/model/Integral.php
new file mode 100755
index 0000000..9717750
--- /dev/null
+++ b/app/member/model/Integral.php
@@ -0,0 +1,440 @@
+insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 16:35
+ * @功能说明:列表
+ */
+ public function integralList($dis,$page){
+
+ $data = $this->where($dis)->order(['update_time desc','id desc'])->paginate($page)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ if($v['controller_type']==0){
+
+ $v['controller_name'] = '系统核算';
+
+ $icon = $v['integral_add']>0?'+':'-';
+
+ $integral_add = $v['integral_add']>0?$v['integral_add']:$v['integral_add']*-1;
+
+ $text = $v['integral_add']>0?'增加积分':'使用积分';
+
+ $boj = $this->returnObj($v['type']);
+
+ $refund = $v['refund']==1?'(已退款)':'';
+
+ $v['text'] = $boj.$text.$icon.$integral_add.',现积分 '.$v['integral_after'].$refund;
+
+ $v['type_text'] = $boj;
+
+ }
+
+ }
+
+ }
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 15:17
+ * @功能说明:返回一个对象
+ */
+ public function returnObj($type){
+
+ switch ($type){
+ //购买会员商品
+ case 0:
+ return '升级会员';
+
+ break;
+ //会员购买商品
+ case 1:
+ return '消费';
+
+ break;
+ //购买储值套餐赠送
+ case 2:
+ return '购买储值套餐';
+
+ break;
+
+ case 3:
+ return '购买商城商品';
+
+ break;
+
+ case 4:
+ return '购买餐饮菜品';
+
+ break;
+
+ case 5://取消订单
+ return '商城商品退款';
+
+ break;
+ case 6://售后
+ return '商城商品退款';
+
+ break;
+ case 7://
+ return '同步银豹';
+
+ break;
+ case 8://
+ return '报名活动';
+
+ break;
+ case 9://
+ return '购买赛车产品';
+
+ break;
+
+ case 10://
+ return '购买商城商品';
+
+ break;
+ case 11://
+ return '购买餐饮商品';
+
+ break;
+ default:
+ return '消费';
+
+ break;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function integralInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function integralUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 10:28
+ * @功能说明:增加用户积分
+ */
+ public function integralUserAdd($user_id,$integral,$uniacid,$status = 2,$type=0,$order_id=0){
+ //积分倍率
+ $arr = $this->pointDouble($user_id,$integral);
+
+ $integral = $arr['integral'];
+ //查询单日获取积分是否超限
+ $integral = $this->dayGetIntegral($user_id,$integral,$uniacid);
+
+ if(!empty(intval($integral))){
+
+ $member_model = new User();
+
+ $member_info = $member_model->dataInfo(['id'=>$user_id]);
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $user_id,
+
+ 'integral_add' => intval($integral),
+
+ 'integral_before'=> intval($member_info['integral']),
+
+ 'integral_after' => intval($member_info['integral']+$integral),
+
+ 'status' => $status,
+
+ 'type' => $type,
+
+ 'order_id' => $order_id,
+
+ 'double' => $arr['double'],
+ ];
+
+ $res = $this->integralAdd($insert);
+
+ if($res==0){
+
+ return false;
+ }
+
+ $res = $member_model->dataUpdate(['id'=>$user_id],['integral'=>$insert['integral_after']]);
+
+ if($res==0){
+
+ return false;
+ }
+
+
+ }
+ return true;
+
+ }
+
+
+ /**\
+ * @author chenniang
+ * @DataTime: 2021-11-12 17:31
+ * @功能说明:积分倍率
+ */
+ public function pointDouble($user_id,$integral){
+
+ $user_model = new User();
+
+ $member_level = $user_model->where(['id'=>$user_id])->value('member_level');
+
+ $arr['double'] = 1;
+
+ $arr['integral'] = $integral;
+
+ if(empty($member_level)){
+
+ return $arr;
+ }
+
+ $level_model = new Level();
+
+ $level = $level_model->levelInfo(['id'=>$member_level]);
+
+ if(empty($level)){
+
+ return $arr;
+ }
+
+ if(empty($level['integral_switch'])){
+
+ return $arr;
+
+ }
+
+ $arr['double'] = $level['integral'];
+
+ $arr['integral'] = floor($level['integral']*$integral);
+
+ return $arr;
+
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 14:05
+ * @功能说明:单天获得积分
+ */
+ public function dayGetIntegral($user_id,$integral,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ if($config['integral_limit']==0){
+
+ return $integral;
+ }
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['integral_add','>',0];
+ //单日获取积分
+ $integral_day = $this->where($dis)->whereDay('create_time')->sum('integral_add');
+ //单日可获取最大积分
+ $integral_day_max = $config['integral_day_max'];
+
+ $point = $integral_day_max-$integral_day;
+
+ if($point<=0){
+
+ return 0;
+ }
+
+ $point = $point-$integral>0?$integral:$point;
+
+ return $point;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 10:21
+ * @功能说明:每日领取的积分
+ */
+ public function dayIntegral($user_id,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ if($config['integral_limit']==1){
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'refund' => 0,
+
+ 'type' => 1
+ ];
+
+ $integral = $this->where($dis)->where('status','>',0)->whereDay('create_time')->sum('integral_add');
+
+ $re_integral = $config['integral_day_max'] - $integral;
+
+ $re_integral = $re_integral>0?$re_integral:0;
+
+ return intval($re_integral);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 11:07
+ * @功能说明:给用户加积分
+ */
+ public function incUserIntegral($order_id,$user_id,$uniacid){
+
+ $dis = [
+
+ 'order_id' => $order_id,
+
+ 'status' => 1
+ ];
+
+ $info = $this->where($dis)->select()->toArray();
+
+ $member_model = new Member();
+
+ if(!empty($info)){
+
+ foreach ($info as $value){
+
+ $integral = $value['integral_add'];
+
+ $member_info = $member_model->getMemberInfo(['user_id'=>$user_id,'uniacid'=>$uniacid]);
+
+ $update = [
+ //修改状态
+ 'status' => 2,
+ //当前
+ 'integral_before' => intval($member_info['integral']),
+ //修改后对
+ 'integral_after' => intval($member_info['integral']+$integral),
+
+ ];
+
+ $this->integralUpdate(['id'=>$value['id']],$update);
+
+ if(is_numeric($integral)&&$integral>0){
+
+ $dis = [
+
+ 'user_id' => $user_id
+
+ ];
+
+ $member_model->incDecGrowth($dis,$integral,'integral');
+
+ }
+
+ }
+
+ }
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Level.php b/app/member/model/Level.php
new file mode 100755
index 0000000..4081f91
--- /dev/null
+++ b/app/member/model/Level.php
@@ -0,0 +1,739 @@
+insert($data);
+ //id
+ $level_id = $this->getLastInsID();
+ //修改相关数据
+ $this->updateSome($goods_id,$rights,$level_id,$data,$coupon,$stored);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-10 15:13
+ * @功能说明:初始化
+ */
+ public function initLevel($dis){
+
+ //初始化普通会员
+ if($dis['type']==0){
+
+ for ($i=1;$i<11;$i++){
+
+ $insert[$i]['uniacid'] = $dis['uniacid'];
+
+ $insert[$i]['status'] = 0;
+
+ $insert[$i]['create_time'] = time();
+
+ $insert[$i]['update_time'] = time();
+
+ $insert[$i]['top'] = $i;
+ }
+
+ $this->saveAll($insert);
+
+ }else{
+ //初始化puls会员
+ $insert['uniacid'] = $dis['uniacid'];
+
+ $insert['status'] = 0;
+
+ $insert['create_time'] = time();
+
+ $insert['update_time'] = time();
+
+ $insert['type'] = 1;
+
+ $insert['top'] = 999;
+
+ $insert['over_time'] = -1;
+
+ $this->insert($insert);
+ }
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:12
+ * @功能说明:列表
+ */
+ public function levelList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id')->paginate($page)->toArray();
+
+ $right_model = new Rights();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['rights'] = $right_model->customRights($v['id']);
+ //商品折扣
+ if($v['discount_switch']==1){
+
+ array_unshift($v['rights'],'商品打折');
+
+ }
+ //积分倍率
+ if($v['integral_switch']==1){
+
+ array_unshift($v['rights'],'积分倍率'.$v['integral'].'倍');
+
+ }
+ //赠送积分
+ if($v['send_integral_switch']==1){
+
+ array_unshift($v['rights'],'赠送积分'.$v['send_integral']);
+
+ }
+// //赠送优惠券
+ if($v['coupon_switch']==1){
+
+ array_unshift($v['rights'],'赠送卡券');
+
+ }
+
+ $user_model = new User();
+ //会员人数
+ $v['member_num'] = $user_model->where(['member_level'=>$v['id']])->count();
+
+
+ }
+ }
+
+
+ return $data;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function levelInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:删除直播
+ */
+ public function levelUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $goods_id = [];
+
+ $rights = [];
+
+ $coupon = [];
+
+ $stored = [];
+
+ //关联的权益
+ if(isset($data['rights'])){
+
+ $rights = $data['rights'];
+
+ unset($data['rights']);
+ }
+ //关联的优惠券
+ if(isset($data['coupon'])){
+
+ $coupon = $data['coupon'];
+
+ unset($data['coupon']);
+ }
+
+
+ $res = $this->where($dis)->update($data);
+
+ $this->updateSome($rights,$data['id'],$data,$coupon);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $level_id
+ * @param $data
+ * @功能说明:修改相关数据
+ * @author chenniang
+ * @DataTime: 2020-07-15 13:40
+ */
+ public function updateSome($rights,$level_id,$data,$coupon=[]){
+
+
+ //关联的商品模型
+ $rights_model = new RightsRelation();
+
+ $rights_model->where(['member_id'=>$level_id])->delete();
+ //添加关联的商品
+ if(!empty($rights)){
+
+ array_walk($rights, function ($value, $key) use (&$rights, $level_id,$data) {
+
+ $rights[$key] = [
+ //商品id
+ 'rights_id' => $value['id'],
+ //等级id
+ 'member_id' => $level_id,
+
+ 'uniacid' => $data['uniacid'],
+
+ 'type' => $value['type']
+
+ ];
+
+ });
+ //添加
+ $res = $rights_model->saveAll($rights);
+ }
+ //优惠券关联模型
+ $coupon_model = new Coupon();
+ //添加
+ $coupon_model->addCoupon($coupon,$level_id,$data);
+
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 11:08
+ * @功能说明:获取成长值区间
+ */
+ public function getGrowth($level){
+
+ $data = $this->where(['id'=>$level])->find();
+
+ $dis[]= ['uniacid','=',$data['uniacid']];
+
+ $dis[]= ['growth','>',$data['growth']];
+
+ $top = $this->where($dis)->order('growth')->find();
+
+ $info['start_growth'] = $data['growth'];
+
+ $info['end_growth'] = !empty($top['growth'])?$top['growth']:0;
+
+ return $info;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-17 13:22
+ * @功能说明:会员商品
+ */
+ public function memberGoods($uniacid,$level_id){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['is_member','=',1];
+
+ $id = $this->haveSelectGoods($uniacid,$level_id);
+
+ $dis[] = ['id','not in',$id];
+
+ $data = Db::name('longbing_card_goods')->where($dis)->field('name,id')->select();
+
+ return $data;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-09 13:39
+ * @功能说明:下拉框
+ */
+ public function storedSelect($uniacid,$level_id){
+
+ $id = $this->haveSelectStored($uniacid,$level_id);
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['id','not in',$id];
+
+ $data = Db::name('longbing_card_member_stored')->where($dis)->order('top desc,id desc')->select()->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-09 14:09
+ * @功能说明:已经选了储值
+ */
+
+ public function haveSelectStored($uniacid,$level_id){
+
+ $dis[] = ['a.uniacid','=',$uniacid];
+
+ $dis[] = ['b.uniacid','=',$uniacid];
+
+ $dis[] = ['a.member_id','<>',$level_id];
+
+ $store_level_model = new StoredLevel();
+
+ $id = $store_level_model->alias('a')
+ ->join('longbing_card_member_level b','a.member_id = b.id')
+ ->where($dis)
+ ->column('a.stored_id');
+
+ return $id;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-06 15:21
+ * @功能说明:已经选了的商品
+ */
+ public function haveSelectGoods($uniacid,$level_id){
+
+ $dis[] = ['a.uniacid','=',$uniacid];
+
+ $dis[] = ['b.uniacid','=',$uniacid];
+
+ $dis[] = ['a.member_id','<>',$level_id];
+
+ $goods_model = new Goods();
+
+ $id = $goods_model->alias('a')
+ ->join('longbing_card_member_level b','a.member_id = b.id')
+ ->where($dis)
+ ->column('goods_id');
+
+ return $id;
+ }
+
+
+ /**
+ * @param $uniacid
+ * @功能说明:会员权益
+ * @author chenniang
+ * @DataTime: 2020-07-22 14:23
+ */
+ public function memberRights($uniacid,$type = 0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['type','=',$type];
+
+ $rights_model = new Rights();
+
+ $data = $rights_model->where($dis)->field('title,id,is_up')->select();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-27 14:14
+ * @功能说明:检测状态
+ */
+
+
+ public function checkStatus($id,$status){
+
+ $info = $this->levelInfo(['id'=>$id]);
+
+ if(empty($info)){
+
+ return [ 'code' => 400,'msg' => '未找到' ];
+
+ }
+ //开启
+ if($status==1){
+
+ $dis[] = ['uniacid','=',$info['uniacid']];
+
+ $dis[] = ['status','=',0];
+
+ $dis[] = ['type','=',0];
+
+ $data = $this->where($dis)->order('top')->find();
+
+ if($data['id']!=$id){
+
+ return [ 'code' => 400,'msg' => '请先开启上级或下级'];
+
+ }
+ }
+ //关闭
+ if($status==0){
+
+ $dis[] = ['uniacid','=',$info['uniacid']];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['type','=',0];
+
+ $data = $this->where($dis)->order('top desc')->find();
+
+ if($data['id'] != $id){
+
+ return [ 'code' => 400,'msg' => '请先关闭上级或下级'];
+
+ }
+
+ }
+
+ return [ 'code' => 200,'msg' => '' ];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 11:23
+ * @功能说明:获取等级
+ */
+
+ public function getMemberLevel($uniacid,$growth,$type = 0){
+
+ $where = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ 'type' => 0
+ ];
+
+ if($type==0){
+
+ $data = $this->where($where)->where('growth','>',$growth)->order('growth')->find();
+
+ }else{
+
+ $data = $this->where($where)->where('growth','<=',$growth)->order('growth desc')->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-10 14:09
+ * @功能说明:获取用户等级
+ */
+ public function getUserLevelV2($user_id){
+
+ $dis = [
+
+ 'b.id' => $user_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('massage_service_user_list b','a.id = b.member_level')
+ ->where($dis)
+ ->field('a.*')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-18 10:14
+ * @功能说明:获取plus会员
+ */
+ public function getPlusLvel($uniacid){
+
+
+ $where = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ 'type' => 1,
+
+ 'top' => 999
+ ];
+
+ $data = $this->where($where)->order('growth')->find();
+
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 09:45
+ * @功能说明:获取用户的等级
+ */
+ public function getUserLevel($uid,$uniacid){
+
+ $member_model = new Member();
+
+ $over_time = $member_model->where(['user_id'=>$uid])->value('over_time');
+ //查看是否是plus会员 -1是永久有效
+ if($over_time>time()||$over_time==-1){
+
+ $level = $this->getPlusLvel($uniacid);
+
+ if(!empty($level)){
+
+ return $level;
+ }
+
+ }
+
+ $growth = $member_model->where(['user_id'=>$uid])->value('growth');
+
+ $growth = !empty($growth)?$growth:0;
+
+ $level = $this->getMemberLevel($uniacid,$growth,1);
+
+
+ return $level;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-07 09:39
+ * @功能说明:
+ */
+ public function getAllLevel($uniacid){
+
+ $where = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ // 'type' => 0
+ ];
+
+ $son_level = $this->where($where)->column('id');
+
+ return $son_level;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-30 09:53
+ * @功能说明:获取下级或者上级的等级
+ */
+ public function getSonLevel($level,$uniacid,$type=0){
+
+ $where = [
+
+ 'uniacid' => $uniacid,
+
+ 'status' => 1,
+
+ ];
+
+ if($type==0){
+
+ $son_level = $this->where($where)->where('top','<',$level['top'])->column('id');
+
+ }else{
+
+ $icon = $level['top']==999?'>=':'>';
+
+ $son_level = $this->where($where)->where('top',$icon,$level['top'])->column('id');
+
+ }
+
+ return $son_level;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 10:39
+ * @功能说明:升级用户的权益
+ */
+ public function upUserRights($level,$order){
+
+ $uniacid = $order['uniacid'];
+
+ $user_id = $order['user_id'];
+
+ $integral_model = new Integral();
+
+ $member_model = new Member();
+
+ $coupon_model = new Coupon();
+
+ $level_info = $this->levelInfo(['top'=>$level,'uniacid'=>$uniacid]);
+ //增加积分记录
+ $integral_model->integralUserAdd($user_id,$level_info['send_integral'],$uniacid);
+ //加会员的积分
+ $dis = [
+ 'user_id' => $user_id
+ ];
+
+ $member_model->incDecGrowth($dis,$level_info['send_integral'],'integral');
+ //赠送优惠券
+ $coupon_model->insertCoupon($level_info,$order);
+ //第一次升级时候 修改创建时间
+ $member_model->where(['user_id'=>$order['user_id'],'is_vip'=>0])->update(['create_time'=>time(),'is_vip'=>1]);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 17:22
+ * @功能说明:会员成长值
+ */
+ public function memberGrowth($uniacid){
+
+ $data = $this->where(['uniacid'=>$uniacid,'status'=>1,'type'=>0])->min('growth');
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-18 17:02
+ * @功能说明:
+ */
+ public function upUserRightsEnd($update,$order){
+
+ $user_id = $order['user_id'];
+
+ $uniacid = $order['uniacid'];
+
+ $member_model = new Member();
+ //还未升级以前的等级
+ $level_start = $this->getUserLevel($user_id,$uniacid);
+ //如果空就不是会员
+ $level_start = !empty($level_start['top'])?$level_start['top']:0;
+ //更新会员信息
+ $member_model->where(['user_id'=>$user_id])->update($update);
+ //增加后的等级
+ $level_end = $this->getUserLevel($user_id,$uniacid);
+
+ $level_end = !empty($level_end['top'])?$level_end['top']:0;
+ //普通会员升级礼包
+ if($level_end>$level_start){
+
+ $this->upUserRights($level_end,$order);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Log.php b/app/member/model/Log.php
new file mode 100755
index 0000000..372b74d
--- /dev/null
+++ b/app/member/model/Log.php
@@ -0,0 +1,138 @@
+where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 09:49
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-27 17:16
+ * @功能说明:编辑
+ */
+ public function updateSome($id,$coupon,$uniacid){
+
+ $coupon_model = new StoredCoupon();
+
+ $coupon_model->where(['stored_id'=>$id])->delete();
+
+ if(!empty($coupon)){
+
+ foreach ($coupon as $value){
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'coupon_id'=> $value['coupon_id'],
+
+ 'stored_id'=> $id,
+
+ 'num' => $value['num']
+
+ ];
+
+ $coupon_model->insert($insert);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function storedInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function storedUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ if(isset($data['coupon'])){
+
+ $coupon = $data['coupon'];
+
+ unset($data['coupon']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($coupon)){
+
+ $id = $dis['id'];
+
+ $this->updateSome($id,$coupon,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Member.php b/app/member/model/Member.php
new file mode 100755
index 0000000..66ce75c
--- /dev/null
+++ b/app/member/model/Member.php
@@ -0,0 +1,624 @@
+getUserLevel($data['user_id'],$data['uniacid']);
+
+ return !empty($text)?$text['title']:'';
+
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:获取等级名称
+ * @author chenniang
+ * @DataTime: 2020-07-16 09:47
+ */
+ public function getLevelTopAttr($value,$data){
+
+ if(!empty($data['user_id'])&&!empty($data['uniacid'])){
+
+ $level_model = new Level();
+
+ $text = $level_model->getUserLevel($data['user_id'],$data['uniacid']);
+
+ return !empty($text)?$text['top']:'';
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-11 11:36
+ * @功能说明:
+ *
+ */
+ public function memberUpdateInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->memberAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 09:49
+ * @功能说明:添加
+ */
+ public function memberAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $data['update_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function memberInfo($dis){
+
+ $data = $this->alias('a')
+ ->join('longbing_card_user b','a.user_id = b.id','left')
+ ->where($dis)
+ ->field(['a.*','b.nickName','b.avatarUrl','ifnull(a.growth,0) as growth','ifnull(a.integral,0) as integral'])
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function memberInfoIndex($dis){
+
+ $data = $this->alias('a')
+ ->join('longbing_card_user b','a.user_id = b.id','right')
+ ->where($dis)
+ ->field(['ifnull(a.over_time,0) as over_time','a.id','b.nickName','b.avatarUrl','ifnull(a.stored,0) as balance','ifnull(a.cash_stored,0) as cash_balance','ifnull(a.over_time,0) as over_time','ifnull(a.growth,0) as growth','ifnull(a.integral,0) as integral'])
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 09:35
+ * @功能说明:编辑
+ */
+ public function memberUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-19 13:50
+ * @功能说明:会员列表
+ */
+ public function memberListV2(){
+
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 09:41
+ * @功能说明:会员列表
+ */
+
+ public function memberList($dis,$where,$mapor,$page){
+
+
+ $data = $this->alias('a')
+ ->join('longbing_card_user b','a.user_id = b.id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field(['a.*','b.nickName','b.id as user_id',])
+ ->group('a.id')
+ ->order(['a.create_time desc','a.id'])
+ ->paginate($page)
+ ->toArray();
+
+ $order_model = new AdminShopOrder();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['member_phone'] = Db::name('longbing_card_user_phone')->where(['user_id'=>$v['user_id']])->value('phone');
+
+ $diss = [];
+
+ $diss[] = ['uniacid','=',$v['uniacid']];
+
+ $diss[] = ['user_id','=',$v['user_id']];
+
+ $diss[] = ['create_time','>',$v['create_time']];
+
+ $diss[] = ['pay_status','=',1];
+ //消费金额
+ $v['price'] = $order_model->where($diss)->sum('total_price');
+ //订单量
+ $v['order_num'] = $order_model->where($diss)->count();
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-08 10:20
+ * @功能说明:讲所有用户添加到会员表
+ */
+ public function memberInit($uniacid){
+
+ $member_user = $this->where(['uniacid'=>$uniacid])->column('user_id');
+
+ $no_member_user = Db::name('longbing_card_user')->where(['uniacid'=>$uniacid])->where('id','not in',$member_user)->column('id');
+
+ if(!empty($no_member_user)){
+
+ foreach ($no_member_user as $value){
+
+ $dis = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $value
+ ];
+
+ $this->getMemberInfo($dis);
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 15:30
+ * @功能说明:统计
+ */
+ public function listForm($id){
+
+ $order_model = new \app\shop\model\Order();
+
+ $car_order_model = new Order();
+
+ $record_model = new CarAtvRecord();
+
+ $dis[] = ['user_id','=',$id];
+
+ $dis[] = ['pay_type','>',1];
+
+// $dis[] = ['create_time','>',$member['create_time']];
+ //商城消费金额
+ $shop_price = $order_model->where($dis)->sum('true_price');
+ //商城订单量
+ $shop_count = $order_model->where($dis)->count();
+ //赛车订单
+ $car_price = $car_order_model->where($dis)->sum('pay_price');
+ //赛车订单量
+ $car_count = $car_order_model->where($dis)->count();
+ //活动订单
+ $atv_price = $record_model->where($dis)->sum('pay_price');
+ //活动订单量
+ $atv_count = $record_model->where($dis)->count();
+
+ $data = [
+
+ 'price' => round($shop_price+$car_price+$atv_price,2),
+
+ 'count' => round($shop_count+$car_count+$atv_count,2),
+ ];
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-19 16:09
+ * @功能说明:获取总的订单
+ */
+ public function totalOrder($user_id,$type=1){
+
+ $order_model = new Order();
+
+// $dis = [
+//
+// ''
+// ]
+
+ if($type==1){
+
+
+
+
+ }else{
+
+
+ }
+
+
+
+
+
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 09:44
+ * @功能说明:用户信息
+ */
+ public function userInfo($user_id,$uniacid){
+
+ $dis = [
+
+ 'b.id' => $user_id
+
+ ];
+ //用户信息
+ $user_info = $this->memberInfoIndex($dis);
+ //等级模型
+ $level_model = new Level();
+
+ $user_info['now_level'] = $level_model->getUserLevel($user_id,$uniacid);
+ //是否是会员
+ $user_info['is_member'] = !empty($user_info['now_level'])?1:0;
+
+ if(!empty($user_info['now_level'])&&$user_info['now_level']['top']==999){
+ //下一级等级
+ $user_info['next_level'] = [];
+
+ }else{
+ //下一级等级
+ $user_info['next_level'] = $level_model->getMemberLevel($uniacid,$user_info['growth']);
+ }
+
+ return $user_info;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 09:16
+ * @功能说明:更新会员
+ */
+ public function updateMember($order){
+
+ $growth_model = new Growth();
+
+ $level_model = new Level();
+
+ $integral_model = new Integral();
+
+ $member_goods_model = new Goods();
+
+ Db::startTrans();
+ //还未升级以前的等级
+ $level_start = $level_model->getUserLevel($order['user_id'],$order['uniacid']);
+ //如果空就不是会员
+ $level_start = !empty($level_start['top'])?$level_start['top']:0;
+ //普通会员给成长值,plus会员给时间
+ $member_goods_model->ordertypeUpdate($order);
+ //增加成长值
+ $growth_model->incUserGrowth($order['id'],$order['user_id'],$order['uniacid']);
+ //增加后的等级
+ $level_end = $level_model->getUserLevel($order['user_id'],$order['uniacid']);
+
+ $level_end = !empty($level_end['top'])?$level_end['top']:0;
+ //普通会员升级礼包
+ if($level_end>$level_start){
+
+ $level_model->upUserRights($level_end,$order);
+
+ }
+ //增加积分
+ $integral_model->incUserIntegral($order['id'],$order['user_id'],$order['uniacid']);
+
+ Db::commit();
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 09:43
+ * @功能说明:加减成长值
+ */
+ public function incDecGrowth($dis,$growth,$file = 'growth',$type = 0){
+
+ if($type==0){
+
+ $this->where($dis)->update([$file=>Db::raw("$file+$growth")]);
+
+ }else{
+
+ $this->where($dis)->update([$file=>Db::raw("$file-$growth")]);
+
+ }
+
+ return true;
+ }
+
+ /**
+ * @param $dis
+ * @功能说明:获取数据 没有就添加一条
+ * @author chenniang
+ * @DataTime: 2020-07-31 09:27
+ */
+
+ public function getMemberInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->memberAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return $data->toArray();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-03 11:51
+ * @功能说明:商品详情
+ */
+ public function goodsInfoMember($goods_id,$user_id,$uniacid){
+
+ //会员权限
+ $member_p = new PermissionMember($uniacid);
+ //会员商品折扣模型
+ $discount_goods_model = new DiscountGoods();
+ //会员配置模型
+ $member_config_model = new Config();
+ //会员等级模型
+ $level_model = new Level();
+
+ $member_config = $member_config_model->configInfo(['uniacid'=>$uniacid]);
+ //sass端授权
+ $member_auth = $member_p->pAuth();
+ //会员开关
+ $data['member_auth'] = $member_config['status']==1?$member_auth:false;
+ //会员商品折扣
+ $data['goods_discount'] = $discount_goods_model->userGoodsDiscount($goods_id,$user_id,$uniacid);
+
+ $data['goods_discount'] = $data['goods_discount']*10;
+ //会员等级
+ $level = $level_model->getUserLevel($user_id,$uniacid);
+
+ $data['level_title'] = !empty($level)?$level['title']:'';
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 09:30
+ * @功能说明:会员购买的回调
+ */
+
+ public function memberPayResult($order){
+
+ $config_model = new Config();
+ //配置
+ $config = $config_model->configInfo(['uniacid'=>$order['uniacid']]);
+
+ if($config['status']==1){
+
+ $level_model = new Level();
+
+ $integral_model = new Integral();
+
+ $growth_model = new Growth();
+ //配置
+ $config = $config_model->configInfo(['uniacid'=>$order['uniacid']]);
+ //等级
+ $level = $level_model->getUserLevel($order['user_id'],$order['uniacid']);
+ //每日限领积分
+ $day_integral = $integral_model->dayIntegral($order['user_id'],$order['uniacid']);
+ //赠送积分
+ if(!empty($config['integral_cash'])){
+ //积分
+ $integral = $order['total_price']*$config['integral_cash'];
+ //积分倍率
+ $balance = !empty($level['integral_switch'])?$level['integral']:1;
+ //要加的积分
+ $integral = $integral*$balance;
+ //最终的积分
+ $integral = is_numeric($day_integral)&&$day_integral<$integral?$day_integral:$integral;
+ //添加积分记录
+ $integral_model->integralUserAdd($order['user_id'],$integral,$order['uniacid'],1,1,$order['id']);
+
+ }
+ //每日限领成长值
+ $day_growth = $growth_model->dayGrowth($order['user_id'],$order['uniacid']);
+ //赠送增长值(金额)
+ if(!empty($config['growth_cash'])&&!empty($level)){
+ //成长值
+ $growth_cash = intval($order['total_price']*$config['growth_cash']);
+ //最终成长值
+ $growth_cash = is_numeric($day_growth)&&$day_growth<$growth_cash?$day_growth:$growth_cash;
+ //添加成长值记录
+ $growth_model->addUserGrowth($order['uniacid'],$order['user_id'],$growth_cash,$order['id'],1);
+ }
+ //赠送增长值(订单) 只有会员才送
+ if(!empty($config['growth_order'])&&!empty($level)){
+ //成长值
+ $growth_cash = intval($config['growth_order']);
+ //最终成长值
+ $growth_cash = is_numeric($day_growth)&&$day_growth<$growth_cash?$day_growth:$growth_cash;
+ //添加成长值记录
+ $growth_model->addUserGrowth($order['uniacid'],$order['user_id'],$growth_cash,$order['id'],1);
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-07 17:12
+ * @功能说明:退款
+ */
+ public function refundOrder($order_id){
+
+ $integral_model = new Integral();
+
+ $growth_model = new Growth();
+
+ $dis = [
+
+ 'order_id' => $order_id
+ ];
+
+ $integral_model->where($dis)->update(['refund'=>1]);
+
+ $growth_model->where($dis)->update(['refund'=>1]);
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-11 11:25
+ * @功能说明:会员权限
+ */
+ public function getAuth($uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ $persisson = new PermissionMember($uniacid);
+
+ $auth = $persisson->pAuth();
+
+ $auth = $config['status']==1?$auth:false;
+
+ return $auth;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Rights.php b/app/member/model/Rights.php
new file mode 100755
index 0000000..d31aff6
--- /dev/null
+++ b/app/member/model/Rights.php
@@ -0,0 +1,368 @@
+where(['rights_id'=>$data['id']])->find();
+
+ return !empty($info)?1:0;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 09:49
+ * @功能说明:添加
+ */
+ public function rightsAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $data['update_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 11:57
+ * @功能说明:初始化
+ */
+ public function initData($uniacid){
+
+ $dis = [
+
+ 'uniacid' => $uniacid,
+
+ 'type' => 0
+
+ ];
+
+ $data = $this->rightsInfo($dis);
+
+ if(empty($data)){
+
+ $arr = [
+
+ [
+ 'title' => '消费折扣',
+
+ 'show_title' => '优享会员价',
+
+ 'type' => 0,
+
+ 'content' => '',
+
+ 'top' => 10,
+
+ 'icon' => 'https://longbingcdn.xiaochengxucms.com/admin/car/discount.png',
+
+ 'uniacid' => $uniacid,
+
+ 'use_type' => 1,
+
+ 'status' => 1
+
+ ],[
+ 'title' => '积分倍率',
+
+ 'show_title' => '会员多积分',
+
+ 'type' => 0,
+
+ 'content' => '',
+
+ 'top' => 10,
+
+ 'icon' => 'https://longbingcdn.xiaochengxucms.com/admin/car/multiple.png',
+
+ 'uniacid' => $uniacid,
+
+ 'use_type' => 2,
+
+ 'status' => 1
+ ],[
+ 'title' => '赠送积分',
+
+ 'show_title' => '会员专享积分',
+
+ 'type' => 0,
+
+ 'content' => '',
+
+ 'top' => 10,
+
+ 'icon' => 'https://longbingcdn.xiaochengxucms.com/admin/car/integral.png',
+
+ 'uniacid' => $uniacid,
+
+ 'use_type' => 3,
+
+ 'status' => 1,
+
+ 'is_up' => 1
+
+ ],
+ [
+
+ 'title' => '会员送券',
+
+ 'show_title' => '送卡券',
+
+ 'type' => 0,
+
+ 'content' => '',
+
+ 'top' => 10,
+
+ 'icon' => 'https://longbingcdn.xiaochengxucms.com/admin/car/coupon.png',
+
+ 'uniacid' => $uniacid,
+
+ 'use_type' => 4,
+
+ 'status' => 1,
+
+ 'is_up' => 1
+ ]
+ ];
+
+ $this->saveAll($arr);
+
+ }
+
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:12
+ * @功能说明:列表
+ */
+ public function rightsList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function rightsInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function rightsUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-22 16:58
+ * @功能说明:自定义权益
+ */
+ public function customRights($member_id){
+
+ $dis[]= ['b.member_id','=',$member_id];
+
+ $dis[]= ['b.type','=',1];
+
+ $dis[]= ['a.status','=',1];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_v2_member_rights_relation b','a.id = b.rights_id')
+ ->where($dis)
+ ->group('b.rights_id')
+ ->column('a.title');
+
+ return array_values($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-28 10:38
+ * @功能说明:会员权益
+ */
+ public function memberRights($level_id,$uniacid){
+
+ $dis = [
+
+ 'b.member_id' => $level_id,
+
+ 'b.uniacid' => $uniacid,
+
+ 'a.status' => 1
+ ];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_v2_member_rights_relation b','a.id = b.rights_id')
+ ->where($dis)
+ ->field(['a.id','a.show_title','a.type','a.use_type','a.icon'])
+ ->group('a.id')
+ ->order(['a.top desc','a.id desc'])
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-29 10:49
+ * @功能说明:商品等级下拉框
+ */
+ public function goodsLevelSelect($dis){
+
+ $data = $this->alias('a')
+ ->join('longbing_card_member_rights_relation b','a.id = b.rights_id')
+ ->join('longbing_card_member_level c','c.id = b.member_id')
+ ->where($dis)
+ ->field('c.title,c.id,c.top')
+ ->group('c.id')
+ ->order('c.top')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 17:40
+ * @功能说明:给用户权益
+ */
+ public function giveRights($level_id,$user_id,$order_id=0){
+
+ $log_model = new RightsLog();
+
+ $level_model = new Level();
+
+ $level = $level_model->levelInfo(['id'=>$level_id]);
+
+ if(empty($level)){
+
+ return false;
+ }
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'level_id'=> $level_id,
+
+ 'uniacid' => $level['uniacid']
+ ];
+ //已经给或该权益了
+ $find = $log_model->rightsInfo($dis);
+
+ if(!empty($find)){
+
+ return false;
+ }
+
+ $log_model->insert($dis);
+ //赠送积分
+ if(!empty($level['send_integral'])&&!empty($level['send_integral_switch'])){
+
+ $point_model = new Integral();
+
+ $point_model->integralUserAdd($user_id,$level['send_integral'],$level['uniacid'],2,0,$order_id);
+ }
+ //赠送卡券
+ //优惠券
+ $coupon_model= new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $dis = [
+
+ 'member_id' => $level_id
+ ];
+ //优惠券
+ $coupon = $coupon_model->where($dis)->select()->toArray();
+
+ if(!empty($coupon)&&!empty($level['coupon_switch'])){
+
+ foreach ($coupon as &$value){
+
+ $coupon_record_model->recordAdd($value['coupon_id'],$user_id,$value['num']);
+
+ }
+
+ }
+
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/RightsLog.php b/app/member/model/RightsLog.php
new file mode 100755
index 0000000..970453d
--- /dev/null
+++ b/app/member/model/RightsLog.php
@@ -0,0 +1,79 @@
+insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:12
+ * @功能说明:列表
+ */
+ public function rightsList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function rightsInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:删除直播
+ */
+ public function rightsUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/RightsRelation.php b/app/member/model/RightsRelation.php
new file mode 100755
index 0000000..d35e2c4
--- /dev/null
+++ b/app/member/model/RightsRelation.php
@@ -0,0 +1,79 @@
+insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:12
+ * @功能说明:列表
+ */
+ public function rightsList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function rightsInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:删除直播
+ */
+ public function rightsUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/Stored.php b/app/member/model/Stored.php
new file mode 100755
index 0000000..55eaf36
--- /dev/null
+++ b/app/member/model/Stored.php
@@ -0,0 +1,177 @@
+storedType($data['id']);
+
+ return $type;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-09 10:37
+ * @功能说明:列表
+ */
+ public function storedList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 09:49
+ * @功能说明:添加
+ */
+ public function storedAdd($data){
+
+ $data['create_time'] = time();
+
+ $data['update_time'] = time();
+
+ $data['status'] = 1;
+
+ if(isset($data['coupon'])){
+
+ $coupon = $data['coupon'];
+
+ unset($data['coupon']);
+ }
+
+ $res = $this->insert($data);
+
+ if(!empty($coupon)){
+
+ $id = $this->getLastInsID();
+
+ $this->updateSome($id,$coupon,$data['uniacid']);
+ }
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-08-27 17:16
+ * @功能说明:编辑
+ */
+ public function updateSome($id,$coupon,$uniacid){
+
+ $coupon_model = new StoredCoupon();
+
+ $coupon_model->where(['stored_id'=>$id])->delete();
+
+ if(!empty($coupon)){
+
+ foreach ($coupon as $value){
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'coupon_id'=> $value['coupon_id'],
+
+ 'stored_id'=> $id,
+
+ 'num' => $value['num']
+
+ ];
+
+ $coupon_model->insert($insert);
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function storedInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function storedUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ if(isset($data['coupon'])){
+
+ $coupon = $data['coupon'];
+
+ unset($data['coupon']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($coupon)){
+
+ $id = $dis['id'];
+
+ $this->updateSome($id,$coupon,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/StoredCoupon.php b/app/member/model/StoredCoupon.php
new file mode 100755
index 0000000..515afcd
--- /dev/null
+++ b/app/member/model/StoredCoupon.php
@@ -0,0 +1,156 @@
+where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-15 09:49
+ * @功能说明:添加
+ */
+ public function storedAdd($data){
+
+ $data['create_time'] = time();
+
+ $data['update_time'] = time();
+
+ $data['status'] = 1;
+
+ $res = $this->insert($data);
+
+ return $res;
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function storedInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function storedUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-08 16:30
+ * @功能说明:添加用户的优惠券
+ */
+ public function insertCoupon($id,$user_id,$uniacid){
+
+
+ $order = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $user_id,
+
+ 'to_uid' => 0
+ ];
+
+
+ $dis = [
+
+ 'a.stored_id' => $id
+ ];
+
+
+ $data = $this->alias('a')
+ ->join('longbing_card_coupon b','a.coupon_id = b.id')
+ ->where($dis)
+ ->group('a.coupon_id')
+ ->field('b.*,a.num as coupon_num')
+ ->select()
+ ->toArray();
+
+ $record_model = new IndexCouponRecord();
+
+ if(!empty($data)){
+
+ foreach ($data as $coupon){
+
+ for ($i=0;$i<$coupon['coupon_num'];$i++){
+
+ if(!isset($order['staff_id'])&&isset($order['to_uid'])){
+
+ $order['staff_id'] = $order['to_uid'];
+ }
+ //领取优惠券
+ $record_model->insertRecord($coupon,$order);
+
+ }
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/StoredLevel.php b/app/member/model/StoredLevel.php
new file mode 100755
index 0000000..e97833a
--- /dev/null
+++ b/app/member/model/StoredLevel.php
@@ -0,0 +1,101 @@
+where(['member_id'=>$level_id])->delete();
+
+ if(!empty($stored)){
+
+ array_walk($stored, function ($value, $key) use (&$stored, $level_id,$data) {
+
+ $stored[$key] = [
+ //等级id
+ 'member_id' => $level_id,
+
+ 'uniacid' => $data['uniacid'],
+
+ 'stored_id' => $value,
+
+ ];
+
+ });
+ //添加
+ $res = $this->saveAll($stored);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-11 11:10
+ * @功能说明:储值卡类型
+ */
+ public function storedType($stored_id){
+
+ $dis = [
+
+ 'a.stored_id' => $stored_id,
+
+ 'b.status' => 1,
+
+ 'b.type' => 1
+ ];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_member_level b','a.member_id=b.id')
+ ->where($dis)
+ ->find();
+
+ return !empty($data)?1:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-11 15:49
+ * @功能说明:获取puls会员的详情
+ */
+ public function getLevel($stored_id){
+
+ $dis = [
+
+ 'a.stored_id' => $stored_id,
+
+ 'b.status' => 1,
+
+ 'b.type' => 1
+ ];
+
+ $data = $this->alias('a')
+ ->join('longbing_card_member_level b','a.member_id=b.id')
+ ->where($dis)
+ ->field('b.*')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/model/StoredOrder.php b/app/member/model/StoredOrder.php
new file mode 100755
index 0000000..a4c831d
--- /dev/null
+++ b/app/member/model/StoredOrder.php
@@ -0,0 +1,566 @@
+where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-11 10:29
+ * @功能说明:下单
+ */
+ public function addOrder($stored,$user_id,$staff_id,$share_id){
+
+ $member_model = new Member();
+
+ $member_info = $member_model->getMemberInfo(['user_id'=>$user_id,'uniacid'=>$stored['uniacid']]);
+
+ $data = [
+
+ 'create_time' => time(),
+
+ 'status' => 0,
+
+ 'user_id' => $user_id,
+
+ 'staff_id' => $staff_id,
+
+ 'stored_id' => $stored['id'],
+
+ 'pay_price' => round($stored['pay_price'],2),
+
+ 'true_price' => round($stored['true_price'],2),
+
+ 'true_price_before' => round($member_info['stored'],2),
+
+ 'true_price_after' => round($member_info['stored']+$stored['true_price'],2),
+
+ 'growth' => $stored['growth'],
+
+ 'title' => $stored['title'],
+
+ 'uniacid' => $stored['uniacid'],
+
+ 'order_code' => orderCode(),
+
+ 'type' => $stored['stored_type'],
+
+ 'over_time' => 0,
+
+ 'share_id' => $share_id
+
+ ];
+ //如果是puls会员的,要把过期时间加好
+ if($stored['stored_type']==1){
+
+ $stored_level_model = new StoredLevel();
+
+ $level = $stored_level_model->getLevel($stored['id']);
+
+ if(empty($level)){
+
+ return ['code'=>400,'msg'=>'等级未找到'];
+ }
+
+ $data['over_time'] = $level['over_time'];
+ }
+
+ $res = $this->insert($data);
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-17 13:48
+ * @功能说明:订单退款时候处理储值
+ */
+ public function orderRefundStore($order_id,$app,$refund_prices){
+
+ $order_model = new IndexShopOrder();
+
+ $order_info = $order_model->orderInfo(['id'=>$order_id]);
+ //储值支付
+ $reslut = new IndexPayResunt($app);
+ //储值记录
+ $res = $reslut->orderStoredResult($order_info,5,$refund_prices);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-16 10:52
+ * @功能说明:储值扣款
+ */
+ public function desStore($price,$text,$member_info,$controller_type,$controller,$order_code=0,$title=0){
+ //注意:(3和5的order_code都是商城订单的order_code,其他的都是系统生成的)
+ $order_code = !empty($order_code)?$order_code:orderCode();
+ //4 是直接修改价格 1、2、3的是扣除 0、5充值是加,6是加 霸王餐优惠;7申请提现;8申请拒绝
+ switch ($controller_type){
+
+ case 0:
+ $true_price_after = round($member_info['stored']+$price,2);
+ break;
+
+ case 1:
+ $true_price_after = round($member_info['stored']-$price,2);
+ break;
+
+ case 2:
+ $true_price_after = round($member_info['stored']-$price,2);
+ break;
+
+ case 3:
+ $true_price_after = round($member_info['stored']-$price,2);
+ break;
+
+ case 4:
+ $true_price_after = $price;
+ break;
+
+ case 5:
+ $true_price_after = round($member_info['stored']+$price,2);
+ break;
+
+ case 6:
+ $true_price_after = round($member_info['stored']+$price,2);
+ break;
+
+ case 7:
+ $true_price_after = round($member_info['stored']-$price,2);
+ break;
+
+ case 8:
+ $true_price_after = round($member_info['stored']+$price,2);
+ break;
+
+ }
+
+ $data = [
+
+ 'create_time' => time(),
+
+ 'pay_time' => time(),
+
+ 'status' => 0,
+
+ 'user_id' => $member_info['user_id'],
+
+ 'staff_id' => in_array($controller_type,[1,4,6,7,8])?0:$controller,
+
+ 'stored_id' => 0,
+
+ 'pay_price' => round($price,2),
+
+ 'true_price' => round($price,2),
+
+ 'true_price_before' => round($member_info['stored'],2),
+ //4 是直接修改价格 2、3的是扣除 1充值是加
+ 'true_price_after' => $true_price_after,
+
+ 'growth' => 0,
+
+ 'title' => $title,
+
+ 'uniacid' => $member_info['uniacid'],
+
+ 'order_code' => $order_code,
+
+ 'type' => 0,
+
+ 'over_time' => 0,
+
+ 'share_id' => 0,
+
+ 'status' => 2,
+
+ 'controller_type' => $controller_type,
+
+ 'controller' => $controller,
+
+ 'text' => $text
+
+ ];
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if($res==1){
+
+ $member_model = new Member();
+
+ if(in_array($controller_type,[4])){
+
+ $y_price = $price;
+
+ }elseif (in_array($controller_type,[1,2,3])){
+
+ $y_price = $member_info['stored']-$price;
+
+ }elseif (in_array($controller_type,[0,5])){
+
+ $y_price = $member_info['stored']+$price;
+ //霸王餐 优惠 管理员
+ }elseif (in_array($controller_type,[6,8])){
+
+ $y_price = $member_info['stored']+$price;
+
+ $member_info['cash_stored'] +=$price;
+ //提现 (霸王餐)
+ }elseif (in_array($controller_type,[7])){
+
+ $y_price = $member_info['stored']-$price;
+
+ $member_info['cash_stored'] -=$price;
+
+ }
+
+ $where[] = ['id','=',$member_info['id']];
+
+ $where[] = ['stored','>=',0];
+
+ $res = $member_model->where($where)->update(['stored'=>$y_price,'cash_stored'=>$member_info['cash_stored']]);
+ //目前只有员工扣款和后台扣款有佣金
+ if(in_array($controller_type,[1,2])){
+
+ $order = $this->orderInfo(['id'=>$id]);
+ //配置模型
+ $congfig = new Config();
+ //返佣
+ $congfig->controllerCommission($order);
+ }
+
+ }
+
+ return $res;
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-11 10:59
+ * @功能说明:回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order = $this->where(['order_code'=>$order_code])->find();
+
+ if(empty($order_code)||$order->status!=0){
+
+ return false;
+ }
+
+ $order = $order->toArray();
+ //修改订单状态
+ $this->where(['order_code'=>$order_code])->update(['status'=>2,'pay_time'=>time(),'transaction_id'=>$transaction_id]);
+ //会员模型
+ $member_model = new Member();
+ //等级模型
+ $level_model = new Level();
+ //获取用户会员信息(没有则创建)
+ $user_info = $member_model->memberUpdateInfo(['user_id'=>$order['user_id'],'uniacid'=>$order['uniacid']]);
+ //送储值
+ $row['stored'] = $user_info['stored']+$order['true_price'];
+ //0是普通会员,要送成长值
+ if($order['type']==0){
+
+ $row['growth'] = $user_info['growth']+$order['growth'];
+
+ $growth_model = new Growth();
+
+ $growth_model->addUserGrowth($order['uniacid'],$order['user_id'],$order['growth'],$order['id'],2,2);
+
+
+ }else{
+ //1是plus会员,给会员过期时间
+ if($user_info['over_time']upUserRights('999',$order);
+ }
+ }
+ //编辑用户
+ $level_model->upUserRightsEnd($row,$order);
+ //返佣
+ $config_model = new Config();
+
+ $config_model->storeOrderCommission($order);
+
+ $store_coupon = new StoredCoupon();
+
+ $store_coupon->insertCoupon($order['stored_id'],$order['user_id'],$order['uniacid']);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 16:35
+ * @功能说明:列表
+ */
+ public function recordList($dis,$page){
+
+ $data = $this->where($dis)->order(['create_time desc','id desc'])->paginate($page)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v = $this->orderText($v['id']);
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-27 14:33
+ * @功能说明:拼接扣款文案
+ */
+ public function orderText($order_id){
+
+ $v = $this->orderInfo(['id'=>$order_id]);
+
+ //购买储值套餐
+ if($v['controller_type']==0){
+
+ $v['controller_avatar'] = lbUserAvatar($v['user_id']);
+
+ $v['controller_name'] = '系统核算';
+
+ $icon = $v['true_price']>0?'+':'-';
+
+ $growth_add = $v['true_price']>0?$v['true_price']:$v['true_price']*-1;
+
+ $boj = $this->returnObj($v['type']);
+
+ $v['admin_text'] = $boj.'【'.$v['title'].'】'.$icon.'¥'.$growth_add.',现余额 ¥'.$v['true_price_after'];
+
+ $v['index_text'] = $boj.'【'.$v['title'].'】';
+
+ }elseif($v['controller_type']==1){
+ //后台扣款
+ $v['controller_name'] = Db::name('longbing_admin')->where(['admin_id'=>$v['controller']])->value('account');
+
+ $v['controller_avatar'] = 'https://retail.xiaochengxucms.com/defaultAvatar.png';
+
+ $v['admin_text'] = '扣除储值 ¥'.$v['true_price'].',现储值 ¥'.$v['true_price_after'];
+
+ $v['true_price'] = '-'.$v['true_price'];
+
+ $v['index_text'] = '系统扣除储值';
+
+ }elseif($v['controller_type']==2){
+ //员工扣款
+ $v['controller_avatar'] = lbUserAvatar($v['controller']);
+
+ $v['controller_name'] = lbUserName($v['controller']);
+
+ $v['admin_text'] = '扣除储值 ¥'.$v['true_price'].',现储值 ¥'.$v['true_price_after'];
+
+ $v['true_price'] = '-'.$v['true_price'];
+
+ $v['index_text'] = '员工扣除储值'.'【'.$v['controller_name'].'】';
+
+ }elseif ($v['controller_type']==3){
+ //购买套餐
+ $v['controller_avatar'] = lbUserAvatar($v['user_id']);
+
+ $v['controller_name'] = '系统核算';
+
+ $growth_add = $v['true_price']>0?$v['true_price']:$v['true_price']*-1;
+
+ $boj = $this->returnObj($v['controller_type']);
+
+ $v['admin_text'] = $boj.'【'.$v['title'].'】-¥'.$growth_add.',现余额 ¥'.$v['true_price_after'];
+
+ $v['index_text'] = $boj.'【'.$v['title'].'】';
+
+ $v['true_price'] = '-'.$v['true_price'];
+
+ }elseif ($v['controller_type']==4){
+ //员工修改
+ $v['controller_name'] = Db::name('longbing_admin')->where(['admin_id'=>$v['controller']])->value('account');
+
+ $v['controller_avatar'] = 'https://retail.xiaochengxucms.com/defaultAvatar.png';
+
+ $v['admin_text'] = '储值 ¥'.$v['true_price_before'].',修改为 ¥'.$v['true_price_after'];
+
+ $v['index_text'] = '系统修改储值';
+
+ }elseif ($v['controller_type']==5){
+ //购买商品退款
+ $v['controller_avatar'] = lbUserAvatar($v['user_id']);
+
+ $v['controller_name'] = '系统核算';
+
+ $growth_add = $v['true_price']>0?$v['true_price']:$v['true_price']*-1;
+
+ $boj = $this->returnObj($v['controller_type']);
+
+ $v['admin_text'] = $boj.'【'.$v['title'].'】+¥'.$growth_add.',现余额 ¥'.$v['true_price_after'];
+
+ $v['index_text'] = $boj.'【'.$v['title'].'】';
+
+
+ }elseif ($v['controller_type']==6){
+ //霸王餐优惠
+ $v['controller_avatar'] = lbUserAvatar($v['user_id']);
+
+ $v['controller_name'] = is_numeric($v['controller'])?lbUserName($v['controller']):Db::name('longbing_admin')->where(['admin_id'=>$v['controller']])->value('account');;
+
+ $growth_add = $v['true_price'];
+
+ $boj = $this->returnObj($v['controller_type']);
+
+ $atv_model = new Active();
+
+ $title = $atv_model->where(['id'=>$v['title']])->value('title');
+
+ $v['admin_text'] = $boj.'【'.$title.'】'.'¥'.$growth_add.',现余额 ¥'.$v['true_price_after'];
+
+ $v['index_text'] = $boj.'【'.$title.'】';
+
+ }elseif ($v['controller_type']==7){
+ //霸王餐优惠(提现)
+ $v['controller_avatar'] = lbUserAvatar($v['user_id']);
+
+ $v['controller_name'] = is_numeric($v['controller'])?lbUserName($v['controller']):Db::name('longbing_admin')->where(['admin_id'=>$v['controller']])->value('account');;
+
+ $growth_add = $v['true_price'];
+
+ $boj = $this->returnObj($v['controller_type']);
+
+ $v['admin_text'] = $boj.'-¥'.$growth_add.',现余额 ¥'.$v['true_price_after'];
+
+ $v['true_price'] = '-'.$v['true_price'];
+
+ $v['index_text'] = $boj;
+
+ }elseif ($v['controller_type']==8){
+ //霸王餐优惠(拒绝提现)
+ $v['controller_avatar'] = lbUserAvatar($v['user_id']);
+
+ $v['controller_name'] = Db::name('longbing_admin')->where(['admin_id'=>$v['controller']])->value('account');;
+
+ $growth_add = $v['true_price'];
+
+ $boj = $this->returnObj($v['controller_type']);
+
+ $v['admin_text'] = $boj.'¥'.$growth_add.',现余额 ¥'.$v['true_price_after'];
+
+ $v['index_text'] = $boj;
+
+ }
+
+ return $v;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 15:17
+ * @功能说明:返回一个对象
+ */
+ public function returnObj($type){
+
+ switch ($type){
+ //购买会员商品
+ case 0:
+ return '购买套餐';
+
+ break;
+ //会员购买商品
+ case 1:
+ return '购买套餐';
+
+ break;
+ //购买储值套餐赠送
+ case 2:
+ return '购买储值套餐赠送';
+
+ break;
+
+ case 3:
+ return '购买商品';
+
+ break;
+
+ case 5:
+ return '商品退款';
+
+ break;
+ case 6:
+ return '霸王餐活动';
+
+ break;
+ case 7:
+ return '提现申请';
+
+ break;
+ case 8:
+ return '拒绝提现';
+
+ break;
+ default:
+ return '消费获得';
+
+ break;
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/member/route/route.php b/app/member/route/route.php
new file mode 100755
index 0000000..819f322
--- /dev/null
+++ b/app/member/route/route.php
@@ -0,0 +1,130 @@
+
+// +----------------------------------------------------------------------
+
+use app\ExceptionHandle;
+use app\Request;
+
+// 容器Provider定义文件
+return [
+ 'think\Request' => Request::class,
+ 'think\exception\Handle' => ExceptionHandle::class,
+];
diff --git a/app/publics/controller/AdminTmpl.php b/app/publics/controller/AdminTmpl.php
new file mode 100755
index 0000000..fe37609
--- /dev/null
+++ b/app/publics/controller/AdminTmpl.php
@@ -0,0 +1,111 @@
+model = new TmplConfig();
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-26 15:40
+ * @功能说明: 添加模版消息 并返回模版id
+ */
+ public function getTmplId(){
+
+ $input = $this->_input;
+ //实列化模版订阅通知库类;
+ $service_model = new WxTmpl($this->_uniacid);
+
+ $dis['id'] = $input['id'];
+ //生成模版消息
+ $tmpl_data = $service_model::addtmpl($dis);
+ //返回结果
+ if(isset($tmpl_data['errcode'])&&$tmpl_data['errcode']==0){
+ //修改数据库
+ $this->model->tmplUpdate($dis,['tmpl_id'=>$tmpl_data['priTmplId']]);
+
+ return $this->success($tmpl_data['priTmplId']);
+ }else{
+ return $this->error($tmpl_data['errmsg']);
+ }
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-30 11:08
+ * @功能说明:生成数据库模版消息
+ */
+ public function tmpList(){
+ //获取模块名
+ $input = $this->_input;
+
+ $tmpl_data = [] ;
+ if(isset($input['model_name'])){
+ $tmpl_data = PublicsService::getTmplByModelName($this->_uniacid , $input['model_name']) ;
+ }
+ return $this->success($tmpl_data);
+
+ }
+
+ /**
+ * @author jingshuixian
+ * @DataTime: 2020/1/15 11:16
+ * @功能说明:获取所有有权限的订阅消息配置列表
+ */
+ public function tmpLists(){
+
+ $authModelList = AdminMenu::getAuthList($this->_uniacid);
+ $tmpl_data = [] ;
+ foreach ($authModelList as $key => $item ){
+
+ $modelTmplData = PublicsService::getTmplByModelName($this->_uniacid , $key ) ;
+
+ $tmpl_data = array_merge($tmpl_data , $modelTmplData ) ;
+
+ }
+
+ return $this->success($tmpl_data);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-26 18:38
+ * @功能说明:商城模块编辑
+ */
+ public function tmplUpdate(){
+ $input = $this->_input;
+ if(!empty($input)&&is_array($input)){
+ foreach ($input as $value){
+ $res = $this->model->tmplUpdate(['id'=>$value['id']],['tmpl_id'=>$value['tmpl_id'],'kidList'=>$value['kidList']]);
+ }
+ return $this->success($res);
+ }else{
+ return $this->error('参数错误');
+ }
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/publics/controller/HttpAsyn.php b/app/publics/controller/HttpAsyn.php
new file mode 100755
index 0000000..ae351f8
--- /dev/null
+++ b/app/publics/controller/HttpAsyn.php
@@ -0,0 +1,71 @@
+ $data['user_id']]);
+ longbingCreateSharePng($data['gData'] ,$data['user_id'] ,$data['uniacid']);
+ break;
+ case 'longbingSaveFormId':
+ longbingSaveFormId($data['data']);
+ break;
+ case 'longbingCreateHeaderQr':
+ UserService::createHeaderQr($data['uniacid'],['staff_id'=> $data['user_id']]);
+ break;
+
+ case 'collageFailCancelOrder':
+
+ $collage_model = new CollageStart();
+
+ $collage_model->initAtv($data['pay_config']);
+ break;
+ }
+ //}catch(Exception $e)
+ //{}
+ echo 'message ok ';
+
+ }
+
+}
diff --git a/app/publics/controller/IndexTmpl.php b/app/publics/controller/IndexTmpl.php
new file mode 100755
index 0000000..b9aec08
--- /dev/null
+++ b/app/publics/controller/IndexTmpl.php
@@ -0,0 +1,40 @@
+model = new TmplConfig();
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-26 15:40
+ * @功能说明: 获取模版消息
+ */
+ public function getTmplId(){
+ $input = $this->_input;
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ $dis[] = ['tmpl_id','<>',0];
+ $dis[] = ['tmpl_name','in',$input['tmpl_name']];
+ $data = $this->model->tmplIdList($dis);
+ return $this->success($data);
+ }
+
+
+
+
+
+
+}
diff --git a/app/publics/controller/IndexWxPay.php b/app/publics/controller/IndexWxPay.php
new file mode 100755
index 0000000..74e57c6
--- /dev/null
+++ b/app/publics/controller/IndexWxPay.php
@@ -0,0 +1,178 @@
+app = $app;
+ }
+
+
+ /**
+ * @param $paymentApp
+ * @param $openid
+ * @param $uniacid
+ * @param $body
+ * @param $attach
+ * @param $totalprice
+ * @throws \WxPayException
+ * 支付
+ */
+ public function createWeixinPay($paymentApp , $openid , $uniacid , $body , $attach,$totalprice){
+ global $_GPC, $_W;
+ $setting['mini_appid'] = $paymentApp['app_id'];
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+ define('WX_APPID', $setting['mini_appid']);
+ define('WX_MCHID', $setting['mini_mid']);
+ define('WX_KEY', $setting['mini_apicode']);
+ define('WX_APPSECRET', $setting['mini_appsecrept']);
+ define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+ define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+ define('WX_CURL_PROXY_HOST', '0.0.0.0');
+ define('WX_CURL_PROXY_PORT', 0);
+ define('WX_REPORT_LEVENL', 0);
+
+
+ require_once PAY_PATH . "/weixinpay/lib/WxPay.Api.php";
+ require_once PAY_PATH . "/weixinpay/example/WxPay.JsApiPay.php";
+
+ $tools = new \JsApiPay();
+ $input = new \WxPayUnifiedOrder();
+
+ $input->SetBody($body);
+ $input->SetAttach(json_encode($attach));
+ $input->SetOut_trade_no($attach['out_trade_no']);
+ $input->SetTotal_fee($totalprice *100);
+ $input->SetTime_start(date("YmdHis"));
+
+ $param_arr=[
+ 'i' => $uniacid,
+ 't' => $_GPC['t'],
+ 'v' => $_GPC['v'],
+ 'n' => APP_MODEL_NAME
+ ];
+ $reply_path=json_encode($param_arr);
+ //需要判断 是否是微擎的版本
+ if(defined('IS_WEIQIN')){
+ $path = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?params=".$reply_path;
+ $paths = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?ck=789";
+ $a = @file_get_contents($paths);
+ if($a != 1){
+ $this->errorMsg('发起支付失败');
+ }
+ }else{
+ $path = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?params=".$reply_path;
+ $paths = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?ck=789";
+ $a = @file_get_contents($paths);
+ if($a != 1){
+ $this->errorMsg('发起支付失败');
+ }
+ }
+ $this ->lb_logOutput('BaseApiPath:-----'.$path);
+ $input->SetNotify_url($path);
+ $input->SetTrade_type("JSAPI");
+ $input->SetOpenid($openid);
+ $order = \WxPayApi::unifiedOrder($input);
+ if(!empty($order['return_code'])&&$order['return_code'] == 'FAIL'){
+ $this->errorMsg($order['return_msg']);
+ }
+ $jsApiParameters = $tools->GetJsApiParameters($order);
+
+ $jsApiParameters = json_decode($jsApiParameters, true) ;
+ if (!empty($jsApiParameters['return_code']))
+ $this->errorMsg( '发起支付失败');
+ return $jsApiParameters;
+ }
+
+
+
+
+ /**
+ * @param $data
+ * @param int $flag
+ * @return void|null
+ * 打印数据
+ */
+
+ public function lb_logOutput($data,$flag=0) {
+ if($flag==0){
+ return ;
+ }
+ //数据类型检测
+ if (is_array($data)) {
+ $data = json_encode($data);
+ }
+ $filename = "./".date("Y-m-d").".log";
+ $str = date("Y-m-d H:i:s")." $data"."\r\n";
+ file_put_contents($filename, $str, FILE_APPEND|LOCK_EX);
+ return null;
+ }
+
+ /**
+ * 支付回调
+ */
+
+ public function returnPay(){
+
+ $this->lb_logOutput("in--mingpianNotify");
+ $xmlData = file_get_contents('php://input');
+ if(empty($xmlData)){
+ $xmlData = 'empty xmlData';
+ }
+ $this->lb_logOutput('xmlData in mingpian:-----'.$xmlData);
+
+ $this->lb_logOutput("in-mingpian2");
+ global $_GPC;
+ $xmlData = file_get_contents('php://input');
+ $this->lb_logOutput('in-mingpian-$xmlData:-----'.$xmlData);
+ //获取配置
+
+ if(defined( 'IS_WEIQIN' )){
+ $uniacid=$_GPC['i'];
+ }else{
+ $uniacid = $_GET['i'];
+ }
+
+ $paymentApp = $this->payConfig($uniacid);
+ // dump($paymentApp);exit;
+ $this->lb_logOutput('in-mingpian-uniacid:-----'.$uniacid);
+
+ $setting['mini_appid'] = $paymentApp['app_id'];
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+
+ define('WX_APPID', $setting['mini_appid']);
+ define('WX_MCHID', $setting['mini_mid']);
+ define('WX_KEY', $setting['mini_apicode']);
+ define('WX_APPSECRET', $setting['mini_appsecrept']);
+ define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+ define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+ define('WX_CURL_PROXY_HOST', '0.0.0.0');
+ define('WX_CURL_PROXY_PORT', 0);
+ define('WX_REPORT_LEVENL', 0);
+ require_once PAY_PATH.'/weixinpay/lib/WxOrderNotify.php';
+ $WxPay = new \WxOrderNotify($this->app);
+ $WxPay->Handle(false);
+ }
+
+
+
+
+
+}
diff --git a/app/publics/controller/Pay.php b/app/publics/controller/Pay.php
new file mode 100755
index 0000000..b6400c8
--- /dev/null
+++ b/app/publics/controller/Pay.php
@@ -0,0 +1,17 @@
+type_model = new AdminShopType();
+// $this->company_model = new AdminCompany();
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-26 15:40
+ * @功能说明: 获取模版消息
+ */
+ public function getCompany(){
+ $dis[] = ['status' ,'=',1];
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ $data = $this->company_model->companySelect($dis);
+ return $this->success($data);
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-11-29 17:28
+ * @return void
+ * descption:获取员工
+ */
+ public function getStaffInfo(){
+ $input = $this->_input;
+ $user_model = new UserInfo();
+ $user_info = new CardUser();
+// $data = [];
+ $dis[] = ['is_staff','=',1];
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ if(!empty($input['name'])){
+ $dis[] = ['name','like',"%".$input['name']."%"];
+ }
+ $data = $user_model->where($dis)->field('fans_id as id,name')->select();
+ if(!empty($data)){
+ foreach ($data as &$v){
+ if(empty($v['name'])){
+ $v['name'] = $user_info->where(['id'=>$v['id']])->value('nickName');
+ }
+ }
+ }
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-05-18 16:29
+ * @功能说明:职位列表
+ */
+ public function jobList(){
+
+ $job_model = new Job();
+
+ $input = $this->_input;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = !empty($input['status'])?['status','>',0]:['status','>',-1];
+
+ $list = $job_model->where($dis)->order('top desc')->field('id,name')->select();
+
+ return $this->success($list);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-03 15:16
+ * @功能说明:获取平台所有的用户
+ */
+ public function getAllUser(){
+
+ $user_info = new CardUser();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+
+ ];
+ //只查id和昵称,一般用于下拉框
+ $data = $user_info->where($dis)->field('id,nickName')->select()->toArray();
+
+ return $this->success($data);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-12-08 13:47
+ * @功能说明:商品列表
+ */
+ public function goodsSelect(){
+
+ $input = $this->_input;
+
+ $goods_model = new Goods();
+
+ $spe_price_model = new GoodsSpePrice();
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['name','like','%'.$input['title'].'%'];
+ }
+
+ $data = $goods_model->where($dis)->order('top desc,id desc')->paginate($input['limit'])->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //总库存
+ $v['stock'] = $spe_price_model->getGoodsStock($v['id']);
+
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @param $goods_id
+ * @功能说明:商品规格
+ * @author chenniang
+ * @DataTime: 2021-01-19 14:26
+ */
+ public function goodsSpeList(){
+
+ $input = $this->_input;
+
+ $spe_model = new GoodsSpe();
+
+ $spe_price_model = new GoodsSpePrice();
+
+ $goods_id = $input['goods_id'];
+
+ $dis['goods_id'] = $goods_id;
+
+ $dis['status'] = 1;
+
+ $data['text'] = $spe_model->goodsSpe($dis);
+
+ $data['price'] = $spe_price_model->goodsSpePrice($dis);
+
+ if(!empty($data['price'])){
+
+ foreach ($data['price'] as &$v){
+
+ $v['title'] = $v['spe_name_text'];
+
+ $v['true_id'] = $v['id'];
+
+ $v['id'] = implode(',',$v['spe_array_text']);
+
+ }
+ }
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-01-30 11:00
+ * @功能说明:获取商品规格
+ */
+ public function getSpePrice(){
+
+ $input = $this->_input;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['goods_id','=',$input['goods_id']];
+
+ $dis[] = ['status','>',-1];
+
+ $spe_price_model = new AdminShopSpePrice();
+
+ $data = $spe_price_model->goodsSpePrice($dis);
+
+ if(!empty($data)){
+
+ foreach ($data as &$v){
+
+ $v['spe_content'] = $v['spe_name_text'].':'.$v['price'];
+
+ $v['spe_price_id']= $v['id'];
+ }
+ }
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-02-22 17:11
+ * @功能说明:生成二维码
+ */
+ public function getQr(){
+
+ $input = $this->_input;
+
+ $uniacid = $this->_uniacid;
+
+ $data = longbingCreateWxCode($uniacid,$input,$input['page']);
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+ $qr = $data['qr_path'];
+
+ return $qr;
+
+ }
+
+
+
+}
diff --git a/app/publics/model/TmplConfig.php b/app/publics/model/TmplConfig.php
new file mode 100755
index 0000000..6be3943
--- /dev/null
+++ b/app/publics/model/TmplConfig.php
@@ -0,0 +1,100 @@
+select()->toArray();
+ return $data;
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-12-25 10:50
+ * @param $dis
+ * @param $data
+ * @return TmplConfig
+ * descrption:模版消息编辑
+ */
+ public function tmplUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = self::where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-12-25 10:51
+ * @param $data
+ * @return int|string
+ * descrption:编辑模版消息
+ */
+
+ public function tmplAdd($data){
+ $data['create_time'] = time();
+ $data['update_time'] = time();
+ $res = self::insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-17 10:10
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+ /**
+ * User: chenniang
+ * Date: 2019-12-25 10:51
+ * @param $dis
+ * @return array|\think\Model|null
+ * descrption:添加模版消息
+ */
+ public function tmplInfo($dis){
+ $data = self::where($dis)->find();
+ if(empty($data)){
+ $data = $this->tmplAdd($dis);
+ $data = self::where($dis)->find();
+ }
+ return !empty($data)?$data->toArray():$data;
+ }
+
+
+ /**
+ * @param $dis
+ * @功能说明: 获取模版id 列表
+ * @author chenniang
+ * @DataTime: 2019-12-27 17:00
+ */
+ public function tmplIdList($dis){
+ $data = $this->where($dis)->column('tmpl_id');
+ return array_values($data);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/app/publics/route/route.php b/app/publics/route/route.php
new file mode 100755
index 0000000..e03472d
--- /dev/null
+++ b/app/publics/route/route.php
@@ -0,0 +1,48 @@
+ $uniacid,
+ 'model_name' => $model_name,
+ 'tmpl_name' => $value,
+ 'tid' => $param['tid'],
+ 'kidList' => $param['kidList'],
+ 'kid' => $param['kid'],
+ 'sceneDesc' => $param['sceneDesc'],
+ 'example' => $param['example'],
+ ];
+ //获取每天模版消息
+ $tmpl_info = $model->tmplInfo($dis);
+ //返回值
+ $tmpl_data[] = $tmpl_info;
+ }
+ }
+ }
+
+
+ return $tmpl_data;
+ }
+
+}
\ No newline at end of file
diff --git a/app/shop/config.php b/app/shop/config.php
new file mode 100755
index 0000000..5e415de
--- /dev/null
+++ b/app/shop/config.php
@@ -0,0 +1,35 @@
+ 20,
+ "is_show" => 1,
+ "iconPath" =>"icon-shangcheng1",
+ "selectedIconPath"=> "icon-shangcheng",
+ "pageComponents" => "shopHome",
+ "name" => "商城",
+ "url" => "/pages/user/home",
+ "url_out" => "",
+ "url_jump_way" => 0
+];
+
+$page_shop = [
+
+];
+
+
+return [
+
+ 'Malls_tabbar' => $tabbar_shop,
+ 'Malls_page' => $page_shop
+
+];
\ No newline at end of file
diff --git a/app/shop/controller/Admin.php b/app/shop/controller/Admin.php
new file mode 100755
index 0000000..e9e6514
--- /dev/null
+++ b/app/shop/controller/Admin.php
@@ -0,0 +1,132 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-11 13:53
+ * @功能说明:登陆
+ */
+ public function login(){
+
+// $input = $this->_input;
+
+ initLogin();
+
+ $input = json_decode( $this->request->getInput(), true );
+
+ //dump($input);exit;
+
+ $dis = [
+
+ // 'uniacid' => $this->_uniacid,
+
+ 'username'=> $input['username']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ if(empty($data)){
+
+ return $this->error('该用户不存在', 400);
+
+ }
+
+ if($data['passwd']!=checkPass($input['passwd'])){
+
+
+ return $this->error('密码错误', 400);
+ }
+
+ $result['user'] = $data;
+
+ $result['token'] = uuid();
+
+ if (empty($result['token'])) {
+
+ return $this->error('系统错误', 400);
+ }
+ //添加缓存数据
+ setUserForToken($result['token'], $data, 99999999);
+
+ return $this->success($result);
+
+ }
+
+ public function success ( $data, $code = 200 )
+ {
+ $result[ 'data' ] = $data;
+ $result[ 'code' ] = $code;
+ $result[ 'sign' ] = null;
+ //复杂的签名
+ // if(isset($this->_user['keys'])){
+ // $result['sign'] = rsa2CreateSign($this->_user['keys'] ,json_encode($data));
+ // }
+ //简单的签名
+ if ( !empty( $this->_token ) ) $result[ 'sign' ] = createSimpleSign( $this->_token, is_string( $data ) ? $data : json_encode( $data ) );
+
+ return $this->response( $result, 'json', $code );
+ }
+
+ //返回错误数据
+ public function error ( $msg, $code = 400 )
+ {
+ $result[ 'error' ] = Lang::get($msg);
+ $result[ 'code' ] = $code;
+ return $this->response( $result, 'json', 200 );
+ }
+
+ /**
+ * 输出返回数据
+ * @access protected
+ * @param mixed $data 要返回的数据
+ * @param String $type 返回类型 JSON XML
+ * @param integer $code HTTP状态码
+ * @return Response
+ */
+ protected function response ( $data, $type = 'json', $code = 200 )
+ {
+ return Response::create( $data, $type )->code( $code );
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminCap.php b/app/shop/controller/AdminCap.php
new file mode 100755
index 0000000..d21cc9c
--- /dev/null
+++ b/app/shop/controller/AdminCap.php
@@ -0,0 +1,446 @@
+model = new Model();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function capList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+
+ if(!empty($input['status'])){
+
+ if($input['status']==3){
+
+ $dis[] = ['a.status','in',[3,4]];
+
+ }else{
+
+ $dis[] = ['a.status','=',$input['status']];
+ }
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+ }
+
+ $where = [] ;
+
+ if(!empty($input['name'])){
+
+ $where [] = ['a.store_name','like','%'.$input['name'].'%'];
+
+ $where [] = ['a.name','like','%'.$input['name'].'%'];
+
+ $where [] = ['a.mobile','like','%'.$input['name'].'%'];
+ }
+
+ $data = $this->model->adminDataList($dis,$where,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 16:50
+ * @功能说明:财务中心列表
+ */
+ public function financeList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ }else{
+
+ $date_model = new Date();
+
+ $start_time = $date_model->where(['uniacid'=>$this->_uniacid])->min('date_str');
+
+ $end_time = $date_model->where(['uniacid'=>$this->_uniacid])->max('date_str');
+
+ $end_time +=86399;
+ }
+
+ $dis[] = ['a.status','in',[2,3]];
+
+ $where = [] ;
+
+ if(!empty($input['name'])){
+
+ $where [] = ['a.store_name','like','%'.$input['name'].'%'];
+
+ $where [] = ['a.name','like','%'.$input['name'].'%'];
+
+ $where [] = ['a.mobile','like','%'.$input['name'].'%'];
+ }
+
+ $data = $this->model->adminDataList($dis,$where,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $order_model = new Order();
+
+ $wallet_model= new Wallet();
+
+ $refund_model= new RefundOrder();
+
+ foreach ($data['data'] as &$v){
+ //总收入
+ $v['total_cash'] = $order_model->datePrice($start_time,$this->_uniacid,$v['id'],$end_time);
+ //单量
+ $v['total_count'] = $order_model->datePrice($start_time,$this->_uniacid,$v['id'],$end_time,0);
+ //总提现
+ $v['wallet_cash'] = $wallet_model->datePrice($start_time,$this->_uniacid,$v['id'],$end_time);
+ //提现笔数
+ $v['wallet_count'] = $wallet_model->datePrice($start_time,$this->_uniacid,$v['id'],$end_time,0);
+ //退款金额
+ $v['refund_price'] = $refund_model->datePrice($start_time,$this->_uniacid,$v['id'],$end_time);
+
+ $v['refund_count'] = $refund_model->datePrice($start_time,$this->_uniacid,$v['id'],$end_time,0);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:55
+ * @功能说明:团长数量
+ */
+ public function capCount(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+ //所有
+ $data['all_count'] = $this->model->where($dis)->where('status','>',-1)->count();
+ //未授权
+ $data['no_pass_count'] = $this->model->where($dis)->where('status','in',[3,4])->count();
+
+ $dis['status'] = 1;
+ //申请中
+ $data['apply_count'] = $this->model->where($dis)->count();
+
+ $dis['status'] = 2;
+ //已授权
+ $data['pass_count'] = $this->model->where($dis)->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:团长详情
+ */
+ public function capInfo(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 17:53
+ * @功能说明:店铺下拉框
+ */
+ public function capSelect(){
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','in',[2,3]];
+
+ $data = $this->model->where($dis)->field('id,store_name')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 15:03
+ * @功能说明:修改团长
+ */
+ public function capUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['sh_time'] = time();
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 16:04
+ * @功能说明:楼长提现列表
+ */
+ public function walletList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+ }
+
+ $wallet_model = new Wallet();
+
+ $data = $wallet_model->adminList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 17:04
+ * @功能说明:通过审核
+ */
+ public function walletPass(){
+
+ $input = $this->_input;
+
+ $wallet_model = new Wallet();
+
+ $info = $wallet_model->dataInfo(['id'=>$input['id']]);
+
+ if($info['status']==2){
+
+ $this->errorMsg('已同意打款');
+ }
+
+ if($info['status']==3){
+
+ $this->errorMsg('已拒绝打款');
+ }
+
+ $update = [
+
+ 'cash_time' => time(),
+
+ //'text' => !empty($input['text'])?$input['text']:'',
+
+ 'status' => 2,
+
+ 'online' => $input['online'],
+
+ 'pay_cash' => $info['true_cash']
+ ];
+
+ Db::startTrans();
+
+ $res = $wallet_model->dataUpdate(['id'=>$input['id'],'status'=>1],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('打款失败');
+
+ }
+ //线上转账
+ if($input['online']==1){
+
+ $user_model = new User();
+
+ $openid = $user_model->where(['id'=>$info['user_id']])->value('openid');
+
+ if(empty($openid)){
+
+ return $this->error('用户信息错误,未获取到openid');
+ }
+ //微信相关模型
+ $wx_pay = new WxPay($this->_uniacid);
+ //微信提现
+ $res = $wx_pay->crteateMchPay($this->payConfig(),$openid,$update['pay_cash']);
+
+ if($res['result_code']=='SUCCESS'&&$res['return_code']=='SUCCESS'){
+
+ if(!empty($res['payment_no'])){
+
+ $wallet_model->dataUpdate(['id'=>$input['id']],['payment_no'=>$res['payment_no']]);
+ }
+
+ }else{
+
+ Db::rollback();
+
+ return $this->error(!empty($res['err_code_des'])?$res['err_code_des']:'你还未该权限');
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:03
+ * @功能说明:决绝提现
+ */
+ public function walletNoPass(){
+
+ $input = $this->_input;
+
+ $wallet_model = new Wallet();
+
+ $info = $wallet_model->dataInfo(['id'=>$input['id']]);
+
+ if($info['status']==2){
+
+ $this->errorMsg('已同意打款');
+ }
+
+ if($info['status']==3){
+
+ $this->errorMsg('已拒绝打款');
+ }
+
+ Db::startTrans();
+
+
+ $update = [
+
+ 'cash_time' => time(),
+
+ //'text' => !empty($input['text'])?$input['text']:'',
+
+ 'status' => 3,
+
+ ];
+
+ $res = $wallet_model->dataUpdate(['id'=>$input['id'],'status'=>1],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('打款失败');
+
+ }
+
+ $cap_info = $this->model->dataInfo(['id'=>$info['cap_id']]);
+
+ $res = $this->model->dataUpdate(['id'=>$info['cap_id']],['cap_cash'=>$cap_info['cap_cash']+$info['apply_cash']]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('打款失败');
+
+ }
+
+ Db::commit();
+
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminExcel.php b/app/shop/controller/AdminExcel.php
new file mode 100755
index 0000000..14ef35a
--- /dev/null
+++ b/app/shop/controller/AdminExcel.php
@@ -0,0 +1,299 @@
+model = new Model();
+
+ $this->order_goods_model = new OrderGoods();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+ }
+ //手机号搜索
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['d.mobile','like','%'.$input['mobile'].'%'];
+ }
+ //订单状态搜索
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+ }
+ //店铺名字搜索
+ if(!empty($input['store_id'])){
+
+ $dis[] = ['a.cap_id','=',$input['store_id']];
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+ }
+
+ $data = $this->model->adminDataSelect($dis,$input['limit']);
+
+ $name = '订单列表';
+
+ $header=[
+ '订单ID',
+ '商品名',
+ '商品价格',
+ '商品规格',
+ '商品数量',
+ '下单人',
+ '手机号',
+ '实收金额',
+ '系统订单号',
+ '付款订单号',
+ '下单时间',
+ '支付方式',
+ '配送方式',
+ '核销人',
+ '状态',
+ ];
+
+ $new_data = [];
+
+ foreach ($data as $v){
+
+ $info = array();
+
+ $info[] = $v['id'];
+
+ $info[] = $v['goods_name'];
+
+ $info[] = $v['goods_price'];
+
+ $info[] = $v['spe_name'];
+
+ $info[] = $v['goods_num'];
+
+ $info[] = $v['store_name'];
+
+ $info[] = $v['name'];
+
+ $info[] = $v['user_name'];
+
+ $info[] = $v['mobile'];
+
+ $info[] = $v['pay_price'];
+
+ $info[] = $v['order_code'];
+
+ $info[] = $v['transaction_id'];
+
+ $info[] = $v['create_time']?date('Y-m-d H:i:s',$v['create_time']):'暂无信息';
+
+ $info[] = !empty($v['balance'])?'余额支付':'微信支付';
+
+ $info[] = $v['send_type']==1?'自提':'快递';
+
+ $info[] = $v['send_type']==1?'自提':'快递';
+
+ $info[] = $this->orderStatusText($v['pay_type']);
+
+ $info[] = $v['hx_user_name'];
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data,'',2);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 16:32
+ * @功能说明:
+ */
+ public function orderStatusText($status){
+
+ switch ($status){
+
+ case 1:
+ return '待支付';
+
+ break;
+ case 2:
+ return '已支付';
+
+ break;
+
+ case 7:
+ return '已完成';
+
+ break;
+
+ case -1:
+ return '已取消';
+
+ break;
+
+ }
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 13:37
+ * @功能说明:财务数据统计导出
+ */
+ public function dateCount(){
+
+ $input = $this->_param;
+
+ $cap_id = $input['cap_id'];
+
+ $date_model = new Date();
+
+ $wallet_model = new Wallet();
+
+ $cap_model = new Cap();
+
+ $date_model->dataInit($this->_uniacid);
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['date_str','between',"$start_time,$end_time"];
+ }
+
+ $date_list = $date_model->dataList($dis,100000);
+ //店铺名字
+ $store_name = $cap_model->where(['id'=>$cap_id])->value('store_name');
+ //开始时间结束时间
+ if(!empty($start_time)){
+
+ $date_list['start_time'] = $start_time;
+
+ $date_list['end_time'] = $end_time;
+
+ }else{
+
+ $date_list['start_time'] = $date_model->where(['uniacid'=>$this->_uniacid])->min('date_str');
+
+ $date_list['end_time'] = $date_model->where(['uniacid'=>$this->_uniacid])->max('date_str');
+
+ }
+
+ if(!empty($date_list['data'])){
+
+ foreach ($date_list['data'] as $k=>$v){
+ //订单金额
+ $date_list['data'][$k]['order_price'] = $this->model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+ //退款金额
+ $date_list['data'][$k]['refund_price'] = $this->refund_order_model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+ //提现金额
+ $date_list['data'][$k]['wallet_price'] = $wallet_model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+
+ }
+
+ }
+
+ $name = $store_name.'财务报表';
+
+ $header=[
+ '收支时间',
+ '订单收入',
+ '订单退款',
+ '提现(元)',
+ ];
+
+ $new_data = [];
+
+ foreach ($date_list['data'] as $v){
+
+ $info = array();
+
+ $info[] = $v['date'];
+
+ $info[] = $v['order_price'];
+
+ $info[] = $v['refund_price'];
+
+ $info[] = $v['wallet_price'];
+
+ $new_data[] = $info;
+ }
+
+ $excel = new Excel();
+
+ $excel->excelExport($name,$header,$new_data);
+
+ return $this->success($date_list);
+
+ }
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminFreight.php b/app/shop/controller/AdminFreight.php
new file mode 100755
index 0000000..40c891f
--- /dev/null
+++ b/app/shop/controller/AdminFreight.php
@@ -0,0 +1,173 @@
+model = new FreightTemplate();
+
+ $this->config_model = new FreightConfig();
+
+ $this->province_model = new FreightProvince();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:43
+ * @功能说明:模版列表
+ */
+ public function tmplList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(isset($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+ }else{
+
+ $dis[] = ['status','>',-1];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:43
+ * @功能说明:模版列表
+ */
+ public function tmplSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-11 15:47
+ * @功能说明:添加运费模版
+ */
+ public function tmplAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->tmplAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:44
+ * @功能说明:编辑运费模版
+ */
+ public function tmplUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->tmplUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:45
+ * @功能说明:模版详情
+ */
+ public function tmplInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminGoods.php b/app/shop/controller/AdminGoods.php
new file mode 100755
index 0000000..2002830
--- /dev/null
+++ b/app/shop/controller/AdminGoods.php
@@ -0,0 +1,615 @@
+model = new ShopGoods();
+
+ $this->cate_model = new ShopGoodsCate();
+
+ $this->spe_model = new ShopGoodsSpe();
+
+ $this->spe_price_model = new GoodsSpePrice();
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:01
+ * @功能说明:商品分类列表
+ */
+ public function goodsCateList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->cate_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ $farmer_model = new Farmer();
+
+ foreach ($data['data'] as &$v){
+
+ $v['farmer_name'] = $farmer_model->where('id','in',$v['store'])->column('title');
+
+ $v['farmer_name'] = implode(',',$v['farmer_name']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:17
+ * @功能说明:添加分类
+ */
+ public function goodsCateAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $data = $this->cate_model->dataAdd($input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:18
+ * @功能说明:编辑分类
+ */
+ public function goodsCateUpdate(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->cate_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:18
+ * @功能说明:编辑分类
+ */
+ public function goodsCateInfo(){
+
+ $input = $this->_param;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $data = $this->cate_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 17:58
+ * @功能说明:分类下拉框
+ */
+ public function goodsCateSelect(){
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+
+ ];
+
+ $data = $this->cate_model->where($dis)->select()->toArray();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-13 17:21
+ * @功能说明:商品列表
+ */
+ public function goodsList(){
+
+ $input= $this->_param;
+
+ $dis[]= ['a.uniacid','=',$this->_uniacid];
+
+ if(!empty($input['name'])){
+
+ $dis[] = ['a.goods_name','like',"%".$input['name']."%"];
+ }
+
+ if(!empty($input['cate_id'])){
+
+ $dis[] = ['c.cate_id','=',$input['cate_id']];
+ }
+
+ if(!empty($input['store_id'])){
+
+ $dis[] = ['b.store_id','=',$input['store_id']];
+ }
+
+ $sale_type = $input['type']==2?0:1;
+
+ $sale_out_goods = $this->spe_price_model->getSellOut($this->_uniacid,$sale_type);
+
+ switch ($input['type']){
+
+ case 1:
+ $dis[] = ['a.status','=',1];
+ break;
+
+ case 2:
+ $dis[]= ['a.status','>',-1];
+ break;
+
+ case 3:
+ $dis[] = ['a.status','=',0];
+
+ break;
+ }
+
+ $dis[] = ['a.id','in',$sale_out_goods];
+
+// $data = $this->model->goodsList($dis,$this->_input['limit']);
+ $data = $this->model->goodsList($dis,$input['limit']);
+
+ $farmer_model = new Farmer();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $cate_name = $this->cate_model->where('id','in',$v['cate_id'])->column('title');
+
+ $v['cate_name'] = implode(',',$cate_name);
+
+ $store_name = $farmer_model->where('id','in',$v['store'])->column('title');
+
+ $v['store_name'] = implode(',',$store_name);
+
+ }
+
+ }
+ //销售中
+ $data['sale_ing'] = $this->model->saleIngCount($this->_uniacid);
+ //售罄
+ $data['sale_out'] = $this->model->saleIngCount($this->_uniacid,2);
+ //下架
+ $data['sale_end'] = $this->model->saleIngCount($this->_uniacid,3);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:33
+ * @功能说明:添加商品
+ */
+ public function goodsAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ Db::startTrans();
+
+ $goods_id = $this->model->dataAdd($input);
+
+ $spe_arr = $this->goodsSpeAdd($input['specsItem'],$goods_id);
+
+ $res = $this->goodsSpePriceAdd($input['specsTable'],$goods_id,$spe_arr);
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-13 17:50
+ * @功能说明:修改商品
+ */
+ public function goodsUpdate(){
+
+ $input= $this->_input;
+
+ $dis = is_array($input['id'])? ['id','in',$input['id']]:['id' =>$input['id']];
+
+ Db::startTrans();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $this->model->goodsUpdate($dis,$input);
+
+ $this->spe_model->goodsSpeUpdate(['uniacid'=>$this->_uniacid,'goods_id'=>$input['id']],['status'=>-1]);
+
+ $this->spe_price_model->goodsSpePriceUpdate(['uniacid'=>$this->_uniacid,'goods_id'=>$input['id']],['status'=>-1]);
+
+ $spe_arr = $this->goodsSpeAdd($input['specsItem'],$input['id']);
+
+ $res = $this->goodsSpePriceAdd($input['specsTable'],$input['id'],$spe_arr);
+
+ Db::commit();
+
+ return $this->success($res);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-09 17:49
+ * @功能说明:商品复制
+ */
+ public function goodsCopy(){
+
+ $input = $this->_input;
+
+ $data = $this->model->dataInfo(['id'=>$input['id']]);
+
+ $data['goods_name'] = $input['goods_name'];
+
+ $data['store'] = $input['store'];
+
+ unset($data['id']);
+
+ unset($data['show_price']);
+
+ unset($data['show_init_price']);
+
+ unset($data['all_stock']);
+
+ unset($data['all_sale_count']);
+
+ $spe_info = $this->goodsSpeList($input['id']);
+
+ $data['specsItem'] = $spe_info['text'];
+
+ $data['specsTable'] = $spe_info['price'];
+
+ Db::startTrans();
+
+
+ $goods_id = $this->model->dataAdd($data);
+
+ $spe_arr = $this->goodsSpeAdd($data['specsItem'],$goods_id,1);
+
+ $res = $this->goodsSpePriceAdd($data['specsTable'],$goods_id,$spe_arr);
+
+ Db::commit();
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-21 11:21
+ * @功能说明:分类详情
+ */
+ public function goodsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+
+ ];
+
+ $res['goods_info'] = $this->model->dataInfo($dis);
+
+ $res['spe_info'] = $this->goodsSpeList($input['id']);
+
+ $freightTemplate_model = new FreightTemplate();
+
+ $res['goods_info']['send_template_type'] = $freightTemplate_model->where(['id'=>$res['goods_info']['send_tmpl_id']])->value('type');
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * 获取商品规格
+ */
+ public function goodsSpeList($goods_id){
+
+ $dis['goods_id'] = $goods_id;
+
+ $dis['status'] = 1;
+
+ $data['text'] = $this->spe_model->goodsSpe($dis);
+
+ $data['price'] = $this->spe_price_model->goodsSpePrice($dis);
+
+ if(!empty($data['price'])){
+
+ foreach ($data['price'] as &$v){
+
+ $v['title'] = $v['spe_name_text'];
+
+ $v['true_id'] = $v['id'];
+
+ $v['id'] = implode(',',$v['spe_array_text']);
+
+ }
+ }
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-26 10:09
+ * @功能说明:列表页修改商品库存
+ */
+ public function updateSpe(){
+
+ $input= $this->_input;
+
+ $input= $input['stock'];
+
+ if(!empty($input)&&!is_array($input)){
+
+ $this->errorMsg('数据错误');
+ }
+
+ foreach ($input as $value){
+
+ $this->spe_price_model->goodsSpePriceUpdate(['id'=>$value['id']],['stock'=>$value['stock']]);
+ }
+
+ return $this->success(true);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-28 10:33
+ * @功能说明:修改商品基本的参数
+ */
+ public function goodsBasicUpdate(){
+
+ $input= $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $this->model->goodsUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * 上下架删除商品
+ */
+ public function goodsStatusUpdate(){
+
+ $input= $this->_input;
+
+ if(isset($input['status'])){
+
+ $data = ['status'=>$input['status']];
+
+ }else{
+
+ $data = ['index_show'=>$input['index_show']];
+
+ }
+ $res = $this->model->where('id','in',$input['id'])->update($data);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @param $data
+ * @param $goods_id
+ * @return array
+ * 添加多规格
+ */
+ public function goodsSpeAdd($data,$goods_id,$is_copy=0){
+ /**
+ * 循环判断是否存在多个规格名添加图片的问题
+ * @date 2020/5/14 10:42 --lichuanming
+ */
+ $isimg_count = 0;
+ foreach ($data as $item ){
+ if($item['is_img'] == 1){
+ $isimg_count++;
+ }
+ }
+ if($isimg_count > 1){
+ return $this->error('当前已有规格名添加了图片,继续添加则需取消上一个规格名的图片勾选');
+ }
+
+ $arr = array();
+ if(!empty($data)){
+ foreach ($data as $v){
+ $is_img = $v['is_img']?$v['is_img']:0; #@date 2020/5/14 10:42 --lichuanming
+ if(strlen($v['pid'])>10||$is_copy==1){
+ $pid = $this->spe_model->goodsSpeAdd(['uniacid'=>$this->_uniacid,'goods_id'=>$goods_id,'title'=>$v['title'],'is_img'=>$is_img]);
+ }else{
+ $this->spe_model->goodsSpeUpdate(['id'=>$v['id']],['status'=>1,'title'=>$v['title'],'is_img'=>$is_img]);
+ $pid = $v['id'];
+ }
+ if(!empty($v['cate'])){
+ foreach ($v['cate'] as $value){
+ $image = $is_img?$value['image']:''; #@date 2020/5/14 10:42 --lichuanming
+
+ if(strlen($value['id'])>10||$is_copy==1) {
+ $id = $this->spe_model->goodsSpeAdd(['uniacid' => $this->_uniacid, 'goods_id' => $goods_id, 'title' => $value['title'], 'pid' => $pid,'is_img'=>$is_img,'image'=>$image]);
+ }else{
+ $this->spe_model->goodsSpeUpdate(['id'=>$value['id']],['status'=>1,'title'=>$value['title'],'is_img'=>$is_img,'image'=>$image]);
+ $id = $value['id'];
+ }
+ $arr[$value['id']] = $id;
+ }
+ }
+ }
+ }
+
+ // dump($data,$arr);exit;
+ return $arr;
+ }
+
+
+ /**
+ * @param $data
+ * @param $good_id
+ * @param $arr
+ * @return int|string
+ * 添加多规格价格
+ */
+ public function goodsSpePriceAdd($data,$good_id,$arr){
+ if(!empty($data)){
+ foreach ($data as $v){
+ if (strlen($v['price'])>8||strlen($v['original_price'])>8){
+
+ // $this->errorMsg('价格最多8位');
+
+ }
+
+ $pid = explode(',',$v['id']);
+ $spe_id = [];
+ if(empty($arr)){
+ $this->errorMsg('规格不正确,请删除错误规格,重新编辑');
+ }
+ foreach ($pid as $value){
+ if(!key_exists($value,$arr)){
+ $this->errorMsg('规格不正确,请删除错误规格,重新编辑');
+ }
+ $spe_id[] = $arr[$value];
+ }
+ $spe_price_id = implode('-',$spe_id);
+
+ $ins['uniacid'] = $this->_uniacid;
+
+ $ins['goods_id']= $good_id;
+
+ $ins['spe_id_1']= $spe_price_id;
+
+ $ins['price'] = $v['price'];
+
+ $ins['stock'] = $v['stock'];
+
+// $ins['alert_stock'] = $v['alert_stock'];
+
+ $ins['status'] = 1;
+ //原价
+ $ins['original_price'] = !empty($v['original_price'])?$v['original_price']:0;
+ //成本价
+ $ins['cost_price'] = !empty($v['cost_price'])?$v['cost_price']:0;
+
+ $spe_price = $this->spe_price_model->singeSpePrice(['goods_id'=>$good_id,'spe_id_1'=>$spe_price_id,'uniacid'=>$this->_uniacid]);
+
+ if(empty($spe_price)) {
+
+ $res = $this->spe_price_model->goodsSpePriceAdd($ins);
+
+ }else{
+
+ $res = $this->spe_price_model->goodsSpePriceUpdate(['id'=>$spe_price['id']],$ins);
+ }
+ }
+ }
+ return !empty($res)?$res:1;
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminMark.php b/app/shop/controller/AdminMark.php
new file mode 100755
index 0000000..a869489
--- /dev/null
+++ b/app/shop/controller/AdminMark.php
@@ -0,0 +1,579 @@
+model = new IntegralList();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:43
+ * @功能说明:积分列表
+ */
+ public function integralList(){
+
+ $this->model->initAtv();
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.status','>',-1];
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['b.name','like','%'.$input['goods_name'].'%'];
+ }
+
+ if(!empty($input['atv_status'])){
+
+ $dis[] = ['a.atv_status','=',$input['atv_status']];
+ }
+
+ $data = $this->model->dataGoodsList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 11:58
+ * @功能说明:添加积分商城规则
+ */
+ //[{"spe_id":1,"stock":1,"price":1,"integral":1}]
+ public function integralAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:28
+ * @功能说明:积分活动详情
+ */
+ public function integralInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $goods_model = new ShopGoods();
+
+ $data['goods_name'] = $goods_model->where(['id'=> $data['goods_id']])->value('goods_name');
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:30
+ * @功能说明:编辑积分规则
+ */
+ public function integralUpdate(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataUpdate(['id'=>$input['id']],$input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 11:54
+ * @功能说明:签到详情
+ */
+ public function signInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $sign_model = new Signin();
+
+ $data = $sign_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 11:54
+ * @功能说明:签到编辑
+ */
+ public function signUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $sign_model = new Signin();
+
+ $data = $sign_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:17
+ * @功能说明:抽奖活动列表
+ */
+ public function luckList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['atv_status'])){
+
+ $dis[] = ['atv_status','=',$input['atv_status']];
+
+ }
+
+ $luck_model = new LuckDraw();
+
+ $luck_model->initAtv();
+
+ $data = $luck_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:18
+ * @功能说明:添加抽奖
+ */
+ public function luckAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $luck_model = new LuckDraw();
+
+ if(!empty($input['data'])){
+
+ $balance = array_sum(array_column($input['data'],'balane'));
+
+ if($balance>100||$balance<0){
+
+ $this->errorMsg('累计中奖率在0-100%之间');
+ }
+
+ }
+
+ $check = $luck_model->checkTime($input);
+
+ if(!empty($check['code'])){
+
+ $this->errorMsg($check['msg']);
+
+ }
+
+ $res = $luck_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:18
+ * @功能说明:添加抽奖
+ */
+ public function luckUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ if(!empty($input['data'])){
+
+ $balance = array_sum(array_column($input['data'],'balane'));
+
+ if($balance>100||$balance<0){
+
+ $this->errorMsg('累计中奖率在0-100%之间');
+ }
+
+ }
+ $luck_model = new LuckDraw();
+
+ $check = $luck_model->checkTime($input);
+
+ if(!empty($check['code'])){
+
+ $this->errorMsg($check['msg']);
+
+ }
+
+ $res = $luck_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:19
+ * @功能说明:抽奖详情
+ */
+ public function luckInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $luck_model = new LuckDraw();
+
+ $res = $luck_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:17
+ * @功能说明:秒杀活动列表
+ */
+ public function killList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ if(!empty($input['atv_status'])){
+
+ $dis[] = ['atv_status','=',$input['atv_status']];
+ }
+
+ $luck_model = new SeckillList();
+
+ $luck_model->initAtv();
+
+ $data = $luck_model->dataList($dis,$input['limit']);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['order_price'] = 0;
+
+ $v['order_count'] = 0;
+
+ $v['user_count'] = 0;
+
+ }
+ }
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:18
+ * @功能说明:添加秒杀
+ */
+ public function killAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $luck_model = new SeckillList();
+
+ $res = $luck_model->atvCheck($input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ $res = $luck_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:18
+ * @功能说明:编辑秒杀
+ */
+ public function killUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $luck_model = new SeckillList();
+
+ if(isset($input['start_time'])&&isset($input['end_time'])){
+
+ $res = $luck_model->atvCheck($input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ }
+
+ $res = $luck_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:19
+ * @功能说明:秒杀详情
+ */
+ public function killInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $luck_model = new SeckillList();
+
+ $res = $luck_model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 14:22
+ * @功能说明:添加秒杀商品
+ */
+ public function addKillGoods(){
+
+ $input = $this->_input;
+
+ $luck_model = new SeckillList();
+
+ $res = $luck_model->updateSome($input['atv_id'],$this->_uniacid,$input['goods_info'],$input['goods_id']);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 14:58
+ * @功能说明:秒杀商品列表
+ */
+ public function killGoodsList(){
+
+ $input = $this->_param;
+
+ $goods_model = new SeckillGoods();
+
+ $dis[] = ['a.atv_id','=',$input['atv_id']];
+
+ $dis[] = ['b.status','=',1];
+
+ $dis[] = ['a.status','=',1];
+
+ $dis[] = ['d.status','=',2];
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['b.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ $data = $goods_model->goodsList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 15:13
+ * @功能说明:删除秒杀商品
+ */
+ public function killGoodsDel(){
+
+ $input = $this->_input;
+
+ $goods_model = new SeckillGoods();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $goods_model->where($dis)->delete();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 15:23
+ * @功能说明:秒杀商品详情
+ */
+ public function killGoodsInfo(){
+
+ $input = $this->_param;
+
+ $goods_model = new SeckillGoods();
+
+ $dis = [
+
+ 'atv_id' => $input['atv_id'],
+
+ 'goods_id'=> $input['goods_id'],
+ ];
+
+ $res = $goods_model->dataInfo($dis);
+
+ $goods_model = new ShopGoods();
+
+ $res['goods_name'] = $goods_model->where(['id'=> $input['goods_id']])->value('goods_name');
+
+ return $this->success($res);
+
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminMember.php b/app/shop/controller/AdminMember.php
new file mode 100755
index 0000000..eae1bcb
--- /dev/null
+++ b/app/shop/controller/AdminMember.php
@@ -0,0 +1,174 @@
+model = new Member();
+
+ $this->config_model = new FreightConfig();
+
+ $this->province_model = new FreightProvince();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:43
+ * @功能说明:会员列表
+ */
+ public function memberList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ if(isset($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+ }else{
+
+ $dis[] = ['status','>',-1];
+ }
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:43
+ * @功能说明:会员列表
+ */
+ public function memberSelect(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $this->model->where($dis)->order('id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-11 15:47
+ * @功能说明:添加会员
+ */
+ public function memberAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:44
+ * @功能说明:编辑会员
+ */
+ public function memberUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:45
+ * @功能说明:会员详情
+ */
+ public function memberInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $this->model->dataInfo($dis);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminOrder.php b/app/shop/controller/AdminOrder.php
new file mode 100755
index 0000000..1991a15
--- /dev/null
+++ b/app/shop/controller/AdminOrder.php
@@ -0,0 +1,369 @@
+model = new Model();
+
+ $this->order_goods_model = new OrderGoods();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:43
+ * @功能说明:列表
+ */
+ public function orderList(){
+
+ //超时自动取消订单
+ $this->model->autoCancelOrder($this->_uniacid);
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['a.create_time','between',"$start_time,$end_time"];
+ }
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+ }
+ //手机号搜索
+ if(!empty($input['mobile'])){
+
+ $dis[] = ['d.mobile','like','%'.$input['mobile'].'%'];
+ }
+ //订单状态搜索
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+ }
+
+ if(!empty($input['order_code'])){
+
+ $dis[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+ }
+
+ if(!empty($input['send_type'])){
+
+ $dis[] = ['a.send_type','=',$input['send_type']];
+ }
+
+ $data = $this->model->adminDataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-04 09:39
+ * @功能说明:修改订单
+ */
+ public function orderGoodsSend(){
+
+ $input = $this->_input;
+
+ $update = [
+ //快递公司
+ 'express_company' => $input['express_company'],
+ //快递电话
+ 'express_mobile' => $input['express_mobile'],
+ //快递单号
+ 'express_code' => $input['express_code'],
+
+ 'send_time' => time(),
+
+ 'pay_type' => 3,
+ ];
+
+ $res = $this->model->dataUpdate(['id'=>$input['id']],$update);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-04 09:52
+ * @功能说明:核销订单
+ */
+ public function hxOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+ //自提
+ if($order['send_type']==1&&$order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+ //快递
+ if($order['send_type']==2&&$order['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $this->model->hxOrder($order);
+
+ return $this->success($res);
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->refund_order_model->dataInfo($dis);
+
+ $data['pay_order_code'] = $this->model->where(['id'=>$data['order_id']])->value('order_code');
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ return $this->success($data);
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:44
+ * @功能说明:退款订单列表
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['c.goods_name','like','%'.$input['goods_name'].'%'];
+ }
+ //订单状态搜索
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $where = [];
+
+ if(!empty($input['order_code'])){
+
+ $where[] = ['a.order_code','like','%'.$input['order_code'].'%'];
+
+ $where[] = ['d.order_code','like','%'.$input['order_code'].'%'];
+ }
+ $data = $this->refund_order_model->adminDataList($dis,$input['limit'],$where);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:21
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund(){
+
+ $input = $this->_input;
+
+ $res = $this->refund_order_model->noPassRefund($input['id']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**\
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:28
+ * @功能说明:同意退款
+ */
+ public function passRefund(){
+
+ $input = $this->_input;
+
+ $res = $this->refund_order_model->passOrder($input['id'],$input['price'],$this->payConfig(),0,$input['text']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 13:37
+ * @功能说明:数据统计
+ */
+ public function dateCount(){
+
+ $input = $this->_param;
+
+ $cap_id = $input['cap_id'];
+
+ $date_model = new Date();
+
+ $wallet_model = new Wallet();
+
+ $cap_model = new Cap();
+
+ $date_model->dataInit($this->_uniacid);
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //时间搜素
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['date_str','between',"$start_time,$end_time"];
+ }
+
+ $date_list = $date_model->dataList($dis,$input['limit']);
+ //店铺名字
+ $date_list['store_name'] = $cap_model->where(['id'=>$cap_id])->value('store_name');
+ //开始时间结束时间
+ if(!empty($start_time)){
+
+ $date_list['start_time'] = $start_time;
+
+ $date_list['end_time'] = $end_time;
+
+ }else{
+
+ $date_list['start_time'] = $date_model->where(['uniacid'=>$this->_uniacid])->min('date_str');
+
+ $date_list['end_time'] = $date_model->where(['uniacid'=>$this->_uniacid])->max('date_str');
+
+ }
+
+ if(!empty($date_list['data'])){
+
+ foreach ($date_list['data'] as &$v){
+ //订单金额
+ $v['order_price'] = $this->model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+ //退款金额
+ $v['refund_price'] = $this->refund_order_model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+ //提现金额
+ $v['wallet_price'] = $wallet_model->datePrice($v['date_str'],$this->_uniacid,$cap_id);
+
+ }
+
+ }
+
+ return $this->success($date_list);
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminSetting.php b/app/shop/controller/AdminSetting.php
new file mode 100755
index 0000000..ba0bdbd
--- /dev/null
+++ b/app/shop/controller/AdminSetting.php
@@ -0,0 +1,406 @@
+model = new Model();
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function configInfo(){
+
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:14
+ * @功能说明:编辑配置
+ */
+ public function configUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:15
+ * @功能说明:banner列表
+ */
+ public function bannerList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $banner_model = new Banner();
+
+ $data = $banner_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:18
+ * @功能说明:添加banner
+ */
+ public function bannerAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:20
+ * @功能说明:编辑banner
+ */
+ public function bannerUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:27
+ * @功能说明:banner详情
+ */
+ public function bannerInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $banner_model = new Banner();
+
+ $res = $banner_model->dataInfo($dis);
+
+ return $this->success($res);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:27
+ * @功能说明:新闻列表
+ */
+ public function articleList(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['title'])){
+
+ $dis[] = ['title','like','%'.$input['title'].'%'];
+ }
+
+ $data = $article_model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:37
+ * @功能说明:添加文章
+ *
+ */
+ public function articleAdd(){
+
+ $input = $this->_input;
+
+ $article_model = new Article();
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $res = $article_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:编辑文章
+ */
+ public function articleUpdate(){
+
+ $input = $this->_input;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $article_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:35
+ * @功能说明:文章详情
+ */
+ public function articleInfo(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $res = $article_model->dataInfo($dis);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 13:50
+ * @功能说明:文章下拉框
+ */
+ public function articleSelect(){
+
+ $input = $this->_param;
+
+ $article_model = new Article();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $res = $article_model->where($dis)->field('id,title')->select()->toArray();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:53
+ * @功能说明:支付配置详情
+ */
+ public function payConfigInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $pay_model = new PayConfig();
+
+ $data = $pay_model->dataInfo($dis);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:55
+ * @功能说明:编辑支付配置
+ */
+ public function payConfigUpdate(){
+
+ $input = $this->_input;
+
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ if(!strstr($input['cert_path'],FILE_UPLOAD_PATH)){
+
+ $input['cert_path'] = FILE_UPLOAD_PATH.$input['cert_path'];
+
+ }
+ if(!strstr($input['key_path'],FILE_UPLOAD_PATH)){
+
+ $input['key_path'] = FILE_UPLOAD_PATH.$input['key_path'];
+ }
+
+ $pay_model = new PayConfig();
+
+ $data = $pay_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-31 15:16
+ * @功能说明:修改密码
+ */
+ public function updatePass(){
+
+ $input = $this->_input;
+
+ $admin = new \app\shop\model\Admin();
+
+ $update = [
+
+ 'passwd' => checkPass($input['pass']),
+ ];
+
+ $res = $admin->dataUpdate(['uniacid'=>$this->_uniacid],$update);
+
+
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 15:04
+ * @功能说明:配置详情
+ */
+ public function msgConfigInfo(){
+
+ $msg_model = new MsgConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $msg_model->dataInfo($dis);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-12 16:14
+ * @功能说明:编辑配置
+ */
+ public function msgConfigUpdate(){
+
+ $input = $this->_input;
+
+ $msg_model = new MsgConfig();
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $data = $msg_model->dataUpdate($dis,$input);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/AdminUser.php b/app/shop/controller/AdminUser.php
new file mode 100755
index 0000000..a28ce24
--- /dev/null
+++ b/app/shop/controller/AdminUser.php
@@ -0,0 +1,91 @@
+model = new Model();
+
+ $this->order_goods_model = new OrderGoods();
+
+ $this->refund_order_model = new RefundOrder();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 10:24
+ * @功能说明:用户列表
+ */
+ public function userList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+ //是否授权
+ if(!empty($input['type'])){
+
+ if($input['type']==1){
+
+ $dis[] = ['nickName','=',''];
+
+ }else{
+
+ $dis[] = ['nickName','<>',''];
+
+ }
+
+ }
+
+ if(!empty($input['nickName'])){
+
+ $dis[] = ['nickName','like','%'.$input['nickName'].'%'];
+ }
+
+ if(!empty($input['start_time'])&&!empty($input['end_time'])){
+
+ $start_time = $input['start_time'];
+
+ $end_time = $input['end_time'];
+
+ $dis[] = ['create_time','between',"$start_time,$end_time"];
+ }
+
+ $data = $this->model->dataList($dis,$input['limit']);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/Index.php b/app/shop/controller/Index.php
new file mode 100755
index 0000000..32efeca
--- /dev/null
+++ b/app/shop/controller/Index.php
@@ -0,0 +1,110 @@
+model = new Banner();
+
+ $this->article_model = new Article();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:20
+ * @功能说明:首页
+ */
+ public function index(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'status' => 1
+ ];
+
+ $data['article'] = $this->article_model->where($dis)->field('id,title')->order('top desc,id desc')->select()->toArray();
+
+ $data['banner'] = $this->model->where($dis)->field('id,img,link')->order('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:55
+ * @功能说明:文章详情
+ */
+ public function articleInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->article_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 14:16
+ * @功能说明:获取配置信息
+ */
+ public function configInfo(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid
+ ];
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo($dis);
+
+ return $this->success($config);
+
+ }
+
+
+
+
+
+}
diff --git a/app/shop/controller/IndexCap.php b/app/shop/controller/IndexCap.php
new file mode 100755
index 0000000..35e0d2a
--- /dev/null
+++ b/app/shop/controller/IndexCap.php
@@ -0,0 +1,938 @@
+model = new Cap();
+
+ $cap_dis[] = ['user_id','=',$this->getUserId()];
+
+ $cap_dis[] = ['status','in',[2,3]];
+
+ $this->cap_info = $this->model->dataInfo($cap_dis);
+
+ if(empty($this->cap_info)){
+
+ $this->errorMsg('你还不是楼长');
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:59
+ * @功能说明:修改团长信息
+ */
+ public function capUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $this->cap_info['id']
+ ];
+
+ $res = $this->model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function index(){
+
+ $data = $this->getUserInfo();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:34
+ * @功能说明:商品分类列表
+ */
+ public function goodsCateList(){
+
+ $cate_model = new GoodsCate();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','>',-1];
+
+ $dis[] = ['cap_id','=',$this->cap_info['id']];
+
+ $data = $cate_model->dataList($dis,20);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:03
+ * @功能说明:添加商品分类
+ */
+ public function goodsCateAdd(){
+
+ $input = $this->_input;
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['cap_id'] = $this->cap_info['id'];
+
+ $cate_model = new GoodsCate();
+
+ $res = $cate_model->dataAdd($input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:06
+ * @功能说明:编辑商品分类
+ */
+ public function goodsCateUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $cate_model = new GoodsCate();
+
+ $cate_info = $cate_model->dataInfo($dis);
+
+ if(empty($cate_info)){
+
+ $this->errorMsg('商品分类不存在');
+ }
+ //如果是删除
+ if(!empty($input['status'])&&$input['status']==-1&&$cate_info['goods_num']>0){
+
+ $this->errorMsg('该分类下存在商品,无法删除');
+
+ }
+
+ $res = $cate_model->dataUpdate($dis,$input);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:08
+ * @功能说明:商品分类下拉框
+ */
+ public function goodsCateSelect(){
+
+ $cate_model = new GoodsCate();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['cap_id','=',$this->cap_info['id']];
+
+ $data = $cate_model->where($dis)->where('top desc,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 15:06
+ * @功能说明:商品各个状态下的数量
+ */
+ public function goodsCount(){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'cap_id' => $this->cap_info['id'],
+
+ 'status' => 1
+
+ ];
+
+ $goods_model = new Goods();
+ //上架数量
+ $data['on_count'] = $goods_model->where($dis)->count();
+
+ $dis['status'] = 2;
+ //下架数量
+ $data['off_count'] = $goods_model->where($dis)->count();
+
+ $dis['status'] = 3;
+ //仓库数量
+ $data['house_count'] = $goods_model->where($dis)->count();
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:08
+ * @功能说明:商品列表
+ */
+ public function goodsList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['cap_id','=',$this->cap_info['id']];
+
+ $dis[] = ['status','=',$input['status']];
+ //商品名字搜索
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['goods_name','like','%'.$input['goods_name'].'%'];
+ }
+
+ $goods_model = new Goods();
+
+ $data = $goods_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+ //创建时间
+ $v['create_time'] = date('Y/m/d',strtotime($v['create_time']));
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 09:32
+ * @功能说明:添加商品
+ */
+ public function goodsAdd(){
+
+ $input = $this->_input;
+ //0放入仓库 1提交审核
+ $type = !empty($input['type'])?$input['type']:0;
+
+ unset($input['type']);
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['cap_id'] = $this->cap_info['id'];
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+
+ $core = new WxSetting($this->_uniacid);
+
+ if(!empty($input['goods_name'])){
+
+ $rest = $core->wxContentRlue($input['goods_name']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('标题含有违法违规内容');
+ }
+
+ }
+
+ if(!empty($input['text'])){
+
+ $rest = $core->wxContentRlue($input['text']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('标题含有违法违规内容');
+ }
+
+ }
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+ //判断是不是需要审核
+ if($config['goods_sh']==1){
+ //待审核
+ $input['status'] = 3;
+
+ }else{
+ //直接上架
+ $input['status'] = 1;
+
+ }
+
+ $goods_model = new Goods();
+
+ $id = $goods_model->dataAdd($input);
+ //提交审核
+ if($type==1&&$config['goods_sh']==1){
+
+ $this->subGoodsShAction([$id]);
+
+ }
+
+ return $this->success(1);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:28
+ * @功能说明:编辑商品信息
+ */
+ public function goodsUpdate(){
+
+ $input = $this->_input;
+
+ $type = !empty($input['type'])?$input['type']:0;
+
+ unset($input['type']);
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $input['uniacid'] = $this->_uniacid;
+
+ $input['imgs'] = !empty($input['imgs'])?implode(',',$input['imgs']):'';
+
+ $core = new WxSetting($this->_uniacid);
+
+ if(!empty($input['goods_name'])){
+
+ $rest = $core->wxContentRlue($input['goods_name']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('标题含有违法违规内容');
+ }
+
+ }
+
+ if(!empty($input['text'])){
+
+ $rest = $core->wxContentRlue($input['text']);
+
+ if($rest['errcode'] != 0){
+
+ return $this->error('标题含有违法违规内容');
+ }
+
+ }
+
+ $goods_model = new Goods();
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+ //判断是不是需要审核
+ if($config['goods_sh']==1){
+
+ $input['status'] = 3;
+ }
+
+ $res = $goods_model->goodsUpdate($dis,$input);
+ //提交审核
+ if($type==1&&$config['goods_sh']==1){
+
+ $this->subGoodsShAction([$input['id']]);
+
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 14:18
+ * @功能说明:商品上下架
+ */
+ public function goodsStatusUpdate(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $goods_model = new Goods();
+
+ $res = $goods_model->dataUpdate($dis,['status'=>$input['status']]);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:29
+ * @功能说明:商品详情
+ */
+ public function goodsInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $goods_model = new Goods();
+
+ $res = $goods_model->dataInfo($dis);
+
+ $cate_model = new GoodsCate();
+ //分类名字
+ $res['cate_name'] = $cate_model->where(['id'=>$res['cate_id']])->value('title');
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @param $input
+ * @功能说明:提交审核方法
+ * @author chenniang
+ * @DataTime: 2021-03-23 14:27
+ */
+ public function subGoodsShAction($goods_id){
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'cap_id' => $this->cap_info['id'],
+
+ 'order_code' => orderCode(),
+
+ 'status' => 1,
+
+ ];
+
+ $goods_sh_model = new GoodsSh();
+
+ $goods_sh_model->dataAdd($insert);
+
+ $id = $goods_sh_model->getLastInsID();
+ //提交审核
+ $res = $goods_sh_model->subSh($id,$goods_id);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $res;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 10:30
+ * @功能说明:提交商品审核
+ */
+ public function subGoodsSh(){
+
+ $input = $this->_input;
+ //全选
+ if(!empty($input['all'])){
+
+ $goods_model = new Goods();
+
+ $dis = [
+
+ 'cap_id' => $this->cap_info['id'],
+
+ 'status' => 3
+ ];
+
+ $goods_id = $goods_model->where($dis)->column('id');
+
+ }else{
+
+ $goods_id = $input['goods_id'];
+ }
+
+ if(empty($goods_id)){
+
+ $this->errorMsg('暂无商品');
+ }
+ //提交审核
+ $res = $this->subGoodsShAction($goods_id);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:13
+ * @功能说明:商品审核列表
+ */
+ public function shList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['cap_id','=',$this->cap_info['id']];
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['status','=',$input['status']];
+ }
+
+ $goods_sh_model = new GoodsSh();
+
+ $data = $goods_sh_model->dataList($dis);
+
+ $data['sh_ing'] = $goods_sh_model->shIng($this->cap_info['id']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:21
+ * @功能说明:审核详情
+ */
+ public function shInfo(){
+
+ $input = $this->_param;
+
+ $goods_sh_model = new GoodsSh();
+
+ $data = $goods_sh_model->dataInfo(['id'=>$input['id']]);
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function orderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.cap_id','=',$this->cap_info['id']];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }else{
+
+ $dis[] = ['a.pay_type','>',1];
+
+ }
+
+ $order_model = new Order();
+
+ $data = $order_model->indexDataList($dis,$where);
+
+ return $this->success($data);
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:31
+ * @功能说明:商品批量上下架
+ */
+ public function someGoodsUpdate(){
+
+ $input = $this->_input;
+
+ $goods_model = new Goods();
+ //全选
+ if(!empty($input['all'])){
+
+ $res = $goods_model->where('cap_id','=',$this->cap_info['id'])->where(['status'=>$input['type']])->update(['status'=>$input['status']]);
+
+ }else{
+
+ $res = $goods_model->where('id','in',$input['goods_id'])->update(['status'=>$input['status']]);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:29
+ * @功能说明:退款订单详情
+ *
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.cap_id','=',$this->cap_info['id']];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $refund_model = new RefundOrder();
+
+ $data = $refund_model->indexDataList($dis,$where);
+
+ $data['refund_ing'] = $refund_model->refundIng($this->cap_info['id']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 11:34
+ * @功能说明:同意退款
+ */
+ public function passRefund(){
+
+ $input = $this->_input;
+
+ $refund_model = new RefundOrder();
+ //同意退款
+ $res = $refund_model->passOrder($input['id'],$input['price'],$this->payConfig(),$this->getUserId());
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:21
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund(){
+
+ $input = $this->_input;
+
+ $refund_order_model = new RefundOrder();
+
+ $res = $refund_order_model->noPassRefund($input['id']);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-24 13:33
+ * @功能说明:团长审核提现
+ */
+ public function applyWallet(){
+
+ $input = $this->_input;
+
+ if($input['apply_cash']>$this->cap_info['cap_cash']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $key = 'cap_wallet'.$this->getUserId();
+
+ $value = getCache($key);
+
+ if(!empty($value)){
+
+ $this->errorMsg('网络错误,请刷新重试');
+
+ }
+ //加一个锁防止重复提交
+ incCache($key,1,$this->_uniacid);
+
+ Db::startTrans();
+ //减佣金
+ $res = $this->model->dataUpdate(['id'=>$this->cap_info['id']],['cap_cash'=>$this->cap_info['cap_cash']-$input['apply_cash']]);
+
+ if($res!=1){
+
+ Db::rollback();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $this->errorMsg('申请失败');
+ }
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'cap_id' => $this->cap_info['id'],
+
+ 'apply_cash' => $input['apply_cash'],
+
+ 'order_code' => orderCode(),
+
+ 'text' => $input['text'],
+
+ 'true_cash' => round($input['apply_cash']*$config['cash_balance']/100,2),
+
+ 'cash_balance' => $config['cash_balance']
+
+ ];
+
+ $wallet_model = new Wallet();
+ //提交审核
+ $res = $wallet_model->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $this->errorMsg('申请失败');
+ }
+
+ Db::commit();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ return $this->success($res);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:14
+ * @功能说明:楼长核销订单
+ */
+ public function hxOrder(){
+
+ $input = $this->_input;
+
+ $order_model= new Order();
+
+ $order = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ if($order['cap_id']!=$this->cap_info['id']){
+
+ $this->errorMsg('你不是该订单的楼长');
+
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $order_model->hxOrder($input['id'],$this->cap_info['id']);
+
+ return $this->success($res);
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 13:38
+ * @功能说明:团长端佣金信息
+ */
+ public function capCashInfo(){
+
+ $key = 'cap_wallet'.$this->getUserId();
+ //减掉
+ delCache($key,$this->_uniacid);
+
+ $wallet_model = new Wallet();
+ //可提现佣金
+ $data['cap_cash'] = $this->cap_info['cap_cash'];
+ //累计提现
+ $data['cap_total_price'] = $wallet_model->capCash($this->cap_info['id']);
+ //累计收益
+ $data['cap_frozen_price'] = $wallet_model->capCash($this->cap_info['id'],1);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-30 14:39
+ * @功能说明:团长提现记录
+ */
+ public function capCashList(){
+
+ $wallet_model = new Wallet();
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'cap_id' => $this->cap_info['id']
+ ];
+
+
+ if(!empty($input['status'])){
+
+ $dis['status'] = $input['status'];
+ }
+ //提现记录
+ $data = $wallet_model->dataList($dis,10);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+ }
+ }
+
+ return $this->success($data);
+
+
+ }
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/IndexGoods.php b/app/shop/controller/IndexGoods.php
new file mode 100755
index 0000000..cc4443a
--- /dev/null
+++ b/app/shop/controller/IndexGoods.php
@@ -0,0 +1,389 @@
+model = new ShopGoods();
+
+ $this->kill_model = new SeckillList();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 16:33
+ * @功能说明:秒杀活动
+ */
+ public function killAtvList(){
+
+ $this->kill_model->initAtv();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['status','=',1];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $this->kill_model->where($dis)->order('start_time,id desc')->select()->toArray();
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 11:38
+ * @功能说明:热门商品列表
+ */
+ public function hotGoodsList(){
+
+ $input = $this->_param;
+
+ $goods_model = new ShopGoods();
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['index_show','=',1];
+
+ $dis[] = ['status','=',1];
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ $data = $goods_model->where($dis)->order('top desc,id desc')->paginate(10)->toArray();
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 15:51
+ * @功能说明:秒杀商品列表
+ */
+ public function killGoodsList(){
+
+ $input = $this->_param;
+
+ $goods_model = new SeckillGoods();
+
+ $dis[] = ['a.atv_id','=',$input['atv_id']];
+
+ $dis[] = ['b.status','=',1];
+
+ $dis[] = ['a.status','=',1];
+
+ $dis[] = ['e.status','=',1];
+
+ $dis[] = ['d.status','=',2];
+
+ $dis[] = ['d.business_status','=',1];
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['b.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ $data = $goods_model->goodsList($dis);
+
+ if(!empty($data['data'])){
+
+ $info_model = new SeckillInfo();
+
+ foreach ($data['data'] as &$v){
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'goods_id' => $v['goods_id'],
+
+ 'kill_id' => $v['atv_id'],
+
+ 'user_id' => $this->getUserId()
+ ];
+
+ $find = $info_model->dataInfo($dis);
+
+ $v['have_notice'] = !empty($find)?1:0;
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-24 15:10
+ * @功能说明:秒杀活动提醒
+ */
+ public function killNotice(){
+
+ $input = $this->_input;
+
+ $dis = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'goods_id' => $input['goods_id'],
+
+ 'kill_id' => $input['atv_id'],
+
+ 'user_id' => $this->getUserId()
+
+ ];
+
+ $info_model = new SeckillInfo();
+
+ $find = $info_model->dataInfo($dis);
+
+ if(empty($find)){
+
+ $info_model->dataAdd($dis);
+
+ }else{
+
+ $info_model->where($dis)->delete();
+ }
+
+ return $this->success(true);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-26 14:03
+ * @功能说明:抽奖详情
+ */
+ public function luckInfo(){
+
+ $input = $this->_param;
+
+ $dis[] = ['uniacid','=',$this->_uniacid];
+
+ $dis[] = ['start_time','<',time()];
+
+ $dis[] = ['end_time','>',time()];
+
+ $dis[] = ['status','=',1];
+
+ $luck_model = new LuckDraw();
+
+ $atv= $luck_model->dataInfo($dis);
+
+ if(empty($atv)){
+
+ return $this->success($atv);
+ $this->errorMsg('活动已经结束');
+ }
+
+ $config_model = new LuckConfig();
+
+ $record_model = new LuckRecord();
+
+ $user_model = new \app\farm\model\User();
+
+ $list = $config_model->where(['luck_id'=>$atv['id']])->order('top,id desc')->select()->toArray();
+
+ $user_num = $record_model->where(['user_id'=>$this->getUserId(),'atv_id'=>$atv['id']])->whereTime('create_time','today')->count();
+
+ $arr['data'] = $list;
+
+ $arr['user_num'] = ($atv['day_times'] - $user_num)>0?$atv['day_times'] - $user_num:0;
+
+ $arr['integral'] = $atv['integral'];
+
+ $arr['atv_id'] = $atv['id'];
+
+ $arr['cover'] = $atv['cover'];
+
+ $arr['text'] = $atv['text'];
+
+ $arr['day_times']= $atv['day_times'];
+
+ $arr['user_integral'] = $user_model->where(['id'=>$this->getUserId()])->sum('integral');
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-26 16:12
+ * @功能说明:中奖记录
+ */
+ public function luckRecord(){
+
+ $input = $this->_param;
+
+ $record_model = new LuckRecord();
+
+ $dis = [
+
+ 'a.atv_id' => $input['id'],
+
+ 'a.is_luck'=> 1
+ ];
+
+ $data = $record_model->recordList($dis);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-25 11:04
+ * @功能说明:用户中奖记录
+ */
+ public function userLuckRecord(){
+
+ $input = $this->_param;
+
+ $record_model = new LuckRecord();
+
+ $dis = [
+
+ 'a.user_id' => $this->getUserId(),
+
+ // 'a.is_luck'=> 1
+ ];
+
+ if(!empty($input['id'])){
+
+ $dis['a.atv_id'] = $input['id'];
+ }
+
+ $data = $record_model->recordList($dis);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['create_time'] = date('Y-m-d H:i:s',$v['create_time']);
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-26 14:09
+ * @功能说明:用户抽奖
+ */
+ public function luckDraw(){
+
+ $input = $this->_input;
+
+ $luck_model = new LuckDraw();
+
+ $record_model = new LuckRecord();
+
+ $dis[] = ['id','=',$input['id']];
+
+ $dis[] = ['start_time','<',time()];
+
+ $dis[] = ['end_time','>',time()];
+
+ $data = $luck_model->dataInfo($dis);
+
+ if(empty($data)){
+
+ $this->errorMsg('活动未在规则时间内');
+ }
+
+ $user_num = $record_model->where(['user_id'=>$this->getUserId(),'atv_id'=>$input['id']])->whereTime('create_time','today')->count();
+
+ if($user_num>=$data['day_times']){
+
+ $this->errorMsg('超过每日抽奖次数,你今日已抽'.$user_num.'次');
+ }
+
+ $user_model = new \app\farm\model\User();
+
+ $user_integral= $user_model->where(['id'=>$this->getUserId()])->sum('integral');
+
+ if($data['integral']>$user_integral){
+
+ $this->errorMsg('积分不足');
+ }
+ //抽奖
+ $res = $luck_model->luckDraw($input['id'],$this->getUserId(),$data['integral'],$user_num);
+
+ return $this->success($res);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/IndexOrder.php b/app/shop/controller/IndexOrder.php
new file mode 100755
index 0000000..a33e988
--- /dev/null
+++ b/app/shop/controller/IndexOrder.php
@@ -0,0 +1,819 @@
+model = new Order();
+
+ $this->refund_model = new RefundOrder();
+
+ $this->order_goods_model = new OrderGoods();
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 15:48
+ * @功能说明:个人中心
+ */
+ public function orderList(){
+ //超时自动取消订单
+ $this->model->autoCancelOrder($this->_uniacid,$this->getUserId());
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['pay_type'])){
+
+ $dis[] = ['a.pay_type','=',$input['pay_type']];
+
+ }
+
+ $data = $this->model->indexDataList($dis,$where);
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $can_refund_num = is_array($v['order_goods'])?array_sum(array_column($v['order_goods'],'can_refund_num')):0;
+
+ if(!empty($v['add_price'])&&$v['add_price_refund']==0){
+
+ $can_refund_num+=1;
+ }
+ //是否可以申请退款
+ if(($v['pay_type']==7&&$v['can_refund_time']>time()&&$can_refund_num>0)||($v['pay_type']==2&&$can_refund_num>0)){
+
+ $v['can_refund'] = 1;
+
+ }else{
+
+ $v['can_refund'] = 0;
+ }
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:58
+ * @功能说明:订单详情
+ */
+ public function orderInfo(){
+
+ $input = $this->_param;
+
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->model->dataInfo($dis);
+
+ $data['over_time'] -= time();
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+ //剩余可申请退款数量
+ $can_refund_num = array_sum(array_column($data['order_goods'],'can_refund_num'));
+ //如果有跑腿业务 可退款数量+1
+ if(!empty($data['add_price'])&&$data['add_price_refund']==0){
+
+ $can_refund_num+=1;
+ }
+ //是否可以申请退款
+ if(($data['pay_type']==7&&$data['can_refund_time']>time()&&$can_refund_num>0)||($data['pay_type']==2&&$can_refund_num>0)){
+
+ $data['can_refund'] = 1;
+
+ }else{
+
+ $data['can_refund'] = 0;
+ }
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:29
+ * @功能说明:退款订单详情
+ *
+ */
+ public function refundOrderList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['a.user_id','=',$this->getUserId()];
+
+ $where = [];
+
+ if(!empty($input['name'])){
+
+ $where[] = ['b.goods_name','like','%'.$input['name'].'%'];
+
+ $where[] = ['a.order_code','like','%'.$input['name'].'%'];
+
+ }
+
+ if(!empty($input['status'])){
+
+ $dis[] = ['a.status','=',$input['status']];
+
+ }else{
+
+ $dis[] = ['a.status','>',-1];
+
+ }
+
+ $data = $this->refund_model->indexDataList($dis,$where);
+
+ return $this->success($data);
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:50
+ * @功能说明:退款订单详情
+ */
+
+ public function refundOrderInfo(){
+
+ $input = $this->_param;
+
+ $dis = [
+
+ 'id' => $input['id']
+ ];
+
+ $data = $this->refund_model->dataInfo($dis);
+
+ $data['create_time'] = date('Y-m-d H:i:s',$data['create_time']);
+
+ $data['refund_time'] = date('Y-m-d H:i:s',$data['refund_time']);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-09-01 16:08
+ * @功能说明:配送方式
+ */
+ public function goodsSendType(){
+
+ $input = $this->_param;
+
+ $car_model = new Car();
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $list = $car_model->carList($this->getUserId(),1,0,$is_show);
+
+ $data['is_self'] = 0;
+
+ $data['is_send'] = 0;
+
+ if(!empty($list)){
+
+ foreach ($list as &$value){
+
+ $data['is_self'] = !empty($value['is_self'])?$value['is_self']:$data['is_self'];
+
+ $data['is_send'] = !empty($value['is_send'])?$value['is_send']:$data['is_send'];
+
+ }
+
+ }
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 09:43
+ * @功能说明:下单页面详情
+ */
+ public function payOrderInfo(){
+
+ $input = $this->_param;
+
+ $send_type = !empty($input['send_type'])?$input['send_type']:0;
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $no_i = isset($input['no_i'])?$input['no_i']:1;
+
+ $coupon_id = isset($input['coupon_id'])?$input['coupon_id']:0;
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),$is_show,$no_i,$send_type,$coupon_id);
+
+ $address_model = new Address();
+
+ if(!empty($input['address_id'])){
+ //默认地址
+ $order_info['address_info'] = $address_model->dataInfo(['id'=>$input['address_id']]);
+
+ }
+ //自提地址
+ if($send_type==1){
+
+ $config_model = new \app\massage\model\Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $order_info['address_info'] = [
+
+ 'mobile' => $config['mobile'],
+
+ 'lat' => $config['zt_lat'],
+
+ 'lng' => $config['zt_lng'],
+
+ 'address' => $config['zt_address'],
+
+ 'address_id' => 0,
+
+ 'user_name' => $config['app_name'],
+
+ ];
+
+ }
+
+ $coupon_modle = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+ //可用优惠券数量
+ $canUseCoupon = $coupon_modle->canUseCoupon($this->getUserId(),2,$is_show,$no_i);
+
+ $order_info['canUseCoupon'] = $coupon_record_model->where('id','in',$canUseCoupon)->sum('num');
+
+ return $this->success($order_info);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 09:53
+ * @功能说明:下单
+ */
+ public function payOrder(){
+
+ $input = $this->_input;
+
+ $send_type = isset($input['send_type'])?$input['send_type']:1;
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $no_i = isset($input['no_i'])?$input['no_i']:1;
+
+ $coupon_id = !empty($input['coupon_id'])?$input['coupon_id']:0;
+
+ $order_info = $this->model->payOrderInfo($this->getUserId(),$is_show,$no_i,$send_type,$coupon_id);
+
+ $config_model = new Config();
+
+ $address_order_model = new OrderAddress();
+
+ $config = $config_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $member_config_model = new \app\member\model\Config();
+
+ $member_config = $member_config_model->configInfo(['uniacid'=>$this->_uniacid]);
+
+ Db::startTrans();
+
+ $order_insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'order_code' => orderCode(),
+
+ 'user_id' => $this->getUserId(),
+
+ 'pay_price' => $order_info['pay_price'],
+
+ 'true_price' => $order_info['pay_price'],
+
+ 'pay_type' => 1,
+
+ 'goods_price'=> $order_info['goods_price'],
+
+ 'true_goods_price'=> $order_info['goods_price'],
+
+ 'init_price' => $order_info['init_price'],
+
+ 'init_goods_price' => $order_info['init_goods_price'],
+
+ 'text' => $input['text'],
+
+ 'over_time' => time()+$config['over_time']*60,
+
+ 'send_type' => $send_type,
+
+ 'integral' => $order_info['integral'],
+
+ 'discount' => $order_info['discount'],
+
+ 'freight' => $order_info['freight'],
+ //会员折扣抵扣了多少钱
+ 'member_discount_price' => $order_info['member_discount_price'],
+
+ 'integral_discount_price' => $order_info['integral_discount_price'],
+
+ 'balance' => !empty($input['is_balance'])?$order_info['pay_price']:0,
+ //付费获得的积分
+ 'get_integral' => empty($input['is_balance'])?floor($order_info['pay_price']*$member_config['integral_cash']):0,
+
+ ];
+
+ //下单
+ $res = $this->model->dataAdd($order_insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('下单失败');
+ }
+
+ $order_id = $this->model->getLastInsID();
+
+ if($send_type==2){
+ //添加下单地址
+ $res = $address_order_model->orderAddressAdd($input['address_id'],$order_id);
+
+ }else{
+
+ $res = $address_order_model->selfAddressAdd($this->_uniacid,$order_id,$input['user_name'],$input['mobile']);
+
+ }
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+
+ }
+
+ $order_insert['id'] = $order_id;
+
+ //使用优惠券
+ if(!empty($order_info['coupon_id'])){
+
+ $coupon_record_model = new CouponRecord();
+
+ $coupon_id = $coupon_record_model->couponUse($order_info['coupon_id'],$order_id);
+
+ $this->model->dataUpdate(['id'=>$order_id],['coupon_id'=>$coupon_id]);
+
+ }
+
+ if(empty($order_info['order_goods'])){
+
+ $this->errorMsg('订单错误');
+ }
+ //添加到子订单
+ $res = $this->order_goods_model->orderGoodsAdd($order_info['order_goods'],$order_id,$is_show,$this->getUserId());
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+ }
+ //积分活动
+ $res = $this->model->marketingCheck($order_insert,$order_info['order_goods']);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->errorMsg($res['msg']);
+
+ }
+
+ Db::commit();
+ //如果是0元
+ if($order_insert['pay_price']<=0){
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+ }
+ //余额支付
+ if(!empty($input['is_balance'])){
+
+ $user_model = new \app\massage\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"团购",['type' => 'SchoolShop' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 15:59
+ * @功能说明:重新支付
+ */
+ public function rePayOrder(){
+
+ $input = $this->_input;
+
+ $order_insert = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+ //余额支付
+ if(!empty($order_insert['balance'])){
+
+ $user_model = new \app\massage\model\User();
+
+ $user_balance= $user_model->where(['id'=>$this->getUserId()])->value('balance');
+
+ if($user_balance<$order_insert['pay_price']){
+
+ $this->errorMsg('余额不足');
+ }
+
+ $this->model->orderResult($order_insert['order_code'],$order_insert['order_code']);
+
+ return $this->success(true);
+
+ }
+ //微信支付
+ $pay_controller = new IndexWxPay($this->app);
+ //支付
+ $jsApiParameters= $pay_controller->createWeixinPay($this->payConfig(),$this->getUserInfo()['openid'],$this->_uniacid,"团购",['type' => 'SchoolShop' , 'out_trade_no' => $order_insert['order_code']],$order_insert['pay_price']);
+
+ $arr['pay_list']= $jsApiParameters;
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 16:38
+ * @功能说明:取消订单
+ */
+
+ public function cancelOrder(){
+
+ $input = $this->_input;
+
+ $order_insert = $this->model->dataInfo(['id'=>$input['id']]);
+
+ if($order_insert['pay_type']!=1){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ $res = $this->model->cancelOrder($order_insert);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 11:39
+ * @功能说明:申请退款
+ */
+ public function applyOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->model->dataInfo(['id'=>$input['order_id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if($order['pay_type']<2&&$order['have_tx']!=0){
+
+ $this->errorMsg('订单状态错误');
+
+ }
+
+ if(empty($input['list'])){
+
+ $this->errorMsg('请选择商品');
+
+ }
+
+ if($order['can_refund_time']errorMsg('核销后24小时内才能申请退款哦');
+
+ }
+ //申请退款
+ $res = $this->refund_model->applyRefund($order,$input);
+
+ if(!empty($res['code'])){
+
+ $this->errorMsg($res['msg']);
+ }
+// //给楼长发送服务通知
+// $msg_model = new MsgConfig();
+//
+// $refund_order = $this->refund_model->dataInfo(['id'=>$res]);
+// //发送通知
+// $msg_model->refundSendMsg($refund_order);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:55
+ * @功能说明:取消退款
+ */
+ public function cancelRefundOrder(){
+
+ $input = $this->_input;
+
+ $order = $this->refund_model->dataInfo(['id'=>$input['id']]);
+
+ if($order['status']!=1){
+
+ $this->errorMsg('订单已经审核');
+
+ }
+
+ Db::startTrans();
+
+ $res = $this->refund_model->dataUpdate(['id'=>$input['id']],['status'=>-1,'cancel_time'=>time()]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('取消失败');
+ }
+
+ if(!empty($order['order_goods'])){
+
+ $order_goods_model = new OrderGoods();
+
+ foreach ($order['order_goods'] as $v){
+
+ if(!empty($v['order_goods_id'])){
+
+ $num = $v['goods_num'];
+
+ $res = $order_goods_model->where(['id'=>$v['order_goods_id']])->update(['can_refund_num'=>Db::Raw("can_refund_num+$num")]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ $this->errorMsg('取消失败');
+ }
+
+ }else{
+
+ $this->model->dataUpdate(['id'=>$order['order_id']],['add_price_refund'=>0]);
+
+ }
+
+ }
+
+ }
+
+ Db::commit();
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-07 15:30
+ * @功能说明:刷新订单二维码
+ */
+ public function refreshQr(){
+
+ $input = $this->_input;
+
+ $qr_insert = [
+
+ 'id' => $input['id']
+ ];
+ //获取二维码
+ $qr = $this->model->orderQr($qr_insert,$this->_uniacid);
+
+ if(!empty($qr)){
+
+ $this->model->dataUpdate(['id'=>$input['id']],['qr'=>$qr]);
+
+ }
+
+ return $this->success($qr);
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:14
+ * @功能说明:楼长核销订单
+ */
+ public function endOrder(){
+
+ $input = $this->_input;
+
+ $order_model= new Order();
+
+ $order = $order_model->dataInfo(['id'=>$input['id']]);
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+
+ if(empty($order)){
+
+ $this->errorMsg('订单未找到');
+ }
+ //自提
+ if($order['send_type']==1&&$order['pay_type']!=2){
+
+ $this->errorMsg('订单状态错误');
+ }
+ //快递
+ if($order['send_type']==2&&$order['pay_type']!=3){
+
+ $this->errorMsg('订单状态错误');
+ }
+
+ if($order['send_type']==1){
+
+ $user_model = new \app\massage\model\User();
+
+ $role = $user_model->where(['id'=>$this->getUserId()])->value('role');
+
+ if($role!=1){
+
+ $this->errorMsg('只有管理员才能核销');
+ }
+ }
+
+ $refund_model = new RefundOrder();
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$order['id'],'status'=>1]);
+
+ if(!empty($refund_order)){
+
+ $this->errorMsg('该订单正在申请退款,请先处理再核销');
+
+ }
+
+ $res = $order_model->hxOrder($input['id'],$this->getUserId());
+
+ return $this->success($res);
+
+
+ }
+
+ public function getPayNumber(){
+
+ $input = $this->_input;
+
+ $number= $this->order_goods_model->getGoodsNumber(['a.goods_id'=>$input['id'],'b.user_id'=>$this->getUserId()] );
+
+ return $this->success(['number'=>$number]);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-07-10 00:40
+ * @功能说明:可用的优惠券列表
+ */
+ public function couponList(){
+
+ $input = $this->_param;
+
+ $coupon_model = new Coupon();
+
+ $coupon_record_model = new CouponRecord();
+
+ $is_show = isset($input['is_show'])?$input['is_show']:1;
+
+ $coupon_id = $coupon_model->canUseCoupon($this->getUserId(),2,$is_show);
+
+ $data = $coupon_record_model->where('id','in',$coupon_id)->order('id desc')->paginate(10)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $v['start_time'] = date('Y.m.d H:i',$v['start_time']).' - '.date('Y.m.d H:i',$v['end_time']);
+
+ }
+ }
+
+ return $this->success($data);
+
+ }
+
+}
diff --git a/app/shop/controller/IndexUser.php b/app/shop/controller/IndexUser.php
new file mode 100755
index 0000000..2a96ffd
--- /dev/null
+++ b/app/shop/controller/IndexUser.php
@@ -0,0 +1,318 @@
+model = new \app\farm\model\User();
+
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-03 13:35
+ * @功能说明:积分使用明细
+ */
+ public function integralList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['user_id','=',$this->getUserId()];
+
+ $dis[] = ['status','=',2];
+
+ $i_model = new IntegralLog();
+
+// if(!empty($input['add'])&&$input['add']==1){
+//
+// $dis[]=['integral_add','>',0];
+//
+// }else{
+//
+// $dis[]=['integral_add','<',0];
+// }
+
+ $data = $i_model->integralList($dis,15);
+
+ return $this->success($data);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 11:33
+ * @功能说明:积分商城商品列表
+ */
+ public function integralGoodsList(){
+
+ $input = $this->_param;
+
+ $dis[] = ['a.uniacid','=',$this->_uniacid];
+
+ $dis[] = ['c.start_time','<',time()];
+
+ $dis[] = ['c.end_time','>',time()];
+
+ $dis[] = ['c.status','=',1];
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($input['goods_name'])){
+
+ $dis[] = ['a.goods_name','like','%'.$input['goods_name'].'%'];
+
+ }
+
+ if(!empty($input['type'])){
+
+ $dis[] = ['c.type','=',$input['type']];
+
+ }
+
+ $i_model = new IntegralList();
+
+ $data = $i_model->integralGoodsList($dis);
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 11:44
+ * @功能说明:获取个人信息
+ */
+ public function userInfo(){
+
+ $data = $this->model->dataInfo(['id'=>$this->getUserId()],'nickName,avatarUrl,integral');
+
+ $signin_model = new Signin();
+
+ $data['signin_integral'] = $signin_model->where(['uniacid'=>$this->_uniacid])->sum('integral');
+
+ return $this->success($data);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 14:14
+ * @功能说明:
+ */
+ public function signinIndex(){
+
+ $input = $this->_param;
+ //用户积分
+ $user = $this->model->dataInfo(['id'=>$this->getUserId()],'integral,sign_notice,create_time');
+
+ $start_time = strtotime(date("Y-m-01", strtotime($input['day'])));
+
+ $end_time = strtotime(date("Y-m-t", strtotime($input['day'])));
+
+ $i = 0;
+
+ $sign_record_model = new SigninRecord();
+
+ $signin_model = new Signin();
+
+ $sign_record_model->initSign($this->getUserId());
+
+ while ($start_time<=$end_time){
+
+ $list[$i]['day'] = date('d',$start_time)*1;
+
+ $list[$i]['day_str'] = $start_time;
+
+ $list[$i]['week'] = date('w',$start_time);
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'create_date' => date('Y-m-d',$start_time)
+ ];
+
+ $find = $sign_record_model->dataInfo($dis);
+ //未在签到时间内
+ if($start_time+86400<$user['create_time']||$start_time>time()){
+
+ $list[$i]['status'] = 2;
+ //已经签到
+ }elseif(!empty($find)){
+
+ $list[$i]['status'] = 1;
+
+ }else{
+
+ $list[$i]['status'] = 0;
+
+ }
+ $start_time+=86400;
+
+ $i++;
+ }
+
+ $dis = [
+
+ 'user_id' => $this->getUserId()
+ ];
+
+ $arr['list'] = $list;
+ //总签到
+ $arr['total_sign_num'] = $sign_record_model->where($dis)->count();
+
+ $dis['status'] = 1;
+ //连续签到
+ $arr['sign_num'] = $sign_record_model->where($dis)->count();
+ //积分规则
+ $arr['integral_text'] = $signin_model->where(['uniacid'=>$this->_uniacid])->value('text');
+
+ $arr = array_merge($arr,$user);
+
+ return $this->success($arr);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 15:24
+ * @功能说明:用户签到
+ */
+ public function signin(){
+
+ $input = $this->_param;
+
+ $sign_record_model = new SigninRecord();
+
+ $signin_model = new Signin();
+
+ $date = date('Y-m-d',$input['day']);
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'create_date' => $date
+ ];
+
+ $find = $sign_record_model->dataInfo($dis);
+
+ if(!empty($find)){
+
+ $this->errorMsg('你已经签到过了');
+ }
+
+ if($input['day']+86400<$this->getUserInfo()['create_time']||$input['day']>time()){
+
+ $this->errorMsg('未在签到时间内');
+
+ }
+ //补签
+ if(date('Y-m-d')!=date('Y-m-d',$input['day'])){
+
+ $status = 2;
+
+ }else{
+
+ $status = 1;
+
+ $this->model->dataUpdate(['id'=>$this->getUserId()],['sign_time'=>time()]);
+ }
+
+ $sign_atv = $signin_model->dataInfo(['uniacid'=>$this->_uniacid]);
+
+ $insert = [
+
+ 'uniacid' => $this->_uniacid,
+
+ 'user_id' => $this->getUserId(),
+
+ 'status' => $status,
+
+ 'create_time' => time(),
+
+ 'create_date' => date('Y-m-d',$input['day']),
+
+ 'integral' => $sign_atv['integral']
+ ];
+
+ $res = $sign_record_model->dataAdd($insert);
+
+ $id = $sign_record_model->getLastInsID();
+
+ $i_log_model = new IntegralLog();
+
+ $dis = [
+
+ 'user_id' => $this->getUserId(),
+
+ 'status' => 1
+ ];
+ //连续签到
+ $sign_atv['times'] = $sign_record_model->where($dis)->count();
+
+ $i_log_model->integralUserAdd($this->getUserId(),$sign_atv['integral'],$this->_uniacid,2,10,$id,0,$sign_atv);
+
+ return $this->success($res);
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 16:18
+ * @功能说明:签到记录
+ */
+ public function signinRecordList(){
+
+ $sign_record_model = new SigninRecord();
+
+ $dis = [
+
+ 'user_id' => $this->getUserId()
+ ];
+
+ $data = $sign_record_model->dataList($dis);
+
+ return $this->success($data);
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/app/shop/controller/IndexWxPay.php b/app/shop/controller/IndexWxPay.php
new file mode 100755
index 0000000..8f48f13
--- /dev/null
+++ b/app/shop/controller/IndexWxPay.php
@@ -0,0 +1,317 @@
+app = $app;
+ }
+
+ public function getSSLPage($url) {
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_HEADER, false);
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_SSLVERSION,3);
+ $result = curl_exec($ch);
+ curl_close($ch);
+ return $result;
+ }
+
+ /**
+ * @param $paymentApp
+ * @param $openid
+ * @param $uniacid
+ * @param $body
+ * @param $attach
+ * @param $totalprice
+ * @throws \WxPayException
+ * 支付
+ */
+ public function createWeixinPay($paymentApp , $openid , $uniacid , $body , $attach,$totalprice){
+ global $_GPC, $_W;
+ $setting['mini_appid'] = $paymentApp['app_id'];
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+ define('WX_APPID', $setting['mini_appid']);
+ define('WX_MCHID', $setting['mini_mid']);
+ define('WX_KEY', $setting['mini_apicode']);
+ define('WX_APPSECRET', $setting['mini_appsecrept']);
+ define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+ define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+ define('WX_CURL_PROXY_HOST', '0.0.0.0');
+ define('WX_CURL_PROXY_PORT', 0);
+ define('WX_REPORT_LEVENL', 0);
+
+
+ require_once PAY_PATH . "/weixinpay/lib/WxPay.Api.php";
+ require_once PAY_PATH . "/weixinpay/example/WxPay.JsApiPay.php";
+
+ $tools = new \JsApiPay();
+ $input = new \WxPayUnifiedOrder();
+
+ $input->SetBody($body);
+ $input->SetAttach(json_encode($attach));
+ $input->SetOut_trade_no($attach['out_trade_no']);
+ $input->SetTotal_fee($totalprice *100);
+ $input->SetTime_start(date("YmdHis"));
+
+ Log::write("111_GPC");
+ Log::write($_GPC);
+
+ $param_arr=[
+ 'i' => $uniacid,
+// 't' => $_GPC['t'],
+// 'v' => $_GPC['v'],
+ 'is_app' => $paymentApp['is_app'],
+ 'n' => APP_MODEL_NAME,
+
+ ];
+ $reply_path=json_encode($param_arr);
+ //需要判断 是否是微擎的版本
+ if(defined('IS_WEIQIN')){
+ $path = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?params=".$reply_path;
+ $paths = "https://" . $_SERVER['HTTP_HOST'] ."/addons/".APP_MODEL_NAME."/core2/app/Common/wexinPay.php?ck=789";
+ $a = file_get_contents($paths);
+ if($a != 1){
+ $this->errorMsg('发起支付失败');
+ }
+ }else{
+ $path = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?params=".$reply_path;
+ $paths = "https://" . $_SERVER['HTTP_HOST'] ."/wexinPay.php?ck=789";
+// $a = file_get_contents($paths);
+// Log::write($paths);
+// $a = $this->getSSLPage($paths);
+// if($a != 1){
+// $this->errorMsg('发起支付失败');
+// }
+
+ }
+
+ $this ->lb_logOutput('BaseApiPath:-----'.$path);
+
+ $input->SetNotify_url($path);
+
+ if($paymentApp['is_app']!=1){
+
+ $input->SetTrade_type("JSAPI");
+
+ $input->SetOpenid($openid);
+
+ }else{
+
+ $input->SetTrade_type("APP");
+
+ }
+
+ $order = \WxPayApi::unifiedOrder($input);
+
+ if(!empty($order['return_code'])&&$order['return_code'] == 'FAIL'){
+
+ $this->errorMsg($order['return_msg']);
+ }
+
+ $order['mini_mid'] = $setting['mini_mid'];
+
+ if($paymentApp['is_app']!=1){
+
+ $jsApiParameters = $tools->GetJsApiParameters($order);
+
+ $jsApiParameters = json_decode($jsApiParameters, true) ;
+
+ } else{
+
+ $jsApiParameters = $this->getOrder($order);
+ }
+
+ Log::write('jsApiParameters');
+ Log::write($jsApiParameters);
+
+ if (!empty($jsApiParameters['return_code']))
+ $this->errorMsg( '发起支付失败');
+
+ return $jsApiParameters;
+ }
+
+
+ public function getOrder($order)
+ {
+ $data = array(
+ 'appid' => WX_APPID,//appid
+ 'partnerid' => WX_MCHID,//商户号
+ 'timestamp' => time(),//时间戳
+ 'noncestr' => WxPayApi::getNonceStr(),//随机字符串
+ 'package' => 'Sign=WXPay',//预支付交易会话标识
+ 'prepayid' => $order['prepay_id'],//预支付回话标志
+ //'sign_type'=>'MD5'//加密方式
+ );
+
+ $data['paySign'] = $this->makeSign($data);
+
+ return $data;
+ }
+ /**
+ * 生成签名
+ * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
+ */
+ public function makeSign($data)
+ {
+ // 去空
+ $data = array_filter($data);
+ //签名步骤一:按字典序排序参数
+ ksort($data);
+ $string_a = http_build_query($data);
+ $string_a = urldecode($string_a);
+ //签名步骤二:在string后加入KEY
+
+ $string_sign_temp = $string_a . "&key=" . WX_KEY;
+ //签名步骤三:MD5加密
+ $sign = md5($string_sign_temp);
+ // 签名步骤四:所有字符转为大写
+ $result = strtoupper($sign);
+ return $result;
+ }
+ /**
+ * @param $data
+ * @param int $flag
+ * @return void|null
+ * 打印数据
+ */
+
+ public function lb_logOutput($data,$flag=0) {
+ if($flag==0){
+ return ;
+ }
+ //数据类型检测
+ if (is_array($data)) {
+ $data = json_encode($data);
+ }
+ $filename = "./".date("Y-m-d").".log";
+ $str = date("Y-m-d H:i:s")." $data"."\r\n";
+ file_put_contents($filename, $str, FILE_APPEND|LOCK_EX);
+ return null;
+ }
+
+ /**
+ * 支付回调
+ */
+
+ public function returnPay(){
+
+
+ $this->lb_logOutput("in--mingpianNotify");
+ $xmlData = file_get_contents('php://input');
+ if(empty($xmlData)){
+ $xmlData = 'empty xmlData';
+ }
+ $this->lb_logOutput('xmlData in mingpian:-----'.$xmlData);
+
+ $this->lb_logOutput("in-mingpian2");
+ global $_GPC;
+ $xmlData = file_get_contents('php://input');
+ $this->lb_logOutput('in-mingpian-$xmlData:-----'.$xmlData);
+ //获取配置
+
+ if(defined( 'IS_WEIQIN' )){
+
+ $uniacid=$_GPC['i'];
+
+ $is_app=$_GPC['is_app'];
+
+
+ }else{
+
+ $is_app = $_GET['is_app'];
+
+ $uniacid = $_GET['i'];
+ }
+
+ $paymentApp = $this->payConfig($uniacid,$is_app);
+ // dump($paymentApp);exit;
+ $this->lb_logOutput('in-mingpian-uniacid:-----'.$uniacid);
+
+ $setting['mini_appid'] = $paymentApp['app_id'];
+ $setting['mini_appsecrept'] = $paymentApp['secret'];
+ $setting['mini_mid'] = $paymentApp['payment']['merchant_id'];
+ $setting['mini_apicode'] = $paymentApp['payment']['key'];
+ $setting['apiclient_cert'] = $paymentApp['payment']['cert_path'];
+ $setting['apiclient_cert_key'] = $paymentApp['payment']['key_path'];
+
+ define('WX_APPID', $setting['mini_appid']);
+ define('WX_MCHID', $setting['mini_mid']);
+ define('WX_KEY', $setting['mini_apicode']);
+ define('WX_APPSECRET', $setting['mini_appsecrept']);
+ define('WX_SSLCERT_PATH', $setting['apiclient_cert']);
+ define('WX_SSLKEY_PATH', $setting['apiclient_cert_key']);
+ define('WX_CURL_PROXY_HOST', '0.0.0.0');
+ define('WX_CURL_PROXY_PORT', 0);
+ define('WX_REPORT_LEVENL', 0);
+ require_once PAY_PATH.'/weixinpay/lib/WxOrderNotify.php';
+ $WxPay = new \WxOrderNotify($this->app);
+ $WxPay->Handle(false);
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-19 11:26
+ * @功能说明:阿里回调
+ */
+ public function aliNotify(){
+
+ $data = $_POST;
+
+ if(empty($data)){
+
+ $data = $_GET;
+ }
+
+ $pay_config = $this->payConfig();
+
+ require_once EXTEND_PATH.'alipay/aop/AopClient.php';
+
+ $aop = new \AopClient;
+
+ $aop->alipayrsaPublicKey = $pay_config[ 'payment' ][ 'ali_publickey' ];
+
+ $flag = $aop->rsaCheckV1($data, NULL, "RSA2");
+
+ if(!$flag){
+
+ return false;
+ }
+
+ $data['flag'] = $flag;
+
+ if(!empty($data)&&$data['trade_status']=='TRADE_SUCCESS') //支付状态
+ {
+
+ $notify_model = new PayNotify();
+
+ $notify_model->aliNotify($data);
+ }
+
+ return true;
+
+ }
+
+
+
+
+}
diff --git a/app/shop/info/AdminMenu.php b/app/shop/info/AdminMenu.php
new file mode 100755
index 0000000..be79591
--- /dev/null
+++ b/app/shop/info/AdminMenu.php
@@ -0,0 +1,596 @@
+ $malls];
+
+
diff --git a/app/shop/info/DiyCompoents.php b/app/shop/info/DiyCompoents.php
new file mode 100755
index 0000000..e308bfd
--- /dev/null
+++ b/app/shop/info/DiyCompoents.php
@@ -0,0 +1,51 @@
+ "业务组件",
+
+ 'type' => 'shopCompoent',
+
+ 'data' =>[
+
+ json_decode($search, true),
+
+ json_decode($goods, true),
+
+ ]
+ ],
+];
\ No newline at end of file
diff --git a/app/shop/info/DiyDefaultCompoents.php b/app/shop/info/DiyDefaultCompoents.php
new file mode 100755
index 0000000..0508625
--- /dev/null
+++ b/app/shop/info/DiyDefaultCompoents.php
@@ -0,0 +1,276 @@
+ 2,
+ "title" => "商城",
+ "type" => "shop",
+ "data" => [
+ [
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/diy/admin/Module/functionPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "功能页面",
+ //小程序路径
+ "page" => "common_page"
+ ],[
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/shop/admin/AdminShopType/cateInfoPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商品分类页面",
+ //小程序路径
+ "page" => "/shop/pages/filter"
+ ],[
+ //接口请求路径 api_path 不为空, 返回 page + '?' 数据参数
+ "api_path" => "/shop/admin/AdminShopGoods/goodsInfoPage",
+ //已经取消了
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商品详情页面",
+ //小程序路径
+ "page" => "/pages/shop/detail"
+ ],
+ ]
+ ],
+];
\ No newline at end of file
diff --git a/app/shop/info/DiyTabbar.php b/app/shop/info/DiyTabbar.php
new file mode 100755
index 0000000..539d278
--- /dev/null
+++ b/app/shop/info/DiyTabbar.php
@@ -0,0 +1,42 @@
+ 2 ,
+ //是否显示
+ 'is_show' => 1 ,
+ //图标
+ 'iconPath' => 'icon-shangcheng1',
+ //选中图标样式
+ 'selectedIconPath' => 'icon-shangcheng',
+ //那个页面 英文名称
+ 'pageComponents' => 'shopHome',
+ //名称
+ 'name' => '商城',
+ 'url' => '',
+ 'url_jump_way' => '0',
+ 'url_out' => '',
+ 'is_delete' => false ,
+ 'bind_compoents'=>[
+ 'base',
+ 'shopCompoent',
+ 'operate'
+ ],
+
+ 'bind_links' => [
+
+ 'shop'
+ ],
+ 'page'=> []
+ ],
+
+];
\ No newline at end of file
diff --git a/app/shop/info/FunctionPage.php b/app/shop/info/FunctionPage.php
new file mode 100755
index 0000000..8562ec4
--- /dev/null
+++ b/app/shop/info/FunctionPage.php
@@ -0,0 +1,86 @@
+'',
+
+ 'level'=>1,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城页面",
+ //小程序路径
+ "path" => "/pages/user/home?key=2&staff_id="
+ ],[
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城购物车",
+ //小程序路径
+ "path" => "/shop/pages/cart"
+ ],[
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城卡券列表",
+ //小程序路径
+ "path" => "/shop/pages/coupon/receive?staff_id="
+ ],
+
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城全部分类",
+ //小程序路径
+ "path" => "/shop/pages/cate"
+ ],
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城采购模版",
+ //小程序路径
+ "path" => "/shop/pages/purchase/list?staff_id="
+ ],
+ [
+ 'id'=>'',
+
+ 'level'=>2,
+
+ 'key'=> 2,
+ //"params"=>"{"page" : "PAGE", "page_count" : "PAGE_COUNT"}",
+ "title" => "商城砍价列表页",
+ //小程序路径
+ "path" => "/shop/pages/bargain/list?staff_id="
+ ],
+
+
+
+];
+
+
+return $tmp;
\ No newline at end of file
diff --git a/app/shop/info/Info.php b/app/shop/info/Info.php
new file mode 100755
index 0000000..a828e64
--- /dev/null
+++ b/app/shop/info/Info.php
@@ -0,0 +1,32 @@
+ 'shop',
+ //模块标题[必填]
+ 'title' =>'商城',
+ //内容简介
+ 'desc' =>'',
+ //封面图标
+ 'icon' =>'',
+ //模块类型[必填] model:模块 可以出现在左侧一级 app:应用中心 , 是一个应用中心的应用
+ 'type' => 'model',
+ // 模块唯一标识[必填],格式:模块名.开发者标识.module
+ 'identifier' => 'shop.longbing.module',
+ // 版本[必填],格式采用三段式:主版本号.次版本号.修订版本号
+ 'version' => '1.0.80',
+ // 模块依赖[可选],格式[[模块名, 模块唯一标识, 依赖版本, 对比方式]]
+ 'need_module'=> [],
+ // 应用依赖[可选],格式[[插件名, 应用唯一标识, 依赖版本, 对比方式]]
+ 'need_app' => [],
+ //订阅消息
+ 'tmpl_name'=>['pay_order','send_order','land_order','land_over']
+
+];
\ No newline at end of file
diff --git a/app/shop/info/PermissionShop.php b/app/shop/info/PermissionShop.php
new file mode 100755
index 0000000..f157129
--- /dev/null
+++ b/app/shop/info/PermissionShop.php
@@ -0,0 +1,106 @@
+saasKey = longbing_get_auth_prefix('AUTH_SHOP') ;
+ parent::__construct($uniacid, self::tabbarKey, self::adminMenuKey, $this->saasKey, self::apiPaths , $infoConfigOptions);
+ }
+
+
+ /**
+ * 返回saas端授权结果
+ * @return bool
+ */
+ public function sAuth(): bool
+ {
+ if(!$this->getAuthIsSaasCheck()){
+ return true ;
+ }
+ return $this->sassValue == 1 ? true : false;
+ }
+
+ /**
+ * 返回p端授权结果
+ * @return bool
+ */
+ public function pAuth(): bool
+ {
+ if (!$this->sAuth()) {
+ return false;
+ };
+
+ //代理管理端可以控制商城是否展示权限 , 这里需要判断权限
+ $pAuthConfig = $this->getPAuthConfig();
+ //必须平台授权才能使用
+
+ //dump($this->getAuthIsPlatformCheck());exit;
+ if($this->getAuthIsPlatformCheck()){
+ //根据授权而定
+ if ($pAuthConfig ){
+
+// dump($pAuthConfig);exit;
+ return $pAuthConfig['shop_switch'] ? true : false ;
+ }
+ }
+
+ return true;
+
+ }
+
+ /**
+ * 返回c端授权结果
+ *
+ * @param int $user_id
+ * @return bool
+ * @author ArtizanZhang
+ * @DataTime: 2019/12/9 17:13
+ */
+ public function cAuth(int $user_id): bool
+ {
+
+ return true;
+ }
+
+ /**
+ * 添加商品数量
+ *
+ * @author shuixian
+ * @DataTime: 2019/12/19 19:02
+ */
+ public function getAddGoodsNumber(){
+ return $this->getAuthVaule( longbing_get_auth_prefix('AUTH_GOODS') , 4);
+
+ }
+}
\ No newline at end of file
diff --git a/app/shop/info/RadarMessage.php b/app/shop/info/RadarMessage.php
new file mode 100755
index 0000000..63f6b05
--- /dev/null
+++ b/app/shop/info/RadarMessage.php
@@ -0,0 +1,204 @@
+ "copy",
+ "type"=> 8,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请及时留意雷达动态",
+ "operation"=> "咨询",
+ "item"=> "产品",
+ "show_count"=> 1,
+ "table_name"=> "",
+ "field"=> "",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+ [
+ "sign"=> "view",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商城列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机,主动提供细致的商品讲解将大大有利于成交",
+ "operation"=> "正在查看",
+ "item"=> "商品",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_goods",
+ "field"=> "name",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 11,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请尽快把握商机",
+ "operation"=> "浏览",
+ "item"=> "商品分类列表",
+ "show_count"=> 1,
+ "table_name"=> "longbing_card_shop_type",
+ "field"=> "title",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+ [
+ "sign"=> "view",
+ "type"=> 19,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "订单商品已发货,系统订单号为:",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 20,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "自提商品已提货",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 21,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请等待管理员审核并注意查收",
+ "operation"=> "已申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 22,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "已取消申请退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 23,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请前往订单中心查看详情",
+ "operation"=> "管理员拒绝退款",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "view",
+ "type"=> 24,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请注意查收",
+ "operation"=> "退款成功",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 1,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 1,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已购买商品",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 2,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在订单中心查看详情",
+ "operation"=> "已参与拼团",
+ "item"=> "",
+ "show_count"=> 0,
+ "table_name"=> "longbing_card_shop_order",
+ "field"=> "out_trade_no",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+ [
+ "sign"=> "order",
+ "type"=> 3,
+ "max"=> 0,
+ "pid"=> 0,
+ "msg"=> "请在预约订单中心查看详情",
+ "operation"=> "预约了",
+ "item"=> "服务",
+ "show_count"=> 0,
+ "table_name"=> "lb_appoint_record",
+ "field"=> "name,phone,project_id,start_time,remark",
+ "send"=> 2,
+ "uniacid"=> 2,
+ "status"=> 1
+ ],
+
+
+];
+
+return $radar_msg;
diff --git a/app/shop/info/Subscribe.php b/app/shop/info/Subscribe.php
new file mode 100755
index 0000000..2631956
--- /dev/null
+++ b/app/shop/info/Subscribe.php
@@ -0,0 +1,455 @@
+_uniacid);
+ if($permissson->pAuth()) {
+
+ $modelMenu = [
+ "title" => '商品服务',
+ "desc" => '',
+ "show" => true,
+ "row" => 4,
+ "list" => [
+ [
+ "title" => "我的收入",
+ "icon" => "icontixianguanli",
+ "link" => "/shop/pages/partner/income",
+ "linkType" => 4
+ ],
+ [
+ "title" => "订单管理",
+ "icon" => "iconwodedingdan",
+ "link" => "/shop/pages/order/list?target=staff",
+ "linkType" => 4
+ ],
+ [
+ "title" => "退款管理",
+ "icon" => "iconwodeshouhou",
+ "link" => "/shop/pages/refund/list?target=staff",
+ "linkType" => 4
+ ],
+ [
+ "title" => "推荐商品",
+ "icon" => "icontuijianshangpin",
+ "link" => "/shop/pages/staff/goods/push",
+ "linkType" => 4
+ ],
+ [
+ "title" => "卡券管理",
+ "icon" => "iconwodekaquan",
+ "link" => "/shop/pages/staff/coupon/list",
+ "linkType" => 4
+ ]
+ ]
+ ];
+
+ return [$modelMenu];
+ }
+ return [];
+
+ }
+
+ /**
+ * 名片展示页获取其他模块数据
+ *
+ * @param $params
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/24 14:24
+ */
+ public function onCardInfo($params)
+ {
+
+ //获取推荐商品 By.jingshuixian
+ $modelExtension = new CardExtension();
+ $goods_list = $modelExtension->cardExtensionList($params['staff_id'], $this->_uniacid);
+
+ $collage_model = new IndexShopCollage();
+ foreach ($goods_list as $key => $val) {
+ $goods_list[$key]['is_collage'] = 0;
+ $count = $collage_model->getCollage(['goods_id' => $val['id'], 'uniacid' => $this->_uniacid, 'status' => 1]);
+ if (!empty($count)) $goods_list[$key]['is_collage'] = 1;
+ }
+
+ return ['goods_list'=>$goods_list];
+ }
+
+ /**
+ * 客户获取列表查询
+ *
+ * @param $data
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/26 10:30
+ */
+ public function onStaffCustomerList($data)
+ {
+ // 商城订单
+ $orderCount = RadarOrder::where( [ [ 'pay_status', '=', 1 ],
+ [ 'order_status', '<>', 1 ],
+ [ 'user_id', '=', $data[ 'uid' ] ],
+ [ 'to_uid', '=', $data[ 'to_uid' ]],
+ [ 'refund_status', '=', 0 ] ]
+ )
+ ->count();
+
+ $returnData[ 'count' ] = $orderCount;
+ $returnData[ 'title' ] = "订单";
+
+ return [$returnData];
+ }
+
+
+ /**
+ * @param $data
+ * @功能说明:处理一下数据 主要是权限方面的
+ * @author chenniang
+ * @DataTime: 2020-12-16 16:21
+ */
+ public function onDiyModuleMenuShop($data){
+
+
+ if(!empty($data['data']['list'])){
+
+ foreach ($data['data']['list'] as $v){
+
+ if($v['icon']!='icontemplate'||$data['shop_auth']==true){
+
+ $arr[] = $v;
+ }
+
+ }
+ $data['data']['list'] = $arr;
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * 监听用户中心模块
+ *
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/18 14:04
+ */
+ public function onAddUcenterCompoent(){
+ $this->getUserId();
+
+ $user = longbingGetUserInfo($this->getUserId() , $this->_uniacid);
+
+ $last_staff_id = !empty($user['last_staff_id'])?$user['last_staff_id']:0;
+
+ $moduleMenuShopOrder = <<_uniacid);
+
+ $bargain_auth = $bargain_p->pAuth();
+
+ $bargain = $bargain_auth==true?',
+ {
+ "title": "我的砍价",
+ "icon": "iconkanjiajilu",
+ "link": {
+ "type": 2,
+ "url": "/shop/pages/bargain/record"
+ }
+ }':'';
+
+ $moduleMenuShop = <<_uniacid);
+ $compoentList = [] ;
+ if($permission->pAuth()){
+ $compoentList = [
+ json_decode($moduleMenuShopOrder, true),
+ json_decode($moduleMenuShop, true)
+ ] ;
+ }
+
+ return $compoentList ;
+ }
+
+
+
+ /**
+ * 监听代理管理端授权小程序事件
+ *
+ * @param $data
+ * @return array
+ * @author shuixian
+ * @DataTime: 2019/12/27 17:33
+ */
+ public function onAgentAppAuthEdit($config){
+
+
+ $returnArr = [] ;
+
+ $permission = new PermissionShop(0);
+ $shop_switch = [] ;
+ if($permission->sAuth() && $permission->infoConfig['auth_platform'] ) {
+
+ $shop_switch['formType'] = 'radio';
+ $shop_switch['name'] = 'shop_switch';
+
+ $shop_switch['value'] = $config ? $config[ $shop_switch['name'] ] : 0;
+ $shop_switch['title'] = $permission->info['title'];
+ $returnArr[] = $shop_switch;
+ }
+
+
+ $pay_shop = [] ;
+ if($permission->sAuth() && $permission->infoConfig['auth_platform'] ) {
+
+ $pay_shop['formType'] = 'radio';
+ $pay_shop['name'] = 'pay_shop';
+
+ $pay_shop['value'] = $config ? $config[ $pay_shop['name'] ] : 0;
+ $pay_shop['title'] = $permission->info['title'].'支付';
+ $returnArr[] = $pay_shop;
+ }
+
+ return $returnArr ;
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/shop/info/UpdateSql.php b/app/shop/info/UpdateSql.php
new file mode 100755
index 0000000..e69de29
diff --git a/app/shop/lang/zh-cn.php b/app/shop/lang/zh-cn.php
new file mode 100755
index 0000000..d94b055
--- /dev/null
+++ b/app/shop/lang/zh-cn.php
@@ -0,0 +1,15 @@
+ '未找到退款订单',
+ 'not find order' => '未找到订单',
+ 'status is error' => '状态错误',
+ 'Too little money' => '体现金额不得小于平台最低提现金额',
+ 'no profit' => '未找到佣金记录',
+ 'Insufficient amount' => '佣金不足',
+ 'no data' => '未找到记录',
+ 'not data' => '未找到记录',
+ 'Only offline package can be cancelled' => '只有线下福包才能核销',
+ 'The coupon has expired'=> '福包已过期',
+ 'not find card' => '名片没有找到',
+ 'no config of pay' => '未配置支付信息',
+];
\ No newline at end of file
diff --git a/app/shop/model/DistributionCash.php b/app/shop/model/DistributionCash.php
new file mode 100755
index 0000000..26cfdec
--- /dev/null
+++ b/app/shop/model/DistributionCash.php
@@ -0,0 +1,550 @@
+getShopGoods($data['id']);
+
+ }elseif($data['type']==2){
+
+ $list = $goods_model->getLandGoods($data['id']);
+
+ }else{
+
+ $list = $goods_model->getCliamGoods($data['id']);
+
+ }
+
+ return $list;
+
+ }
+
+ }
+
+
+
+ /**
+ * @param $type
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-21 17:02
+ */
+ public function returnType($type){
+
+ switch ($type){
+
+ case 1:
+
+ $text = '商城产品';
+
+ break;
+ case 2:
+
+ $text = '土地产品';
+
+ break;
+ case 3:
+
+ $text = '认养产品';
+
+ break;
+ default:
+
+ $text = '商城产品';
+
+ break;
+
+ }
+
+ return $text;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $order
+ * @param $type
+ * @param int $status
+ * @功能说明:添加商城分销记录
+ * @author chenniang
+ * @DataTime: 2022-07-27 13:51
+ */
+ public function addUserCashShop($fx_id,$top_id,$order,$type,$status=1){
+
+
+ if(!empty($order['order_goods'])){
+
+ $goods_model = new ShopGoods();
+
+ $cash_goods_model = new DistributionGoods();
+
+ $is_fx = $total_cash = 0;
+
+ foreach ($order['order_goods'] as &$v){
+
+ $goods_info = $goods_model->dataInfo(['id'=>$v['goods_id']]);
+
+ if(!empty($goods_info['is_fx'])){
+
+ $v['fx_balance'] = $type==1?$goods_info['one_fx']:$goods_info['two_fx'];
+
+ $v['is_fx'] = $goods_info['is_fx'];
+
+ $v['fx_cash']= $v['pay_price']*$v['fx_balance']/100;
+
+ $total_cash += $v['fx_cash'];
+
+ $is_fx = 1;
+
+ }
+ }
+ //说明有分销商品
+ if($is_fx==1){
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $top_id,
+
+ 'source_id' => $order['user_id'],
+
+ 'order_code'=> $order['order_code'],
+
+ 'transaction_id'=> $order['transaction_id'],
+
+ 'order_id' => $order['id'],
+
+ 'type' => 1,
+
+ 'status' => $status,
+
+ 'fx_type' => $type,
+
+ 'cash' => round($total_cash,2),
+
+ 'reseller_id'=> $fx_id,
+ ];
+
+ $this->dataAdd($insert);
+
+ $id = $this->getLastInsID();
+
+ foreach ($order['order_goods'] as $v){
+
+ if($v['is_fx']==1){
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'cash_id' => $id,
+
+ 'order_goods_id' => $v['id'],
+
+ 'balance' => $v['fx_balance'],
+
+ 'cash' => $v['fx_cash'] ,
+
+ 'single_cash'=> round($v['fx_cash']/$v['goods_num'],2),
+
+ 'num' => $v['goods_num'],
+ ];
+
+ $cash_goods_model->dataAdd($insert);
+
+ }
+
+ }
+
+ }
+
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param $order
+ * @param $type
+ * @param int $status
+ * @功能说明:添加土地订单分销
+ * @author chenniang
+ * @DataTime: 2022-07-27 13:53
+ */
+ public function addUserCashLand($fx_id,$top_id,$order,$type,$status=1){
+
+ $land_model = new LandList();
+
+ $land = $land_model->dataInfo(['id'=>$order['land_id']]);
+
+ if(!empty($land['is_fx'])){
+
+ $fx_balance = $type==1?$land['one_fx']:$land['two_fx'];
+
+ $total_cash = $order['pay_price']*$fx_balance/100;
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $top_id,
+
+ 'source_id' => $order['user_id'],
+
+ 'order_code'=> $order['order_code'],
+
+ 'transaction_id'=> $order['transaction_id'],
+
+ 'order_id' => $order['id'],
+
+ 'type' => 2,
+
+ 'status' => $status,
+
+ 'fx_type' => $type,
+
+ 'reseller_id'=> $fx_id,
+
+ 'cash' => round($total_cash,2),
+ ];
+
+ $this->dataAdd($insert);
+
+ $id = $this->getLastInsID();
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'cash_id' => $id,
+
+ 'order_goods_id' => $order['id'],
+
+ 'balance' => $fx_balance,
+
+ 'cash' => $total_cash ,
+
+ 'single_cash'=> $total_cash,
+
+ 'num' => 1,
+ ];
+
+ $cash_goods_model = new DistributionGoods();
+
+ $cash_goods_model->dataAdd($insert);
+
+ }
+
+ return true;
+ }
+
+
+
+ /**
+ * @param $order
+ * @param $type
+ * @param int $status
+ * @功能说明:添加认养订单分销
+ * @author chenniang
+ * @DataTime: 2022-07-27 13:53
+ */
+ public function addUserCashClaim($fx_id,$top_id,$order,$type,$status=1){
+
+ $land_model = new Claim();
+
+ $land = $land_model->dataInfo(['id'=>$order['claim_id']]);
+
+ if(!empty($land['is_fx'])){
+
+ $fx_balance = $type==1?$land['one_fx']:$land['two_fx'];
+
+ $total_cash = $order['pay_price']*$fx_balance/100;
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'user_id' => $top_id,
+
+ 'source_id' => $order['user_id'],
+
+ 'order_code'=> $order['order_code'],
+
+ 'transaction_id'=> $order['transaction_id'],
+
+ 'order_id' => $order['id'],
+
+ 'type' => 3,
+
+ 'status' => $status,
+
+ 'fx_type' => $type,
+
+ 'reseller_id' => $fx_id,
+
+ 'cash' => round($total_cash,2),
+ ];
+
+ $this->dataAdd($insert);
+
+ $id = $this->getLastInsID();
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'cash_id' => $id,
+
+ 'order_goods_id' => $order['id'],
+
+ 'balance' => $fx_balance,
+
+ 'cash' => $total_cash ,
+
+ 'single_cash'=> round($total_cash/$order['num']),
+
+ 'num' => $order['num'],
+ ];
+
+ $cash_goods_model = new DistributionGoods();
+
+ $cash_goods_model->dataAdd($insert);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-27 15:47
+ * @功能说明:增加佣金信息
+ */
+ public function addUserCash($order,$type=1){
+
+ $user_model = new User();
+
+ $top_id = $user_model->where(['id'=>$order['user_id'],'is_fx'=>1])->value('pid');
+ //没有上级不往下执行
+ if(empty($top_id)){
+
+ return true;
+ }
+ //二级分销
+ if($type==2){
+
+ $top_id = $user_model->where(['id'=>$top_id,'is_fx'=>1])->value('pid');
+
+ if(empty($top_id)){
+
+ return true;
+ }
+
+ }
+
+ $fx_model = new DistributionList();
+
+ $dis = [
+
+ 'user_id' => $top_id,
+
+ 'status' => 2
+ ];
+ //查询分销id
+ $fx_id = $fx_model->where($dis)->value('id');
+
+ if(empty($fx_id)){
+
+ return true;
+ }
+
+ if($type==1){
+ //商城一级分销
+ $this->addUserCashShop($fx_id,$top_id,$order,1);
+ //商城二级分销
+ $this->addUserCashShop($fx_id,$top_id,$order,2);
+
+ }elseif ($type==2){
+ //土地一级分销
+ $this->addUserCashLand($fx_id,$top_id,$order,1);
+ //土地二级分销
+ $this->addUserCashLand($fx_id,$top_id,$order,2);
+
+ }else{
+ //土地一级分销
+ $this->addUserCashClaim($fx_id,$top_id,$order,1);
+ //土地二级分销
+ $this->addUserCashClaim($fx_id,$top_id,$order,2);
+
+ }
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-28 17:18
+ * @功能说明:佣金到账
+ */
+ public function cashArrival($order,$type=1){
+
+ $dis = [
+
+ 'order_id' => $order['id'],
+
+ 'type' => $type,
+
+ 'status' => 1
+ ];
+
+ $list = $this->dataInfo($dis);
+
+ if(!empty($list)){
+
+ $res = $this->dataUpdate($dis,['status'=>2]);
+
+ if($res==0){
+
+ return false;
+ }
+
+ $user_model = new User();
+
+ $cash = $list['cash'];
+
+ $res = $user_model->where(['id'=>$order['user_id']])->update(['fx_cash'=>Db::Raw("fx_cash+$cash")]);
+
+ if($res==0){
+
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-29 11:49
+ * @功能说明:分销佣金列表
+ */
+ public function adminCashList($dis,$where,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_distribution_list b','a.reseller_id = b.id','left')
+ ->join('lbfarm_user_list c','a.user_id = c.id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,c.nickName,b.user_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/DistributionGoods.php b/app/shop/model/DistributionGoods.php
new file mode 100755
index 0000000..4b67f25
--- /dev/null
+++ b/app/shop/model/DistributionGoods.php
@@ -0,0 +1,154 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-27 17:46
+ * @功能说明:获取商城商品
+ */
+ public function getShopGoods($cash_id){
+
+ $dis = [
+
+ 'a.cash_id' => $cash_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods b','a.order_goods_id = b.id')
+ ->where($dis)
+ ->field('b.goods_name,b.goods_cover,b.spe_name,b.pay_price,a.*,b.singe_pay_price')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-27 17:54
+ * @功能说明:获取土地商品
+ */
+ public function getLandGoods($cash_id){
+
+ $dis = [
+
+ 'a.cash_id' => $cash_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_land_order b','a.order_goods_id = b.id')
+ ->where($dis)
+ ->field('b.goods_name,b.goods_cover,b.spe_name,b.pay_price,a.*,b.pay_price as singe_pay_price ')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-27 17:54
+ * @功能说明:获取认养商品
+ */
+ public function getCliamGoods($cash_id){
+
+ $dis = [
+
+ 'a.cash_id' => $cash_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_claim_order b','a.order_goods_id = b.id')
+ ->where($dis)
+ ->field('b.goods_name,b.goods_cover,b.spe_name,b.pay_price,a.*,b.pay_price as singe_pay_price')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/DistributionList.php b/app/shop/model/DistributionList.php
new file mode 100755
index 0000000..6eceb3f
--- /dev/null
+++ b/app/shop/model/DistributionList.php
@@ -0,0 +1,244 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $user_id
+ * @功能说明:我的状态
+ * @author chenniang
+ * @DataTime: 2022-07-28 10:00
+ */
+ public function myTeam($user_id,$type=1){
+
+ $user_model = new User();
+
+ $dis[] = ['is_fx','=',1];
+
+ if($type==1){
+
+ $dis[] = ['pid','=',$user_id];
+
+ }else{
+
+ $top_id = $user_model->where(['pid'=>$user_id,'is_fx'=>1])->column('id');
+
+ $dis[] = ['pid','in',$top_id];
+
+ }
+
+ $data = $user_model->where($dis)->field('id,nickName,avatarUrl,fx_bind_time')->order('fx_bind_time desc')->paginate(10)->toArray();
+
+ if(!empty($data['data'])){
+
+ $water_model = new FinanceWater();
+
+ foreach ($data['data'] as &$v){
+
+ $v['fx_bind_time'] = date('Y-m-d H:i:s',$v['fx_bind_time']);
+
+ $dis = [
+
+ 'is_fx' => 1,
+
+ 'pid' => $v['id']
+ ];
+ //推广人数
+ $v['team_count'] = $user_model->where($dis)->count();
+
+ $order_data = $water_model->resellerCashData($v['id']);
+
+ $v = array_merge($v,$order_data);
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @param $user_id
+ * @param int $type
+ * @功能说明:团队人数
+ * @author chenniang
+ * @DataTime: 2022-07-28 17:58
+ */
+ public function teamCount($user_id,$type=1){
+
+ $user_model = new User();
+
+ $dis[] = ['is_fx','=',1];
+
+ if($type==1){
+
+ $dis[] = ['pid','=',$user_id];
+
+ }else{
+
+ $top_id = $user_model->where(['pid'=>$user_id,'is_fx'=>1])->column('id');
+
+ $dis[] = ['pid','in',$top_id];
+
+ }
+
+ $data = $user_model->where($dis)->count();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-12-30 11:26
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10,$where=[]){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_user_list b','a.user_id = b.id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,b.nickName,b.avatarUrl')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:用户收益列表
+ * @author chenniang
+ * @DataTime: 2022-07-29 14:50
+ */
+ public function userProfitList($dis,$page=10,$where=[]){
+
+ $user_model = new User();
+
+ $data = $user_model->alias('a')
+ ->join('lbfarm_v2_distribution_list b','a.id = b.user_id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('b.*,a.nickName,a.avatarUrl,a.fx_cash')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:用户收益列表
+ * @author chenniang
+ * @DataTime: 2022-07-29 14:50
+ */
+ public function userProfitSelect($dis,$where=[]){
+
+ $user_model = new User();
+
+ $data = $user_model->alias('a')
+ ->join('lbfarm_v2_distribution_list b','a.id = b.user_id','left')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('b.*,a.nickName,a.avatarUrl,a.fx_cash')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ return $data;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/FreightConfig.php b/app/shop/model/FreightConfig.php
new file mode 100755
index 0000000..a7bfa37
--- /dev/null
+++ b/app/shop/model/FreightConfig.php
@@ -0,0 +1,103 @@
+where(['config_id'=>$data['id']])->column('province');
+
+ return array_values($list);
+ }
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/FreightProvince.php b/app/shop/model/FreightProvince.php
new file mode 100755
index 0000000..ac0b092
--- /dev/null
+++ b/app/shop/model/FreightProvince.php
@@ -0,0 +1,77 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/FreightTemplate.php b/app/shop/model/FreightTemplate.php
new file mode 100755
index 0000000..63f507d
--- /dev/null
+++ b/app/shop/model/FreightTemplate.php
@@ -0,0 +1,219 @@
+where(['template_id'=>$data['id']])->select()->toArray();
+
+ return $list;
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $data
+ * @功能说明:添加模版
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:32
+ */
+ public function tmplAdd($data){
+
+ if(isset($data['config'])){
+
+ $config = $data['config'];
+
+
+ unset($data['config']);
+
+ }
+
+ $res = $this->dataAdd($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($config)){
+
+ $this->updateSome($config,$id,$data['uniacid']);
+ }
+
+ return $id;
+ }
+
+
+ /**
+ * @param $dis
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:37
+ */
+ public function tmplUpdate($dis,$data){
+
+ if(isset($data['config'])){
+
+ $config = $data['config'];
+
+ unset($data['config']);
+
+ }
+
+ $res = $this->dataUpdate($dis,$data);
+
+ if(isset($config)){
+
+ $this->updateSome($config,$dis['id'],$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $data
+ * @param $id
+ * @param $uniacid
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-11 16:11
+ */
+ public function updateSome($data,$id,$uniacid){
+
+ $config_model = new FreightConfig();
+
+ $province_model = new FreightProvince();
+
+ $config_model->where(['template_id'=>$id])->delete();
+
+ $province_model->where(['template_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $key=>$value){
+
+ $value['uniacid'] = $uniacid;
+
+ $value['template_id'] = $id;
+
+ $province = $value['province'];
+
+ unset($value['province']);
+
+ $config_model->dataAdd($value);
+
+ $config_id = $config_model->getLastInsID();
+
+ foreach ($province as $ks=>$vs){
+
+ $insert[$ks] = [
+
+ 'uniacid' => $uniacid,
+
+ 'config_id'=> $config_id,
+
+ 'province' => $vs,
+
+ 'template_id' => $id
+
+ ];
+ }
+
+ $province_model->saveAll($insert);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/GoodsSpePrice.php b/app/shop/model/GoodsSpePrice.php
new file mode 100755
index 0000000..86c4a58
--- /dev/null
+++ b/app/shop/model/GoodsSpePrice.php
@@ -0,0 +1,187 @@
+where(['status'=>1])->where('id','IN',$pec_id)->select()->toArray();
+ if(!empty($spe_names)){
+ foreach ($spe_names as $value){
+ $spe_name[] = $value['title'];
+ }
+ return implode('-',$spe_name);
+ }
+
+ }
+ /**
+ * @param $value
+ * @param $data
+ * @return mixed
+ * get spearray
+ */
+ public function getSpeArrayTextAttr($value,$data){
+ return explode('-',$data['spe_id_1']);
+ }
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @return mixed
+ * 获取商品多规格价格库存
+ */
+ public function goodsSpePrice($dis){
+ $data = $this->where($dis)->select()->toArray();
+ return $data;
+ }
+
+ /**
+ * @param $data
+ * @return int|string
+ * 添加商品规格
+ */
+
+ public function goodsSpePriceAdd($data){
+ $data['create_time'] = time();
+ $data['status'] = 1;
+ $res = $this->insert($data);
+ return $res;
+ }
+
+
+ /**
+ * @param $data
+ * @return int|string
+ * 添加商品规格
+ */
+
+ public function goodsSpePriceSaveAll($data){
+ $res = $this->saveAll($data);
+ return $res;
+ }
+
+ /**
+ * @param $data
+ * @return int|string
+ * 编辑啊商品规格
+ */
+
+ public function goodsSpePriceUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = $this->where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ * @param $dis
+ * 根据条件获取id
+ */
+
+ public function goodsSpePriceId($dis){
+ $data = $this->where($dis)->column('id');
+ return $data;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @return mixed
+ * 获取商品多规格价格库存
+ */
+ public function singeSpePrice($dis){
+ $data = $this->where($dis)->find();
+ return !empty($data)?$data->toArray():$data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-25 16:13
+ * @功能说明:获取售罄的商品id
+ */
+ public function getSellOut($uniacid,$type=0){
+
+ $dis[] = ['uniacid','=', $uniacid];
+
+ $dis[] = ['status','=', 1];
+
+ $all_goods = $this->where($dis)->column('goods_id');
+
+ $dis[] = ['stock','>',0];
+
+ $diff_goods = $this->where($dis)->column('goods_id');
+
+ if($type==1){
+
+ return $diff_goods;
+ }
+
+ $data = array_diff($all_goods,$diff_goods);
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-26 09:53
+ * @功能说明:获取商品库存
+ */
+ public function getGoodsStock($goods_id){
+
+ $dis = [
+
+ 'goods_id' => $goods_id,
+
+ 'status' => 1
+ ];
+
+ $stock = $this->where($dis)->sum('stock');
+
+ return is_numeric($stock)?$stock:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-01-19 18:15
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/IntegralGoods.php b/app/shop/model/IntegralGoods.php
new file mode 100755
index 0000000..0cc9bc8
--- /dev/null
+++ b/app/shop/model/IntegralGoods.php
@@ -0,0 +1,195 @@
+dataInfo(['id'=>$data['spe_id']]);
+
+ if(!empty($info)){
+
+ return $info['spe_name_text'];
+ }
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:34
+ * @功能说明:积分列表可以通过商品名字查询
+ */
+ public function dataGoodsList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('longbing_card_v2_shop_goods b','a.goods_id = b.id','left')
+ ->where($dis)
+ ->field('a.*,b.name as goods_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:54
+ * @功能说明:初始化活动时间
+ */
+ public function initAtv(){
+
+ $this->where('start_time','>',time())->update(['atv_status'=>1]);
+
+ $this->where('start_time','<',time())->update(['atv_status'=>2]);
+
+ $this->where('end_time','>',time())->update(['atv_status'=>3]);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 17:58
+ * @功能说明:修改
+ */
+ public function updateAtvStock($integral_id,$goods_id,$spe_id,$num,$type=1){
+
+ $dis = [
+
+ 'atv_id' => $integral_id,
+
+ 'goods_id'=> $goods_id,
+
+ 'spe_id' => $spe_id
+
+ ];
+
+ $integral_goods_model = new IntegralGoods();
+
+ $find = $integral_goods_model->dataInfo($dis);
+
+ if($type==1){
+
+ if(empty($find)){
+
+ return ['code'=>500,'msg'=>'积分活动已下架'];
+
+ }
+
+ if($find['have_stock']+$num>$find['stock']){
+
+ return ['code'=>500,'msg'=>'可兑换数量不足'];
+
+ }
+
+ $integral_goods_model->where($dis)->update(['have_stock'=> Db::Raw("have_stock+$num")]);
+
+ }else{
+
+ if(!empty($find)){
+
+ $integral_goods_model->where($dis)->update(['have_stock'=> Db::Raw("have_stock-$num")]);
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/IntegralList.php b/app/shop/model/IntegralList.php
new file mode 100755
index 0000000..afe5fa9
--- /dev/null
+++ b/app/shop/model/IntegralList.php
@@ -0,0 +1,656 @@
+ $data['id'],
+
+ 'b.status' => 2,
+
+ 'b.type' => 2
+ ];
+
+ $list = $store_model->alias('a')
+ ->join('lbfarm_farmer b','a.store_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title,b.is_admin,b.cover')
+ ->select()
+ ->toArray();
+
+ return array_values($list);
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 18:52
+ * @功能说明:参与活动的商品规格信息
+ */
+ public function getGoodsInfoAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $i_model = new IntegralGoods();
+
+ $list = $i_model->alias('a')
+ ->join('lbfarm_v2_shop_spe_price b','a.spe_id = b.id')
+ ->where(['a.atv_id' => $data['id']])
+ ->field(['b.stock as goods_stock','b.price as goods_price','a.*'])
+ ->select()
+ ->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 18:46
+ * @功能说明:获取第一个规格的价格
+ */
+ public function getShowPriceAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $i_model = new IntegralGoods();
+
+ $info = $i_model->dataInfo(['atv_id'=>$data['id']]);
+
+ $text = '';
+
+ if(!empty($info['integral'])){
+
+ $text .= $info['integral'].'积分';
+ }
+
+ if(!empty($info['price'])){
+
+ $text .= '+'.$info['price'].'元';
+ }
+
+ return $text;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 18:50
+ * @功能说明:总的库存
+ */
+ public function getAllStockAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $i_model = new IntegralGoods();
+
+ $num = $i_model->where(['atv_id'=>$data['id']])->sum('stock');
+
+ return $num;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 18:50
+ * @功能说明:总的库存
+ */
+ public function getAllHaveStockAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $i_model = new IntegralGoods();
+
+ $num = $i_model->where(['atv_id'=>$data['id']])->sum('have_stock');
+
+ return $num;
+ }
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $goods_info = $data['goods_info'];
+
+ unset($data['goods_info']);
+
+// $store_info = $data['store_info'];
+//
+// unset($data['store_info']);
+
+ Db::startTrans();
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ $res = $this->updateSome($id,$data,$goods_info);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+ }
+
+ Db::commit();
+
+ return $res;
+
+ }
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 18:21
+ * @功能说明:
+ */
+ public function updateSome($id,$data,$goods_info){
+
+ $i_model = new IntegralGoods();
+
+ $atv = $this->dataInfo(['id'=>$id]);
+
+ $arr = [];
+
+ if(!empty($goods_info)){
+
+ foreach ($goods_info as &$value){
+
+ $i_dis = [
+
+ 'atv_id' => $id,
+
+ 'goods_id'=> $data['goods_id'],
+
+ 'spe_id' => $value['spe_id'],
+ ];
+
+ $have_stock = $i_model->where($i_dis)->value('have_stock');
+
+ $i_model->where($i_dis)->delete();
+
+ $where = [];
+
+ $where[] = ['a.goods_id','=',$data['goods_id']];
+
+ $where[] = ['b.spe_id','=',$value['spe_id']];
+
+ $where[] = ['a.status','>',-1];
+
+ $where[] = ['a.id','<>',$id];
+
+ $info = $i_model->alias('b')
+ ->join('lbfarm_v2_integral_shop a','a.id = b.atv_id')
+ ->where($where)
+ ->field('a.*,b.*')
+ ->select()
+ ->toArray();
+
+ if(!empty($info)){
+
+ foreach ($info as $vs){
+
+ $res = is_time_cross($vs['start_time'],$vs['end_time'],$atv['start_time'],$atv['end_time']);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'规格'.$vs['spe_name'].'该时间段已有积分活动,请先删除,再添加'];
+ }
+
+ }
+
+ }
+
+ $insert = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'goods_id'=> $data['goods_id'],
+
+ 'spe_id' => $value['spe_id'],
+
+ 'stock' => $value['stock'],
+
+ 'price' => $value['price'],
+
+ 'integral'=> $value['integral'],
+
+ 'have_stock'=> !empty($have_stock)?$have_stock:0,
+
+ 'atv_id' => $id,
+ ];
+
+ $i_model->dataAdd($insert);
+
+ $arr[] = $i_model->getLastInsID();
+
+ }
+ }
+
+ $i_model->where('id','not in',$arr)->where('atv_id','=',$id)->delete();
+
+// $store_model = new IntegralStore();
+//
+// $store_model->where(['integral_id'=>$id])->delete();
+//
+// foreach ($store_info as $k=>$v){
+//
+// $store_insert[$k] = [
+//
+// 'uniacid' => $data['uniacid'],
+//
+// 'integral_id' => $id,
+//
+// 'store_id' => $v
+//
+// ];
+//
+// }
+//
+// $store_model->saveAll($store_insert);
+
+ return true;
+
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(!empty($data['goods_info'])){
+
+ $goods_info = $data['goods_info'];
+
+ unset($data['goods_info']);
+ }
+
+// if(!empty($data['store_info'])){
+//
+// $store_info = $data['store_info'];
+//
+// unset($data['store_info']);
+// }
+
+ Db::startTrans();
+
+ $res = $this->where($dis)->update($data);
+
+ if(!empty($goods_info)){
+
+ $res = $this->updateSome($dis['id'],$data,$goods_info);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+ }
+ }
+
+ Db::commit();
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:34
+ * @功能说明:积分列表可以通过商品名字查询
+ */
+ public function dataGoodsList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_goods b','a.goods_id = b.id','left')
+ ->where($dis)
+ ->field('a.*,b.goods_name,cover')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:54
+ * @功能说明:初始化活动时间
+ */
+ public function initAtv(){
+
+ $this->where('start_time','>',time())->update(['atv_status'=>1]);
+
+ $this->where('start_time','<',time())->update(['atv_status'=>2]);
+
+ $this->where('end_time','<',time())->update(['atv_status'=>3]);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-01 10:18
+ * @功能说明:正在进行中的活动
+ */
+ public function atvIng($goods_id,$spe_id=0){
+
+ $dis[] = ['a.atv_status','=',2];
+
+ $dis[] = ['a.goods_id','=',$goods_id];
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($spe_id)){
+
+ $dis[] = ['b.spe_id','=',$spe_id];
+ }
+
+// if(!empty($store_id)){
+//
+// $dis[] = ['c.store_id','=',$store_id];
+//
+// }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_integral_shop_goods b','a.id = b.atv_id')
+ // ->join('lbfarm_v2_integral_store c','a.id = c.integral_id')
+ ->where($dis)
+ ->field('a.*,b.*')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-01 10:18
+ * @功能说明:正在进行中的活动
+ */
+ public function buyLimit($goods_id,$spe_id=0){
+
+ $dis[] = ['a.atv_status','=',2];
+
+ $dis[] = ['a.goods_id','=',$goods_id];
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($spe_id)){
+
+ $dis[] = ['b.spe_id','=',$spe_id];
+ }
+
+// if(!empty($store_id)){
+//
+// $dis[] = ['c.store_id','=',$store_id];
+//
+// }
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_integral_shop_goods b','a.id = b.atv_id')
+ // ->join('lbfarm_v2_integral_store c','a.id = c.integral_id')
+ ->where($dis)
+ ->field('a.*')
+ ->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-04 14:41
+ * @功能说明:获取是否
+ */
+ public function getBuyLimit($list){
+
+ $this->initAtv();
+
+ $data['buy_limit'] = 1;
+
+ $data['discount_add'] = 1;
+
+ foreach ($list as $value){
+
+ $res = $this->buyLimit($value['goods_id'],$value['spe_id']);
+
+ if(!empty($res)){
+
+ if($res['buy_limit']==0){
+
+ $data['buy_limit'] = 0;
+ }
+
+ if($res['discount_add']==0){
+
+ $data['discount_add'] = 0;
+ }
+
+ }
+
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-11 16:50
+ * @功能说明:获取活动次数
+ */
+ public function getAtvNum1($id,$user_id){
+
+ $order_model = new Order();
+
+ $dis = [
+
+ 'b.integral_id' => $id,
+
+ 'a.user_id' => $user_id
+
+ ];
+
+ $num = $order_model->alias('a')
+ ->join('longbing_card_v2_shop_order_goods b','a.id = b.order_id')
+ ->where('a.pay_type','>=',1)
+ ->where($dis)
+ ->sum('goods_num');
+
+ return $num;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @return float
+ * 获取历史商品件数
+ */
+ public function getAtvNum($id,$user_id){
+
+ $dis = [
+
+ 'a.integral_id' => $id,
+
+ 'b.user_id' => $user_id
+
+ ];
+
+ $order_model = new \app\farm\model\ShopOrderGoods();
+
+ //取消订单的不算 chen
+ $num = $order_model->alias('a')
+ ->join('lbfarm_shop_order b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->group('a.id')
+ ->sum('a.goods_num');
+
+
+ $order_id = $order_model->alias('a')
+ ->join('lbfarm_shop_order b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->column('b.id');
+
+ $order_refund_goods = new \app\farm\model\ShopRefundGoods();
+ //申请退款成功的
+ $refund_num = $order_refund_goods->where('order_id','in',$order_id)->where(['status'=>2])->sum('goods_num');
+
+ return $num - $refund_num;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 11:01
+ * @功能说明:积分商品列表
+ */
+ public function integralGoodsList($dis,$page=10){
+
+ $goods_model = new ShopGoods();
+
+ $i_goods_model = new IntegralGoods();
+
+ $spe_model = new GoodsSpePrice();
+
+ $data = $goods_model->alias('a')
+ ->join('lbfarm_v2_integral_shop_goods b','b.goods_id = a.id')
+ ->join('lbfarm_v2_integral_shop c','b.atv_id = c.id')
+ ->where($dis)
+ ->field('a.goods_name,a.cover,a.id as goods_id,c.id as atv_id,c.type')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ $spe = $i_goods_model->where(['atv_id'=>$v['atv_id']])->order('price')->find()->toArray();
+
+ $v['integral'] = $spe['integral'];
+
+ $v['price'] = $spe['price'];
+
+ $v['init_price'] = $spe_model->where(['id'=>$spe['spe_id']])->sum('price');
+
+ $v['all_have_stock'] = $i_goods_model->where(['atv_id'=>$v['atv_id']])->sum('have_stock');
+
+ }
+
+ }
+
+ return $data;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/IntegralLog.php b/app/shop/model/IntegralLog.php
new file mode 100755
index 0000000..b2229b3
--- /dev/null
+++ b/app/shop/model/IntegralLog.php
@@ -0,0 +1,512 @@
+insert($data);
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-16 16:35
+ * @功能说明:列表
+ */
+ public function integralList($dis,$page){
+
+ $data = $this->where($dis)->order(['update_time desc','id desc'])->paginate($page)->toArray();
+
+ if(!empty($data['data'])){
+
+ foreach ($data['data'] as &$v){
+
+ if($v['controller_type']==0){
+
+ $v['controller_name'] = '系统核算';
+
+ $icon = $v['integral_add']>0?'+':'-';
+
+ $integral_add = $v['integral_add']>0?$v['integral_add']:$v['integral_add']*-1;
+
+ $text = $v['integral_add']>0?'增加积分':'使用积分';
+
+ $boj = $this->returnObj($v['type']);
+
+ $refund = $v['refund']==1?'(已退款)':'';
+
+ $v['text'] = $boj.$text.$icon.$integral_add.',现积分 '.$v['integral_after'].$refund;
+
+ $v['type_text'] = $boj;
+
+ }
+
+ }
+
+ }
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-14 15:17
+ * @功能说明:返回一个对象
+ */
+ public function returnObj($type){
+
+ switch ($type){
+
+ //加
+ case 1:
+ return '购买商城商品';
+
+ break;
+ //购买储值套餐赠送
+ case 2:
+ return '购买储值套餐';
+
+ break;
+
+ case 3://减
+ return '购买商城商品';
+
+ break;
+
+ case 4:
+ return '购买土地产品';
+
+ break;
+
+ case 5:
+ return '购买认养产品';
+
+ break;
+ case 6://售后
+ return '商城商品退款';
+
+ break;
+ case 7://售后
+ return '购买养殖产品';
+
+ break;
+
+ case 8:
+ return '购买认养配送';
+
+ break;
+
+ case 9:
+ return '购买土地配送';
+
+ break;
+
+ case 10:
+ return '签到';
+
+ break;
+ case 11://消耗
+ return '抽奖';
+
+ break;
+ case 12:
+ return '后台充值';
+
+ break;
+ case 13:
+ return '后台扣除';
+
+ break;
+
+ case 14:
+ return '抽奖获取';
+
+ break;
+ default:
+ return '消费';
+
+ break;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:08
+ * @功能说明:详情
+ */
+ public function integralInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-04-26 17:13
+ * @功能说明:编辑
+ */
+ public function integralUpdate($dis,$data){
+
+ $data['update_time'] = time();
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-24 10:49
+ * @功能说明:发送积分消息
+ */
+ public function sendMsg($data,$user_id,$integral,$type){
+
+ if(in_array($type,[1,3,4,5,10,11])){
+
+ $data['integral'] = abs($integral);
+
+ $data['user_id'] = $user_id;
+ //消费获取的积分
+ if(in_array($type,[1,2,4,5])){
+
+ $s_type = 10;
+
+ }elseif (in_array($type,[3])){
+ //消费消耗的积分
+ $s_type = 11;
+
+ }elseif (in_array($type,[11])){
+ //抽奖消耗
+ $s_type = 12;
+
+ }elseif (in_array($type,[10])){
+ //签到获取积分
+ $s_type = 13;
+
+ }
+
+ $info_model = new PushMsgModel($data['uniacid']);
+
+ $info_model->sendMsg($data,$s_type);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-07-31 10:28
+ * @功能说明:增加用户积分
+ */
+ public function integralUserAdd($user_id,$integral,$uniacid,$status = 2,$type=0,$order_id=0,$time=0,$data=[]){
+
+// if(!in_array($type,[5,6,7,8])){
+// //积分倍率
+// $arr = $this->pointDouble($user_id,$integral);
+//
+// $integral = $arr['integral'];
+// //查询单日获取积分是否超限
+// $integral = $this->dayGetIntegral($user_id,$integral,$uniacid);
+// }
+
+ $time = !empty($time)?$time:time();
+
+ if(!empty($integral)&&$integral!='0.00'){
+ //发送消息
+ $this->sendMsg($data,$user_id,$integral,$type);
+
+ $member_model = new \app\farm\model\User();
+
+ $member_info = $member_model->dataInfo(['id'=>$user_id]);
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'user_id' => $user_id,
+
+ 'integral_add' => $integral,
+
+ 'integral_before'=> $member_info['integral'],
+
+ 'integral_after' => $member_info['integral']+$integral,
+
+ 'status' => $status,
+
+ 'type' => $type,
+
+ 'order_id' => $order_id,
+
+ 'double' => !empty($arr['double'])?$arr['double']:1,
+
+ 'create_time' => $time,
+
+ 'update_time' => $time,
+ ];
+
+ $res = $this->insert($insert);
+
+ if($res==0){
+
+ return false;
+ }
+
+ $res = $member_model->dataUpdate(['id'=>$user_id],['integral'=>$insert['integral_after']]);
+
+ if($res==0){
+
+ return false;
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**\
+ * @author chenniang
+ * @DataTime: 2021-11-12 17:31
+ * @功能说明:积分倍率
+ */
+ public function pointDouble($user_id,$integral){
+
+ $arr['double'] = 1;
+
+ $arr['integral'] = $integral;
+
+ if($integral<0){
+
+ return $arr;
+ }
+
+ $user_model = new User();
+
+ $member_level = $user_model->where(['id'=>$user_id])->value('member_level');
+
+
+ if(empty($member_level)){
+
+ return $arr;
+ }
+
+ $level_model = new Level();
+
+ $level = $level_model->levelInfo(['id'=>$member_level]);
+
+ if(empty($level)){
+
+ return $arr;
+ }
+
+ if(empty($level['integral_switch'])){
+
+ return $arr;
+
+ }
+
+ $arr['double'] = $level['integral'];
+
+ $arr['integral'] = floor($level['integral']*$integral);
+
+ return $arr;
+
+
+ }
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-12 14:05
+ * @功能说明:单天获得积分
+ */
+ public function dayGetIntegral($user_id,$integral,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ if($config['integral_limit']==0){
+
+ return $integral;
+ }
+
+ $dis[] = ['user_id','=',$user_id];
+
+ $dis[] = ['integral_add','>',0];
+
+ $dis[] = ['type','not in',[5,6,7]];
+ //单日获取积分
+ $integral_day = $this->where($dis)->whereDay('create_time')->sum('integral_add');
+ //单日可获取最大积分
+ $integral_day_max = $config['integral_day_max'];
+
+ $point = $integral_day_max-$integral_day;
+
+ if($point<=0){
+
+ return 0;
+ }
+
+ $point = $point-$integral>0?$integral:$point;
+
+ return $point;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 10:21
+ * @功能说明:每日领取的积分
+ */
+ public function dayIntegral($user_id,$uniacid){
+
+ $config_model = new Config();
+
+ $config = $config_model->configInfo(['uniacid'=>$uniacid]);
+
+ if($config['integral_limit']==1){
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'refund' => 0,
+
+ 'type' => 1
+ ];
+
+ $integral = $this->where($dis)->where('status','>',0)->whereDay('create_time')->sum('integral_add');
+
+ $re_integral = $config['integral_day_max'] - $integral;
+
+ $re_integral = $re_integral>0?$re_integral:0;
+
+ return intval($re_integral);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-08-04 11:07
+ * @功能说明:给用户加积分
+ */
+ public function incUserIntegral($order_id,$user_id,$uniacid){
+
+ $dis = [
+
+ 'order_id' => $order_id,
+
+ 'status' => 1
+ ];
+
+ $info = $this->where($dis)->select()->toArray();
+
+ $member_model = new Member();
+
+ if(!empty($info)){
+
+ foreach ($info as $value){
+
+ $integral = $value['integral_add'];
+
+ $member_info = $member_model->getMemberInfo(['user_id'=>$user_id,'uniacid'=>$uniacid]);
+
+ $update = [
+ //修改状态
+ 'status' => 2,
+ //当前
+ 'integral_before' => intval($member_info['integral']),
+ //修改后对
+ 'integral_after' => intval($member_info['integral']+$integral),
+
+ ];
+
+ $this->integralUpdate(['id'=>$value['id']],$update);
+
+ if(is_numeric($integral)&&$integral>0){
+
+ $dis = [
+
+ 'user_id' => $user_id
+
+ ];
+
+ $member_model->incDecGrowth($dis,$integral,'integral');
+
+ }
+
+ }
+
+ }
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/IntegralStore.php b/app/shop/model/IntegralStore.php
new file mode 100755
index 0000000..dea4612
--- /dev/null
+++ b/app/shop/model/IntegralStore.php
@@ -0,0 +1,78 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/LuckConfig.php b/app/shop/model/LuckConfig.php
new file mode 100755
index 0000000..a70e1fa
--- /dev/null
+++ b/app/shop/model/LuckConfig.php
@@ -0,0 +1,183 @@
+where(['id'=>$data['coupon_id']])->value('title');
+
+ return $title;
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(isset($data['data'])){
+
+ $arr = $data['data'];
+
+ unset($data['data']);
+ }
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($arr)){
+
+ $this->updateSome($id,$arr,$data['uniacid']);
+
+ }
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:24
+ * @功能说明:添加奖品信息
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $config_model = new LuckConfig();
+
+ $arr = [];
+
+// $config_model->where(['luck_id'=>$id])->delete();
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $v['uniacid'] = $uniacid;
+
+ $v['luck_id'] = $id;
+
+ if(empty($v['id'])){
+
+ $config_model->insert($v);
+
+ $arr[] = $v['id'];
+
+ }else{
+
+ $config_model->dataUpdate(['id'=>$v['id']],$v);
+
+ $arr[] = $config_model->getLastInsID();
+
+ }
+
+ $config_model->save($v);
+
+
+ }
+
+ }
+
+ $config_model->where(['luck_id'=>$id])->where('id','not in',$arr)->delete();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['data'])){
+
+ $arr = $data['data'];
+
+ unset($data['data']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($arr)){
+
+ $this->updateSome($dis['id'],$arr,$data['uniacid']);
+
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/LuckDraw.php b/app/shop/model/LuckDraw.php
new file mode 100755
index 0000000..574595c
--- /dev/null
+++ b/app/shop/model/LuckDraw.php
@@ -0,0 +1,463 @@
+where(['luck_id'=>$data['id'],'is_luck'=>1])->order('top,id desc')->select()->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(isset($data['data'])){
+
+ $arr = $data['data'];
+
+ unset($data['data']);
+ }
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($arr)){
+
+ $this->updateSome($id,$arr,$data['uniacid']);
+
+ }
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:24
+ * @功能说明:添加奖品信息
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $config_model = new LuckConfig();
+
+ $list = $this->changeData($data,$uniacid,$id);
+
+ $data = array_merge($data,$list);
+
+ $ids = array_column($data,'id');
+
+ $config_model->where(['luck_id'=>$id])->where('id','not in',$ids)->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $v['uniacid'] = $uniacid;
+
+ $v['luck_id'] = $id;
+
+ if(!empty($v['id'])){
+
+ $config_model->dataUpdate(['id'=>$v['id']],$v);
+
+ }else{
+
+ $config_model->insert($v);
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-26 14:50
+ * @功能说明:
+ */
+ public function changeData($data,$uniacid,$id){
+
+ $blance = array_sum(array_column($data,'balance'));
+
+ $no_balance = 100-$blance;
+
+ $no_balance = $no_balance>0?ceil($no_balance/count($data)):0;
+
+ for ($i=1;$i<=9;$i++){
+
+ if(!in_array($i,array_column($data,'top'))){
+
+ $arr[] = $i;
+ }
+
+ }
+
+ if(!empty($arr)){
+
+ foreach ($arr as $key=> $value){
+
+ $list[$key] = [
+
+ 'uniacid' => $uniacid,
+
+ 'top' => $value,
+
+ 'title' => '谢谢参与',
+
+ 'is_luck' => 0,
+
+ 'balance' => $no_balance,
+
+ 'luck_id' => $id,
+
+ 'num' => 1
+ ];
+
+ }
+ }
+
+ return !empty($list)?$list:[];
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(isset($data['data'])){
+
+ $arr = $data['data'];
+
+ unset($data['data']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($arr)){
+
+ $this->updateSome($dis['id'],$arr,$data['uniacid']);
+
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $arr
+ * @功能说明:抽奖算法
+ * 根据概率随机中奖
+ *
+ * @author chenniang
+ * @DataTime: 2022-07-26 14:40
+ */
+ public function getRand($data){
+
+ foreach ($data as $k=>$v){
+
+ $arr[$v['id']] = $v['balance'];
+ }
+
+ $sum = array_sum($arr);
+
+ $res = 0;
+
+ foreach ($arr as $key=>$value){
+
+ $rand_num = mt_rand(1,$sum);
+
+ if($rand_num<=$value){
+
+ $res = $key;
+
+ break;
+ }else{
+
+ $sum -= $value;
+ }
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:54
+ * @功能说明:初始化活动时间
+ */
+ public function initAtv(){
+
+ $this->where('start_time','>',time())->update(['atv_status'=>1]);
+
+ $this->where('start_time','<',time())->update(['atv_status'=>2]);
+
+ $this->where('end_time','<',time())->update(['atv_status'=>3]);
+
+ return true;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-26 15:04
+ * @功能说明:用户抽奖
+ */
+ public function luckDraw($atv_id,$user_id,$use_integral,$user_num=0){
+
+ $config_model = new LuckConfig();
+ //获取未中奖的奖项
+ $list = $config_model->where(['luck_id'=>$atv_id])->where('num','>',0)->order('top,id desc')->select()->toArray();
+
+ if(empty($list)){
+
+ return ['code'=>500,'msg'=>'所有奖已被抽完'];
+ }
+
+ $id = $this->getRand($list);
+
+ $data = $config_model->dataInfo(['id'=>$id]);
+
+ $data['times'] = $user_num+1;
+
+ if(empty($data)||($data['is_luck']==1&&$data['num']<=0)){
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+ }
+
+ Db::startTrans();
+ //如果中奖需减数量
+ if($data['is_luck']==1){
+
+ $res = $config_model->dataUpdate(['id'=>$id,'num'=>$data['num']],['num'=>$data['num']-1]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+ }
+ }
+ //添加中奖记录
+ $insert = [
+
+ 'uniacid' => $data['uniacid'],
+
+ 'user_id' => $user_id,
+
+ 'atv_id' => $atv_id,
+
+ 'type' => $data['type'],
+
+ 'coupon_id' => $data['coupon_id'],
+
+ 'integral' => $data['integral'],
+
+ 'icon' => $data['icon'],
+
+ 'title' => $data['title'],
+
+ 'is_luck' => $data['is_luck'],
+
+ 'use_integral' => $use_integral,
+
+ ];
+
+ $record_model = new LuckRecord();
+
+ $i_model = new IntegralLog();
+
+ $res = $record_model->dataAdd($insert);
+
+ if($res==0){
+
+ Db::rollback();
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+
+ }
+ $record_id = $record_model->getLastInsID();
+
+ if($data['is_luck']==1){
+ //卡券
+ if($data['type']==1){
+
+ $coupon_model = new Coupon();
+
+ $coupon = $coupon_model->dataInfo(['id'=>$data['coupon_id'],'status'=>1]);
+
+ if(empty($coupon)){
+
+ Db::rollback();
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+ }
+
+ $coupon_model = new \app\farm\model\CouponRecord();
+
+ $res = $coupon_model->recordAdd($data['coupon_id'],$user_id);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+ }
+
+ }else{
+ //积分
+ $res = $i_model->integralUserAdd($user_id,$data['integral'],$data['uniacid'],2,14,$record_id,0,$data);
+
+ if($res==false){
+
+ Db::rollback();
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+ }
+ }
+ }
+ //积分
+ $res = $i_model->integralUserAdd($user_id,$use_integral*-1,$data['uniacid'],2,11,$record_id,0,$data);
+
+ if($res==false){
+
+ Db::rollback();
+
+ $this->luckDraw($atv_id,$user_id,$use_integral);
+ }
+
+ Db::commit();
+
+ return $data;
+ }
+
+
+ /**
+ * @param $input
+ * @功能说明:校验时间 统一时间段只能有一个活动
+ * @author chenniang
+ * @DataTime: 2022-08-26 13:46
+ */
+ public function checkTime($input){
+
+ if(!empty($input['start_time'])){
+
+ $dis[] = ['uniacid','=',$input['uniacid']];
+
+ $dis[] = ['status','>',-1];
+
+ if(!empty($input['id'])){
+
+ $dis[] = ['id','<>',$input['id']];
+ }
+
+ $data = $this->where($dis)->select()->toArray();
+
+ if(!empty($data)){
+
+ foreach ($data as $value){
+
+ $res = is_time_cross($input['start_time'],$input['end_time'],$value['start_time'],$value['end_time']);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'该时间段已经有该活动,活动名称:'.$value['title']];
+ }
+
+ }
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/LuckRecord.php b/app/shop/model/LuckRecord.php
new file mode 100755
index 0000000..40a6fea
--- /dev/null
+++ b/app/shop/model/LuckRecord.php
@@ -0,0 +1,152 @@
+where(['id'=>$data['coupon_id']])->value('title');
+
+ return $title;
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-15 14:24
+ * @功能说明:添加奖品信息
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $config_model = new LuckConfig();
+
+ $config_model->where(['luck_id'=>$id])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $v['uniacid'] = $uniacid;
+
+ $v['luck_id'] = $id;
+
+ $config_model->insert($v);
+
+ }
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-26 16:14
+ * @功能说明:中奖记录
+ */
+ public function recordList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_user_list b','a.user_id = b.id','left')
+ ->where($dis)
+ ->field('a.*,b.nickName,b.avatarurl')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/Member.php b/app/shop/model/Member.php
new file mode 100755
index 0000000..592886d
--- /dev/null
+++ b/app/shop/model/Member.php
@@ -0,0 +1,81 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/SeckillConfig.php b/app/shop/model/SeckillConfig.php
new file mode 100755
index 0000000..d95d07c
--- /dev/null
+++ b/app/shop/model/SeckillConfig.php
@@ -0,0 +1,108 @@
+dataInfo(['id'=>$data['spe_id']]);
+
+ if(!empty($info)){
+
+ return $info['spe_name_text'];
+ }
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/SeckillGoods.php b/app/shop/model/SeckillGoods.php
new file mode 100755
index 0000000..9f99c1e
--- /dev/null
+++ b/app/shop/model/SeckillGoods.php
@@ -0,0 +1,321 @@
+where(['atv_id'=>$data['id']])->sum('stock');
+
+ return $num;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 18:50
+ * @功能说明:总的库存
+ */
+ public function getAllHaveStockAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $i_model = new SeckillConfig();
+
+ $num = $i_model->where(['atv_id'=>$data['id']])->sum('have_stock');
+
+ return $num;
+ }
+
+ }
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-21 18:29
+ */
+ public function getGoodsInfoAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $config_model = new SeckillConfig();
+
+ $list = $config_model->alias('a')
+ ->join('lbfarm_v2_shop_spe_price b','a.spe_id = b.id')
+ ->where(['a.atv_id' => $data['id']])
+ ->field(['b.stock as goods_stock','b.price as goods_price','a.*'])
+ ->select()
+ ->toArray();
+ return $list;
+
+ }
+
+ }
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-21 14:19
+ */
+ public function getShowDataAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $config_model = new SeckillConfig();
+
+ $spe_model = new GoodsSpePrice();
+
+ $info = $config_model->where(['atv_id'=>$data['id']])->order('price')->find();
+
+ if(!empty($info)){
+
+ $info = $info->toArray();
+
+ $info['init_price'] = $spe_model->where(['id'=>$info['spe_id']])->value('price');
+
+ }
+
+ return $info;
+
+ }
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @功能说明:商品列表
+ * @author chenniang
+ * @DataTime: 2022-07-25 14:59
+ */
+ public function goodsList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_goods b','a.goods_id = b.id')
+ ->join('lbfarm_v2_goods_store c','c.goods_id = b.id AND c.type=1')
+ ->join('lbfarm_farmer d','c.store_id = d.id')
+ ->join('lbfarm_v2_seckill_list e','a.atv_id = e.id')
+ ->where($dis)
+ ->field('a.*,b.goods_name,b.cover,d.title as store_name,d.id as store_id,d.cover as store_cover')
+ ->group('a.id')
+ ->order('b.top desc,a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 17:19
+ * @功能说明:增加销量
+ */
+ public function delAtvStock($atv_id,$goods_id,$spe_id,$num){
+
+ $config_model = new SeckillConfig();
+
+ $dis = [
+
+ 'a.atv_id' => $atv_id,
+
+ 'a.goods_id'=> $goods_id,
+
+ 'b.spe_id' => $spe_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_seckill_config b','a.id = b.atv_id')
+ ->where($dis)
+ ->field('b.*')
+ ->find();
+
+ if(empty($data)){
+
+ return ['code'=>500,'msg'=>'该活动已经下架'];
+ }
+
+ $data = $data->toArray();
+
+ if($data['have_stock']+$num>$data['stock']){
+
+ return ['code'=>500,'msg'=>'可兑换数量不足'];
+
+ }
+
+ $res = $config_model->where(['id'=>$data['id']])->update(['have_stock'=> Db::Raw("have_stock+$num")]);
+
+ return $res;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-25 17:19
+ * @功能说明:减少销量
+ */
+ public function incAtvStock($atv_id,$goods_id,$spe_id,$num){
+
+ $config_model = new SeckillConfig();
+
+ $dis = [
+
+ 'a.atv_id' => $atv_id,
+
+ 'a.goods_id'=> $goods_id,
+
+ 'b.spe_id' => $spe_id
+ ];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_seckill_config b','a.id = b.atv_id')
+ ->where($dis)
+ ->field('b.*')
+ ->find();
+
+ if(empty($data)){
+
+ return true;
+ }
+
+ $data = $data->toArray();
+
+ $res = $config_model->where(['id'=>$data['id']])->update(['have_stock'=> Db::Raw("have_stock-$num")]);
+
+ return $res;
+ }
+
+
+ /**
+ * @param $atv_id
+ * @param $goods_id
+ * @param $spe_id
+ * @param $num
+ * @param int $type
+ * @功能说明:修改活动销量
+ * @author chenniang
+ * @DataTime: 2022-07-25 17:47
+ */
+ public function updateAtvStock($atv_id,$goods_id,$spe_id,$num,$type=1){
+
+ if($type==1){
+
+ $res = $this->delAtvStock($atv_id,$goods_id,$spe_id,$num);
+
+ }else{
+
+ $res = $this->incAtvStock($atv_id,$goods_id,$spe_id,$num);
+
+ }
+
+ return $res;
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/SeckillInfo.php b/app/shop/model/SeckillInfo.php
new file mode 100755
index 0000000..e4ba708
--- /dev/null
+++ b/app/shop/model/SeckillInfo.php
@@ -0,0 +1,125 @@
+alias('a')
+ ->join('lbfarm_v2_seckill_list b','a.kill_id = b.id')
+ ->join('lbfarm_v2_seckill_goods c','c.atv_id = b.id')
+ ->where($dis)
+ ->field('a.*')
+ ->group('a.id')
+ ->select()
+ ->toArray();
+
+ if(!empty($data)){
+
+ $push_model = new PushMsgModel($uniacid);
+
+ foreach ($data as $v){
+
+ $this->dataUpdate(['id'=>$v['id']],['status'=>2]);
+
+ $v['id'] = $v['goods_id'];
+
+ $push_model->sendMsg($v,15);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/SeckillList.php b/app/shop/model/SeckillList.php
new file mode 100755
index 0000000..dc1a94f
--- /dev/null
+++ b/app/shop/model/SeckillList.php
@@ -0,0 +1,374 @@
+',-1];
+
+ if(!empty($input['id'])){
+
+ $dis[] = ['id','<>',$input['id']];
+
+ }
+
+ $list = $this->where($dis)->select()->toArray();
+
+ if(!empty($list)){
+
+ foreach ($list as $value){
+
+ $res = is_time_cross($input['start_time'],$input['end_time'],$value['start_time'],$value['end_time']);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'该时间段已经有该活动,活动名称:'.$value['title']];
+ }
+
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $uniacid
+ * @param $config
+ * @param $store
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-15 16:11
+ */
+ public function updateSome($id,$uniacid,$spe,$goods_id){
+
+ $config_model = new SeckillConfig();
+
+ $goods_model = new SeckillGoods();
+
+ $insert = [
+
+ 'uniacid' => $uniacid,
+
+ 'atv_id' => $id,
+
+ 'goods_id'=> $goods_id
+ ];
+
+ $find = $goods_model->dataInfo($insert);
+
+ if(empty($find)){
+
+ $goods_model->dataAdd($insert);
+
+ $atv_id = $goods_model->getLastInsID();
+
+ }else{
+
+ $atv_id = $find['id'];
+
+ }
+
+ if(!empty($spe)){
+
+ foreach ($spe as $value){
+
+ $i_dis = [
+
+ 'atv_id' => $id,
+
+ 'goods_id'=> $goods_id,
+
+ 'spe_id' => $value['spe_id'],
+ ];
+
+ $have_stock = $config_model->where($i_dis)->sum('have_stock');
+
+ $value['uniacid'] = $uniacid;
+
+ $value['atv_id'] = $atv_id;
+
+ $value['have_stock'] = $have_stock;
+
+ $config_model->insert($value);
+
+ $arr[] = $config_model->getLastInsID();
+ }
+
+ }
+
+ $config_model->where(['atv_id'=>$atv_id])->where('id','not in',$arr)->delete();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-10-29 13:54
+ * @功能说明:初始化活动时间
+ */
+ public function initAtv(){
+
+ $this->where('start_time','>',time())->update(['atv_status'=>1]);
+
+ $this->where('start_time','<',time())->update(['atv_status'=>2]);
+
+ $this->where('end_time','<',time())->update(['atv_status'=>3]);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-01 10:18
+ * @功能说明:正在进行中的活动
+ */
+ public function atvIng($goods_id,$spe_id=0,$type=1){
+
+ $this->initAtv();
+
+ if($type==1){
+
+ $dis[] = ['a.atv_status','=',2];
+
+ }else{
+
+ $dis[] = ['a.atv_status','in',[1,2]];
+
+ }
+
+ $dis[] = ['b.goods_id','=',$goods_id];
+
+ $dis[] = ['a.status','=',1];
+
+ if(!empty($spe_id)){
+
+ $dis[] = ['c.spe_id','=',$spe_id];
+ }
+
+// $dis[] = ['c.store_id','=',$store_id];
+//
+// $dis[] = ['c.type','=',6];
+
+ $data = $this->alias('a')
+ ->join('lbfarm_v2_seckill_goods b','a.id = b.atv_id')
+ ->join('lbfarm_v2_seckill_config c','b.id = c.atv_id')
+ // ->join('lbfarm_v2_goods_store c','a.id = c.goods_id')
+ ->where($dis)
+ ->field('b.*,a.*,c.price,c.spe_id,c.stock,c.have_stock,a.id as kill_atv_id')
+ ->order('c.price')
+ ->find();
+
+ if(!empty($data)){
+
+ $data = $data->toArray();
+ //减去已经销售的
+ $data['stock'] = ($data['stock'] - $data['have_stock'])>0?$data['stock'] - $data['have_stock']:0;
+
+ $spe_model = new GoodsSpePrice();
+
+ $data['init_price'] = $spe_model->where(['id'=>$data['spe_id']])->value('price');
+
+ }
+
+ return $data;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-04 14:41
+ * @功能说明:获取是否
+ */
+ public function getBuyLimit($list,$store_id=0){
+
+ foreach ($list as $value){
+
+ $res = $this->atvIng($value['goods_id'],$value['spe_id']);
+
+ if(!empty($res)){
+
+ return 1;
+
+ }
+
+ }
+
+ return 0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-28 15:58
+ * @功能说明:校验用户是否可以参加秒杀
+ */
+ public function userCheck($user_id,$atv_id,$is_show){
+
+ if(empty($atv_id)){
+
+ return true;
+ }
+
+ if(!empty($atv_id)&&$is_show!=2){
+
+ return ['code'=>500,'msg'=>'秒杀商品不能从购物车下单哦'];
+ }
+
+ $atv = $this->dataInfo(['id'=>$atv_id]);
+
+ if(empty($atv)){
+
+ return ['code'=>500,'msg'=>'秒杀活动已结束'];
+
+ }
+
+ if($atv['is_limit']==1){
+
+ $num = $this->getAtvNum($atv_id,$user_id);
+
+ if($num>=$atv['limit_num']){
+
+ return ['code'=>500,'msg'=>'超过秒杀次数'];
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @return float
+ * 获取历史商品件数
+ */
+ public function getAtvNum($id,$user_id){
+
+ $dis = [
+
+ 'b.kill_atv_id' => $id,
+
+ 'b.user_id' => $user_id
+
+ ];
+
+ $order_model = new \app\farm\model\ShopOrderGoods();
+ //取消订单的不算 chen
+ $num = $order_model->alias('a')
+ ->join('lbfarm_shop_order b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->group('a.id')
+ ->sum('a.goods_num');
+
+
+ $order_id = $order_model->alias('a')
+ ->join('lbfarm_shop_order b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->column('b.id');
+
+ $order_refund_goods = new \app\farm\model\ShopRefundGoods();
+ //申请退款成功的
+ $refund_num = $order_refund_goods->where('order_id','in',$order_id)->where(['status'=>2])->sum('goods_num');
+
+ return $num - $refund_num;
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/ShopGoodsCate.php b/app/shop/model/ShopGoodsCate.php
new file mode 100755
index 0000000..c1772b5
--- /dev/null
+++ b/app/shop/model/ShopGoodsCate.php
@@ -0,0 +1,206 @@
+ 2,
+
+ 'a.goods_id' => $data['id'],
+
+ 'a.type' => 2
+ ];
+
+ $store_goods_model = new StoreGoods();
+
+ $list = $store_goods_model->alias('a')
+ ->join('lbfarm_farmer b','a.store_id = b.id')
+ ->where($dis)
+ ->field('a.*,b.title')
+ ->group('a.id')
+ ->order('a.id dsec')
+ ->column('b.id');
+
+ return array_values($list);
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-23 13:46
+ * @功能说明:分类下面端商品数量
+ */
+ public function getGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $goods_model = new ShopGoods();
+
+ $num = $goods_model->where(['cate_id'=>$data['id']])->where('status','>',-1)->count();
+
+ return $num;
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ if(!empty($data['store'])){
+
+ $store = $data['store'];
+
+ unset($data['store']);
+ }
+
+ $res = $this->insert($data);
+
+ $id = $this->getLastInsID();
+
+ if(isset($store)){
+
+ $this->updateSome($id,$store,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @param $id
+ * @param $data
+ * @param $uniacid
+ * @功能说明:
+ * @author chenniang
+ * @DataTime: 2022-07-04 14:47
+ */
+ public function updateSome($id,$data,$uniacid){
+
+ $store_goods_model = new StoreGoods();
+
+ $store_goods_model->where(['goods_id'=>$id,'type'=>2])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $uniacid,
+
+ 'store_id'=> $v,
+
+ 'goods_id'=> $id,
+
+ 'type' => 2
+ ];
+
+ }
+
+ $store_goods_model->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ if(!empty($data['store'])){
+
+ $store = $data['store'];
+
+ unset($data['store']);
+ }
+
+ $res = $this->where($dis)->update($data);
+
+ if(isset($store)){
+
+ $this->updateSome($dis['id'],$store,$data['uniacid']);
+ }
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/ShopGoodsSpe.php b/app/shop/model/ShopGoodsSpe.php
new file mode 100755
index 0000000..dd732f7
--- /dev/null
+++ b/app/shop/model/ShopGoodsSpe.php
@@ -0,0 +1,135 @@
+where($dis)->select()->toArray();
+ return $this->getTree($data,0);
+ }
+ /**
+ * @param $data
+ * @param $pId
+ * @return array
+ * 递归无限极
+ */
+ public function getTree($data, $pId){
+ $tree = array();
+ if(!empty($data)){
+ foreach($data as $k => $v) {
+ if($v['pid'] == $pId) {
+ $v['cate'] = $this->getTree($data, $v['id']);
+ $tree[] = $v;
+ }
+ }
+ }
+ return $tree;
+ }
+
+ /**
+ * @param $data
+ * @return int|string
+ * 添加商品规格
+ */
+
+ public function goodsSpeAdd($data){
+ $data['create_time'] = time();
+ $data['status'] = 1;
+ $res = $this->insert($data);
+ $res = $this->getLastInsID();
+ return $res;
+ }
+
+ /**
+ * @param $data
+ * @return int|string
+ * 添加商品规格
+ */
+
+ public function goodsSpeUpdate($dis,$data){
+ $data['update_time'] = time();
+ $res = $this->where($dis)->update($data);
+ return $res;
+ }
+
+ /**
+ * @param $dis
+ * 根据条件获取id
+ */
+
+ public function goodsSpeId($dis){
+ $data = $this->where($dis)->column('id');
+ return $data;
+ }
+
+
+ /**
+ * @param $dis
+ * @return array|\think\Model|null
+ * @throws \think\exception\DbException
+ * 获取一个
+ */
+ public function getSinge($dis){
+ $data = $this->where($dis)->find();
+ return !empty($data)?$data->toArray():$data;
+
+ }
+
+ /**
+ * @param $dis
+ * @param int $page
+ * @return mixed
+ * 获取多规格
+ */
+ public function goodsSpeNot($dis,$data){
+ $data = $this->where($dis)->where('pid','not in',$data)->select()->toArray();
+ return $data;
+ }
+
+ /**
+ * @param $dis
+ * 获取多规格的pid
+ */
+ public function goodSpePid($dis){
+ $data = $this->where($dis)->value('pid');
+ return $data;
+
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/ShopOrder.php b/app/shop/model/ShopOrder.php
new file mode 100755
index 0000000..b046bb8
--- /dev/null
+++ b/app/shop/model/ShopOrder.php
@@ -0,0 +1,1142 @@
+dataInfo(['id'=>$data['store_id'],'type'=>2]);
+
+ return $info;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 17:38
+ * @功能说明:
+ */
+ public function getFarmerInfoAttr($value,$data){
+
+ if(!empty($data['farmer_id'])){
+
+ $farmer_model= new Farmer();
+
+ $info = $farmer_model->dataInfo(['id'=>$data['farmer_id'],'type'=>1]);
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-10 17:08
+ * @功能说明:核销人
+ */
+ public function getHxUserNameAttr($value,$data){
+
+ if(isset($data['hx_user'])){
+
+ if(!empty($data['hx_user'])){
+
+ $user_model = new User();
+
+ $name = $user_model->where(['id'=>$data['hx_user']])->value('nickName');
+
+ return $name;
+
+ }else{
+
+ return '自动收货';
+ }
+
+ }
+
+ }
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:地址信息
+ * @author chenniang
+ * @DataTime: 2021-04-08 10:11
+ */
+ public function getAddressInfoAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $address_model = new OrderAddress();
+
+ $address_info = $address_model->dataInfo(['order_id'=>$data['id'],'type'=>5]);
+
+ return $address_info;
+ }
+
+
+ }
+
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总商品数量
+ * @author chenniang
+ * @DataTime: 2021-03-25 14:39
+ */
+ public function getAllGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $dis = [
+
+ 'order_id' => $data['id']
+ ];
+
+ $num = $order_goods_model->where($dis)->sum('goods_num');
+
+ return $num;
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:05
+ * @功能说明:子订单信息
+ */
+
+ public function getOrderGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $dis = [
+
+ 'order_id' => $data['id']
+ ];
+
+ $list = $order_goods_model->where($dis)->select()->toArray();
+
+ return $list;
+
+ }
+
+ }
+
+
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-25 17:40
+ * @功能说明:生产二维码
+ */
+ public function getQrAttr($value,$data){
+
+ if(!empty($value)){
+
+ return $value;
+ }
+
+ if(!empty($data['pay_type'])&&$data['pay_type']>1&&!empty($data['id'])&&!empty($data['uniacid'])){
+
+ $qr_insert = [
+
+ 'id' => $data['id']
+ ];
+
+ $qr = $this->orderQr($qr_insert,$data['uniacid']);
+
+ if(!empty($qr)){
+
+ $this->dataUpdate(['id'=>$data['id']],['qr'=>$qr]);
+
+ return $qr;
+ }
+
+ return '';
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-10-27 15:42
+ * @功能说明:订单自提码
+ */
+ public function orderQr($input,$uniacid){
+
+ $data = longbingCreateWxCode($uniacid,$input,'shop/pages/order/hexiao');
+
+ $data = transImagesOne($data ,['qr_path'] ,$uniacid);
+
+ $qr = $data['qr_path'];
+
+ return $qr;
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 16:23
+ * @功能说明:前端订单列表
+ */
+
+ public function indexDataList($dis,$mapor,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods b','a.id = b.order_id')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods c','a.id = c.order_id')
+ ->join('lbfarm_order_address d','a.id = d.order_id AND d.type=5')
+ ->where($dis)
+ ->field('a.*,d.mobile,d.user_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataSelect($dis){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_order_goods c','a.id = c.order_id')
+ ->join('lbfarm_order_address d','a.id = d.order_id AND d.type=5')
+ ->where($dis)
+ ->field('a.*,d.mobile,d.user_name')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->select()
+ ->toArray();
+
+ if(!empty($data)){
+
+ $user_model = new User();
+
+ foreach ($data as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 14:33
+ * @功能说明:
+ */
+ public function datePrice($date,$uniacid,$cap_id=0,$end_time = '',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['transaction_id','<>',''];
+
+ $dis[] = ['auto_refund','=',0];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('pay_price');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 09:28
+ * @功能说明:计算用户下单时候的各类金额
+ */
+ public function payOrderInfo($user_id,$store_id,$coupon=0,$address_id=0,$is_show=1,$send_type=2){
+
+ $car_model = new Car();
+ //获取购物车里面的信息
+ $car_list = $car_model->carPriceAndCount($user_id,$store_id,0,$is_show);
+
+ $coupon_model = new Coupon();
+
+ $car_list = $coupon_model->orderCouponData($car_list,$coupon,2);
+
+ $address_model = new Address();
+
+ $config_model = new Config();
+
+ $address = $address_model->dataInfo(['id'=>$address_id]);
+
+ if(!empty($car_list['list'])){
+
+ foreach ($car_list['list'] as &$value){
+
+ if(!empty($address_id)&&$send_type==2){
+
+ $distance = getdistance($value['farmer_info']['lng'],$value['farmer_info']['lat'],$address['lng'],$address['lat']);
+
+ $value['distance'] = $distance;
+ //计算运费
+ $value['freight'] = $config_model->getSendPrice(round($distance/1000,2),$value['farmer_info']['uniacid']);
+
+ }else{
+
+ $value['distance'] = 0;
+
+ }
+
+ $value['distance_text'] = distance_text($value['distance']);
+ //商品总价格
+ $value['goods_price'] = round($value['car_price']-$value['coupon_discount'],2);
+ //订单支付价
+ $value['pay_price'] = round($value['goods_price']+$value['freight'] ,2);
+
+ $value['init_goods_price'] = round($value['init_price'] ,2);
+ //订单总价格
+ $value['init_price'] = round($value['init_price']+$value['freight'] ,2);
+
+ }
+ }
+
+ $coupon = !empty($car_list['car_price'])?$coupon:0;
+
+ $data['coupon_id'] = $coupon;
+ //购物车列表
+ $data['order_goods'] = $car_list['list'];
+ //商品总价格
+ $data['coupon_discount'] = round(array_sum(array_column($car_list['list'],'coupon_discount')),2);
+
+ $data['goods_price'] = round(array_sum(array_column($car_list['list'],'goods_price')),2);
+
+ $data['init_price'] = round(array_sum(array_column($car_list['list'],'init_price')),2);
+
+ $data['init_goods_price'] = round(array_sum(array_column($car_list['list'],'init_goods_price')),2);
+
+ $data['pay_price'] = round(array_sum(array_column($car_list['list'],'pay_price')),2);
+
+ $data['freight'] = round(array_sum(array_column($car_list['list'],'freight')),2);
+
+ $data['car_count'] = $car_list['car_count'];
+
+ return $data;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:31
+ * @功能说明:订单支付回调
+ */
+ public function orderResult($order_code,$transaction_id){
+
+ $order_list = $this->whereOr(['top_order_code'=>$order_code,'order_code'=>$order_code])->select()->toArray();
+
+ if(!empty($order_list)){
+
+ foreach ($order_list as $order){
+
+ if(!empty($order)&&$order['pay_type']==1){
+
+ Db::startTrans();
+
+ $update = [
+
+ 'transaction_id' => $transaction_id,
+
+ 'pay_type' => 2,
+
+ 'pay_time' => time(),
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$order['id']],$update);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return false;
+
+ }
+ //扣除余额
+ if($order['balance']>0){
+
+ $water_model = new BalanceWater();
+
+ $res = $water_model->addWater($order,7,0);
+
+ if($res==0){
+
+ Db::rollback();
+
+ }
+ }
+ //添加流水
+ $water_model = new FinanceWater();
+
+ $water_model->addWater($order['id'],8,2,0);
+ //商城订单农场主获得运费
+ $water_model->addWater($order['id'],16,1,0);
+
+ Db::commit();
+ //发送订阅消息
+ $order['pay_time'] = $update['pay_time'];
+
+ $this->paySendService($order);
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发送订阅消息
+ */
+ public function sendOrderService($order){
+ //获取用户的open_id
+ $user_model = new User();
+
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'shop/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where([['uniacid','=',$order['uniacid']],['tmpl_name','=','send_order'],['tmpl_id','<>',0]])->find();
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+
+ return true;
+
+ }else{
+
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+// //模版类容
+// $key_worlds = $tmpl['kidList'];
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+ return true;
+ }
+ $order['express_company'] = $service_model::strToUtf8($order['express_company']);
+ //发送内容
+ $send_data = array(
+ $key_worlds[1]=>array(
+ //发货时间物流公司
+ 'value'=>date('Y-m-d H:i:s',$order['send_time']),
+ ),
+ $key_worlds[2]=>array(
+ //订单编号
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[3]=>array(
+ //物流编号
+ 'value'=>$order['express_code'],
+ ),
+ $key_worlds[4]=>array(
+ //
+ 'value'=>$order['express_company'],
+ )
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+ }
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发送订阅消息
+ */
+ public function paySendService($order){
+
+ $user_model = new User();
+ //获取用户的open_id
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'shop/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$order['uniacid'],'tmpl_name'=>'pay_order'])->find();
+
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+ return true;
+ }else{
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+// //模版类容
+// $key_worlds = $tmpl['kidList'];
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+
+ return true;
+ }
+
+ $goods_names = implode(',',array_column($order['order_goods'],'goods_name'));
+
+// $goods_name = msubstr($goods_names,0,18);
+ $goods_name = mb_substr($goods_names,0,18);
+ //发送内容
+ $send_data = array(
+
+ $key_worlds[1]=>array(
+ //商品名称
+ 'value'=> $goods_name,
+ //'value'=>'圣女果小番茄--物流、自提,圣女果小番茄圣女果小番茄',
+ ),
+ $key_worlds[2]=>array(
+ //商品价格
+ 'value'=>$order['pay_price'].'元',
+ ),
+ $key_worlds[3]=>array(
+ //支付金额
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[4]=>array(
+ //支付时间
+ 'value'=>date('Y-m-d H:i:s',$order['pay_time']),
+ ),
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+
+ return true;
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:31
+ * @功能说明:团长冻结资金
+ */
+ public function capFrozenPrice($cap_id,$total=0,$toDay=0){
+
+ $dis[] = ['cap_id','=',$cap_id];
+
+ if($total==0){
+
+ $dis[] = ['have_tx','=',0];
+ }
+
+ $dis[] = ['pay_type','>',1];
+
+ if($toDay==1){
+ //当日
+ $price = $this->where($dis)->whereDay('create_time')->sum('cap_price');
+
+ }else{
+
+ $price = $this->where($dis)->sum('cap_price');
+
+ }
+
+ return round($price,2);
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:31
+ * @功能说明:团长冻结资金
+ */
+ public function capFrozenCount($cap_id,$total=0,$toDay=0){
+
+ $dis[] = ['cap_id','=',$cap_id];
+
+ if($total==0){
+
+ $dis[] = ['have_tx','=',0];
+ }
+
+ $dis[] = ['pay_type','>',1];
+
+ if($toDay==1){
+ //当日
+ $price = $this->where($dis)->whereDay('create_time')->count();
+
+ }else{
+
+ $price = $this->where($dis)->count();
+
+ }
+
+ return $price;
+
+ }
+
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 15:41
+ * @功能说明:团长佣金到账
+ */
+ public function capArrPrice($uniacid,$user_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',7];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $dis[] = ['have_tx','=',0];
+
+ $dis[] = ['can_refund_time','<',time()];
+
+ $order = $this->where($dis)->field('id,get_integral,user_id,uniacid,can_refund_time')->select()->toArray();
+
+ if(!empty($order)){
+
+ $refund_model = new RefundOrder();
+
+ $integral_model = new \app\member\model\Integral();
+
+ foreach ($order as $value){
+ //判断有无申请中的退款订单
+ $refund_order = $refund_model->dataInfo(['order_id'=>$value['id'],'status'=>1]);
+
+ if(empty($refund_order)){
+ //修改订单状态
+ $res = $this->where(['id'=>$value['id'],'have_tx'=>0])->update(['have_tx'=>1]);
+ //增加用户积分
+ if($res==1){
+
+ $integral_model->integralUserAdd($value['user_id'],$value['get_integral'],$value['uniacid'],2,10,$value['id'],$value['can_refund_time']);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 15:15
+ * @功能说明:核销订单
+ */
+ public function hxOrder($order_id,$cap_id=0,$uniacid=1,$time = 0){
+
+ $config_model = new Config();
+
+ $config = $config_model->dataInfo(['uniacid'=>$uniacid]);
+
+ $update = [
+
+ 'hx_time' => !empty($time)?$time:time(),
+
+ 'pay_type'=> 7,
+
+ 'hx_user' => $cap_id,
+ //可申请退款的时间
+ 'can_refund_time' => time()+$config['can_tx_time']*3600
+
+ ];
+
+ $res = $this->dataUpdate(['id'=>$order_id],$update);
+ //修改佣金到账状态
+ $water_model = new FinanceWater();
+
+ $dis[] = ['type','in',[8,15,16]];
+
+ $dis[] = ['order_id','=',$order_id];
+
+ $res = $water_model->dataUpdate($dis,['cash_status'=>1,'cash_time'=>$update['can_refund_time']]);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:超时自动退款
+ */
+ public function autoCancelOrder($uniacid,$user_id=0){
+
+ $dis[] = ['uniacid','=',$uniacid];
+
+ $dis[] = ['pay_type','=',1];
+
+ $dis[] = ['over_time','<',time()];
+
+ if(!empty($user_id)){
+
+ $dis[] = ['user_id','=',$user_id];
+ }
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->cancelOrder($value,1);
+
+ }
+
+ }
+ //自动核销订单
+ $this->autoHxOrder($uniacid);
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-19 13:27
+ * @功能说明:自动核销订单
+ */
+ public function autoHxOrder($uniacid){
+ //仅限快递
+// $dis[] = ['send_type','=',2];
+ //已经发货
+ $dis[] = ['pay_type','=',3];
+
+ $dis[] = ['hx_over_time','<',time()];
+
+ $order = $this->where($dis)->select()->toArray();
+
+ if(!empty($order)){
+
+ foreach ($order as $value){
+
+ $this->hxOrder($value['id'],0,$uniacid,$value['hx_over_time']);
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-01 10:13
+ * @功能说明:退款
+ */
+ public function cancelOrder($order,$auto_refund=0){
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$order['id'],'pay_type'=>1],['pay_type'=>-1,'auto_refund'=>$auto_refund,'cancel_time'=>time()]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'取消失败'];
+ }
+
+ $goods_model = new ShopGoods();
+ //退换库存
+ foreach ($order['order_goods'] as $v){
+
+ $res = $goods_model->setOrDelStock($v['goods_id'],$v['spe_id'],$v['goods_num'],1,0);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+
+ }
+
+ }
+// //退换优惠券
+// $coupon_model = new CouponRecord();
+//
+// $coupon_model->couponRefund($order['id'],2);
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-11-03 11:11
+ * @功能说明:检查营销活动
+ */
+ public function marketingCheck($data,$list){
+ //使用积分
+ if($data['integral']>0){
+
+ $user_model = new User();
+
+ $i_log = new \app\member\model\Integral();
+
+ $integral_model = new Integral();
+
+ $user = $user_model->dataInfo(['id'=>$data['user_id']]);
+ //检查用户积分
+ if($user['integral']<$data['integral']){
+
+ return ['code'=>500,'msg'=>'积分不足'];
+ }
+
+
+ foreach ($list as $value){
+
+ if(!empty($value['integral_id'])){
+
+ $atv = $integral_model->dataInfo(['id'=>$value['integral_id']]);
+
+ if(empty($atv)){
+
+ return ['code'=>500,'msg'=>'积分活动已下架'.$value['integral_id']];
+
+ }
+
+ $num = $integral_model->getAtvNum($value['integral_id'],$data['user_id']);
+
+ if($num>$atv['user_limit']){
+
+ return ['code'=>500,'msg'=>'该积分活动限购'.$atv['user_limit'].'次'];
+
+ }
+
+ }
+
+ }
+ //抵扣积分
+ $res = $i_log->integralUserAdd($data['user_id'],$data['integral']*-1,$data['uniacid'],2,3,$data['id']);
+
+ if($res==false){
+
+ return ['code'=>500,'msg'=>'积分抵扣失败'];
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2019-12-27 19:19
+ * @功能说明:发货发送订阅消息
+ */
+ public function orderSendService($order){
+
+ $user_model = new User();
+ //获取用户的open_id
+ $openid = $user_model->where(['id'=>$order['user_id']])->value('openid');
+ //访问页面
+ $page = 'shop/pages/order/detail?id='.$order['id'].'¬ice=1';
+ //模版消息model
+ $tmpl_model = new TmplConfig();
+ //获取模版
+ $tmpl = $tmpl_model->where(['uniacid'=>$order['uniacid'],'tmpl_name'=>'send_order'])->find();
+
+ //如果未添加模版消息 则不发送
+ if(empty($tmpl)){
+
+ return true;
+ }else{
+ $tmpl = $tmpl->toArray();
+ }
+ //模版id
+ $tmpl_id = $tmpl['tmpl_id'];
+ //模版类容
+ $service_model = new WxTmpl($order['uniacid']);
+ //模版的key
+ $key_worlds = $service_model::getTmplKey($tmpl_id);
+
+ if(!empty($openid)&&!empty($tmpl_id)&&!empty($key_worlds)){
+ //验证模版内容
+ if(!is_array($key_worlds)||count($key_worlds)<4){
+
+ return true;
+ }
+ //发送内容
+ $send_data = array(
+
+ $key_worlds[1]=>array(
+ //商品名称
+ 'value'=> date('Y-m-d H:i:s',$order['send_time']),
+ ),
+ $key_worlds[2]=>array(
+ //订单编号
+ 'value'=>$order['order_code'],
+ ),
+ $key_worlds[3]=>array(
+ //物流编号
+ 'value'=>$order['express_code'],
+ ),
+ $key_worlds[4]=>array(
+ //物流公司
+ 'value'=>$order['express_company'],
+ ),
+ );
+ //模版消息库类
+ $tmpl_sever = new WxTmpl($order['uniacid']);
+ //发送模版消息
+ $res = $tmpl_sever::sendTmpl($openid,$tmpl_id,$send_data,$page);
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/ShopOrderGoods.php b/app/shop/model/ShopOrderGoods.php
new file mode 100755
index 0000000..b99a85e
--- /dev/null
+++ b/app/shop/model/ShopOrderGoods.php
@@ -0,0 +1,263 @@
+orderRefundIng($data['id']);
+
+ return $res;
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:获取退款的数量
+ * @author chenniang
+ * @DataTime: 2021-04-12 10:46
+ */
+ public function getRefundNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $refund_model = new ShopRefund();
+
+ $num = $refund_model->refundNum($data['id']);
+
+ return $num;
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataSelect($dis){
+
+ $data = $this->where($dis)->order('id desc')->select()->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-22 11:12
+ * @功能说明:添加商品子订单
+ */
+ public function orderGoodsAdd($order_goods,$order_id,$user_id,$store_id){
+
+ $goods_model = new ShopGoods();
+
+ $car_model = new Car();
+
+ foreach ($order_goods as $v){
+// //限购
+// if($v['is_limit']==2){
+// //已购数量
+// $buy_num = $this->getGoodsNumber(['b.user_id'=>$user_id,'a.goods_id'=>$v['goods_id']]);
+//
+// if($v['limit']<$buy_num+$v['goods_num']){
+//
+// return ['code'=>500,'msg'=>$v['name'].'超出限购数量,限购数量'.$v['limit']];
+// }
+//
+// }
+
+ $insert = [
+
+ 'uniacid' => $v['uniacid'],
+
+ 'order_id' => $order_id,
+
+ 'user_id' => $user_id,
+
+ 'pay_type' => 1,
+
+ 'goods_name' => $v['goods_name'],
+
+ 'goods_cover' => $v['cover'],
+
+ 'spe_name' => $v['spe_name'],
+
+ 'goods_price' => $v['price'],
+
+ 'pay_price' => $v['true_price'],
+
+ 'singe_pay_price'=> $v['true_price']/$v['goods_num'],
+
+ 'goods_num' => $v['goods_num'],
+
+ 'can_refund_num' => $v['goods_num'],
+
+ 'spe_id' => $v['spe_id'],
+
+ 'goods_id' => $v['goods_id'],
+
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ return ['code'=>500,'msg'=>'下单失败'];
+ }
+ //减少库存 增加销量
+ $res = $goods_model->setOrDelStock($v['goods_id'],$v['spe_id'],$v['goods_num'],0,0);
+
+ if(!empty($res['code'])){
+
+ return $res;
+ }
+ //删除购物车
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'status' => 1,
+
+ 'goods_id'=> $v['goods_id'],
+
+ 'spe_id' => $v['spe_id'],
+
+ 'farmer_id' => $store_id
+ ];
+
+ $res = $car_model->where($dis)->delete();
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * @param $dis
+ * @return float
+ * 获取历史商品件数
+ */
+ public function getGoodsNumber($dis){
+
+ //取消订单的不算 chen
+ $num = $this->alias('a')
+ ->join('longbing_card_v2_shop_order_list b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->group('a.id')
+ ->sum('a.goods_num');
+
+
+ $order_id = $this->alias('a')
+ ->join('longbing_card_v2_shop_order_list b','a.order_id = b.id')
+ ->where($dis)
+ ->where('b.pay_type','>=',1)
+ ->column('b.id');
+
+ $order_refund_goods = new RefundOrderGoods();
+ //申请退款成功的
+ $refund_num = $order_refund_goods->where('order_id','in',$order_id)->where(['status'=>2])->sum('goods_num');
+
+ return $num - $refund_num;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/ShopRefund.php b/app/shop/model/ShopRefund.php
new file mode 100755
index 0000000..da09104
--- /dev/null
+++ b/app/shop/model/ShopRefund.php
@@ -0,0 +1,899 @@
+where(['id'=>$data['refund_user']])->value('username');
+
+ }else{
+
+ $model = new \app\farm\model\User();
+
+ $info = $model->where(['id'=>$data['refund_user']])->value('nickName');
+
+ }
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-03-07 17:38
+ * @功能说明:
+ */
+ public function getStoreInfoAttr($value,$data){
+
+ if(!empty($data['store_id'])){
+
+ $farmer_model= new Farmer();
+
+ $info = $farmer_model->dataInfo(['id'=>$data['store_id'],'type'=>2]);
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 16:48
+ * @功能说明:
+ */
+ public function getImgsAttr($value,$data){
+
+ if(!empty($value)){
+
+ return explode(',',$value);
+ }
+
+ }
+
+ /**
+ * @param $value
+ * @param $data
+ * @功能说明:总商品数量
+ * @author chenniang
+ * @DataTime: 2021-03-25 14:39
+ */
+ public function getAllGoodsNumAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $order_goods_model = new ShopRefundGoods();
+
+ $dis = [
+
+ 'refund_id' => $data['id']
+ ];
+
+ $num = $order_goods_model->where($dis)->sum('goods_num');
+
+ return $num;
+ }
+
+
+ }
+
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:16
+ * @功能说明:收货信息
+ */
+ public function getAddressInfoAttr($value,$data){
+
+ if(!empty($data['order_id'])){
+
+ $address_model = new OrderAddress();
+
+ $info = $address_model->dataInfo(['order_id'=>$data['order_id']]);
+
+ return $info;
+
+ }
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-17 17:16
+ * @功能说明:收货信息
+ */
+ public function getOrderGoodsAttr($value,$data){
+
+ if(!empty($data['id'])){
+
+ $goods_model = new ShopRefundGoods();
+
+ $info = $goods_model->dataSelect(['refund_id'=>$data['id']]);
+
+ return $info;
+
+ }
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-15 14:37
+ * @功能说明:后台列表
+ */
+ public function adminDataList($dis,$page=10,$mapor=[]){
+
+ $data = $this->alias('a')
+
+ ->join('lbfarm_shop_refund_order_goods c','a.id = c.refund_id')
+ ->join('lbfarm_shop_order d','a.order_id = d.id')
+ ->join('lbfarm_order_address e','a.order_id = e.order_id AND type = 5','left')
+ ->where($dis)
+ ->where(function ($query) use ($mapor){
+ $query->whereOr($mapor);
+ })
+ ->field('a.*,e.mobile,d.order_code as pay_order_code,e.user_name,d.pay_price')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+
+ if(!empty($data['data'])){
+
+ $user_model = new User();
+
+ foreach ($data['data'] as &$v){
+
+ $v['nickName'] = $user_model->where(['id'=>$v['user_id']])->value('nickName');
+
+ }
+ }
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-19 17:46
+ * @功能说明:小程序退款列表
+ */
+ public function indexDataList($dis,$where=[],$page=10){
+
+ $data = $this->alias('a')
+ ->join('lbfarm_shop_refund_order_goods c','a.id = c.refund_id')
+ ->join('lbfarm_shop_order d','a.order_id = d.id')
+ ->where($dis)
+ ->where(function ($query) use ($where){
+ $query->whereOr($where);
+ })
+ ->field('a.*,d.order_code as pay_order_code')
+ ->group('a.id')
+ ->order('a.id desc')
+ ->paginate($page)
+ ->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-08 17:08
+ * @功能说明:退款中
+ */
+ public function refundIng($cap_id){
+
+ $dis = [
+
+ 'cap_id' => $cap_id,
+
+ 'status' => 1
+ ];
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $data['status'] = 1;
+
+ $data['create_time'] = time();
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 09:37
+ * @功能说明:通过退款
+ */
+ public function passOrder($id,$price,$payConfig,$refund_user=0,$text='',$id_admin=0){
+
+ $refund_order= $this->dataInfo(['id'=>$id]);
+
+ $order_model = new ShopOrder();
+
+ $pay_order = $order_model->dataInfo(['id'=>$refund_order['order_id']]);
+
+ if($refund_order['status']!=1){
+
+ return ['code'=>500,'msg'=>'订单状态错误'];
+ }
+
+ $update = [
+
+ 'refund_user' => $refund_user,
+
+ 'status' => 2,
+
+ 'refund_time' => time(),
+
+ 'refund_price'=> $price,
+
+ 'pay_price' => $price,
+
+ 'refund_text' => $text,
+
+ 'refund_user_admin' => $id_admin
+ ];
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate(['id'=>$refund_order['id']],$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试'];
+
+ }
+ //修改退款子订单的退款状态
+ $order_refund_goods = new ShopRefundGoods();
+
+ $res = $order_refund_goods->dataUpdate(['refund_id'=>$id],['status'=>2]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试1'.$res];
+
+ }
+
+ $goods_model = new ShopGoods();
+ //退换库存
+ foreach ($refund_order['order_goods'] as $v){
+
+ $res = $goods_model->setOrDelStock($v['goods_id'],$v['spe_id'],$v['goods_num'],1,1);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return $res;
+
+ }
+
+ }
+
+ $res = $order_model->dataUpdate(['id'=>$refund_order['order_id']],['true_price'=>$pay_order['true_price']-$price]);
+ //查看货是否退完了
+ $refund_success = $this->checkRefundNum($refund_order['order_id']);
+ //退完了 就修改订单状态
+ if($refund_success==1){
+
+ $res = $order_model->dataUpdate(['id'=>$refund_order['order_id']],['pay_type'=>-1]);
+ //退换优惠券
+ $coupon_model = new CouponRecord();
+//
+// $coupon_model->couponRefund($pay_order['id'],2);
+// if($res==0){
+//
+// Db::rollback();
+//
+// return ['code'=>500,'msg'=>'退款失败,请重试2'];
+//
+// }
+
+ }
+
+ $pay_order = $order_model->dataInfo(['id'=>$refund_order['order_id']]);
+
+ $refund_order= $this->dataInfo(['id'=>$id]);
+
+ $res = $this->refundCash($payConfig,$pay_order,$price,$refund_order);
+
+ if(!empty($res['code'])){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>$res['msg']];
+ }
+
+ if($res!=true){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试3'];
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+ /**
+ * @param $payConfig
+ * @param $pay_order
+ * @param $price
+ * @param int $refund_id
+ * @功能说明:退钱
+ * @author chenniang
+ * @DataTime: 2021-07-12 20:31
+ */
+ public function refundCash($payConfig,$pay_order,$price,$refund_order){
+
+ if($price<=0){
+
+ return true;
+ }
+
+ $water_model = new FinanceWater();
+ //说明订单已经完成
+ if($pay_order['type']=-1){
+ //将流水状态修改为可入账
+ $water_model->dataUpdate(['order_id'=>$pay_order['id'],'type'=>8],['cash_status'=>1]);
+ //增加退款流水
+ $water_model->addWater($refund_order['id'],9,2,1);
+ //如果有运费将运费也改为可入账
+ $water_model->dataUpdate(['order_id'=>$pay_order['id'],'type'=>16],['cash_status'=>1]);
+ //增加运费退款流水
+ $water_model->addWater($refund_order['id'],17,1,1);
+
+ }else{
+
+ $water_model->addWater($refund_order['id'],9,2,0);
+
+ $water_model->addWater($refund_order['id'],17,1,0);
+
+ }
+
+ $water_model->cashArrival();
+
+ if(empty($pay_order['balance'])){
+ //微信退款
+ $response = orderRefundApi($payConfig,$pay_order['pay_price'],$price,$pay_order['transaction_id']);
+ //如果退款成功修改一下状态
+ if ( isset( $response[ 'return_code' ] ) && isset( $response[ 'result_code' ] ) && $response[ 'return_code' ] == 'SUCCESS' && $response[ 'result_code' ] == 'SUCCESS' ) {
+
+ $response['out_refund_no'] = !empty($response['out_refund_no'])?$response['out_refund_no']:$pay_order['order_code'];
+
+ $this->dataUpdate(['id'=>$refund_order['id']],['out_refund_no'=>$response['out_refund_no']]);
+
+ }else {
+ //失败就报错
+ $discption = !empty($response['err_code_des'])?$response['err_code_des']:$response['return_msg'];
+
+ return ['code'=>500,'msg'=> $discption];
+
+ }
+
+ }else{
+
+ $data = [
+
+ 'user_id' => $pay_order['user_id'],
+
+ 'pay_price'=> $price,
+
+ 'id' => $refund_order['id'],
+
+ 'uniacid' => $pay_order['uniacid']
+ ];
+
+ $water_model = new \app\farm\model\BalanceWater();
+
+ $res = $water_model->addWater($data,10,1);
+
+ if($res==0){
+
+ return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 10:29
+ * @功能说明:检查改订单款退完了没
+ */
+ public function checkRefundNum($order_id,$status=2){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $order_refund_goods_model = new ShopRefundGoods();
+
+ $dis = [
+
+ 'order_id' => $order_id
+ ];
+
+ $goods_num = $order_goods_model->where($dis)->sum('goods_num');
+
+ if($status==2){
+
+ $dis['status'] = 2;
+
+ $refund_num= $order_refund_goods_model->where($dis)->sum('goods_num');
+ }else{
+
+ $refund_num= $order_refund_goods_model->where($dis)->where('status','in',[1,2])->sum('goods_num');
+ }
+
+ return $refund_num>=$goods_num?1:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-18 15:38
+ * @功能说明:该天的退款
+ */
+ public function datePrice($date,$uniacid,$cap_id=0,$end_time='',$type=1){
+
+ $end_time = !empty($end_time)?$end_time:$date+86399;
+
+ $dis = [];
+
+ $dis[] = ['status','=',2];
+
+ $dis[] = ['create_time','between',"$date,$end_time"];
+
+ $dis[] = ['uniacid',"=",$uniacid];
+
+ if(!empty($cap_id)){
+
+ $dis[] = ['cap_id','=',$cap_id];
+ }
+
+ if($type==1){
+
+ $price = $this->where($dis)->sum('refund_price');
+
+ return round($price,2);
+
+ }else{
+
+ $count = $this->where($dis)->count();
+
+ return $count;
+ }
+
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-03-26 13:33
+ * @功能说明:申请退款
+ */
+ public function applyRefund($order,$input){
+
+ $order_goods_model = new ShopOrderGoods();
+
+ $refund_price = 0;
+
+ $integral = 0;
+
+ Db::startTrans();
+
+ $list = $input['list'];
+
+ foreach ($list as $k=>$value){
+
+ $order_goods = $order_goods_model->dataInfo(['id'=>$value['id']]);
+
+ if(empty($order_goods)){
+
+ return ['code'=>500,'msg'=>'商品未找到'];
+ }
+
+ if($value['num']>$order_goods['can_refund_num']||$value['num']==0){
+
+ return ['code'=>500,'msg'=>'退款数量错误'];
+
+ }
+ //退款金额
+ $refund_price += $order_goods['singe_pay_price']*$value['num'];
+
+
+ $list[$k]['goods_id'] = $order_goods['goods_id'];
+
+ $list[$k]['goods_name'] = $order_goods['goods_name'];
+
+ $list[$k]['goods_cover'] = $order_goods['goods_cover'];
+
+ $list[$k]['spe_name'] = $order_goods['spe_name'];
+
+ $list[$k]['spe_id'] = $order_goods['spe_id'];
+
+ $list[$k]['goods_price'] = $order_goods['goods_price'];
+
+ $res = $order_goods_model->where(['id'=>$value['id']])->update(['can_refund_num'=>$order_goods['can_refund_num']-$value['num']]);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ }
+
+// if($refund_price<=0){
+//
+// Db::rollback();
+//
+// return ['code'=>500,'msg'=>'退款金额至少为0.01元'];
+// }
+
+ $refund_price = round($refund_price,2);
+
+ $refund_price = $refund_price<=$order['pay_price']?$refund_price:$order['pay_price'];
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'store_id' => $order['store_id'],
+
+ 'user_id' => $order['user_id'],
+
+ 'farmer_id' => $order['farmer_id'],
+
+ 'order_code' => orderCode(),
+
+ 'apply_price'=> $refund_price,
+
+ 'order_id' => $order['id'],
+
+ 'text' => $input['text'],
+
+ 'imgs' => !empty($input['imgs'])?implode(',',$input['imgs']):''
+ ];
+
+ $res = $this->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ $refund_id = $this->getLastInsID();
+
+ $refund_goods_model = new ShopRefundGoods();
+
+ foreach ($list as $value){
+
+ $insert = [
+
+ 'uniacid' => $order['uniacid'],
+
+ 'order_id' => $order['id'],
+
+ 'refund_id' => $refund_id,
+
+ 'order_goods_id' => $value['id'],
+
+ 'goods_id' => $value['goods_id'],
+
+ 'goods_name' => $value['goods_name'],
+
+ 'goods_cover' => $value['goods_cover'],
+
+ 'spe_name' => $value['spe_name'],
+
+ 'spe_id' => $value['spe_id'],
+
+ 'goods_num' => $value['num'],
+
+ 'goods_price' => $value['goods_price'],
+
+ 'status' => 1
+ ];
+
+ $res = $refund_goods_model->dataAdd($insert);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'申请失败'];
+
+ }
+
+ }
+ //查看货是否退完了
+ $refund_success = $this->checkRefundNum($order['id'],1);
+ //退完并且未发货 就退运费
+ if($refund_success==1&&$order['pay_type']<3){
+
+ $refund_price += $order['freight'];
+
+ $refund_price = $refund_price<=$order['pay_price']?$refund_price:$order['pay_price'];
+
+ $this->dataUpdate(['id'=>$refund_id],['apply_price'=>$refund_price,'car_price'=>$order['freight']]);
+
+ }
+
+ Db::commit();
+
+ return $refund_id;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 09:23
+ * @功能说明:获取订单已经退款的数量
+ */
+ public function refundNum($order_goods_id){
+
+ $dis = [
+
+ 'b.order_goods_id' => $order_goods_id,
+
+ 'a.status' => 2
+ ];
+
+ $num = $this->alias('a')
+ ->join('lbfarm_shop_refund_order_goods b','a.id = b.refund_id')
+ ->where($dis)
+ ->group('b.order_goods_id')
+ ->sum('b.goods_num');
+
+ return $num;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 09:23
+ * @功能说明:获取订单已经退款的数量
+ */
+ public function orderRefundIng($order_goods_id){
+
+ $dis = [
+
+ 'b.order_goods_id' => $order_goods_id,
+
+ 'a.status' => 1
+ ];
+
+ $num = $this->alias('a')
+ ->join('lbfarm_shop_refund_order_goods b','a.id = b.refund_id')
+ ->where($dis)
+ ->group('b.order_goods_id')
+ ->find();
+
+ return !empty($num)?1:0;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2021-04-12 12:04
+ * @功能说明:拒绝退款
+ */
+ public function noPassRefund($refund_id){
+
+ $dis = [
+
+ 'id' => $refund_id
+ ];
+
+ $refund_order = $this->dataInfo($dis);
+
+ if($refund_order['status']!=1){
+
+ return ['code'=>500,'msg'=>'退款状态错误'];
+
+ }
+
+ $update = [
+
+ 'status' => 3,
+
+ 'refund_time' => time()
+
+ ];
+
+ Db::startTrans();
+
+ $res = $this->dataUpdate($dis,$update);
+
+ if($res!=1){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试1'];
+
+ }
+ //修改退款子订单的退款状态
+ $order_refund_goods = new ShopRefundGoods();
+
+ $res = $order_refund_goods->dataUpdate(['refund_id'=>$refund_id],['status'=>3]);
+
+ if($res==0){
+
+ Db::rollback();
+
+ return ['code'=>500,'msg'=>'退款失败,请重试2'];
+
+ }
+ //查询通支付订单未退款对售后订单
+ $where[] = ['order_id','=',$refund_order['order_id']];
+
+ $where[] = ['status','=',1];
+
+ $where[] = ['car_price','>',0];
+
+ $find = $this->dataInfo($where);
+
+ if(!empty($find)){
+
+ $apply_price = $find['apply_price'] - $find['car_price'];
+
+ $apply_price = $apply_price>0?$apply_price:0;
+
+ $update = [
+
+ 'apply_price' => $apply_price,
+
+ 'car_price' => 0
+ ];
+
+ $this->dataUpdate(['id'=>$find['id']],$update);
+ }
+
+ Db::commit();
+
+ return true;
+
+ }
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/ShopRefundGoods.php b/app/shop/model/ShopRefundGoods.php
new file mode 100755
index 0000000..4fe453b
--- /dev/null
+++ b/app/shop/model/ShopRefundGoods.php
@@ -0,0 +1,116 @@
+where(['id'=>$data['order_goods_id']])->sum('singe_pay_price');
+
+ return $price;
+
+ }
+
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:04
+ * @功能说明:添加
+ */
+ public function dataAdd($data){
+
+ $res = $this->insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataSelect($dis){
+
+ $data = $this->where($dis)->order('id desc')->select()->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/Signin.php b/app/shop/model/Signin.php
new file mode 100755
index 0000000..c8ef188
--- /dev/null
+++ b/app/shop/model/Signin.php
@@ -0,0 +1,102 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ if(empty($data)){
+
+ $this->dataAdd($dis);
+
+ $data = $this->where($dis)->find();
+
+ }
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-24 11:45
+ * @功能说明:发送提醒消息
+ */
+ public function sendMsg($uniacid){
+
+
+
+
+
+
+
+ }
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/SigninRecord.php b/app/shop/model/SigninRecord.php
new file mode 100755
index 0000000..81647b3
--- /dev/null
+++ b/app/shop/model/SigninRecord.php
@@ -0,0 +1,185 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page=10){
+
+ $data = $this->where($dis)->order('id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-22 16:11
+ * @功能说明:判断是否是连续签到
+ */
+ public function initSign($user_id){
+
+ $date = date('Y-m-d',strtotime('-1 day'));
+
+ $today = date('Y-m-d',time());
+
+ $dis = [
+
+ 'user_id' => $user_id,
+
+ 'create_date' => $date,
+
+ 'status' => 1
+ ];
+
+ $find = $this->dataInfo($dis);
+
+ if(empty($find)){
+
+ $where[] = ['user_id','=',$user_id];
+
+ $where[] = ['status','=',1];
+
+ $where[] = ['create_date','<>',$today];
+
+ $this->dataUpdate($where,['status'=>0]);
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-08-26 14:55
+ * @功能说明:发送消息
+ */
+ public function sendMsg($uniacid){
+
+ $user_model = new User();
+
+ $time = date('H',time());
+
+ if($time<10){
+
+ return false;
+ }
+
+ $push_model = new PushMsgModel($uniacid);
+
+ $today = strtotime(date('Y-m-d',time()));
+ //开启了签到提醒
+ $dis[] = ['uniacid','=',$uniacid];
+ //今天没有发送过消息
+ $dis[] = ['sign_notice_time','<',$today];
+ //今天未签到
+ $dis[] = ['sign_time','<',$today];
+
+ $data = $user_model->where($dis)->field('id,uniacid,id as user_id')->limit(10)->select()->toArray();
+
+ if(!empty($data)){
+
+ foreach ($data as $v){
+
+ $res = $user_model->where(['id'=>$v['user_id']])->where('sign_notice_time','<',$today)->update(['sign_notice_time'=>time()]);
+
+ if($res!=0){
+
+ $push_model->sendMsg($v,14);
+ }
+
+ }
+
+ }
+
+ return true;
+ }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/model/StoreGoods.php b/app/shop/model/StoreGoods.php
new file mode 100755
index 0000000..cfc2bd2
--- /dev/null
+++ b/app/shop/model/StoreGoods.php
@@ -0,0 +1,113 @@
+insert($data);
+
+ return $res;
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:05
+ * @功能说明:编辑
+ */
+ public function dataUpdate($dis,$data){
+
+ $res = $this->where($dis)->update($data);
+
+ return $res;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:06
+ * @功能说明:列表
+ */
+ public function dataList($dis,$page){
+
+ $data = $this->where($dis)->order('top desc,id desc')->paginate($page)->toArray();
+
+ return $data;
+
+ }
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2020-09-29 11:43
+ * @功能说明:
+ */
+ public function dataInfo($dis){
+
+ $data = $this->where($dis)->find();
+
+ return !empty($data)?$data->toArray():[];
+
+ }
+
+
+
+ /**
+ * @author chenniang
+ * @DataTime: 2022-07-12 16:16
+ * @功能说明:
+ */
+ public function addData($id,$type,$uniacid,$data){
+
+ $this->where(['goods_id'=>$id,'type'=>$type])->delete();
+
+ if(!empty($data)){
+
+ foreach ($data as $k=>$v){
+
+ $insert[$k] = [
+
+ 'uniacid' => $uniacid,
+
+ 'store_id' => $v,
+
+ 'goods_id'=> $id,
+
+ 'type' => $type
+ ];
+
+ }
+
+ $this->saveAll($insert);
+
+ }
+
+ return true;
+
+ }
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/shop/route/route.php b/app/shop/route/route.php
new file mode 100755
index 0000000..9d5f781
--- /dev/null
+++ b/app/shop/route/route.php
@@ -0,0 +1,416 @@
+_observer[] = $observer;
+ }
+
+ /**
+ * @purpose: 从注册树中移除观察者
+ * @param string $key 给所添加的观察者的一个唯一 key,方便从注册树中移除观察者
+ * @return mixed
+ */
+ public function removeObserver($key)
+ {
+ unset($this->_observer[$key]);
+ }
+
+ /**
+ * @purpose: 广播通知以注册的观察者,对注册树进行遍历,让每个对象实现其接口提供的操作
+ * @return mixed
+ */
+ public function notify($id,$data)
+ {
+ if(!empty($this->_observer)){
+
+ foreach ($this->_observer as $observer) {
+
+ $data[] = $observer->eventCoupon($id,$data);
+ }
+
+ }
+
+ return !empty($data)?$data:[];
+
+ }
+
+
+}
diff --git a/build.example.php b/build.example.php
new file mode 100755
index 0000000..ba9607c
--- /dev/null
+++ b/build.example.php
@@ -0,0 +1,26 @@
+
+// +----------------------------------------------------------------------
+
+/**
+ * php think build 自动生成应用的目录结构的定义示例
+ */
+return [
+ // 需要自动创建的文件
+ '__file__' => [],
+ // 需要自动创建的目录
+ '__dir__' => ['controller', 'model', 'view'],
+ // 需要自动创建的控制器
+ 'controller' => ['Index'],
+ // 需要自动创建的模型
+ 'model' => ['AdminUser'],
+ // 需要自动创建的模板
+ 'view' => ['index/index'],
+];
diff --git a/composer.json b/composer.json
new file mode 100755
index 0000000..2a15c66
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,54 @@
+{
+ "name": "topthink/think",
+ "description": "the new thinkphp framework",
+ "type": "project",
+ "keywords": [
+ "framework",
+ "thinkphp",
+ "ORM"
+ ],
+ "homepage": "http://thinkphp.cn/",
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=7.1.0",
+ "topthink/framework": "6.0.*-dev",
+ "topthink/think-view": "^1.0",
+ "justinrainbow/json-schema": "~1.3",
+ "ramsey/uuid": "^3.8",
+ "predis/predis": "^1.1",
+ "topthink/think-multi-app": "^1.0",
+ "guzzlehttp/guzzle": "~6.0",
+ "topthink/think-socketlog": "^1.0",
+ "topthink/think-swoole": "^3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "app\\": "app",
+ "longbingcore\\": "longbingcore"
+ },
+ "psr-0": {
+ "": "extend/"
+ }
+ },
+ "config": {
+ "preferred-install": "dist"
+ },
+ "repositories": {
+ "packagist": {
+ "type": "composer",
+ "url": "https://packagist.phpcomposer.com"
+ }
+ },
+ "scripts": {
+ "post-autoload-dump": [
+ "@php think service:discover",
+ "@php think vendor:publish"
+ ]
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100755
index 0000000..9e0cd16
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,1566 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "9f474e2a41296397a64a2793bdf81e78",
+ "packages": [
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "6.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "0274c05370a7bc9bb3a33838858253418bd7d14b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0274c05370a7bc9bb3a33838858253418bd7d14b",
+ "reference": "0274c05370a7bc9bb3a33838858253418bd7d14b",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.6.1",
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "ext-intl": "Required for Internationalized Domain Name (IDN) support",
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.5-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "time": "2019-12-21T08:51:15+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "v1.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "time": "2016-12-20T10:07:11+00:00"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "239400de7a173fe9901b9ac7c06497751f00727a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a",
+ "reference": "239400de7a173fe9901b9ac7c06497751f00727a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "ext-zlib": "*",
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
+ },
+ "suggest": {
+ "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "psr-7",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ],
+ "time": "2019-07-01T23:21:34+00:00"
+ },
+ {
+ "name": "justinrainbow/json-schema",
+ "version": "1.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/justinrainbow/json-schema.git",
+ "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/cc84765fb7317f6b07bd8ac78364747f95b86341",
+ "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.29"
+ },
+ "require-dev": {
+ "json-schema/json-schema-test-suite": "1.1.0",
+ "phpdocumentor/phpdocumentor": "~2",
+ "phpunit/phpunit": "~3.7"
+ },
+ "bin": [
+ "bin/validate-json"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "JsonSchema\\": "src/JsonSchema/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Bruno Prieto Reis",
+ "email": "bruno.p.reis@gmail.com"
+ },
+ {
+ "name": "Justin Rainbow",
+ "email": "justin.rainbow@gmail.com"
+ },
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ },
+ {
+ "name": "Robert Schönthal",
+ "email": "seroscho@googlemail.com"
+ }
+ ],
+ "description": "A library to validate a json schema.",
+ "homepage": "https://github.com/justinrainbow/json-schema",
+ "keywords": [
+ "json",
+ "schema"
+ ],
+ "time": "2016-01-25T15:43:01+00:00"
+ },
+ {
+ "name": "league/flysystem",
+ "version": "1.0.61",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/flysystem.git",
+ "reference": "4fb13c01784a6c9f165a351e996871488ca2d8c9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fb13c01784a6c9f165a351e996871488ca2d8c9",
+ "reference": "4fb13c01784a6c9f165a351e996871488ca2d8c9",
+ "shasum": ""
+ },
+ "require": {
+ "ext-fileinfo": "*",
+ "php": ">=5.5.9"
+ },
+ "conflict": {
+ "league/flysystem-sftp": "<1.0.6"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^3.4",
+ "phpunit/phpunit": "^5.7.10"
+ },
+ "suggest": {
+ "ext-fileinfo": "Required for MimeType",
+ "ext-ftp": "Allows you to use FTP server storage",
+ "ext-openssl": "Allows you to use FTPS server storage",
+ "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2",
+ "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3",
+ "league/flysystem-azure": "Allows you to use Windows Azure Blob storage",
+ "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching",
+ "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem",
+ "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files",
+ "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib",
+ "league/flysystem-webdav": "Allows you to use WebDAV storage",
+ "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter",
+ "spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
+ "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\Flysystem\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Frank de Jonge",
+ "email": "info@frenky.net"
+ }
+ ],
+ "description": "Filesystem abstraction: Many filesystems, one API.",
+ "keywords": [
+ "Cloud Files",
+ "WebDAV",
+ "abstraction",
+ "aws",
+ "cloud",
+ "copy.com",
+ "dropbox",
+ "file systems",
+ "files",
+ "filesystem",
+ "filesystems",
+ "ftp",
+ "rackspace",
+ "remote",
+ "s3",
+ "sftp",
+ "storage"
+ ],
+ "time": "2019-12-08T21:46:50+00:00"
+ },
+ {
+ "name": "league/flysystem-cached-adapter",
+ "version": "1.0.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/flysystem-cached-adapter.git",
+ "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/08ef74e9be88100807a3b92cc9048a312bf01d6f",
+ "reference": "08ef74e9be88100807a3b92cc9048a312bf01d6f",
+ "shasum": ""
+ },
+ "require": {
+ "league/flysystem": "~1.0",
+ "psr/cache": "^1.0.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "~0.9",
+ "phpspec/phpspec": "^3.4",
+ "phpunit/phpunit": "^5.7",
+ "predis/predis": "~1.0",
+ "tedivm/stash": "~0.12"
+ },
+ "suggest": {
+ "ext-phpredis": "Pure C implemented extension for PHP"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "League\\Flysystem\\Cached\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "frankdejonge",
+ "email": "info@frenky.net"
+ }
+ ],
+ "description": "An adapter decorator to enable meta-data caching.",
+ "time": "2018-07-09T20:51:04+00:00"
+ },
+ {
+ "name": "nette/php-generator",
+ "version": "v3.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/php-generator.git",
+ "reference": "4240fd7adf499138c07b814ef9b9a6df9f6d7187"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/php-generator/zipball/4240fd7adf499138c07b814ef9b9a6df9f6d7187",
+ "reference": "4240fd7adf499138c07b814ef9b9a6df9f6d7187",
+ "shasum": ""
+ },
+ "require": {
+ "nette/utils": "^2.4.2 || ~3.0.0",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "nette/tester": "^2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.3-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "code",
+ "nette",
+ "php",
+ "scaffolding"
+ ],
+ "time": "2019-11-22T11:12:11+00:00"
+ },
+ {
+ "name": "nette/utils",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/utils.git",
+ "reference": "c133e18c922dcf3ad07673077d92d92cef25a148"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/utils/zipball/c133e18c922dcf3ad07673077d92d92cef25a148",
+ "reference": "c133e18c922dcf3ad07673077d92d92cef25a148",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "nette/tester": "~2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "suggest": {
+ "ext-gd": "to use Image",
+ "ext-iconv": "to use Strings::webalize() and toAscii()",
+ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
+ "ext-json": "to use Nette\\Utils\\Json",
+ "ext-mbstring": "to use Strings::lower() etc...",
+ "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
+ "ext-xml": "to use Strings::length() etc. when mbstring is not available"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "array",
+ "core",
+ "datetime",
+ "images",
+ "json",
+ "nette",
+ "paginator",
+ "password",
+ "slugify",
+ "string",
+ "unicode",
+ "utf-8",
+ "utility",
+ "validation"
+ ],
+ "time": "2019-10-21T20:40:16+00:00"
+ },
+ {
+ "name": "opis/closure",
+ "version": "3.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/opis/closure.git",
+ "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/opis/closure/zipball/93ebc5712cdad8d5f489b500c59d122df2e53969",
+ "reference": "93ebc5712cdad8d5f489b500c59d122df2e53969",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.4 || ^7.0"
+ },
+ "require-dev": {
+ "jeremeamia/superclosure": "^2.0",
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Opis\\Closure\\": "src/"
+ },
+ "files": [
+ "functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marius Sarca",
+ "email": "marius.sarca@gmail.com"
+ },
+ {
+ "name": "Sorin Sarca",
+ "email": "sarca_sorin@hotmail.com"
+ }
+ ],
+ "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.",
+ "homepage": "https://opis.io/closure",
+ "keywords": [
+ "anonymous functions",
+ "closure",
+ "function",
+ "serializable",
+ "serialization",
+ "serialize"
+ ],
+ "time": "2019-11-29T22:36:02+00:00"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.99",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+ "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "time": "2018-07-02T15:55:56+00:00"
+ },
+ {
+ "name": "predis/predis",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nrk/predis.git",
+ "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1",
+ "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8"
+ },
+ "suggest": {
+ "ext-curl": "Allows access to Webdis when paired with phpiredis",
+ "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Predis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Daniele Alessandri",
+ "email": "suppakilla@gmail.com",
+ "homepage": "http://clorophilla.net"
+ }
+ ],
+ "description": "Flexible and feature-complete Redis client for PHP and HHVM",
+ "homepage": "http://github.com/nrk/predis",
+ "keywords": [
+ "nosql",
+ "predis",
+ "redis"
+ ],
+ "time": "2016-06-16T16:22:20+00:00"
+ },
+ {
+ "name": "psr/cache",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/cache.git",
+ "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+ "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for caching libraries",
+ "keywords": [
+ "cache",
+ "psr",
+ "psr-6"
+ ],
+ "time": "2016-08-06T20:24:11+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "time": "2017-02-14T16:28:37+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "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": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "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"
+ ],
+ "time": "2016-08-06T14:39:51+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "1.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2019-11-01T11:05:21+00:00"
+ },
+ {
+ "name": "psr/simple-cache",
+ "version": "1.0.1",
+ "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": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "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"
+ ],
+ "time": "2017-10-23T01:57:42+00:00"
+ },
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders.",
+ "time": "2019-03-08T08:55:37+00:00"
+ },
+ {
+ "name": "ramsey/uuid",
+ "version": "3.9.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ramsey/uuid.git",
+ "reference": "7779489a47d443f845271badbdcedfe4df8e06fb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb",
+ "reference": "7779489a47d443f845271badbdcedfe4df8e06fb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "paragonie/random_compat": "^1 | ^2 | 9.99.99",
+ "php": "^5.4 | ^7 | ^8",
+ "symfony/polyfill-ctype": "^1.8"
+ },
+ "replace": {
+ "rhumsaa/uuid": "self.version"
+ },
+ "require-dev": {
+ "codeception/aspect-mock": "^1 | ^2",
+ "doctrine/annotations": "^1.2",
+ "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1",
+ "jakub-onderka/php-parallel-lint": "^1",
+ "mockery/mockery": "^0.9.11 | ^1",
+ "moontoast/math": "^1.1",
+ "paragonie/random-lib": "^2",
+ "php-mock/php-mock-phpunit": "^0.3 | ^1.1",
+ "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5",
+ "squizlabs/php_codesniffer": "^3.5"
+ },
+ "suggest": {
+ "ext-ctype": "Provides support for PHP Ctype functions",
+ "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
+ "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
+ "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
+ "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
+ "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
+ "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
+ "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Ramsey\\Uuid\\": "src/"
+ },
+ "files": [
+ "src/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ },
+ {
+ "name": "Marijn Huizendveld",
+ "email": "marijn.huizendveld@gmail.com"
+ },
+ {
+ "name": "Thibaud Fabre",
+ "email": "thibaud@aztech.io"
+ }
+ ],
+ "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
+ "homepage": "https://github.com/ramsey/uuid",
+ "keywords": [
+ "guid",
+ "identifier",
+ "uuid"
+ ],
+ "time": "2019-12-17T08:18:51+00:00"
+ },
+ {
+ "name": "swoole/ide-helper",
+ "version": "4.4.12",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swoole/ide-helper.git",
+ "reference": "915964abd1ff4fe78be3e341ce9008b6d6a7648a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swoole/ide-helper/zipball/915964abd1ff4fe78be3e341ce9008b6d6a7648a",
+ "reference": "915964abd1ff4fe78be3e341ce9008b6d6a7648a",
+ "shasum": ""
+ },
+ "require-dev": {
+ "squizlabs/php_codesniffer": "~3.4.0",
+ "symfony/filesystem": "~4.3.0",
+ "zendframework/zend-code": "~3.3.0"
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Team Swoole",
+ "email": "team@swoole.com"
+ }
+ ],
+ "description": "IDE help files for Swoole.",
+ "time": "2019-11-04T17:53:06+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v4.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "ce8743441da64c41e2a667b8eb66070444ed911e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/ce8743441da64c41e2a667b8eb66070444ed911e",
+ "reference": "ce8743441da64c41e2a667b8eb66070444ed911e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Finder Component",
+ "homepage": "https://symfony.com",
+ "time": "2019-11-17T21:56:56+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
+ "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.13-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "time": "2019-11-27T13:56:44+00:00"
+ },
+ {
+ "name": "topthink/framework",
+ "version": "6.0.x-dev",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/framework.git",
+ "reference": "2e57ce8ccfddadf9b31fb41ac96a8cf15ee034f0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/framework/zipball/2e57ce8ccfddadf9b31fb41ac96a8cf15ee034f0",
+ "reference": "2e57ce8ccfddadf9b31fb41ac96a8cf15ee034f0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "league/flysystem": "^1.0",
+ "league/flysystem-cached-adapter": "^1.0",
+ "opis/closure": "^3.1",
+ "php": ">=7.1.0",
+ "psr/container": "~1.0",
+ "psr/log": "~1.0",
+ "psr/simple-cache": "^1.0",
+ "topthink/think-helper": "^3.1.1",
+ "topthink/think-orm": "^2.0"
+ },
+ "require-dev": {
+ "mikey179/vfsstream": "^1.6",
+ "mockery/mockery": "^1.2",
+ "phpunit/phpunit": "^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [],
+ "psr-4": {
+ "think\\": "src/think/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ },
+ {
+ "name": "yunwuxin",
+ "email": "448901948@qq.com"
+ }
+ ],
+ "description": "The ThinkPHP Framework.",
+ "homepage": "http://thinkphp.cn/",
+ "keywords": [
+ "framework",
+ "orm",
+ "thinkphp"
+ ],
+ "time": "2019-12-22T12:44:23+00:00"
+ },
+ {
+ "name": "topthink/think-helper",
+ "version": "v3.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-helper.git",
+ "reference": "4d85dfd3778623bbb1de3648f1dcd0c82f4439f4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-helper/zipball/4d85dfd3778623bbb1de3648f1dcd0c82f4439f4",
+ "reference": "4d85dfd3778623bbb1de3648f1dcd0c82f4439f4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "think\\": "src"
+ },
+ "files": [
+ "src/helper.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "yunwuxin",
+ "email": "448901948@qq.com"
+ }
+ ],
+ "description": "The ThinkPHP6 Helper Package",
+ "time": "2019-09-30T02:36:48+00:00"
+ },
+ {
+ "name": "topthink/think-multi-app",
+ "version": "v1.0.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-multi-app.git",
+ "reference": "215f4a6bb88e53ad41b448c61957336eb55ce6f9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/215f4a6bb88e53ad41b448c61957336eb55ce6f9",
+ "reference": "215f4a6bb88e53ad41b448c61957336eb55ce6f9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0",
+ "topthink/framework": "^6.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "think": {
+ "services": [
+ "think\\app\\Service"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "think\\app\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "thinkphp6 multi app support",
+ "time": "2019-10-29T06:34:59+00:00"
+ },
+ {
+ "name": "topthink/think-orm",
+ "version": "v2.0.28",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-orm.git",
+ "reference": "ff5f112f5559497222f2716385b5a709ab82741b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-orm/zipball/ff5f112f5559497222f2716385b5a709ab82741b",
+ "reference": "ff5f112f5559497222f2716385b5a709ab82741b",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": ">=7.1.0",
+ "psr/log": "~1.0",
+ "psr/simple-cache": "^1.0",
+ "topthink/think-helper": "^3.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "think\\": "src"
+ },
+ "files": []
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "think orm",
+ "keywords": [
+ "database",
+ "orm"
+ ],
+ "time": "2019-11-17T07:53:45+00:00"
+ },
+ {
+ "name": "topthink/think-socketlog",
+ "version": "v1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-socketlog.git",
+ "reference": "fe7134c41026dc74176796d4a6b7f57ae3fa1a84"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-socketlog/zipball/fe7134c41026dc74176796d4a6b7f57ae3fa1a84",
+ "reference": "fe7134c41026dc74176796d4a6b7f57ae3fa1a84",
+ "shasum": ""
+ },
+ "require": {
+ "topthink/framework": "^6.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "think\\log\\driver\\": "src"
+ },
+ "files": []
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "SocketLog for thinkphp",
+ "time": "2019-06-10T08:15:30+00:00"
+ },
+ {
+ "name": "topthink/think-swoole",
+ "version": "v3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-swoole.git",
+ "reference": "e36eff2f2bd88b5fe30631f55aa6b1c27b89aefa"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-swoole/zipball/e36eff2f2bd88b5fe30631f55aa6b1c27b89aefa",
+ "reference": "e36eff2f2bd88b5fe30631f55aa6b1c27b89aefa",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-swoole": ">=4.0.0",
+ "nette/php-generator": "^3.2",
+ "swoole/ide-helper": "^4.3",
+ "symfony/finder": "^4.3.2",
+ "topthink/framework": "^6.0",
+ "topthink/think-helper": "^3.0.4"
+ },
+ "require-dev": {
+ "symfony/var-dumper": "^4.3"
+ },
+ "type": "library",
+ "extra": {
+ "think": {
+ "services": [
+ "think\\swoole\\Service"
+ ],
+ "config": {
+ "swoole": "src/config/swoole.php"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "think\\swoole\\": "src"
+ },
+ "files": [
+ "src/helpers.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "Swoole extend for thinkphp",
+ "time": "2019-10-21T12:03:07+00:00"
+ },
+ {
+ "name": "topthink/think-template",
+ "version": "v2.0.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-template.git",
+ "reference": "e98bdbb4a4c94b442f17dfceba81e0134d4fbd19"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-template/zipball/e98bdbb4a4c94b442f17dfceba81e0134d4fbd19",
+ "reference": "e98bdbb4a4c94b442f17dfceba81e0134d4fbd19",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0",
+ "psr/simple-cache": "^1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "think\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "the php template engine",
+ "time": "2019-09-20T15:31:04+00:00"
+ },
+ {
+ "name": "topthink/think-view",
+ "version": "v1.0.13",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/top-think/think-view.git",
+ "reference": "90803b73f781db5d42619082c4597afc58b2d4c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/top-think/think-view/zipball/90803b73f781db5d42619082c4597afc58b2d4c5",
+ "reference": "90803b73f781db5d42619082c4597afc58b2d4c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0",
+ "topthink/think-template": "^2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "think\\view\\driver\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "liu21st",
+ "email": "liu21st@gmail.com"
+ }
+ ],
+ "description": "thinkphp template driver",
+ "time": "2019-10-07T12:23:10+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {
+ "topthink/framework": 20
+ },
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=7.1.0"
+ },
+ "platform-dev": []
+}
diff --git a/config/app.php b/config/app.php
new file mode 100755
index 0000000..3891e37
--- /dev/null
+++ b/config/app.php
@@ -0,0 +1,72 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | 应用设置
+// +----------------------------------------------------------------------
+
+use think\facade\Env;
+use think\facade\Request;
+
+//By.jingshuixian
+//自定义开发模式
+$adminModelListPaht = include app()->getBasePath().'/Info.php';
+
+if(Env::get('DEV_MODE',false)){
+ $host = Request::host();
+ $infoPath = app()->getBasePath().'/Info_'.$host.'.php';
+ if(file_exists($infoPath)){
+ $infoData = include $infoPath;
+ $adminModelListPaht = $infoData ;
+ }
+}
+
+return [
+ // 应用地址
+ 'app_host' => Env::get('app.host', ''),
+ // 应用Trace(环境变量优先读取)
+ 'app_trace' => false,
+ // 应用的命名空间
+ 'app_namespace' => '',
+ // 是否启用路由
+ 'with_route' => true,
+ // 是否启用事件
+ 'with_event' => true,
+ // 自动多应用模式
+ 'auto_multi_app' => true,
+ // 应用映射(自动多应用模式有效)
+ 'app_map' => [],
+ // 域名绑定(自动多应用模式有效)
+ 'domain_bind' => [],
+ // 禁止URL访问的应用列表(自动多应用模式有效)
+ 'deny_app_list' => [],
+ // 默认应用
+ 'default_app' => 'index',
+ // 默认时区
+ 'default_timezone' => 'Asia/Shanghai',
+ // 默认验证器
+ 'default_validate' => '',
+ // 异常页面的模板文件
+ 'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
+ // 错误显示信息,非调试模式有效
+ 'error_message' => '页面错误!请稍后再试~',
+ // 显示错误信息
+ 'show_error_msg' => true,
+ //是否是微擎系统
+ //'is_weiqin' => true,
+ //By.jingshuixian 2019年11月23日16:13:36
+ 'AdminModelList' => $adminModelListPaht,
+ //验证地址 // 这里应该是多个验证地址,防止验证失败
+ 'longbing_saas_url'=> 'http://api.longbing.org',
+
+ 'longbing_version' => '0.0.1',
+
+];
diff --git a/config/cache.php b/config/cache.php
new file mode 100755
index 0000000..c16b54a
--- /dev/null
+++ b/config/cache.php
@@ -0,0 +1,77 @@
+
+// +----------------------------------------------------------------------
+use think\facade\Env;
+defined('IN_IA') || define('IN_IA',true);
+// +----------------------------------------------------------------------
+// | 缓存设置
+// +----------------------------------------------------------------------
+$host = Env::get('cache.host', '127.0.0.1');
+$prefix = Env::get('cache.prefix', 'longbing_');
+$password = Env::get('cache.passwd', '');
+$expire = Env::get('cache.expire', 0);
+$port = Env::get('cache.port', 6379);
+
+
+
+$dir_path = __DIR__ . '/../../../../data/config.php';
+// var_dump(file_exists($dir_path));
+if(file_exists($dir_path) && longbingIsWeiqin())
+{
+ require_once $dir_path;
+
+ if(isset($config['setting']['redis']['server']) ) $host = $config['setting']['redis']['server'];
+ if(isset($config['setting']['redis']['prefix']) ) $prefix = $config['setting']['redis']['prefix'];
+ if(isset($config['setting']['redis']['pconnect']) ) $expire = $config['setting']['redis']['pconnect'];
+ if(isset($config['setting']['redis']['requirepass']) ) $password = $config['setting']['redis']['requirepass'];
+ if(isset($config['setting']['redis']['port']) ) $port = $config['setting']['redis']['port'];
+}
+// var_dump($host ,$prefix ,$password ,$expire);die;
+return [
+ // 默认缓存驱动
+ 'default' => Env::get('cache.driver', 'redis'),
+
+ // 缓存连接方式配置
+ 'stores' => [
+// 'file' => [
+// // 驱动方式
+// 'type' => 'file',
+// // 缓存保存目录
+// 'path' => '',
+// // 缓存前缀
+// 'prefix' => '',
+// // 缓存有效期 0表示永久缓存
+// 'expire' => 0,
+// // 缓存标签前缀
+// 'tag_prefix' => 'tag:',
+// // 序列化机制 例如 ['serialize', 'unserialize']
+// 'serialize' => [],
+// ],
+ // 更多的缓存连接
+ // redis缓存
+ 'redis' => [
+ // 驱动方式
+ 'type' => 'redis',
+ // 服务器地址
+ 'host' => !empty($host)?$host:'127.0.0.1',
+ //前缀
+ 'prefix' => !empty($prefix)?$prefix:'longbing_',
+ //密码
+ 'password' => $password,
+ //有效时长
+ 'expire' => $expire,
+ //端口
+ 'port' => !empty($port)?$port:'6379'
+
+
+ ],
+ ],
+];
+
diff --git a/config/console.php b/config/console.php
new file mode 100755
index 0000000..3bbe6e6
--- /dev/null
+++ b/config/console.php
@@ -0,0 +1,28 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | 控制台配置
+// +----------------------------------------------------------------------
+//return [
+// // 执行用户(Windows下无效)
+// 'user' => null,
+// // 指令定义
+// 'commands' => [
+//
+// ],
+//];
+
+return [
+ 'commands' => [
+ 'Swoole-Im' => 'app\command\SwooleIm',
+ ]
+];
diff --git a/config/cookie.php b/config/cookie.php
new file mode 100755
index 0000000..bbc5819
--- /dev/null
+++ b/config/cookie.php
@@ -0,0 +1,28 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | Cookie设置
+// +----------------------------------------------------------------------
+return [
+ // cookie 保存时间
+ 'expire' => 0,
+ // cookie 保存路径
+ 'path' => '/',
+ // cookie 有效域名
+ 'domain' => '',
+ // cookie 启用安全传输
+ 'secure' => false,
+ // httponly设置
+ 'httponly' => false,
+ // 是否使用 setcookie
+ 'setcookie' => true,
+];
diff --git a/config/database.php b/config/database.php
new file mode 100755
index 0000000..47d7aae
--- /dev/null
+++ b/config/database.php
@@ -0,0 +1,91 @@
+
+// +----------------------------------------------------------------------
+use think\facade\Env;
+defined('IN_IA') || define('IN_IA',true);
+$dir_path = __DIR__ . '/../../../../data/config.php';
+if(file_exists($dir_path) && longbingIsWeiqin())
+{
+ require $dir_path;
+}else{
+ $config = array();
+ $config['db']['master']['host'] = Env::get('database.hostname', '127.0.0.1');
+ $config['db']['master']['username'] = Env::get('database.username', 'root');
+ $config['db']['master']['password'] = Env::get('database.password', '');
+ $config['db']['master']['port'] = Env::get('database.hostport', '3306');
+ $config['db']['master']['database'] = Env::get('database.database', '');
+ $config['db']['master']['charset'] = Env::get('database.charset', 'utf8mb4');
+ $config['db']['master']['pconnect'] = 0;
+ $config['db']['master']['tablepre'] = Env::get('database.prefix', 'ims');
+}
+return [
+ // 默认使用的数据库连接配置
+ 'default' => Env::get('database.driver', 'mysql'),
+
+ // 数据库连接配置信息
+ 'connections' => [
+ 'mysql' => [
+ // 数据库类型
+ 'type' => 'mysql',
+ // 服务器地址
+ 'hostname' => $config['db']['master']['host'],
+ // 数据库名
+ 'database' => $config['db']['master']['database'],
+ // 用户名
+ 'username' => $config['db']['master']['username'] ,
+ // 密码
+ 'password' => $config['db']['master']['password'],
+ // 端口
+ 'hostport' => $config['db']['master']['port'],
+ // 连接dsn
+ 'dsn' => '',
+ // 数据库连接参数
+ 'params' => [],
+ // 数据库编码默认采用utf8
+ 'charset' => 'utf8mb4' ,
+ // 数据库表前缀
+ 'prefix' => $config['db']['master']['tablepre'] ,
+ // 数据库调试模式
+ 'debug' => Env::get('APP_DEBUG', false),
+ // 监听SQL
+ 'trigger_sql' => Env::get('APP_DEBUG', false),
+ // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
+ 'deploy' => 0,
+ // 数据库读写是否分离 主从式有效
+ 'rw_separate' => false,
+ // 读写分离后 主服务器数量
+ 'master_num' => 1,
+ // 指定从服务器序号
+ 'slave_no' => '',
+ // 是否严格检查字段是否存在
+ 'fields_strict' => true,
+ // 是否需要进行SQL性能分析
+ 'sql_explain' => false,
+ // Builder类
+ 'builder' => '',
+ // Query类
+ 'query' => '',
+ // 是否需要断线重连
+ 'break_reconnect' => false,
+ //数据集返回类型
+ 'resultset_type' => 'array',
+ ],
+
+ // 更多的数据库配置信息
+ ],
+
+ // 自定义时间查询规则
+ 'time_query_rule' => [],
+ // 自动写入时间戳字段
+// 'auto_timestamp' => 'timestamp',
+ 'auto_timestamp' => true,
+ // 时间字段取出后的默认时间格式
+// 'datetime_format' => 'Y-m-d H:i:s',
+];
diff --git a/config/filesystem.php b/config/filesystem.php
new file mode 100755
index 0000000..3247f88
--- /dev/null
+++ b/config/filesystem.php
@@ -0,0 +1,24 @@
+ Env::get('filesystem.driver', 'local'),
+ 'disks' => [
+ 'local' => [
+ 'type' => 'local',
+ 'root' => app()->getRuntimePath() . 'storage',
+ ],
+ 'public' => [
+ 'type' => 'local',
+ 'root' => app()->getRootPath() . 'public/storage',
+ 'url' => '/storage',
+ 'visibility' => 'public',
+ ],
+ // 更多的磁盘配置信息
+ 'longbing' => [
+ 'type' => 'local',
+ 'root' => FILE_UPLOAD_PATH,
+ ]
+ ],
+];
diff --git a/config/gateway_worker.php b/config/gateway_worker.php
new file mode 100755
index 0000000..21d1ebe
--- /dev/null
+++ b/config/gateway_worker.php
@@ -0,0 +1,45 @@
+
+// +----------------------------------------------------------------------
+// +----------------------------------------------------------------------
+// | Workerman设置 仅对 php think worker:gateway 指令有效
+// +----------------------------------------------------------------------
+return [
+ // 扩展自身需要的配置
+ 'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
+ 'host' => '0.0.0.0', // 监听地址
+ 'port' => 2348, // 监听端口
+ 'socket' => '', // 完整监听地址
+ 'context' => [], // socket 上下文选项
+ 'register_deploy' => true, // 是否需要部署register
+ 'businessWorker_deploy' => true, // 是否需要部署businessWorker
+ 'gateway_deploy' => true, // 是否需要部署gateway
+
+ // Register配置
+ 'registerAddress' => '127.0.0.1:1236',
+
+ // Gateway配置
+ 'name' => 'thinkphp',
+ 'count' => 1,
+ 'lanIp' => '127.0.0.1',
+ 'startPort' => 2000,
+ 'daemonize' => false,
+ 'pingInterval' => 30,
+ 'pingNotResponseLimit' => 0,
+ 'pingData' => '{"type":"ping"}',
+
+ // BusinsessWorker配置
+ 'businessWorker' => [
+ 'name' => 'BusinessWorker',
+ 'count' => 1,
+ 'eventHandler' => '\think\worker\Events',
+ ],
+
+];
diff --git a/config/lang.php b/config/lang.php
new file mode 100755
index 0000000..8f699a5
--- /dev/null
+++ b/config/lang.php
@@ -0,0 +1,37 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | 多语言设置
+// +----------------------------------------------------------------------
+
+use think\facade\Env;
+
+return [
+ // 默认语言
+ 'default_lang' => Env::get('lang.default_lang', 'zh-cn'),
+ // 允许的语言列表
+ 'allow_lang_list' => ['zh-cn', 'en-us'],
+ // 多语言自动侦测变量名
+ 'detect_var' => 'lang',
+ // 是否使用Cookie记录
+ 'use_cookie' => true,
+ // 多语言cookie变量
+ 'cookie_var' => 'think_lang',
+ // 扩展语言包
+ 'extend_list' => [],
+ // Accept-Language转义为对应语言包名称
+ 'accept_language' => [
+ 'zh-hans-cn' => 'zh-cn',
+ ],
+ // 是否支持语言分组
+ 'allow_group' => true,
+];
diff --git a/config/log.php b/config/log.php
new file mode 100755
index 0000000..294571e
--- /dev/null
+++ b/config/log.php
@@ -0,0 +1,82 @@
+
+// +----------------------------------------------------------------------
+use think\facade\Env;
+
+// +----------------------------------------------------------------------
+// | 日志设置
+// +----------------------------------------------------------------------
+
+
+return [
+ // 默认日志记录通道
+ 'default' => Env::get('log.channel', 'file') ,
+ // 日志记录级别
+ 'level' => [],
+ // 日志类型记录的通道 ['error'=>'email',...]
+ 'type_channel' => [],
+ // 是否关闭日志写入
+// 'close' => Env::get('APP_DEBUG', false) ,
+ 'close' => false ,
+
+ // 日志通道列表
+ 'channels' => [
+// 'file' => [
+// // 日志记录方式
+// 'type' => 'File',
+// // 日志保存目录
+// 'path' => '',
+// // 单文件日志写入
+// 'single' => true,
+// // 独立日志级别
+// 'apart_level' => [],
+// // 最大日志文件数量
+// 'max_files' => 100,
+// //文件大小
+// 'file_size' => 1024 * 1024 * 1024,
+// ],
+ 'file' => [
+ // 日志记录方式
+ 'type' => 'File',
+ // 日志保存目录
+ 'path' => '',
+ // 单文件日志写入
+ 'single' => false,
+ // 独立日志级别
+ 'apart_level' => [],
+ // 最大日志文件数量
+ 'max_files' => 0,
+ // 使用JSON格式记录
+ 'json' => false,
+ // 日志处理
+ 'processor' => null,
+ // 关闭通道日志写入
+ 'close' => false,
+ // 日志输出格式化
+ 'format' => '[%s][%s] %s',
+ //单个日志文件大小
+ 'file_size' => 1024*1024*1024,
+ // 是否实时写入
+ 'realtime_write' => true,
+
+ 'record_trace' => true,
+ ],
+ // 其它日志通道配置
+ 'SocketLog'=> [
+ 'type' => 'SocketLog',
+ 'host' => 'slog.migugu.com',
+ //日志强制记录到配置的client_id
+ 'force_client_ids' => ['shuixian_zfH5NbLn','longbing_TkbB7uznHAdfLtCP','chenniang_qkEAbc1vgmKlL6H0'],
+ //限制允许读取日志的client_id
+ 'allow_client_ids' => ['shuixian_zfH5NbLn','longbing_TkbB7uznHAdfLtCP','chenniang_qkEAbc1vgmKlL6H0'],
+ ]
+ ],
+
+];
diff --git a/config/permissions.php b/config/permissions.php
new file mode 100755
index 0000000..f2be209
--- /dev/null
+++ b/config/permissions.php
@@ -0,0 +1,33 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | 应用设置
+// +----------------------------------------------------------------------
+
+return [
+ // PATHINFO变量名 用于兼容模式
+ 'var_pathinfo' => 's',
+ // 兼容PATH_INFO获取
+ 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
+ // pathinfo分隔符
+ 'pathinfo_depr' => '/',
+ // HTTPS代理标识
+ 'https_agent_name' => '',
+ // URL伪静态后缀
+ 'url_html_suffix' => 'html',
+ // URL普通方式参数 用于自动生成
+ 'url_common_param' => true,
+ // 是否开启路由延迟解析
+ 'url_lazy_route' => false,
+ // 是否强制使用路由
+ 'url_route_must' => true,
+ // 合并路由规则
+ 'route_rule_merge' => true,
+ // 路由是否完全匹配
+ 'route_complete_match' => true,
+ // 使用注解路由
+ 'route_annotation' => false,
+ // 是否开启路由缓存
+ 'route_check_cache' => false,
+ // 路由缓存连接参数
+ 'route_cache_option' => [],
+ // 路由缓存Key
+ 'route_check_cache_key' => '',
+ // 访问控制器层名称
+ 'controller_layer' => 'controller',
+ // 空控制器名
+ 'empty_controller' => 'Error',
+ // 是否使用控制器后缀
+ 'controller_suffix' => false,
+ // 默认的路由变量规则
+ 'default_route_pattern' => '[\w\.]+',
+ // 域名根,如thinkphp.cn
+ 'url_domain_root' => '',
+ // 是否自动转换URL中的控制器和操作名
+ 'url_convert' => true,
+ // 表单请求类型伪装变量
+ 'var_method' => '_method',
+ // 表单ajax伪装变量
+ 'var_ajax' => '_ajax',
+ // 表单pjax伪装变量
+ 'var_pjax' => '_pjax',
+ // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则
+ 'request_cache' => false,
+ // 请求缓存有效期
+ 'request_cache_expire' => null,
+ // 全局请求缓存排除规则
+ 'request_cache_except' => [],
+ // 默认控制器名
+ 'default_controller' => 'Index',
+ // 默认操作名
+ 'default_action' => 'index',
+ // 操作方法后缀
+ 'action_suffix' => '',
+ // 默认JSONP格式返回的处理方法
+ 'default_jsonp_handler' => 'jsonpReturn',
+ // 默认JSONP处理方法
+ 'var_jsonp_handler' => 'callback',
+];
diff --git a/config/session.php b/config/session.php
new file mode 100755
index 0000000..7a2527a
--- /dev/null
+++ b/config/session.php
@@ -0,0 +1,27 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | 会话设置
+// +----------------------------------------------------------------------
+
+return [
+ // session name
+ 'name' => '',
+ // SESSION_ID的提交变量,解决flash上传跨域
+ 'var_session_id' => '',
+ // 驱动方式 支持file redis memcache memcached
+ 'type' => 'file',
+ // 过期时间
+ 'expire' => 0,
+ // 前缀
+ 'prefix' => '',
+];
diff --git a/config/swoole.php b/config/swoole.php
new file mode 100755
index 0000000..864db49
--- /dev/null
+++ b/config/swoole.php
@@ -0,0 +1,54 @@
+ [
+ 'host' => '0.0.0.0', // 监听地址
+ 'port' => Env::get('swoole.port', '8005'), // 监听端口
+ 'mode' => SWOOLE_PROCESS, // 运行模式 默认为SWOOLE_PROCESS
+ 'sock_type' => SWOOLE_SOCK_TCP, // sock type 默认为SWOOLE_SOCK_TCP
+ 'options' => [
+ 'pid_file' => runtime_path() . 'swoole.pid',
+ 'log_file' => Env::get('APP_DEBUG', false) ? runtime_path() . 'swoole.log' : false,
+ 'daemonize' => Env::get('swoole.daemonize', false),
+ // Normally this value should be 1~4 times larger according to your cpu cores.
+ 'reactor_num' => swoole_cpu_num(),
+ 'worker_num' => swoole_cpu_num(),
+ 'task_worker_num' => swoole_cpu_num(),
+ 'enable_static_handler' => true,
+ 'document_root' => root_path('public'),
+ 'package_max_length' => 20 * 1024 * 1024,
+ 'buffer_output_size' => 10 * 1024 * 1024,
+ 'socket_buffer_size' => 128 * 1024 * 1024,
+ 'max_request' => 3000,
+ 'send_yield' => true,
+ ],
+ ],
+ 'websocket' => [
+ 'enabled' => true,
+ 'handler' => Handler::class,
+ 'parser' => Parser::class,
+ 'route_file' => base_path() . 'im/controller/websocket.php',
+ 'ping_interval' => 25000,
+ 'ping_timeout' => 60000,
+ 'room' => [
+ 'type' => TableRoom::class,
+ 'room_rows' => 4096,
+ 'room_size' => 2048,
+ 'client_rows' => 8192,
+ 'client_size' => 2048,
+ ],
+ ],
+ 'hot_update' => [
+ 'enable' => true,
+ 'name' => ['*.php'],
+ 'include' => [app_path().'im/controller'],
+ 'exclude' => [],
+ ],
+ 'auto_reload' => false,
+ 'enable_coroutine' => true,
+ 'resetters' => [],
+ 'tables' => [],
+];
diff --git a/config/template.php b/config/template.php
new file mode 100755
index 0000000..98fd536
--- /dev/null
+++ b/config/template.php
@@ -0,0 +1,25 @@
+ 'Think',
+ // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
+ 'auto_rule' => 1,
+ // 模板路径
+ 'view_path' => '',
+ // 模板后缀
+ 'view_suffix' => 'html',
+ // 模板文件名分隔符
+ 'view_depr' => DIRECTORY_SEPARATOR,
+ // 模板引擎普通标签开始标记
+ 'tpl_begin' => '{',
+ // 模板引擎普通标签结束标记
+ 'tpl_end' => '}',
+ // 标签库标签开始标记
+ 'taglib_begin' => '{',
+ // 标签库标签结束标记
+ 'taglib_end' => '}',
+];
diff --git a/config/trace.php b/config/trace.php
new file mode 100755
index 0000000..da33a46
--- /dev/null
+++ b/config/trace.php
@@ -0,0 +1,18 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | Trace设置 开启调试模式后有效
+// +----------------------------------------------------------------------
+return [
+ // 内置Html 支持扩展
+ 'type' => 'Html',
+];
diff --git a/config/view.php b/config/view.php
new file mode 100755
index 0000000..28b4403
--- /dev/null
+++ b/config/view.php
@@ -0,0 +1,23 @@
+ 'Think',
+ // 模板路径
+ 'view_path' => '',
+ // 模板后缀
+ 'view_suffix' => 'html',
+ // 模板文件名分隔符
+ 'view_depr' => '/',
+ // 模板引擎普通标签开始标记
+ 'tpl_begin' => '{',
+ // 模板引擎普通标签结束标记
+ 'tpl_end' => '}',
+ // 标签库标签开始标记
+ 'taglib_begin' => '{',
+ // 标签库标签结束标记
+ 'taglib_end' => '}',
+];
diff --git a/config/worker.php b/config/worker.php
new file mode 100755
index 0000000..498812c
--- /dev/null
+++ b/config/worker.php
@@ -0,0 +1,30 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | Workerman设置 仅对 php think worker 指令有效
+// +----------------------------------------------------------------------
+return [
+ // 扩展自身需要的配置
+ 'host' => '0.0.0.0', // 监听地址
+ 'port' => 2346, // 监听端口
+ 'root' => '', // WEB 根目录 默认会定位public目录
+ 'app_path' => '', // 应用目录 守护进程模式必须设置(绝对路径)
+ 'file_monitor' => false, // 是否开启PHP文件更改监控(调试模式下自动开启)
+ 'file_monitor_interval' => 2, // 文件监控检测时间间隔(秒)
+ 'file_monitor_path' => [], // 文件监控目录 默认监控application和config目录
+
+ // 支持workerman的所有配置参数
+ 'name' => 'thinkphp',
+ 'count' => 4,
+ 'daemonize' => false,
+ 'pidFile' => '',
+];
diff --git a/config/worker_server.php b/config/worker_server.php
new file mode 100755
index 0000000..292328f
--- /dev/null
+++ b/config/worker_server.php
@@ -0,0 +1,55 @@
+
+// +----------------------------------------------------------------------
+
+// +----------------------------------------------------------------------
+// | Workerman设置 仅对 php think worker:server 指令有效
+// +----------------------------------------------------------------------
+return [
+ // 扩展自身需要的配置
+ 'protocol' => 'websocket', // 协议 支持 tcp udp unix http websocket text
+ 'host' => '0.0.0.0', // 监听地址
+ 'port' => 2345, // 监听端口
+ 'socket' => '', // 完整监听地址
+ 'context' => [], // socket 上下文选项
+ 'worker_class' => '', // 自定义Workerman服务类名 支持数组定义多个服务
+
+ // 支持workerman的所有配置参数
+ 'name' => 'thinkphp',
+ 'count' => 4,
+ 'daemonize' => false,
+ 'pidFile' => '',
+
+ // 支持事件回调
+ // onWorkerStart
+ 'onWorkerStart' => function ($worker) {
+
+ },
+ // onWorkerReload
+ 'onWorkerReload' => function ($worker) {
+
+ },
+ // onConnect
+ 'onConnect' => function ($connection) {
+
+ },
+ // onMessage
+ 'onMessage' => function ($connection, $data) {
+ $connection->send('receive success');
+ },
+ // onClose
+ 'onClose' => function ($connection) {
+
+ },
+ // onError
+ 'onError' => function ($connection, $code, $msg) {
+ echo "error [ $code ] $msg\n";
+ },
+];
diff --git a/extend/PHPExcel/PHPExcel.php b/extend/PHPExcel/PHPExcel.php
new file mode 100755
index 0000000..b8dbe0e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel.php
@@ -0,0 +1,1153 @@
+hasMacros;
+ }
+
+ /**
+ * Define if a workbook has macros
+ *
+ * @param boolean $hasMacros true|false
+ */
+ public function setHasMacros($hasMacros = false)
+ {
+ $this->hasMacros = (bool) $hasMacros;
+ }
+
+ /**
+ * Set the macros code
+ *
+ * @param string $MacrosCode string|null
+ */
+ public function setMacrosCode($MacrosCode = null)
+ {
+ $this->macrosCode=$MacrosCode;
+ $this->setHasMacros(!is_null($MacrosCode));
+ }
+
+ /**
+ * Return the macros code
+ *
+ * @return string|null
+ */
+ public function getMacrosCode()
+ {
+ return $this->macrosCode;
+ }
+
+ /**
+ * Set the macros certificate
+ *
+ * @param string|null $Certificate
+ */
+ public function setMacrosCertificate($Certificate = null)
+ {
+ $this->macrosCertificate=$Certificate;
+ }
+
+ /**
+ * Is the project signed ?
+ *
+ * @return boolean true|false
+ */
+ public function hasMacrosCertificate()
+ {
+ return !is_null($this->macrosCertificate);
+ }
+
+ /**
+ * Return the macros certificate
+ *
+ * @return string|null
+ */
+ public function getMacrosCertificate()
+ {
+ return $this->macrosCertificate;
+ }
+
+ /**
+ * Remove all macros, certificate from spreadsheet
+ *
+ */
+ public function discardMacros()
+ {
+ $this->hasMacros=false;
+ $this->macrosCode=null;
+ $this->macrosCertificate=null;
+ }
+
+ /**
+ * set ribbon XML data
+ *
+ */
+ public function setRibbonXMLData($Target = null, $XMLData = null)
+ {
+ if (!is_null($Target) && !is_null($XMLData)) {
+ $this->ribbonXMLData = array('target' => $Target, 'data' => $XMLData);
+ } else {
+ $this->ribbonXMLData = null;
+ }
+ }
+
+ /**
+ * retrieve ribbon XML Data
+ *
+ * return string|null|array
+ */
+ public function getRibbonXMLData($What = 'all') //we need some constants here...
+ {
+ $ReturnData = null;
+ $What = strtolower($What);
+ switch ($What){
+ case 'all':
+ $ReturnData = $this->ribbonXMLData;
+ break;
+ case 'target':
+ case 'data':
+ if (is_array($this->ribbonXMLData) && array_key_exists($What, $this->ribbonXMLData)) {
+ $ReturnData = $this->ribbonXMLData[$What];
+ }
+ break;
+ }
+
+ return $ReturnData;
+ }
+
+ /**
+ * store binaries ribbon objects (pictures)
+ *
+ */
+ public function setRibbonBinObjects($BinObjectsNames = null, $BinObjectsData = null)
+ {
+ if (!is_null($BinObjectsNames) && !is_null($BinObjectsData)) {
+ $this->ribbonBinObjects = array('names' => $BinObjectsNames, 'data' => $BinObjectsData);
+ } else {
+ $this->ribbonBinObjects = null;
+ }
+ }
+ /**
+ * return the extension of a filename. Internal use for a array_map callback (php<5.3 don't like lambda function)
+ *
+ */
+ private function getExtensionOnly($ThePath)
+ {
+ return pathinfo($ThePath, PATHINFO_EXTENSION);
+ }
+
+ /**
+ * retrieve Binaries Ribbon Objects
+ *
+ */
+ public function getRibbonBinObjects($What = 'all')
+ {
+ $ReturnData = null;
+ $What = strtolower($What);
+ switch($What) {
+ case 'all':
+ return $this->ribbonBinObjects;
+ break;
+ case 'names':
+ case 'data':
+ if (is_array($this->ribbonBinObjects) && array_key_exists($What, $this->ribbonBinObjects)) {
+ $ReturnData=$this->ribbonBinObjects[$What];
+ }
+ break;
+ case 'types':
+ if (is_array($this->ribbonBinObjects) &&
+ array_key_exists('data', $this->ribbonBinObjects) && is_array($this->ribbonBinObjects['data'])) {
+ $tmpTypes=array_keys($this->ribbonBinObjects['data']);
+ $ReturnData = array_unique(array_map(array($this, 'getExtensionOnly'), $tmpTypes));
+ } else {
+ $ReturnData=array(); // the caller want an array... not null if empty
+ }
+ break;
+ }
+ return $ReturnData;
+ }
+
+ /**
+ * This workbook have a custom UI ?
+ *
+ * @return boolean true|false
+ */
+ public function hasRibbon()
+ {
+ return !is_null($this->ribbonXMLData);
+ }
+
+ /**
+ * This workbook have additionnal object for the ribbon ?
+ *
+ * @return boolean true|false
+ */
+ public function hasRibbonBinObjects()
+ {
+ return !is_null($this->ribbonBinObjects);
+ }
+
+ /**
+ * Check if a sheet with a specified code name already exists
+ *
+ * @param string $pSheetCodeName Name of the worksheet to check
+ * @return boolean
+ */
+ public function sheetCodeNameExists($pSheetCodeName)
+ {
+ return ($this->getSheetByCodeName($pSheetCodeName) !== null);
+ }
+
+ /**
+ * Get sheet by code name. Warning : sheet don't have always a code name !
+ *
+ * @param string $pName Sheet name
+ * @return PHPExcel_Worksheet
+ */
+ public function getSheetByCodeName($pName = '')
+ {
+ $worksheetCount = count($this->workSheetCollection);
+ for ($i = 0; $i < $worksheetCount; ++$i) {
+ if ($this->workSheetCollection[$i]->getCodeName() == $pName) {
+ return $this->workSheetCollection[$i];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a new PHPExcel with one Worksheet
+ */
+ public function __construct()
+ {
+ $this->uniqueID = uniqid();
+ $this->calculationEngine = new PHPExcel_Calculation($this);
+
+ // Initialise worksheet collection and add one worksheet
+ $this->workSheetCollection = array();
+ $this->workSheetCollection[] = new PHPExcel_Worksheet($this);
+ $this->activeSheetIndex = 0;
+
+ // Create document properties
+ $this->properties = new PHPExcel_DocumentProperties();
+
+ // Create document security
+ $this->security = new PHPExcel_DocumentSecurity();
+
+ // Set named ranges
+ $this->namedRanges = array();
+
+ // Create the cellXf supervisor
+ $this->cellXfSupervisor = new PHPExcel_Style(true);
+ $this->cellXfSupervisor->bindParent($this);
+
+ // Create the default style
+ $this->addCellXf(new PHPExcel_Style);
+ $this->addCellStyleXf(new PHPExcel_Style);
+ }
+
+ /**
+ * Code to execute when this worksheet is unset()
+ *
+ */
+ public function __destruct()
+ {
+ $this->calculationEngine = null;
+ $this->disconnectWorksheets();
+ }
+
+ /**
+ * Disconnect all worksheets from this PHPExcel workbook object,
+ * typically so that the PHPExcel object can be unset
+ *
+ */
+ public function disconnectWorksheets()
+ {
+ $worksheet = null;
+ foreach ($this->workSheetCollection as $k => &$worksheet) {
+ $worksheet->disconnectCells();
+ $this->workSheetCollection[$k] = null;
+ }
+ unset($worksheet);
+ $this->workSheetCollection = array();
+ }
+
+ /**
+ * Return the calculation engine for this worksheet
+ *
+ * @return PHPExcel_Calculation
+ */
+ public function getCalculationEngine()
+ {
+ return $this->calculationEngine;
+ } // function getCellCacheController()
+
+ /**
+ * Get properties
+ *
+ * @return PHPExcel_DocumentProperties
+ */
+ public function getProperties()
+ {
+ return $this->properties;
+ }
+
+ /**
+ * Set properties
+ *
+ * @param PHPExcel_DocumentProperties $pValue
+ */
+ public function setProperties(PHPExcel_DocumentProperties $pValue)
+ {
+ $this->properties = $pValue;
+ }
+
+ /**
+ * Get security
+ *
+ * @return PHPExcel_DocumentSecurity
+ */
+ public function getSecurity()
+ {
+ return $this->security;
+ }
+
+ /**
+ * Set security
+ *
+ * @param PHPExcel_DocumentSecurity $pValue
+ */
+ public function setSecurity(PHPExcel_DocumentSecurity $pValue)
+ {
+ $this->security = $pValue;
+ }
+
+ /**
+ * Get active sheet
+ *
+ * @return PHPExcel_Worksheet
+ *
+ * @throws PHPExcel_Exception
+ */
+ public function getActiveSheet()
+ {
+ return $this->getSheet($this->activeSheetIndex);
+ }
+
+ /**
+ * Create sheet and add it to this workbook
+ *
+ * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
+ * @return PHPExcel_Worksheet
+ * @throws PHPExcel_Exception
+ */
+ public function createSheet($iSheetIndex = null)
+ {
+ $newSheet = new PHPExcel_Worksheet($this);
+ $this->addSheet($newSheet, $iSheetIndex);
+ return $newSheet;
+ }
+
+ /**
+ * Check if a sheet with a specified name already exists
+ *
+ * @param string $pSheetName Name of the worksheet to check
+ * @return boolean
+ */
+ public function sheetNameExists($pSheetName)
+ {
+ return ($this->getSheetByName($pSheetName) !== null);
+ }
+
+ /**
+ * Add sheet
+ *
+ * @param PHPExcel_Worksheet $pSheet
+ * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
+ * @return PHPExcel_Worksheet
+ * @throws PHPExcel_Exception
+ */
+ public function addSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = null)
+ {
+ if ($this->sheetNameExists($pSheet->getTitle())) {
+ throw new PHPExcel_Exception(
+ "Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename this worksheet first."
+ );
+ }
+
+ if ($iSheetIndex === null) {
+ if ($this->activeSheetIndex < 0) {
+ $this->activeSheetIndex = 0;
+ }
+ $this->workSheetCollection[] = $pSheet;
+ } else {
+ // Insert the sheet at the requested index
+ array_splice(
+ $this->workSheetCollection,
+ $iSheetIndex,
+ 0,
+ array($pSheet)
+ );
+
+ // Adjust active sheet index if necessary
+ if ($this->activeSheetIndex >= $iSheetIndex) {
+ ++$this->activeSheetIndex;
+ }
+ }
+
+ if ($pSheet->getParent() === null) {
+ $pSheet->rebindParent($this);
+ }
+
+ return $pSheet;
+ }
+
+ /**
+ * Remove sheet by index
+ *
+ * @param int $pIndex Active sheet index
+ * @throws PHPExcel_Exception
+ */
+ public function removeSheetByIndex($pIndex = 0)
+ {
+
+ $numSheets = count($this->workSheetCollection);
+ if ($pIndex > $numSheets - 1) {
+ throw new PHPExcel_Exception(
+ "You tried to remove a sheet by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
+ );
+ } else {
+ array_splice($this->workSheetCollection, $pIndex, 1);
+ }
+ // Adjust active sheet index if necessary
+ if (($this->activeSheetIndex >= $pIndex) &&
+ ($pIndex > count($this->workSheetCollection) - 1)) {
+ --$this->activeSheetIndex;
+ }
+
+ }
+
+ /**
+ * Get sheet by index
+ *
+ * @param int $pIndex Sheet index
+ * @return PHPExcel_Worksheet
+ * @throws PHPExcel_Exception
+ */
+ public function getSheet($pIndex = 0)
+ {
+ if (!isset($this->workSheetCollection[$pIndex])) {
+ $numSheets = $this->getSheetCount();
+ throw new PHPExcel_Exception(
+ "Your requested sheet index: {$pIndex} is out of bounds. The actual number of sheets is {$numSheets}."
+ );
+ }
+
+ return $this->workSheetCollection[$pIndex];
+ }
+
+ /**
+ * Get all sheets
+ *
+ * @return PHPExcel_Worksheet[]
+ */
+ public function getAllSheets()
+ {
+ return $this->workSheetCollection;
+ }
+
+ /**
+ * Get sheet by name
+ *
+ * @param string $pName Sheet name
+ * @return PHPExcel_Worksheet
+ */
+ public function getSheetByName($pName = '')
+ {
+ $worksheetCount = count($this->workSheetCollection);
+ for ($i = 0; $i < $worksheetCount; ++$i) {
+ if ($this->workSheetCollection[$i]->getTitle() === $pName) {
+ return $this->workSheetCollection[$i];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get index for sheet
+ *
+ * @param PHPExcel_Worksheet $pSheet
+ * @return int Sheet index
+ * @throws PHPExcel_Exception
+ */
+ public function getIndex(PHPExcel_Worksheet $pSheet)
+ {
+ foreach ($this->workSheetCollection as $key => $value) {
+ if ($value->getHashCode() == $pSheet->getHashCode()) {
+ return $key;
+ }
+ }
+
+ throw new PHPExcel_Exception("Sheet does not exist.");
+ }
+
+ /**
+ * Set index for sheet by sheet name.
+ *
+ * @param string $sheetName Sheet name to modify index for
+ * @param int $newIndex New index for the sheet
+ * @return int New sheet index
+ * @throws PHPExcel_Exception
+ */
+ public function setIndexByName($sheetName, $newIndex)
+ {
+ $oldIndex = $this->getIndex($this->getSheetByName($sheetName));
+ $pSheet = array_splice(
+ $this->workSheetCollection,
+ $oldIndex,
+ 1
+ );
+ array_splice(
+ $this->workSheetCollection,
+ $newIndex,
+ 0,
+ $pSheet
+ );
+ return $newIndex;
+ }
+
+ /**
+ * Get sheet count
+ *
+ * @return int
+ */
+ public function getSheetCount()
+ {
+ return count($this->workSheetCollection);
+ }
+
+ /**
+ * Get active sheet index
+ *
+ * @return int Active sheet index
+ */
+ public function getActiveSheetIndex()
+ {
+ return $this->activeSheetIndex;
+ }
+
+ /**
+ * Set active sheet index
+ *
+ * @param int $pIndex Active sheet index
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Worksheet
+ */
+ public function setActiveSheetIndex($pIndex = 0)
+ {
+ $numSheets = count($this->workSheetCollection);
+
+ if ($pIndex > $numSheets - 1) {
+ throw new PHPExcel_Exception(
+ "You tried to set a sheet active by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
+ );
+ } else {
+ $this->activeSheetIndex = $pIndex;
+ }
+ return $this->getActiveSheet();
+ }
+
+ /**
+ * Set active sheet index by name
+ *
+ * @param string $pValue Sheet title
+ * @return PHPExcel_Worksheet
+ * @throws PHPExcel_Exception
+ */
+ public function setActiveSheetIndexByName($pValue = '')
+ {
+ if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet) {
+ $this->setActiveSheetIndex($this->getIndex($worksheet));
+ return $worksheet;
+ }
+
+ throw new PHPExcel_Exception('Workbook does not contain sheet:' . $pValue);
+ }
+
+ /**
+ * Get sheet names
+ *
+ * @return string[]
+ */
+ public function getSheetNames()
+ {
+ $returnValue = array();
+ $worksheetCount = $this->getSheetCount();
+ for ($i = 0; $i < $worksheetCount; ++$i) {
+ $returnValue[] = $this->getSheet($i)->getTitle();
+ }
+
+ return $returnValue;
+ }
+
+ /**
+ * Add external sheet
+ *
+ * @param PHPExcel_Worksheet $pSheet External sheet to add
+ * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Worksheet
+ */
+ public function addExternalSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = null)
+ {
+ if ($this->sheetNameExists($pSheet->getTitle())) {
+ throw new PHPExcel_Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
+ }
+
+ // count how many cellXfs there are in this workbook currently, we will need this below
+ $countCellXfs = count($this->cellXfCollection);
+
+ // copy all the shared cellXfs from the external workbook and append them to the current
+ foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
+ $this->addCellXf(clone $cellXf);
+ }
+
+ // move sheet to this workbook
+ $pSheet->rebindParent($this);
+
+ // update the cellXfs
+ foreach ($pSheet->getCellCollection(false) as $cellID) {
+ $cell = $pSheet->getCell($cellID);
+ $cell->setXfIndex($cell->getXfIndex() + $countCellXfs);
+ }
+
+ return $this->addSheet($pSheet, $iSheetIndex);
+ }
+
+ /**
+ * Get named ranges
+ *
+ * @return PHPExcel_NamedRange[]
+ */
+ public function getNamedRanges()
+ {
+ return $this->namedRanges;
+ }
+
+ /**
+ * Add named range
+ *
+ * @param PHPExcel_NamedRange $namedRange
+ * @return boolean
+ */
+ public function addNamedRange(PHPExcel_NamedRange $namedRange)
+ {
+ if ($namedRange->getScope() == null) {
+ // global scope
+ $this->namedRanges[$namedRange->getName()] = $namedRange;
+ } else {
+ // local scope
+ $this->namedRanges[$namedRange->getScope()->getTitle().'!'.$namedRange->getName()] = $namedRange;
+ }
+ return true;
+ }
+
+ /**
+ * Get named range
+ *
+ * @param string $namedRange
+ * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
+ * @return PHPExcel_NamedRange|null
+ */
+ public function getNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null)
+ {
+ $returnValue = null;
+
+ if ($namedRange != '' && ($namedRange !== null)) {
+ // first look for global defined name
+ if (isset($this->namedRanges[$namedRange])) {
+ $returnValue = $this->namedRanges[$namedRange];
+ }
+
+ // then look for local defined name (has priority over global defined name if both names exist)
+ if (($pSheet !== null) && isset($this->namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
+ $returnValue = $this->namedRanges[$pSheet->getTitle() . '!' . $namedRange];
+ }
+ }
+
+ return $returnValue;
+ }
+
+ /**
+ * Remove named range
+ *
+ * @param string $namedRange
+ * @param PHPExcel_Worksheet|null $pSheet Scope: use null for global scope.
+ * @return PHPExcel
+ */
+ public function removeNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null)
+ {
+ if ($pSheet === null) {
+ if (isset($this->namedRanges[$namedRange])) {
+ unset($this->namedRanges[$namedRange]);
+ }
+ } else {
+ if (isset($this->namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
+ unset($this->namedRanges[$pSheet->getTitle() . '!' . $namedRange]);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Get worksheet iterator
+ *
+ * @return PHPExcel_WorksheetIterator
+ */
+ public function getWorksheetIterator()
+ {
+ return new PHPExcel_WorksheetIterator($this);
+ }
+
+ /**
+ * Copy workbook (!= clone!)
+ *
+ * @return PHPExcel
+ */
+ public function copy()
+ {
+ $copied = clone $this;
+
+ $worksheetCount = count($this->workSheetCollection);
+ for ($i = 0; $i < $worksheetCount; ++$i) {
+ $this->workSheetCollection[$i] = $this->workSheetCollection[$i]->copy();
+ $this->workSheetCollection[$i]->rebindParent($this);
+ }
+
+ return $copied;
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ foreach ($this as $key => $val) {
+ if (is_object($val) || (is_array($val))) {
+ $this->{$key} = unserialize(serialize($val));
+ }
+ }
+ }
+
+ /**
+ * Get the workbook collection of cellXfs
+ *
+ * @return PHPExcel_Style[]
+ */
+ public function getCellXfCollection()
+ {
+ return $this->cellXfCollection;
+ }
+
+ /**
+ * Get cellXf by index
+ *
+ * @param int $pIndex
+ * @return PHPExcel_Style
+ */
+ public function getCellXfByIndex($pIndex = 0)
+ {
+ return $this->cellXfCollection[$pIndex];
+ }
+
+ /**
+ * Get cellXf by hash code
+ *
+ * @param string $pValue
+ * @return PHPExcel_Style|boolean False if no match found
+ */
+ public function getCellXfByHashCode($pValue = '')
+ {
+ foreach ($this->cellXfCollection as $cellXf) {
+ if ($cellXf->getHashCode() == $pValue) {
+ return $cellXf;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if style exists in style collection
+ *
+ * @param PHPExcel_Style $pCellStyle
+ * @return boolean
+ */
+ public function cellXfExists($pCellStyle = null)
+ {
+ return in_array($pCellStyle, $this->cellXfCollection, true);
+ }
+
+ /**
+ * Get default style
+ *
+ * @return PHPExcel_Style
+ * @throws PHPExcel_Exception
+ */
+ public function getDefaultStyle()
+ {
+ if (isset($this->cellXfCollection[0])) {
+ return $this->cellXfCollection[0];
+ }
+ throw new PHPExcel_Exception('No default style found for this workbook');
+ }
+
+ /**
+ * Add a cellXf to the workbook
+ *
+ * @param PHPExcel_Style $style
+ */
+ public function addCellXf(PHPExcel_Style $style)
+ {
+ $this->cellXfCollection[] = $style;
+ $style->setIndex(count($this->cellXfCollection) - 1);
+ }
+
+ /**
+ * Remove cellXf by index. It is ensured that all cells get their xf index updated.
+ *
+ * @param integer $pIndex Index to cellXf
+ * @throws PHPExcel_Exception
+ */
+ public function removeCellXfByIndex($pIndex = 0)
+ {
+ if ($pIndex > count($this->cellXfCollection) - 1) {
+ throw new PHPExcel_Exception("CellXf index is out of bounds.");
+ } else {
+ // first remove the cellXf
+ array_splice($this->cellXfCollection, $pIndex, 1);
+
+ // then update cellXf indexes for cells
+ foreach ($this->workSheetCollection as $worksheet) {
+ foreach ($worksheet->getCellCollection(false) as $cellID) {
+ $cell = $worksheet->getCell($cellID);
+ $xfIndex = $cell->getXfIndex();
+ if ($xfIndex > $pIndex) {
+ // decrease xf index by 1
+ $cell->setXfIndex($xfIndex - 1);
+ } elseif ($xfIndex == $pIndex) {
+ // set to default xf index 0
+ $cell->setXfIndex(0);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the cellXf supervisor
+ *
+ * @return PHPExcel_Style
+ */
+ public function getCellXfSupervisor()
+ {
+ return $this->cellXfSupervisor;
+ }
+
+ /**
+ * Get the workbook collection of cellStyleXfs
+ *
+ * @return PHPExcel_Style[]
+ */
+ public function getCellStyleXfCollection()
+ {
+ return $this->cellStyleXfCollection;
+ }
+
+ /**
+ * Get cellStyleXf by index
+ *
+ * @param integer $pIndex Index to cellXf
+ * @return PHPExcel_Style
+ */
+ public function getCellStyleXfByIndex($pIndex = 0)
+ {
+ return $this->cellStyleXfCollection[$pIndex];
+ }
+
+ /**
+ * Get cellStyleXf by hash code
+ *
+ * @param string $pValue
+ * @return PHPExcel_Style|boolean False if no match found
+ */
+ public function getCellStyleXfByHashCode($pValue = '')
+ {
+ foreach ($this->cellStyleXfCollection as $cellStyleXf) {
+ if ($cellStyleXf->getHashCode() == $pValue) {
+ return $cellStyleXf;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add a cellStyleXf to the workbook
+ *
+ * @param PHPExcel_Style $pStyle
+ */
+ public function addCellStyleXf(PHPExcel_Style $pStyle)
+ {
+ $this->cellStyleXfCollection[] = $pStyle;
+ $pStyle->setIndex(count($this->cellStyleXfCollection) - 1);
+ }
+
+ /**
+ * Remove cellStyleXf by index
+ *
+ * @param integer $pIndex Index to cellXf
+ * @throws PHPExcel_Exception
+ */
+ public function removeCellStyleXfByIndex($pIndex = 0)
+ {
+ if ($pIndex > count($this->cellStyleXfCollection) - 1) {
+ throw new PHPExcel_Exception("CellStyleXf index is out of bounds.");
+ } else {
+ array_splice($this->cellStyleXfCollection, $pIndex, 1);
+ }
+ }
+
+ /**
+ * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
+ * and columns in the workbook
+ */
+ public function garbageCollect()
+ {
+ // how many references are there to each cellXf ?
+ $countReferencesCellXf = array();
+ foreach ($this->cellXfCollection as $index => $cellXf) {
+ $countReferencesCellXf[$index] = 0;
+ }
+
+ foreach ($this->getWorksheetIterator() as $sheet) {
+ // from cells
+ foreach ($sheet->getCellCollection(false) as $cellID) {
+ $cell = $sheet->getCell($cellID);
+ ++$countReferencesCellXf[$cell->getXfIndex()];
+ }
+
+ // from row dimensions
+ foreach ($sheet->getRowDimensions() as $rowDimension) {
+ if ($rowDimension->getXfIndex() !== null) {
+ ++$countReferencesCellXf[$rowDimension->getXfIndex()];
+ }
+ }
+
+ // from column dimensions
+ foreach ($sheet->getColumnDimensions() as $columnDimension) {
+ ++$countReferencesCellXf[$columnDimension->getXfIndex()];
+ }
+ }
+
+ // remove cellXfs without references and create mapping so we can update xfIndex
+ // for all cells and columns
+ $countNeededCellXfs = 0;
+ $map = array();
+ foreach ($this->cellXfCollection as $index => $cellXf) {
+ if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
+ ++$countNeededCellXfs;
+ } else {
+ unset($this->cellXfCollection[$index]);
+ }
+ $map[$index] = $countNeededCellXfs - 1;
+ }
+ $this->cellXfCollection = array_values($this->cellXfCollection);
+
+ // update the index for all cellXfs
+ foreach ($this->cellXfCollection as $i => $cellXf) {
+ $cellXf->setIndex($i);
+ }
+
+ // make sure there is always at least one cellXf (there should be)
+ if (empty($this->cellXfCollection)) {
+ $this->cellXfCollection[] = new PHPExcel_Style();
+ }
+
+ // update the xfIndex for all cells, row dimensions, column dimensions
+ foreach ($this->getWorksheetIterator() as $sheet) {
+ // for all cells
+ foreach ($sheet->getCellCollection(false) as $cellID) {
+ $cell = $sheet->getCell($cellID);
+ $cell->setXfIndex($map[$cell->getXfIndex()]);
+ }
+
+ // for all row dimensions
+ foreach ($sheet->getRowDimensions() as $rowDimension) {
+ if ($rowDimension->getXfIndex() !== null) {
+ $rowDimension->setXfIndex($map[$rowDimension->getXfIndex()]);
+ }
+ }
+
+ // for all column dimensions
+ foreach ($sheet->getColumnDimensions() as $columnDimension) {
+ $columnDimension->setXfIndex($map[$columnDimension->getXfIndex()]);
+ }
+
+ // also do garbage collection for all the sheets
+ $sheet->garbageCollect();
+ }
+ }
+
+ /**
+ * Return the unique ID value assigned to this spreadsheet workbook
+ *
+ * @return string
+ */
+ public function getID()
+ {
+ return $this->uniqueID;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Autoloader.php b/extend/PHPExcel/PHPExcel/Autoloader.php
new file mode 100755
index 0000000..c3b95a2
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Autoloader.php
@@ -0,0 +1,81 @@
+= 0) {
+ return spl_autoload_register(array('PHPExcel_Autoloader', 'load'), true, true);
+ } else {
+ return spl_autoload_register(array('PHPExcel_Autoloader', 'load'));
+ }
+ }
+
+ /**
+ * Autoload a class identified by name
+ *
+ * @param string $pClassName Name of the object to load
+ */
+ public static function load($pClassName)
+ {
+ if ((class_exists($pClassName, false)) || (strpos($pClassName, 'PHPExcel') !== 0)) {
+ // Either already loaded, or not a PHPExcel class request
+ return false;
+ }
+
+ $pClassFilePath = PHPEXCEL_ROOT .
+ str_replace('_', DIRECTORY_SEPARATOR, $pClassName) .
+ '.php';
+
+ if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
+ // Can't load
+ return false;
+ }
+
+ require($pClassFilePath);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/APC.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/APC.php
new file mode 100755
index 0000000..c74b07f
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/APC.php
@@ -0,0 +1,290 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ if (!apc_store(
+ $this->cachePrefix . $this->currentObjectID . '.cache',
+ serialize($this->currentObject),
+ $this->cacheTime
+ )) {
+ $this->__destruct();
+ throw new PHPExcel_Exception('Failed to store cell ' . $this->currentObjectID . ' in APC');
+ }
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @access public
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+ $this->cellCache[$pCoord] = true;
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+ /**
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+ *
+ * @access public
+ * @param string $pCoord Coordinate address of the cell to check
+ * @throws PHPExcel_Exception
+ * @return boolean
+ */
+ public function isDataSet($pCoord)
+ {
+ // Check if the requested entry is the current object, or exists in the cache
+ if (parent::isDataSet($pCoord)) {
+ if ($this->currentObjectID == $pCoord) {
+ return true;
+ }
+ // Check if the requested entry still exists in apc
+ $success = apc_fetch($this->cachePrefix.$pCoord.'.cache');
+ if ($success === false) {
+ // Entry no longer exists in APC, so clear it from the cache array
+ parent::deleteCacheData($pCoord);
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @access public
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (parent::isDataSet($pCoord)) {
+ $obj = apc_fetch($this->cachePrefix . $pCoord . '.cache');
+ if ($obj === false) {
+ // Entry no longer exists in APC, so clear it from the cache array
+ parent::deleteCacheData($pCoord);
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
+ }
+ } else {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = unserialize($obj);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+ /**
+ * Delete a cell in cache identified by coordinate address
+ *
+ * @access public
+ * @param string $pCoord Coordinate address of the cell to delete
+ * @throws PHPExcel_Exception
+ */
+ public function deleteCacheData($pCoord)
+ {
+ // Delete the entry from APC
+ apc_delete($this->cachePrefix.$pCoord.'.cache');
+
+ // Delete the entry from our cell address array
+ parent::deleteCacheData($pCoord);
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @access public
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @throws PHPExcel_Exception
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ parent::copyCellCollection($parent);
+ // Get a new id for the new file name
+ $baseUnique = $this->getUniqueID();
+ $newCachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+ $cacheList = $this->getCellList();
+ foreach ($cacheList as $cellID) {
+ if ($cellID != $this->currentObjectID) {
+ $obj = apc_fetch($this->cachePrefix . $cellID . '.cache');
+ if ($obj === false) {
+ // Entry no longer exists in APC, so clear it from the cache array
+ parent::deleteCacheData($cellID);
+ throw new PHPExcel_Exception('Cell entry ' . $cellID . ' no longer exists in APC');
+ }
+ if (!apc_store($newCachePrefix . $cellID . '.cache', $obj, $this->cacheTime)) {
+ $this->__destruct();
+ throw new PHPExcel_Exception('Failed to store cell ' . $cellID . ' in APC');
+ }
+ }
+ }
+ $this->cachePrefix = $newCachePrefix;
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if ($this->currentObject !== null) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+
+ // Flush the APC cache
+ $this->__destruct();
+
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ * @param array of mixed $arguments Additional initialisation arguments
+ */
+ public function __construct(PHPExcel_Worksheet $parent, $arguments)
+ {
+ $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
+
+ if ($this->cachePrefix === null) {
+ $baseUnique = $this->getUniqueID();
+ $this->cachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+ $this->cacheTime = $cacheTime;
+
+ parent::__construct($parent);
+ }
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ $cacheList = $this->getCellList();
+ foreach ($cacheList as $cellID) {
+ apc_delete($this->cachePrefix . $cellID . '.cache');
+ }
+ }
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ if (!function_exists('apc_store')) {
+ return false;
+ }
+ if (apc_sma_info() === false) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php
new file mode 100755
index 0000000..9a12ec8
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/CacheBase.php
@@ -0,0 +1,368 @@
+parent = $parent;
+ }
+
+ /**
+ * Return the parent worksheet for this cell collection
+ *
+ * @return PHPExcel_Worksheet
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+ *
+ * @param string $pCoord Coordinate address of the cell to check
+ * @return boolean
+ */
+ public function isDataSet($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return true;
+ }
+ // Check if the requested entry exists in the cache
+ return isset($this->cellCache[$pCoord]);
+ }
+
+ /**
+ * Move a cell object from one address to another
+ *
+ * @param string $fromAddress Current address of the cell to move
+ * @param string $toAddress Destination address of the cell to move
+ * @return boolean
+ */
+ public function moveCell($fromAddress, $toAddress)
+ {
+ if ($fromAddress === $this->currentObjectID) {
+ $this->currentObjectID = $toAddress;
+ }
+ $this->currentCellIsDirty = true;
+ if (isset($this->cellCache[$fromAddress])) {
+ $this->cellCache[$toAddress] = &$this->cellCache[$fromAddress];
+ unset($this->cellCache[$fromAddress]);
+ }
+
+ return true;
+ }
+
+ /**
+ * Add or Update a cell in cache
+ *
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function updateCacheData(PHPExcel_Cell $cell)
+ {
+ return $this->addCacheData($cell->getCoordinate(), $cell);
+ }
+
+ /**
+ * Delete a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to delete
+ * @throws PHPExcel_Exception
+ */
+ public function deleteCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID && !is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ if (is_object($this->cellCache[$pCoord])) {
+ $this->cellCache[$pCoord]->detach();
+ unset($this->cellCache[$pCoord]);
+ }
+ $this->currentCellIsDirty = false;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ return array_keys($this->cellCache);
+ }
+
+ /**
+ * Sort the list of all cell addresses currently held in cache by row and column
+ *
+ * @return string[]
+ */
+ public function getSortedCellList()
+ {
+ $sortKeys = array();
+ foreach ($this->getCellList() as $coord) {
+ sscanf($coord, '%[A-Z]%d', $column, $row);
+ $sortKeys[sprintf('%09d%3s', $row, $column)] = $coord;
+ }
+ ksort($sortKeys);
+
+ return array_values($sortKeys);
+ }
+
+ /**
+ * Get highest worksheet column and highest row that have cell records
+ *
+ * @return array Highest column name and highest row number
+ */
+ public function getHighestRowAndColumn()
+ {
+ // Lookup highest column and highest row
+ $col = array('A' => '1A');
+ $row = array(1);
+ foreach ($this->getCellList() as $coord) {
+ sscanf($coord, '%[A-Z]%d', $c, $r);
+ $row[$r] = $r;
+ $col[$c] = strlen($c).$c;
+ }
+ if (!empty($row)) {
+ // Determine highest column and row
+ $highestRow = max($row);
+ $highestColumn = substr(max($col), 1);
+ }
+
+ return array(
+ 'row' => $highestRow,
+ 'column' => $highestColumn
+ );
+ }
+
+ /**
+ * Return the cell address of the currently active cell object
+ *
+ * @return string
+ */
+ public function getCurrentAddress()
+ {
+ return $this->currentObjectID;
+ }
+
+ /**
+ * Return the column address of the currently active cell object
+ *
+ * @return string
+ */
+ public function getCurrentColumn()
+ {
+ sscanf($this->currentObjectID, '%[A-Z]%d', $column, $row);
+ return $column;
+ }
+
+ /**
+ * Return the row address of the currently active cell object
+ *
+ * @return integer
+ */
+ public function getCurrentRow()
+ {
+ sscanf($this->currentObjectID, '%[A-Z]%d', $column, $row);
+ return (integer) $row;
+ }
+
+ /**
+ * Get highest worksheet column
+ *
+ * @param string $row Return the highest column for the specified row,
+ * or the highest column of any row if no row number is passed
+ * @return string Highest column name
+ */
+ public function getHighestColumn($row = null)
+ {
+ if ($row == null) {
+ $colRow = $this->getHighestRowAndColumn();
+ return $colRow['column'];
+ }
+
+ $columnList = array(1);
+ foreach ($this->getCellList() as $coord) {
+ sscanf($coord, '%[A-Z]%d', $c, $r);
+ if ($r != $row) {
+ continue;
+ }
+ $columnList[] = PHPExcel_Cell::columnIndexFromString($c);
+ }
+ return PHPExcel_Cell::stringFromColumnIndex(max($columnList) - 1);
+ }
+
+ /**
+ * Get highest worksheet row
+ *
+ * @param string $column Return the highest row for the specified column,
+ * or the highest row of any column if no column letter is passed
+ * @return int Highest row number
+ */
+ public function getHighestRow($column = null)
+ {
+ if ($column == null) {
+ $colRow = $this->getHighestRowAndColumn();
+ return $colRow['row'];
+ }
+
+ $rowList = array(0);
+ foreach ($this->getCellList() as $coord) {
+ sscanf($coord, '%[A-Z]%d', $c, $r);
+ if ($c != $column) {
+ continue;
+ }
+ $rowList[] = $r;
+ }
+
+ return max($rowList);
+ }
+
+ /**
+ * Generate a unique ID for cache referencing
+ *
+ * @return string Unique Reference
+ */
+ protected function getUniqueID()
+ {
+ if (function_exists('posix_getpid')) {
+ $baseUnique = posix_getpid();
+ } else {
+ $baseUnique = mt_rand();
+ }
+ return uniqid($baseUnique, true);
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ $this->currentCellIsDirty;
+ $this->storeData();
+
+ $this->parent = $parent;
+ if (($this->currentObject !== null) && (is_object($this->currentObject))) {
+ $this->currentObject->attach($this);
+ }
+ } // function copyCellCollection()
+
+ /**
+ * Remove a row, deleting all cells in that row
+ *
+ * @param string $row Row number to remove
+ * @return void
+ */
+ public function removeRow($row)
+ {
+ foreach ($this->getCellList() as $coord) {
+ sscanf($coord, '%[A-Z]%d', $c, $r);
+ if ($r == $row) {
+ $this->deleteCacheData($coord);
+ }
+ }
+ }
+
+ /**
+ * Remove a column, deleting all cells in that column
+ *
+ * @param string $column Column ID to remove
+ * @return void
+ */
+ public function removeColumn($column)
+ {
+ foreach ($this->getCellList() as $coord) {
+ sscanf($coord, '%[A-Z]%d', $c, $r);
+ if ($c == $column) {
+ $this->deleteCacheData($coord);
+ }
+ }
+ }
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php
new file mode 100755
index 0000000..13bc033
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/DiscISAM.php
@@ -0,0 +1,208 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ fseek($this->fileHandle, 0, SEEK_END);
+
+ $this->cellCache[$this->currentObjectID] = array(
+ 'ptr' => ftell($this->fileHandle),
+ 'sz' => fwrite($this->fileHandle, serialize($this->currentObject))
+ );
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (!isset($this->cellCache[$pCoord])) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ fseek($this->fileHandle, $this->cellCache[$pCoord]['ptr']);
+ $this->currentObject = unserialize(fread($this->fileHandle, $this->cellCache[$pCoord]['sz']));
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ parent::copyCellCollection($parent);
+ // Get a new id for the new file name
+ $baseUnique = $this->getUniqueID();
+ $newFileName = $this->cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
+ // Copy the existing cell cache file
+ copy($this->fileName, $newFileName);
+ $this->fileName = $newFileName;
+ // Open the copied cell cache file
+ $this->fileHandle = fopen($this->fileName, 'a+');
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+
+ // Close down the temporary cache file
+ $this->__destruct();
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ * @param array of mixed $arguments Additional initialisation arguments
+ */
+ public function __construct(PHPExcel_Worksheet $parent, $arguments)
+ {
+ $this->cacheDirectory = ((isset($arguments['dir'])) && ($arguments['dir'] !== null))
+ ? $arguments['dir']
+ : PHPExcel_Shared_File::sys_get_temp_dir();
+
+ parent::__construct($parent);
+ if (is_null($this->fileHandle)) {
+ $baseUnique = $this->getUniqueID();
+ $this->fileName = $this->cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
+ $this->fileHandle = fopen($this->fileName, 'a+');
+ }
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ if (!is_null($this->fileHandle)) {
+ fclose($this->fileHandle);
+ unlink($this->fileName);
+ }
+ $this->fileHandle = null;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php
new file mode 100755
index 0000000..aafef6e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/ICache.php
@@ -0,0 +1,103 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ $this->cellCache[$this->currentObjectID] = igbinary_serialize($this->currentObject);
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ } // function _storeData()
+
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ } // function addCacheData()
+
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (!isset($this->cellCache[$pCoord])) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = igbinary_unserialize($this->cellCache[$pCoord]);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ } // function getCacheData()
+
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ } // function unsetWorksheetCells()
+
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ if (!function_exists('igbinary_serialize')) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php
new file mode 100755
index 0000000..07942cc
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/Memcache.php
@@ -0,0 +1,308 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ $obj = serialize($this->currentObject);
+ if (!$this->memcache->replace($this->cachePrefix . $this->currentObjectID . '.cache', $obj, null, $this->cacheTime)) {
+ if (!$this->memcache->add($this->cachePrefix . $this->currentObjectID . '.cache', $obj, null, $this->cacheTime)) {
+ $this->__destruct();
+ throw new PHPExcel_Exception("Failed to store cell {$this->currentObjectID} in MemCache");
+ }
+ }
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ } // function _storeData()
+
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+ $this->cellCache[$pCoord] = true;
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ } // function addCacheData()
+
+
+ /**
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+ *
+ * @param string $pCoord Coordinate address of the cell to check
+ * @return boolean
+ * @return boolean
+ */
+ public function isDataSet($pCoord)
+ {
+ // Check if the requested entry is the current object, or exists in the cache
+ if (parent::isDataSet($pCoord)) {
+ if ($this->currentObjectID == $pCoord) {
+ return true;
+ }
+ // Check if the requested entry still exists in Memcache
+ $success = $this->memcache->get($this->cachePrefix.$pCoord.'.cache');
+ if ($success === false) {
+ // Entry no longer exists in Memcache, so clear it from the cache array
+ parent::deleteCacheData($pCoord);
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (parent::isDataSet($pCoord)) {
+ $obj = $this->memcache->get($this->cachePrefix . $pCoord . '.cache');
+ if ($obj === false) {
+ // Entry no longer exists in Memcache, so clear it from the cache array
+ parent::deleteCacheData($pCoord);
+ throw new PHPExcel_Exception("Cell entry {$pCoord} no longer exists in MemCache");
+ }
+ } else {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = unserialize($obj);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+ /**
+ * Delete a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to delete
+ * @throws PHPExcel_Exception
+ */
+ public function deleteCacheData($pCoord)
+ {
+ // Delete the entry from Memcache
+ $this->memcache->delete($this->cachePrefix . $pCoord . '.cache');
+
+ // Delete the entry from our cell address array
+ parent::deleteCacheData($pCoord);
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ parent::copyCellCollection($parent);
+ // Get a new id for the new file name
+ $baseUnique = $this->getUniqueID();
+ $newCachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+ $cacheList = $this->getCellList();
+ foreach ($cacheList as $cellID) {
+ if ($cellID != $this->currentObjectID) {
+ $obj = $this->memcache->get($this->cachePrefix.$cellID.'.cache');
+ if ($obj === false) {
+ // Entry no longer exists in Memcache, so clear it from the cache array
+ parent::deleteCacheData($cellID);
+ throw new PHPExcel_Exception("Cell entry {$cellID} no longer exists in MemCache");
+ }
+ if (!$this->memcache->add($newCachePrefix . $cellID . '.cache', $obj, null, $this->cacheTime)) {
+ $this->__destruct();
+ throw new PHPExcel_Exception("Failed to store cell {$cellID} in MemCache");
+ }
+ }
+ }
+ $this->cachePrefix = $newCachePrefix;
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+
+ // Flush the Memcache cache
+ $this->__destruct();
+
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ * @param array of mixed $arguments Additional initialisation arguments
+ */
+ public function __construct(PHPExcel_Worksheet $parent, $arguments)
+ {
+ $memcacheServer = (isset($arguments['memcacheServer'])) ? $arguments['memcacheServer'] : 'localhost';
+ $memcachePort = (isset($arguments['memcachePort'])) ? $arguments['memcachePort'] : 11211;
+ $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
+
+ if (is_null($this->cachePrefix)) {
+ $baseUnique = $this->getUniqueID();
+ $this->cachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+
+ // Set a new Memcache object and connect to the Memcache server
+ $this->memcache = new Memcache();
+ if (!$this->memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) {
+ throw new PHPExcel_Exception("Could not connect to MemCache server at {$memcacheServer}:{$memcachePort}");
+ }
+ $this->cacheTime = $cacheTime;
+
+ parent::__construct($parent);
+ }
+ }
+
+ /**
+ * Memcache error handler
+ *
+ * @param string $host Memcache server
+ * @param integer $port Memcache port
+ * @throws PHPExcel_Exception
+ */
+ public function failureCallback($host, $port)
+ {
+ throw new PHPExcel_Exception("memcache {$host}:{$port} failed");
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ $cacheList = $this->getCellList();
+ foreach ($cacheList as $cellID) {
+ $this->memcache->delete($this->cachePrefix.$cellID . '.cache');
+ }
+ }
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ if (!function_exists('memcache_add')) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php
new file mode 100755
index 0000000..0e2ea0b
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/Memory.php
@@ -0,0 +1,118 @@
+cellCache[$pCoord] = $cell;
+
+ // Set current entry to the new/updated entry
+ $this->currentObjectID = $pCoord;
+
+ return $cell;
+ }
+
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ // Check if the entry that has been requested actually exists
+ if (!isset($this->cellCache[$pCoord])) {
+ $this->currentObjectID = null;
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+
+ // Return requested entry
+ return $this->cellCache[$pCoord];
+ }
+
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ parent::copyCellCollection($parent);
+
+ $newCollection = array();
+ foreach ($this->cellCache as $k => &$cell) {
+ $newCollection[$k] = clone $cell;
+ $newCollection[$k]->attach($this);
+ }
+
+ $this->cellCache = $newCollection;
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ */
+ public function unsetWorksheetCells()
+ {
+ // Because cells are all stored as intact objects in memory, we need to detach each one from the parent
+ foreach ($this->cellCache as $k => &$cell) {
+ $cell->detach();
+ $this->cellCache[$k] = null;
+ }
+ unset($cell);
+
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php
new file mode 100755
index 0000000..c06ec71
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/MemoryGZip.php
@@ -0,0 +1,133 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ $this->cellCache[$this->currentObjectID] = gzdeflate(serialize($this->currentObject));
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (!isset($this->cellCache[$pCoord])) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = unserialize(gzinflate($this->cellCache[$pCoord]));
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php
new file mode 100755
index 0000000..1332514
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/MemorySerialized.php
@@ -0,0 +1,129 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ $this->cellCache[$this->currentObjectID] = serialize($this->currentObject);
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (!isset($this->cellCache[$pCoord])) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = unserialize($this->cellCache[$pCoord]);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php
new file mode 100755
index 0000000..43c7819
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/PHPTemp.php
@@ -0,0 +1,200 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ fseek($this->fileHandle, 0, SEEK_END);
+
+ $this->cellCache[$this->currentObjectID] = array(
+ 'ptr' => ftell($this->fileHandle),
+ 'sz' => fwrite($this->fileHandle, serialize($this->currentObject))
+ );
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ if (!isset($this->cellCache[$pCoord])) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ fseek($this->fileHandle, $this->cellCache[$pCoord]['ptr']);
+ $this->currentObject = unserialize(fread($this->fileHandle, $this->cellCache[$pCoord]['sz']));
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ parent::copyCellCollection($parent);
+ // Open a new stream for the cell cache data
+ $newFileHandle = fopen('php://temp/maxmemory:' . $this->memoryCacheSize, 'a+');
+ // Copy the existing cell cache data to the new stream
+ fseek($this->fileHandle, 0);
+ while (!feof($this->fileHandle)) {
+ fwrite($newFileHandle, fread($this->fileHandle, 1024));
+ }
+ $this->fileHandle = $newFileHandle;
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+
+ // Close down the php://temp file
+ $this->__destruct();
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ * @param array of mixed $arguments Additional initialisation arguments
+ */
+ public function __construct(PHPExcel_Worksheet $parent, $arguments)
+ {
+ $this->memoryCacheSize = (isset($arguments['memoryCacheSize'])) ? $arguments['memoryCacheSize'] : '1MB';
+
+ parent::__construct($parent);
+ if (is_null($this->fileHandle)) {
+ $this->fileHandle = fopen('php://temp/maxmemory:' . $this->memoryCacheSize, 'a+');
+ }
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ if (!is_null($this->fileHandle)) {
+ fclose($this->fileHandle);
+ }
+ $this->fileHandle = null;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/SQLite.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/SQLite.php
new file mode 100755
index 0000000..e7b50c5
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/SQLite.php
@@ -0,0 +1,307 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ if (!$this->DBHandle->queryExec("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES('".$this->currentObjectID."','".sqlite_escape_string(serialize($this->currentObject))."')")) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ }
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ $query = "SELECT value FROM kvp_".$this->TableName." WHERE id='".$pCoord."'";
+ $cellResultSet = $this->DBHandle->query($query, SQLITE_ASSOC);
+ if ($cellResultSet === false) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ } elseif ($cellResultSet->numRows() == 0) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+
+ $cellResult = $cellResultSet->fetchSingle();
+ $this->currentObject = unserialize($cellResult);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Is a value set for an indexed cell?
+ *
+ * @param string $pCoord Coordinate address of the cell to check
+ * @return boolean
+ */
+ public function isDataSet($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return true;
+ }
+
+ // Check if the requested entry exists in the cache
+ $query = "SELECT id FROM kvp_".$this->TableName." WHERE id='".$pCoord."'";
+ $cellResultSet = $this->DBHandle->query($query, SQLITE_ASSOC);
+ if ($cellResultSet === false) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ } elseif ($cellResultSet->numRows() == 0) {
+ // Return null if requested entry doesn't exist in cache
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Delete a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to delete
+ * @throws PHPExcel_Exception
+ */
+ public function deleteCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ $this->currentObject->detach();
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ // Check if the requested entry exists in the cache
+ $query = "DELETE FROM kvp_".$this->TableName." WHERE id='".$pCoord."'";
+ if (!$this->DBHandle->queryExec($query)) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ }
+
+ $this->currentCellIsDirty = false;
+ }
+
+ /**
+ * Move a cell object from one address to another
+ *
+ * @param string $fromAddress Current address of the cell to move
+ * @param string $toAddress Destination address of the cell to move
+ * @return boolean
+ */
+ public function moveCell($fromAddress, $toAddress)
+ {
+ if ($fromAddress === $this->currentObjectID) {
+ $this->currentObjectID = $toAddress;
+ }
+
+ $query = "DELETE FROM kvp_".$this->TableName." WHERE id='".$toAddress."'";
+ $result = $this->DBHandle->exec($query);
+ if ($result === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ $query = "UPDATE kvp_".$this->TableName." SET id='".$toAddress."' WHERE id='".$fromAddress."'";
+ $result = $this->DBHandle->exec($query);
+ if ($result === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ return true;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ $query = "SELECT id FROM kvp_".$this->TableName;
+ $cellIdsResult = $this->DBHandle->unbufferedQuery($query, SQLITE_ASSOC);
+ if ($cellIdsResult === false) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ }
+
+ $cellKeys = array();
+ foreach ($cellIdsResult as $row) {
+ $cellKeys[] = $row['id'];
+ }
+
+ return $cellKeys;
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ $this->currentCellIsDirty;
+ $this->storeData();
+
+ // Get a new id for the new table name
+ $tableName = str_replace('.', '_', $this->getUniqueID());
+ if (!$this->DBHandle->queryExec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
+ AS SELECT * FROM kvp_'.$this->TableName)
+ ) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ }
+
+ // Copy the existing cell cache file
+ $this->TableName = $tableName;
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+
+ // Close down the temporary cache file
+ $this->__destruct();
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ */
+ public function __construct(PHPExcel_Worksheet $parent)
+ {
+ parent::__construct($parent);
+ if (is_null($this->DBHandle)) {
+ $this->TableName = str_replace('.', '_', $this->getUniqueID());
+ $_DBName = ':memory:';
+
+ $this->DBHandle = new SQLiteDatabase($_DBName);
+ if ($this->DBHandle === false) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ }
+ if (!$this->DBHandle->queryExec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) {
+ throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError()));
+ }
+ }
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ if (!is_null($this->DBHandle)) {
+ $this->DBHandle->queryExec('DROP TABLE kvp_'.$this->TableName);
+ }
+ $this->DBHandle = null;
+ }
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ if (!function_exists('sqlite_open')) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/SQLite3.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/SQLite3.php
new file mode 100755
index 0000000..27473d6
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/SQLite3.php
@@ -0,0 +1,346 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ $this->insertQuery->bindValue('id', $this->currentObjectID, SQLITE3_TEXT);
+ $this->insertQuery->bindValue('data', serialize($this->currentObject), SQLITE3_BLOB);
+ $result = $this->insertQuery->execute();
+ if ($result === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+ $this->currentCellIsDirty = false;
+ }
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
+ $cellResult = $this->selectQuery->execute();
+ if ($cellResult === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+ $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
+ if ($cellData === false) {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+
+ $this->currentObject = unserialize($cellData['value']);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+ /**
+ * Is a value set for an indexed cell?
+ *
+ * @param string $pCoord Coordinate address of the cell to check
+ * @return boolean
+ */
+ public function isDataSet($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return true;
+ }
+
+ // Check if the requested entry exists in the cache
+ $this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
+ $cellResult = $this->selectQuery->execute();
+ if ($cellResult === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+ $cellData = $cellResult->fetchArray(SQLITE3_ASSOC);
+
+ return ($cellData === false) ? false : true;
+ }
+
+ /**
+ * Delete a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to delete
+ * @throws PHPExcel_Exception
+ */
+ public function deleteCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ $this->currentObject->detach();
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ // Check if the requested entry exists in the cache
+ $this->deleteQuery->bindValue('id', $pCoord, SQLITE3_TEXT);
+ $result = $this->deleteQuery->execute();
+ if ($result === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ $this->currentCellIsDirty = false;
+ }
+
+ /**
+ * Move a cell object from one address to another
+ *
+ * @param string $fromAddress Current address of the cell to move
+ * @param string $toAddress Destination address of the cell to move
+ * @return boolean
+ */
+ public function moveCell($fromAddress, $toAddress)
+ {
+ if ($fromAddress === $this->currentObjectID) {
+ $this->currentObjectID = $toAddress;
+ }
+
+ $this->deleteQuery->bindValue('id', $toAddress, SQLITE3_TEXT);
+ $result = $this->deleteQuery->execute();
+ if ($result === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ $this->updateQuery->bindValue('toid', $toAddress, SQLITE3_TEXT);
+ $this->updateQuery->bindValue('fromid', $fromAddress, SQLITE3_TEXT);
+ $result = $this->updateQuery->execute();
+ if ($result === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ return true;
+ }
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ $query = "SELECT id FROM kvp_".$this->TableName;
+ $cellIdsResult = $this->DBHandle->query($query);
+ if ($cellIdsResult === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ $cellKeys = array();
+ while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) {
+ $cellKeys[] = $row['id'];
+ }
+
+ return $cellKeys;
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ $this->currentCellIsDirty;
+ $this->storeData();
+
+ // Get a new id for the new table name
+ $tableName = str_replace('.', '_', $this->getUniqueID());
+ if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
+ AS SELECT * FROM kvp_'.$this->TableName)
+ ) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+
+ // Copy the existing cell cache file
+ $this->TableName = $tableName;
+ }
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+
+ // Close down the temporary cache file
+ $this->__destruct();
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ */
+ public function __construct(PHPExcel_Worksheet $parent)
+ {
+ parent::__construct($parent);
+ if (is_null($this->DBHandle)) {
+ $this->TableName = str_replace('.', '_', $this->getUniqueID());
+ $_DBName = ':memory:';
+
+ $this->DBHandle = new SQLite3($_DBName);
+ if ($this->DBHandle === false) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+ if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) {
+ throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg());
+ }
+ }
+
+ $this->selectQuery = $this->DBHandle->prepare("SELECT value FROM kvp_".$this->TableName." WHERE id = :id");
+ $this->insertQuery = $this->DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES(:id,:data)");
+ $this->updateQuery = $this->DBHandle->prepare("UPDATE kvp_".$this->TableName." SET id=:toId WHERE id=:fromId");
+ $this->deleteQuery = $this->DBHandle->prepare("DELETE FROM kvp_".$this->TableName." WHERE id = :id");
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ if (!is_null($this->DBHandle)) {
+ $this->DBHandle->exec('DROP TABLE kvp_'.$this->TableName);
+ $this->DBHandle->close();
+ }
+ $this->DBHandle = null;
+ }
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ if (!class_exists('SQLite3', false)) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php b/extend/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php
new file mode 100755
index 0000000..1567874
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorage/Wincache.php
@@ -0,0 +1,289 @@
+currentCellIsDirty && !empty($this->currentObjectID)) {
+ $this->currentObject->detach();
+
+ $obj = serialize($this->currentObject);
+ if (wincache_ucache_exists($this->cachePrefix.$this->currentObjectID.'.cache')) {
+ if (!wincache_ucache_set($this->cachePrefix.$this->currentObjectID.'.cache', $obj, $this->cacheTime)) {
+ $this->__destruct();
+ throw new PHPExcel_Exception('Failed to store cell '.$this->currentObjectID.' in WinCache');
+ }
+ } else {
+ if (!wincache_ucache_add($this->cachePrefix.$this->currentObjectID.'.cache', $obj, $this->cacheTime)) {
+ $this->__destruct();
+ throw new PHPExcel_Exception('Failed to store cell '.$this->currentObjectID.' in WinCache');
+ }
+ }
+ $this->currentCellIsDirty = false;
+ }
+
+ $this->currentObjectID = $this->currentObject = null;
+ }
+
+ /**
+ * Add or Update a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to update
+ * @param PHPExcel_Cell $cell Cell to update
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function addCacheData($pCoord, PHPExcel_Cell $cell)
+ {
+ if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) {
+ $this->storeData();
+ }
+ $this->cellCache[$pCoord] = true;
+
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = $cell;
+ $this->currentCellIsDirty = true;
+
+ return $cell;
+ }
+
+ /**
+ * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+ *
+ * @param string $pCoord Coordinate address of the cell to check
+ * @return boolean
+ */
+ public function isDataSet($pCoord)
+ {
+ // Check if the requested entry is the current object, or exists in the cache
+ if (parent::isDataSet($pCoord)) {
+ if ($this->currentObjectID == $pCoord) {
+ return true;
+ }
+ // Check if the requested entry still exists in cache
+ $success = wincache_ucache_exists($this->cachePrefix.$pCoord.'.cache');
+ if ($success === false) {
+ // Entry no longer exists in Wincache, so clear it from the cache array
+ parent::deleteCacheData($pCoord);
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Get cell at a specific coordinate
+ *
+ * @param string $pCoord Coordinate of the cell
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_Cell Cell that was found, or null if not found
+ */
+ public function getCacheData($pCoord)
+ {
+ if ($pCoord === $this->currentObjectID) {
+ return $this->currentObject;
+ }
+ $this->storeData();
+
+ // Check if the entry that has been requested actually exists
+ $obj = null;
+ if (parent::isDataSet($pCoord)) {
+ $success = false;
+ $obj = wincache_ucache_get($this->cachePrefix.$pCoord.'.cache', $success);
+ if ($success === false) {
+ // Entry no longer exists in WinCache, so clear it from the cache array
+ parent::deleteCacheData($pCoord);
+ throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
+ }
+ } else {
+ // Return null if requested entry doesn't exist in cache
+ return null;
+ }
+
+ // Set current entry to the requested entry
+ $this->currentObjectID = $pCoord;
+ $this->currentObject = unserialize($obj);
+ // Re-attach this as the cell's parent
+ $this->currentObject->attach($this);
+
+ // Return requested entry
+ return $this->currentObject;
+ }
+
+
+ /**
+ * Get a list of all cell addresses currently held in cache
+ *
+ * @return string[]
+ */
+ public function getCellList()
+ {
+ if ($this->currentObjectID !== null) {
+ $this->storeData();
+ }
+
+ return parent::getCellList();
+ }
+
+ /**
+ * Delete a cell in cache identified by coordinate address
+ *
+ * @param string $pCoord Coordinate address of the cell to delete
+ * @throws PHPExcel_Exception
+ */
+ public function deleteCacheData($pCoord)
+ {
+ // Delete the entry from Wincache
+ wincache_ucache_delete($this->cachePrefix.$pCoord.'.cache');
+
+ // Delete the entry from our cell address array
+ parent::deleteCacheData($pCoord);
+ }
+
+ /**
+ * Clone the cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The new worksheet
+ * @return void
+ */
+ public function copyCellCollection(PHPExcel_Worksheet $parent)
+ {
+ parent::copyCellCollection($parent);
+ // Get a new id for the new file name
+ $baseUnique = $this->getUniqueID();
+ $newCachePrefix = substr(md5($baseUnique), 0, 8) . '.';
+ $cacheList = $this->getCellList();
+ foreach ($cacheList as $cellID) {
+ if ($cellID != $this->currentObjectID) {
+ $success = false;
+ $obj = wincache_ucache_get($this->cachePrefix.$cellID.'.cache', $success);
+ if ($success === false) {
+ // Entry no longer exists in WinCache, so clear it from the cache array
+ parent::deleteCacheData($cellID);
+ throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in Wincache');
+ }
+ if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->cacheTime)) {
+ $this->__destruct();
+ throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in Wincache');
+ }
+ }
+ }
+ $this->cachePrefix = $newCachePrefix;
+ }
+
+
+ /**
+ * Clear the cell collection and disconnect from our parent
+ *
+ * @return void
+ */
+ public function unsetWorksheetCells()
+ {
+ if (!is_null($this->currentObject)) {
+ $this->currentObject->detach();
+ $this->currentObject = $this->currentObjectID = null;
+ }
+
+ // Flush the WinCache cache
+ $this->__destruct();
+
+ $this->cellCache = array();
+
+ // detach ourself from the worksheet, so that it can then delete this object successfully
+ $this->parent = null;
+ }
+
+ /**
+ * Initialise this new cell collection
+ *
+ * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
+ * @param array of mixed $arguments Additional initialisation arguments
+ */
+ public function __construct(PHPExcel_Worksheet $parent, $arguments)
+ {
+ $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
+
+ if (is_null($this->cachePrefix)) {
+ $baseUnique = $this->getUniqueID();
+ $this->cachePrefix = substr(md5($baseUnique), 0, 8).'.';
+ $this->cacheTime = $cacheTime;
+
+ parent::__construct($parent);
+ }
+ }
+
+ /**
+ * Destroy this cell collection
+ */
+ public function __destruct()
+ {
+ $cacheList = $this->getCellList();
+ foreach ($cacheList as $cellID) {
+ wincache_ucache_delete($this->cachePrefix.$cellID.'.cache');
+ }
+ }
+
+ /**
+ * Identify whether the caching method is currently available
+ * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+ *
+ * @return boolean
+ */
+ public static function cacheMethodIsAvailable()
+ {
+ if (!function_exists('wincache_ucache_add')) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CachedObjectStorageFactory.php b/extend/PHPExcel/PHPExcel/CachedObjectStorageFactory.php
new file mode 100755
index 0000000..0a96978
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CachedObjectStorageFactory.php
@@ -0,0 +1,231 @@
+ array(
+ ),
+ self::cache_in_memory_gzip => array(
+ ),
+ self::cache_in_memory_serialized => array(
+ ),
+ self::cache_igbinary => array(
+ ),
+ self::cache_to_phpTemp => array( 'memoryCacheSize' => '1MB'
+ ),
+ self::cache_to_discISAM => array( 'dir' => null
+ ),
+ self::cache_to_apc => array( 'cacheTime' => 600
+ ),
+ self::cache_to_memcache => array( 'memcacheServer' => 'localhost',
+ 'memcachePort' => 11211,
+ 'cacheTime' => 600
+ ),
+ self::cache_to_wincache => array( 'cacheTime' => 600
+ ),
+ self::cache_to_sqlite => array(
+ ),
+ self::cache_to_sqlite3 => array(
+ ),
+ );
+
+ /**
+ * Arguments for the active cache storage method
+ *
+ * @var array of mixed array
+ */
+ private static $storageMethodParameters = array();
+
+ /**
+ * Return the current cache storage method
+ *
+ * @return string|null
+ **/
+ public static function getCacheStorageMethod()
+ {
+ return self::$cacheStorageMethod;
+ }
+
+ /**
+ * Return the current cache storage class
+ *
+ * @return PHPExcel_CachedObjectStorage_ICache|null
+ **/
+ public static function getCacheStorageClass()
+ {
+ return self::$cacheStorageClass;
+ }
+
+ /**
+ * Return the list of all possible cache storage methods
+ *
+ * @return string[]
+ **/
+ public static function getAllCacheStorageMethods()
+ {
+ return self::$storageMethods;
+ }
+
+ /**
+ * Return the list of all available cache storage methods
+ *
+ * @return string[]
+ **/
+ public static function getCacheStorageMethods()
+ {
+ $activeMethods = array();
+ foreach (self::$storageMethods as $storageMethod) {
+ $cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $storageMethod;
+ if (call_user_func(array($cacheStorageClass, 'cacheMethodIsAvailable'))) {
+ $activeMethods[] = $storageMethod;
+ }
+ }
+ return $activeMethods;
+ }
+
+ /**
+ * Identify the cache storage method to use
+ *
+ * @param string $method Name of the method to use for cell cacheing
+ * @param array of mixed $arguments Additional arguments to pass to the cell caching class
+ * when instantiating
+ * @return boolean
+ **/
+ public static function initialize($method = self::cache_in_memory, $arguments = array())
+ {
+ if (!in_array($method, self::$storageMethods)) {
+ return false;
+ }
+
+ $cacheStorageClass = 'PHPExcel_CachedObjectStorage_'.$method;
+ if (!call_user_func(array( $cacheStorageClass,
+ 'cacheMethodIsAvailable'))) {
+ return false;
+ }
+
+ self::$storageMethodParameters[$method] = self::$storageMethodDefaultParameters[$method];
+ foreach ($arguments as $k => $v) {
+ if (array_key_exists($k, self::$storageMethodParameters[$method])) {
+ self::$storageMethodParameters[$method][$k] = $v;
+ }
+ }
+
+ if (self::$cacheStorageMethod === null) {
+ self::$cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $method;
+ self::$cacheStorageMethod = $method;
+ }
+ return true;
+ }
+
+ /**
+ * Initialise the cache storage
+ *
+ * @param PHPExcel_Worksheet $parent Enable cell caching for this worksheet
+ * @return PHPExcel_CachedObjectStorage_ICache
+ **/
+ public static function getInstance(PHPExcel_Worksheet $parent)
+ {
+ $cacheMethodIsAvailable = true;
+ if (self::$cacheStorageMethod === null) {
+ $cacheMethodIsAvailable = self::initialize();
+ }
+
+ if ($cacheMethodIsAvailable) {
+ $instance = new self::$cacheStorageClass(
+ $parent,
+ self::$storageMethodParameters[self::$cacheStorageMethod]
+ );
+ if ($instance !== null) {
+ return $instance;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Clear the cache storage
+ *
+ **/
+ public static function finalize()
+ {
+ self::$cacheStorageMethod = null;
+ self::$cacheStorageClass = null;
+ self::$storageMethodParameters = array();
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CalcEngine/CyclicReferenceStack.php b/extend/PHPExcel/PHPExcel/CalcEngine/CyclicReferenceStack.php
new file mode 100755
index 0000000..1072fc7
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CalcEngine/CyclicReferenceStack.php
@@ -0,0 +1,94 @@
+stack);
+ }
+
+ /**
+ * Push a new entry onto the stack
+ *
+ * @param mixed $value
+ */
+ public function push($value)
+ {
+ $this->stack[$value] = $value;
+ }
+
+ /**
+ * Pop the last entry from the stack
+ *
+ * @return mixed
+ */
+ public function pop()
+ {
+ return array_pop($this->stack);
+ }
+
+ /**
+ * Test to see if a specified entry exists on the stack
+ *
+ * @param mixed $value The value to test
+ */
+ public function onStack($value)
+ {
+ return isset($this->stack[$value]);
+ }
+
+ /**
+ * Clear the stack
+ */
+ public function clear()
+ {
+ $this->stack = array();
+ }
+
+ /**
+ * Return an array of all entries on the stack
+ *
+ * @return mixed[]
+ */
+ public function showStack()
+ {
+ return $this->stack;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/CalcEngine/Logger.php b/extend/PHPExcel/PHPExcel/CalcEngine/Logger.php
new file mode 100755
index 0000000..c5ffe73
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/CalcEngine/Logger.php
@@ -0,0 +1,151 @@
+cellStack = $stack;
+ }
+
+ /**
+ * Enable/Disable Calculation engine logging
+ *
+ * @param boolean $pValue
+ */
+ public function setWriteDebugLog($pValue = false)
+ {
+ $this->writeDebugLog = $pValue;
+ }
+
+ /**
+ * Return whether calculation engine logging is enabled or disabled
+ *
+ * @return boolean
+ */
+ public function getWriteDebugLog()
+ {
+ return $this->writeDebugLog;
+ }
+
+ /**
+ * Enable/Disable echoing of debug log information
+ *
+ * @param boolean $pValue
+ */
+ public function setEchoDebugLog($pValue = false)
+ {
+ $this->echoDebugLog = $pValue;
+ }
+
+ /**
+ * Return whether echoing of debug log information is enabled or disabled
+ *
+ * @return boolean
+ */
+ public function getEchoDebugLog()
+ {
+ return $this->echoDebugLog;
+ }
+
+ /**
+ * Write an entry to the calculation engine debug log
+ */
+ public function writeDebugLog()
+ {
+ // Only write the debug log if logging is enabled
+ if ($this->writeDebugLog) {
+ $message = implode(func_get_args());
+ $cellReference = implode(' -> ', $this->cellStack->showStack());
+ if ($this->echoDebugLog) {
+ echo $cellReference,
+ ($this->cellStack->count() > 0 ? ' => ' : ''),
+ $message,
+ PHP_EOL;
+ }
+ $this->debugLog[] = $cellReference .
+ ($this->cellStack->count() > 0 ? ' => ' : '') .
+ $message;
+ }
+ }
+
+ /**
+ * Clear the calculation engine debug log
+ */
+ public function clearLog()
+ {
+ $this->debugLog = array();
+ }
+
+ /**
+ * Return the calculation engine debug log
+ *
+ * @return string[]
+ */
+ public function getLog()
+ {
+ return $this->debugLog;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation.php b/extend/PHPExcel/PHPExcel/Calculation.php
new file mode 100755
index 0000000..20b1ec3
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation.php
@@ -0,0 +1,4391 @@
+=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d{1,7})');
+ // Named Range of cells
+ define('CALCULATION_REGEXP_NAMEDRANGE', '((([^\s,!&%^\/\*\+<>=-]*)|(\'[^\']*\')|(\"[^\"]*\"))!)?([_A-Z][_A-Z0-9\.]*)');
+ } else {
+ // Cell reference (cell or range of cells, with or without a sheet reference)
+ define('CALCULATION_REGEXP_CELLREF', '(((\w*)|(\'[^\']*\')|(\"[^\"]*\"))!)?\$?([a-z]{1,3})\$?(\d+)');
+ // Named Range of cells
+ define('CALCULATION_REGEXP_NAMEDRANGE', '(((\w*)|(\'.*\')|(\".*\"))!)?([_A-Z][_A-Z0-9\.]*)');
+ }
+}
+
+/**
+ * PHPExcel_Calculation (Multiton)
+ *
+ * Copyright (c) 2006 - 2015 PHPExcel
+ *
+ * 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
+ *
+ * @category PHPExcel
+ * @package PHPExcel_Calculation
+ * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ * @version ##VERSION##, ##DATE##
+ */
+class PHPExcel_Calculation
+{
+ /** Constants */
+ /** Regular Expressions */
+ // Numeric operand
+ const CALCULATION_REGEXP_NUMBER = '[-+]?\d*\.?\d+(e[-+]?\d+)?';
+ // String operand
+ const CALCULATION_REGEXP_STRING = '"(?:[^"]|"")*"';
+ // Opening bracket
+ const CALCULATION_REGEXP_OPENBRACE = '\(';
+ // Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it)
+ const CALCULATION_REGEXP_FUNCTION = '@?([A-Z][A-Z0-9\.]*)[\s]*\(';
+ // Cell reference (cell or range of cells, with or without a sheet reference)
+ const CALCULATION_REGEXP_CELLREF = CALCULATION_REGEXP_CELLREF;
+ // Named Range of cells
+ const CALCULATION_REGEXP_NAMEDRANGE = CALCULATION_REGEXP_NAMEDRANGE;
+ // Error
+ const CALCULATION_REGEXP_ERROR = '\#[A-Z][A-Z0_\/]*[!\?]?';
+
+
+ /** constants */
+ const RETURN_ARRAY_AS_ERROR = 'error';
+ const RETURN_ARRAY_AS_VALUE = 'value';
+ const RETURN_ARRAY_AS_ARRAY = 'array';
+
+ private static $returnArrayAsType = self::RETURN_ARRAY_AS_VALUE;
+
+
+ /**
+ * Instance of this class
+ *
+ * @access private
+ * @var PHPExcel_Calculation
+ */
+ private static $instance;
+
+
+ /**
+ * Instance of the workbook this Calculation Engine is using
+ *
+ * @access private
+ * @var PHPExcel
+ */
+ private $workbook;
+
+ /**
+ * List of instances of the calculation engine that we've instantiated for individual workbooks
+ *
+ * @access private
+ * @var PHPExcel_Calculation[]
+ */
+ private static $workbookSets;
+
+ /**
+ * Calculation cache
+ *
+ * @access private
+ * @var array
+ */
+ private $calculationCache = array ();
+
+
+ /**
+ * Calculation cache enabled
+ *
+ * @access private
+ * @var boolean
+ */
+ private $calculationCacheEnabled = true;
+
+
+ /**
+ * List of operators that can be used within formulae
+ * The true/false value indicates whether it is a binary operator or a unary operator
+ *
+ * @access private
+ * @var array
+ */
+ private static $operators = array(
+ '+' => true, '-' => true, '*' => true, '/' => true,
+ '^' => true, '&' => true, '%' => false, '~' => false,
+ '>' => true, '<' => true, '=' => true, '>=' => true,
+ '<=' => true, '<>' => true, '|' => true, ':' => true
+ );
+
+ /**
+ * List of binary operators (those that expect two operands)
+ *
+ * @access private
+ * @var array
+ */
+ private static $binaryOperators = array(
+ '+' => true, '-' => true, '*' => true, '/' => true,
+ '^' => true, '&' => true, '>' => true, '<' => true,
+ '=' => true, '>=' => true, '<=' => true, '<>' => true,
+ '|' => true, ':' => true
+ );
+
+ /**
+ * The debug log generated by the calculation engine
+ *
+ * @access private
+ * @var PHPExcel_CalcEngine_Logger
+ *
+ */
+ private $debugLog;
+
+ /**
+ * Flag to determine how formula errors should be handled
+ * If true, then a user error will be triggered
+ * If false, then an exception will be thrown
+ *
+ * @access public
+ * @var boolean
+ *
+ */
+ public $suppressFormulaErrors = false;
+
+ /**
+ * Error message for any error that was raised/thrown by the calculation engine
+ *
+ * @access public
+ * @var string
+ *
+ */
+ public $formulaError = null;
+
+ /**
+ * An array of the nested cell references accessed by the calculation engine, used for the debug log
+ *
+ * @access private
+ * @var array of string
+ *
+ */
+ private $cyclicReferenceStack;
+
+ private $cellStack = array();
+
+ /**
+ * Current iteration counter for cyclic formulae
+ * If the value is 0 (or less) then cyclic formulae will throw an exception,
+ * otherwise they will iterate to the limit defined here before returning a result
+ *
+ * @var integer
+ *
+ */
+ private $cyclicFormulaCounter = 1;
+
+ private $cyclicFormulaCell = '';
+
+ /**
+ * Number of iterations for cyclic formulae
+ *
+ * @var integer
+ *
+ */
+ public $cyclicFormulaCount = 1;
+
+ /**
+ * Epsilon Precision used for comparisons in calculations
+ *
+ * @var float
+ *
+ */
+ private $delta = 0.1e-12;
+
+
+ /**
+ * The current locale setting
+ *
+ * @var string
+ *
+ */
+ private static $localeLanguage = 'en_us'; // US English (default locale)
+
+ /**
+ * List of available locale settings
+ * Note that this is read for the locale subdirectory only when requested
+ *
+ * @var string[]
+ *
+ */
+ private static $validLocaleLanguages = array(
+ 'en' // English (default language)
+ );
+
+ /**
+ * Locale-specific argument separator for function arguments
+ *
+ * @var string
+ *
+ */
+ private static $localeArgumentSeparator = ',';
+ private static $localeFunctions = array();
+
+ /**
+ * Locale-specific translations for Excel constants (True, False and Null)
+ *
+ * @var string[]
+ *
+ */
+ public static $localeBoolean = array(
+ 'TRUE' => 'TRUE',
+ 'FALSE' => 'FALSE',
+ 'NULL' => 'NULL'
+ );
+
+ /**
+ * Excel constant string translations to their PHP equivalents
+ * Constant conversion from text name/value to actual (datatyped) value
+ *
+ * @var string[]
+ *
+ */
+ private static $excelConstants = array(
+ 'TRUE' => true,
+ 'FALSE' => false,
+ 'NULL' => null
+ );
+
+ // PHPExcel functions
+ private static $PHPExcelFunctions = array(
+ 'ABS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'abs',
+ 'argumentCount' => '1'
+ ),
+ 'ACCRINT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINT',
+ 'argumentCount' => '4-7'
+ ),
+ 'ACCRINTM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::ACCRINTM',
+ 'argumentCount' => '3-5'
+ ),
+ 'ACOS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'acos',
+ 'argumentCount' => '1'
+ ),
+ 'ACOSH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'acosh',
+ 'argumentCount' => '1'
+ ),
+ 'ADDRESS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::CELL_ADDRESS',
+ 'argumentCount' => '2-5'
+ ),
+ 'AMORDEGRC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::AMORDEGRC',
+ 'argumentCount' => '6,7'
+ ),
+ 'AMORLINC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::AMORLINC',
+ 'argumentCount' => '6,7'
+ ),
+ 'AND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_AND',
+ 'argumentCount' => '1+'
+ ),
+ 'AREAS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'ASC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'ASIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'asin',
+ 'argumentCount' => '1'
+ ),
+ 'ASINH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'asinh',
+ 'argumentCount' => '1'
+ ),
+ 'ATAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'atan',
+ 'argumentCount' => '1'
+ ),
+ 'ATAN2' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::ATAN2',
+ 'argumentCount' => '2'
+ ),
+ 'ATANH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'atanh',
+ 'argumentCount' => '1'
+ ),
+ 'AVEDEV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::AVEDEV',
+ 'argumentCount' => '1+'
+ ),
+ 'AVERAGE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGE',
+ 'argumentCount' => '1+'
+ ),
+ 'AVERAGEA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEA',
+ 'argumentCount' => '1+'
+ ),
+ 'AVERAGEIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::AVERAGEIF',
+ 'argumentCount' => '2,3'
+ ),
+ 'AVERAGEIFS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '3+'
+ ),
+ 'BAHTTEXT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'BESSELI' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELI',
+ 'argumentCount' => '2'
+ ),
+ 'BESSELJ' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELJ',
+ 'argumentCount' => '2'
+ ),
+ 'BESSELK' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELK',
+ 'argumentCount' => '2'
+ ),
+ 'BESSELY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BESSELY',
+ 'argumentCount' => '2'
+ ),
+ 'BETADIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::BETADIST',
+ 'argumentCount' => '3-5'
+ ),
+ 'BETAINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::BETAINV',
+ 'argumentCount' => '3-5'
+ ),
+ 'BIN2DEC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTODEC',
+ 'argumentCount' => '1'
+ ),
+ 'BIN2HEX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOHEX',
+ 'argumentCount' => '1,2'
+ ),
+ 'BIN2OCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::BINTOOCT',
+ 'argumentCount' => '1,2'
+ ),
+ 'BINOMDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::BINOMDIST',
+ 'argumentCount' => '4'
+ ),
+ 'CEILING' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::CEILING',
+ 'argumentCount' => '2'
+ ),
+ 'CELL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1,2'
+ ),
+ 'CHAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::CHARACTER',
+ 'argumentCount' => '1'
+ ),
+ 'CHIDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::CHIDIST',
+ 'argumentCount' => '2'
+ ),
+ 'CHIINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::CHIINV',
+ 'argumentCount' => '2'
+ ),
+ 'CHITEST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2'
+ ),
+ 'CHOOSE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::CHOOSE',
+ 'argumentCount' => '2+'
+ ),
+ 'CLEAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::TRIMNONPRINTABLE',
+ 'argumentCount' => '1'
+ ),
+ 'CODE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::ASCIICODE',
+ 'argumentCount' => '1'
+ ),
+ 'COLUMN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMN',
+ 'argumentCount' => '-1',
+ 'passByReference' => array(true)
+ ),
+ 'COLUMNS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::COLUMNS',
+ 'argumentCount' => '1'
+ ),
+ 'COMBIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::COMBIN',
+ 'argumentCount' => '2'
+ ),
+ 'COMPLEX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::COMPLEX',
+ 'argumentCount' => '2,3'
+ ),
+ 'CONCATENATE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::CONCATENATE',
+ 'argumentCount' => '1+'
+ ),
+ 'CONFIDENCE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::CONFIDENCE',
+ 'argumentCount' => '3'
+ ),
+ 'CONVERT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::CONVERTUOM',
+ 'argumentCount' => '3'
+ ),
+ 'CORREL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL',
+ 'argumentCount' => '2'
+ ),
+ 'COS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'cos',
+ 'argumentCount' => '1'
+ ),
+ 'COSH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'cosh',
+ 'argumentCount' => '1'
+ ),
+ 'COUNT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNT',
+ 'argumentCount' => '1+'
+ ),
+ 'COUNTA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTA',
+ 'argumentCount' => '1+'
+ ),
+ 'COUNTBLANK' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTBLANK',
+ 'argumentCount' => '1'
+ ),
+ 'COUNTIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::COUNTIF',
+ 'argumentCount' => '2'
+ ),
+ 'COUNTIFS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2'
+ ),
+ 'COUPDAYBS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYBS',
+ 'argumentCount' => '3,4'
+ ),
+ 'COUPDAYS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYS',
+ 'argumentCount' => '3,4'
+ ),
+ 'COUPDAYSNC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::COUPDAYSNC',
+ 'argumentCount' => '3,4'
+ ),
+ 'COUPNCD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::COUPNCD',
+ 'argumentCount' => '3,4'
+ ),
+ 'COUPNUM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::COUPNUM',
+ 'argumentCount' => '3,4'
+ ),
+ 'COUPPCD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::COUPPCD',
+ 'argumentCount' => '3,4'
+ ),
+ 'COVAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::COVAR',
+ 'argumentCount' => '2'
+ ),
+ 'CRITBINOM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::CRITBINOM',
+ 'argumentCount' => '3'
+ ),
+ 'CUBEKPIMEMBER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUBEMEMBER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUBEMEMBERPROPERTY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUBERANKEDMEMBER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUBESET' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUBESETCOUNT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUBEVALUE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_CUBE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '?'
+ ),
+ 'CUMIPMT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::CUMIPMT',
+ 'argumentCount' => '6'
+ ),
+ 'CUMPRINC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::CUMPRINC',
+ 'argumentCount' => '6'
+ ),
+ 'DATE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DATE',
+ 'argumentCount' => '3'
+ ),
+ 'DATEDIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DATEDIF',
+ 'argumentCount' => '2,3'
+ ),
+ 'DATEVALUE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DATEVALUE',
+ 'argumentCount' => '1'
+ ),
+ 'DAVERAGE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DAVERAGE',
+ 'argumentCount' => '3'
+ ),
+ 'DAY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFMONTH',
+ 'argumentCount' => '1'
+ ),
+ 'DAYS360' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYS360',
+ 'argumentCount' => '2,3'
+ ),
+ 'DB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::DB',
+ 'argumentCount' => '4,5'
+ ),
+ 'DCOUNT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DCOUNT',
+ 'argumentCount' => '3'
+ ),
+ 'DCOUNTA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DCOUNTA',
+ 'argumentCount' => '3'
+ ),
+ 'DDB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::DDB',
+ 'argumentCount' => '4,5'
+ ),
+ 'DEC2BIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOBIN',
+ 'argumentCount' => '1,2'
+ ),
+ 'DEC2HEX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOHEX',
+ 'argumentCount' => '1,2'
+ ),
+ 'DEC2OCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::DECTOOCT',
+ 'argumentCount' => '1,2'
+ ),
+ 'DEGREES' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'rad2deg',
+ 'argumentCount' => '1'
+ ),
+ 'DELTA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::DELTA',
+ 'argumentCount' => '1,2'
+ ),
+ 'DEVSQ' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::DEVSQ',
+ 'argumentCount' => '1+'
+ ),
+ 'DGET' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DGET',
+ 'argumentCount' => '3'
+ ),
+ 'DISC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::DISC',
+ 'argumentCount' => '4,5'
+ ),
+ 'DMAX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DMAX',
+ 'argumentCount' => '3'
+ ),
+ 'DMIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DMIN',
+ 'argumentCount' => '3'
+ ),
+ 'DOLLAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::DOLLAR',
+ 'argumentCount' => '1,2'
+ ),
+ 'DOLLARDE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARDE',
+ 'argumentCount' => '2'
+ ),
+ 'DOLLARFR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::DOLLARFR',
+ 'argumentCount' => '2'
+ ),
+ 'DPRODUCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DPRODUCT',
+ 'argumentCount' => '3'
+ ),
+ 'DSTDEV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DSTDEV',
+ 'argumentCount' => '3'
+ ),
+ 'DSTDEVP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DSTDEVP',
+ 'argumentCount' => '3'
+ ),
+ 'DSUM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DSUM',
+ 'argumentCount' => '3'
+ ),
+ 'DURATION' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '5,6'
+ ),
+ 'DVAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DVAR',
+ 'argumentCount' => '3'
+ ),
+ 'DVARP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATABASE,
+ 'functionCall' => 'PHPExcel_Calculation_Database::DVARP',
+ 'argumentCount' => '3'
+ ),
+ 'EDATE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::EDATE',
+ 'argumentCount' => '2'
+ ),
+ 'EFFECT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::EFFECT',
+ 'argumentCount' => '2'
+ ),
+ 'EOMONTH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::EOMONTH',
+ 'argumentCount' => '2'
+ ),
+ 'ERF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::ERF',
+ 'argumentCount' => '1,2'
+ ),
+ 'ERFC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::ERFC',
+ 'argumentCount' => '1'
+ ),
+ 'ERROR.TYPE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::ERROR_TYPE',
+ 'argumentCount' => '1'
+ ),
+ 'EVEN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::EVEN',
+ 'argumentCount' => '1'
+ ),
+ 'EXACT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2'
+ ),
+ 'EXP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'exp',
+ 'argumentCount' => '1'
+ ),
+ 'EXPONDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::EXPONDIST',
+ 'argumentCount' => '3'
+ ),
+ 'FACT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::FACT',
+ 'argumentCount' => '1'
+ ),
+ 'FACTDOUBLE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::FACTDOUBLE',
+ 'argumentCount' => '1'
+ ),
+ 'FALSE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::FALSE',
+ 'argumentCount' => '0'
+ ),
+ 'FDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '3'
+ ),
+ 'FIND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE',
+ 'argumentCount' => '2,3'
+ ),
+ 'FINDB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHSENSITIVE',
+ 'argumentCount' => '2,3'
+ ),
+ 'FINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '3'
+ ),
+ 'FISHER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::FISHER',
+ 'argumentCount' => '1'
+ ),
+ 'FISHERINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::FISHERINV',
+ 'argumentCount' => '1'
+ ),
+ 'FIXED' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::FIXEDFORMAT',
+ 'argumentCount' => '1-3'
+ ),
+ 'FLOOR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::FLOOR',
+ 'argumentCount' => '2'
+ ),
+ 'FORECAST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::FORECAST',
+ 'argumentCount' => '3'
+ ),
+ 'FREQUENCY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2'
+ ),
+ 'FTEST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2'
+ ),
+ 'FV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::FV',
+ 'argumentCount' => '3-5'
+ ),
+ 'FVSCHEDULE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::FVSCHEDULE',
+ 'argumentCount' => '2'
+ ),
+ 'GAMMADIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMADIST',
+ 'argumentCount' => '4'
+ ),
+ 'GAMMAINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMAINV',
+ 'argumentCount' => '3'
+ ),
+ 'GAMMALN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::GAMMALN',
+ 'argumentCount' => '1'
+ ),
+ 'GCD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::GCD',
+ 'argumentCount' => '1+'
+ ),
+ 'GEOMEAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::GEOMEAN',
+ 'argumentCount' => '1+'
+ ),
+ 'GESTEP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::GESTEP',
+ 'argumentCount' => '1,2'
+ ),
+ 'GETPIVOTDATA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2+'
+ ),
+ 'GROWTH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::GROWTH',
+ 'argumentCount' => '1-4'
+ ),
+ 'HARMEAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::HARMEAN',
+ 'argumentCount' => '1+'
+ ),
+ 'HEX2BIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOBIN',
+ 'argumentCount' => '1,2'
+ ),
+ 'HEX2DEC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTODEC',
+ 'argumentCount' => '1'
+ ),
+ 'HEX2OCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::HEXTOOCT',
+ 'argumentCount' => '1,2'
+ ),
+ 'HLOOKUP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::HLOOKUP',
+ 'argumentCount' => '3,4'
+ ),
+ 'HOUR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::HOUROFDAY',
+ 'argumentCount' => '1'
+ ),
+ 'HYPERLINK' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::HYPERLINK',
+ 'argumentCount' => '1,2',
+ 'passCellReference' => true
+ ),
+ 'HYPGEOMDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::HYPGEOMDIST',
+ 'argumentCount' => '4'
+ ),
+ 'IF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::STATEMENT_IF',
+ 'argumentCount' => '1-3'
+ ),
+ 'IFERROR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::IFERROR',
+ 'argumentCount' => '2'
+ ),
+ 'IMABS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMABS',
+ 'argumentCount' => '1'
+ ),
+ 'IMAGINARY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMAGINARY',
+ 'argumentCount' => '1'
+ ),
+ 'IMARGUMENT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMARGUMENT',
+ 'argumentCount' => '1'
+ ),
+ 'IMCONJUGATE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMCONJUGATE',
+ 'argumentCount' => '1'
+ ),
+ 'IMCOS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMCOS',
+ 'argumentCount' => '1'
+ ),
+ 'IMDIV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMDIV',
+ 'argumentCount' => '2'
+ ),
+ 'IMEXP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMEXP',
+ 'argumentCount' => '1'
+ ),
+ 'IMLN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLN',
+ 'argumentCount' => '1'
+ ),
+ 'IMLOG10' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG10',
+ 'argumentCount' => '1'
+ ),
+ 'IMLOG2' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMLOG2',
+ 'argumentCount' => '1'
+ ),
+ 'IMPOWER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMPOWER',
+ 'argumentCount' => '2'
+ ),
+ 'IMPRODUCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMPRODUCT',
+ 'argumentCount' => '1+'
+ ),
+ 'IMREAL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMREAL',
+ 'argumentCount' => '1'
+ ),
+ 'IMSIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSIN',
+ 'argumentCount' => '1'
+ ),
+ 'IMSQRT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSQRT',
+ 'argumentCount' => '1'
+ ),
+ 'IMSUB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUB',
+ 'argumentCount' => '2'
+ ),
+ 'IMSUM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::IMSUM',
+ 'argumentCount' => '1+'
+ ),
+ 'INDEX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDEX',
+ 'argumentCount' => '1-4'
+ ),
+ 'INDIRECT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::INDIRECT',
+ 'argumentCount' => '1,2',
+ 'passCellReference' => true
+ ),
+ 'INFO' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'INT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::INT',
+ 'argumentCount' => '1'
+ ),
+ 'INTERCEPT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::INTERCEPT',
+ 'argumentCount' => '2'
+ ),
+ 'INTRATE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::INTRATE',
+ 'argumentCount' => '4,5'
+ ),
+ 'IPMT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::IPMT',
+ 'argumentCount' => '4-6'
+ ),
+ 'IRR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::IRR',
+ 'argumentCount' => '1,2'
+ ),
+ 'ISBLANK' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_BLANK',
+ 'argumentCount' => '1'
+ ),
+ 'ISERR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERR',
+ 'argumentCount' => '1'
+ ),
+ 'ISERROR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_ERROR',
+ 'argumentCount' => '1'
+ ),
+ 'ISEVEN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_EVEN',
+ 'argumentCount' => '1'
+ ),
+ 'ISLOGICAL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_LOGICAL',
+ 'argumentCount' => '1'
+ ),
+ 'ISNA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_NA',
+ 'argumentCount' => '1'
+ ),
+ 'ISNONTEXT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_NONTEXT',
+ 'argumentCount' => '1'
+ ),
+ 'ISNUMBER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_NUMBER',
+ 'argumentCount' => '1'
+ ),
+ 'ISODD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_ODD',
+ 'argumentCount' => '1'
+ ),
+ 'ISPMT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::ISPMT',
+ 'argumentCount' => '4'
+ ),
+ 'ISREF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'ISTEXT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::IS_TEXT',
+ 'argumentCount' => '1'
+ ),
+ 'JIS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'KURT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::KURT',
+ 'argumentCount' => '1+'
+ ),
+ 'LARGE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::LARGE',
+ 'argumentCount' => '2'
+ ),
+ 'LCM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::LCM',
+ 'argumentCount' => '1+'
+ ),
+ 'LEFT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::LEFT',
+ 'argumentCount' => '1,2'
+ ),
+ 'LEFTB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::LEFT',
+ 'argumentCount' => '1,2'
+ ),
+ 'LEN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH',
+ 'argumentCount' => '1'
+ ),
+ 'LENB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::STRINGLENGTH',
+ 'argumentCount' => '1'
+ ),
+ 'LINEST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::LINEST',
+ 'argumentCount' => '1-4'
+ ),
+ 'LN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'log',
+ 'argumentCount' => '1'
+ ),
+ 'LOG' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::LOG_BASE',
+ 'argumentCount' => '1,2'
+ ),
+ 'LOG10' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'log10',
+ 'argumentCount' => '1'
+ ),
+ 'LOGEST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGEST',
+ 'argumentCount' => '1-4'
+ ),
+ 'LOGINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGINV',
+ 'argumentCount' => '3'
+ ),
+ 'LOGNORMDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::LOGNORMDIST',
+ 'argumentCount' => '3'
+ ),
+ 'LOOKUP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::LOOKUP',
+ 'argumentCount' => '2,3'
+ ),
+ 'LOWER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::LOWERCASE',
+ 'argumentCount' => '1'
+ ),
+ 'MATCH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::MATCH',
+ 'argumentCount' => '2,3'
+ ),
+ 'MAX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MAX',
+ 'argumentCount' => '1+'
+ ),
+ 'MAXA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MAXA',
+ 'argumentCount' => '1+'
+ ),
+ 'MAXIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MAXIF',
+ 'argumentCount' => '2+'
+ ),
+ 'MDETERM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::MDETERM',
+ 'argumentCount' => '1'
+ ),
+ 'MDURATION' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '5,6'
+ ),
+ 'MEDIAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MEDIAN',
+ 'argumentCount' => '1+'
+ ),
+ 'MEDIANIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2+'
+ ),
+ 'MID' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::MID',
+ 'argumentCount' => '3'
+ ),
+ 'MIDB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::MID',
+ 'argumentCount' => '3'
+ ),
+ 'MIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MIN',
+ 'argumentCount' => '1+'
+ ),
+ 'MINA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MINA',
+ 'argumentCount' => '1+'
+ ),
+ 'MINIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MINIF',
+ 'argumentCount' => '2+'
+ ),
+ 'MINUTE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::MINUTEOFHOUR',
+ 'argumentCount' => '1'
+ ),
+ 'MINVERSE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::MINVERSE',
+ 'argumentCount' => '1'
+ ),
+ 'MIRR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::MIRR',
+ 'argumentCount' => '3'
+ ),
+ 'MMULT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::MMULT',
+ 'argumentCount' => '2'
+ ),
+ 'MOD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::MOD',
+ 'argumentCount' => '2'
+ ),
+ 'MODE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::MODE',
+ 'argumentCount' => '1+'
+ ),
+ 'MONTH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::MONTHOFYEAR',
+ 'argumentCount' => '1'
+ ),
+ 'MROUND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::MROUND',
+ 'argumentCount' => '2'
+ ),
+ 'MULTINOMIAL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::MULTINOMIAL',
+ 'argumentCount' => '1+'
+ ),
+ 'N' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::N',
+ 'argumentCount' => '1'
+ ),
+ 'NA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::NA',
+ 'argumentCount' => '0'
+ ),
+ 'NEGBINOMDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::NEGBINOMDIST',
+ 'argumentCount' => '3'
+ ),
+ 'NETWORKDAYS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::NETWORKDAYS',
+ 'argumentCount' => '2+'
+ ),
+ 'NOMINAL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::NOMINAL',
+ 'argumentCount' => '2'
+ ),
+ 'NORMDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMDIST',
+ 'argumentCount' => '4'
+ ),
+ 'NORMINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMINV',
+ 'argumentCount' => '3'
+ ),
+ 'NORMSDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSDIST',
+ 'argumentCount' => '1'
+ ),
+ 'NORMSINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::NORMSINV',
+ 'argumentCount' => '1'
+ ),
+ 'NOT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::NOT',
+ 'argumentCount' => '1'
+ ),
+ 'NOW' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DATETIMENOW',
+ 'argumentCount' => '0'
+ ),
+ 'NPER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::NPER',
+ 'argumentCount' => '3-5'
+ ),
+ 'NPV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::NPV',
+ 'argumentCount' => '2+'
+ ),
+ 'OCT2BIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOBIN',
+ 'argumentCount' => '1,2'
+ ),
+ 'OCT2DEC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTODEC',
+ 'argumentCount' => '1'
+ ),
+ 'OCT2HEX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_ENGINEERING,
+ 'functionCall' => 'PHPExcel_Calculation_Engineering::OCTTOHEX',
+ 'argumentCount' => '1,2'
+ ),
+ 'ODD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::ODD',
+ 'argumentCount' => '1'
+ ),
+ 'ODDFPRICE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '8,9'
+ ),
+ 'ODDFYIELD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '8,9'
+ ),
+ 'ODDLPRICE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '7,8'
+ ),
+ 'ODDLYIELD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '7,8'
+ ),
+ 'OFFSET' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::OFFSET',
+ 'argumentCount' => '3-5',
+ 'passCellReference' => true,
+ 'passByReference' => array(true)
+ ),
+ 'OR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::LOGICAL_OR',
+ 'argumentCount' => '1+'
+ ),
+ 'PEARSON' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::CORREL',
+ 'argumentCount' => '2'
+ ),
+ 'PERCENTILE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTILE',
+ 'argumentCount' => '2'
+ ),
+ 'PERCENTRANK' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::PERCENTRANK',
+ 'argumentCount' => '2,3'
+ ),
+ 'PERMUT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::PERMUT',
+ 'argumentCount' => '2'
+ ),
+ 'PHONETIC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1'
+ ),
+ 'PI' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'pi',
+ 'argumentCount' => '0'
+ ),
+ 'PMT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::PMT',
+ 'argumentCount' => '3-5'
+ ),
+ 'POISSON' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::POISSON',
+ 'argumentCount' => '3'
+ ),
+ 'POWER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::POWER',
+ 'argumentCount' => '2'
+ ),
+ 'PPMT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::PPMT',
+ 'argumentCount' => '4-6'
+ ),
+ 'PRICE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::PRICE',
+ 'argumentCount' => '6,7'
+ ),
+ 'PRICEDISC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::PRICEDISC',
+ 'argumentCount' => '4,5'
+ ),
+ 'PRICEMAT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::PRICEMAT',
+ 'argumentCount' => '5,6'
+ ),
+ 'PROB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '3,4'
+ ),
+ 'PRODUCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::PRODUCT',
+ 'argumentCount' => '1+'
+ ),
+ 'PROPER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::PROPERCASE',
+ 'argumentCount' => '1'
+ ),
+ 'PV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::PV',
+ 'argumentCount' => '3-5'
+ ),
+ 'QUARTILE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::QUARTILE',
+ 'argumentCount' => '2'
+ ),
+ 'QUOTIENT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::QUOTIENT',
+ 'argumentCount' => '2'
+ ),
+ 'RADIANS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'deg2rad',
+ 'argumentCount' => '1'
+ ),
+ 'RAND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND',
+ 'argumentCount' => '0'
+ ),
+ 'RANDBETWEEN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::RAND',
+ 'argumentCount' => '2'
+ ),
+ 'RANK' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::RANK',
+ 'argumentCount' => '2,3'
+ ),
+ 'RATE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::RATE',
+ 'argumentCount' => '3-6'
+ ),
+ 'RECEIVED' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::RECEIVED',
+ 'argumentCount' => '4-5'
+ ),
+ 'REPLACE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE',
+ 'argumentCount' => '4'
+ ),
+ 'REPLACEB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::REPLACE',
+ 'argumentCount' => '4'
+ ),
+ 'REPT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'str_repeat',
+ 'argumentCount' => '2'
+ ),
+ 'RIGHT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT',
+ 'argumentCount' => '1,2'
+ ),
+ 'RIGHTB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::RIGHT',
+ 'argumentCount' => '1,2'
+ ),
+ 'ROMAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROMAN',
+ 'argumentCount' => '1,2'
+ ),
+ 'ROUND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'round',
+ 'argumentCount' => '2'
+ ),
+ 'ROUNDDOWN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDDOWN',
+ 'argumentCount' => '2'
+ ),
+ 'ROUNDUP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::ROUNDUP',
+ 'argumentCount' => '2'
+ ),
+ 'ROW' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROW',
+ 'argumentCount' => '-1',
+ 'passByReference' => array(true)
+ ),
+ 'ROWS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::ROWS',
+ 'argumentCount' => '1'
+ ),
+ 'RSQ' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::RSQ',
+ 'argumentCount' => '2'
+ ),
+ 'RTD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '1+'
+ ),
+ 'SEARCH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE',
+ 'argumentCount' => '2,3'
+ ),
+ 'SEARCHB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::SEARCHINSENSITIVE',
+ 'argumentCount' => '2,3'
+ ),
+ 'SECOND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::SECONDOFMINUTE',
+ 'argumentCount' => '1'
+ ),
+ 'SERIESSUM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SERIESSUM',
+ 'argumentCount' => '4'
+ ),
+ 'SIGN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SIGN',
+ 'argumentCount' => '1'
+ ),
+ 'SIN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'sin',
+ 'argumentCount' => '1'
+ ),
+ 'SINH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'sinh',
+ 'argumentCount' => '1'
+ ),
+ 'SKEW' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::SKEW',
+ 'argumentCount' => '1+'
+ ),
+ 'SLN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::SLN',
+ 'argumentCount' => '3'
+ ),
+ 'SLOPE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::SLOPE',
+ 'argumentCount' => '2'
+ ),
+ 'SMALL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::SMALL',
+ 'argumentCount' => '2'
+ ),
+ 'SQRT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'sqrt',
+ 'argumentCount' => '1'
+ ),
+ 'SQRTPI' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SQRTPI',
+ 'argumentCount' => '1'
+ ),
+ 'STANDARDIZE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::STANDARDIZE',
+ 'argumentCount' => '3'
+ ),
+ 'STDEV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEV',
+ 'argumentCount' => '1+'
+ ),
+ 'STDEVA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVA',
+ 'argumentCount' => '1+'
+ ),
+ 'STDEVP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVP',
+ 'argumentCount' => '1+'
+ ),
+ 'STDEVPA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::STDEVPA',
+ 'argumentCount' => '1+'
+ ),
+ 'STEYX' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::STEYX',
+ 'argumentCount' => '2'
+ ),
+ 'SUBSTITUTE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::SUBSTITUTE',
+ 'argumentCount' => '3,4'
+ ),
+ 'SUBTOTAL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUBTOTAL',
+ 'argumentCount' => '2+'
+ ),
+ 'SUM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUM',
+ 'argumentCount' => '1+'
+ ),
+ 'SUMIF' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMIF',
+ 'argumentCount' => '2,3'
+ ),
+ 'SUMIFS' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMIFS',
+ 'argumentCount' => '3+'
+ ),
+ 'SUMPRODUCT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMPRODUCT',
+ 'argumentCount' => '1+'
+ ),
+ 'SUMSQ' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMSQ',
+ 'argumentCount' => '1+'
+ ),
+ 'SUMX2MY2' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2MY2',
+ 'argumentCount' => '2'
+ ),
+ 'SUMX2PY2' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMX2PY2',
+ 'argumentCount' => '2'
+ ),
+ 'SUMXMY2' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::SUMXMY2',
+ 'argumentCount' => '2'
+ ),
+ 'SYD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::SYD',
+ 'argumentCount' => '4'
+ ),
+ 'T' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::RETURNSTRING',
+ 'argumentCount' => '1'
+ ),
+ 'TAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'tan',
+ 'argumentCount' => '1'
+ ),
+ 'TANH' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'tanh',
+ 'argumentCount' => '1'
+ ),
+ 'TBILLEQ' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLEQ',
+ 'argumentCount' => '3'
+ ),
+ 'TBILLPRICE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLPRICE',
+ 'argumentCount' => '3'
+ ),
+ 'TBILLYIELD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::TBILLYIELD',
+ 'argumentCount' => '3'
+ ),
+ 'TDIST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::TDIST',
+ 'argumentCount' => '3'
+ ),
+ 'TEXT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::TEXTFORMAT',
+ 'argumentCount' => '2'
+ ),
+ 'TIME' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::TIME',
+ 'argumentCount' => '3'
+ ),
+ 'TIMEVALUE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::TIMEVALUE',
+ 'argumentCount' => '1'
+ ),
+ 'TINV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::TINV',
+ 'argumentCount' => '2'
+ ),
+ 'TODAY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DATENOW',
+ 'argumentCount' => '0'
+ ),
+ 'TRANSPOSE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::TRANSPOSE',
+ 'argumentCount' => '1'
+ ),
+ 'TREND' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::TREND',
+ 'argumentCount' => '1-4'
+ ),
+ 'TRIM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::TRIMSPACES',
+ 'argumentCount' => '1'
+ ),
+ 'TRIMMEAN' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::TRIMMEAN',
+ 'argumentCount' => '2'
+ ),
+ 'TRUE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOGICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Logical::TRUE',
+ 'argumentCount' => '0'
+ ),
+ 'TRUNC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_MATH_AND_TRIG,
+ 'functionCall' => 'PHPExcel_Calculation_MathTrig::TRUNC',
+ 'argumentCount' => '1,2'
+ ),
+ 'TTEST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '4'
+ ),
+ 'TYPE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::TYPE',
+ 'argumentCount' => '1'
+ ),
+ 'UPPER' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::UPPERCASE',
+ 'argumentCount' => '1'
+ ),
+ 'USDOLLAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '2'
+ ),
+ 'VALUE' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_TEXT_AND_DATA,
+ 'functionCall' => 'PHPExcel_Calculation_TextData::VALUE',
+ 'argumentCount' => '1'
+ ),
+ 'VAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::VARFunc',
+ 'argumentCount' => '1+'
+ ),
+ 'VARA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::VARA',
+ 'argumentCount' => '1+'
+ ),
+ 'VARP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::VARP',
+ 'argumentCount' => '1+'
+ ),
+ 'VARPA' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::VARPA',
+ 'argumentCount' => '1+'
+ ),
+ 'VDB' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '5-7'
+ ),
+ 'VERSION' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_INFORMATION,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::VERSION',
+ 'argumentCount' => '0'
+ ),
+ 'VLOOKUP' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_LOOKUP_AND_REFERENCE,
+ 'functionCall' => 'PHPExcel_Calculation_LookupRef::VLOOKUP',
+ 'argumentCount' => '3,4'
+ ),
+ 'WEEKDAY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::DAYOFWEEK',
+ 'argumentCount' => '1,2'
+ ),
+ 'WEEKNUM' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::WEEKOFYEAR',
+ 'argumentCount' => '1,2'
+ ),
+ 'WEIBULL' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::WEIBULL',
+ 'argumentCount' => '4'
+ ),
+ 'WORKDAY' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::WORKDAY',
+ 'argumentCount' => '2+'
+ ),
+ 'XIRR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::XIRR',
+ 'argumentCount' => '2,3'
+ ),
+ 'XNPV' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::XNPV',
+ 'argumentCount' => '3'
+ ),
+ 'YEAR' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::YEAR',
+ 'argumentCount' => '1'
+ ),
+ 'YEARFRAC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_DATE_AND_TIME,
+ 'functionCall' => 'PHPExcel_Calculation_DateTime::YEARFRAC',
+ 'argumentCount' => '2,3'
+ ),
+ 'YIELD' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Functions::DUMMY',
+ 'argumentCount' => '6,7'
+ ),
+ 'YIELDDISC' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::YIELDDISC',
+ 'argumentCount' => '4,5'
+ ),
+ 'YIELDMAT' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_FINANCIAL,
+ 'functionCall' => 'PHPExcel_Calculation_Financial::YIELDMAT',
+ 'argumentCount' => '5,6'
+ ),
+ 'ZTEST' => array(
+ 'category' => PHPExcel_Calculation_Function::CATEGORY_STATISTICAL,
+ 'functionCall' => 'PHPExcel_Calculation_Statistical::ZTEST',
+ 'argumentCount' => '2-3'
+ )
+ );
+
+ // Internal functions used for special control purposes
+ private static $controlFunctions = array(
+ 'MKMATRIX' => array(
+ 'argumentCount' => '*',
+ 'functionCall' => 'self::mkMatrix'
+ )
+ );
+
+
+ public function __construct(PHPExcel $workbook = null)
+ {
+ $this->delta = 1 * pow(10, 0 - ini_get('precision'));
+
+ $this->workbook = $workbook;
+ $this->cyclicReferenceStack = new PHPExcel_CalcEngine_CyclicReferenceStack();
+ $this->_debugLog = new PHPExcel_CalcEngine_Logger($this->cyclicReferenceStack);
+ }
+
+
+ private static function loadLocales()
+ {
+ $localeFileDirectory = PHPEXCEL_ROOT.'PHPExcel/locale/';
+ foreach (glob($localeFileDirectory.'/*', GLOB_ONLYDIR) as $filename) {
+ $filename = substr($filename, strlen($localeFileDirectory)+1);
+ if ($filename != 'en') {
+ self::$validLocaleLanguages[] = $filename;
+ }
+ }
+ }
+
+ /**
+ * Get an instance of this class
+ *
+ * @access public
+ * @param PHPExcel $workbook Injected workbook for working with a PHPExcel object,
+ * or NULL to create a standalone claculation engine
+ * @return PHPExcel_Calculation
+ */
+ public static function getInstance(PHPExcel $workbook = null)
+ {
+ if ($workbook !== null) {
+ $instance = $workbook->getCalculationEngine();
+ if (isset($instance)) {
+ return $instance;
+ }
+ }
+
+ if (!isset(self::$instance) || (self::$instance === null)) {
+ self::$instance = new PHPExcel_Calculation();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Unset an instance of this class
+ *
+ * @access public
+ */
+ public function __destruct()
+ {
+ $this->workbook = null;
+ }
+
+ /**
+ * Flush the calculation cache for any existing instance of this class
+ * but only if a PHPExcel_Calculation instance exists
+ *
+ * @access public
+ * @return null
+ */
+ public function flushInstance()
+ {
+ $this->clearCalculationCache();
+ }
+
+
+ /**
+ * Get the debuglog for this claculation engine instance
+ *
+ * @access public
+ * @return PHPExcel_CalcEngine_Logger
+ */
+ public function getDebugLog()
+ {
+ return $this->_debugLog;
+ }
+
+ /**
+ * __clone implementation. Cloning should not be allowed in a Singleton!
+ *
+ * @access public
+ * @throws PHPExcel_Calculation_Exception
+ */
+ final public function __clone()
+ {
+ throw new PHPExcel_Calculation_Exception('Cloning the calculation engine is not allowed!');
+ }
+
+
+ /**
+ * Return the locale-specific translation of TRUE
+ *
+ * @access public
+ * @return string locale-specific translation of TRUE
+ */
+ public static function getTRUE()
+ {
+ return self::$localeBoolean['TRUE'];
+ }
+
+ /**
+ * Return the locale-specific translation of FALSE
+ *
+ * @access public
+ * @return string locale-specific translation of FALSE
+ */
+ public static function getFALSE()
+ {
+ return self::$localeBoolean['FALSE'];
+ }
+
+ /**
+ * Set the Array Return Type (Array or Value of first element in the array)
+ *
+ * @access public
+ * @param string $returnType Array return type
+ * @return boolean Success or failure
+ */
+ public static function setArrayReturnType($returnType)
+ {
+ if (($returnType == self::RETURN_ARRAY_AS_VALUE) ||
+ ($returnType == self::RETURN_ARRAY_AS_ERROR) ||
+ ($returnType == self::RETURN_ARRAY_AS_ARRAY)) {
+ self::$returnArrayAsType = $returnType;
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Return the Array Return Type (Array or Value of first element in the array)
+ *
+ * @access public
+ * @return string $returnType Array return type
+ */
+ public static function getArrayReturnType()
+ {
+ return self::$returnArrayAsType;
+ }
+
+
+ /**
+ * Is calculation caching enabled?
+ *
+ * @access public
+ * @return boolean
+ */
+ public function getCalculationCacheEnabled()
+ {
+ return $this->calculationCacheEnabled;
+ }
+
+ /**
+ * Enable/disable calculation cache
+ *
+ * @access public
+ * @param boolean $pValue
+ */
+ public function setCalculationCacheEnabled($pValue = true)
+ {
+ $this->calculationCacheEnabled = $pValue;
+ $this->clearCalculationCache();
+ }
+
+
+ /**
+ * Enable calculation cache
+ */
+ public function enableCalculationCache()
+ {
+ $this->setCalculationCacheEnabled(true);
+ }
+
+
+ /**
+ * Disable calculation cache
+ */
+ public function disableCalculationCache()
+ {
+ $this->setCalculationCacheEnabled(false);
+ }
+
+
+ /**
+ * Clear calculation cache
+ */
+ public function clearCalculationCache()
+ {
+ $this->calculationCache = array();
+ }
+
+ /**
+ * Clear calculation cache for a specified worksheet
+ *
+ * @param string $worksheetName
+ */
+ public function clearCalculationCacheForWorksheet($worksheetName)
+ {
+ if (isset($this->calculationCache[$worksheetName])) {
+ unset($this->calculationCache[$worksheetName]);
+ }
+ }
+
+ /**
+ * Rename calculation cache for a specified worksheet
+ *
+ * @param string $fromWorksheetName
+ * @param string $toWorksheetName
+ */
+ public function renameCalculationCacheForWorksheet($fromWorksheetName, $toWorksheetName)
+ {
+ if (isset($this->calculationCache[$fromWorksheetName])) {
+ $this->calculationCache[$toWorksheetName] = &$this->calculationCache[$fromWorksheetName];
+ unset($this->calculationCache[$fromWorksheetName]);
+ }
+ }
+
+
+ /**
+ * Get the currently defined locale code
+ *
+ * @return string
+ */
+ public function getLocale()
+ {
+ return self::$localeLanguage;
+ }
+
+
+ /**
+ * Set the locale code
+ *
+ * @param string $locale The locale to use for formula translation
+ * @return boolean
+ */
+ public function setLocale($locale = 'en_us')
+ {
+ // Identify our locale and language
+ $language = $locale = strtolower($locale);
+ if (strpos($locale, '_') !== false) {
+ list($language) = explode('_', $locale);
+ }
+
+ if (count(self::$validLocaleLanguages) == 1) {
+ self::loadLocales();
+ }
+ // Test whether we have any language data for this language (any locale)
+ if (in_array($language, self::$validLocaleLanguages)) {
+ // initialise language/locale settings
+ self::$localeFunctions = array();
+ self::$localeArgumentSeparator = ',';
+ self::$localeBoolean = array('TRUE' => 'TRUE', 'FALSE' => 'FALSE', 'NULL' => 'NULL');
+ // Default is English, if user isn't requesting english, then read the necessary data from the locale files
+ if ($locale != 'en_us') {
+ // Search for a file with a list of function names for locale
+ $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $locale).DIRECTORY_SEPARATOR.'functions';
+ if (!file_exists($functionNamesFile)) {
+ // If there isn't a locale specific function file, look for a language specific function file
+ $functionNamesFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'functions';
+ if (!file_exists($functionNamesFile)) {
+ return false;
+ }
+ }
+ // Retrieve the list of locale or language specific function names
+ $localeFunctions = file($functionNamesFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ foreach ($localeFunctions as $localeFunction) {
+ list($localeFunction) = explode('##', $localeFunction); // Strip out comments
+ if (strpos($localeFunction, '=') !== false) {
+ list($fName, $lfName) = explode('=', $localeFunction);
+ $fName = trim($fName);
+ $lfName = trim($lfName);
+ if ((isset(self::$PHPExcelFunctions[$fName])) && ($lfName != '') && ($fName != $lfName)) {
+ self::$localeFunctions[$fName] = $lfName;
+ }
+ }
+ }
+ // Default the TRUE and FALSE constants to the locale names of the TRUE() and FALSE() functions
+ if (isset(self::$localeFunctions['TRUE'])) {
+ self::$localeBoolean['TRUE'] = self::$localeFunctions['TRUE'];
+ }
+ if (isset(self::$localeFunctions['FALSE'])) {
+ self::$localeBoolean['FALSE'] = self::$localeFunctions['FALSE'];
+ }
+
+ $configFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $locale).DIRECTORY_SEPARATOR.'config';
+ if (!file_exists($configFile)) {
+ $configFile = PHPEXCEL_ROOT . 'PHPExcel'.DIRECTORY_SEPARATOR.'locale'.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'config';
+ }
+ if (file_exists($configFile)) {
+ $localeSettings = file($configFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ foreach ($localeSettings as $localeSetting) {
+ list($localeSetting) = explode('##', $localeSetting); // Strip out comments
+ if (strpos($localeSetting, '=') !== false) {
+ list($settingName, $settingValue) = explode('=', $localeSetting);
+ $settingName = strtoupper(trim($settingName));
+ switch ($settingName) {
+ case 'ARGUMENTSEPARATOR':
+ self::$localeArgumentSeparator = trim($settingValue);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ self::$functionReplaceFromExcel = self::$functionReplaceToExcel =
+ self::$functionReplaceFromLocale = self::$functionReplaceToLocale = null;
+ self::$localeLanguage = $locale;
+ return true;
+ }
+ return false;
+ }
+
+
+
+ public static function translateSeparator($fromSeparator, $toSeparator, $formula, &$inBraces)
+ {
+ $strlen = mb_strlen($formula);
+ for ($i = 0; $i < $strlen; ++$i) {
+ $chr = mb_substr($formula, $i, 1);
+ switch ($chr) {
+ case '{':
+ $inBraces = true;
+ break;
+ case '}':
+ $inBraces = false;
+ break;
+ case $fromSeparator:
+ if (!$inBraces) {
+ $formula = mb_substr($formula, 0, $i).$toSeparator.mb_substr($formula, $i+1);
+ }
+ }
+ }
+ return $formula;
+ }
+
+ private static function translateFormula($from, $to, $formula, $fromSeparator, $toSeparator)
+ {
+ // Convert any Excel function names to the required language
+ if (self::$localeLanguage !== 'en_us') {
+ $inBraces = false;
+ // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
+ if (strpos($formula, '"') !== false) {
+ // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
+ // the formula
+ $temp = explode('"', $formula);
+ $i = false;
+ foreach ($temp as &$value) {
+ // Only count/replace in alternating array entries
+ if ($i = !$i) {
+ $value = preg_replace($from, $to, $value);
+ $value = self::translateSeparator($fromSeparator, $toSeparator, $value, $inBraces);
+ }
+ }
+ unset($value);
+ // Then rebuild the formula string
+ $formula = implode('"', $temp);
+ } else {
+ // If there's no quoted strings, then we do a simple count/replace
+ $formula = preg_replace($from, $to, $formula);
+ $formula = self::translateSeparator($fromSeparator, $toSeparator, $formula, $inBraces);
+ }
+ }
+
+ return $formula;
+ }
+
+ private static $functionReplaceFromExcel = null;
+ private static $functionReplaceToLocale = null;
+
+ public function _translateFormulaToLocale($formula)
+ {
+ if (self::$functionReplaceFromExcel === null) {
+ self::$functionReplaceFromExcel = array();
+ foreach (array_keys(self::$localeFunctions) as $excelFunctionName) {
+ self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelFunctionName).'([\s]*\()/Ui';
+ }
+ foreach (array_keys(self::$localeBoolean) as $excelBoolean) {
+ self::$functionReplaceFromExcel[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui';
+ }
+
+ }
+
+ if (self::$functionReplaceToLocale === null) {
+ self::$functionReplaceToLocale = array();
+ foreach (array_values(self::$localeFunctions) as $localeFunctionName) {
+ self::$functionReplaceToLocale[] = '$1'.trim($localeFunctionName).'$2';
+ }
+ foreach (array_values(self::$localeBoolean) as $localeBoolean) {
+ self::$functionReplaceToLocale[] = '$1'.trim($localeBoolean).'$2';
+ }
+ }
+
+ return self::translateFormula(self::$functionReplaceFromExcel, self::$functionReplaceToLocale, $formula, ',', self::$localeArgumentSeparator);
+ }
+
+
+ private static $functionReplaceFromLocale = null;
+ private static $functionReplaceToExcel = null;
+
+ public function _translateFormulaToEnglish($formula)
+ {
+ if (self::$functionReplaceFromLocale === null) {
+ self::$functionReplaceFromLocale = array();
+ foreach (array_values(self::$localeFunctions) as $localeFunctionName) {
+ self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($localeFunctionName).'([\s]*\()/Ui';
+ }
+ foreach (array_values(self::$localeBoolean) as $excelBoolean) {
+ self::$functionReplaceFromLocale[] = '/(@?[^\w\.])'.preg_quote($excelBoolean).'([^\w\.])/Ui';
+ }
+ }
+
+ if (self::$functionReplaceToExcel === null) {
+ self::$functionReplaceToExcel = array();
+ foreach (array_keys(self::$localeFunctions) as $excelFunctionName) {
+ self::$functionReplaceToExcel[] = '$1'.trim($excelFunctionName).'$2';
+ }
+ foreach (array_keys(self::$localeBoolean) as $excelBoolean) {
+ self::$functionReplaceToExcel[] = '$1'.trim($excelBoolean).'$2';
+ }
+ }
+
+ return self::translateFormula(self::$functionReplaceFromLocale, self::$functionReplaceToExcel, $formula, self::$localeArgumentSeparator, ',');
+ }
+
+
+ public static function localeFunc($function)
+ {
+ if (self::$localeLanguage !== 'en_us') {
+ $functionName = trim($function, '(');
+ if (isset(self::$localeFunctions[$functionName])) {
+ $brace = ($functionName != $function);
+ $function = self::$localeFunctions[$functionName];
+ if ($brace) {
+ $function .= '(';
+ }
+ }
+ }
+ return $function;
+ }
+
+
+
+
+ /**
+ * Wrap string values in quotes
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ public static function wrapResult($value)
+ {
+ if (is_string($value)) {
+ // Error values cannot be "wrapped"
+ if (preg_match('/^'.self::CALCULATION_REGEXP_ERROR.'$/i', $value, $match)) {
+ // Return Excel errors "as is"
+ return $value;
+ }
+ // Return strings wrapped in quotes
+ return '"'.$value.'"';
+ // Convert numeric errors to NaN error
+ } elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return $value;
+ }
+
+
+ /**
+ * Remove quotes used as a wrapper to identify string values
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ public static function unwrapResult($value)
+ {
+ if (is_string($value)) {
+ if ((isset($value{0})) && ($value{0} == '"') && (substr($value, -1) == '"')) {
+ return substr($value, 1, -1);
+ }
+ // Convert numeric errors to NaN error
+ } elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return $value;
+ }
+
+
+
+
+ /**
+ * Calculate cell value (using formula from a cell ID)
+ * Retained for backward compatibility
+ *
+ * @access public
+ * @param PHPExcel_Cell $pCell Cell to calculate
+ * @return mixed
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function calculate(PHPExcel_Cell $pCell = null)
+ {
+ try {
+ return $this->calculateCellValue($pCell);
+ } catch (PHPExcel_Exception $e) {
+ throw new PHPExcel_Calculation_Exception($e->getMessage());
+ }
+ }
+
+
+ /**
+ * Calculate the value of a cell formula
+ *
+ * @access public
+ * @param PHPExcel_Cell $pCell Cell to calculate
+ * @param Boolean $resetLog Flag indicating whether the debug log should be reset or not
+ * @return mixed
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function calculateCellValue(PHPExcel_Cell $pCell = null, $resetLog = true)
+ {
+ if ($pCell === null) {
+ return null;
+ }
+
+ $returnArrayAsType = self::$returnArrayAsType;
+ if ($resetLog) {
+ // Initialise the logging settings if requested
+ $this->formulaError = null;
+ $this->_debugLog->clearLog();
+ $this->cyclicReferenceStack->clear();
+ $this->cyclicFormulaCounter = 1;
+
+ self::$returnArrayAsType = self::RETURN_ARRAY_AS_ARRAY;
+ }
+
+ // Execute the calculation for the cell formula
+ $this->cellStack[] = array(
+ 'sheet' => $pCell->getWorksheet()->getTitle(),
+ 'cell' => $pCell->getCoordinate(),
+ );
+ try {
+ $result = self::unwrapResult($this->_calculateFormulaValue($pCell->getValue(), $pCell->getCoordinate(), $pCell));
+ $cellAddress = array_pop($this->cellStack);
+ $this->workbook->getSheetByName($cellAddress['sheet'])->getCell($cellAddress['cell']);
+ } catch (PHPExcel_Exception $e) {
+ $cellAddress = array_pop($this->cellStack);
+ $this->workbook->getSheetByName($cellAddress['sheet'])->getCell($cellAddress['cell']);
+ throw new PHPExcel_Calculation_Exception($e->getMessage());
+ }
+
+ if ((is_array($result)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
+ self::$returnArrayAsType = $returnArrayAsType;
+ $testResult = PHPExcel_Calculation_Functions::flattenArray($result);
+ if (self::$returnArrayAsType == self::RETURN_ARRAY_AS_ERROR) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ // If there's only a single cell in the array, then we allow it
+ if (count($testResult) != 1) {
+ // If keys are numeric, then it's a matrix result rather than a cell range result, so we permit it
+ $r = array_keys($result);
+ $r = array_shift($r);
+ if (!is_numeric($r)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_array($result[$r])) {
+ $c = array_keys($result[$r]);
+ $c = array_shift($c);
+ if (!is_numeric($c)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ }
+ $result = array_shift($testResult);
+ }
+ self::$returnArrayAsType = $returnArrayAsType;
+
+
+ if ($result === null) {
+ return 0;
+ } elseif ((is_float($result)) && ((is_nan($result)) || (is_infinite($result)))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return $result;
+ }
+
+
+ /**
+ * Validate and parse a formula string
+ *
+ * @param string $formula Formula to parse
+ * @return array
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function parseFormula($formula)
+ {
+ // Basic validation that this is indeed a formula
+ // We return an empty array if not
+ $formula = trim($formula);
+ if ((!isset($formula{0})) || ($formula{0} != '=')) {
+ return array();
+ }
+ $formula = ltrim(substr($formula, 1));
+ if (!isset($formula{0})) {
+ return array();
+ }
+
+ // Parse the formula and return the token stack
+ return $this->_parseFormula($formula);
+ }
+
+
+ /**
+ * Calculate the value of a formula
+ *
+ * @param string $formula Formula to parse
+ * @param string $cellID Address of the cell to calculate
+ * @param PHPExcel_Cell $pCell Cell to calculate
+ * @return mixed
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function calculateFormula($formula, $cellID = null, PHPExcel_Cell $pCell = null)
+ {
+ // Initialise the logging settings
+ $this->formulaError = null;
+ $this->_debugLog->clearLog();
+ $this->cyclicReferenceStack->clear();
+
+ if ($this->workbook !== null && $cellID === null && $pCell === null) {
+ $cellID = 'A1';
+ $pCell = $this->workbook->getActiveSheet()->getCell($cellID);
+ } else {
+ // Disable calculation cacheing because it only applies to cell calculations, not straight formulae
+ // But don't actually flush any cache
+ $resetCache = $this->getCalculationCacheEnabled();
+ $this->calculationCacheEnabled = false;
+ }
+
+ // Execute the calculation
+ try {
+ $result = self::unwrapResult($this->_calculateFormulaValue($formula, $cellID, $pCell));
+ } catch (PHPExcel_Exception $e) {
+ throw new PHPExcel_Calculation_Exception($e->getMessage());
+ }
+
+ if ($this->workbook === null) {
+ // Reset calculation cacheing to its previous state
+ $this->calculationCacheEnabled = $resetCache;
+ }
+
+ return $result;
+ }
+
+
+ public function getValueFromCache($cellReference, &$cellValue)
+ {
+ // Is calculation cacheing enabled?
+ // Is the value present in calculation cache?
+ $this->_debugLog->writeDebugLog('Testing cache value for cell ', $cellReference);
+ if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) {
+ $this->_debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache');
+ // Return the cached result
+ $cellValue = $this->calculationCache[$cellReference];
+ return true;
+ }
+ return false;
+ }
+
+ public function saveValueToCache($cellReference, $cellValue)
+ {
+ if ($this->calculationCacheEnabled) {
+ $this->calculationCache[$cellReference] = $cellValue;
+ }
+ }
+
+ /**
+ * Parse a cell formula and calculate its value
+ *
+ * @param string $formula The formula to parse and calculate
+ * @param string $cellID The ID (e.g. A3) of the cell that we are calculating
+ * @param PHPExcel_Cell $pCell Cell to calculate
+ * @return mixed
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function _calculateFormulaValue($formula, $cellID = null, PHPExcel_Cell $pCell = null)
+ {
+ $cellValue = null;
+
+ // Basic validation that this is indeed a formula
+ // We simply return the cell value if not
+ $formula = trim($formula);
+ if ($formula{0} != '=') {
+ return self::wrapResult($formula);
+ }
+ $formula = ltrim(substr($formula, 1));
+ if (!isset($formula{0})) {
+ return self::wrapResult($formula);
+ }
+
+ $pCellParent = ($pCell !== null) ? $pCell->getWorksheet() : null;
+ $wsTitle = ($pCellParent !== null) ? $pCellParent->getTitle() : "\x00Wrk";
+ $wsCellReference = $wsTitle . '!' . $cellID;
+
+ if (($cellID !== null) && ($this->getValueFromCache($wsCellReference, $cellValue))) {
+ return $cellValue;
+ }
+
+ if (($wsTitle{0} !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) {
+ if ($this->cyclicFormulaCount <= 0) {
+ $this->cyclicFormulaCell = '';
+ return $this->raiseFormulaError('Cyclic Reference in Formula');
+ } elseif ($this->cyclicFormulaCell === $wsCellReference) {
+ ++$this->cyclicFormulaCounter;
+ if ($this->cyclicFormulaCounter >= $this->cyclicFormulaCount) {
+ $this->cyclicFormulaCell = '';
+ return $cellValue;
+ }
+ } elseif ($this->cyclicFormulaCell == '') {
+ if ($this->cyclicFormulaCounter >= $this->cyclicFormulaCount) {
+ return $cellValue;
+ }
+ $this->cyclicFormulaCell = $wsCellReference;
+ }
+ }
+
+ // Parse the formula onto the token stack and calculate the value
+ $this->cyclicReferenceStack->push($wsCellReference);
+ $cellValue = $this->processTokenStack($this->_parseFormula($formula, $pCell), $cellID, $pCell);
+ $this->cyclicReferenceStack->pop();
+
+ // Save to calculation cache
+ if ($cellID !== null) {
+ $this->saveValueToCache($wsCellReference, $cellValue);
+ }
+
+ // Return the calculated value
+ return $cellValue;
+ }
+
+
+ /**
+ * Ensure that paired matrix operands are both matrices and of the same size
+ *
+ * @param mixed &$operand1 First matrix operand
+ * @param mixed &$operand2 Second matrix operand
+ * @param integer $resize Flag indicating whether the matrices should be resized to match
+ * and (if so), whether the smaller dimension should grow or the
+ * larger should shrink.
+ * 0 = no resize
+ * 1 = shrink to fit
+ * 2 = extend to fit
+ */
+ private static function checkMatrixOperands(&$operand1, &$operand2, $resize = 1)
+ {
+ // Examine each of the two operands, and turn them into an array if they aren't one already
+ // Note that this function should only be called if one or both of the operand is already an array
+ if (!is_array($operand1)) {
+ list($matrixRows, $matrixColumns) = self::getMatrixDimensions($operand2);
+ $operand1 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand1));
+ $resize = 0;
+ } elseif (!is_array($operand2)) {
+ list($matrixRows, $matrixColumns) = self::getMatrixDimensions($operand1);
+ $operand2 = array_fill(0, $matrixRows, array_fill(0, $matrixColumns, $operand2));
+ $resize = 0;
+ }
+
+ list($matrix1Rows, $matrix1Columns) = self::getMatrixDimensions($operand1);
+ list($matrix2Rows, $matrix2Columns) = self::getMatrixDimensions($operand2);
+ if (($matrix1Rows == $matrix2Columns) && ($matrix2Rows == $matrix1Columns)) {
+ $resize = 1;
+ }
+
+ if ($resize == 2) {
+ // Given two matrices of (potentially) unequal size, convert the smaller in each dimension to match the larger
+ self::resizeMatricesExtend($operand1, $operand2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns);
+ } elseif ($resize == 1) {
+ // Given two matrices of (potentially) unequal size, convert the larger in each dimension to match the smaller
+ self::resizeMatricesShrink($operand1, $operand2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns);
+ }
+ return array( $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns);
+ }
+
+
+ /**
+ * Read the dimensions of a matrix, and re-index it with straight numeric keys starting from row 0, column 0
+ *
+ * @param mixed &$matrix matrix operand
+ * @return array An array comprising the number of rows, and number of columns
+ */
+ private static function getMatrixDimensions(&$matrix)
+ {
+ $matrixRows = count($matrix);
+ $matrixColumns = 0;
+ foreach ($matrix as $rowKey => $rowValue) {
+ $matrixColumns = max(count($rowValue), $matrixColumns);
+ if (!is_array($rowValue)) {
+ $matrix[$rowKey] = array($rowValue);
+ } else {
+ $matrix[$rowKey] = array_values($rowValue);
+ }
+ }
+ $matrix = array_values($matrix);
+ return array($matrixRows, $matrixColumns);
+ }
+
+
+ /**
+ * Ensure that paired matrix operands are both matrices of the same size
+ *
+ * @param mixed &$matrix1 First matrix operand
+ * @param mixed &$matrix2 Second matrix operand
+ * @param integer $matrix1Rows Row size of first matrix operand
+ * @param integer $matrix1Columns Column size of first matrix operand
+ * @param integer $matrix2Rows Row size of second matrix operand
+ * @param integer $matrix2Columns Column size of second matrix operand
+ */
+ private static function resizeMatricesShrink(&$matrix1, &$matrix2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns)
+ {
+ if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
+ if ($matrix2Rows < $matrix1Rows) {
+ for ($i = $matrix2Rows; $i < $matrix1Rows; ++$i) {
+ unset($matrix1[$i]);
+ }
+ }
+ if ($matrix2Columns < $matrix1Columns) {
+ for ($i = 0; $i < $matrix1Rows; ++$i) {
+ for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
+ unset($matrix1[$i][$j]);
+ }
+ }
+ }
+ }
+
+ if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
+ if ($matrix1Rows < $matrix2Rows) {
+ for ($i = $matrix1Rows; $i < $matrix2Rows; ++$i) {
+ unset($matrix2[$i]);
+ }
+ }
+ if ($matrix1Columns < $matrix2Columns) {
+ for ($i = 0; $i < $matrix2Rows; ++$i) {
+ for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
+ unset($matrix2[$i][$j]);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Ensure that paired matrix operands are both matrices of the same size
+ *
+ * @param mixed &$matrix1 First matrix operand
+ * @param mixed &$matrix2 Second matrix operand
+ * @param integer $matrix1Rows Row size of first matrix operand
+ * @param integer $matrix1Columns Column size of first matrix operand
+ * @param integer $matrix2Rows Row size of second matrix operand
+ * @param integer $matrix2Columns Column size of second matrix operand
+ */
+ private static function resizeMatricesExtend(&$matrix1, &$matrix2, $matrix1Rows, $matrix1Columns, $matrix2Rows, $matrix2Columns)
+ {
+ if (($matrix2Columns < $matrix1Columns) || ($matrix2Rows < $matrix1Rows)) {
+ if ($matrix2Columns < $matrix1Columns) {
+ for ($i = 0; $i < $matrix2Rows; ++$i) {
+ $x = $matrix2[$i][$matrix2Columns-1];
+ for ($j = $matrix2Columns; $j < $matrix1Columns; ++$j) {
+ $matrix2[$i][$j] = $x;
+ }
+ }
+ }
+ if ($matrix2Rows < $matrix1Rows) {
+ $x = $matrix2[$matrix2Rows-1];
+ for ($i = 0; $i < $matrix1Rows; ++$i) {
+ $matrix2[$i] = $x;
+ }
+ }
+ }
+
+ if (($matrix1Columns < $matrix2Columns) || ($matrix1Rows < $matrix2Rows)) {
+ if ($matrix1Columns < $matrix2Columns) {
+ for ($i = 0; $i < $matrix1Rows; ++$i) {
+ $x = $matrix1[$i][$matrix1Columns-1];
+ for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
+ $matrix1[$i][$j] = $x;
+ }
+ }
+ }
+ if ($matrix1Rows < $matrix2Rows) {
+ $x = $matrix1[$matrix1Rows-1];
+ for ($i = 0; $i < $matrix2Rows; ++$i) {
+ $matrix1[$i] = $x;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Format details of an operand for display in the log (based on operand type)
+ *
+ * @param mixed $value First matrix operand
+ * @return mixed
+ */
+ private function showValue($value)
+ {
+ if ($this->_debugLog->getWriteDebugLog()) {
+ $testArray = PHPExcel_Calculation_Functions::flattenArray($value);
+ if (count($testArray) == 1) {
+ $value = array_pop($testArray);
+ }
+
+ if (is_array($value)) {
+ $returnMatrix = array();
+ $pad = $rpad = ', ';
+ foreach ($value as $row) {
+ if (is_array($row)) {
+ $returnMatrix[] = implode($pad, array_map(array($this, 'showValue'), $row));
+ $rpad = '; ';
+ } else {
+ $returnMatrix[] = $this->showValue($row);
+ }
+ }
+ return '{ '.implode($rpad, $returnMatrix).' }';
+ } elseif (is_string($value) && (trim($value, '"') == $value)) {
+ return '"'.$value.'"';
+ } elseif (is_bool($value)) {
+ return ($value) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
+ }
+ }
+ return PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ }
+
+
+ /**
+ * Format type and details of an operand for display in the log (based on operand type)
+ *
+ * @param mixed $value First matrix operand
+ * @return mixed
+ */
+ private function showTypeDetails($value)
+ {
+ if ($this->_debugLog->getWriteDebugLog()) {
+ $testArray = PHPExcel_Calculation_Functions::flattenArray($value);
+ if (count($testArray) == 1) {
+ $value = array_pop($testArray);
+ }
+
+ if ($value === null) {
+ return 'a NULL value';
+ } elseif (is_float($value)) {
+ $typeString = 'a floating point number';
+ } elseif (is_int($value)) {
+ $typeString = 'an integer number';
+ } elseif (is_bool($value)) {
+ $typeString = 'a boolean';
+ } elseif (is_array($value)) {
+ $typeString = 'a matrix';
+ } else {
+ if ($value == '') {
+ return 'an empty string';
+ } elseif ($value{0} == '#') {
+ return 'a '.$value.' error';
+ } else {
+ $typeString = 'a string';
+ }
+ }
+ return $typeString.' with a value of '.$this->showValue($value);
+ }
+ }
+
+
+ private function convertMatrixReferences($formula)
+ {
+ static $matrixReplaceFrom = array('{', ';', '}');
+ static $matrixReplaceTo = array('MKMATRIX(MKMATRIX(', '),MKMATRIX(', '))');
+
+ // Convert any Excel matrix references to the MKMATRIX() function
+ if (strpos($formula, '{') !== false) {
+ // If there is the possibility of braces within a quoted string, then we don't treat those as matrix indicators
+ if (strpos($formula, '"') !== false) {
+ // So instead we skip replacing in any quoted strings by only replacing in every other array element after we've exploded
+ // the formula
+ $temp = explode('"', $formula);
+ // Open and Closed counts used for trapping mismatched braces in the formula
+ $openCount = $closeCount = 0;
+ $i = false;
+ foreach ($temp as &$value) {
+ // Only count/replace in alternating array entries
+ if ($i = !$i) {
+ $openCount += substr_count($value, '{');
+ $closeCount += substr_count($value, '}');
+ $value = str_replace($matrixReplaceFrom, $matrixReplaceTo, $value);
+ }
+ }
+ unset($value);
+ // Then rebuild the formula string
+ $formula = implode('"', $temp);
+ } else {
+ // If there's no quoted strings, then we do a simple count/replace
+ $openCount = substr_count($formula, '{');
+ $closeCount = substr_count($formula, '}');
+ $formula = str_replace($matrixReplaceFrom, $matrixReplaceTo, $formula);
+ }
+ // Trap for mismatched braces and trigger an appropriate error
+ if ($openCount < $closeCount) {
+ if ($openCount > 0) {
+ return $this->raiseFormulaError("Formula Error: Mismatched matrix braces '}'");
+ } else {
+ return $this->raiseFormulaError("Formula Error: Unexpected '}' encountered");
+ }
+ } elseif ($openCount > $closeCount) {
+ if ($closeCount > 0) {
+ return $this->raiseFormulaError("Formula Error: Mismatched matrix braces '{'");
+ } else {
+ return $this->raiseFormulaError("Formula Error: Unexpected '{' encountered");
+ }
+ }
+ }
+
+ return $formula;
+ }
+
+
+ private static function mkMatrix()
+ {
+ return func_get_args();
+ }
+
+
+ // Binary Operators
+ // These operators always work on two values
+ // Array key is the operator, the value indicates whether this is a left or right associative operator
+ private static $operatorAssociativity = array(
+ '^' => 0, // Exponentiation
+ '*' => 0, '/' => 0, // Multiplication and Division
+ '+' => 0, '-' => 0, // Addition and Subtraction
+ '&' => 0, // Concatenation
+ '|' => 0, ':' => 0, // Intersect and Range
+ '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison
+ );
+
+ // Comparison (Boolean) Operators
+ // These operators work on two values, but always return a boolean result
+ private static $comparisonOperators = array('>' => true, '<' => true, '=' => true, '>=' => true, '<=' => true, '<>' => true);
+
+ // Operator Precedence
+ // This list includes all valid operators, whether binary (including boolean) or unary (such as %)
+ // Array key is the operator, the value is its precedence
+ private static $operatorPrecedence = array(
+ ':' => 8, // Range
+ '|' => 7, // Intersect
+ '~' => 6, // Negation
+ '%' => 5, // Percentage
+ '^' => 4, // Exponentiation
+ '*' => 3, '/' => 3, // Multiplication and Division
+ '+' => 2, '-' => 2, // Addition and Subtraction
+ '&' => 1, // Concatenation
+ '>' => 0, '<' => 0, '=' => 0, '>=' => 0, '<=' => 0, '<>' => 0 // Comparison
+ );
+
+ // Convert infix to postfix notation
+ private function _parseFormula($formula, PHPExcel_Cell $pCell = null)
+ {
+ if (($formula = $this->convertMatrixReferences(trim($formula))) === false) {
+ return false;
+ }
+
+ // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent worksheet),
+ // so we store the parent worksheet so that we can re-attach it when necessary
+ $pCellParent = ($pCell !== null) ? $pCell->getWorksheet() : null;
+
+ $regexpMatchString = '/^('.self::CALCULATION_REGEXP_FUNCTION.
+ '|'.self::CALCULATION_REGEXP_CELLREF.
+ '|'.self::CALCULATION_REGEXP_NUMBER.
+ '|'.self::CALCULATION_REGEXP_STRING.
+ '|'.self::CALCULATION_REGEXP_OPENBRACE.
+ '|'.self::CALCULATION_REGEXP_NAMEDRANGE.
+ '|'.self::CALCULATION_REGEXP_ERROR.
+ ')/si';
+
+ // Start with initialisation
+ $index = 0;
+ $stack = new PHPExcel_Calculation_Token_Stack;
+ $output = array();
+ $expectingOperator = false; // We use this test in syntax-checking the expression to determine when a
+ // - is a negation or + is a positive operator rather than an operation
+ $expectingOperand = false; // We use this test in syntax-checking the expression to determine whether an operand
+ // should be null in a function call
+ // The guts of the lexical parser
+ // Loop through the formula extracting each operator and operand in turn
+ while (true) {
+//echo 'Assessing Expression '.substr($formula, $index), PHP_EOL;
+ $opCharacter = $formula{$index}; // Get the first character of the value at the current index position
+//echo 'Initial character of expression block is '.$opCharacter, PHP_EOL;
+ if ((isset(self::$comparisonOperators[$opCharacter])) && (strlen($formula) > $index) && (isset(self::$comparisonOperators[$formula{$index+1}]))) {
+ $opCharacter .= $formula{++$index};
+//echo 'Initial character of expression block is comparison operator '.$opCharacter.PHP_EOL;
+ }
+
+ // Find out if we're currently at the beginning of a number, variable, cell reference, function, parenthesis or operand
+ $isOperandOrFunction = preg_match($regexpMatchString, substr($formula, $index), $match);
+//echo '$isOperandOrFunction is '.(($isOperandOrFunction) ? 'True' : 'False').PHP_EOL;
+//var_dump($match);
+
+ if ($opCharacter == '-' && !$expectingOperator) { // Is it a negation instead of a minus?
+//echo 'Element is a Negation operator', PHP_EOL;
+ $stack->push('Unary Operator', '~'); // Put a negation on the stack
+ ++$index; // and drop the negation symbol
+ } elseif ($opCharacter == '%' && $expectingOperator) {
+//echo 'Element is a Percentage operator', PHP_EOL;
+ $stack->push('Unary Operator', '%'); // Put a percentage on the stack
+ ++$index;
+ } elseif ($opCharacter == '+' && !$expectingOperator) { // Positive (unary plus rather than binary operator plus) can be discarded?
+//echo 'Element is a Positive number, not Plus operator', PHP_EOL;
+ ++$index; // Drop the redundant plus symbol
+ } elseif ((($opCharacter == '~') || ($opCharacter == '|')) && (!$isOperandOrFunction)) { // We have to explicitly deny a tilde or pipe, because they are legal
+ return $this->raiseFormulaError("Formula Error: Illegal character '~'"); // on the stack but not in the input expression
+
+ } elseif ((isset(self::$operators[$opCharacter]) or $isOperandOrFunction) && $expectingOperator) { // Are we putting an operator on the stack?
+//echo 'Element with value '.$opCharacter.' is an Operator', PHP_EOL;
+ while ($stack->count() > 0 &&
+ ($o2 = $stack->last()) &&
+ isset(self::$operators[$o2['value']]) &&
+ @(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2['value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2['value']])) {
+ $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
+ }
+ $stack->push('Binary Operator', $opCharacter); // Finally put our current operator onto the stack
+ ++$index;
+ $expectingOperator = false;
+
+ } elseif ($opCharacter == ')' && $expectingOperator) { // Are we expecting to close a parenthesis?
+//echo 'Element is a Closing bracket', PHP_EOL;
+ $expectingOperand = false;
+ while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
+ if ($o2 === null) {
+ return $this->raiseFormulaError('Formula Error: Unexpected closing brace ")"');
+ } else {
+ $output[] = $o2;
+ }
+ }
+ $d = $stack->last(2);
+ if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) { // Did this parenthesis just close a function?
+ $functionName = $matches[1]; // Get the function name
+//echo 'Closed Function is '.$functionName, PHP_EOL;
+ $d = $stack->pop();
+ $argumentCount = $d['value']; // See how many arguments there were (argument count is the next value stored on the stack)
+//if ($argumentCount == 0) {
+// echo 'With no arguments', PHP_EOL;
+//} elseif ($argumentCount == 1) {
+// echo 'With 1 argument', PHP_EOL;
+//} else {
+// echo 'With '.$argumentCount.' arguments', PHP_EOL;
+//}
+ $output[] = $d; // Dump the argument count on the output
+ $output[] = $stack->pop(); // Pop the function and push onto the output
+ if (isset(self::$controlFunctions[$functionName])) {
+//echo 'Built-in function '.$functionName, PHP_EOL;
+ $expectedArgumentCount = self::$controlFunctions[$functionName]['argumentCount'];
+ $functionCall = self::$controlFunctions[$functionName]['functionCall'];
+ } elseif (isset(self::$PHPExcelFunctions[$functionName])) {
+//echo 'PHPExcel function '.$functionName, PHP_EOL;
+ $expectedArgumentCount = self::$PHPExcelFunctions[$functionName]['argumentCount'];
+ $functionCall = self::$PHPExcelFunctions[$functionName]['functionCall'];
+ } else { // did we somehow push a non-function on the stack? this should never happen
+ return $this->raiseFormulaError("Formula Error: Internal error, non-function on stack");
+ }
+ // Check the argument count
+ $argumentCountError = false;
+ if (is_numeric($expectedArgumentCount)) {
+ if ($expectedArgumentCount < 0) {
+//echo '$expectedArgumentCount is between 0 and '.abs($expectedArgumentCount), PHP_EOL;
+ if ($argumentCount > abs($expectedArgumentCount)) {
+ $argumentCountError = true;
+ $expectedArgumentCountString = 'no more than '.abs($expectedArgumentCount);
+ }
+ } else {
+//echo '$expectedArgumentCount is numeric '.$expectedArgumentCount, PHP_EOL;
+ if ($argumentCount != $expectedArgumentCount) {
+ $argumentCountError = true;
+ $expectedArgumentCountString = $expectedArgumentCount;
+ }
+ }
+ } elseif ($expectedArgumentCount != '*') {
+ $isOperandOrFunction = preg_match('/(\d*)([-+,])(\d*)/', $expectedArgumentCount, $argMatch);
+//print_r($argMatch);
+//echo PHP_EOL;
+ switch ($argMatch[2]) {
+ case '+':
+ if ($argumentCount < $argMatch[1]) {
+ $argumentCountError = true;
+ $expectedArgumentCountString = $argMatch[1].' or more ';
+ }
+ break;
+ case '-':
+ if (($argumentCount < $argMatch[1]) || ($argumentCount > $argMatch[3])) {
+ $argumentCountError = true;
+ $expectedArgumentCountString = 'between '.$argMatch[1].' and '.$argMatch[3];
+ }
+ break;
+ case ',':
+ if (($argumentCount != $argMatch[1]) && ($argumentCount != $argMatch[3])) {
+ $argumentCountError = true;
+ $expectedArgumentCountString = 'either '.$argMatch[1].' or '.$argMatch[3];
+ }
+ break;
+ }
+ }
+ if ($argumentCountError) {
+ return $this->raiseFormulaError("Formula Error: Wrong number of arguments for $functionName() function: $argumentCount given, ".$expectedArgumentCountString." expected");
+ }
+ }
+ ++$index;
+
+ } elseif ($opCharacter == ',') { // Is this the separator for function arguments?
+//echo 'Element is a Function argument separator', PHP_EOL;
+ while (($o2 = $stack->pop()) && $o2['value'] != '(') { // Pop off the stack back to the last (
+ if ($o2 === null) {
+ return $this->raiseFormulaError("Formula Error: Unexpected ,");
+ } else {
+ $output[] = $o2; // pop the argument expression stuff and push onto the output
+ }
+ }
+ // If we've a comma when we're expecting an operand, then what we actually have is a null operand;
+ // so push a null onto the stack
+ if (($expectingOperand) || (!$expectingOperator)) {
+ $output[] = array('type' => 'NULL Value', 'value' => self::$excelConstants['NULL'], 'reference' => null);
+ }
+ // make sure there was a function
+ $d = $stack->last(2);
+ if (!preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $d['value'], $matches)) {
+ return $this->raiseFormulaError("Formula Error: Unexpected ,");
+ }
+ $d = $stack->pop();
+ $stack->push($d['type'], ++$d['value'], $d['reference']); // increment the argument count
+ $stack->push('Brace', '('); // put the ( back on, we'll need to pop back to it again
+ $expectingOperator = false;
+ $expectingOperand = true;
+ ++$index;
+
+ } elseif ($opCharacter == '(' && !$expectingOperator) {
+// echo 'Element is an Opening Bracket ';
+ $stack->push('Brace', '(');
+ ++$index;
+
+ } elseif ($isOperandOrFunction && !$expectingOperator) { // do we now have a function/variable/number?
+ $expectingOperator = true;
+ $expectingOperand = false;
+ $val = $match[1];
+ $length = strlen($val);
+// echo 'Element with value '.$val.' is an Operand, Variable, Constant, String, Number, Cell Reference or Function ';
+
+ if (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $val, $matches)) {
+ $val = preg_replace('/\s/u', '', $val);
+// echo 'Element '.$val.' is a Function ';
+ if (isset(self::$PHPExcelFunctions[strtoupper($matches[1])]) || isset(self::$controlFunctions[strtoupper($matches[1])])) { // it's a function
+ $stack->push('Function', strtoupper($val));
+ $ax = preg_match('/^\s*(\s*\))/ui', substr($formula, $index+$length), $amatch);
+ if ($ax) {
+ $stack->push('Operand Count for Function '.strtoupper($val).')', 0);
+ $expectingOperator = true;
+ } else {
+ $stack->push('Operand Count for Function '.strtoupper($val).')', 1);
+ $expectingOperator = false;
+ }
+ $stack->push('Brace', '(');
+ } else { // it's a var w/ implicit multiplication
+ $output[] = array('type' => 'Value', 'value' => $matches[1], 'reference' => null);
+ }
+ } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $val, $matches)) {
+// echo 'Element '.$val.' is a Cell reference ';
+ // Watch for this case-change when modifying to allow cell references in different worksheets...
+ // Should only be applied to the actual cell column, not the worksheet name
+
+ // If the last entry on the stack was a : operator, then we have a cell range reference
+ $testPrevOp = $stack->last(1);
+ if ($testPrevOp['value'] == ':') {
+ // If we have a worksheet reference, then we're playing with a 3D reference
+ if ($matches[2] == '') {
+ // Otherwise, we 'inherit' the worksheet reference from the start cell reference
+ // The start of the cell range reference should be the last entry in $output
+ $startCellRef = $output[count($output)-1]['value'];
+ preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $startCellRef, $startMatches);
+ if ($startMatches[2] > '') {
+ $val = $startMatches[2].'!'.$val;
+ }
+ } else {
+ return $this->raiseFormulaError("3D Range references are not yet supported");
+ }
+ }
+
+ $output[] = array('type' => 'Cell Reference', 'value' => $val, 'reference' => $val);
+// $expectingOperator = FALSE;
+ } else { // it's a variable, constant, string, number or boolean
+// echo 'Element is a Variable, Constant, String, Number or Boolean ';
+ // If the last entry on the stack was a : operator, then we may have a row or column range reference
+ $testPrevOp = $stack->last(1);
+ if ($testPrevOp['value'] == ':') {
+ $startRowColRef = $output[count($output)-1]['value'];
+ $rangeWS1 = '';
+ if (strpos('!', $startRowColRef) !== false) {
+ list($rangeWS1, $startRowColRef) = explode('!', $startRowColRef);
+ }
+ if ($rangeWS1 != '') {
+ $rangeWS1 .= '!';
+ }
+ $rangeWS2 = $rangeWS1;
+ if (strpos('!', $val) !== false) {
+ list($rangeWS2, $val) = explode('!', $val);
+ }
+ if ($rangeWS2 != '') {
+ $rangeWS2 .= '!';
+ }
+ if ((is_integer($startRowColRef)) && (ctype_digit($val)) &&
+ ($startRowColRef <= 1048576) && ($val <= 1048576)) {
+ // Row range
+ $endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestColumn() : 'XFD'; // Max 16,384 columns for Excel2007
+ $output[count($output)-1]['value'] = $rangeWS1.'A'.$startRowColRef;
+ $val = $rangeWS2.$endRowColRef.$val;
+ } elseif ((ctype_alpha($startRowColRef)) && (ctype_alpha($val)) &&
+ (strlen($startRowColRef) <= 3) && (strlen($val) <= 3)) {
+ // Column range
+ $endRowColRef = ($pCellParent !== null) ? $pCellParent->getHighestRow() : 1048576; // Max 1,048,576 rows for Excel2007
+ $output[count($output)-1]['value'] = $rangeWS1.strtoupper($startRowColRef).'1';
+ $val = $rangeWS2.$val.$endRowColRef;
+ }
+ }
+
+ $localeConstant = false;
+ if ($opCharacter == '"') {
+// echo 'Element is a String ';
+ // UnEscape any quotes within the string
+ $val = self::wrapResult(str_replace('""', '"', self::unwrapResult($val)));
+ } elseif (is_numeric($val)) {
+// echo 'Element is a Number ';
+ if ((strpos($val, '.') !== false) || (stripos($val, 'e') !== false) || ($val > PHP_INT_MAX) || ($val < -PHP_INT_MAX)) {
+// echo 'Casting '.$val.' to float ';
+ $val = (float) $val;
+ } else {
+// echo 'Casting '.$val.' to integer ';
+ $val = (integer) $val;
+ }
+ } elseif (isset(self::$excelConstants[trim(strtoupper($val))])) {
+ $excelConstant = trim(strtoupper($val));
+// echo 'Element '.$excelConstant.' is an Excel Constant ';
+ $val = self::$excelConstants[$excelConstant];
+ } elseif (($localeConstant = array_search(trim(strtoupper($val)), self::$localeBoolean)) !== false) {
+// echo 'Element '.$localeConstant.' is an Excel Constant ';
+ $val = self::$excelConstants[$localeConstant];
+ }
+ $details = array('type' => 'Value', 'value' => $val, 'reference' => null);
+ if ($localeConstant) {
+ $details['localeValue'] = $localeConstant;
+ }
+ $output[] = $details;
+ }
+ $index += $length;
+
+ } elseif ($opCharacter == '$') { // absolute row or column range
+ ++$index;
+ } elseif ($opCharacter == ')') { // miscellaneous error checking
+ if ($expectingOperand) {
+ $output[] = array('type' => 'NULL Value', 'value' => self::$excelConstants['NULL'], 'reference' => null);
+ $expectingOperand = false;
+ $expectingOperator = true;
+ } else {
+ return $this->raiseFormulaError("Formula Error: Unexpected ')'");
+ }
+ } elseif (isset(self::$operators[$opCharacter]) && !$expectingOperator) {
+ return $this->raiseFormulaError("Formula Error: Unexpected operator '$opCharacter'");
+ } else { // I don't even want to know what you did to get here
+ return $this->raiseFormulaError("Formula Error: An unexpected error occured");
+ }
+ // Test for end of formula string
+ if ($index == strlen($formula)) {
+ // Did we end with an operator?.
+ // Only valid for the % unary operator
+ if ((isset(self::$operators[$opCharacter])) && ($opCharacter != '%')) {
+ return $this->raiseFormulaError("Formula Error: Operator '$opCharacter' has no operands");
+ } else {
+ break;
+ }
+ }
+ // Ignore white space
+ while (($formula{$index} == "\n") || ($formula{$index} == "\r")) {
+ ++$index;
+ }
+ if ($formula{$index} == ' ') {
+ while ($formula{$index} == ' ') {
+ ++$index;
+ }
+ // If we're expecting an operator, but only have a space between the previous and next operands (and both are
+ // Cell References) then we have an INTERSECTION operator
+// echo 'Possible Intersect Operator ';
+ if (($expectingOperator) && (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'.*/Ui', substr($formula, $index), $match)) &&
+ ($output[count($output)-1]['type'] == 'Cell Reference')) {
+// echo 'Element is an Intersect Operator ';
+ while ($stack->count() > 0 &&
+ ($o2 = $stack->last()) &&
+ isset(self::$operators[$o2['value']]) &&
+ @(self::$operatorAssociativity[$opCharacter] ? self::$operatorPrecedence[$opCharacter] < self::$operatorPrecedence[$o2['value']] : self::$operatorPrecedence[$opCharacter] <= self::$operatorPrecedence[$o2['value']])) {
+ $output[] = $stack->pop(); // Swap operands and higher precedence operators from the stack to the output
+ }
+ $stack->push('Binary Operator', '|'); // Put an Intersect Operator on the stack
+ $expectingOperator = false;
+ }
+ }
+ }
+
+ while (($op = $stack->pop()) !== null) { // pop everything off the stack and push onto output
+ if ((is_array($op) && $op['value'] == '(') || ($op === '(')) {
+ return $this->raiseFormulaError("Formula Error: Expecting ')'"); // if there are any opening braces on the stack, then braces were unbalanced
+ }
+ $output[] = $op;
+ }
+ return $output;
+ }
+
+
+ private static function dataTestReference(&$operandData)
+ {
+ $operand = $operandData['value'];
+ if (($operandData['reference'] === null) && (is_array($operand))) {
+ $rKeys = array_keys($operand);
+ $rowKey = array_shift($rKeys);
+ $cKeys = array_keys(array_keys($operand[$rowKey]));
+ $colKey = array_shift($cKeys);
+ if (ctype_upper($colKey)) {
+ $operandData['reference'] = $colKey.$rowKey;
+ }
+ }
+ return $operand;
+ }
+
+ // evaluate postfix notation
+ private function processTokenStack($tokens, $cellID = null, PHPExcel_Cell $pCell = null)
+ {
+ if ($tokens == false) {
+ return false;
+ }
+
+ // If we're using cell caching, then $pCell may well be flushed back to the cache (which detaches the parent cell collection),
+ // so we store the parent cell collection so that we can re-attach it when necessary
+ $pCellWorksheet = ($pCell !== null) ? $pCell->getWorksheet() : null;
+ $pCellParent = ($pCell !== null) ? $pCell->getParent() : null;
+ $stack = new PHPExcel_Calculation_Token_Stack;
+
+ // Loop through each token in turn
+ foreach ($tokens as $tokenData) {
+// print_r($tokenData);
+// echo ' ';
+ $token = $tokenData['value'];
+// echo 'Token is '.$token.' ';
+ // if the token is a binary operator, pop the top two values off the stack, do the operation, and push the result back on the stack
+ if (isset(self::$binaryOperators[$token])) {
+// echo 'Token is a binary operator ';
+ // We must have two operands, error if we don't
+ if (($operand2Data = $stack->pop()) === null) {
+ return $this->raiseFormulaError('Internal error - Operand value missing from stack');
+ }
+ if (($operand1Data = $stack->pop()) === null) {
+ return $this->raiseFormulaError('Internal error - Operand value missing from stack');
+ }
+
+ $operand1 = self::dataTestReference($operand1Data);
+ $operand2 = self::dataTestReference($operand2Data);
+
+ // Log what we're doing
+ if ($token == ':') {
+ $this->_debugLog->writeDebugLog('Evaluating Range ', $this->showValue($operand1Data['reference']), ' ', $token, ' ', $this->showValue($operand2Data['reference']));
+ } else {
+ $this->_debugLog->writeDebugLog('Evaluating ', $this->showValue($operand1), ' ', $token, ' ', $this->showValue($operand2));
+ }
+
+ // Process the operation in the appropriate manner
+ switch ($token) {
+ // Comparison (Boolean) Operators
+ case '>': // Greater than
+ case '<': // Less than
+ case '>=': // Greater than or Equal to
+ case '<=': // Less than or Equal to
+ case '=': // Equality
+ case '<>': // Inequality
+ $this->executeBinaryComparisonOperation($cellID, $operand1, $operand2, $token, $stack);
+ break;
+ // Binary Operators
+ case ':': // Range
+ $sheet1 = $sheet2 = '';
+ if (strpos($operand1Data['reference'], '!') !== false) {
+ list($sheet1, $operand1Data['reference']) = explode('!', $operand1Data['reference']);
+ } else {
+ $sheet1 = ($pCellParent !== null) ? $pCellWorksheet->getTitle() : '';
+ }
+ if (strpos($operand2Data['reference'], '!') !== false) {
+ list($sheet2, $operand2Data['reference']) = explode('!', $operand2Data['reference']);
+ } else {
+ $sheet2 = $sheet1;
+ }
+ if ($sheet1 == $sheet2) {
+ if ($operand1Data['reference'] === null) {
+ if ((trim($operand1Data['value']) != '') && (is_numeric($operand1Data['value']))) {
+ $operand1Data['reference'] = $pCell->getColumn().$operand1Data['value'];
+ } elseif (trim($operand1Data['reference']) == '') {
+ $operand1Data['reference'] = $pCell->getCoordinate();
+ } else {
+ $operand1Data['reference'] = $operand1Data['value'].$pCell->getRow();
+ }
+ }
+ if ($operand2Data['reference'] === null) {
+ if ((trim($operand2Data['value']) != '') && (is_numeric($operand2Data['value']))) {
+ $operand2Data['reference'] = $pCell->getColumn().$operand2Data['value'];
+ } elseif (trim($operand2Data['reference']) == '') {
+ $operand2Data['reference'] = $pCell->getCoordinate();
+ } else {
+ $operand2Data['reference'] = $operand2Data['value'].$pCell->getRow();
+ }
+ }
+
+ $oData = array_merge(explode(':', $operand1Data['reference']), explode(':', $operand2Data['reference']));
+ $oCol = $oRow = array();
+ foreach ($oData as $oDatum) {
+ $oCR = PHPExcel_Cell::coordinateFromString($oDatum);
+ $oCol[] = PHPExcel_Cell::columnIndexFromString($oCR[0]) - 1;
+ $oRow[] = $oCR[1];
+ }
+ $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow);
+ if ($pCellParent !== null) {
+ $cellValue = $this->extractCellRange($cellRef, $this->workbook->getSheetByName($sheet1), false);
+ } else {
+ return $this->raiseFormulaError('Unable to access Cell Reference');
+ }
+ $stack->push('Cell Reference', $cellValue, $cellRef);
+ } else {
+ $stack->push('Error', PHPExcel_Calculation_Functions::REF(), null);
+ }
+ break;
+ case '+': // Addition
+ $this->executeNumericBinaryOperation($cellID, $operand1, $operand2, $token, 'plusEquals', $stack);
+ break;
+ case '-': // Subtraction
+ $this->executeNumericBinaryOperation($cellID, $operand1, $operand2, $token, 'minusEquals', $stack);
+ break;
+ case '*': // Multiplication
+ $this->executeNumericBinaryOperation($cellID, $operand1, $operand2, $token, 'arrayTimesEquals', $stack);
+ break;
+ case '/': // Division
+ $this->executeNumericBinaryOperation($cellID, $operand1, $operand2, $token, 'arrayRightDivide', $stack);
+ break;
+ case '^': // Exponential
+ $this->executeNumericBinaryOperation($cellID, $operand1, $operand2, $token, 'power', $stack);
+ break;
+ case '&': // Concatenation
+ // If either of the operands is a matrix, we need to treat them both as matrices
+ // (converting the other operand to a matrix if need be); then perform the required
+ // matrix operation
+ if (is_bool($operand1)) {
+ $operand1 = ($operand1) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
+ }
+ if (is_bool($operand2)) {
+ $operand2 = ($operand2) ? self::$localeBoolean['TRUE'] : self::$localeBoolean['FALSE'];
+ }
+ if ((is_array($operand1)) || (is_array($operand2))) {
+ // Ensure that both operands are arrays/matrices
+ self::checkMatrixOperands($operand1, $operand2, 2);
+ try {
+ // Convert operand 1 from a PHP array to a matrix
+ $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1);
+ // Perform the required operation against the operand 1 matrix, passing in operand 2
+ $matrixResult = $matrix->concat($operand2);
+ $result = $matrixResult->getArray();
+ } catch (PHPExcel_Exception $ex) {
+ $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage());
+ $result = '#VALUE!';
+ }
+ } else {
+ $result = '"'.str_replace('""', '"', self::unwrapResult($operand1, '"').self::unwrapResult($operand2, '"')).'"';
+ }
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
+ $stack->push('Value', $result);
+ break;
+ case '|': // Intersect
+ $rowIntersect = array_intersect_key($operand1, $operand2);
+ $cellIntersect = $oCol = $oRow = array();
+ foreach (array_keys($rowIntersect) as $row) {
+ $oRow[] = $row;
+ foreach ($rowIntersect[$row] as $col => $data) {
+ $oCol[] = PHPExcel_Cell::columnIndexFromString($col) - 1;
+ $cellIntersect[$row] = array_intersect_key($operand1[$row], $operand2[$row]);
+ }
+ }
+ $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow);
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($cellIntersect));
+ $stack->push('Value', $cellIntersect, $cellRef);
+ break;
+ }
+
+ // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
+ } elseif (($token === '~') || ($token === '%')) {
+// echo 'Token is a unary operator ';
+ if (($arg = $stack->pop()) === null) {
+ return $this->raiseFormulaError('Internal error - Operand value missing from stack');
+ }
+ $arg = $arg['value'];
+ if ($token === '~') {
+// echo 'Token is a negation operator ';
+ $this->_debugLog->writeDebugLog('Evaluating Negation of ', $this->showValue($arg));
+ $multiplier = -1;
+ } else {
+// echo 'Token is a percentile operator ';
+ $this->_debugLog->writeDebugLog('Evaluating Percentile of ', $this->showValue($arg));
+ $multiplier = 0.01;
+ }
+ if (is_array($arg)) {
+ self::checkMatrixOperands($arg, $multiplier, 2);
+ try {
+ $matrix1 = new PHPExcel_Shared_JAMA_Matrix($arg);
+ $matrixResult = $matrix1->arrayTimesEquals($multiplier);
+ $result = $matrixResult->getArray();
+ } catch (PHPExcel_Exception $ex) {
+ $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage());
+ $result = '#VALUE!';
+ }
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
+ $stack->push('Value', $result);
+ } else {
+ $this->executeNumericBinaryOperation($cellID, $multiplier, $arg, '*', 'arrayTimesEquals', $stack);
+ }
+
+ } elseif (preg_match('/^'.self::CALCULATION_REGEXP_CELLREF.'$/i', $token, $matches)) {
+ $cellRef = null;
+// echo 'Element '.$token.' is a Cell reference ';
+ if (isset($matches[8])) {
+// echo 'Reference is a Range of cells ';
+ if ($pCell === null) {
+// We can't access the range, so return a REF error
+ $cellValue = PHPExcel_Calculation_Functions::REF();
+ } else {
+ $cellRef = $matches[6].$matches[7].':'.$matches[9].$matches[10];
+ if ($matches[2] > '') {
+ $matches[2] = trim($matches[2], "\"'");
+ if ((strpos($matches[2], '[') !== false) || (strpos($matches[2], ']') !== false)) {
+ // It's a Reference to an external workbook (not currently supported)
+ return $this->raiseFormulaError('Unable to access External Workbook');
+ }
+ $matches[2] = trim($matches[2], "\"'");
+// echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].' ';
+ $this->_debugLog->writeDebugLog('Evaluating Cell Range ', $cellRef, ' in worksheet ', $matches[2]);
+ if ($pCellParent !== null) {
+ $cellValue = $this->extractCellRange($cellRef, $this->workbook->getSheetByName($matches[2]), false);
+ } else {
+ return $this->raiseFormulaError('Unable to access Cell Reference');
+ }
+ $this->_debugLog->writeDebugLog('Evaluation Result for cells ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->showTypeDetails($cellValue));
+// $cellRef = $matches[2].'!'.$cellRef;
+ } else {
+// echo '$cellRef='.$cellRef.' in current worksheet ';
+ $this->_debugLog->writeDebugLog('Evaluating Cell Range ', $cellRef, ' in current worksheet');
+ if ($pCellParent !== null) {
+ $cellValue = $this->extractCellRange($cellRef, $pCellWorksheet, false);
+ } else {
+ return $this->raiseFormulaError('Unable to access Cell Reference');
+ }
+ $this->_debugLog->writeDebugLog('Evaluation Result for cells ', $cellRef, ' is ', $this->showTypeDetails($cellValue));
+ }
+ }
+ } else {
+// echo 'Reference is a single Cell ';
+ if ($pCell === null) {
+// We can't access the cell, so return a REF error
+ $cellValue = PHPExcel_Calculation_Functions::REF();
+ } else {
+ $cellRef = $matches[6].$matches[7];
+ if ($matches[2] > '') {
+ $matches[2] = trim($matches[2], "\"'");
+ if ((strpos($matches[2], '[') !== false) || (strpos($matches[2], ']') !== false)) {
+ // It's a Reference to an external workbook (not currently supported)
+ return $this->raiseFormulaError('Unable to access External Workbook');
+ }
+// echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].' ';
+ $this->_debugLog->writeDebugLog('Evaluating Cell ', $cellRef, ' in worksheet ', $matches[2]);
+ if ($pCellParent !== null) {
+ $cellSheet = $this->workbook->getSheetByName($matches[2]);
+ if ($cellSheet && $cellSheet->cellExists($cellRef)) {
+ $cellValue = $this->extractCellRange($cellRef, $this->workbook->getSheetByName($matches[2]), false);
+ $pCell->attach($pCellParent);
+ } else {
+ $cellValue = null;
+ }
+ } else {
+ return $this->raiseFormulaError('Unable to access Cell Reference');
+ }
+ $this->_debugLog->writeDebugLog('Evaluation Result for cell ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->showTypeDetails($cellValue));
+// $cellRef = $matches[2].'!'.$cellRef;
+ } else {
+// echo '$cellRef='.$cellRef.' in current worksheet ';
+ $this->_debugLog->writeDebugLog('Evaluating Cell ', $cellRef, ' in current worksheet');
+ if ($pCellParent->isDataSet($cellRef)) {
+ $cellValue = $this->extractCellRange($cellRef, $pCellWorksheet, false);
+ $pCell->attach($pCellParent);
+ } else {
+ $cellValue = null;
+ }
+ $this->_debugLog->writeDebugLog('Evaluation Result for cell ', $cellRef, ' is ', $this->showTypeDetails($cellValue));
+ }
+ }
+ }
+ $stack->push('Value', $cellValue, $cellRef);
+
+ // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
+ } elseif (preg_match('/^'.self::CALCULATION_REGEXP_FUNCTION.'$/i', $token, $matches)) {
+// echo 'Token is a function ';
+ $functionName = $matches[1];
+ $argCount = $stack->pop();
+ $argCount = $argCount['value'];
+ if ($functionName != 'MKMATRIX') {
+ $this->_debugLog->writeDebugLog('Evaluating Function ', self::localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's'));
+ }
+ if ((isset(self::$PHPExcelFunctions[$functionName])) || (isset(self::$controlFunctions[$functionName]))) { // function
+ if (isset(self::$PHPExcelFunctions[$functionName])) {
+ $functionCall = self::$PHPExcelFunctions[$functionName]['functionCall'];
+ $passByReference = isset(self::$PHPExcelFunctions[$functionName]['passByReference']);
+ $passCellReference = isset(self::$PHPExcelFunctions[$functionName]['passCellReference']);
+ } elseif (isset(self::$controlFunctions[$functionName])) {
+ $functionCall = self::$controlFunctions[$functionName]['functionCall'];
+ $passByReference = isset(self::$controlFunctions[$functionName]['passByReference']);
+ $passCellReference = isset(self::$controlFunctions[$functionName]['passCellReference']);
+ }
+ // get the arguments for this function
+// echo 'Function '.$functionName.' expects '.$argCount.' arguments ';
+ $args = $argArrayVals = array();
+ for ($i = 0; $i < $argCount; ++$i) {
+ $arg = $stack->pop();
+ $a = $argCount - $i - 1;
+ if (($passByReference) &&
+ (isset(self::$PHPExcelFunctions[$functionName]['passByReference'][$a])) &&
+ (self::$PHPExcelFunctions[$functionName]['passByReference'][$a])) {
+ if ($arg['reference'] === null) {
+ $args[] = $cellID;
+ if ($functionName != 'MKMATRIX') {
+ $argArrayVals[] = $this->showValue($cellID);
+ }
+ } else {
+ $args[] = $arg['reference'];
+ if ($functionName != 'MKMATRIX') {
+ $argArrayVals[] = $this->showValue($arg['reference']);
+ }
+ }
+ } else {
+ $args[] = self::unwrapResult($arg['value']);
+ if ($functionName != 'MKMATRIX') {
+ $argArrayVals[] = $this->showValue($arg['value']);
+ }
+ }
+ }
+ // Reverse the order of the arguments
+ krsort($args);
+ if (($passByReference) && ($argCount == 0)) {
+ $args[] = $cellID;
+ $argArrayVals[] = $this->showValue($cellID);
+ }
+// echo 'Arguments are: ';
+// print_r($args);
+// echo ' ';
+ if ($functionName != 'MKMATRIX') {
+ if ($this->_debugLog->getWriteDebugLog()) {
+ krsort($argArrayVals);
+ $this->_debugLog->writeDebugLog('Evaluating ', self::localeFunc($functionName), '( ', implode(self::$localeArgumentSeparator.' ', PHPExcel_Calculation_Functions::flattenArray($argArrayVals)), ' )');
+ }
+ }
+ // Process each argument in turn, building the return value as an array
+// if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) {
+// $operand1 = $args[1];
+// $this->_debugLog->writeDebugLog('Argument is a matrix: ', $this->showValue($operand1));
+// $result = array();
+// $row = 0;
+// foreach($operand1 as $args) {
+// if (is_array($args)) {
+// foreach($args as $arg) {
+// $this->_debugLog->writeDebugLog('Evaluating ', self::localeFunc($functionName), '( ', $this->showValue($arg), ' )');
+// $r = call_user_func_array($functionCall, $arg);
+// $this->_debugLog->writeDebugLog('Evaluation Result for ', self::localeFunc($functionName), '() function call is ', $this->showTypeDetails($r));
+// $result[$row][] = $r;
+// }
+// ++$row;
+// } else {
+// $this->_debugLog->writeDebugLog('Evaluating ', self::localeFunc($functionName), '( ', $this->showValue($args), ' )');
+// $r = call_user_func_array($functionCall, $args);
+// $this->_debugLog->writeDebugLog('Evaluation Result for ', self::localeFunc($functionName), '() function call is ', $this->showTypeDetails($r));
+// $result[] = $r;
+// }
+// }
+// } else {
+ // Process the argument with the appropriate function call
+ if ($passCellReference) {
+ $args[] = $pCell;
+ }
+ if (strpos($functionCall, '::') !== false) {
+ $result = call_user_func_array(explode('::', $functionCall), $args);
+ } else {
+ foreach ($args as &$arg) {
+ $arg = PHPExcel_Calculation_Functions::flattenSingleValue($arg);
+ }
+ unset($arg);
+ $result = call_user_func_array($functionCall, $args);
+ }
+ if ($functionName != 'MKMATRIX') {
+ $this->_debugLog->writeDebugLog('Evaluation Result for ', self::localeFunc($functionName), '() function call is ', $this->showTypeDetails($result));
+ }
+ $stack->push('Value', self::wrapResult($result));
+ }
+
+ } else {
+ // if the token is a number, boolean, string or an Excel error, push it onto the stack
+ if (isset(self::$excelConstants[strtoupper($token)])) {
+ $excelConstant = strtoupper($token);
+// echo 'Token is a PHPExcel constant: '.$excelConstant.' ';
+ $stack->push('Constant Value', self::$excelConstants[$excelConstant]);
+ $this->_debugLog->writeDebugLog('Evaluating Constant ', $excelConstant, ' as ', $this->showTypeDetails(self::$excelConstants[$excelConstant]));
+ } elseif ((is_numeric($token)) || ($token === null) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) {
+// echo 'Token is a number, boolean, string, null or an Excel error ';
+ $stack->push('Value', $token);
+ // if the token is a named range, push the named range name onto the stack
+ } elseif (preg_match('/^'.self::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $token, $matches)) {
+// echo 'Token is a named range ';
+ $namedRange = $matches[6];
+// echo 'Named Range is '.$namedRange.' ';
+ $this->_debugLog->writeDebugLog('Evaluating Named Range ', $namedRange);
+ $cellValue = $this->extractNamedRange($namedRange, ((null !== $pCell) ? $pCellWorksheet : null), false);
+ $pCell->attach($pCellParent);
+ $this->_debugLog->writeDebugLog('Evaluation Result for named range ', $namedRange, ' is ', $this->showTypeDetails($cellValue));
+ $stack->push('Named Range', $cellValue, $namedRange);
+ } else {
+ return $this->raiseFormulaError("undefined variable '$token'");
+ }
+ }
+ }
+ // when we're out of tokens, the stack should have a single element, the final result
+ if ($stack->count() != 1) {
+ return $this->raiseFormulaError("internal error");
+ }
+ $output = $stack->pop();
+ $output = $output['value'];
+
+// if ((is_array($output)) && (self::$returnArrayAsType != self::RETURN_ARRAY_AS_ARRAY)) {
+// return array_shift(PHPExcel_Calculation_Functions::flattenArray($output));
+// }
+ return $output;
+ }
+
+
+ private function validateBinaryOperand($cellID, &$operand, &$stack)
+ {
+ if (is_array($operand)) {
+ if ((count($operand, COUNT_RECURSIVE) - count($operand)) == 1) {
+ do {
+ $operand = array_pop($operand);
+ } while (is_array($operand));
+ }
+ }
+ // Numbers, matrices and booleans can pass straight through, as they're already valid
+ if (is_string($operand)) {
+ // We only need special validations for the operand if it is a string
+ // Start by stripping off the quotation marks we use to identify true excel string values internally
+ if ($operand > '' && $operand{0} == '"') {
+ $operand = self::unwrapResult($operand);
+ }
+ // If the string is a numeric value, we treat it as a numeric, so no further testing
+ if (!is_numeric($operand)) {
+ // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations
+ if ($operand > '' && $operand{0} == '#') {
+ $stack->push('Value', $operand);
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($operand));
+ return false;
+ } elseif (!PHPExcel_Shared_String::convertToNumberIfFraction($operand)) {
+ // If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations
+ $stack->push('Value', '#VALUE!');
+ $this->_debugLog->writeDebugLog('Evaluation Result is a ', $this->showTypeDetails('#VALUE!'));
+ return false;
+ }
+ }
+ }
+
+ // return a true if the value of the operand is one that we can use in normal binary operations
+ return true;
+ }
+
+
+ private function executeBinaryComparisonOperation($cellID, $operand1, $operand2, $operation, &$stack, $recursingArrays = false)
+ {
+ // If we're dealing with matrix operations, we want a matrix result
+ if ((is_array($operand1)) || (is_array($operand2))) {
+ $result = array();
+ if ((is_array($operand1)) && (!is_array($operand2))) {
+ foreach ($operand1 as $x => $operandData) {
+ $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2));
+ $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack);
+ $r = $stack->pop();
+ $result[$x] = $r['value'];
+ }
+ } elseif ((!is_array($operand1)) && (is_array($operand2))) {
+ foreach ($operand2 as $x => $operandData) {
+ $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operand1), ' ', $operation, ' ', $this->showValue($operandData));
+ $this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack);
+ $r = $stack->pop();
+ $result[$x] = $r['value'];
+ }
+ } else {
+ if (!$recursingArrays) {
+ self::checkMatrixOperands($operand1, $operand2, 2);
+ }
+ foreach ($operand1 as $x => $operandData) {
+ $this->_debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2[$x]));
+ $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2[$x], $operation, $stack, true);
+ $r = $stack->pop();
+ $result[$x] = $r['value'];
+ }
+ }
+ // Log the result details
+ $this->_debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->showTypeDetails($result));
+ // And push the result onto the stack
+ $stack->push('Array', $result);
+ return true;
+ }
+
+ // Simple validate the two operands if they are string values
+ if (is_string($operand1) && $operand1 > '' && $operand1{0} == '"') {
+ $operand1 = self::unwrapResult($operand1);
+ }
+ if (is_string($operand2) && $operand2 > '' && $operand2{0} == '"') {
+ $operand2 = self::unwrapResult($operand2);
+ }
+
+ // Use case insensitive comparaison if not OpenOffice mode
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ if (is_string($operand1)) {
+ $operand1 = strtoupper($operand1);
+ }
+ if (is_string($operand2)) {
+ $operand2 = strtoupper($operand2);
+ }
+ }
+
+ $useLowercaseFirstComparison = is_string($operand1) && is_string($operand2) && PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE;
+
+ // execute the necessary operation
+ switch ($operation) {
+ // Greater than
+ case '>':
+ if ($useLowercaseFirstComparison) {
+ $result = $this->strcmpLowercaseFirst($operand1, $operand2) > 0;
+ } else {
+ $result = ($operand1 > $operand2);
+ }
+ break;
+ // Less than
+ case '<':
+ if ($useLowercaseFirstComparison) {
+ $result = $this->strcmpLowercaseFirst($operand1, $operand2) < 0;
+ } else {
+ $result = ($operand1 < $operand2);
+ }
+ break;
+ // Equality
+ case '=':
+ if (is_numeric($operand1) && is_numeric($operand2)) {
+ $result = (abs($operand1 - $operand2) < $this->delta);
+ } else {
+ $result = strcmp($operand1, $operand2) == 0;
+ }
+ break;
+ // Greater than or equal
+ case '>=':
+ if (is_numeric($operand1) && is_numeric($operand2)) {
+ $result = ((abs($operand1 - $operand2) < $this->delta) || ($operand1 > $operand2));
+ } elseif ($useLowercaseFirstComparison) {
+ $result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0;
+ } else {
+ $result = strcmp($operand1, $operand2) >= 0;
+ }
+ break;
+ // Less than or equal
+ case '<=':
+ if (is_numeric($operand1) && is_numeric($operand2)) {
+ $result = ((abs($operand1 - $operand2) < $this->delta) || ($operand1 < $operand2));
+ } elseif ($useLowercaseFirstComparison) {
+ $result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0;
+ } else {
+ $result = strcmp($operand1, $operand2) <= 0;
+ }
+ break;
+ // Inequality
+ case '<>':
+ if (is_numeric($operand1) && is_numeric($operand2)) {
+ $result = (abs($operand1 - $operand2) > 1E-14);
+ } else {
+ $result = strcmp($operand1, $operand2) != 0;
+ }
+ break;
+ }
+
+ // Log the result details
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
+ // And push the result onto the stack
+ $stack->push('Value', $result);
+ return true;
+ }
+
+ /**
+ * Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters
+ * @param string $str1 First string value for the comparison
+ * @param string $str2 Second string value for the comparison
+ * @return integer
+ */
+ private function strcmpLowercaseFirst($str1, $str2)
+ {
+ $inversedStr1 = PHPExcel_Shared_String::StrCaseReverse($str1);
+ $inversedStr2 = PHPExcel_Shared_String::StrCaseReverse($str2);
+
+ return strcmp($inversedStr1, $inversedStr2);
+ }
+
+ private function executeNumericBinaryOperation($cellID, $operand1, $operand2, $operation, $matrixFunction, &$stack)
+ {
+ // Validate the two operands
+ if (!$this->validateBinaryOperand($cellID, $operand1, $stack)) {
+ return false;
+ }
+ if (!$this->validateBinaryOperand($cellID, $operand2, $stack)) {
+ return false;
+ }
+
+ // If either of the operands is a matrix, we need to treat them both as matrices
+ // (converting the other operand to a matrix if need be); then perform the required
+ // matrix operation
+ if ((is_array($operand1)) || (is_array($operand2))) {
+ // Ensure that both operands are arrays/matrices of the same size
+ self::checkMatrixOperands($operand1, $operand2, 2);
+
+ try {
+ // Convert operand 1 from a PHP array to a matrix
+ $matrix = new PHPExcel_Shared_JAMA_Matrix($operand1);
+ // Perform the required operation against the operand 1 matrix, passing in operand 2
+ $matrixResult = $matrix->$matrixFunction($operand2);
+ $result = $matrixResult->getArray();
+ } catch (PHPExcel_Exception $ex) {
+ $this->_debugLog->writeDebugLog('JAMA Matrix Exception: ', $ex->getMessage());
+ $result = '#VALUE!';
+ }
+ } else {
+ if ((PHPExcel_Calculation_Functions::getCompatibilityMode() != PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) &&
+ ((is_string($operand1) && !is_numeric($operand1) && strlen($operand1)>0) ||
+ (is_string($operand2) && !is_numeric($operand2) && strlen($operand2)>0))) {
+ $result = PHPExcel_Calculation_Functions::VALUE();
+ } else {
+ // If we're dealing with non-matrix operations, execute the necessary operation
+ switch ($operation) {
+ // Addition
+ case '+':
+ $result = $operand1 + $operand2;
+ break;
+ // Subtraction
+ case '-':
+ $result = $operand1 - $operand2;
+ break;
+ // Multiplication
+ case '*':
+ $result = $operand1 * $operand2;
+ break;
+ // Division
+ case '/':
+ if ($operand2 == 0) {
+ // Trap for Divide by Zero error
+ $stack->push('Value', '#DIV/0!');
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails('#DIV/0!'));
+ return false;
+ } else {
+ $result = $operand1 / $operand2;
+ }
+ break;
+ // Power
+ case '^':
+ $result = pow($operand1, $operand2);
+ break;
+ }
+ }
+ }
+
+ // Log the result details
+ $this->_debugLog->writeDebugLog('Evaluation Result is ', $this->showTypeDetails($result));
+ // And push the result onto the stack
+ $stack->push('Value', $result);
+ return true;
+ }
+
+
+ // trigger an error, but nicely, if need be
+ protected function raiseFormulaError($errorMessage)
+ {
+ $this->formulaError = $errorMessage;
+ $this->cyclicReferenceStack->clear();
+ if (!$this->suppressFormulaErrors) {
+ throw new PHPExcel_Calculation_Exception($errorMessage);
+ }
+ trigger_error($errorMessage, E_USER_ERROR);
+ }
+
+
+ /**
+ * Extract range values
+ *
+ * @param string &$pRange String based range representation
+ * @param PHPExcel_Worksheet $pSheet Worksheet
+ * @param boolean $resetLog Flag indicating whether calculation log should be reset or not
+ * @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned.
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function extractCellRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog = true)
+ {
+ // Return value
+ $returnValue = array ();
+
+// echo 'extractCellRange('.$pRange.')', PHP_EOL;
+ if ($pSheet !== null) {
+ $pSheetName = $pSheet->getTitle();
+// echo 'Passed sheet name is '.$pSheetName.PHP_EOL;
+// echo 'Range reference is '.$pRange.PHP_EOL;
+ if (strpos($pRange, '!') !== false) {
+// echo '$pRange reference includes sheet reference', PHP_EOL;
+ list($pSheetName, $pRange) = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
+// echo 'New sheet name is '.$pSheetName, PHP_EOL;
+// echo 'Adjusted Range reference is '.$pRange, PHP_EOL;
+ $pSheet = $this->workbook->getSheetByName($pSheetName);
+ }
+
+ // Extract range
+ $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
+ $pRange = $pSheetName.'!'.$pRange;
+ if (!isset($aReferences[1])) {
+ // Single cell in range
+ sscanf($aReferences[0], '%[A-Z]%d', $currentCol, $currentRow);
+ $cellValue = null;
+ if ($pSheet->cellExists($aReferences[0])) {
+ $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
+ } else {
+ $returnValue[$currentRow][$currentCol] = null;
+ }
+ } else {
+ // Extract cell data for all cells in the range
+ foreach ($aReferences as $reference) {
+ // Extract range
+ sscanf($reference, '%[A-Z]%d', $currentCol, $currentRow);
+ $cellValue = null;
+ if ($pSheet->cellExists($reference)) {
+ $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
+ } else {
+ $returnValue[$currentRow][$currentCol] = null;
+ }
+ }
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * Extract range values
+ *
+ * @param string &$pRange String based range representation
+ * @param PHPExcel_Worksheet $pSheet Worksheet
+ * @return mixed Array of values in range if range contains more than one element. Otherwise, a single value is returned.
+ * @param boolean $resetLog Flag indicating whether calculation log should be reset or not
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function extractNamedRange(&$pRange = 'A1', PHPExcel_Worksheet $pSheet = null, $resetLog = true)
+ {
+ // Return value
+ $returnValue = array ();
+
+// echo 'extractNamedRange('.$pRange.') ';
+ if ($pSheet !== null) {
+ $pSheetName = $pSheet->getTitle();
+// echo 'Current sheet name is '.$pSheetName.' ';
+// echo 'Range reference is '.$pRange.' ';
+ if (strpos($pRange, '!') !== false) {
+// echo '$pRange reference includes sheet reference', PHP_EOL;
+ list($pSheetName, $pRange) = PHPExcel_Worksheet::extractSheetTitle($pRange, true);
+// echo 'New sheet name is '.$pSheetName, PHP_EOL;
+// echo 'Adjusted Range reference is '.$pRange, PHP_EOL;
+ $pSheet = $this->workbook->getSheetByName($pSheetName);
+ }
+
+ // Named range?
+ $namedRange = PHPExcel_NamedRange::resolveRange($pRange, $pSheet);
+ if ($namedRange !== null) {
+ $pSheet = $namedRange->getWorksheet();
+// echo 'Named Range '.$pRange.' (';
+ $pRange = $namedRange->getRange();
+ $splitRange = PHPExcel_Cell::splitRange($pRange);
+ // Convert row and column references
+ if (ctype_alpha($splitRange[0][0])) {
+ $pRange = $splitRange[0][0] . '1:' . $splitRange[0][1] . $namedRange->getWorksheet()->getHighestRow();
+ } elseif (ctype_digit($splitRange[0][0])) {
+ $pRange = 'A' . $splitRange[0][0] . ':' . $namedRange->getWorksheet()->getHighestColumn() . $splitRange[0][1];
+ }
+// echo $pRange.') is in sheet '.$namedRange->getWorksheet()->getTitle().' ';
+
+// if ($pSheet->getTitle() != $namedRange->getWorksheet()->getTitle()) {
+// if (!$namedRange->getLocalOnly()) {
+// $pSheet = $namedRange->getWorksheet();
+// } else {
+// return $returnValue;
+// }
+// }
+ } else {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+
+ // Extract range
+ $aReferences = PHPExcel_Cell::extractAllCellReferencesInRange($pRange);
+// var_dump($aReferences);
+ if (!isset($aReferences[1])) {
+ // Single cell (or single column or row) in range
+ list($currentCol, $currentRow) = PHPExcel_Cell::coordinateFromString($aReferences[0]);
+ $cellValue = null;
+ if ($pSheet->cellExists($aReferences[0])) {
+ $returnValue[$currentRow][$currentCol] = $pSheet->getCell($aReferences[0])->getCalculatedValue($resetLog);
+ } else {
+ $returnValue[$currentRow][$currentCol] = null;
+ }
+ } else {
+ // Extract cell data for all cells in the range
+ foreach ($aReferences as $reference) {
+ // Extract range
+ list($currentCol, $currentRow) = PHPExcel_Cell::coordinateFromString($reference);
+// echo 'NAMED RANGE: $currentCol='.$currentCol.' $currentRow='.$currentRow.' ';
+ $cellValue = null;
+ if ($pSheet->cellExists($reference)) {
+ $returnValue[$currentRow][$currentCol] = $pSheet->getCell($reference)->getCalculatedValue($resetLog);
+ } else {
+ $returnValue[$currentRow][$currentCol] = null;
+ }
+ }
+ }
+// print_r($returnValue);
+// echo ' ';
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * Is a specific function implemented?
+ *
+ * @param string $pFunction Function Name
+ * @return boolean
+ */
+ public function isImplemented($pFunction = '')
+ {
+ $pFunction = strtoupper($pFunction);
+ if (isset(self::$PHPExcelFunctions[$pFunction])) {
+ return (self::$PHPExcelFunctions[$pFunction]['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY');
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Get a list of all implemented functions as an array of function objects
+ *
+ * @return array of PHPExcel_Calculation_Function
+ */
+ public function listFunctions()
+ {
+ $returnValue = array();
+
+ foreach (self::$PHPExcelFunctions as $functionName => $function) {
+ if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
+ $returnValue[$functionName] = new PHPExcel_Calculation_Function(
+ $function['category'],
+ $functionName,
+ $function['functionCall']
+ );
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * Get a list of all Excel function names
+ *
+ * @return array
+ */
+ public function listAllFunctionNames()
+ {
+ return array_keys(self::$PHPExcelFunctions);
+ }
+
+ /**
+ * Get a list of implemented Excel function names
+ *
+ * @return array
+ */
+ public function listFunctionNames()
+ {
+ $returnValue = array();
+ foreach (self::$PHPExcelFunctions as $functionName => $function) {
+ if ($function['functionCall'] != 'PHPExcel_Calculation_Functions::DUMMY') {
+ $returnValue[] = $functionName;
+ }
+ }
+
+ return $returnValue;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Database.php b/extend/PHPExcel/PHPExcel/Calculation/Database.php
new file mode 100755
index 0000000..b8d91cb
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Database.php
@@ -0,0 +1,676 @@
+ $criteriaName) {
+ $testCondition = array();
+ $testConditionCount = 0;
+ foreach ($criteria as $row => $criterion) {
+ if ($criterion[$key] > '') {
+ $testCondition[] = '[:'.$criteriaName.']'.PHPExcel_Calculation_Functions::ifCondition($criterion[$key]);
+ $testConditionCount++;
+ }
+ }
+ if ($testConditionCount > 1) {
+ $testConditions[] = 'OR(' . implode(',', $testCondition) . ')';
+ $testConditionsCount++;
+ } elseif ($testConditionCount == 1) {
+ $testConditions[] = $testCondition[0];
+ $testConditionsCount++;
+ }
+ }
+
+ if ($testConditionsCount > 1) {
+ $testConditionSet = 'AND(' . implode(',', $testConditions) . ')';
+ } elseif ($testConditionsCount == 1) {
+ $testConditionSet = $testConditions[0];
+ }
+
+ // Loop through each row of the database
+ foreach ($database as $dataRow => $dataValues) {
+ // Substitute actual values from the database row for our [:placeholders]
+ $testConditionList = $testConditionSet;
+ foreach ($criteriaNames as $key => $criteriaName) {
+ $k = array_search($criteriaName, $fieldNames);
+ if (isset($dataValues[$k])) {
+ $dataValue = $dataValues[$k];
+ $dataValue = (is_string($dataValue)) ? PHPExcel_Calculation::wrapResult(strtoupper($dataValue)) : $dataValue;
+ $testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList);
+ }
+ }
+ // evaluate the criteria against the row data
+ $result = PHPExcel_Calculation::getInstance()->_calculateFormulaValue('='.$testConditionList);
+ // If the row failed to meet the criteria, remove it from the database
+ if (!$result) {
+ unset($database[$dataRow]);
+ }
+ }
+
+ return $database;
+ }
+
+
+ private static function getFilteredColumn($database, $field, $criteria)
+ {
+ // reduce the database to a set of rows that match all the criteria
+ $database = self::filter($database, $criteria);
+ // extract an array of values for the requested column
+ $colData = array();
+ foreach ($database as $row) {
+ $colData[] = $row[$field];
+ }
+
+ return $colData;
+ }
+
+ /**
+ * DAVERAGE
+ *
+ * Averages the values in a column of a list or database that match conditions you specify.
+ *
+ * Excel Function:
+ * DAVERAGE(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DAVERAGE($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::AVERAGE(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DCOUNT
+ *
+ * Counts the cells that contain numbers in a column of a list or database that match conditions
+ * that you specify.
+ *
+ * Excel Function:
+ * DCOUNT(database,[field],criteria)
+ *
+ * Excel Function:
+ * DAVERAGE(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return integer
+ *
+ * @TODO The field argument is optional. If field is omitted, DCOUNT counts all records in the
+ * database that match the criteria.
+ *
+ */
+ public static function DCOUNT($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::COUNT(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DCOUNTA
+ *
+ * Counts the nonblank cells in a column of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DCOUNTA(database,[field],criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return integer
+ *
+ * @TODO The field argument is optional. If field is omitted, DCOUNTA counts all records in the
+ * database that match the criteria.
+ *
+ */
+ public static function DCOUNTA($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // reduce the database to a set of rows that match all the criteria
+ $database = self::filter($database, $criteria);
+ // extract an array of values for the requested column
+ $colData = array();
+ foreach ($database as $row) {
+ $colData[] = $row[$field];
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::COUNTA(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DGET
+ *
+ * Extracts a single value from a column of a list or database that matches conditions that you
+ * specify.
+ *
+ * Excel Function:
+ * DGET(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return mixed
+ *
+ */
+ public static function DGET($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ $colData = self::getFilteredColumn($database, $field, $criteria);
+ if (count($colData) > 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return $colData[0];
+ }
+
+
+ /**
+ * DMAX
+ *
+ * Returns the largest number in a column of a list or database that matches conditions you that
+ * specify.
+ *
+ * Excel Function:
+ * DMAX(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DMAX($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::MAX(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DMIN
+ *
+ * Returns the smallest number in a column of a list or database that matches conditions you that
+ * specify.
+ *
+ * Excel Function:
+ * DMIN(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DMIN($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::MIN(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DPRODUCT
+ *
+ * Multiplies the values in a column of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DPRODUCT(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DPRODUCT($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_MathTrig::PRODUCT(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DSTDEV
+ *
+ * Estimates the standard deviation of a population based on a sample by using the numbers in a
+ * column of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DSTDEV(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DSTDEV($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::STDEV(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DSTDEVP
+ *
+ * Calculates the standard deviation of a population based on the entire population by using the
+ * numbers in a column of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DSTDEVP(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DSTDEVP($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::STDEVP(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DSUM
+ *
+ * Adds the numbers in a column of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DSUM(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DSUM($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_MathTrig::SUM(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DVAR
+ *
+ * Estimates the variance of a population based on a sample by using the numbers in a column
+ * of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DVAR(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DVAR($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::VARFunc(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+
+
+ /**
+ * DVARP
+ *
+ * Calculates the variance of a population based on the entire population by using the numbers
+ * in a column of a list or database that match conditions that you specify.
+ *
+ * Excel Function:
+ * DVARP(database,field,criteria)
+ *
+ * @access public
+ * @category Database Functions
+ * @param mixed[] $database The range of cells that makes up the list or database.
+ * A database is a list of related data in which rows of related
+ * information are records, and columns of data are fields. The
+ * first row of the list contains labels for each column.
+ * @param string|integer $field Indicates which column is used in the function. Enter the
+ * column label enclosed between double quotation marks, such as
+ * "Age" or "Yield," or a number (without quotation marks) that
+ * represents the position of the column within the list: 1 for
+ * the first column, 2 for the second column, and so on.
+ * @param mixed[] $criteria The range of cells that contains the conditions you specify.
+ * You can use any range for the criteria argument, as long as it
+ * includes at least one column label and at least one cell below
+ * the column label in which you specify a condition for the
+ * column.
+ * @return float
+ *
+ */
+ public static function DVARP($database, $field, $criteria)
+ {
+ $field = self::fieldExtract($database, $field);
+ if (is_null($field)) {
+ return null;
+ }
+
+ // Return
+ return PHPExcel_Calculation_Statistical::VARP(
+ self::getFilteredColumn($database, $field, $criteria)
+ );
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/DateTime.php b/extend/PHPExcel/PHPExcel/Calculation/DateTime.php
new file mode 100755
index 0000000..72f4c7a
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/DateTime.php
@@ -0,0 +1,1553 @@
+format('m');
+ $oYear = (int) $PHPDateObject->format('Y');
+
+ $adjustmentMonthsString = (string) $adjustmentMonths;
+ if ($adjustmentMonths > 0) {
+ $adjustmentMonthsString = '+'.$adjustmentMonths;
+ }
+ if ($adjustmentMonths != 0) {
+ $PHPDateObject->modify($adjustmentMonthsString.' months');
+ }
+ $nMonth = (int) $PHPDateObject->format('m');
+ $nYear = (int) $PHPDateObject->format('Y');
+
+ $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
+ if ($monthDiff != $adjustmentMonths) {
+ $adjustDays = (int) $PHPDateObject->format('d');
+ $adjustDaysString = '-'.$adjustDays.' days';
+ $PHPDateObject->modify($adjustDaysString);
+ }
+ return $PHPDateObject;
+ }
+
+
+ /**
+ * DATETIMENOW
+ *
+ * Returns the current date and time.
+ * The NOW function is useful when you need to display the current date and time on a worksheet or
+ * calculate a value based on the current date and time, and have that value updated each time you
+ * open the worksheet.
+ *
+ * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+ * and time format of your regional settings. PHPExcel does not change cell formatting in this way.
+ *
+ * Excel Function:
+ * NOW()
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function DATETIMENOW()
+ {
+ $saveTimeZone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+ $retValue = false;
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
+ break;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ $retValue = (integer) time();
+ break;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ $retValue = new DateTime();
+ break;
+ }
+ date_default_timezone_set($saveTimeZone);
+
+ return $retValue;
+ }
+
+
+ /**
+ * DATENOW
+ *
+ * Returns the current date.
+ * The NOW function is useful when you need to display the current date and time on a worksheet or
+ * calculate a value based on the current date and time, and have that value updated each time you
+ * open the worksheet.
+ *
+ * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+ * and time format of your regional settings. PHPExcel does not change cell formatting in this way.
+ *
+ * Excel Function:
+ * TODAY()
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function DATENOW()
+ {
+ $saveTimeZone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+ $retValue = false;
+ $excelDateTime = floor(PHPExcel_Shared_Date::PHPToExcel(time()));
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ $retValue = (float) $excelDateTime;
+ break;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime);
+ break;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ $retValue = PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
+ break;
+ }
+ date_default_timezone_set($saveTimeZone);
+
+ return $retValue;
+ }
+
+
+ /**
+ * DATE
+ *
+ * The DATE function returns a value that represents a particular date.
+ *
+ * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+ * format of your regional settings. PHPExcel does not change cell formatting in this way.
+ *
+ * Excel Function:
+ * DATE(year,month,day)
+ *
+ * PHPExcel is a lot more forgiving than MS Excel when passing non numeric values to this function.
+ * A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
+ * as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param integer $year The value of the year argument can include one to four digits.
+ * Excel interprets the year argument according to the configured
+ * date system: 1900 or 1904.
+ * If year is between 0 (zero) and 1899 (inclusive), Excel adds that
+ * value to 1900 to calculate the year. For example, DATE(108,1,2)
+ * returns January 2, 2008 (1900+108).
+ * If year is between 1900 and 9999 (inclusive), Excel uses that
+ * value as the year. For example, DATE(2008,1,2) returns January 2,
+ * 2008.
+ * If year is less than 0 or is 10000 or greater, Excel returns the
+ * #NUM! error value.
+ * @param integer $month A positive or negative integer representing the month of the year
+ * from 1 to 12 (January to December).
+ * If month is greater than 12, month adds that number of months to
+ * the first month in the year specified. For example, DATE(2008,14,2)
+ * returns the serial number representing February 2, 2009.
+ * If month is less than 1, month subtracts the magnitude of that
+ * number of months, plus 1, from the first month in the year
+ * specified. For example, DATE(2008,-3,2) returns the serial number
+ * representing September 2, 2007.
+ * @param integer $day A positive or negative integer representing the day of the month
+ * from 1 to 31.
+ * If day is greater than the number of days in the month specified,
+ * day adds that number of days to the first day in the month. For
+ * example, DATE(2008,1,35) returns the serial number representing
+ * February 4, 2008.
+ * If day is less than 1, day subtracts the magnitude that number of
+ * days, plus one, from the first day of the month specified. For
+ * example, DATE(2008,1,-15) returns the serial number representing
+ * December 16, 2007.
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function DATE($year = 0, $month = 1, $day = 1)
+ {
+ $year = PHPExcel_Calculation_Functions::flattenSingleValue($year);
+ $month = PHPExcel_Calculation_Functions::flattenSingleValue($month);
+ $day = PHPExcel_Calculation_Functions::flattenSingleValue($day);
+
+ if (($month !== null) && (!is_numeric($month))) {
+ $month = PHPExcel_Shared_Date::monthStringToNumber($month);
+ }
+
+ if (($day !== null) && (!is_numeric($day))) {
+ $day = PHPExcel_Shared_Date::dayStringToNumber($day);
+ }
+
+ $year = ($year !== null) ? PHPExcel_Shared_String::testStringAsNumeric($year) : 0;
+ $month = ($month !== null) ? PHPExcel_Shared_String::testStringAsNumeric($month) : 0;
+ $day = ($day !== null) ? PHPExcel_Shared_String::testStringAsNumeric($day) : 0;
+ if ((!is_numeric($year)) ||
+ (!is_numeric($month)) ||
+ (!is_numeric($day))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $year = (integer) $year;
+ $month = (integer) $month;
+ $day = (integer) $day;
+
+ $baseYear = PHPExcel_Shared_Date::getExcelCalendar();
+ // Validate parameters
+ if ($year < ($baseYear-1900)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((($baseYear-1900) != 0) && ($year < $baseYear) && ($year >= 1900)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ if (($year < $baseYear) && ($year >= ($baseYear-1900))) {
+ $year += 1900;
+ }
+
+ if ($month < 1) {
+ // Handle year/month adjustment if month < 1
+ --$month;
+ $year += ceil($month / 12) - 1;
+ $month = 13 - abs($month % 12);
+ } elseif ($month > 12) {
+ // Handle year/month adjustment if month > 12
+ $year += floor($month / 12);
+ $month = ($month % 12);
+ }
+
+ // Re-validate the year parameter after adjustments
+ if (($year < $baseYear) || ($year >= 10000)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day);
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ return (float) $excelDateValue;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
+ }
+ }
+
+
+ /**
+ * TIME
+ *
+ * The TIME function returns a value that represents a particular time.
+ *
+ * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
+ * format of your regional settings. PHPExcel does not change cell formatting in this way.
+ *
+ * Excel Function:
+ * TIME(hour,minute,second)
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param integer $hour A number from 0 (zero) to 32767 representing the hour.
+ * Any value greater than 23 will be divided by 24 and the remainder
+ * will be treated as the hour value. For example, TIME(27,0,0) =
+ * TIME(3,0,0) = .125 or 3:00 AM.
+ * @param integer $minute A number from 0 to 32767 representing the minute.
+ * Any value greater than 59 will be converted to hours and minutes.
+ * For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
+ * @param integer $second A number from 0 to 32767 representing the second.
+ * Any value greater than 59 will be converted to hours, minutes,
+ * and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
+ * or 12:33:20 AM
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function TIME($hour = 0, $minute = 0, $second = 0)
+ {
+ $hour = PHPExcel_Calculation_Functions::flattenSingleValue($hour);
+ $minute = PHPExcel_Calculation_Functions::flattenSingleValue($minute);
+ $second = PHPExcel_Calculation_Functions::flattenSingleValue($second);
+
+ if ($hour == '') {
+ $hour = 0;
+ }
+ if ($minute == '') {
+ $minute = 0;
+ }
+ if ($second == '') {
+ $second = 0;
+ }
+
+ if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $hour = (integer) $hour;
+ $minute = (integer) $minute;
+ $second = (integer) $second;
+
+ if ($second < 0) {
+ $minute += floor($second / 60);
+ $second = 60 - abs($second % 60);
+ if ($second == 60) {
+ $second = 0;
+ }
+ } elseif ($second >= 60) {
+ $minute += floor($second / 60);
+ $second = $second % 60;
+ }
+ if ($minute < 0) {
+ $hour += floor($minute / 60);
+ $minute = 60 - abs($minute % 60);
+ if ($minute == 60) {
+ $minute = 0;
+ }
+ } elseif ($minute >= 60) {
+ $hour += floor($minute / 60);
+ $minute = $minute % 60;
+ }
+
+ if ($hour > 23) {
+ $hour = $hour % 24;
+ } elseif ($hour < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ $date = 0;
+ $calendar = PHPExcel_Shared_Date::getExcelCalendar();
+ if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900) {
+ $date = 1;
+ }
+ return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ $dayAdjust = 0;
+ if ($hour < 0) {
+ $dayAdjust = floor($hour / 24);
+ $hour = 24 - abs($hour % 24);
+ if ($hour == 24) {
+ $hour = 0;
+ }
+ } elseif ($hour >= 24) {
+ $dayAdjust = floor($hour / 24);
+ $hour = $hour % 24;
+ }
+ $phpDateObject = new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
+ if ($dayAdjust != 0) {
+ $phpDateObject->modify($dayAdjust.' days');
+ }
+ return $phpDateObject;
+ }
+ }
+
+
+ /**
+ * DATEVALUE
+ *
+ * Returns a value that represents a particular date.
+ * Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
+ * value.
+ *
+ * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+ * format of your regional settings. PHPExcel does not change cell formatting in this way.
+ *
+ * Excel Function:
+ * DATEVALUE(dateValue)
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param string $dateValue Text that represents a date in a Microsoft Excel date format.
+ * For example, "1/30/2008" or "30-Jan-2008" are text strings within
+ * quotation marks that represent dates. Using the default date
+ * system in Excel for Windows, date_text must represent a date from
+ * January 1, 1900, to December 31, 9999. Using the default date
+ * system in Excel for the Macintosh, date_text must represent a date
+ * from January 1, 1904, to December 31, 9999. DATEVALUE returns the
+ * #VALUE! error value if date_text is out of this range.
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function DATEVALUE($dateValue = 1)
+ {
+ $dateValue = trim(PHPExcel_Calculation_Functions::flattenSingleValue($dateValue), '"');
+ // Strip any ordinals because they're allowed in Excel (English only)
+ $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
+ // Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
+ $dateValue = str_replace(array('/', '.', '-', ' '), array(' ', ' ', ' ', ' '), $dateValue);
+
+ $yearFound = false;
+ $t1 = explode(' ', $dateValue);
+ foreach ($t1 as &$t) {
+ if ((is_numeric($t)) && ($t > 31)) {
+ if ($yearFound) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } else {
+ if ($t < 100) {
+ $t += 1900;
+ }
+ $yearFound = true;
+ }
+ }
+ }
+ if ((count($t1) == 1) && (strpos($t, ':') != false)) {
+ // We've been fed a time value without any date
+ return 0.0;
+ } elseif (count($t1) == 2) {
+ // We only have two parts of the date: either day/month or month/year
+ if ($yearFound) {
+ array_unshift($t1, 1);
+ } else {
+ array_push($t1, date('Y'));
+ }
+ }
+ unset($t);
+ $dateValue = implode(' ', $t1);
+
+ $PHPDateArray = date_parse($dateValue);
+ if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
+ $testVal1 = strtok($dateValue, '- ');
+ if ($testVal1 !== false) {
+ $testVal2 = strtok('- ');
+ if ($testVal2 !== false) {
+ $testVal3 = strtok('- ');
+ if ($testVal3 === false) {
+ $testVal3 = strftime('%Y');
+ }
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $PHPDateArray = date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
+ if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
+ $PHPDateArray = date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
+ if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ }
+
+ if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
+ // Execute function
+ if ($PHPDateArray['year'] == '') {
+ $PHPDateArray['year'] = strftime('%Y');
+ }
+ if ($PHPDateArray['year'] < 1900) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if ($PHPDateArray['month'] == '') {
+ $PHPDateArray['month'] = strftime('%m');
+ }
+ if ($PHPDateArray['day'] == '') {
+ $PHPDateArray['day'] = strftime('%d');
+ }
+ $excelDateValue = floor(
+ PHPExcel_Shared_Date::FormattedPHPToExcel(
+ $PHPDateArray['year'],
+ $PHPDateArray['month'],
+ $PHPDateArray['day'],
+ $PHPDateArray['hour'],
+ $PHPDateArray['minute'],
+ $PHPDateArray['second']
+ )
+ );
+
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ return (float) $excelDateValue;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * TIMEVALUE
+ *
+ * Returns a value that represents a particular time.
+ * Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
+ * value.
+ *
+ * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
+ * format of your regional settings. PHPExcel does not change cell formatting in this way.
+ *
+ * Excel Function:
+ * TIMEVALUE(timeValue)
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param string $timeValue A text string that represents a time in any one of the Microsoft
+ * Excel time formats; for example, "6:45 PM" and "18:45" text strings
+ * within quotation marks that represent time.
+ * Date information in time_text is ignored.
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function TIMEVALUE($timeValue)
+ {
+ $timeValue = trim(PHPExcel_Calculation_Functions::flattenSingleValue($timeValue), '"');
+ $timeValue = str_replace(array('/', '.'), array('-', '-'), $timeValue);
+
+ $PHPDateArray = date_parse($timeValue);
+ if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(
+ $PHPDateArray['year'],
+ $PHPDateArray['month'],
+ $PHPDateArray['day'],
+ $PHPDateArray['hour'],
+ $PHPDateArray['minute'],
+ $PHPDateArray['second']
+ );
+ } else {
+ $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1;
+ }
+
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ return (float) $excelDateValue;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) $phpDateValue = PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+25569) - 3600;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * DATEDIF
+ *
+ * @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object
+ * or a standard date string
+ * @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object
+ * or a standard date string
+ * @param string $unit
+ * @return integer Interval between the dates
+ */
+ public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
+ {
+ $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
+ $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
+ $unit = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($unit));
+
+ if (is_string($startDate = self::getDateValue($startDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($endDate = self::getDateValue($endDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Validate parameters
+ if ($startDate >= $endDate) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $difference = $endDate - $startDate;
+
+ $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
+ $startDays = $PHPStartDateObject->format('j');
+ $startMonths = $PHPStartDateObject->format('n');
+ $startYears = $PHPStartDateObject->format('Y');
+
+ $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
+ $endDays = $PHPEndDateObject->format('j');
+ $endMonths = $PHPEndDateObject->format('n');
+ $endYears = $PHPEndDateObject->format('Y');
+
+ $retVal = PHPExcel_Calculation_Functions::NaN();
+ switch ($unit) {
+ case 'D':
+ $retVal = intval($difference);
+ break;
+ case 'M':
+ $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12);
+ // We're only interested in full months
+ if ($endDays < $startDays) {
+ --$retVal;
+ }
+ break;
+ case 'Y':
+ $retVal = intval($endYears - $startYears);
+ // We're only interested in full months
+ if ($endMonths < $startMonths) {
+ --$retVal;
+ } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) {
+ --$retVal;
+ }
+ break;
+ case 'MD':
+ if ($endDays < $startDays) {
+ $retVal = $endDays;
+ $PHPEndDateObject->modify('-'.$endDays.' days');
+ $adjustDays = $PHPEndDateObject->format('j');
+ if ($adjustDays > $startDays) {
+ $retVal += ($adjustDays - $startDays);
+ }
+ } else {
+ $retVal = $endDays - $startDays;
+ }
+ break;
+ case 'YM':
+ $retVal = intval($endMonths - $startMonths);
+ if ($retVal < 0) {
+ $retVal += 12;
+ }
+ // We're only interested in full months
+ if ($endDays < $startDays) {
+ --$retVal;
+ }
+ break;
+ case 'YD':
+ $retVal = intval($difference);
+ if ($endYears > $startYears) {
+ while ($endYears > $startYears) {
+ $PHPEndDateObject->modify('-1 year');
+ $endYears = $PHPEndDateObject->format('Y');
+ }
+ $retVal = $PHPEndDateObject->format('z') - $PHPStartDateObject->format('z');
+ if ($retVal < 0) {
+ $retVal += 365;
+ }
+ }
+ break;
+ default:
+ $retVal = PHPExcel_Calculation_Functions::NaN();
+ }
+ return $retVal;
+ }
+
+
+ /**
+ * DAYS360
+ *
+ * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
+ * which is used in some accounting calculations. Use this function to help compute payments if
+ * your accounting system is based on twelve 30-day months.
+ *
+ * Excel Function:
+ * DAYS360(startDate,endDate[,method])
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param boolean $method US or European Method
+ * FALSE or omitted: U.S. (NASD) method. If the starting date is
+ * the last day of a month, it becomes equal to the 30th of the
+ * same month. If the ending date is the last day of a month and
+ * the starting date is earlier than the 30th of a month, the
+ * ending date becomes equal to the 1st of the next month;
+ * otherwise the ending date becomes equal to the 30th of the
+ * same month.
+ * TRUE: European method. Starting dates and ending dates that
+ * occur on the 31st of a month become equal to the 30th of the
+ * same month.
+ * @return integer Number of days between start date and end date
+ */
+ public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
+ {
+ $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
+ $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
+
+ if (is_string($startDate = self::getDateValue($startDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($endDate = self::getDateValue($endDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (!is_bool($method)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Execute function
+ $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
+ $startDay = $PHPStartDateObject->format('j');
+ $startMonth = $PHPStartDateObject->format('n');
+ $startYear = $PHPStartDateObject->format('Y');
+
+ $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
+ $endDay = $PHPEndDateObject->format('j');
+ $endMonth = $PHPEndDateObject->format('n');
+ $endYear = $PHPEndDateObject->format('Y');
+
+ return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
+ }
+
+
+ /**
+ * YEARFRAC
+ *
+ * Calculates the fraction of the year represented by the number of whole days between two dates
+ * (the start_date and the end_date).
+ * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
+ * obligations to assign to a specific term.
+ *
+ * Excel Function:
+ * YEARFRAC(startDate,endDate[,method])
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param integer $method Method used for the calculation
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float fraction of the year
+ */
+ public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
+ {
+ $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
+ $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
+ $method = PHPExcel_Calculation_Functions::flattenSingleValue($method);
+
+ if (is_string($startDate = self::getDateValue($startDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($endDate = self::getDateValue($endDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
+ switch ($method) {
+ case 0:
+ return self::DAYS360($startDate, $endDate) / 360;
+ case 1:
+ $days = self::DATEDIF($startDate, $endDate);
+ $startYear = self::YEAR($startDate);
+ $endYear = self::YEAR($endDate);
+ $years = $endYear - $startYear + 1;
+ $leapDays = 0;
+ if ($years == 1) {
+ if (self::isLeapYear($endYear)) {
+ $startMonth = self::MONTHOFYEAR($startDate);
+ $endMonth = self::MONTHOFYEAR($endDate);
+ $endDay = self::DAYOFMONTH($endDate);
+ if (($startMonth < 3) ||
+ (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
+ $leapDays += 1;
+ }
+ }
+ } else {
+ for ($year = $startYear; $year <= $endYear; ++$year) {
+ if ($year == $startYear) {
+ $startMonth = self::MONTHOFYEAR($startDate);
+ $startDay = self::DAYOFMONTH($startDate);
+ if ($startMonth < 3) {
+ $leapDays += (self::isLeapYear($year)) ? 1 : 0;
+ }
+ } elseif ($year == $endYear) {
+ $endMonth = self::MONTHOFYEAR($endDate);
+ $endDay = self::DAYOFMONTH($endDate);
+ if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
+ $leapDays += (self::isLeapYear($year)) ? 1 : 0;
+ }
+ } else {
+ $leapDays += (self::isLeapYear($year)) ? 1 : 0;
+ }
+ }
+ if ($years == 2) {
+ if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
+ $leapDays = 1;
+ } elseif ($days < 366) {
+ $years = 1;
+ }
+ }
+ $leapDays /= $years;
+ }
+ return $days / (365 + $leapDays);
+ case 2:
+ return self::DATEDIF($startDate, $endDate) / 360;
+ case 3:
+ return self::DATEDIF($startDate, $endDate) / 365;
+ case 4:
+ return self::DAYS360($startDate, $endDate, true) / 360;
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * NETWORKDAYS
+ *
+ * Returns the number of whole working days between start_date and end_date. Working days
+ * exclude weekends and any dates identified in holidays.
+ * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
+ * worked during a specific term.
+ *
+ * Excel Function:
+ * NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param mixed $holidays,... Optional series of Excel date serial value (float), PHP date
+ * timestamp (integer), PHP DateTime object, or a standard date
+ * strings that will be excluded from the working calendar, such
+ * as state and federal holidays and floating holidays.
+ * @return integer Interval between the dates
+ */
+ public static function NETWORKDAYS($startDate, $endDate)
+ {
+ // Retrieve the mandatory start and end date that are referenced in the function definition
+ $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
+ $endDate = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
+ // Flush the mandatory start and end date that are referenced in the function definition, and get the optional days
+ $dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ array_shift($dateArgs);
+ array_shift($dateArgs);
+
+ // Validate the start and end dates
+ if (is_string($startDate = $sDate = self::getDateValue($startDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $startDate = (float) floor($startDate);
+ if (is_string($endDate = $eDate = self::getDateValue($endDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $endDate = (float) floor($endDate);
+
+ if ($sDate > $eDate) {
+ $startDate = $eDate;
+ $endDate = $sDate;
+ }
+
+ // Execute function
+ $startDoW = 6 - self::DAYOFWEEK($startDate, 2);
+ if ($startDoW < 0) {
+ $startDoW = 0;
+ }
+ $endDoW = self::DAYOFWEEK($endDate, 2);
+ if ($endDoW >= 6) {
+ $endDoW = 0;
+ }
+
+ $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5;
+ $partWeekDays = $endDoW + $startDoW;
+ if ($partWeekDays > 5) {
+ $partWeekDays -= 5;
+ }
+
+ // Test any extra holiday parameters
+ $holidayCountedArray = array();
+ foreach ($dateArgs as $holidayDate) {
+ if (is_string($holidayDate = self::getDateValue($holidayDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
+ if ((self::DAYOFWEEK($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
+ --$partWeekDays;
+ $holidayCountedArray[] = $holidayDate;
+ }
+ }
+ }
+
+ if ($sDate > $eDate) {
+ return 0 - ($wholeWeekDays + $partWeekDays);
+ }
+ return $wholeWeekDays + $partWeekDays;
+ }
+
+
+ /**
+ * WORKDAY
+ *
+ * Returns the date that is the indicated number of working days before or after a date (the
+ * starting date). Working days exclude weekends and any dates identified as holidays.
+ * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
+ * delivery times, or the number of days of work performed.
+ *
+ * Excel Function:
+ * WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
+ *
+ * @access public
+ * @category Date/Time Functions
+ * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param integer $endDays The number of nonweekend and nonholiday days before or after
+ * startDate. A positive value for days yields a future date; a
+ * negative value yields a past date.
+ * @param mixed $holidays,... Optional series of Excel date serial value (float), PHP date
+ * timestamp (integer), PHP DateTime object, or a standard date
+ * strings that will be excluded from the working calendar, such
+ * as state and federal holidays and floating holidays.
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function WORKDAY($startDate, $endDays)
+ {
+ // Retrieve the mandatory start date and days that are referenced in the function definition
+ $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
+ $endDays = PHPExcel_Calculation_Functions::flattenSingleValue($endDays);
+ // Flush the mandatory start date and days that are referenced in the function definition, and get the optional days
+ $dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ array_shift($dateArgs);
+ array_shift($dateArgs);
+
+ if ((is_string($startDate = self::getDateValue($startDate))) || (!is_numeric($endDays))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $startDate = (float) floor($startDate);
+ $endDays = (int) floor($endDays);
+ // If endDays is 0, we always return startDate
+ if ($endDays == 0) {
+ return $startDate;
+ }
+
+ $decrementing = ($endDays < 0) ? true : false;
+
+ // Adjust the start date if it falls over a weekend
+
+ $startDoW = self::DAYOFWEEK($startDate, 3);
+ if (self::DAYOFWEEK($startDate, 3) >= 5) {
+ $startDate += ($decrementing) ? -$startDoW + 4: 7 - $startDoW;
+ ($decrementing) ? $endDays++ : $endDays--;
+ }
+
+ // Add endDays
+ $endDate = (float) $startDate + (intval($endDays / 5) * 7) + ($endDays % 5);
+
+ // Adjust the calculated end date if it falls over a weekend
+ $endDoW = self::DAYOFWEEK($endDate, 3);
+ if ($endDoW >= 5) {
+ $endDate += ($decrementing) ? -$endDoW + 4: 7 - $endDoW;
+ }
+
+ // Test any extra holiday parameters
+ if (!empty($dateArgs)) {
+ $holidayCountedArray = $holidayDates = array();
+ foreach ($dateArgs as $holidayDate) {
+ if (($holidayDate !== null) && (trim($holidayDate) > '')) {
+ if (is_string($holidayDate = self::getDateValue($holidayDate))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (self::DAYOFWEEK($holidayDate, 3) < 5) {
+ $holidayDates[] = $holidayDate;
+ }
+ }
+ }
+ if ($decrementing) {
+ rsort($holidayDates, SORT_NUMERIC);
+ } else {
+ sort($holidayDates, SORT_NUMERIC);
+ }
+ foreach ($holidayDates as $holidayDate) {
+ if ($decrementing) {
+ if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) {
+ if (!in_array($holidayDate, $holidayCountedArray)) {
+ --$endDate;
+ $holidayCountedArray[] = $holidayDate;
+ }
+ }
+ } else {
+ if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
+ if (!in_array($holidayDate, $holidayCountedArray)) {
+ ++$endDate;
+ $holidayCountedArray[] = $holidayDate;
+ }
+ }
+ }
+ // Adjust the calculated end date if it falls over a weekend
+ $endDoW = self::DAYOFWEEK($endDate, 3);
+ if ($endDoW >= 5) {
+ $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW;
+ }
+ }
+ }
+
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ return (float) $endDate;
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
+ }
+ }
+
+
+ /**
+ * DAYOFMONTH
+ *
+ * Returns the day of the month, for a specified date. The day is given as an integer
+ * ranging from 1 to 31.
+ *
+ * Excel Function:
+ * DAY(dateValue)
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @return int Day of the month
+ */
+ public static function DAYOFMONTH($dateValue = 1)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+
+ if ($dateValue === null) {
+ $dateValue = 1;
+ } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($dateValue == 0.0) {
+ return 0;
+ } elseif ($dateValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
+
+ return (int) $PHPDateObject->format('j');
+ }
+
+
+ /**
+ * DAYOFWEEK
+ *
+ * Returns the day of the week for a specified date. The day is given as an integer
+ * ranging from 0 to 7 (dependent on the requested style).
+ *
+ * Excel Function:
+ * WEEKDAY(dateValue[,style])
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param int $style A number that determines the type of return value
+ * 1 or omitted Numbers 1 (Sunday) through 7 (Saturday).
+ * 2 Numbers 1 (Monday) through 7 (Sunday).
+ * 3 Numbers 0 (Monday) through 6 (Sunday).
+ * @return int Day of the week value
+ */
+ public static function DAYOFWEEK($dateValue = 1, $style = 1)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+ $style = PHPExcel_Calculation_Functions::flattenSingleValue($style);
+
+ if (!is_numeric($style)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif (($style < 1) || ($style > 3)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $style = floor($style);
+
+ if ($dateValue === null) {
+ $dateValue = 1;
+ } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($dateValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
+ $DoW = $PHPDateObject->format('w');
+
+ $firstDay = 1;
+ switch ($style) {
+ case 1:
+ ++$DoW;
+ break;
+ case 2:
+ if ($DoW == 0) {
+ $DoW = 7;
+ }
+ break;
+ case 3:
+ if ($DoW == 0) {
+ $DoW = 7;
+ }
+ $firstDay = 0;
+ --$DoW;
+ break;
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL) {
+ // Test for Excel's 1900 leap year, and introduce the error as required
+ if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) {
+ --$DoW;
+ if ($DoW < $firstDay) {
+ $DoW += 7;
+ }
+ }
+ }
+
+ return (int) $DoW;
+ }
+
+
+ /**
+ * WEEKOFYEAR
+ *
+ * Returns the week of the year for a specified date.
+ * The WEEKNUM function considers the week containing January 1 to be the first week of the year.
+ * However, there is a European standard that defines the first week as the one with the majority
+ * of days (four or more) falling in the new year. This means that for years in which there are
+ * three days or less in the first week of January, the WEEKNUM function returns week numbers
+ * that are incorrect according to the European standard.
+ *
+ * Excel Function:
+ * WEEKNUM(dateValue[,style])
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param boolean $method Week begins on Sunday or Monday
+ * 1 or omitted Week begins on Sunday.
+ * 2 Week begins on Monday.
+ * @return int Week Number
+ */
+ public static function WEEKOFYEAR($dateValue = 1, $method = 1)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+ $method = PHPExcel_Calculation_Functions::flattenSingleValue($method);
+
+ if (!is_numeric($method)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif (($method < 1) || ($method > 2)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $method = floor($method);
+
+ if ($dateValue === null) {
+ $dateValue = 1;
+ } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($dateValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
+ $dayOfYear = $PHPDateObject->format('z');
+ $dow = $PHPDateObject->format('w');
+ $PHPDateObject->modify('-' . $dayOfYear . ' days');
+ $dow = $PHPDateObject->format('w');
+ $daysInFirstWeek = 7 - (($dow + (2 - $method)) % 7);
+ $dayOfYear -= $daysInFirstWeek;
+ $weekOfYear = ceil($dayOfYear / 7) + 1;
+
+ return (int) $weekOfYear;
+ }
+
+
+ /**
+ * MONTHOFYEAR
+ *
+ * Returns the month of a date represented by a serial number.
+ * The month is given as an integer, ranging from 1 (January) to 12 (December).
+ *
+ * Excel Function:
+ * MONTH(dateValue)
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @return int Month of the year
+ */
+ public static function MONTHOFYEAR($dateValue = 1)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+
+ if ($dateValue === null) {
+ $dateValue = 1;
+ } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($dateValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
+
+ return (int) $PHPDateObject->format('n');
+ }
+
+
+ /**
+ * YEAR
+ *
+ * Returns the year corresponding to a date.
+ * The year is returned as an integer in the range 1900-9999.
+ *
+ * Excel Function:
+ * YEAR(dateValue)
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @return int Year
+ */
+ public static function YEAR($dateValue = 1)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+
+ if ($dateValue === null) {
+ $dateValue = 1;
+ } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($dateValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Execute function
+ $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
+
+ return (int) $PHPDateObject->format('Y');
+ }
+
+
+ /**
+ * HOUROFDAY
+ *
+ * Returns the hour of a time value.
+ * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
+ *
+ * Excel Function:
+ * HOUR(timeValue)
+ *
+ * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard time string
+ * @return int Hour
+ */
+ public static function HOUROFDAY($timeValue = 0)
+ {
+ $timeValue = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
+
+ if (!is_numeric($timeValue)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $testVal = strtok($timeValue, '/-: ');
+ if (strlen($testVal) < strlen($timeValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ $timeValue = self::getTimeValue($timeValue);
+ if (is_string($timeValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ // Execute function
+ if ($timeValue >= 1) {
+ $timeValue = fmod($timeValue, 1);
+ } elseif ($timeValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
+
+ return (int) gmdate('G', $timeValue);
+ }
+
+
+ /**
+ * MINUTEOFHOUR
+ *
+ * Returns the minutes of a time value.
+ * The minute is given as an integer, ranging from 0 to 59.
+ *
+ * Excel Function:
+ * MINUTE(timeValue)
+ *
+ * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard time string
+ * @return int Minute
+ */
+ public static function MINUTEOFHOUR($timeValue = 0)
+ {
+ $timeValue = $timeTester = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
+
+ if (!is_numeric($timeValue)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $testVal = strtok($timeValue, '/-: ');
+ if (strlen($testVal) < strlen($timeValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ $timeValue = self::getTimeValue($timeValue);
+ if (is_string($timeValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ // Execute function
+ if ($timeValue >= 1) {
+ $timeValue = fmod($timeValue, 1);
+ } elseif ($timeValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
+
+ return (int) gmdate('i', $timeValue);
+ }
+
+
+ /**
+ * SECONDOFMINUTE
+ *
+ * Returns the seconds of a time value.
+ * The second is given as an integer in the range 0 (zero) to 59.
+ *
+ * Excel Function:
+ * SECOND(timeValue)
+ *
+ * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard time string
+ * @return int Second
+ */
+ public static function SECONDOFMINUTE($timeValue = 0)
+ {
+ $timeValue = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
+
+ if (!is_numeric($timeValue)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $testVal = strtok($timeValue, '/-: ');
+ if (strlen($testVal) < strlen($timeValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ $timeValue = self::getTimeValue($timeValue);
+ if (is_string($timeValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ // Execute function
+ if ($timeValue >= 1) {
+ $timeValue = fmod($timeValue, 1);
+ } elseif ($timeValue < 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
+
+ return (int) gmdate('s', $timeValue);
+ }
+
+
+ /**
+ * EDATE
+ *
+ * Returns the serial number that represents the date that is the indicated number of months
+ * before or after a specified date (the start_date).
+ * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
+ * as the date of issue.
+ *
+ * Excel Function:
+ * EDATE(dateValue,adjustmentMonths)
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param int $adjustmentMonths The number of months before or after start_date.
+ * A positive value for months yields a future date;
+ * a negative value yields a past date.
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function EDATE($dateValue = 1, $adjustmentMonths = 0)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+ $adjustmentMonths = PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
+
+ if (!is_numeric($adjustmentMonths)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $adjustmentMonths = floor($adjustmentMonths);
+
+ if (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Execute function
+ $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths);
+
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ return $PHPDateObject;
+ }
+ }
+
+
+ /**
+ * EOMONTH
+ *
+ * Returns the date value for the last day of the month that is the indicated number of months
+ * before or after start_date.
+ * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
+ *
+ * Excel Function:
+ * EOMONTH(dateValue,adjustmentMonths)
+ *
+ * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
+ * PHP DateTime object, or a standard date string
+ * @param int $adjustmentMonths The number of months before or after start_date.
+ * A positive value for months yields a future date;
+ * a negative value yields a past date.
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0)
+ {
+ $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
+ $adjustmentMonths = PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
+
+ if (!is_numeric($adjustmentMonths)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $adjustmentMonths = floor($adjustmentMonths);
+
+ if (is_string($dateValue = self::getDateValue($dateValue))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Execute function
+ $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths+1);
+ $adjustDays = (int) $PHPDateObject->format('d');
+ $adjustDaysString = '-' . $adjustDays . ' days';
+ $PHPDateObject->modify($adjustDaysString);
+
+ switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
+ case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
+ return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
+ return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
+ case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
+ return $PHPDateObject;
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Engineering.php b/extend/PHPExcel/PHPExcel/Calculation/Engineering.php
new file mode 100755
index 0000000..75e2784
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Engineering.php
@@ -0,0 +1,2650 @@
+ array('Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => true),
+ 'sg' => array('Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => false),
+ 'lbm' => array('Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false),
+ 'u' => array('Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => true),
+ 'ozm' => array('Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false),
+ 'm' => array('Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => true),
+ 'mi' => array('Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => false),
+ 'Nmi' => array('Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => false),
+ 'in' => array('Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => false),
+ 'ft' => array('Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => false),
+ 'yd' => array('Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => false),
+ 'ang' => array('Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => true),
+ 'Pica' => array('Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false),
+ 'yr' => array('Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => false),
+ 'day' => array('Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => false),
+ 'hr' => array('Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => false),
+ 'mn' => array('Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => false),
+ 'sec' => array('Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => true),
+ 'Pa' => array('Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true),
+ 'p' => array('Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true),
+ 'atm' => array('Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true),
+ 'at' => array('Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true),
+ 'mmHg' => array('Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => true),
+ 'N' => array('Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => true),
+ 'dyn' => array('Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true),
+ 'dy' => array('Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true),
+ 'lbf' => array('Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => false),
+ 'J' => array('Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => true),
+ 'e' => array('Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => true),
+ 'c' => array('Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => true),
+ 'cal' => array('Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => true),
+ 'eV' => array('Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true),
+ 'ev' => array('Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true),
+ 'HPh' => array('Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false),
+ 'hh' => array('Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false),
+ 'Wh' => array('Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true),
+ 'wh' => array('Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true),
+ 'flb' => array('Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => false),
+ 'BTU' => array('Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false),
+ 'btu' => array('Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false),
+ 'HP' => array('Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false),
+ 'h' => array('Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false),
+ 'W' => array('Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true),
+ 'w' => array('Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true),
+ 'T' => array('Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => true),
+ 'ga' => array('Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => true),
+ 'C' => array('Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false),
+ 'cel' => array('Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false),
+ 'F' => array('Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false),
+ 'fah' => array('Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false),
+ 'K' => array('Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false),
+ 'kel' => array('Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false),
+ 'tsp' => array('Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => false),
+ 'tbs' => array('Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => false),
+ 'oz' => array('Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => false),
+ 'cup' => array('Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => false),
+ 'pt' => array('Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false),
+ 'us_pt' => array('Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false),
+ 'uk_pt' => array('Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => false),
+ 'qt' => array('Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => false),
+ 'gal' => array('Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => false),
+ 'l' => array('Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true),
+ 'lt' => array('Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true),
+ );
+
+ /**
+ * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM()
+ *
+ * @var mixed[]
+ */
+ private static $conversionMultipliers = array(
+ 'Y' => array('multiplier' => 1E24, 'name' => 'yotta'),
+ 'Z' => array('multiplier' => 1E21, 'name' => 'zetta'),
+ 'E' => array('multiplier' => 1E18, 'name' => 'exa'),
+ 'P' => array('multiplier' => 1E15, 'name' => 'peta'),
+ 'T' => array('multiplier' => 1E12, 'name' => 'tera'),
+ 'G' => array('multiplier' => 1E9, 'name' => 'giga'),
+ 'M' => array('multiplier' => 1E6, 'name' => 'mega'),
+ 'k' => array('multiplier' => 1E3, 'name' => 'kilo'),
+ 'h' => array('multiplier' => 1E2, 'name' => 'hecto'),
+ 'e' => array('multiplier' => 1E1, 'name' => 'deka'),
+ 'd' => array('multiplier' => 1E-1, 'name' => 'deci'),
+ 'c' => array('multiplier' => 1E-2, 'name' => 'centi'),
+ 'm' => array('multiplier' => 1E-3, 'name' => 'milli'),
+ 'u' => array('multiplier' => 1E-6, 'name' => 'micro'),
+ 'n' => array('multiplier' => 1E-9, 'name' => 'nano'),
+ 'p' => array('multiplier' => 1E-12, 'name' => 'pico'),
+ 'f' => array('multiplier' => 1E-15, 'name' => 'femto'),
+ 'a' => array('multiplier' => 1E-18, 'name' => 'atto'),
+ 'z' => array('multiplier' => 1E-21, 'name' => 'zepto'),
+ 'y' => array('multiplier' => 1E-24, 'name' => 'yocto'),
+ );
+
+ /**
+ * Details of the Units of measure conversion factors, organised by group
+ *
+ * @var mixed[]
+ */
+ private static $unitConversions = array(
+ 'Mass' => array(
+ 'g' => array(
+ 'g' => 1.0,
+ 'sg' => 6.85220500053478E-05,
+ 'lbm' => 2.20462291469134E-03,
+ 'u' => 6.02217000000000E+23,
+ 'ozm' => 3.52739718003627E-02,
+ ),
+ 'sg' => array(
+ 'g' => 1.45938424189287E+04,
+ 'sg' => 1.0,
+ 'lbm' => 3.21739194101647E+01,
+ 'u' => 8.78866000000000E+27,
+ 'ozm' => 5.14782785944229E+02,
+ ),
+ 'lbm' => array(
+ 'g' => 4.5359230974881148E+02,
+ 'sg' => 3.10810749306493E-02,
+ 'lbm' => 1.0,
+ 'u' => 2.73161000000000E+26,
+ 'ozm' => 1.60000023429410E+01,
+ ),
+ 'u' => array(
+ 'g' => 1.66053100460465E-24,
+ 'sg' => 1.13782988532950E-28,
+ 'lbm' => 3.66084470330684E-27,
+ 'u' => 1.0,
+ 'ozm' => 5.85735238300524E-26,
+ ),
+ 'ozm' => array(
+ 'g' => 2.83495152079732E+01,
+ 'sg' => 1.94256689870811E-03,
+ 'lbm' => 6.24999908478882E-02,
+ 'u' => 1.70725600000000E+25,
+ 'ozm' => 1.0,
+ ),
+ ),
+ 'Distance' => array(
+ 'm' => array(
+ 'm' => 1.0,
+ 'mi' => 6.21371192237334E-04,
+ 'Nmi' => 5.39956803455724E-04,
+ 'in' => 3.93700787401575E+01,
+ 'ft' => 3.28083989501312E+00,
+ 'yd' => 1.09361329797891E+00,
+ 'ang' => 1.00000000000000E+10,
+ 'Pica' => 2.83464566929116E+03,
+ ),
+ 'mi' => array(
+ 'm' => 1.60934400000000E+03,
+ 'mi' => 1.0,
+ 'Nmi' => 8.68976241900648E-01,
+ 'in' => 6.33600000000000E+04,
+ 'ft' => 5.28000000000000E+03,
+ 'yd' => 1.76000000000000E+03,
+ 'ang' => 1.60934400000000E+13,
+ 'Pica' => 4.56191999999971E+06,
+ ),
+ 'Nmi' => array(
+ 'm' => 1.85200000000000E+03,
+ 'mi' => 1.15077944802354E+00,
+ 'Nmi' => 1.0,
+ 'in' => 7.29133858267717E+04,
+ 'ft' => 6.07611548556430E+03,
+ 'yd' => 2.02537182785694E+03,
+ 'ang' => 1.85200000000000E+13,
+ 'Pica' => 5.24976377952723E+06,
+ ),
+ 'in' => array(
+ 'm' => 2.54000000000000E-02,
+ 'mi' => 1.57828282828283E-05,
+ 'Nmi' => 1.37149028077754E-05,
+ 'in' => 1.0,
+ 'ft' => 8.33333333333333E-02,
+ 'yd' => 2.77777777686643E-02,
+ 'ang' => 2.54000000000000E+08,
+ 'Pica' => 7.19999999999955E+01,
+ ),
+ 'ft' => array(
+ 'm' => 3.04800000000000E-01,
+ 'mi' => 1.89393939393939E-04,
+ 'Nmi' => 1.64578833693305E-04,
+ 'in' => 1.20000000000000E+01,
+ 'ft' => 1.0,
+ 'yd' => 3.33333333223972E-01,
+ 'ang' => 3.04800000000000E+09,
+ 'Pica' => 8.63999999999946E+02,
+ ),
+ 'yd' => array(
+ 'm' => 9.14400000300000E-01,
+ 'mi' => 5.68181818368230E-04,
+ 'Nmi' => 4.93736501241901E-04,
+ 'in' => 3.60000000118110E+01,
+ 'ft' => 3.00000000000000E+00,
+ 'yd' => 1.0,
+ 'ang' => 9.14400000300000E+09,
+ 'Pica' => 2.59200000085023E+03,
+ ),
+ 'ang' => array(
+ 'm' => 1.00000000000000E-10,
+ 'mi' => 6.21371192237334E-14,
+ 'Nmi' => 5.39956803455724E-14,
+ 'in' => 3.93700787401575E-09,
+ 'ft' => 3.28083989501312E-10,
+ 'yd' => 1.09361329797891E-10,
+ 'ang' => 1.0,
+ 'Pica' => 2.83464566929116E-07,
+ ),
+ 'Pica' => array(
+ 'm' => 3.52777777777800E-04,
+ 'mi' => 2.19205948372629E-07,
+ 'Nmi' => 1.90484761219114E-07,
+ 'in' => 1.38888888888898E-02,
+ 'ft' => 1.15740740740748E-03,
+ 'yd' => 3.85802469009251E-04,
+ 'ang' => 3.52777777777800E+06,
+ 'Pica' => 1.0,
+ ),
+ ),
+ 'Time' => array(
+ 'yr' => array(
+ 'yr' => 1.0,
+ 'day' => 365.25,
+ 'hr' => 8766.0,
+ 'mn' => 525960.0,
+ 'sec' => 31557600.0,
+ ),
+ 'day' => array(
+ 'yr' => 2.73785078713210E-03,
+ 'day' => 1.0,
+ 'hr' => 24.0,
+ 'mn' => 1440.0,
+ 'sec' => 86400.0,
+ ),
+ 'hr' => array(
+ 'yr' => 1.14077116130504E-04,
+ 'day' => 4.16666666666667E-02,
+ 'hr' => 1.0,
+ 'mn' => 60.0,
+ 'sec' => 3600.0,
+ ),
+ 'mn' => array(
+ 'yr' => 1.90128526884174E-06,
+ 'day' => 6.94444444444444E-04,
+ 'hr' => 1.66666666666667E-02,
+ 'mn' => 1.0,
+ 'sec' => 60.0,
+ ),
+ 'sec' => array(
+ 'yr' => 3.16880878140289E-08,
+ 'day' => 1.15740740740741E-05,
+ 'hr' => 2.77777777777778E-04,
+ 'mn' => 1.66666666666667E-02,
+ 'sec' => 1.0,
+ ),
+ ),
+ 'Pressure' => array(
+ 'Pa' => array(
+ 'Pa' => 1.0,
+ 'p' => 1.0,
+ 'atm' => 9.86923299998193E-06,
+ 'at' => 9.86923299998193E-06,
+ 'mmHg' => 7.50061707998627E-03,
+ ),
+ 'p' => array(
+ 'Pa' => 1.0,
+ 'p' => 1.0,
+ 'atm' => 9.86923299998193E-06,
+ 'at' => 9.86923299998193E-06,
+ 'mmHg' => 7.50061707998627E-03,
+ ),
+ 'atm' => array(
+ 'Pa' => 1.01324996583000E+05,
+ 'p' => 1.01324996583000E+05,
+ 'atm' => 1.0,
+ 'at' => 1.0,
+ 'mmHg' => 760.0,
+ ),
+ 'at' => array(
+ 'Pa' => 1.01324996583000E+05,
+ 'p' => 1.01324996583000E+05,
+ 'atm' => 1.0,
+ 'at' => 1.0,
+ 'mmHg' => 760.0,
+ ),
+ 'mmHg' => array(
+ 'Pa' => 1.33322363925000E+02,
+ 'p' => 1.33322363925000E+02,
+ 'atm' => 1.31578947368421E-03,
+ 'at' => 1.31578947368421E-03,
+ 'mmHg' => 1.0,
+ ),
+ ),
+ 'Force' => array(
+ 'N' => array(
+ 'N' => 1.0,
+ 'dyn' => 1.0E+5,
+ 'dy' => 1.0E+5,
+ 'lbf' => 2.24808923655339E-01,
+ ),
+ 'dyn' => array(
+ 'N' => 1.0E-5,
+ 'dyn' => 1.0,
+ 'dy' => 1.0,
+ 'lbf' => 2.24808923655339E-06,
+ ),
+ 'dy' => array(
+ 'N' => 1.0E-5,
+ 'dyn' => 1.0,
+ 'dy' => 1.0,
+ 'lbf' => 2.24808923655339E-06,
+ ),
+ 'lbf' => array(
+ 'N' => 4.448222,
+ 'dyn' => 4.448222E+5,
+ 'dy' => 4.448222E+5,
+ 'lbf' => 1.0,
+ ),
+ ),
+ 'Energy' => array(
+ 'J' => array(
+ 'J' => 1.0,
+ 'e' => 9.99999519343231E+06,
+ 'c' => 2.39006249473467E-01,
+ 'cal' => 2.38846190642017E-01,
+ 'eV' => 6.24145700000000E+18,
+ 'ev' => 6.24145700000000E+18,
+ 'HPh' => 3.72506430801000E-07,
+ 'hh' => 3.72506430801000E-07,
+ 'Wh' => 2.77777916238711E-04,
+ 'wh' => 2.77777916238711E-04,
+ 'flb' => 2.37304222192651E+01,
+ 'BTU' => 9.47815067349015E-04,
+ 'btu' => 9.47815067349015E-04,
+ ),
+ 'e' => array(
+ 'J' => 1.00000048065700E-07,
+ 'e' => 1.0,
+ 'c' => 2.39006364353494E-08,
+ 'cal' => 2.38846305445111E-08,
+ 'eV' => 6.24146000000000E+11,
+ 'ev' => 6.24146000000000E+11,
+ 'HPh' => 3.72506609848824E-14,
+ 'hh' => 3.72506609848824E-14,
+ 'Wh' => 2.77778049754611E-11,
+ 'wh' => 2.77778049754611E-11,
+ 'flb' => 2.37304336254586E-06,
+ 'BTU' => 9.47815522922962E-11,
+ 'btu' => 9.47815522922962E-11,
+ ),
+ 'c' => array(
+ 'J' => 4.18399101363672E+00,
+ 'e' => 4.18398900257312E+07,
+ 'c' => 1.0,
+ 'cal' => 9.99330315287563E-01,
+ 'eV' => 2.61142000000000E+19,
+ 'ev' => 2.61142000000000E+19,
+ 'HPh' => 1.55856355899327E-06,
+ 'hh' => 1.55856355899327E-06,
+ 'Wh' => 1.16222030532950E-03,
+ 'wh' => 1.16222030532950E-03,
+ 'flb' => 9.92878733152102E+01,
+ 'BTU' => 3.96564972437776E-03,
+ 'btu' => 3.96564972437776E-03,
+ ),
+ 'cal' => array(
+ 'J' => 4.18679484613929E+00,
+ 'e' => 4.18679283372801E+07,
+ 'c' => 1.00067013349059E+00,
+ 'cal' => 1.0,
+ 'eV' => 2.61317000000000E+19,
+ 'ev' => 2.61317000000000E+19,
+ 'HPh' => 1.55960800463137E-06,
+ 'hh' => 1.55960800463137E-06,
+ 'Wh' => 1.16299914807955E-03,
+ 'wh' => 1.16299914807955E-03,
+ 'flb' => 9.93544094443283E+01,
+ 'BTU' => 3.96830723907002E-03,
+ 'btu' => 3.96830723907002E-03,
+ ),
+ 'eV' => array(
+ 'J' => 1.60219000146921E-19,
+ 'e' => 1.60218923136574E-12,
+ 'c' => 3.82933423195043E-20,
+ 'cal' => 3.82676978535648E-20,
+ 'eV' => 1.0,
+ 'ev' => 1.0,
+ 'HPh' => 5.96826078912344E-26,
+ 'hh' => 5.96826078912344E-26,
+ 'Wh' => 4.45053000026614E-23,
+ 'wh' => 4.45053000026614E-23,
+ 'flb' => 3.80206452103492E-18,
+ 'BTU' => 1.51857982414846E-22,
+ 'btu' => 1.51857982414846E-22,
+ ),
+ 'ev' => array(
+ 'J' => 1.60219000146921E-19,
+ 'e' => 1.60218923136574E-12,
+ 'c' => 3.82933423195043E-20,
+ 'cal' => 3.82676978535648E-20,
+ 'eV' => 1.0,
+ 'ev' => 1.0,
+ 'HPh' => 5.96826078912344E-26,
+ 'hh' => 5.96826078912344E-26,
+ 'Wh' => 4.45053000026614E-23,
+ 'wh' => 4.45053000026614E-23,
+ 'flb' => 3.80206452103492E-18,
+ 'BTU' => 1.51857982414846E-22,
+ 'btu' => 1.51857982414846E-22,
+ ),
+ 'HPh' => array(
+ 'J' => 2.68451741316170E+06,
+ 'e' => 2.68451612283024E+13,
+ 'c' => 6.41616438565991E+05,
+ 'cal' => 6.41186757845835E+05,
+ 'eV' => 1.67553000000000E+25,
+ 'ev' => 1.67553000000000E+25,
+ 'HPh' => 1.0,
+ 'hh' => 1.0,
+ 'Wh' => 7.45699653134593E+02,
+ 'wh' => 7.45699653134593E+02,
+ 'flb' => 6.37047316692964E+07,
+ 'BTU' => 2.54442605275546E+03,
+ 'btu' => 2.54442605275546E+03,
+ ),
+ 'hh' => array(
+ 'J' => 2.68451741316170E+06,
+ 'e' => 2.68451612283024E+13,
+ 'c' => 6.41616438565991E+05,
+ 'cal' => 6.41186757845835E+05,
+ 'eV' => 1.67553000000000E+25,
+ 'ev' => 1.67553000000000E+25,
+ 'HPh' => 1.0,
+ 'hh' => 1.0,
+ 'Wh' => 7.45699653134593E+02,
+ 'wh' => 7.45699653134593E+02,
+ 'flb' => 6.37047316692964E+07,
+ 'BTU' => 2.54442605275546E+03,
+ 'btu' => 2.54442605275546E+03,
+ ),
+ 'Wh' => array(
+ 'J' => 3.59999820554720E+03,
+ 'e' => 3.59999647518369E+10,
+ 'c' => 8.60422069219046E+02,
+ 'cal' => 8.59845857713046E+02,
+ 'eV' => 2.24692340000000E+22,
+ 'ev' => 2.24692340000000E+22,
+ 'HPh' => 1.34102248243839E-03,
+ 'hh' => 1.34102248243839E-03,
+ 'Wh' => 1.0,
+ 'wh' => 1.0,
+ 'flb' => 8.54294774062316E+04,
+ 'BTU' => 3.41213254164705E+00,
+ 'btu' => 3.41213254164705E+00,
+ ),
+ 'wh' => array(
+ 'J' => 3.59999820554720E+03,
+ 'e' => 3.59999647518369E+10,
+ 'c' => 8.60422069219046E+02,
+ 'cal' => 8.59845857713046E+02,
+ 'eV' => 2.24692340000000E+22,
+ 'ev' => 2.24692340000000E+22,
+ 'HPh' => 1.34102248243839E-03,
+ 'hh' => 1.34102248243839E-03,
+ 'Wh' => 1.0,
+ 'wh' => 1.0,
+ 'flb' => 8.54294774062316E+04,
+ 'BTU' => 3.41213254164705E+00,
+ 'btu' => 3.41213254164705E+00,
+ ),
+ 'flb' => array(
+ 'J' => 4.21400003236424E-02,
+ 'e' => 4.21399800687660E+05,
+ 'c' => 1.00717234301644E-02,
+ 'cal' => 1.00649785509554E-02,
+ 'eV' => 2.63015000000000E+17,
+ 'ev' => 2.63015000000000E+17,
+ 'HPh' => 1.56974211145130E-08,
+ 'hh' => 1.56974211145130E-08,
+ 'Wh' => 1.17055614802000E-05,
+ 'wh' => 1.17055614802000E-05,
+ 'flb' => 1.0,
+ 'BTU' => 3.99409272448406E-05,
+ 'btu' => 3.99409272448406E-05,
+ ),
+ 'BTU' => array(
+ 'J' => 1.05505813786749E+03,
+ 'e' => 1.05505763074665E+10,
+ 'c' => 2.52165488508168E+02,
+ 'cal' => 2.51996617135510E+02,
+ 'eV' => 6.58510000000000E+21,
+ 'ev' => 6.58510000000000E+21,
+ 'HPh' => 3.93015941224568E-04,
+ 'hh' => 3.93015941224568E-04,
+ 'Wh' => 2.93071851047526E-01,
+ 'wh' => 2.93071851047526E-01,
+ 'flb' => 2.50369750774671E+04,
+ 'BTU' => 1.0,
+ 'btu' => 1.0,
+ ),
+ 'btu' => array(
+ 'J' => 1.05505813786749E+03,
+ 'e' => 1.05505763074665E+10,
+ 'c' => 2.52165488508168E+02,
+ 'cal' => 2.51996617135510E+02,
+ 'eV' => 6.58510000000000E+21,
+ 'ev' => 6.58510000000000E+21,
+ 'HPh' => 3.93015941224568E-04,
+ 'hh' => 3.93015941224568E-04,
+ 'Wh' => 2.93071851047526E-01,
+ 'wh' => 2.93071851047526E-01,
+ 'flb' => 2.50369750774671E+04,
+ 'BTU' => 1.0,
+ 'btu' => 1.0,
+ ),
+ ),
+ 'Power' => array(
+ 'HP' => array(
+ 'HP' => 1.0,
+ 'h' => 1.0,
+ 'W' => 7.45701000000000E+02,
+ 'w' => 7.45701000000000E+02,
+ ),
+ 'h' => array(
+ 'HP' => 1.0,
+ 'h' => 1.0,
+ 'W' => 7.45701000000000E+02,
+ 'w' => 7.45701000000000E+02,
+ ),
+ 'W' => array(
+ 'HP' => 1.34102006031908E-03,
+ 'h' => 1.34102006031908E-03,
+ 'W' => 1.0,
+ 'w' => 1.0,
+ ),
+ 'w' => array(
+ 'HP' => 1.34102006031908E-03,
+ 'h' => 1.34102006031908E-03,
+ 'W' => 1.0,
+ 'w' => 1.0,
+ ),
+ ),
+ 'Magnetism' => array(
+ 'T' => array(
+ 'T' => 1.0,
+ 'ga' => 10000.0,
+ ),
+ 'ga' => array(
+ 'T' => 0.0001,
+ 'ga' => 1.0,
+ ),
+ ),
+ 'Liquid' => array(
+ 'tsp' => array(
+ 'tsp' => 1.0,
+ 'tbs' => 3.33333333333333E-01,
+ 'oz' => 1.66666666666667E-01,
+ 'cup' => 2.08333333333333E-02,
+ 'pt' => 1.04166666666667E-02,
+ 'us_pt' => 1.04166666666667E-02,
+ 'uk_pt' => 8.67558516821960E-03,
+ 'qt' => 5.20833333333333E-03,
+ 'gal' => 1.30208333333333E-03,
+ 'l' => 4.92999408400710E-03,
+ 'lt' => 4.92999408400710E-03,
+ ),
+ 'tbs' => array(
+ 'tsp' => 3.00000000000000E+00,
+ 'tbs' => 1.0,
+ 'oz' => 5.00000000000000E-01,
+ 'cup' => 6.25000000000000E-02,
+ 'pt' => 3.12500000000000E-02,
+ 'us_pt' => 3.12500000000000E-02,
+ 'uk_pt' => 2.60267555046588E-02,
+ 'qt' => 1.56250000000000E-02,
+ 'gal' => 3.90625000000000E-03,
+ 'l' => 1.47899822520213E-02,
+ 'lt' => 1.47899822520213E-02,
+ ),
+ 'oz' => array(
+ 'tsp' => 6.00000000000000E+00,
+ 'tbs' => 2.00000000000000E+00,
+ 'oz' => 1.0,
+ 'cup' => 1.25000000000000E-01,
+ 'pt' => 6.25000000000000E-02,
+ 'us_pt' => 6.25000000000000E-02,
+ 'uk_pt' => 5.20535110093176E-02,
+ 'qt' => 3.12500000000000E-02,
+ 'gal' => 7.81250000000000E-03,
+ 'l' => 2.95799645040426E-02,
+ 'lt' => 2.95799645040426E-02,
+ ),
+ 'cup' => array(
+ 'tsp' => 4.80000000000000E+01,
+ 'tbs' => 1.60000000000000E+01,
+ 'oz' => 8.00000000000000E+00,
+ 'cup' => 1.0,
+ 'pt' => 5.00000000000000E-01,
+ 'us_pt' => 5.00000000000000E-01,
+ 'uk_pt' => 4.16428088074541E-01,
+ 'qt' => 2.50000000000000E-01,
+ 'gal' => 6.25000000000000E-02,
+ 'l' => 2.36639716032341E-01,
+ 'lt' => 2.36639716032341E-01,
+ ),
+ 'pt' => array(
+ 'tsp' => 9.60000000000000E+01,
+ 'tbs' => 3.20000000000000E+01,
+ 'oz' => 1.60000000000000E+01,
+ 'cup' => 2.00000000000000E+00,
+ 'pt' => 1.0,
+ 'us_pt' => 1.0,
+ 'uk_pt' => 8.32856176149081E-01,
+ 'qt' => 5.00000000000000E-01,
+ 'gal' => 1.25000000000000E-01,
+ 'l' => 4.73279432064682E-01,
+ 'lt' => 4.73279432064682E-01,
+ ),
+ 'us_pt' => array(
+ 'tsp' => 9.60000000000000E+01,
+ 'tbs' => 3.20000000000000E+01,
+ 'oz' => 1.60000000000000E+01,
+ 'cup' => 2.00000000000000E+00,
+ 'pt' => 1.0,
+ 'us_pt' => 1.0,
+ 'uk_pt' => 8.32856176149081E-01,
+ 'qt' => 5.00000000000000E-01,
+ 'gal' => 1.25000000000000E-01,
+ 'l' => 4.73279432064682E-01,
+ 'lt' => 4.73279432064682E-01,
+ ),
+ 'uk_pt' => array(
+ 'tsp' => 1.15266000000000E+02,
+ 'tbs' => 3.84220000000000E+01,
+ 'oz' => 1.92110000000000E+01,
+ 'cup' => 2.40137500000000E+00,
+ 'pt' => 1.20068750000000E+00,
+ 'us_pt' => 1.20068750000000E+00,
+ 'uk_pt' => 1.0,
+ 'qt' => 6.00343750000000E-01,
+ 'gal' => 1.50085937500000E-01,
+ 'l' => 5.68260698087162E-01,
+ 'lt' => 5.68260698087162E-01,
+ ),
+ 'qt' => array(
+ 'tsp' => 1.92000000000000E+02,
+ 'tbs' => 6.40000000000000E+01,
+ 'oz' => 3.20000000000000E+01,
+ 'cup' => 4.00000000000000E+00,
+ 'pt' => 2.00000000000000E+00,
+ 'us_pt' => 2.00000000000000E+00,
+ 'uk_pt' => 1.66571235229816E+00,
+ 'qt' => 1.0,
+ 'gal' => 2.50000000000000E-01,
+ 'l' => 9.46558864129363E-01,
+ 'lt' => 9.46558864129363E-01,
+ ),
+ 'gal' => array(
+ 'tsp' => 7.68000000000000E+02,
+ 'tbs' => 2.56000000000000E+02,
+ 'oz' => 1.28000000000000E+02,
+ 'cup' => 1.60000000000000E+01,
+ 'pt' => 8.00000000000000E+00,
+ 'us_pt' => 8.00000000000000E+00,
+ 'uk_pt' => 6.66284940919265E+00,
+ 'qt' => 4.00000000000000E+00,
+ 'gal' => 1.0,
+ 'l' => 3.78623545651745E+00,
+ 'lt' => 3.78623545651745E+00,
+ ),
+ 'l' => array(
+ 'tsp' => 2.02840000000000E+02,
+ 'tbs' => 6.76133333333333E+01,
+ 'oz' => 3.38066666666667E+01,
+ 'cup' => 4.22583333333333E+00,
+ 'pt' => 2.11291666666667E+00,
+ 'us_pt' => 2.11291666666667E+00,
+ 'uk_pt' => 1.75975569552166E+00,
+ 'qt' => 1.05645833333333E+00,
+ 'gal' => 2.64114583333333E-01,
+ 'l' => 1.0,
+ 'lt' => 1.0,
+ ),
+ 'lt' => array(
+ 'tsp' => 2.02840000000000E+02,
+ 'tbs' => 6.76133333333333E+01,
+ 'oz' => 3.38066666666667E+01,
+ 'cup' => 4.22583333333333E+00,
+ 'pt' => 2.11291666666667E+00,
+ 'us_pt' => 2.11291666666667E+00,
+ 'uk_pt' => 1.75975569552166E+00,
+ 'qt' => 1.05645833333333E+00,
+ 'gal' => 2.64114583333333E-01,
+ 'l' => 1.0,
+ 'lt' => 1.0,
+ ),
+ ),
+ );
+
+
+ /**
+ * parseComplex
+ *
+ * Parses a complex number into its real and imaginary parts, and an I or J suffix
+ *
+ * @param string $complexNumber The complex number
+ * @return string[] Indexed on "real", "imaginary" and "suffix"
+ */
+ public static function parseComplex($complexNumber)
+ {
+ $workString = (string) $complexNumber;
+
+ $realNumber = $imaginary = 0;
+ // Extract the suffix, if there is one
+ $suffix = substr($workString, -1);
+ if (!is_numeric($suffix)) {
+ $workString = substr($workString, 0, -1);
+ } else {
+ $suffix = '';
+ }
+
+ // Split the input into its Real and Imaginary components
+ $leadingSign = 0;
+ if (strlen($workString) > 0) {
+ $leadingSign = (($workString{0} == '+') || ($workString{0} == '-')) ? 1 : 0;
+ }
+ $power = '';
+ $realNumber = strtok($workString, '+-');
+ if (strtoupper(substr($realNumber, -1)) == 'E') {
+ $power = strtok('+-');
+ ++$leadingSign;
+ }
+
+ $realNumber = substr($workString, 0, strlen($realNumber)+strlen($power)+$leadingSign);
+
+ if ($suffix != '') {
+ $imaginary = substr($workString, strlen($realNumber));
+
+ if (($imaginary == '') && (($realNumber == '') || ($realNumber == '+') || ($realNumber == '-'))) {
+ $imaginary = $realNumber.'1';
+ $realNumber = '0';
+ } elseif ($imaginary == '') {
+ $imaginary = $realNumber;
+ $realNumber = '0';
+ } elseif (($imaginary == '+') || ($imaginary == '-')) {
+ $imaginary .= '1';
+ }
+ }
+
+ return array(
+ 'real' => $realNumber,
+ 'imaginary' => $imaginary,
+ 'suffix' => $suffix
+ );
+ }
+
+
+ /**
+ * Cleans the leading characters in a complex number string
+ *
+ * @param string $complexNumber The complex number to clean
+ * @return string The "cleaned" complex number
+ */
+ private static function cleanComplex($complexNumber)
+ {
+ if ($complexNumber{0} == '+') {
+ $complexNumber = substr($complexNumber, 1);
+ }
+ if ($complexNumber{0} == '0') {
+ $complexNumber = substr($complexNumber, 1);
+ }
+ if ($complexNumber{0} == '.') {
+ $complexNumber = '0'.$complexNumber;
+ }
+ if ($complexNumber{0} == '+') {
+ $complexNumber = substr($complexNumber, 1);
+ }
+ return $complexNumber;
+ }
+
+ /**
+ * Formats a number base string value with leading zeroes
+ *
+ * @param string $xVal The "number" to pad
+ * @param integer $places The length that we want to pad this value
+ * @return string The padded "number"
+ */
+ private static function nbrConversionFormat($xVal, $places)
+ {
+ if (!is_null($places)) {
+ if (strlen($xVal) <= $places) {
+ return substr(str_pad($xVal, $places, '0', STR_PAD_LEFT), -10);
+ } else {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+
+ return substr($xVal, -10);
+ }
+
+ /**
+ * BESSELI
+ *
+ * Returns the modified Bessel function In(x), which is equivalent to the Bessel function evaluated
+ * for purely imaginary arguments
+ *
+ * Excel Function:
+ * BESSELI(x,ord)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param float $x The value at which to evaluate the function.
+ * If x is nonnumeric, BESSELI returns the #VALUE! error value.
+ * @param integer $ord The order of the Bessel function.
+ * If ord is not an integer, it is truncated.
+ * If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
+ * If $ord < 0, BESSELI returns the #NUM! error value.
+ * @return float
+ *
+ */
+ public static function BESSELI($x, $ord)
+ {
+ $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $ord = (is_null($ord)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($ord);
+
+ if ((is_numeric($x)) && (is_numeric($ord))) {
+ $ord = floor($ord);
+ if ($ord < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ if (abs($x) <= 30) {
+ $fResult = $fTerm = pow($x / 2, $ord) / PHPExcel_Calculation_MathTrig::FACT($ord);
+ $ordK = 1;
+ $fSqrX = ($x * $x) / 4;
+ do {
+ $fTerm *= $fSqrX;
+ $fTerm /= ($ordK * ($ordK + $ord));
+ $fResult += $fTerm;
+ } while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
+ } else {
+ $f_2_PI = 2 * M_PI;
+
+ $fXAbs = abs($x);
+ $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs);
+ if (($ord & 1) && ($x < 0)) {
+ $fResult = -$fResult;
+ }
+ }
+ return (is_nan($fResult)) ? PHPExcel_Calculation_Functions::NaN() : $fResult;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * BESSELJ
+ *
+ * Returns the Bessel function
+ *
+ * Excel Function:
+ * BESSELJ(x,ord)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param float $x The value at which to evaluate the function.
+ * If x is nonnumeric, BESSELJ returns the #VALUE! error value.
+ * @param integer $ord The order of the Bessel function. If n is not an integer, it is truncated.
+ * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
+ * If $ord < 0, BESSELJ returns the #NUM! error value.
+ * @return float
+ *
+ */
+ public static function BESSELJ($x, $ord)
+ {
+ $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $ord = (is_null($ord)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($ord);
+
+ if ((is_numeric($x)) && (is_numeric($ord))) {
+ $ord = floor($ord);
+ if ($ord < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $fResult = 0;
+ if (abs($x) <= 30) {
+ $fResult = $fTerm = pow($x / 2, $ord) / PHPExcel_Calculation_MathTrig::FACT($ord);
+ $ordK = 1;
+ $fSqrX = ($x * $x) / -4;
+ do {
+ $fTerm *= $fSqrX;
+ $fTerm /= ($ordK * ($ordK + $ord));
+ $fResult += $fTerm;
+ } while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
+ } else {
+ $f_PI_DIV_2 = M_PI / 2;
+ $f_PI_DIV_4 = M_PI / 4;
+
+ $fXAbs = abs($x);
+ $fResult = sqrt(M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4);
+ if (($ord & 1) && ($x < 0)) {
+ $fResult = -$fResult;
+ }
+ }
+ return (is_nan($fResult)) ? PHPExcel_Calculation_Functions::NaN() : $fResult;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ private static function besselK0($fNum)
+ {
+ if ($fNum <= 2) {
+ $fNum2 = $fNum * 0.5;
+ $y = ($fNum2 * $fNum2);
+ $fRet = -log($fNum2) * self::BESSELI($fNum, 0) +
+ (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
+ (0.10750e-3 + $y * 0.74e-5))))));
+ } else {
+ $y = 2 / $fNum;
+ $fRet = exp(-$fNum) / sqrt($fNum) *
+ (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y *
+ (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3))))));
+ }
+ return $fRet;
+ }
+
+
+ private static function besselK1($fNum)
+ {
+ if ($fNum <= 2) {
+ $fNum2 = $fNum * 0.5;
+ $y = ($fNum2 * $fNum2);
+ $fRet = log($fNum2) * self::BESSELI($fNum, 1) +
+ (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
+ (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum;
+ } else {
+ $y = 2 / $fNum;
+ $fRet = exp(-$fNum) / sqrt($fNum) *
+ (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y *
+ (0.325614e-2 + $y * (-0.68245e-3)))))));
+ }
+ return $fRet;
+ }
+
+
+ /**
+ * BESSELK
+ *
+ * Returns the modified Bessel function Kn(x), which is equivalent to the Bessel functions evaluated
+ * for purely imaginary arguments.
+ *
+ * Excel Function:
+ * BESSELK(x,ord)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param float $x The value at which to evaluate the function.
+ * If x is nonnumeric, BESSELK returns the #VALUE! error value.
+ * @param integer $ord The order of the Bessel function. If n is not an integer, it is truncated.
+ * If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
+ * If $ord < 0, BESSELK returns the #NUM! error value.
+ * @return float
+ *
+ */
+ public static function BESSELK($x, $ord)
+ {
+ $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $ord = (is_null($ord)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($ord);
+
+ if ((is_numeric($x)) && (is_numeric($ord))) {
+ if (($ord < 0) || ($x == 0.0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ switch (floor($ord)) {
+ case 0:
+ return self::besselK0($x);
+ case 1:
+ return self::besselK1($x);
+ default:
+ $fTox = 2 / $x;
+ $fBkm = self::besselK0($x);
+ $fBk = self::besselK1($x);
+ for ($n = 1; $n < $ord; ++$n) {
+ $fBkp = $fBkm + $n * $fTox * $fBk;
+ $fBkm = $fBk;
+ $fBk = $fBkp;
+ }
+ }
+ return (is_nan($fBk)) ? PHPExcel_Calculation_Functions::NaN() : $fBk;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ private static function besselY0($fNum)
+ {
+ if ($fNum < 8.0) {
+ $y = ($fNum * $fNum);
+ $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733))));
+ $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y))));
+ $fRet = $f1 / $f2 + 0.636619772 * self::BESSELJ($fNum, 0) * log($fNum);
+ } else {
+ $z = 8.0 / $fNum;
+ $y = ($z * $z);
+ $xx = $fNum - 0.785398164;
+ $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6)));
+ $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7))));
+ $fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
+ }
+ return $fRet;
+ }
+
+
+ private static function besselY1($fNum)
+ {
+ if ($fNum < 8.0) {
+ $y = ($fNum * $fNum);
+ $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y *
+ (-0.4237922726e7 + $y * 0.8511937935e4)))));
+ $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
+ (0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
+ $fRet = $f1 / $f2 + 0.636619772 * ( self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum);
+ } else {
+ $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
+ }
+ return $fRet;
+ }
+
+
+ /**
+ * BESSELY
+ *
+ * Returns the Bessel function, which is also called the Weber function or the Neumann function.
+ *
+ * Excel Function:
+ * BESSELY(x,ord)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param float $x The value at which to evaluate the function.
+ * If x is nonnumeric, BESSELK returns the #VALUE! error value.
+ * @param integer $ord The order of the Bessel function. If n is not an integer, it is truncated.
+ * If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
+ * If $ord < 0, BESSELK returns the #NUM! error value.
+ *
+ * @return float
+ */
+ public static function BESSELY($x, $ord)
+ {
+ $x = (is_null($x)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $ord = (is_null($ord)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($ord);
+
+ if ((is_numeric($x)) && (is_numeric($ord))) {
+ if (($ord < 0) || ($x == 0.0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ switch (floor($ord)) {
+ case 0:
+ return self::besselY0($x);
+ case 1:
+ return self::besselY1($x);
+ default:
+ $fTox = 2 / $x;
+ $fBym = self::besselY0($x);
+ $fBy = self::besselY1($x);
+ for ($n = 1; $n < $ord; ++$n) {
+ $fByp = $n * $fTox * $fBy - $fBym;
+ $fBym = $fBy;
+ $fBy = $fByp;
+ }
+ }
+ return (is_nan($fBy)) ? PHPExcel_Calculation_Functions::NaN() : $fBy;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * BINTODEC
+ *
+ * Return a binary value as decimal.
+ *
+ * Excel Function:
+ * BIN2DEC(x)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The binary number (as a string) that you want to convert. The number
+ * cannot contain more than 10 characters (10 bits). The most significant
+ * bit of number is the sign bit. The remaining 9 bits are magnitude bits.
+ * Negative numbers are represented using two's-complement notation.
+ * If number is not a valid binary number, or if number contains more than
+ * 10 characters (10 bits), BIN2DEC returns the #NUM! error value.
+ * @return string
+ */
+ public static function BINTODEC($x)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+
+ if (is_bool($x)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $x = (int) $x;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $x = floor($x);
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (strlen($x) > 10) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (strlen($x) == 10) {
+ // Two's Complement
+ $x = substr($x, -9);
+ return '-'.(512-bindec($x));
+ }
+ return bindec($x);
+ }
+
+
+ /**
+ * BINTOHEX
+ *
+ * Return a binary value as hex.
+ *
+ * Excel Function:
+ * BIN2HEX(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The binary number (as a string) that you want to convert. The number
+ * cannot contain more than 10 characters (10 bits). The most significant
+ * bit of number is the sign bit. The remaining 9 bits are magnitude bits.
+ * Negative numbers are represented using two's-complement notation.
+ * If number is not a valid binary number, or if number contains more than
+ * 10 characters (10 bits), BIN2HEX returns the #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted, BIN2HEX uses the
+ * minimum number of characters necessary. Places is useful for padding the
+ * return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, BIN2HEX returns the #VALUE! error value.
+ * If places is negative, BIN2HEX returns the #NUM! error value.
+ * @return string
+ */
+ public static function BINTOHEX($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $x = (int) $x;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $x = floor($x);
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (strlen($x) > 10) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (strlen($x) == 10) {
+ // Two's Complement
+ return str_repeat('F', 8).substr(strtoupper(dechex(bindec(substr($x, -9)))), -2);
+ }
+ $hexVal = (string) strtoupper(dechex(bindec($x)));
+
+ return self::nbrConversionFormat($hexVal, $places);
+ }
+
+
+ /**
+ * BINTOOCT
+ *
+ * Return a binary value as octal.
+ *
+ * Excel Function:
+ * BIN2OCT(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The binary number (as a string) that you want to convert. The number
+ * cannot contain more than 10 characters (10 bits). The most significant
+ * bit of number is the sign bit. The remaining 9 bits are magnitude bits.
+ * Negative numbers are represented using two's-complement notation.
+ * If number is not a valid binary number, or if number contains more than
+ * 10 characters (10 bits), BIN2OCT returns the #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted, BIN2OCT uses the
+ * minimum number of characters necessary. Places is useful for padding the
+ * return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, BIN2OCT returns the #VALUE! error value.
+ * If places is negative, BIN2OCT returns the #NUM! error value.
+ * @return string
+ */
+ public static function BINTOOCT($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $x = (int) $x;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $x = floor($x);
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[01]/', $x, $out)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (strlen($x) > 10) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (strlen($x) == 10) {
+ // Two's Complement
+ return str_repeat('7', 7).substr(strtoupper(decoct(bindec(substr($x, -9)))), -3);
+ }
+ $octVal = (string) decoct(bindec($x));
+
+ return self::nbrConversionFormat($octVal, $places);
+ }
+
+
+ /**
+ * DECTOBIN
+ *
+ * Return a decimal value as binary.
+ *
+ * Excel Function:
+ * DEC2BIN(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The decimal integer you want to convert. If number is negative,
+ * valid place values are ignored and DEC2BIN returns a 10-character
+ * (10-bit) binary number in which the most significant bit is the sign
+ * bit. The remaining 9 bits are magnitude bits. Negative numbers are
+ * represented using two's-complement notation.
+ * If number < -512 or if number > 511, DEC2BIN returns the #NUM! error
+ * value.
+ * If number is nonnumeric, DEC2BIN returns the #VALUE! error value.
+ * If DEC2BIN requires more than places characters, it returns the #NUM!
+ * error value.
+ * @param integer $places The number of characters to use. If places is omitted, DEC2BIN uses
+ * the minimum number of characters necessary. Places is useful for
+ * padding the return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, DEC2BIN returns the #VALUE! error value.
+ * If places is zero or negative, DEC2BIN returns the #NUM! error value.
+ * @return string
+ */
+ public static function DECTOBIN($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $x = (int) $x;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) floor($x);
+ $r = decbin($x);
+ if (strlen($r) == 32) {
+ // Two's Complement
+ $r = substr($r, -10);
+ } elseif (strlen($r) > 11) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return self::nbrConversionFormat($r, $places);
+ }
+
+
+ /**
+ * DECTOHEX
+ *
+ * Return a decimal value as hex.
+ *
+ * Excel Function:
+ * DEC2HEX(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The decimal integer you want to convert. If number is negative,
+ * places is ignored and DEC2HEX returns a 10-character (40-bit)
+ * hexadecimal number in which the most significant bit is the sign
+ * bit. The remaining 39 bits are magnitude bits. Negative numbers
+ * are represented using two's-complement notation.
+ * If number < -549,755,813,888 or if number > 549,755,813,887,
+ * DEC2HEX returns the #NUM! error value.
+ * If number is nonnumeric, DEC2HEX returns the #VALUE! error value.
+ * If DEC2HEX requires more than places characters, it returns the
+ * #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted, DEC2HEX uses
+ * the minimum number of characters necessary. Places is useful for
+ * padding the return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, DEC2HEX returns the #VALUE! error value.
+ * If places is zero or negative, DEC2HEX returns the #NUM! error value.
+ * @return string
+ */
+ public static function DECTOHEX($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $x = (int) $x;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) floor($x);
+ $r = strtoupper(dechex($x));
+ if (strlen($r) == 8) {
+ // Two's Complement
+ $r = 'FF'.$r;
+ }
+
+ return self::nbrConversionFormat($r, $places);
+ }
+
+
+ /**
+ * DECTOOCT
+ *
+ * Return an decimal value as octal.
+ *
+ * Excel Function:
+ * DEC2OCT(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The decimal integer you want to convert. If number is negative,
+ * places is ignored and DEC2OCT returns a 10-character (30-bit)
+ * octal number in which the most significant bit is the sign bit.
+ * The remaining 29 bits are magnitude bits. Negative numbers are
+ * represented using two's-complement notation.
+ * If number < -536,870,912 or if number > 536,870,911, DEC2OCT
+ * returns the #NUM! error value.
+ * If number is nonnumeric, DEC2OCT returns the #VALUE! error value.
+ * If DEC2OCT requires more than places characters, it returns the
+ * #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted, DEC2OCT uses
+ * the minimum number of characters necessary. Places is useful for
+ * padding the return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, DEC2OCT returns the #VALUE! error value.
+ * If places is zero or negative, DEC2OCT returns the #NUM! error value.
+ * @return string
+ */
+ public static function DECTOOCT($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $x = (int) $x;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) floor($x);
+ $r = decoct($x);
+ if (strlen($r) == 11) {
+ // Two's Complement
+ $r = substr($r, -10);
+ }
+
+ return self::nbrConversionFormat($r, $places);
+ }
+
+
+ /**
+ * HEXTOBIN
+ *
+ * Return a hex value as binary.
+ *
+ * Excel Function:
+ * HEX2BIN(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x the hexadecimal number you want to convert. Number cannot
+ * contain more than 10 characters. The most significant bit of
+ * number is the sign bit (40th bit from the right). The remaining
+ * 9 bits are magnitude bits. Negative numbers are represented
+ * using two's-complement notation.
+ * If number is negative, HEX2BIN ignores places and returns a
+ * 10-character binary number.
+ * If number is negative, it cannot be less than FFFFFFFE00, and
+ * if number is positive, it cannot be greater than 1FF.
+ * If number is not a valid hexadecimal number, HEX2BIN returns
+ * the #NUM! error value.
+ * If HEX2BIN requires more than places characters, it returns
+ * the #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted,
+ * HEX2BIN uses the minimum number of characters necessary. Places
+ * is useful for padding the return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, HEX2BIN returns the #VALUE! error value.
+ * If places is negative, HEX2BIN returns the #NUM! error value.
+ * @return string
+ */
+ public static function HEXTOBIN($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $binVal = decbin(hexdec($x));
+
+ return substr(self::nbrConversionFormat($binVal, $places), -10);
+ }
+
+
+ /**
+ * HEXTODEC
+ *
+ * Return a hex value as decimal.
+ *
+ * Excel Function:
+ * HEX2DEC(x)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The hexadecimal number you want to convert. This number cannot
+ * contain more than 10 characters (40 bits). The most significant
+ * bit of number is the sign bit. The remaining 39 bits are magnitude
+ * bits. Negative numbers are represented using two's-complement
+ * notation.
+ * If number is not a valid hexadecimal number, HEX2DEC returns the
+ * #NUM! error value.
+ * @return string
+ */
+ public static function HEXTODEC($x)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+
+ if (is_bool($x)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return hexdec($x);
+ }
+
+
+ /**
+ * HEXTOOCT
+ *
+ * Return a hex value as octal.
+ *
+ * Excel Function:
+ * HEX2OCT(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The hexadecimal number you want to convert. Number cannot
+ * contain more than 10 characters. The most significant bit of
+ * number is the sign bit. The remaining 39 bits are magnitude
+ * bits. Negative numbers are represented using two's-complement
+ * notation.
+ * If number is negative, HEX2OCT ignores places and returns a
+ * 10-character octal number.
+ * If number is negative, it cannot be less than FFE0000000, and
+ * if number is positive, it cannot be greater than 1FFFFFFF.
+ * If number is not a valid hexadecimal number, HEX2OCT returns
+ * the #NUM! error value.
+ * If HEX2OCT requires more than places characters, it returns
+ * the #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted, HEX2OCT
+ * uses the minimum number of characters necessary. Places is
+ * useful for padding the return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, HEX2OCT returns the #VALUE! error
+ * value.
+ * If places is negative, HEX2OCT returns the #NUM! error value.
+ * @return string
+ */
+ public static function HEXTOOCT($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) $x;
+ if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $octVal = decoct(hexdec($x));
+
+ return self::nbrConversionFormat($octVal, $places);
+ } // function HEXTOOCT()
+
+
+ /**
+ * OCTTOBIN
+ *
+ * Return an octal value as binary.
+ *
+ * Excel Function:
+ * OCT2BIN(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The octal number you want to convert. Number may not
+ * contain more than 10 characters. The most significant
+ * bit of number is the sign bit. The remaining 29 bits
+ * are magnitude bits. Negative numbers are represented
+ * using two's-complement notation.
+ * If number is negative, OCT2BIN ignores places and returns
+ * a 10-character binary number.
+ * If number is negative, it cannot be less than 7777777000,
+ * and if number is positive, it cannot be greater than 777.
+ * If number is not a valid octal number, OCT2BIN returns
+ * the #NUM! error value.
+ * If OCT2BIN requires more than places characters, it
+ * returns the #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted,
+ * OCT2BIN uses the minimum number of characters necessary.
+ * Places is useful for padding the return value with
+ * leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, OCT2BIN returns the #VALUE!
+ * error value.
+ * If places is negative, OCT2BIN returns the #NUM! error
+ * value.
+ * @return string
+ */
+ public static function OCTTOBIN($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) $x;
+ if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $r = decbin(octdec($x));
+
+ return self::nbrConversionFormat($r, $places);
+ }
+
+
+ /**
+ * OCTTODEC
+ *
+ * Return an octal value as decimal.
+ *
+ * Excel Function:
+ * OCT2DEC(x)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The octal number you want to convert. Number may not contain
+ * more than 10 octal characters (30 bits). The most significant
+ * bit of number is the sign bit. The remaining 29 bits are
+ * magnitude bits. Negative numbers are represented using
+ * two's-complement notation.
+ * If number is not a valid octal number, OCT2DEC returns the
+ * #NUM! error value.
+ * @return string
+ */
+ public static function OCTTODEC($x)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+
+ if (is_bool($x)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) $x;
+ if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return octdec($x);
+ }
+
+
+ /**
+ * OCTTOHEX
+ *
+ * Return an octal value as hex.
+ *
+ * Excel Function:
+ * OCT2HEX(x[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $x The octal number you want to convert. Number may not contain
+ * more than 10 octal characters (30 bits). The most significant
+ * bit of number is the sign bit. The remaining 29 bits are
+ * magnitude bits. Negative numbers are represented using
+ * two's-complement notation.
+ * If number is negative, OCT2HEX ignores places and returns a
+ * 10-character hexadecimal number.
+ * If number is not a valid octal number, OCT2HEX returns the
+ * #NUM! error value.
+ * If OCT2HEX requires more than places characters, it returns
+ * the #NUM! error value.
+ * @param integer $places The number of characters to use. If places is omitted, OCT2HEX
+ * uses the minimum number of characters necessary. Places is useful
+ * for padding the return value with leading 0s (zeros).
+ * If places is not an integer, it is truncated.
+ * If places is nonnumeric, OCT2HEX returns the #VALUE! error value.
+ * If places is negative, OCT2HEX returns the #NUM! error value.
+ * @return string
+ */
+ public static function OCTTOHEX($x, $places = null)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $places = PHPExcel_Calculation_Functions::flattenSingleValue($places);
+
+ if (is_bool($x)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $x = (string) $x;
+ if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $hexVal = strtoupper(dechex(octdec($x)));
+
+ return self::nbrConversionFormat($hexVal, $places);
+ }
+
+
+ /**
+ * COMPLEX
+ *
+ * Converts real and imaginary coefficients into a complex number of the form x + yi or x + yj.
+ *
+ * Excel Function:
+ * COMPLEX(realNumber,imaginary[,places])
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param float $realNumber The real coefficient of the complex number.
+ * @param float $imaginary The imaginary coefficient of the complex number.
+ * @param string $suffix The suffix for the imaginary component of the complex number.
+ * If omitted, the suffix is assumed to be "i".
+ * @return string
+ */
+ public static function COMPLEX($realNumber = 0.0, $imaginary = 0.0, $suffix = 'i')
+ {
+ $realNumber = (is_null($realNumber)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($realNumber);
+ $imaginary = (is_null($imaginary)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($imaginary);
+ $suffix = (is_null($suffix)) ? 'i' : PHPExcel_Calculation_Functions::flattenSingleValue($suffix);
+
+ if (((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
+ (($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))) {
+ $realNumber = (float) $realNumber;
+ $imaginary = (float) $imaginary;
+
+ if ($suffix == '') {
+ $suffix = 'i';
+ }
+ if ($realNumber == 0.0) {
+ if ($imaginary == 0.0) {
+ return (string) '0';
+ } elseif ($imaginary == 1.0) {
+ return (string) $suffix;
+ } elseif ($imaginary == -1.0) {
+ return (string) '-'.$suffix;
+ }
+ return (string) $imaginary.$suffix;
+ } elseif ($imaginary == 0.0) {
+ return (string) $realNumber;
+ } elseif ($imaginary == 1.0) {
+ return (string) $realNumber.'+'.$suffix;
+ } elseif ($imaginary == -1.0) {
+ return (string) $realNumber.'-'.$suffix;
+ }
+ if ($imaginary > 0) {
+ $imaginary = (string) '+'.$imaginary;
+ }
+ return (string) $realNumber.$imaginary.$suffix;
+ }
+
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * IMAGINARY
+ *
+ * Returns the imaginary coefficient of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMAGINARY(complexNumber)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $complexNumber The complex number for which you want the imaginary
+ * coefficient.
+ * @return float
+ */
+ public static function IMAGINARY($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+ return $parsedComplex['imaginary'];
+ }
+
+
+ /**
+ * IMREAL
+ *
+ * Returns the real coefficient of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMREAL(complexNumber)
+ *
+ * @access public
+ * @category Engineering Functions
+ * @param string $complexNumber The complex number for which you want the real coefficient.
+ * @return float
+ */
+ public static function IMREAL($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+ return $parsedComplex['real'];
+ }
+
+
+ /**
+ * IMABS
+ *
+ * Returns the absolute value (modulus) of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMABS(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the absolute value.
+ * @return float
+ */
+ public static function IMABS($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ return sqrt(
+ ($parsedComplex['real'] * $parsedComplex['real']) +
+ ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])
+ );
+ }
+
+
+ /**
+ * IMARGUMENT
+ *
+ * Returns the argument theta of a complex number, i.e. the angle in radians from the real
+ * axis to the representation of the number in polar coordinates.
+ *
+ * Excel Function:
+ * IMARGUMENT(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the argument theta.
+ * @return float
+ */
+ public static function IMARGUMENT($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if ($parsedComplex['real'] == 0.0) {
+ if ($parsedComplex['imaginary'] == 0.0) {
+ return 0.0;
+ } elseif ($parsedComplex['imaginary'] < 0.0) {
+ return M_PI / -2;
+ } else {
+ return M_PI / 2;
+ }
+ } elseif ($parsedComplex['real'] > 0.0) {
+ return atan($parsedComplex['imaginary'] / $parsedComplex['real']);
+ } elseif ($parsedComplex['imaginary'] < 0.0) {
+ return 0 - (M_PI - atan(abs($parsedComplex['imaginary']) / abs($parsedComplex['real'])));
+ } else {
+ return M_PI - atan($parsedComplex['imaginary'] / abs($parsedComplex['real']));
+ }
+ }
+
+
+ /**
+ * IMCONJUGATE
+ *
+ * Returns the complex conjugate of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMCONJUGATE(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the conjugate.
+ * @return string
+ */
+ public static function IMCONJUGATE($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if ($parsedComplex['imaginary'] == 0.0) {
+ return $parsedComplex['real'];
+ } else {
+ return self::cleanComplex(
+ self::COMPLEX(
+ $parsedComplex['real'],
+ 0 - $parsedComplex['imaginary'],
+ $parsedComplex['suffix']
+ )
+ );
+ }
+ }
+
+
+ /**
+ * IMCOS
+ *
+ * Returns the cosine of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMCOS(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the cosine.
+ * @return string|float
+ */
+ public static function IMCOS($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if ($parsedComplex['imaginary'] == 0.0) {
+ return cos($parsedComplex['real']);
+ } else {
+ return self::IMCONJUGATE(
+ self::COMPLEX(
+ cos($parsedComplex['real']) * cosh($parsedComplex['imaginary']),
+ sin($parsedComplex['real']) * sinh($parsedComplex['imaginary']),
+ $parsedComplex['suffix']
+ )
+ );
+ }
+ }
+
+
+ /**
+ * IMSIN
+ *
+ * Returns the sine of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMSIN(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the sine.
+ * @return string|float
+ */
+ public static function IMSIN($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if ($parsedComplex['imaginary'] == 0.0) {
+ return sin($parsedComplex['real']);
+ } else {
+ return self::COMPLEX(
+ sin($parsedComplex['real']) * cosh($parsedComplex['imaginary']),
+ cos($parsedComplex['real']) * sinh($parsedComplex['imaginary']),
+ $parsedComplex['suffix']
+ );
+ }
+ }
+
+
+ /**
+ * IMSQRT
+ *
+ * Returns the square root of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMSQRT(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the square root.
+ * @return string
+ */
+ public static function IMSQRT($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ $theta = self::IMARGUMENT($complexNumber);
+ $d1 = cos($theta / 2);
+ $d2 = sin($theta / 2);
+ $r = sqrt(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
+
+ if ($parsedComplex['suffix'] == '') {
+ return self::COMPLEX($d1 * $r, $d2 * $r);
+ } else {
+ return self::COMPLEX($d1 * $r, $d2 * $r, $parsedComplex['suffix']);
+ }
+ }
+
+
+ /**
+ * IMLN
+ *
+ * Returns the natural logarithm of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMLN(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the natural logarithm.
+ * @return string
+ */
+ public static function IMLN($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $logR = log(sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary'])));
+ $t = self::IMARGUMENT($complexNumber);
+
+ if ($parsedComplex['suffix'] == '') {
+ return self::COMPLEX($logR, $t);
+ } else {
+ return self::COMPLEX($logR, $t, $parsedComplex['suffix']);
+ }
+ }
+
+
+ /**
+ * IMLOG10
+ *
+ * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMLOG10(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the common logarithm.
+ * @return string
+ */
+ public static function IMLOG10($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
+ return log10($parsedComplex['real']);
+ }
+
+ return self::IMPRODUCT(log10(EULER), self::IMLN($complexNumber));
+ }
+
+
+ /**
+ * IMLOG2
+ *
+ * Returns the base-2 logarithm of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMLOG2(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the base-2 logarithm.
+ * @return string
+ */
+ public static function IMLOG2($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (($parsedComplex['real'] > 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
+ return log($parsedComplex['real'], 2);
+ }
+
+ return self::IMPRODUCT(log(EULER, 2), self::IMLN($complexNumber));
+ }
+
+
+ /**
+ * IMEXP
+ *
+ * Returns the exponential of a complex number in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMEXP(complexNumber)
+ *
+ * @param string $complexNumber The complex number for which you want the exponential.
+ * @return string
+ */
+ public static function IMEXP($complexNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ if (($parsedComplex['real'] == 0.0) && ($parsedComplex['imaginary'] == 0.0)) {
+ return '1';
+ }
+
+ $e = exp($parsedComplex['real']);
+ $eX = $e * cos($parsedComplex['imaginary']);
+ $eY = $e * sin($parsedComplex['imaginary']);
+
+ if ($parsedComplex['suffix'] == '') {
+ return self::COMPLEX($eX, $eY);
+ } else {
+ return self::COMPLEX($eX, $eY, $parsedComplex['suffix']);
+ }
+ }
+
+
+ /**
+ * IMPOWER
+ *
+ * Returns a complex number in x + yi or x + yj text format raised to a power.
+ *
+ * Excel Function:
+ * IMPOWER(complexNumber,realNumber)
+ *
+ * @param string $complexNumber The complex number you want to raise to a power.
+ * @param float $realNumber The power to which you want to raise the complex number.
+ * @return string
+ */
+ public static function IMPOWER($complexNumber, $realNumber)
+ {
+ $complexNumber = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber);
+ $realNumber = PHPExcel_Calculation_Functions::flattenSingleValue($realNumber);
+
+ if (!is_numeric($realNumber)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ $parsedComplex = self::parseComplex($complexNumber);
+
+ $r = sqrt(($parsedComplex['real'] * $parsedComplex['real']) + ($parsedComplex['imaginary'] * $parsedComplex['imaginary']));
+ $rPower = pow($r, $realNumber);
+ $theta = self::IMARGUMENT($complexNumber) * $realNumber;
+ if ($theta == 0) {
+ return 1;
+ } elseif ($parsedComplex['imaginary'] == 0.0) {
+ return self::COMPLEX($rPower * cos($theta), $rPower * sin($theta), $parsedComplex['suffix']);
+ } else {
+ return self::COMPLEX($rPower * cos($theta), $rPower * sin($theta), $parsedComplex['suffix']);
+ }
+ }
+
+
+ /**
+ * IMDIV
+ *
+ * Returns the quotient of two complex numbers in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMDIV(complexDividend,complexDivisor)
+ *
+ * @param string $complexDividend The complex numerator or dividend.
+ * @param string $complexDivisor The complex denominator or divisor.
+ * @return string
+ */
+ public static function IMDIV($complexDividend, $complexDivisor)
+ {
+ $complexDividend = PHPExcel_Calculation_Functions::flattenSingleValue($complexDividend);
+ $complexDivisor = PHPExcel_Calculation_Functions::flattenSingleValue($complexDivisor);
+
+ $parsedComplexDividend = self::parseComplex($complexDividend);
+ $parsedComplexDivisor = self::parseComplex($complexDivisor);
+
+ if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] != '') &&
+ ($parsedComplexDividend['suffix'] != $parsedComplexDivisor['suffix'])) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (($parsedComplexDividend['suffix'] != '') && ($parsedComplexDivisor['suffix'] == '')) {
+ $parsedComplexDivisor['suffix'] = $parsedComplexDividend['suffix'];
+ }
+
+ $d1 = ($parsedComplexDividend['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['imaginary']);
+ $d2 = ($parsedComplexDividend['imaginary'] * $parsedComplexDivisor['real']) - ($parsedComplexDividend['real'] * $parsedComplexDivisor['imaginary']);
+ $d3 = ($parsedComplexDivisor['real'] * $parsedComplexDivisor['real']) + ($parsedComplexDivisor['imaginary'] * $parsedComplexDivisor['imaginary']);
+
+ $r = $d1 / $d3;
+ $i = $d2 / $d3;
+
+ if ($i > 0.0) {
+ return self::cleanComplex($r.'+'.$i.$parsedComplexDivisor['suffix']);
+ } elseif ($i < 0.0) {
+ return self::cleanComplex($r.$i.$parsedComplexDivisor['suffix']);
+ } else {
+ return $r;
+ }
+ }
+
+
+ /**
+ * IMSUB
+ *
+ * Returns the difference of two complex numbers in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMSUB(complexNumber1,complexNumber2)
+ *
+ * @param string $complexNumber1 The complex number from which to subtract complexNumber2.
+ * @param string $complexNumber2 The complex number to subtract from complexNumber1.
+ * @return string
+ */
+ public static function IMSUB($complexNumber1, $complexNumber2)
+ {
+ $complexNumber1 = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber1);
+ $complexNumber2 = PHPExcel_Calculation_Functions::flattenSingleValue($complexNumber2);
+
+ $parsedComplex1 = self::parseComplex($complexNumber1);
+ $parsedComplex2 = self::parseComplex($complexNumber2);
+
+ if ((($parsedComplex1['suffix'] != '') && ($parsedComplex2['suffix'] != '')) &&
+ ($parsedComplex1['suffix'] != $parsedComplex2['suffix'])) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (($parsedComplex1['suffix'] == '') && ($parsedComplex2['suffix'] != '')) {
+ $parsedComplex1['suffix'] = $parsedComplex2['suffix'];
+ }
+
+ $d1 = $parsedComplex1['real'] - $parsedComplex2['real'];
+ $d2 = $parsedComplex1['imaginary'] - $parsedComplex2['imaginary'];
+
+ return self::COMPLEX($d1, $d2, $parsedComplex1['suffix']);
+ }
+
+
+ /**
+ * IMSUM
+ *
+ * Returns the sum of two or more complex numbers in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMSUM(complexNumber[,complexNumber[,...]])
+ *
+ * @param string $complexNumber,... Series of complex numbers to add
+ * @return string
+ */
+ public static function IMSUM()
+ {
+ // Return value
+ $returnValue = self::parseComplex('0');
+ $activeSuffix = '';
+
+ // Loop through the arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ $parsedComplex = self::parseComplex($arg);
+
+ if ($activeSuffix == '') {
+ $activeSuffix = $parsedComplex['suffix'];
+ } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ $returnValue['real'] += $parsedComplex['real'];
+ $returnValue['imaginary'] += $parsedComplex['imaginary'];
+ }
+
+ if ($returnValue['imaginary'] == 0.0) {
+ $activeSuffix = '';
+ }
+ return self::COMPLEX($returnValue['real'], $returnValue['imaginary'], $activeSuffix);
+ }
+
+
+ /**
+ * IMPRODUCT
+ *
+ * Returns the product of two or more complex numbers in x + yi or x + yj text format.
+ *
+ * Excel Function:
+ * IMPRODUCT(complexNumber[,complexNumber[,...]])
+ *
+ * @param string $complexNumber,... Series of complex numbers to multiply
+ * @return string
+ */
+ public static function IMPRODUCT()
+ {
+ // Return value
+ $returnValue = self::parseComplex('1');
+ $activeSuffix = '';
+
+ // Loop through the arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ $parsedComplex = self::parseComplex($arg);
+
+ $workValue = $returnValue;
+ if (($parsedComplex['suffix'] != '') && ($activeSuffix == '')) {
+ $activeSuffix = $parsedComplex['suffix'];
+ } elseif (($parsedComplex['suffix'] != '') && ($activeSuffix != $parsedComplex['suffix'])) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $returnValue['real'] = ($workValue['real'] * $parsedComplex['real']) - ($workValue['imaginary'] * $parsedComplex['imaginary']);
+ $returnValue['imaginary'] = ($workValue['real'] * $parsedComplex['imaginary']) + ($workValue['imaginary'] * $parsedComplex['real']);
+ }
+
+ if ($returnValue['imaginary'] == 0.0) {
+ $activeSuffix = '';
+ }
+ return self::COMPLEX($returnValue['real'], $returnValue['imaginary'], $activeSuffix);
+ }
+
+
+ /**
+ * DELTA
+ *
+ * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise.
+ * Use this function to filter a set of values. For example, by summing several DELTA
+ * functions you calculate the count of equal pairs. This function is also known as the
+ * Kronecker Delta function.
+ *
+ * Excel Function:
+ * DELTA(a[,b])
+ *
+ * @param float $a The first number.
+ * @param float $b The second number. If omitted, b is assumed to be zero.
+ * @return int
+ */
+ public static function DELTA($a, $b = 0)
+ {
+ $a = PHPExcel_Calculation_Functions::flattenSingleValue($a);
+ $b = PHPExcel_Calculation_Functions::flattenSingleValue($b);
+
+ return (int) ($a == $b);
+ }
+
+
+ /**
+ * GESTEP
+ *
+ * Excel Function:
+ * GESTEP(number[,step])
+ *
+ * Returns 1 if number >= step; returns 0 (zero) otherwise
+ * Use this function to filter a set of values. For example, by summing several GESTEP
+ * functions you calculate the count of values that exceed a threshold.
+ *
+ * @param float $number The value to test against step.
+ * @param float $step The threshold value.
+ * If you omit a value for step, GESTEP uses zero.
+ * @return int
+ */
+ public static function GESTEP($number, $step = 0)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $step = PHPExcel_Calculation_Functions::flattenSingleValue($step);
+
+ return (int) ($number >= $step);
+ }
+
+
+ //
+ // Private method to calculate the erf value
+ //
+ private static $twoSqrtPi = 1.128379167095512574;
+
+ public static function erfVal($x)
+ {
+ if (abs($x) > 2.2) {
+ return 1 - self::erfcVal($x);
+ }
+ $sum = $term = $x;
+ $xsqr = ($x * $x);
+ $j = 1;
+ do {
+ $term *= $xsqr / $j;
+ $sum -= $term / (2 * $j + 1);
+ ++$j;
+ $term *= $xsqr / $j;
+ $sum += $term / (2 * $j + 1);
+ ++$j;
+ if ($sum == 0.0) {
+ break;
+ }
+ } while (abs($term / $sum) > PRECISION);
+ return self::$twoSqrtPi * $sum;
+ }
+
+
+ /**
+ * ERF
+ *
+ * Returns the error function integrated between the lower and upper bound arguments.
+ *
+ * Note: In Excel 2007 or earlier, if you input a negative value for the upper or lower bound arguments,
+ * the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
+ * improved, so that it can now calculate the function for both positive and negative ranges.
+ * PHPExcel follows Excel 2010 behaviour, and accepts nagative arguments.
+ *
+ * Excel Function:
+ * ERF(lower[,upper])
+ *
+ * @param float $lower lower bound for integrating ERF
+ * @param float $upper upper bound for integrating ERF.
+ * If omitted, ERF integrates between zero and lower_limit
+ * @return float
+ */
+ public static function ERF($lower, $upper = null)
+ {
+ $lower = PHPExcel_Calculation_Functions::flattenSingleValue($lower);
+ $upper = PHPExcel_Calculation_Functions::flattenSingleValue($upper);
+
+ if (is_numeric($lower)) {
+ if (is_null($upper)) {
+ return self::erfVal($lower);
+ }
+ if (is_numeric($upper)) {
+ return self::erfVal($upper) - self::erfVal($lower);
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ //
+ // Private method to calculate the erfc value
+ //
+ private static $oneSqrtPi = 0.564189583547756287;
+
+ private static function erfcVal($x)
+ {
+ if (abs($x) < 2.2) {
+ return 1 - self::erfVal($x);
+ }
+ if ($x < 0) {
+ return 2 - self::ERFC(-$x);
+ }
+ $a = $n = 1;
+ $b = $c = $x;
+ $d = ($x * $x) + 0.5;
+ $q1 = $q2 = $b / $d;
+ $t = 0;
+ do {
+ $t = $a * $n + $b * $x;
+ $a = $b;
+ $b = $t;
+ $t = $c * $n + $d * $x;
+ $c = $d;
+ $d = $t;
+ $n += 0.5;
+ $q1 = $q2;
+ $q2 = $b / $d;
+ } while ((abs($q1 - $q2) / $q2) > PRECISION);
+ return self::$oneSqrtPi * exp(-$x * $x) * $q2;
+ }
+
+
+ /**
+ * ERFC
+ *
+ * Returns the complementary ERF function integrated between x and infinity
+ *
+ * Note: In Excel 2007 or earlier, if you input a negative value for the lower bound argument,
+ * the function would return a #NUM! error. However, in Excel 2010, the function algorithm was
+ * improved, so that it can now calculate the function for both positive and negative x values.
+ * PHPExcel follows Excel 2010 behaviour, and accepts nagative arguments.
+ *
+ * Excel Function:
+ * ERFC(x)
+ *
+ * @param float $x The lower bound for integrating ERFC
+ * @return float
+ */
+ public static function ERFC($x)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+
+ if (is_numeric($x)) {
+ return self::erfcVal($x);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * getConversionGroups
+ * Returns a list of the different conversion groups for UOM conversions
+ *
+ * @return array
+ */
+ public static function getConversionGroups()
+ {
+ $conversionGroups = array();
+ foreach (self::$conversionUnits as $conversionUnit) {
+ $conversionGroups[] = $conversionUnit['Group'];
+ }
+ return array_merge(array_unique($conversionGroups));
+ }
+
+
+ /**
+ * getConversionGroupUnits
+ * Returns an array of units of measure, for a specified conversion group, or for all groups
+ *
+ * @param string $group The group whose units of measure you want to retrieve
+ * @return array
+ */
+ public static function getConversionGroupUnits($group = null)
+ {
+ $conversionGroups = array();
+ foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
+ if ((is_null($group)) || ($conversionGroup['Group'] == $group)) {
+ $conversionGroups[$conversionGroup['Group']][] = $conversionUnit;
+ }
+ }
+ return $conversionGroups;
+ }
+
+
+ /**
+ * getConversionGroupUnitDetails
+ *
+ * @param string $group The group whose units of measure you want to retrieve
+ * @return array
+ */
+ public static function getConversionGroupUnitDetails($group = null)
+ {
+ $conversionGroups = array();
+ foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
+ if ((is_null($group)) || ($conversionGroup['Group'] == $group)) {
+ $conversionGroups[$conversionGroup['Group']][] = array(
+ 'unit' => $conversionUnit,
+ 'description' => $conversionGroup['Unit Name']
+ );
+ }
+ }
+ return $conversionGroups;
+ }
+
+
+ /**
+ * getConversionMultipliers
+ * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM()
+ *
+ * @return array of mixed
+ */
+ public static function getConversionMultipliers()
+ {
+ return self::$conversionMultipliers;
+ }
+
+
+ /**
+ * CONVERTUOM
+ *
+ * Converts a number from one measurement system to another.
+ * For example, CONVERT can translate a table of distances in miles to a table of distances
+ * in kilometers.
+ *
+ * Excel Function:
+ * CONVERT(value,fromUOM,toUOM)
+ *
+ * @param float $value The value in fromUOM to convert.
+ * @param string $fromUOM The units for value.
+ * @param string $toUOM The units for the result.
+ *
+ * @return float
+ */
+ public static function CONVERTUOM($value, $fromUOM, $toUOM)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $fromUOM = PHPExcel_Calculation_Functions::flattenSingleValue($fromUOM);
+ $toUOM = PHPExcel_Calculation_Functions::flattenSingleValue($toUOM);
+
+ if (!is_numeric($value)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $fromMultiplier = 1.0;
+ if (isset(self::$conversionUnits[$fromUOM])) {
+ $unitGroup1 = self::$conversionUnits[$fromUOM]['Group'];
+ } else {
+ $fromMultiplier = substr($fromUOM, 0, 1);
+ $fromUOM = substr($fromUOM, 1);
+ if (isset(self::$conversionMultipliers[$fromMultiplier])) {
+ $fromMultiplier = self::$conversionMultipliers[$fromMultiplier]['multiplier'];
+ } else {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ if ((isset(self::$conversionUnits[$fromUOM])) && (self::$conversionUnits[$fromUOM]['AllowPrefix'])) {
+ $unitGroup1 = self::$conversionUnits[$fromUOM]['Group'];
+ } else {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ }
+ $value *= $fromMultiplier;
+
+ $toMultiplier = 1.0;
+ if (isset(self::$conversionUnits[$toUOM])) {
+ $unitGroup2 = self::$conversionUnits[$toUOM]['Group'];
+ } else {
+ $toMultiplier = substr($toUOM, 0, 1);
+ $toUOM = substr($toUOM, 1);
+ if (isset(self::$conversionMultipliers[$toMultiplier])) {
+ $toMultiplier = self::$conversionMultipliers[$toMultiplier]['multiplier'];
+ } else {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ if ((isset(self::$conversionUnits[$toUOM])) && (self::$conversionUnits[$toUOM]['AllowPrefix'])) {
+ $unitGroup2 = self::$conversionUnits[$toUOM]['Group'];
+ } else {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ }
+ if ($unitGroup1 != $unitGroup2) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+ if (($fromUOM == $toUOM) && ($fromMultiplier == $toMultiplier)) {
+ // We've already factored $fromMultiplier into the value, so we need
+ // to reverse it again
+ return $value / $fromMultiplier;
+ } elseif ($unitGroup1 == 'Temperature') {
+ if (($fromUOM == 'F') || ($fromUOM == 'fah')) {
+ if (($toUOM == 'F') || ($toUOM == 'fah')) {
+ return $value;
+ } else {
+ $value = (($value - 32) / 1.8);
+ if (($toUOM == 'K') || ($toUOM == 'kel')) {
+ $value += 273.15;
+ }
+ return $value;
+ }
+ } elseif ((($fromUOM == 'K') || ($fromUOM == 'kel')) &&
+ (($toUOM == 'K') || ($toUOM == 'kel'))) {
+ return $value;
+ } elseif ((($fromUOM == 'C') || ($fromUOM == 'cel')) &&
+ (($toUOM == 'C') || ($toUOM == 'cel'))) {
+ return $value;
+ }
+ if (($toUOM == 'F') || ($toUOM == 'fah')) {
+ if (($fromUOM == 'K') || ($fromUOM == 'kel')) {
+ $value -= 273.15;
+ }
+ return ($value * 1.8) + 32;
+ }
+ if (($toUOM == 'C') || ($toUOM == 'cel')) {
+ return $value - 273.15;
+ }
+ return $value + 273.15;
+ }
+ return ($value * self::$unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Exception.php b/extend/PHPExcel/PHPExcel/Calculation/Exception.php
new file mode 100755
index 0000000..52d73fc
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Exception.php
@@ -0,0 +1,46 @@
+line = $line;
+ $e->file = $file;
+ throw $e;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php b/extend/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php
new file mode 100755
index 0000000..4cb0a68
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/ExceptionHandler.php
@@ -0,0 +1,45 @@
+format('d') == $testDate->format('t'));
+ }
+
+
+ /**
+ * isFirstDayOfMonth
+ *
+ * Returns a boolean TRUE/FALSE indicating if this date is the first date of the month
+ *
+ * @param DateTime $testDate The date for testing
+ * @return boolean
+ */
+ private static function isFirstDayOfMonth($testDate)
+ {
+ return ($testDate->format('d') == 1);
+ }
+
+
+ private static function couponFirstPeriodDate($settlement, $maturity, $frequency, $next)
+ {
+ $months = 12 / $frequency;
+
+ $result = PHPExcel_Shared_Date::ExcelToPHPObject($maturity);
+ $eom = self::isLastDayOfMonth($result);
+
+ while ($settlement < PHPExcel_Shared_Date::PHPToExcel($result)) {
+ $result->modify('-'.$months.' months');
+ }
+ if ($next) {
+ $result->modify('+'.$months.' months');
+ }
+
+ if ($eom) {
+ $result->modify('-1 day');
+ }
+
+ return PHPExcel_Shared_Date::PHPToExcel($result);
+ }
+
+
+ private static function isValidFrequency($frequency)
+ {
+ if (($frequency == 1) || ($frequency == 2) || ($frequency == 4)) {
+ return true;
+ }
+ if ((PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) &&
+ (($frequency == 6) || ($frequency == 12))) {
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * daysPerYear
+ *
+ * Returns the number of days in a specified year, as defined by the "basis" value
+ *
+ * @param integer $year The year against which we're testing
+ * @param integer $basis The type of day count:
+ * 0 or omitted US (NASD) 360
+ * 1 Actual (365 or 366 in a leap year)
+ * 2 360
+ * 3 365
+ * 4 European 360
+ * @return integer
+ */
+ private static function daysPerYear($year, $basis = 0)
+ {
+ switch ($basis) {
+ case 0:
+ case 2:
+ case 4:
+ $daysPerYear = 360;
+ break;
+ case 3:
+ $daysPerYear = 365;
+ break;
+ case 1:
+ $daysPerYear = (PHPExcel_Calculation_DateTime::isLeapYear($year)) ? 366 : 365;
+ break;
+ default:
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return $daysPerYear;
+ }
+
+
+ private static function interestAndPrincipal($rate = 0, $per = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
+ {
+ $pmt = self::PMT($rate, $nper, $pv, $fv, $type);
+ $capital = $pv;
+ for ($i = 1; $i<= $per; ++$i) {
+ $interest = ($type && $i == 1) ? 0 : -$capital * $rate;
+ $principal = $pmt - $interest;
+ $capital += $principal;
+ }
+ return array($interest, $principal);
+ }
+
+
+ /**
+ * ACCRINT
+ *
+ * Returns the accrued interest for a security that pays periodic interest.
+ *
+ * Excel Function:
+ * ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed $issue The security's issue date.
+ * @param mixed $firstinterest The security's first interest date.
+ * @param mixed $settlement The security's settlement date.
+ * The security settlement date is the date after the issue date
+ * when the security is traded to the buyer.
+ * @param float $rate The security's annual coupon rate.
+ * @param float $par The security's par value.
+ * If you omit par, ACCRINT uses $1,000.
+ * @param integer $frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer $basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
+ {
+ $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
+ $firstinterest = PHPExcel_Calculation_Functions::flattenSingleValue($firstinterest);
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $par = (is_null($par)) ? 1000 : PHPExcel_Calculation_Functions::flattenSingleValue($par);
+ $frequency = (is_null($frequency)) ? 1 : PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if ((is_numeric($rate)) && (is_numeric($par))) {
+ $rate = (float) $rate;
+ $par = (float) $par;
+ if (($rate <= 0) || ($par <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
+ if (!is_numeric($daysBetweenIssueAndSettlement)) {
+ // return date error
+ return $daysBetweenIssueAndSettlement;
+ }
+
+ return $par * $rate * $daysBetweenIssueAndSettlement;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * ACCRINTM
+ *
+ * Returns the accrued interest for a security that pays interest at maturity.
+ *
+ * Excel Function:
+ * ACCRINTM(issue,settlement,rate[,par[,basis]])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed issue The security's issue date.
+ * @param mixed settlement The security's settlement (or maturity) date.
+ * @param float rate The security's annual coupon rate.
+ * @param float par The security's par value.
+ * If you omit par, ACCRINT uses $1,000.
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
+ {
+ $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $par = (is_null($par)) ? 1000 : PHPExcel_Calculation_Functions::flattenSingleValue($par);
+ $basis = (is_null($basis)) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if ((is_numeric($rate)) && (is_numeric($par))) {
+ $rate = (float) $rate;
+ $par = (float) $par;
+ if (($rate <= 0) || ($par <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
+ if (!is_numeric($daysBetweenIssueAndSettlement)) {
+ // return date error
+ return $daysBetweenIssueAndSettlement;
+ }
+ return $par * $rate * $daysBetweenIssueAndSettlement;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * AMORDEGRC
+ *
+ * Returns the depreciation for each accounting period.
+ * This function is provided for the French accounting system. If an asset is purchased in
+ * the middle of the accounting period, the prorated depreciation is taken into account.
+ * The function is similar to AMORLINC, except that a depreciation coefficient is applied in
+ * the calculation depending on the life of the assets.
+ * This function will return the depreciation until the last period of the life of the assets
+ * or until the cumulated value of depreciation is greater than the cost of the assets minus
+ * the salvage value.
+ *
+ * Excel Function:
+ * AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float cost The cost of the asset.
+ * @param mixed purchased Date of the purchase of the asset.
+ * @param mixed firstPeriod Date of the end of the first period.
+ * @param mixed salvage The salvage value at the end of the life of the asset.
+ * @param float period The period.
+ * @param float rate Rate of depreciation.
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0)
+ {
+ $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
+ $purchased = PHPExcel_Calculation_Functions::flattenSingleValue($purchased);
+ $firstPeriod = PHPExcel_Calculation_Functions::flattenSingleValue($firstPeriod);
+ $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
+ $period = floor(PHPExcel_Calculation_Functions::flattenSingleValue($period));
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // The depreciation coefficients are:
+ // Life of assets (1/rate) Depreciation coefficient
+ // Less than 3 years 1
+ // Between 3 and 4 years 1.5
+ // Between 5 and 6 years 2
+ // More than 6 years 2.5
+ $fUsePer = 1.0 / $rate;
+ if ($fUsePer < 3.0) {
+ $amortiseCoeff = 1.0;
+ } elseif ($fUsePer < 5.0) {
+ $amortiseCoeff = 1.5;
+ } elseif ($fUsePer <= 6.0) {
+ $amortiseCoeff = 2.0;
+ } else {
+ $amortiseCoeff = 2.5;
+ }
+
+ $rate *= $amortiseCoeff;
+ $fNRate = round(PHPExcel_Calculation_DateTime::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost, 0);
+ $cost -= $fNRate;
+ $fRest = $cost - $salvage;
+
+ for ($n = 0; $n < $period; ++$n) {
+ $fNRate = round($rate * $cost, 0);
+ $fRest -= $fNRate;
+
+ if ($fRest < 0.0) {
+ switch ($period - $n) {
+ case 0:
+ case 1:
+ return round($cost * 0.5, 0);
+ default:
+ return 0.0;
+ }
+ }
+ $cost -= $fNRate;
+ }
+ return $fNRate;
+ }
+
+
+ /**
+ * AMORLINC
+ *
+ * Returns the depreciation for each accounting period.
+ * This function is provided for the French accounting system. If an asset is purchased in
+ * the middle of the accounting period, the prorated depreciation is taken into account.
+ *
+ * Excel Function:
+ * AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float cost The cost of the asset.
+ * @param mixed purchased Date of the purchase of the asset.
+ * @param mixed firstPeriod Date of the end of the first period.
+ * @param mixed salvage The salvage value at the end of the life of the asset.
+ * @param float period The period.
+ * @param float rate Rate of depreciation.
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0)
+ {
+ $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
+ $purchased = PHPExcel_Calculation_Functions::flattenSingleValue($purchased);
+ $firstPeriod = PHPExcel_Calculation_Functions::flattenSingleValue($firstPeriod);
+ $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
+ $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ $fOneRate = $cost * $rate;
+ $fCostDelta = $cost - $salvage;
+ // Note, quirky variation for leap years on the YEARFRAC for this function
+ $purchasedYear = PHPExcel_Calculation_DateTime::YEAR($purchased);
+ $yearFrac = PHPExcel_Calculation_DateTime::YEARFRAC($purchased, $firstPeriod, $basis);
+
+ if (($basis == 1) && ($yearFrac < 1) && (PHPExcel_Calculation_DateTime::isLeapYear($purchasedYear))) {
+ $yearFrac *= 365 / 366;
+ }
+
+ $f0Rate = $yearFrac * $rate * $cost;
+ $nNumOfFullPeriods = intval(($cost - $salvage - $f0Rate) / $fOneRate);
+
+ if ($period == 0) {
+ return $f0Rate;
+ } elseif ($period <= $nNumOfFullPeriods) {
+ return $fOneRate;
+ } elseif ($period == ($nNumOfFullPeriods + 1)) {
+ return ($fCostDelta - $fOneRate * $nNumOfFullPeriods - $f0Rate);
+ } else {
+ return 0.0;
+ }
+ }
+
+
+ /**
+ * COUPDAYBS
+ *
+ * Returns the number of days from the beginning of the coupon period to the settlement date.
+ *
+ * Excel Function:
+ * COUPDAYBS(settlement,maturity,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function COUPDAYBS($settlement, $maturity, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $daysPerYear = self::daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement), $basis);
+ $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, false);
+
+ return PHPExcel_Calculation_DateTime::YEARFRAC($prev, $settlement, $basis) * $daysPerYear;
+ }
+
+
+ /**
+ * COUPDAYS
+ *
+ * Returns the number of days in the coupon period that contains the settlement date.
+ *
+ * Excel Function:
+ * COUPDAYS(settlement,maturity,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function COUPDAYS($settlement, $maturity, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ switch ($basis) {
+ case 3:
+ // Actual/365
+ return 365 / $frequency;
+ case 1:
+ // Actual/actual
+ if ($frequency == 1) {
+ $daysPerYear = self::daysPerYear(PHPExcel_Calculation_DateTime::YEAR($maturity), $basis);
+ return ($daysPerYear / $frequency);
+ }
+ $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, false);
+ $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true);
+ return ($next - $prev);
+ default:
+ // US (NASD) 30/360, Actual/360 or European 30/360
+ return 360 / $frequency;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * COUPDAYSNC
+ *
+ * Returns the number of days from the settlement date to the next coupon date.
+ *
+ * Excel Function:
+ * COUPDAYSNC(settlement,maturity,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $daysPerYear = self::daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement), $basis);
+ $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true);
+
+ return PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $next, $basis) * $daysPerYear;
+ }
+
+
+ /**
+ * COUPNCD
+ *
+ * Returns the next coupon date after the settlement date.
+ *
+ * Excel Function:
+ * COUPNCD(settlement,maturity,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function COUPNCD($settlement, $maturity, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return self::couponFirstPeriodDate($settlement, $maturity, $frequency, true);
+ }
+
+
+ /**
+ * COUPNUM
+ *
+ * Returns the number of coupons payable between the settlement date and maturity date,
+ * rounded up to the nearest whole coupon.
+ *
+ * Excel Function:
+ * COUPNUM(settlement,maturity,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return integer
+ */
+ public static function COUPNUM($settlement, $maturity, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $settlement = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true);
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis) * 365;
+
+ switch ($frequency) {
+ case 1: // annual payments
+ return ceil($daysBetweenSettlementAndMaturity / 360);
+ case 2: // half-yearly
+ return ceil($daysBetweenSettlementAndMaturity / 180);
+ case 4: // quarterly
+ return ceil($daysBetweenSettlementAndMaturity / 90);
+ case 6: // bimonthly
+ return ceil($daysBetweenSettlementAndMaturity / 60);
+ case 12: // monthly
+ return ceil($daysBetweenSettlementAndMaturity / 30);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * COUPPCD
+ *
+ * Returns the previous coupon date before the settlement date.
+ *
+ * Excel Function:
+ * COUPPCD(settlement,maturity,frequency[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed frequency the number of coupon payments per year.
+ * Valid frequency values are:
+ * 1 Annual
+ * 2 Semi-Annual
+ * 4 Quarterly
+ * If working in Gnumeric Mode, the following frequency options are
+ * also available
+ * 6 Bimonthly
+ * 12 Monthly
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+ * depending on the value of the ReturnDateType flag
+ */
+ public static function COUPPCD($settlement, $maturity, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return self::couponFirstPeriodDate($settlement, $maturity, $frequency, false);
+ }
+
+
+ /**
+ * CUMIPMT
+ *
+ * Returns the cumulative interest paid on a loan between the start and end periods.
+ *
+ * Excel Function:
+ * CUMIPMT(rate,nper,pv,start,end[,type])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float $rate The Interest rate
+ * @param integer $nper The total number of payment periods
+ * @param float $pv Present Value
+ * @param integer $start The first period in the calculation.
+ * Payment periods are numbered beginning with 1.
+ * @param integer $end The last period in the calculation.
+ * @param integer $type A number 0 or 1 and indicates when payments are due:
+ * 0 or omitted At the end of the period.
+ * 1 At the beginning of the period.
+ * @return float
+ */
+ public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $start = (int) PHPExcel_Calculation_Functions::flattenSingleValue($start);
+ $end = (int) PHPExcel_Calculation_Functions::flattenSingleValue($end);
+ $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($start < 1 || $start > $end) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Calculate
+ $interest = 0;
+ for ($per = $start; $per <= $end; ++$per) {
+ $interest += self::IPMT($rate, $per, $nper, $pv, 0, $type);
+ }
+
+ return $interest;
+ }
+
+
+ /**
+ * CUMPRINC
+ *
+ * Returns the cumulative principal paid on a loan between the start and end periods.
+ *
+ * Excel Function:
+ * CUMPRINC(rate,nper,pv,start,end[,type])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float $rate The Interest rate
+ * @param integer $nper The total number of payment periods
+ * @param float $pv Present Value
+ * @param integer $start The first period in the calculation.
+ * Payment periods are numbered beginning with 1.
+ * @param integer $end The last period in the calculation.
+ * @param integer $type A number 0 or 1 and indicates when payments are due:
+ * 0 or omitted At the end of the period.
+ * 1 At the beginning of the period.
+ * @return float
+ */
+ public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $start = (int) PHPExcel_Calculation_Functions::flattenSingleValue($start);
+ $end = (int) PHPExcel_Calculation_Functions::flattenSingleValue($end);
+ $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($start < 1 || $start > $end) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Calculate
+ $principal = 0;
+ for ($per = $start; $per <= $end; ++$per) {
+ $principal += self::PPMT($rate, $per, $nper, $pv, 0, $type);
+ }
+
+ return $principal;
+ }
+
+
+ /**
+ * DB
+ *
+ * Returns the depreciation of an asset for a specified period using the
+ * fixed-declining balance method.
+ * This form of depreciation is used if you want to get a higher depreciation value
+ * at the beginning of the depreciation (as opposed to linear depreciation). The
+ * depreciation value is reduced with every depreciation period by the depreciation
+ * already deducted from the initial cost.
+ *
+ * Excel Function:
+ * DB(cost,salvage,life,period[,month])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float cost Initial cost of the asset.
+ * @param float salvage Value at the end of the depreciation.
+ * (Sometimes called the salvage value of the asset)
+ * @param integer life Number of periods over which the asset is depreciated.
+ * (Sometimes called the useful life of the asset)
+ * @param integer period The period for which you want to calculate the
+ * depreciation. Period must use the same units as life.
+ * @param integer month Number of months in the first year. If month is omitted,
+ * it defaults to 12.
+ * @return float
+ */
+ public static function DB($cost, $salvage, $life, $period, $month = 12)
+ {
+ $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
+ $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
+ $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
+ $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
+ $month = PHPExcel_Calculation_Functions::flattenSingleValue($month);
+
+ // Validate
+ if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) {
+ $cost = (float) $cost;
+ $salvage = (float) $salvage;
+ $life = (int) $life;
+ $period = (int) $period;
+ $month = (int) $month;
+ if ($cost == 0) {
+ return 0.0;
+ } elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ // Set Fixed Depreciation Rate
+ $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
+ $fixedDepreciationRate = round($fixedDepreciationRate, 3);
+
+ // Loop through each period calculating the depreciation
+ $previousDepreciation = 0;
+ for ($per = 1; $per <= $period; ++$per) {
+ if ($per == 1) {
+ $depreciation = $cost * $fixedDepreciationRate * $month / 12;
+ } elseif ($per == ($life + 1)) {
+ $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12;
+ } else {
+ $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate;
+ }
+ $previousDepreciation += $depreciation;
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $depreciation = round($depreciation, 2);
+ }
+ return $depreciation;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * DDB
+ *
+ * Returns the depreciation of an asset for a specified period using the
+ * double-declining balance method or some other method you specify.
+ *
+ * Excel Function:
+ * DDB(cost,salvage,life,period[,factor])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float cost Initial cost of the asset.
+ * @param float salvage Value at the end of the depreciation.
+ * (Sometimes called the salvage value of the asset)
+ * @param integer life Number of periods over which the asset is depreciated.
+ * (Sometimes called the useful life of the asset)
+ * @param integer period The period for which you want to calculate the
+ * depreciation. Period must use the same units as life.
+ * @param float factor The rate at which the balance declines.
+ * If factor is omitted, it is assumed to be 2 (the
+ * double-declining balance method).
+ * @return float
+ */
+ public static function DDB($cost, $salvage, $life, $period, $factor = 2.0)
+ {
+ $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
+ $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
+ $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
+ $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
+ $factor = PHPExcel_Calculation_Functions::flattenSingleValue($factor);
+
+ // Validate
+ if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) {
+ $cost = (float) $cost;
+ $salvage = (float) $salvage;
+ $life = (int) $life;
+ $period = (int) $period;
+ $factor = (float) $factor;
+ if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ // Set Fixed Depreciation Rate
+ $fixedDepreciationRate = 1 - pow(($salvage / $cost), (1 / $life));
+ $fixedDepreciationRate = round($fixedDepreciationRate, 3);
+
+ // Loop through each period calculating the depreciation
+ $previousDepreciation = 0;
+ for ($per = 1; $per <= $period; ++$per) {
+ $depreciation = min(($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation));
+ $previousDepreciation += $depreciation;
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ $depreciation = round($depreciation, 2);
+ }
+ return $depreciation;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * DISC
+ *
+ * Returns the discount rate for a security.
+ *
+ * Excel Function:
+ * DISC(settlement,maturity,price,redemption[,basis])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue
+ * date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param integer price The security's price per $100 face value.
+ * @param integer redemption The security's redemption value per $100 face value.
+ * @param integer basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function DISC($settlement, $maturity, $price, $redemption, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
+ $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
+ $basis = PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) {
+ $price = (float) $price;
+ $redemption = (float) $redemption;
+ $basis = (int) $basis;
+ if (($price <= 0) || ($redemption <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+
+ return ((1 - $price / $redemption) / $daysBetweenSettlementAndMaturity);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * DOLLARDE
+ *
+ * Converts a dollar price expressed as an integer part and a fraction
+ * part into a dollar price expressed as a decimal number.
+ * Fractional dollar numbers are sometimes used for security prices.
+ *
+ * Excel Function:
+ * DOLLARDE(fractional_dollar,fraction)
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float $fractional_dollar Fractional Dollar
+ * @param integer $fraction Fraction
+ * @return float
+ */
+ public static function DOLLARDE($fractional_dollar = null, $fraction = 0)
+ {
+ $fractional_dollar = PHPExcel_Calculation_Functions::flattenSingleValue($fractional_dollar);
+ $fraction = (int)PHPExcel_Calculation_Functions::flattenSingleValue($fraction);
+
+ // Validate parameters
+ if (is_null($fractional_dollar) || $fraction < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($fraction == 0) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $dollars = floor($fractional_dollar);
+ $cents = fmod($fractional_dollar, 1);
+ $cents /= $fraction;
+ $cents *= pow(10, ceil(log10($fraction)));
+ return $dollars + $cents;
+ }
+
+
+ /**
+ * DOLLARFR
+ *
+ * Converts a dollar price expressed as a decimal number into a dollar price
+ * expressed as a fraction.
+ * Fractional dollar numbers are sometimes used for security prices.
+ *
+ * Excel Function:
+ * DOLLARFR(decimal_dollar,fraction)
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float $decimal_dollar Decimal Dollar
+ * @param integer $fraction Fraction
+ * @return float
+ */
+ public static function DOLLARFR($decimal_dollar = null, $fraction = 0)
+ {
+ $decimal_dollar = PHPExcel_Calculation_Functions::flattenSingleValue($decimal_dollar);
+ $fraction = (int)PHPExcel_Calculation_Functions::flattenSingleValue($fraction);
+
+ // Validate parameters
+ if (is_null($decimal_dollar) || $fraction < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($fraction == 0) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $dollars = floor($decimal_dollar);
+ $cents = fmod($decimal_dollar, 1);
+ $cents *= $fraction;
+ $cents *= pow(10, -ceil(log10($fraction)));
+ return $dollars + $cents;
+ }
+
+
+ /**
+ * EFFECT
+ *
+ * Returns the effective interest rate given the nominal rate and the number of
+ * compounding payments per year.
+ *
+ * Excel Function:
+ * EFFECT(nominal_rate,npery)
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float $nominal_rate Nominal interest rate
+ * @param integer $npery Number of compounding payments per year
+ * @return float
+ */
+ public static function EFFECT($nominal_rate = 0, $npery = 0)
+ {
+ $nominal_rate = PHPExcel_Calculation_Functions::flattenSingleValue($nominal_rate);
+ $npery = (int)PHPExcel_Calculation_Functions::flattenSingleValue($npery);
+
+ // Validate parameters
+ if ($nominal_rate <= 0 || $npery < 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return pow((1 + $nominal_rate / $npery), $npery) - 1;
+ }
+
+
+ /**
+ * FV
+ *
+ * Returns the Future Value of a cash flow with constant payments and interest rate (annuities).
+ *
+ * Excel Function:
+ * FV(rate,nper,pmt[,pv[,type]])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float $rate The interest rate per period
+ * @param int $nper Total number of payment periods in an annuity
+ * @param float $pmt The payment made each period: it cannot change over the
+ * life of the annuity. Typically, pmt contains principal
+ * and interest but no other fees or taxes.
+ * @param float $pv Present Value, or the lump-sum amount that a series of
+ * future payments is worth right now.
+ * @param integer $type A number 0 or 1 and indicates when payments are due:
+ * 0 or omitted At the end of the period.
+ * 1 At the beginning of the period.
+ * @return float
+ */
+ public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Calculate
+ if (!is_null($rate) && $rate != 0) {
+ return -$pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate;
+ }
+ return -$pv - $pmt * $nper;
+ }
+
+
+ /**
+ * FVSCHEDULE
+ *
+ * Returns the future value of an initial principal after applying a series of compound interest rates.
+ * Use FVSCHEDULE to calculate the future value of an investment with a variable or adjustable rate.
+ *
+ * Excel Function:
+ * FVSCHEDULE(principal,schedule)
+ *
+ * @param float $principal The present value.
+ * @param float[] $schedule An array of interest rates to apply.
+ * @return float
+ */
+ public static function FVSCHEDULE($principal, $schedule)
+ {
+ $principal = PHPExcel_Calculation_Functions::flattenSingleValue($principal);
+ $schedule = PHPExcel_Calculation_Functions::flattenArray($schedule);
+
+ foreach ($schedule as $rate) {
+ $principal *= 1 + $rate;
+ }
+
+ return $principal;
+ }
+
+
+ /**
+ * INTRATE
+ *
+ * Returns the interest rate for a fully invested security.
+ *
+ * Excel Function:
+ * INTRATE(settlement,maturity,investment,redemption[,basis])
+ *
+ * @param mixed $settlement The security's settlement date.
+ * The security settlement date is the date after the issue date when the security is traded to the buyer.
+ * @param mixed $maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param integer $investment The amount invested in the security.
+ * @param integer $redemption The amount to be received at maturity.
+ * @param integer $basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $investment = PHPExcel_Calculation_Functions::flattenSingleValue($investment);
+ $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
+ $basis = PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) {
+ $investment = (float) $investment;
+ $redemption = (float) $redemption;
+ $basis = (int) $basis;
+ if (($investment <= 0) || ($redemption <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+
+ return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * IPMT
+ *
+ * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
+ *
+ * Excel Function:
+ * IPMT(rate,per,nper,pv[,fv][,type])
+ *
+ * @param float $rate Interest rate per period
+ * @param int $per Period for which we want to find the interest
+ * @param int $nper Number of periods
+ * @param float $pv Present Value
+ * @param float $fv Future Value
+ * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
+ * @return float
+ */
+ public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $per = (int) PHPExcel_Calculation_Functions::flattenSingleValue($per);
+ $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
+ $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($per <= 0 || $per > $nper) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Calculate
+ $interestAndPrincipal = self::interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
+ return $interestAndPrincipal[0];
+ }
+
+ /**
+ * IRR
+ *
+ * Returns the internal rate of return for a series of cash flows represented by the numbers in values.
+ * These cash flows do not have to be even, as they would be for an annuity. However, the cash flows must occur
+ * at regular intervals, such as monthly or annually. The internal rate of return is the interest rate received
+ * for an investment consisting of payments (negative values) and income (positive values) that occur at regular
+ * periods.
+ *
+ * Excel Function:
+ * IRR(values[,guess])
+ *
+ * @param float[] $values An array or a reference to cells that contain numbers for which you want
+ * to calculate the internal rate of return.
+ * Values must contain at least one positive value and one negative value to
+ * calculate the internal rate of return.
+ * @param float $guess A number that you guess is close to the result of IRR
+ * @return float
+ */
+ public static function IRR($values, $guess = 0.1)
+ {
+ if (!is_array($values)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $values = PHPExcel_Calculation_Functions::flattenArray($values);
+ $guess = PHPExcel_Calculation_Functions::flattenSingleValue($guess);
+
+ // create an initial range, with a root somewhere between 0 and guess
+ $x1 = 0.0;
+ $x2 = $guess;
+ $f1 = self::NPV($x1, $values);
+ $f2 = self::NPV($x2, $values);
+ for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
+ if (($f1 * $f2) < 0.0) {
+ break;
+ }
+ if (abs($f1) < abs($f2)) {
+ $f1 = self::NPV($x1 += 1.6 * ($x1 - $x2), $values);
+ } else {
+ $f2 = self::NPV($x2 += 1.6 * ($x2 - $x1), $values);
+ }
+ }
+ if (($f1 * $f2) > 0.0) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ $f = self::NPV($x1, $values);
+ if ($f < 0.0) {
+ $rtb = $x1;
+ $dx = $x2 - $x1;
+ } else {
+ $rtb = $x2;
+ $dx = $x1 - $x2;
+ }
+
+ for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
+ $dx *= 0.5;
+ $x_mid = $rtb + $dx;
+ $f_mid = self::NPV($x_mid, $values);
+ if ($f_mid <= 0.0) {
+ $rtb = $x_mid;
+ }
+ if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) {
+ return $x_mid;
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * ISPMT
+ *
+ * Returns the interest payment for an investment based on an interest rate and a constant payment schedule.
+ *
+ * Excel Function:
+ * =ISPMT(interest_rate, period, number_payments, PV)
+ *
+ * interest_rate is the interest rate for the investment
+ *
+ * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments.
+ *
+ * number_payments is the number of payments for the annuity
+ *
+ * PV is the loan amount or present value of the payments
+ */
+ public static function ISPMT()
+ {
+ // Return value
+ $returnValue = 0;
+
+ // Get the parameters
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ $interestRate = array_shift($aArgs);
+ $period = array_shift($aArgs);
+ $numberPeriods = array_shift($aArgs);
+ $principleRemaining = array_shift($aArgs);
+
+ // Calculate
+ $principlePayment = ($principleRemaining * 1.0) / ($numberPeriods * 1.0);
+ for ($i=0; $i <= $period; ++$i) {
+ $returnValue = $interestRate * $principleRemaining * -1;
+ $principleRemaining -= $principlePayment;
+ // principle needs to be 0 after the last payment, don't let floating point screw it up
+ if ($i == $numberPeriods) {
+ $returnValue = 0;
+ }
+ }
+ return($returnValue);
+ }
+
+
+ /**
+ * MIRR
+ *
+ * Returns the modified internal rate of return for a series of periodic cash flows. MIRR considers both
+ * the cost of the investment and the interest received on reinvestment of cash.
+ *
+ * Excel Function:
+ * MIRR(values,finance_rate, reinvestment_rate)
+ *
+ * @param float[] $values An array or a reference to cells that contain a series of payments and
+ * income occurring at regular intervals.
+ * Payments are negative value, income is positive values.
+ * @param float $finance_rate The interest rate you pay on the money used in the cash flows
+ * @param float $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them
+ * @return float
+ */
+ public static function MIRR($values, $finance_rate, $reinvestment_rate)
+ {
+ if (!is_array($values)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $values = PHPExcel_Calculation_Functions::flattenArray($values);
+ $finance_rate = PHPExcel_Calculation_Functions::flattenSingleValue($finance_rate);
+ $reinvestment_rate = PHPExcel_Calculation_Functions::flattenSingleValue($reinvestment_rate);
+ $n = count($values);
+
+ $rr = 1.0 + $reinvestment_rate;
+ $fr = 1.0 + $finance_rate;
+
+ $npv_pos = $npv_neg = 0.0;
+ foreach ($values as $i => $v) {
+ if ($v >= 0) {
+ $npv_pos += $v / pow($rr, $i);
+ } else {
+ $npv_neg += $v / pow($fr, $i);
+ }
+ }
+
+ if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvestment_rate <= -1)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ $mirr = pow((-$npv_pos * pow($rr, $n))
+ / ($npv_neg * ($rr)), (1.0 / ($n - 1))) - 1.0;
+
+ return (is_finite($mirr) ? $mirr : PHPExcel_Calculation_Functions::VALUE());
+ }
+
+
+ /**
+ * NOMINAL
+ *
+ * Returns the nominal interest rate given the effective rate and the number of compounding payments per year.
+ *
+ * @param float $effect_rate Effective interest rate
+ * @param int $npery Number of compounding payments per year
+ * @return float
+ */
+ public static function NOMINAL($effect_rate = 0, $npery = 0)
+ {
+ $effect_rate = PHPExcel_Calculation_Functions::flattenSingleValue($effect_rate);
+ $npery = (int)PHPExcel_Calculation_Functions::flattenSingleValue($npery);
+
+ // Validate parameters
+ if ($effect_rate <= 0 || $npery < 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Calculate
+ return $npery * (pow($effect_rate + 1, 1 / $npery) - 1);
+ }
+
+
+ /**
+ * NPER
+ *
+ * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate.
+ *
+ * @param float $rate Interest rate per period
+ * @param int $pmt Periodic payment (annuity)
+ * @param float $pv Present Value
+ * @param float $fv Future Value
+ * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
+ * @return float
+ */
+ public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
+ $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Calculate
+ if (!is_null($rate) && $rate != 0) {
+ if ($pmt == 0 && $pv == 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate);
+ }
+ if ($pmt == 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return (-$pv -$fv) / $pmt;
+ }
+
+ /**
+ * NPV
+ *
+ * Returns the Net Present Value of a cash flow series given a discount rate.
+ *
+ * @return float
+ */
+ public static function NPV()
+ {
+ // Return value
+ $returnValue = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $rate = array_shift($aArgs);
+ for ($i = 1; $i <= count($aArgs); ++$i) {
+ // Is it a numeric value?
+ if (is_numeric($aArgs[$i - 1])) {
+ $returnValue += $aArgs[$i - 1] / pow(1 + $rate, $i);
+ }
+ }
+
+ // Return
+ return $returnValue;
+ }
+
+ /**
+ * PMT
+ *
+ * Returns the constant payment (annuity) for a cash flow with a constant interest rate.
+ *
+ * @param float $rate Interest rate per period
+ * @param int $nper Number of periods
+ * @param float $pv Present Value
+ * @param float $fv Future Value
+ * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
+ * @return float
+ */
+ public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
+ $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Calculate
+ if (!is_null($rate) && $rate != 0) {
+ return (-$fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate);
+ }
+ return (-$pv - $fv) / $nper;
+ }
+
+
+ /**
+ * PPMT
+ *
+ * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate.
+ *
+ * @param float $rate Interest rate per period
+ * @param int $per Period for which we want to find the interest
+ * @param int $nper Number of periods
+ * @param float $pv Present Value
+ * @param float $fv Future Value
+ * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
+ * @return float
+ */
+ public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $per = (int) PHPExcel_Calculation_Functions::flattenSingleValue($per);
+ $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
+ $type = (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($per <= 0 || $per > $nper) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Calculate
+ $interestAndPrincipal = self::interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
+ return $interestAndPrincipal[1];
+ }
+
+
+ public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $rate = (float) PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $yield = (float) PHPExcel_Calculation_Functions::flattenSingleValue($yield);
+ $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
+ $frequency = (int) PHPExcel_Calculation_Functions::flattenSingleValue($frequency);
+ $basis = (is_null($basis)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ if (is_string($settlement = PHPExcel_Calculation_DateTime::getDateValue($settlement))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (($settlement > $maturity) ||
+ (!self::isValidFrequency($frequency)) ||
+ (($basis < 0) || ($basis > 4))) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $dsc = self::COUPDAYSNC($settlement, $maturity, $frequency, $basis);
+ $e = self::COUPDAYS($settlement, $maturity, $frequency, $basis);
+ $n = self::COUPNUM($settlement, $maturity, $frequency, $basis);
+ $a = self::COUPDAYBS($settlement, $maturity, $frequency, $basis);
+
+ $baseYF = 1.0 + ($yield / $frequency);
+ $rfp = 100 * ($rate / $frequency);
+ $de = $dsc / $e;
+
+ $result = $redemption / pow($baseYF, (--$n + $de));
+ for ($k = 0; $k <= $n; ++$k) {
+ $result += $rfp / (pow($baseYF, ($k + $de)));
+ }
+ $result -= $rfp * ($a / $e);
+
+ return $result;
+ }
+
+
+ /**
+ * PRICEDISC
+ *
+ * Returns the price per $100 face value of a discounted security.
+ *
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param int discount The security's discount rate.
+ * @param int redemption The security's redemption value per $100 face value.
+ * @param int basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $discount = (float) PHPExcel_Calculation_Functions::flattenSingleValue($discount);
+ $redemption = (float) PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
+ $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) {
+ if (($discount <= 0) || ($redemption <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+
+ return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * PRICEMAT
+ *
+ * Returns the price per $100 face value of a security that pays interest at maturity.
+ *
+ * @param mixed settlement The security's settlement date.
+ * The security's settlement date is the date after the issue date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed issue The security's issue date.
+ * @param int rate The security's interest rate at date of issue.
+ * @param int yield The security's annual yield.
+ * @param int basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $yield = PHPExcel_Calculation_Functions::flattenSingleValue($yield);
+ $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if (is_numeric($rate) && is_numeric($yield)) {
+ if (($rate <= 0) || ($yield <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysPerYear = self::daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement), $basis);
+ if (!is_numeric($daysPerYear)) {
+ return $daysPerYear;
+ }
+ $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
+ if (!is_numeric($daysBetweenIssueAndSettlement)) {
+ // return date error
+ return $daysBetweenIssueAndSettlement;
+ }
+ $daysBetweenIssueAndSettlement *= $daysPerYear;
+ $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $maturity, $basis);
+ if (!is_numeric($daysBetweenIssueAndMaturity)) {
+ // return date error
+ return $daysBetweenIssueAndMaturity;
+ }
+ $daysBetweenIssueAndMaturity *= $daysPerYear;
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+ $daysBetweenSettlementAndMaturity *= $daysPerYear;
+
+ return ((100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) /
+ (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) -
+ (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * PV
+ *
+ * Returns the Present Value of a cash flow with constant payments and interest rate (annuities).
+ *
+ * @param float $rate Interest rate per period
+ * @param int $nper Number of periods
+ * @param float $pmt Periodic payment (annuity)
+ * @param float $fv Future Value
+ * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period
+ * @return float
+ */
+ public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $nper = PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
+ $fv = PHPExcel_Calculation_Functions::flattenSingleValue($fv);
+ $type = PHPExcel_Calculation_Functions::flattenSingleValue($type);
+
+ // Validate parameters
+ if ($type != 0 && $type != 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // Calculate
+ if (!is_null($rate) && $rate != 0) {
+ return (-$pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper);
+ }
+ return -$fv - $pmt * $nper;
+ }
+
+
+ /**
+ * RATE
+ *
+ * Returns the interest rate per period of an annuity.
+ * RATE is calculated by iteration and can have zero or more solutions.
+ * If the successive results of RATE do not converge to within 0.0000001 after 20 iterations,
+ * RATE returns the #NUM! error value.
+ *
+ * Excel Function:
+ * RATE(nper,pmt,pv[,fv[,type[,guess]]])
+ *
+ * @access public
+ * @category Financial Functions
+ * @param float nper The total number of payment periods in an annuity.
+ * @param float pmt The payment made each period and cannot change over the life
+ * of the annuity.
+ * Typically, pmt includes principal and interest but no other
+ * fees or taxes.
+ * @param float pv The present value - the total amount that a series of future
+ * payments is worth now.
+ * @param float fv The future value, or a cash balance you want to attain after
+ * the last payment is made. If fv is omitted, it is assumed
+ * to be 0 (the future value of a loan, for example, is 0).
+ * @param integer type A number 0 or 1 and indicates when payments are due:
+ * 0 or omitted At the end of the period.
+ * 1 At the beginning of the period.
+ * @param float guess Your guess for what the rate will be.
+ * If you omit guess, it is assumed to be 10 percent.
+ * @return float
+ **/
+ public static function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1)
+ {
+ $nper = (int) PHPExcel_Calculation_Functions::flattenSingleValue($nper);
+ $pmt = PHPExcel_Calculation_Functions::flattenSingleValue($pmt);
+ $pv = PHPExcel_Calculation_Functions::flattenSingleValue($pv);
+ $fv = (is_null($fv)) ? 0.0 : PHPExcel_Calculation_Functions::flattenSingleValue($fv);
+ $type = (is_null($type)) ? 0 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($type);
+ $guess = (is_null($guess)) ? 0.1 : PHPExcel_Calculation_Functions::flattenSingleValue($guess);
+
+ $rate = $guess;
+ if (abs($rate) < FINANCIAL_PRECISION) {
+ $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
+ } else {
+ $f = exp($nper * log(1 + $rate));
+ $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
+ }
+ $y0 = $pv + $pmt * $nper + $fv;
+ $y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
+
+ // find root by secant method
+ $i = $x0 = 0.0;
+ $x1 = $rate;
+ while ((abs($y0 - $y1) > FINANCIAL_PRECISION) && ($i < FINANCIAL_MAX_ITERATIONS)) {
+ $rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
+ $x0 = $x1;
+ $x1 = $rate;
+ if (($nper * abs($pmt)) > ($pv - $fv)) {
+ $x1 = abs($x1);
+ }
+ if (abs($rate) < FINANCIAL_PRECISION) {
+ $y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
+ } else {
+ $f = exp($nper * log(1 + $rate));
+ $y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
+ }
+
+ $y0 = $y1;
+ $y1 = $y;
+ ++$i;
+ }
+ return $rate;
+ }
+
+
+ /**
+ * RECEIVED
+ *
+ * Returns the price per $100 face value of a discounted security.
+ *
+ * @param mixed settlement The security's settlement date.
+ * The security settlement date is the date after the issue date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param int investment The amount invested in the security.
+ * @param int discount The security's discount rate.
+ * @param int basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $investment = (float) PHPExcel_Calculation_Functions::flattenSingleValue($investment);
+ $discount = (float) PHPExcel_Calculation_Functions::flattenSingleValue($discount);
+ $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) {
+ if (($investment <= 0) || ($discount <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+
+ return $investment / ( 1 - ($discount * $daysBetweenSettlementAndMaturity));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SLN
+ *
+ * Returns the straight-line depreciation of an asset for one period
+ *
+ * @param cost Initial cost of the asset
+ * @param salvage Value at the end of the depreciation
+ * @param life Number of periods over which the asset is depreciated
+ * @return float
+ */
+ public static function SLN($cost, $salvage, $life)
+ {
+ $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
+ $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
+ $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
+
+ // Calculate
+ if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) {
+ if ($life < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return ($cost - $salvage) / $life;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SYD
+ *
+ * Returns the sum-of-years' digits depreciation of an asset for a specified period.
+ *
+ * @param cost Initial cost of the asset
+ * @param salvage Value at the end of the depreciation
+ * @param life Number of periods over which the asset is depreciated
+ * @param period Period
+ * @return float
+ */
+ public static function SYD($cost, $salvage, $life, $period)
+ {
+ $cost = PHPExcel_Calculation_Functions::flattenSingleValue($cost);
+ $salvage = PHPExcel_Calculation_Functions::flattenSingleValue($salvage);
+ $life = PHPExcel_Calculation_Functions::flattenSingleValue($life);
+ $period = PHPExcel_Calculation_Functions::flattenSingleValue($period);
+
+ // Calculate
+ if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) {
+ if (($life < 1) || ($period > $life)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * TBILLEQ
+ *
+ * Returns the bond-equivalent yield for a Treasury bill.
+ *
+ * @param mixed settlement The Treasury bill's settlement date.
+ * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
+ * @param mixed maturity The Treasury bill's maturity date.
+ * The maturity date is the date when the Treasury bill expires.
+ * @param int discount The Treasury bill's discount rate.
+ * @return float
+ */
+ public static function TBILLEQ($settlement, $maturity, $discount)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $discount = PHPExcel_Calculation_Functions::flattenSingleValue($discount);
+
+ // Use TBILLPRICE for validation
+ $testValue = self::TBILLPRICE($settlement, $maturity, $discount);
+ if (is_string($testValue)) {
+ return $testValue;
+ }
+
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ ++$maturity;
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360;
+ } else {
+ $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::getDateValue($maturity) - PHPExcel_Calculation_DateTime::getDateValue($settlement));
+ }
+
+ return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity);
+ }
+
+
+ /**
+ * TBILLPRICE
+ *
+ * Returns the yield for a Treasury bill.
+ *
+ * @param mixed settlement The Treasury bill's settlement date.
+ * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
+ * @param mixed maturity The Treasury bill's maturity date.
+ * The maturity date is the date when the Treasury bill expires.
+ * @param int discount The Treasury bill's discount rate.
+ * @return float
+ */
+ public static function TBILLPRICE($settlement, $maturity, $discount)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $discount = PHPExcel_Calculation_Functions::flattenSingleValue($discount);
+
+ if (is_string($maturity = PHPExcel_Calculation_DateTime::getDateValue($maturity))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // Validate
+ if (is_numeric($discount)) {
+ if ($discount <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ ++$maturity;
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360;
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+ } else {
+ $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::getDateValue($maturity) - PHPExcel_Calculation_DateTime::getDateValue($settlement));
+ }
+
+ if ($daysBetweenSettlementAndMaturity > 360) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360));
+ if ($price <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return $price;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * TBILLYIELD
+ *
+ * Returns the yield for a Treasury bill.
+ *
+ * @param mixed settlement The Treasury bill's settlement date.
+ * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer.
+ * @param mixed maturity The Treasury bill's maturity date.
+ * The maturity date is the date when the Treasury bill expires.
+ * @param int price The Treasury bill's price per $100 face value.
+ * @return float
+ */
+ public static function TBILLYIELD($settlement, $maturity, $price)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
+
+ // Validate
+ if (is_numeric($price)) {
+ if ($price <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ ++$maturity;
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity) * 360;
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+ } else {
+ $daysBetweenSettlementAndMaturity = (PHPExcel_Calculation_DateTime::getDateValue($maturity) - PHPExcel_Calculation_DateTime::getDateValue($settlement));
+ }
+
+ if ($daysBetweenSettlementAndMaturity > 360) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ public static function XIRR($values, $dates, $guess = 0.1)
+ {
+ if ((!is_array($values)) && (!is_array($dates))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $values = PHPExcel_Calculation_Functions::flattenArray($values);
+ $dates = PHPExcel_Calculation_Functions::flattenArray($dates);
+ $guess = PHPExcel_Calculation_Functions::flattenSingleValue($guess);
+ if (count($values) != count($dates)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ // create an initial range, with a root somewhere between 0 and guess
+ $x1 = 0.0;
+ $x2 = $guess;
+ $f1 = self::XNPV($x1, $values, $dates);
+ $f2 = self::XNPV($x2, $values, $dates);
+ for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
+ if (($f1 * $f2) < 0.0) {
+ break;
+ } elseif (abs($f1) < abs($f2)) {
+ $f1 = self::XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates);
+ } else {
+ $f2 = self::XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates);
+ }
+ }
+ if (($f1 * $f2) > 0.0) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ $f = self::XNPV($x1, $values, $dates);
+ if ($f < 0.0) {
+ $rtb = $x1;
+ $dx = $x2 - $x1;
+ } else {
+ $rtb = $x2;
+ $dx = $x1 - $x2;
+ }
+
+ for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
+ $dx *= 0.5;
+ $x_mid = $rtb + $dx;
+ $f_mid = self::XNPV($x_mid, $values, $dates);
+ if ($f_mid <= 0.0) {
+ $rtb = $x_mid;
+ }
+ if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) {
+ return $x_mid;
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * XNPV
+ *
+ * Returns the net present value for a schedule of cash flows that is not necessarily periodic.
+ * To calculate the net present value for a series of cash flows that is periodic, use the NPV function.
+ *
+ * Excel Function:
+ * =XNPV(rate,values,dates)
+ *
+ * @param float $rate The discount rate to apply to the cash flows.
+ * @param array of float $values A series of cash flows that corresponds to a schedule of payments in dates.
+ * The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment.
+ * If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year.
+ * The series of values must contain at least one positive value and one negative value.
+ * @param array of mixed $dates A schedule of payment dates that corresponds to the cash flow payments.
+ * The first payment date indicates the beginning of the schedule of payments.
+ * All other dates must be later than this date, but they may occur in any order.
+ * @return float
+ */
+ public static function XNPV($rate, $values, $dates)
+ {
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ if (!is_numeric($rate)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if ((!is_array($values)) || (!is_array($dates))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $values = PHPExcel_Calculation_Functions::flattenArray($values);
+ $dates = PHPExcel_Calculation_Functions::flattenArray($dates);
+ $valCount = count($values);
+ if ($valCount != count($dates)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((min($values) > 0) || (max($values) < 0)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ $xnpv = 0.0;
+ for ($i = 0; $i < $valCount; ++$i) {
+ if (!is_numeric($values[$i])) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $xnpv += $values[$i] / pow(1 + $rate, PHPExcel_Calculation_DateTime::DATEDIF($dates[0], $dates[$i], 'd') / 365);
+ }
+ return (is_finite($xnpv)) ? $xnpv : PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * YIELDDISC
+ *
+ * Returns the annual yield of a security that pays interest at maturity.
+ *
+ * @param mixed settlement The security's settlement date.
+ * The security's settlement date is the date after the issue date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param int price The security's price per $100 face value.
+ * @param int redemption The security's redemption value per $100 face value.
+ * @param int basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
+ $redemption = PHPExcel_Calculation_Functions::flattenSingleValue($redemption);
+ $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if (is_numeric($price) && is_numeric($redemption)) {
+ if (($price <= 0) || ($redemption <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysPerYear = self::daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement), $basis);
+ if (!is_numeric($daysPerYear)) {
+ return $daysPerYear;
+ }
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+ $daysBetweenSettlementAndMaturity *= $daysPerYear;
+
+ return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * YIELDMAT
+ *
+ * Returns the annual yield of a security that pays interest at maturity.
+ *
+ * @param mixed settlement The security's settlement date.
+ * The security's settlement date is the date after the issue date when the security is traded to the buyer.
+ * @param mixed maturity The security's maturity date.
+ * The maturity date is the date when the security expires.
+ * @param mixed issue The security's issue date.
+ * @param int rate The security's interest rate at date of issue.
+ * @param int price The security's price per $100 face value.
+ * @param int basis The type of day count to use.
+ * 0 or omitted US (NASD) 30/360
+ * 1 Actual/actual
+ * 2 Actual/360
+ * 3 Actual/365
+ * 4 European 30/360
+ * @return float
+ */
+ public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis = 0)
+ {
+ $settlement = PHPExcel_Calculation_Functions::flattenSingleValue($settlement);
+ $maturity = PHPExcel_Calculation_Functions::flattenSingleValue($maturity);
+ $issue = PHPExcel_Calculation_Functions::flattenSingleValue($issue);
+ $rate = PHPExcel_Calculation_Functions::flattenSingleValue($rate);
+ $price = PHPExcel_Calculation_Functions::flattenSingleValue($price);
+ $basis = (int) PHPExcel_Calculation_Functions::flattenSingleValue($basis);
+
+ // Validate
+ if (is_numeric($rate) && is_numeric($price)) {
+ if (($rate <= 0) || ($price <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $daysPerYear = self::daysPerYear(PHPExcel_Calculation_DateTime::YEAR($settlement), $basis);
+ if (!is_numeric($daysPerYear)) {
+ return $daysPerYear;
+ }
+ $daysBetweenIssueAndSettlement = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $settlement, $basis);
+ if (!is_numeric($daysBetweenIssueAndSettlement)) {
+ // return date error
+ return $daysBetweenIssueAndSettlement;
+ }
+ $daysBetweenIssueAndSettlement *= $daysPerYear;
+ $daysBetweenIssueAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($issue, $maturity, $basis);
+ if (!is_numeric($daysBetweenIssueAndMaturity)) {
+ // return date error
+ return $daysBetweenIssueAndMaturity;
+ }
+ $daysBetweenIssueAndMaturity *= $daysPerYear;
+ $daysBetweenSettlementAndMaturity = PHPExcel_Calculation_DateTime::YEARFRAC($settlement, $maturity, $basis);
+ if (!is_numeric($daysBetweenSettlementAndMaturity)) {
+ // return date error
+ return $daysBetweenSettlementAndMaturity;
+ }
+ $daysBetweenSettlementAndMaturity *= $daysPerYear;
+
+ return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) /
+ (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) *
+ ($daysPerYear / $daysBetweenSettlementAndMaturity);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/FormulaParser.php b/extend/PHPExcel/PHPExcel/Calculation/FormulaParser.php
new file mode 100755
index 0000000..893f19e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/FormulaParser.php
@@ -0,0 +1,622 @@
+<";
+ const OPERATORS_POSTFIX = "%";
+
+ /**
+ * Formula
+ *
+ * @var string
+ */
+ private $formula;
+
+ /**
+ * Tokens
+ *
+ * @var PHPExcel_Calculation_FormulaToken[]
+ */
+ private $tokens = array();
+
+ /**
+ * Create a new PHPExcel_Calculation_FormulaParser
+ *
+ * @param string $pFormula Formula to parse
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function __construct($pFormula = '')
+ {
+ // Check parameters
+ if (is_null($pFormula)) {
+ throw new PHPExcel_Calculation_Exception("Invalid parameter passed: formula");
+ }
+
+ // Initialise values
+ $this->formula = trim($pFormula);
+ // Parse!
+ $this->parseToTokens();
+ }
+
+ /**
+ * Get Formula
+ *
+ * @return string
+ */
+ public function getFormula()
+ {
+ return $this->formula;
+ }
+
+ /**
+ * Get Token
+ *
+ * @param int $pId Token id
+ * @return string
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function getToken($pId = 0)
+ {
+ if (isset($this->tokens[$pId])) {
+ return $this->tokens[$pId];
+ } else {
+ throw new PHPExcel_Calculation_Exception("Token with id $pId does not exist.");
+ }
+ }
+
+ /**
+ * Get Token count
+ *
+ * @return string
+ */
+ public function getTokenCount()
+ {
+ return count($this->tokens);
+ }
+
+ /**
+ * Get Tokens
+ *
+ * @return PHPExcel_Calculation_FormulaToken[]
+ */
+ public function getTokens()
+ {
+ return $this->tokens;
+ }
+
+ /**
+ * Parse to tokens
+ */
+ private function parseToTokens()
+ {
+ // No attempt is made to verify formulas; assumes formulas are derived from Excel, where
+ // they can only exist if valid; stack overflows/underflows sunk as nulls without exceptions.
+
+ // Check if the formula has a valid starting =
+ $formulaLength = strlen($this->formula);
+ if ($formulaLength < 2 || $this->formula{0} != '=') {
+ return;
+ }
+
+ // Helper variables
+ $tokens1 = $tokens2 = $stack = array();
+ $inString = $inPath = $inRange = $inError = false;
+ $token = $previousToken = $nextToken = null;
+
+ $index = 1;
+ $value = '';
+
+ $ERRORS = array("#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A");
+ $COMPARATORS_MULTI = array(">=", "<=", "<>");
+
+ while ($index < $formulaLength) {
+ // state-dependent character evaluation (order is important)
+
+ // double-quoted strings
+ // embeds are doubled
+ // end marks token
+ if ($inString) {
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) {
+ if ((($index + 2) <= $formulaLength) && ($this->formula{$index + 1} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE)) {
+ $value .= PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE;
+ ++$index;
+ } else {
+ $inString = false;
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_TEXT);
+ $value = "";
+ }
+ } else {
+ $value .= $this->formula{$index};
+ }
+ ++$index;
+ continue;
+ }
+
+ // single-quoted strings (links)
+ // embeds are double
+ // end does not mark a token
+ if ($inPath) {
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) {
+ if ((($index + 2) <= $formulaLength) && ($this->formula{$index + 1} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE)) {
+ $value .= PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE;
+ ++$index;
+ } else {
+ $inPath = false;
+ }
+ } else {
+ $value .= $this->formula{$index};
+ }
+ ++$index;
+ continue;
+ }
+
+ // bracked strings (R1C1 range index or linked workbook name)
+ // no embeds (changed to "()" by Excel)
+ // end does not mark a token
+ if ($inRange) {
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACKET_CLOSE) {
+ $inRange = false;
+ }
+ $value .= $this->formula{$index};
+ ++$index;
+ continue;
+ }
+
+ // error values
+ // end marks a token, determined from absolute list of values
+ if ($inError) {
+ $value .= $this->formula{$index};
+ ++$index;
+ if (in_array($value, $ERRORS)) {
+ $inError = false;
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_ERROR);
+ $value = "";
+ }
+ continue;
+ }
+
+ // scientific notation check
+ if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_SN, $this->formula{$index}) !== false) {
+ if (strlen($value) > 1) {
+ if (preg_match("/^[1-9]{1}(\.[0-9]+)?E{1}$/", $this->formula{$index}) != 0) {
+ $value .= $this->formula{$index};
+ ++$index;
+ continue;
+ }
+ }
+ }
+
+ // independent character evaluation (order not important)
+
+ // establish state-dependent character evaluations
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) {
+ if (strlen($value > 0)) {
+ // unexpected
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+ $value = "";
+ }
+ $inString = true;
+ ++$index;
+ continue;
+ }
+
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) {
+ if (strlen($value) > 0) {
+ // unexpected
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+ $value = "";
+ }
+ $inPath = true;
+ ++$index;
+ continue;
+ }
+
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACKET_OPEN) {
+ $inRange = true;
+ $value .= PHPExcel_Calculation_FormulaParser::BRACKET_OPEN;
+ ++$index;
+ continue;
+ }
+
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::ERROR_START) {
+ if (strlen($value) > 0) {
+ // unexpected
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+ $value = "";
+ }
+ $inError = true;
+ $value .= PHPExcel_Calculation_FormulaParser::ERROR_START;
+ ++$index;
+ continue;
+ }
+
+ // mark start and end of arrays and array rows
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACE_OPEN) {
+ if (strlen($value) > 0) {
+ // unexpected
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN);
+ $value = "";
+ }
+
+ $tmp = new PHPExcel_Calculation_FormulaToken("ARRAY", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+ $tokens1[] = $tmp;
+ $stack[] = clone $tmp;
+
+ $tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+ $tokens1[] = $tmp;
+ $stack[] = clone $tmp;
+
+ ++$index;
+ continue;
+ }
+
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::SEMICOLON) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+
+ $tmp = array_pop($stack);
+ $tmp->setValue("");
+ $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+ $tokens1[] = $tmp;
+
+ $tmp = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT);
+ $tokens1[] = $tmp;
+
+ $tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+ $tokens1[] = $tmp;
+ $stack[] = clone $tmp;
+
+ ++$index;
+ continue;
+ }
+
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACE_CLOSE) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+
+ $tmp = array_pop($stack);
+ $tmp->setValue("");
+ $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+ $tokens1[] = $tmp;
+
+ $tmp = array_pop($stack);
+ $tmp->setValue("");
+ $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+ $tokens1[] = $tmp;
+
+ ++$index;
+ continue;
+ }
+
+ // trim white-space
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::WHITESPACE) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE);
+ ++$index;
+ while (($this->formula{$index} == PHPExcel_Calculation_FormulaParser::WHITESPACE) && ($index < $formulaLength)) {
+ ++$index;
+ }
+ continue;
+ }
+
+ // multi-character comparators
+ if (($index + 2) <= $formulaLength) {
+ if (in_array(substr($this->formula, $index, 2), $COMPARATORS_MULTI)) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken(substr($this->formula, $index, 2), PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL);
+ $index += 2;
+ continue;
+ }
+ }
+
+ // standard infix operators
+ if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_INFIX, $this->formula{$index}) !== false) {
+ if (strlen($value) > 0) {
+ $tokens1[] =new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula{$index}, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX);
+ ++$index;
+ continue;
+ }
+
+ // standard postfix operators (only one)
+ if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_POSTFIX, $this->formula{$index}) !== false) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula{$index}, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX);
+ ++$index;
+ continue;
+ }
+
+ // start subexpression or function
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::PAREN_OPEN) {
+ if (strlen($value) > 0) {
+ $tmp = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+ $tokens1[] = $tmp;
+ $stack[] = clone $tmp;
+ $value = "";
+ } else {
+ $tmp = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START);
+ $tokens1[] = $tmp;
+ $stack[] = clone $tmp;
+ }
+ ++$index;
+ continue;
+ }
+
+ // function, subexpression, or array parameters, or operand unions
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::COMMA) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+
+ $tmp = array_pop($stack);
+ $tmp->setValue("");
+ $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+ $stack[] = $tmp;
+
+ if ($tmp->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_UNION);
+ } else {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT);
+ }
+ ++$index;
+ continue;
+ }
+
+ // stop subexpression
+ if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::PAREN_CLOSE) {
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ $value = "";
+ }
+
+ $tmp = array_pop($stack);
+ $tmp->setValue("");
+ $tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP);
+ $tokens1[] = $tmp;
+
+ ++$index;
+ continue;
+ }
+
+ // token accumulation
+ $value .= $this->formula{$index};
+ ++$index;
+ }
+
+ // dump remaining accumulation
+ if (strlen($value) > 0) {
+ $tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND);
+ }
+
+ // move tokenList to new set, excluding unnecessary white-space tokens and converting necessary ones to intersections
+ $tokenCount = count($tokens1);
+ for ($i = 0; $i < $tokenCount; ++$i) {
+ $token = $tokens1[$i];
+ if (isset($tokens1[$i - 1])) {
+ $previousToken = $tokens1[$i - 1];
+ } else {
+ $previousToken = null;
+ }
+ if (isset($tokens1[$i + 1])) {
+ $nextToken = $tokens1[$i + 1];
+ } else {
+ $nextToken = null;
+ }
+
+ if (is_null($token)) {
+ continue;
+ }
+
+ if ($token->getTokenType() != PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE) {
+ $tokens2[] = $token;
+ continue;
+ }
+
+ if (is_null($previousToken)) {
+ continue;
+ }
+
+ if (! (
+ (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+ (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+ ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)
+ ) ) {
+ continue;
+ }
+
+ if (is_null($nextToken)) {
+ continue;
+ }
+
+ if (! (
+ (($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) ||
+ (($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) ||
+ ($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)
+ ) ) {
+ continue;
+ }
+
+ $tokens2[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_INTERSECTION);
+ }
+
+ // move tokens to final list, switching infix "-" operators to prefix when appropriate, switching infix "+" operators
+ // to noop when appropriate, identifying operand and infix-operator subtypes, and pulling "@" from function names
+ $this->tokens = array();
+
+ $tokenCount = count($tokens2);
+ for ($i = 0; $i < $tokenCount; ++$i) {
+ $token = $tokens2[$i];
+ if (isset($tokens2[$i - 1])) {
+ $previousToken = $tokens2[$i - 1];
+ } else {
+ $previousToken = null;
+ }
+ if (isset($tokens2[$i + 1])) {
+ $nextToken = $tokens2[$i + 1];
+ } else {
+ $nextToken = null;
+ }
+
+ if (is_null($token)) {
+ continue;
+ }
+
+ if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "-") {
+ if ($i == 0) {
+ $token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX);
+ } elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) &&
+ ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+ (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) &&
+ ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+ ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) ||
+ ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH);
+ } else {
+ $token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX);
+ }
+
+ $this->tokens[] = $token;
+ continue;
+ }
+
+ if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "+") {
+ if ($i == 0) {
+ continue;
+ } elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) &&
+ ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+ (($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) &&
+ ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) ||
+ ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) ||
+ ($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH);
+ } else {
+ continue;
+ }
+
+ $this->tokens[] = $token;
+ continue;
+ }
+
+ if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX &&
+ $token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) {
+ if (strpos("<>=", substr($token->getValue(), 0, 1)) !== false) {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL);
+ } elseif ($token->getValue() == "&") {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_CONCATENATION);
+ } else {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH);
+ }
+
+ $this->tokens[] = $token;
+ continue;
+ }
+
+ if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND &&
+ $token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) {
+ if (!is_numeric($token->getValue())) {
+ if (strtoupper($token->getValue()) == "TRUE" || strtoupper($token->getValue() == "FALSE")) {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL);
+ } else {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_RANGE);
+ }
+ } else {
+ $token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NUMBER);
+ }
+
+ $this->tokens[] = $token;
+ continue;
+ }
+
+ if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) {
+ if (strlen($token->getValue() > 0)) {
+ if (substr($token->getValue(), 0, 1) == "@") {
+ $token->setValue(substr($token->getValue(), 1));
+ }
+ }
+ }
+
+ $this->tokens[] = $token;
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/FormulaToken.php b/extend/PHPExcel/PHPExcel/Calculation/FormulaToken.php
new file mode 100755
index 0000000..41c6e3d
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/FormulaToken.php
@@ -0,0 +1,176 @@
+value = $pValue;
+ $this->tokenType = $pTokenType;
+ $this->tokenSubType = $pTokenSubType;
+ }
+
+ /**
+ * Get Value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Set Value
+ *
+ * @param string $value
+ */
+ public function setValue($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Get Token Type (represented by TOKEN_TYPE_*)
+ *
+ * @return string
+ */
+ public function getTokenType()
+ {
+ return $this->tokenType;
+ }
+
+ /**
+ * Set Token Type
+ *
+ * @param string $value
+ */
+ public function setTokenType($value = PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN)
+ {
+ $this->tokenType = $value;
+ }
+
+ /**
+ * Get Token SubType (represented by TOKEN_SUBTYPE_*)
+ *
+ * @return string
+ */
+ public function getTokenSubType()
+ {
+ return $this->tokenSubType;
+ }
+
+ /**
+ * Set Token SubType
+ *
+ * @param string $value
+ */
+ public function setTokenSubType($value = PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING)
+ {
+ $this->tokenSubType = $value;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Function.php b/extend/PHPExcel/PHPExcel/Calculation/Function.php
new file mode 100755
index 0000000..d58cef2
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Function.php
@@ -0,0 +1,148 @@
+category = $pCategory;
+ $this->excelName = $pExcelName;
+ $this->phpExcelName = $pPHPExcelName;
+ } else {
+ throw new PHPExcel_Calculation_Exception("Invalid parameters passed.");
+ }
+ }
+
+ /**
+ * Get Category (represented by CATEGORY_*)
+ *
+ * @return string
+ */
+ public function getCategory()
+ {
+ return $this->category;
+ }
+
+ /**
+ * Set Category (represented by CATEGORY_*)
+ *
+ * @param string $value
+ * @throws PHPExcel_Calculation_Exception
+ */
+ public function setCategory($value = null)
+ {
+ if (!is_null($value)) {
+ $this->category = $value;
+ } else {
+ throw new PHPExcel_Calculation_Exception("Invalid parameter passed.");
+ }
+ }
+
+ /**
+ * Get Excel name
+ *
+ * @return string
+ */
+ public function getExcelName()
+ {
+ return $this->excelName;
+ }
+
+ /**
+ * Set Excel name
+ *
+ * @param string $value
+ */
+ public function setExcelName($value)
+ {
+ $this->excelName = $value;
+ }
+
+ /**
+ * Get PHPExcel name
+ *
+ * @return string
+ */
+ public function getPHPExcelName()
+ {
+ return $this->phpExcelName;
+ }
+
+ /**
+ * Set PHPExcel name
+ *
+ * @param string $value
+ */
+ public function setPHPExcelName($value)
+ {
+ $this->phpExcelName = $value;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Functions.php b/extend/PHPExcel/PHPExcel/Calculation/Functions.php
new file mode 100755
index 0000000..5a1e5ee
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Functions.php
@@ -0,0 +1,760 @@
+ '#NULL!',
+ 'divisionbyzero' => '#DIV/0!',
+ 'value' => '#VALUE!',
+ 'reference' => '#REF!',
+ 'name' => '#NAME?',
+ 'num' => '#NUM!',
+ 'na' => '#N/A',
+ 'gettingdata' => '#GETTING_DATA'
+ );
+
+
+ /**
+ * Set the Compatibility Mode
+ *
+ * @access public
+ * @category Function Configuration
+ * @param string $compatibilityMode Compatibility Mode
+ * Permitted values are:
+ * PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel'
+ * PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
+ * PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
+ * @return boolean (Success or Failure)
+ */
+ public static function setCompatibilityMode($compatibilityMode)
+ {
+ if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
+ ($compatibilityMode == self::COMPATIBILITY_GNUMERIC) ||
+ ($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) {
+ self::$compatibilityMode = $compatibilityMode;
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Return the current Compatibility Mode
+ *
+ * @access public
+ * @category Function Configuration
+ * @return string Compatibility Mode
+ * Possible Return values are:
+ * PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel'
+ * PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric'
+ * PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc'
+ */
+ public static function getCompatibilityMode()
+ {
+ return self::$compatibilityMode;
+ }
+
+
+ /**
+ * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
+ *
+ * @access public
+ * @category Function Configuration
+ * @param string $returnDateType Return Date Format
+ * Permitted values are:
+ * PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P'
+ * PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O'
+ * PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E'
+ * @return boolean Success or failure
+ */
+ public static function setReturnDateType($returnDateType)
+ {
+ if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
+ ($returnDateType == self::RETURNDATE_PHP_OBJECT) ||
+ ($returnDateType == self::RETURNDATE_EXCEL)) {
+ self::$returnDateType = $returnDateType;
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
+ *
+ * @access public
+ * @category Function Configuration
+ * @return string Return Date Format
+ * Possible Return values are:
+ * PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P'
+ * PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O'
+ * PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E'
+ */
+ public static function getReturnDateType()
+ {
+ return self::$returnDateType;
+ }
+
+
+ /**
+ * DUMMY
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #Not Yet Implemented
+ */
+ public static function DUMMY()
+ {
+ return '#Not Yet Implemented';
+ }
+
+
+ /**
+ * DIV0
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #Not Yet Implemented
+ */
+ public static function DIV0()
+ {
+ return self::$errorCodes['divisionbyzero'];
+ }
+
+
+ /**
+ * NA
+ *
+ * Excel Function:
+ * =NA()
+ *
+ * Returns the error value #N/A
+ * #N/A is the error value that means "no value is available."
+ *
+ * @access public
+ * @category Logical Functions
+ * @return string #N/A!
+ */
+ public static function NA()
+ {
+ return self::$errorCodes['na'];
+ }
+
+
+ /**
+ * NaN
+ *
+ * Returns the error value #NUM!
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #NUM!
+ */
+ public static function NaN()
+ {
+ return self::$errorCodes['num'];
+ }
+
+
+ /**
+ * NAME
+ *
+ * Returns the error value #NAME?
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #NAME?
+ */
+ public static function NAME()
+ {
+ return self::$errorCodes['name'];
+ }
+
+
+ /**
+ * REF
+ *
+ * Returns the error value #REF!
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #REF!
+ */
+ public static function REF()
+ {
+ return self::$errorCodes['reference'];
+ }
+
+
+ /**
+ * NULL
+ *
+ * Returns the error value #NULL!
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #NULL!
+ */
+ public static function NULL()
+ {
+ return self::$errorCodes['null'];
+ }
+
+
+ /**
+ * VALUE
+ *
+ * Returns the error value #VALUE!
+ *
+ * @access public
+ * @category Error Returns
+ * @return string #VALUE!
+ */
+ public static function VALUE()
+ {
+ return self::$errorCodes['value'];
+ }
+
+
+ public static function isMatrixValue($idx)
+ {
+ return ((substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0));
+ }
+
+
+ public static function isValue($idx)
+ {
+ return (substr_count($idx, '.') == 0);
+ }
+
+
+ public static function isCellValue($idx)
+ {
+ return (substr_count($idx, '.') > 1);
+ }
+
+
+ public static function ifCondition($condition)
+ {
+ $condition = PHPExcel_Calculation_Functions::flattenSingleValue($condition);
+ if (!isset($condition{0})) {
+ $condition = '=""';
+ }
+ if (!in_array($condition{0}, array('>', '<', '='))) {
+ if (!is_numeric($condition)) {
+ $condition = PHPExcel_Calculation::wrapResult(strtoupper($condition));
+ }
+ return '=' . $condition;
+ } else {
+ preg_match('/([<>=]+)(.*)/', $condition, $matches);
+ list(, $operator, $operand) = $matches;
+
+ if (!is_numeric($operand)) {
+ $operand = str_replace('"', '""', $operand);
+ $operand = PHPExcel_Calculation::wrapResult(strtoupper($operand));
+ }
+
+ return $operator.$operand;
+ }
+ }
+
+ /**
+ * ERROR_TYPE
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function ERROR_TYPE($value = '')
+ {
+ $value = self::flattenSingleValue($value);
+
+ $i = 1;
+ foreach (self::$errorCodes as $errorCode) {
+ if ($value === $errorCode) {
+ return $i;
+ }
+ ++$i;
+ }
+ return self::NA();
+ }
+
+
+ /**
+ * IS_BLANK
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_BLANK($value = null)
+ {
+ if (!is_null($value)) {
+ $value = self::flattenSingleValue($value);
+ }
+
+ return is_null($value);
+ }
+
+
+ /**
+ * IS_ERR
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_ERR($value = '')
+ {
+ $value = self::flattenSingleValue($value);
+
+ return self::IS_ERROR($value) && (!self::IS_NA($value));
+ }
+
+
+ /**
+ * IS_ERROR
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_ERROR($value = '')
+ {
+ $value = self::flattenSingleValue($value);
+
+ if (!is_string($value)) {
+ return false;
+ }
+ return in_array($value, array_values(self::$errorCodes));
+ }
+
+
+ /**
+ * IS_NA
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_NA($value = '')
+ {
+ $value = self::flattenSingleValue($value);
+
+ return ($value === self::NA());
+ }
+
+
+ /**
+ * IS_EVEN
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_EVEN($value = null)
+ {
+ $value = self::flattenSingleValue($value);
+
+ if ($value === null) {
+ return self::NAME();
+ } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
+ return self::VALUE();
+ }
+
+ return ($value % 2 == 0);
+ }
+
+
+ /**
+ * IS_ODD
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_ODD($value = null)
+ {
+ $value = self::flattenSingleValue($value);
+
+ if ($value === null) {
+ return self::NAME();
+ } elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
+ return self::VALUE();
+ }
+
+ return (abs($value) % 2 == 1);
+ }
+
+
+ /**
+ * IS_NUMBER
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_NUMBER($value = null)
+ {
+ $value = self::flattenSingleValue($value);
+
+ if (is_string($value)) {
+ return false;
+ }
+ return is_numeric($value);
+ }
+
+
+ /**
+ * IS_LOGICAL
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_LOGICAL($value = null)
+ {
+ $value = self::flattenSingleValue($value);
+
+ return is_bool($value);
+ }
+
+
+ /**
+ * IS_TEXT
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_TEXT($value = null)
+ {
+ $value = self::flattenSingleValue($value);
+
+ return (is_string($value) && !self::IS_ERROR($value));
+ }
+
+
+ /**
+ * IS_NONTEXT
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function IS_NONTEXT($value = null)
+ {
+ return !self::IS_TEXT($value);
+ }
+
+
+ /**
+ * VERSION
+ *
+ * @return string Version information
+ */
+ public static function VERSION()
+ {
+ return 'PHPExcel ##VERSION##, ##DATE##';
+ }
+
+
+ /**
+ * N
+ *
+ * Returns a value converted to a number
+ *
+ * @param value The value you want converted
+ * @return number N converts values listed in the following table
+ * If value is or refers to N returns
+ * A number That number
+ * A date The serial number of that date
+ * TRUE 1
+ * FALSE 0
+ * An error value The error value
+ * Anything else 0
+ */
+ public static function N($value = null)
+ {
+ while (is_array($value)) {
+ $value = array_shift($value);
+ }
+
+ switch (gettype($value)) {
+ case 'double':
+ case 'float':
+ case 'integer':
+ return $value;
+ case 'boolean':
+ return (integer) $value;
+ case 'string':
+ // Errors
+ if ((strlen($value) > 0) && ($value{0} == '#')) {
+ return $value;
+ }
+ break;
+ }
+ return 0;
+ }
+
+
+ /**
+ * TYPE
+ *
+ * Returns a number that identifies the type of a value
+ *
+ * @param value The value you want tested
+ * @return number N converts values listed in the following table
+ * If value is or refers to N returns
+ * A number 1
+ * Text 2
+ * Logical Value 4
+ * An error value 16
+ * Array or Matrix 64
+ */
+ public static function TYPE($value = null)
+ {
+ $value = self::flattenArrayIndexed($value);
+ if (is_array($value) && (count($value) > 1)) {
+ end($value);
+ $a = key($value);
+ // Range of cells is an error
+ if (self::isCellValue($a)) {
+ return 16;
+ // Test for Matrix
+ } elseif (self::isMatrixValue($a)) {
+ return 64;
+ }
+ } elseif (empty($value)) {
+ // Empty Cell
+ return 1;
+ }
+ $value = self::flattenSingleValue($value);
+
+ if (($value === null) || (is_float($value)) || (is_int($value))) {
+ return 1;
+ } elseif (is_bool($value)) {
+ return 4;
+ } elseif (is_array($value)) {
+ return 64;
+ } elseif (is_string($value)) {
+ // Errors
+ if ((strlen($value) > 0) && ($value{0} == '#')) {
+ return 16;
+ }
+ return 2;
+ }
+ return 0;
+ }
+
+
+ /**
+ * Convert a multi-dimensional array to a simple 1-dimensional array
+ *
+ * @param array $array Array to be flattened
+ * @return array Flattened array
+ */
+ public static function flattenArray($array)
+ {
+ if (!is_array($array)) {
+ return (array) $array;
+ }
+
+ $arrayValues = array();
+ foreach ($array as $value) {
+ if (is_array($value)) {
+ foreach ($value as $val) {
+ if (is_array($val)) {
+ foreach ($val as $v) {
+ $arrayValues[] = $v;
+ }
+ } else {
+ $arrayValues[] = $val;
+ }
+ }
+ } else {
+ $arrayValues[] = $value;
+ }
+ }
+
+ return $arrayValues;
+ }
+
+
+ /**
+ * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
+ *
+ * @param array $array Array to be flattened
+ * @return array Flattened array
+ */
+ public static function flattenArrayIndexed($array)
+ {
+ if (!is_array($array)) {
+ return (array) $array;
+ }
+
+ $arrayValues = array();
+ foreach ($array as $k1 => $value) {
+ if (is_array($value)) {
+ foreach ($value as $k2 => $val) {
+ if (is_array($val)) {
+ foreach ($val as $k3 => $v) {
+ $arrayValues[$k1.'.'.$k2.'.'.$k3] = $v;
+ }
+ } else {
+ $arrayValues[$k1.'.'.$k2] = $val;
+ }
+ }
+ } else {
+ $arrayValues[$k1] = $value;
+ }
+ }
+
+ return $arrayValues;
+ }
+
+
+ /**
+ * Convert an array to a single scalar value by extracting the first element
+ *
+ * @param mixed $value Array or scalar value
+ * @return mixed
+ */
+ public static function flattenSingleValue($value = '')
+ {
+ while (is_array($value)) {
+ $value = array_pop($value);
+ }
+
+ return $value;
+ }
+}
+
+
+//
+// There are a few mathematical functions that aren't available on all versions of PHP for all platforms
+// These functions aren't available in Windows implementations of PHP prior to version 5.3.0
+// So we test if they do exist for this version of PHP/operating platform; and if not we create them
+//
+if (!function_exists('acosh')) {
+ function acosh($x)
+ {
+ return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2));
+ } // function acosh()
+}
+
+if (!function_exists('asinh')) {
+ function asinh($x)
+ {
+ return log($x + sqrt(1 + $x * $x));
+ } // function asinh()
+}
+
+if (!function_exists('atanh')) {
+ function atanh($x)
+ {
+ return (log(1 + $x) - log(1 - $x)) / 2;
+ } // function atanh()
+}
+
+
+//
+// Strangely, PHP doesn't have a mb_str_replace multibyte function
+// As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set
+//
+if ((!function_exists('mb_str_replace')) &&
+ (function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) {
+ function mb_str_replace($search, $replace, $subject)
+ {
+ if (is_array($subject)) {
+ $ret = array();
+ foreach ($subject as $key => $val) {
+ $ret[$key] = mb_str_replace($search, $replace, $val);
+ }
+ return $ret;
+ }
+
+ foreach ((array) $search as $key => $s) {
+ if ($s == '' && $s !== 0) {
+ continue;
+ }
+ $r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : '');
+ $pos = mb_strpos($subject, $s, 0, 'UTF-8');
+ while ($pos !== false) {
+ $subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8');
+ $pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8');
+ }
+ }
+ return $subject;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Logical.php b/extend/PHPExcel/PHPExcel/Calculation/Logical.php
new file mode 100755
index 0000000..dd65f01
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Logical.php
@@ -0,0 +1,285 @@
+ $arg) {
+ // Is it a boolean value?
+ if (is_bool($arg)) {
+ $returnValue = $returnValue && $arg;
+ } elseif ((is_numeric($arg)) && (!is_string($arg))) {
+ $returnValue = $returnValue && ($arg != 0);
+ } elseif (is_string($arg)) {
+ $arg = strtoupper($arg);
+ if (($arg == 'TRUE') || ($arg == PHPExcel_Calculation::getTRUE())) {
+ $arg = true;
+ } elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) {
+ $arg = false;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $returnValue = $returnValue && ($arg != 0);
+ }
+ }
+
+ // Return
+ if ($argCount < 0) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * LOGICAL_OR
+ *
+ * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
+ *
+ * Excel Function:
+ * =OR(logical1[,logical2[, ...]])
+ *
+ * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
+ * or references that contain logical values.
+ *
+ * Boolean arguments are treated as True or False as appropriate
+ * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
+ * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
+ * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
+ *
+ * @access public
+ * @category Logical Functions
+ * @param mixed $arg,... Data values
+ * @return boolean The logical OR of the arguments.
+ */
+ public static function LOGICAL_OR()
+ {
+ // Return value
+ $returnValue = false;
+
+ // Loop through the arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ $argCount = -1;
+ foreach ($aArgs as $argCount => $arg) {
+ // Is it a boolean value?
+ if (is_bool($arg)) {
+ $returnValue = $returnValue || $arg;
+ } elseif ((is_numeric($arg)) && (!is_string($arg))) {
+ $returnValue = $returnValue || ($arg != 0);
+ } elseif (is_string($arg)) {
+ $arg = strtoupper($arg);
+ if (($arg == 'TRUE') || ($arg == PHPExcel_Calculation::getTRUE())) {
+ $arg = true;
+ } elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) {
+ $arg = false;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $returnValue = $returnValue || ($arg != 0);
+ }
+ }
+
+ // Return
+ if ($argCount < 0) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * NOT
+ *
+ * Returns the boolean inverse of the argument.
+ *
+ * Excel Function:
+ * =NOT(logical)
+ *
+ * The argument must evaluate to a logical value such as TRUE or FALSE
+ *
+ * Boolean arguments are treated as True or False as appropriate
+ * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False
+ * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
+ * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
+ *
+ * @access public
+ * @category Logical Functions
+ * @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE
+ * @return boolean The boolean inverse of the argument.
+ */
+ public static function NOT($logical = false)
+ {
+ $logical = PHPExcel_Calculation_Functions::flattenSingleValue($logical);
+ if (is_string($logical)) {
+ $logical = strtoupper($logical);
+ if (($logical == 'TRUE') || ($logical == PHPExcel_Calculation::getTRUE())) {
+ return false;
+ } elseif (($logical == 'FALSE') || ($logical == PHPExcel_Calculation::getFALSE())) {
+ return true;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+
+ return !$logical;
+ }
+
+ /**
+ * STATEMENT_IF
+ *
+ * Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
+ *
+ * Excel Function:
+ * =IF(condition[,returnIfTrue[,returnIfFalse]])
+ *
+ * Condition is any value or expression that can be evaluated to TRUE or FALSE.
+ * For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100,
+ * the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE.
+ * This argument can use any comparison calculation operator.
+ * ReturnIfTrue is the value that is returned if condition evaluates to TRUE.
+ * For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE,
+ * then the IF function returns the text "Within budget"
+ * If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use
+ * the logical value TRUE for this argument.
+ * ReturnIfTrue can be another formula.
+ * ReturnIfFalse is the value that is returned if condition evaluates to FALSE.
+ * For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE,
+ * then the IF function returns the text "Over budget".
+ * If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned.
+ * If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned.
+ * ReturnIfFalse can be another formula.
+ *
+ * @access public
+ * @category Logical Functions
+ * @param mixed $condition Condition to evaluate
+ * @param mixed $returnIfTrue Value to return when condition is true
+ * @param mixed $returnIfFalse Optional value to return when condition is false
+ * @return mixed The value of returnIfTrue or returnIfFalse determined by condition
+ */
+ public static function STATEMENT_IF($condition = true, $returnIfTrue = 0, $returnIfFalse = false)
+ {
+ $condition = (is_null($condition)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($condition);
+ $returnIfTrue = (is_null($returnIfTrue)) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($returnIfTrue);
+ $returnIfFalse = (is_null($returnIfFalse)) ? false : PHPExcel_Calculation_Functions::flattenSingleValue($returnIfFalse);
+
+ return ($condition) ? $returnIfTrue : $returnIfFalse;
+ }
+
+
+ /**
+ * IFERROR
+ *
+ * Excel Function:
+ * =IFERROR(testValue,errorpart)
+ *
+ * @access public
+ * @category Logical Functions
+ * @param mixed $testValue Value to check, is also the value returned when no error
+ * @param mixed $errorpart Value to return when testValue is an error condition
+ * @return mixed The value of errorpart or testValue determined by error condition
+ */
+ public static function IFERROR($testValue = '', $errorpart = '')
+ {
+ $testValue = (is_null($testValue)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($testValue);
+ $errorpart = (is_null($errorpart)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($errorpart);
+
+ return self::STATEMENT_IF(PHPExcel_Calculation_Functions::IS_ERROR($testValue), $errorpart, $testValue);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/LookupRef.php b/extend/PHPExcel/PHPExcel/Calculation/LookupRef.php
new file mode 100755
index 0000000..1fe7790
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/LookupRef.php
@@ -0,0 +1,879 @@
+ '') {
+ if (strpos($sheetText, ' ') !== false) {
+ $sheetText = "'".$sheetText."'";
+ }
+ $sheetText .='!';
+ }
+ if ((!is_bool($referenceStyle)) || $referenceStyle) {
+ $rowRelative = $columnRelative = '$';
+ $column = PHPExcel_Cell::stringFromColumnIndex($column-1);
+ if (($relativity == 2) || ($relativity == 4)) {
+ $columnRelative = '';
+ }
+ if (($relativity == 3) || ($relativity == 4)) {
+ $rowRelative = '';
+ }
+ return $sheetText.$columnRelative.$column.$rowRelative.$row;
+ } else {
+ if (($relativity == 2) || ($relativity == 4)) {
+ $column = '['.$column.']';
+ }
+ if (($relativity == 3) || ($relativity == 4)) {
+ $row = '['.$row.']';
+ }
+ return $sheetText.'R'.$row.'C'.$column;
+ }
+ }
+
+
+ /**
+ * COLUMN
+ *
+ * Returns the column number of the given cell reference
+ * If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array.
+ * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
+ * reference of the cell in which the COLUMN function appears; otherwise this function returns 0.
+ *
+ * Excel Function:
+ * =COLUMN([cellAddress])
+ *
+ * @param cellAddress A reference to a range of cells for which you want the column numbers
+ * @return integer or array of integer
+ */
+ public static function COLUMN($cellAddress = null)
+ {
+ if (is_null($cellAddress) || trim($cellAddress) === '') {
+ return 0;
+ }
+
+ if (is_array($cellAddress)) {
+ foreach ($cellAddress as $columnKey => $value) {
+ $columnKey = preg_replace('/[^a-z]/i', '', $columnKey);
+ return (integer) PHPExcel_Cell::columnIndexFromString($columnKey);
+ }
+ } else {
+ if (strpos($cellAddress, '!') !== false) {
+ list($sheet, $cellAddress) = explode('!', $cellAddress);
+ }
+ if (strpos($cellAddress, ':') !== false) {
+ list($startAddress, $endAddress) = explode(':', $cellAddress);
+ $startAddress = preg_replace('/[^a-z]/i', '', $startAddress);
+ $endAddress = preg_replace('/[^a-z]/i', '', $endAddress);
+ $returnValue = array();
+ do {
+ $returnValue[] = (integer) PHPExcel_Cell::columnIndexFromString($startAddress);
+ } while ($startAddress++ != $endAddress);
+ return $returnValue;
+ } else {
+ $cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress);
+ return (integer) PHPExcel_Cell::columnIndexFromString($cellAddress);
+ }
+ }
+ }
+
+
+ /**
+ * COLUMNS
+ *
+ * Returns the number of columns in an array or reference.
+ *
+ * Excel Function:
+ * =COLUMNS(cellAddress)
+ *
+ * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of columns
+ * @return integer The number of columns in cellAddress
+ */
+ public static function COLUMNS($cellAddress = null)
+ {
+ if (is_null($cellAddress) || $cellAddress === '') {
+ return 1;
+ } elseif (!is_array($cellAddress)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ reset($cellAddress);
+ $isMatrix = (is_numeric(key($cellAddress)));
+ list($columns, $rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress);
+
+ if ($isMatrix) {
+ return $rows;
+ } else {
+ return $columns;
+ }
+ }
+
+
+ /**
+ * ROW
+ *
+ * Returns the row number of the given cell reference
+ * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array.
+ * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
+ * reference of the cell in which the ROW function appears; otherwise this function returns 0.
+ *
+ * Excel Function:
+ * =ROW([cellAddress])
+ *
+ * @param cellAddress A reference to a range of cells for which you want the row numbers
+ * @return integer or array of integer
+ */
+ public static function ROW($cellAddress = null)
+ {
+ if (is_null($cellAddress) || trim($cellAddress) === '') {
+ return 0;
+ }
+
+ if (is_array($cellAddress)) {
+ foreach ($cellAddress as $columnKey => $rowValue) {
+ foreach ($rowValue as $rowKey => $cellValue) {
+ return (integer) preg_replace('/[^0-9]/i', '', $rowKey);
+ }
+ }
+ } else {
+ if (strpos($cellAddress, '!') !== false) {
+ list($sheet, $cellAddress) = explode('!', $cellAddress);
+ }
+ if (strpos($cellAddress, ':') !== false) {
+ list($startAddress, $endAddress) = explode(':', $cellAddress);
+ $startAddress = preg_replace('/[^0-9]/', '', $startAddress);
+ $endAddress = preg_replace('/[^0-9]/', '', $endAddress);
+ $returnValue = array();
+ do {
+ $returnValue[][] = (integer) $startAddress;
+ } while ($startAddress++ != $endAddress);
+ return $returnValue;
+ } else {
+ list($cellAddress) = explode(':', $cellAddress);
+ return (integer) preg_replace('/[^0-9]/', '', $cellAddress);
+ }
+ }
+ }
+
+
+ /**
+ * ROWS
+ *
+ * Returns the number of rows in an array or reference.
+ *
+ * Excel Function:
+ * =ROWS(cellAddress)
+ *
+ * @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows
+ * @return integer The number of rows in cellAddress
+ */
+ public static function ROWS($cellAddress = null)
+ {
+ if (is_null($cellAddress) || $cellAddress === '') {
+ return 1;
+ } elseif (!is_array($cellAddress)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ reset($cellAddress);
+ $isMatrix = (is_numeric(key($cellAddress)));
+ list($columns, $rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress);
+
+ if ($isMatrix) {
+ return $columns;
+ } else {
+ return $rows;
+ }
+ }
+
+
+ /**
+ * HYPERLINK
+ *
+ * Excel Function:
+ * =HYPERLINK(linkURL,displayName)
+ *
+ * @access public
+ * @category Logical Functions
+ * @param string $linkURL Value to check, is also the value returned when no error
+ * @param string $displayName Value to return when testValue is an error condition
+ * @param PHPExcel_Cell $pCell The cell to set the hyperlink in
+ * @return mixed The value of $displayName (or $linkURL if $displayName was blank)
+ */
+ public static function HYPERLINK($linkURL = '', $displayName = null, PHPExcel_Cell $pCell = null)
+ {
+ $args = func_get_args();
+ $pCell = array_pop($args);
+
+ $linkURL = (is_null($linkURL)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($linkURL);
+ $displayName = (is_null($displayName)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($displayName);
+
+ if ((!is_object($pCell)) || (trim($linkURL) == '')) {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+
+ if ((is_object($displayName)) || trim($displayName) == '') {
+ $displayName = $linkURL;
+ }
+
+ $pCell->getHyperlink()->setUrl($linkURL);
+ $pCell->getHyperlink()->setTooltip($displayName);
+
+ return $displayName;
+ }
+
+
+ /**
+ * INDIRECT
+ *
+ * Returns the reference specified by a text string.
+ * References are immediately evaluated to display their contents.
+ *
+ * Excel Function:
+ * =INDIRECT(cellAddress)
+ *
+ * NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010
+ *
+ * @param cellAddress $cellAddress The cell address of the current cell (containing this formula)
+ * @param PHPExcel_Cell $pCell The current cell (containing this formula)
+ * @return mixed The cells referenced by cellAddress
+ *
+ * @todo Support for the optional a1 parameter introduced in Excel 2010
+ *
+ */
+ public static function INDIRECT($cellAddress = null, PHPExcel_Cell $pCell = null)
+ {
+ $cellAddress = PHPExcel_Calculation_Functions::flattenSingleValue($cellAddress);
+ if (is_null($cellAddress) || $cellAddress === '') {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+
+ $cellAddress1 = $cellAddress;
+ $cellAddress2 = null;
+ if (strpos($cellAddress, ':') !== false) {
+ list($cellAddress1, $cellAddress2) = explode(':', $cellAddress);
+ }
+
+ if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress1, $matches)) ||
+ ((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress2, $matches)))) {
+ if (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $cellAddress1, $matches)) {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+
+ if (strpos($cellAddress, '!') !== false) {
+ list($sheetName, $cellAddress) = explode('!', $cellAddress);
+ $sheetName = trim($sheetName, "'");
+ $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
+ } else {
+ $pSheet = $pCell->getWorksheet();
+ }
+
+ return PHPExcel_Calculation::getInstance()->extractNamedRange($cellAddress, $pSheet, false);
+ }
+
+ if (strpos($cellAddress, '!') !== false) {
+ list($sheetName, $cellAddress) = explode('!', $cellAddress);
+ $sheetName = trim($sheetName, "'");
+ $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
+ } else {
+ $pSheet = $pCell->getWorksheet();
+ }
+
+ return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false);
+ }
+
+
+ /**
+ * OFFSET
+ *
+ * Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells.
+ * The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and
+ * the number of columns to be returned.
+ *
+ * Excel Function:
+ * =OFFSET(cellAddress, rows, cols, [height], [width])
+ *
+ * @param cellAddress The reference from which you want to base the offset. Reference must refer to a cell or
+ * range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value.
+ * @param rows The number of rows, up or down, that you want the upper-left cell to refer to.
+ * Using 5 as the rows argument specifies that the upper-left cell in the reference is
+ * five rows below reference. Rows can be positive (which means below the starting reference)
+ * or negative (which means above the starting reference).
+ * @param cols The number of columns, to the left or right, that you want the upper-left cell of the result
+ * to refer to. Using 5 as the cols argument specifies that the upper-left cell in the
+ * reference is five columns to the right of reference. Cols can be positive (which means
+ * to the right of the starting reference) or negative (which means to the left of the
+ * starting reference).
+ * @param height The height, in number of rows, that you want the returned reference to be. Height must be a positive number.
+ * @param width The width, in number of columns, that you want the returned reference to be. Width must be a positive number.
+ * @return string A reference to a cell or range of cells
+ */
+ public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $height = null, $width = null)
+ {
+ $rows = PHPExcel_Calculation_Functions::flattenSingleValue($rows);
+ $columns = PHPExcel_Calculation_Functions::flattenSingleValue($columns);
+ $height = PHPExcel_Calculation_Functions::flattenSingleValue($height);
+ $width = PHPExcel_Calculation_Functions::flattenSingleValue($width);
+ if ($cellAddress == null) {
+ return 0;
+ }
+
+ $args = func_get_args();
+ $pCell = array_pop($args);
+ if (!is_object($pCell)) {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+
+ $sheetName = null;
+ if (strpos($cellAddress, "!")) {
+ list($sheetName, $cellAddress) = explode("!", $cellAddress);
+ $sheetName = trim($sheetName, "'");
+ }
+ if (strpos($cellAddress, ":")) {
+ list($startCell, $endCell) = explode(":", $cellAddress);
+ } else {
+ $startCell = $endCell = $cellAddress;
+ }
+ list($startCellColumn, $startCellRow) = PHPExcel_Cell::coordinateFromString($startCell);
+ list($endCellColumn, $endCellRow) = PHPExcel_Cell::coordinateFromString($endCell);
+
+ $startCellRow += $rows;
+ $startCellColumn = PHPExcel_Cell::columnIndexFromString($startCellColumn) - 1;
+ $startCellColumn += $columns;
+
+ if (($startCellRow <= 0) || ($startCellColumn < 0)) {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+ $endCellColumn = PHPExcel_Cell::columnIndexFromString($endCellColumn) - 1;
+ if (($width != null) && (!is_object($width))) {
+ $endCellColumn = $startCellColumn + $width - 1;
+ } else {
+ $endCellColumn += $columns;
+ }
+ $startCellColumn = PHPExcel_Cell::stringFromColumnIndex($startCellColumn);
+
+ if (($height != null) && (!is_object($height))) {
+ $endCellRow = $startCellRow + $height - 1;
+ } else {
+ $endCellRow += $rows;
+ }
+
+ if (($endCellRow <= 0) || ($endCellColumn < 0)) {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+ $endCellColumn = PHPExcel_Cell::stringFromColumnIndex($endCellColumn);
+
+ $cellAddress = $startCellColumn.$startCellRow;
+ if (($startCellColumn != $endCellColumn) || ($startCellRow != $endCellRow)) {
+ $cellAddress .= ':'.$endCellColumn.$endCellRow;
+ }
+
+ if ($sheetName !== null) {
+ $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName);
+ } else {
+ $pSheet = $pCell->getWorksheet();
+ }
+
+ return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false);
+ }
+
+
+ /**
+ * CHOOSE
+ *
+ * Uses lookup_value to return a value from the list of value arguments.
+ * Use CHOOSE to select one of up to 254 values based on the lookup_value.
+ *
+ * Excel Function:
+ * =CHOOSE(index_num, value1, [value2], ...)
+ *
+ * @param index_num Specifies which value argument is selected.
+ * Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number
+ * between 1 and 254.
+ * @param value1... Value1 is required, subsequent values are optional.
+ * Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on
+ * index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or
+ * text.
+ * @return mixed The selected value
+ */
+ public static function CHOOSE()
+ {
+ $chooseArgs = func_get_args();
+ $chosenEntry = PHPExcel_Calculation_Functions::flattenArray(array_shift($chooseArgs));
+ $entryCount = count($chooseArgs) - 1;
+
+ if (is_array($chosenEntry)) {
+ $chosenEntry = array_shift($chosenEntry);
+ }
+ if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) {
+ --$chosenEntry;
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $chosenEntry = floor($chosenEntry);
+ if (($chosenEntry < 0) || ($chosenEntry > $entryCount)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (is_array($chooseArgs[$chosenEntry])) {
+ return PHPExcel_Calculation_Functions::flattenArray($chooseArgs[$chosenEntry]);
+ } else {
+ return $chooseArgs[$chosenEntry];
+ }
+ }
+
+
+ /**
+ * MATCH
+ *
+ * The MATCH function searches for a specified item in a range of cells
+ *
+ * Excel Function:
+ * =MATCH(lookup_value, lookup_array, [match_type])
+ *
+ * @param lookup_value The value that you want to match in lookup_array
+ * @param lookup_array The range of cells being searched
+ * @param match_type The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered.
+ * @return integer The relative position of the found item
+ */
+ public static function MATCH($lookup_value, $lookup_array, $match_type = 1)
+ {
+ $lookup_array = PHPExcel_Calculation_Functions::flattenArray($lookup_array);
+ $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value);
+ $match_type = (is_null($match_type)) ? 1 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($match_type);
+ // MATCH is not case sensitive
+ $lookup_value = strtolower($lookup_value);
+
+ // lookup_value type has to be number, text, or logical values
+ if ((!is_numeric($lookup_value)) && (!is_string($lookup_value)) && (!is_bool($lookup_value))) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+ // match_type is 0, 1 or -1
+ if (($match_type !== 0) && ($match_type !== -1) && ($match_type !== 1)) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+ // lookup_array should not be empty
+ $lookupArraySize = count($lookup_array);
+ if ($lookupArraySize <= 0) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+ // lookup_array should contain only number, text, or logical values, or empty (null) cells
+ foreach ($lookup_array as $i => $lookupArrayValue) {
+ // check the type of the value
+ if ((!is_numeric($lookupArrayValue)) && (!is_string($lookupArrayValue)) &&
+ (!is_bool($lookupArrayValue)) && (!is_null($lookupArrayValue))) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ // convert strings to lowercase for case-insensitive testing
+ if (is_string($lookupArrayValue)) {
+ $lookup_array[$i] = strtolower($lookupArrayValue);
+ }
+ if ((is_null($lookupArrayValue)) && (($match_type == 1) || ($match_type == -1))) {
+ $lookup_array = array_slice($lookup_array, 0, $i-1);
+ }
+ }
+
+ // if match_type is 1 or -1, the list has to be ordered
+ if ($match_type == 1) {
+ asort($lookup_array);
+ $keySet = array_keys($lookup_array);
+ } elseif ($match_type == -1) {
+ arsort($lookup_array);
+ $keySet = array_keys($lookup_array);
+ }
+
+ // **
+ // find the match
+ // **
+ foreach ($lookup_array as $i => $lookupArrayValue) {
+ if (($match_type == 0) && ($lookupArrayValue == $lookup_value)) {
+ // exact match
+ return ++$i;
+ } elseif (($match_type == -1) && ($lookupArrayValue <= $lookup_value)) {
+ $i = array_search($i, $keySet);
+ // if match_type is -1 <=> find the smallest value that is greater than or equal to lookup_value
+ if ($i < 1) {
+ // 1st cell was already smaller than the lookup_value
+ break;
+ } else {
+ // the previous cell was the match
+ return $keySet[$i-1]+1;
+ }
+ } elseif (($match_type == 1) && ($lookupArrayValue >= $lookup_value)) {
+ $i = array_search($i, $keySet);
+ // if match_type is 1 <=> find the largest value that is less than or equal to lookup_value
+ if ($i < 1) {
+ // 1st cell was already bigger than the lookup_value
+ break;
+ } else {
+ // the previous cell was the match
+ return $keySet[$i-1]+1;
+ }
+ }
+ }
+
+ // unsuccessful in finding a match, return #N/A error value
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+
+ /**
+ * INDEX
+ *
+ * Uses an index to choose a value from a reference or array
+ *
+ * Excel Function:
+ * =INDEX(range_array, row_num, [column_num])
+ *
+ * @param range_array A range of cells or an array constant
+ * @param row_num The row in array from which to return a value. If row_num is omitted, column_num is required.
+ * @param column_num The column in array from which to return a value. If column_num is omitted, row_num is required.
+ * @return mixed the value of a specified cell or array of cells
+ */
+ public static function INDEX($arrayValues, $rowNum = 0, $columnNum = 0)
+ {
+ if (($rowNum < 0) || ($columnNum < 0)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (!is_array($arrayValues)) {
+ return PHPExcel_Calculation_Functions::REF();
+ }
+
+ $rowKeys = array_keys($arrayValues);
+ $columnKeys = @array_keys($arrayValues[$rowKeys[0]]);
+
+ if ($columnNum > count($columnKeys)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($columnNum == 0) {
+ if ($rowNum == 0) {
+ return $arrayValues;
+ }
+ $rowNum = $rowKeys[--$rowNum];
+ $returnArray = array();
+ foreach ($arrayValues as $arrayColumn) {
+ if (is_array($arrayColumn)) {
+ if (isset($arrayColumn[$rowNum])) {
+ $returnArray[] = $arrayColumn[$rowNum];
+ } else {
+ return $arrayValues[$rowNum];
+ }
+ } else {
+ return $arrayValues[$rowNum];
+ }
+ }
+ return $returnArray;
+ }
+ $columnNum = $columnKeys[--$columnNum];
+ if ($rowNum > count($rowKeys)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($rowNum == 0) {
+ return $arrayValues[$columnNum];
+ }
+ $rowNum = $rowKeys[--$rowNum];
+
+ return $arrayValues[$rowNum][$columnNum];
+ }
+
+
+ /**
+ * TRANSPOSE
+ *
+ * @param array $matrixData A matrix of values
+ * @return array
+ *
+ * Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix.
+ */
+ public static function TRANSPOSE($matrixData)
+ {
+ $returnMatrix = array();
+ if (!is_array($matrixData)) {
+ $matrixData = array(array($matrixData));
+ }
+
+ $column = 0;
+ foreach ($matrixData as $matrixRow) {
+ $row = 0;
+ foreach ($matrixRow as $matrixCell) {
+ $returnMatrix[$row][$column] = $matrixCell;
+ ++$row;
+ }
+ ++$column;
+ }
+ return $returnMatrix;
+ }
+
+
+ private static function vlookupSort($a, $b)
+ {
+ reset($a);
+ $firstColumn = key($a);
+ if (($aLower = strtolower($a[$firstColumn])) == ($bLower = strtolower($b[$firstColumn]))) {
+ return 0;
+ }
+ return ($aLower < $bLower) ? -1 : 1;
+ }
+
+
+ /**
+ * VLOOKUP
+ * The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value in the same row based on the index_number.
+ * @param lookup_value The value that you want to match in lookup_array
+ * @param lookup_array The range of cells being searched
+ * @param index_number The column number in table_array from which the matching value must be returned. The first column is 1.
+ * @param not_exact_match Determines if you are looking for an exact match based on lookup_value.
+ * @return mixed The value of the found cell
+ */
+ public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match = true)
+ {
+ $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value);
+ $index_number = PHPExcel_Calculation_Functions::flattenSingleValue($index_number);
+ $not_exact_match = PHPExcel_Calculation_Functions::flattenSingleValue($not_exact_match);
+
+ // index_number must be greater than or equal to 1
+ if ($index_number < 1) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // index_number must be less than or equal to the number of columns in lookup_array
+ if ((!is_array($lookup_array)) || (empty($lookup_array))) {
+ return PHPExcel_Calculation_Functions::REF();
+ } else {
+ $f = array_keys($lookup_array);
+ $firstRow = array_pop($f);
+ if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array[$firstRow]))) {
+ return PHPExcel_Calculation_Functions::REF();
+ } else {
+ $columnKeys = array_keys($lookup_array[$firstRow]);
+ $returnColumn = $columnKeys[--$index_number];
+ $firstColumn = array_shift($columnKeys);
+ }
+ }
+
+ if (!$not_exact_match) {
+ uasort($lookup_array, array('self', 'vlookupSort'));
+ }
+
+ $rowNumber = $rowValue = false;
+ foreach ($lookup_array as $rowKey => $rowData) {
+ if ((is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) ||
+ (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && (strtolower($rowData[$firstColumn]) > strtolower($lookup_value)))) {
+ break;
+ }
+ $rowNumber = $rowKey;
+ $rowValue = $rowData[$firstColumn];
+ }
+
+ if ($rowNumber !== false) {
+ if ((!$not_exact_match) && ($rowValue != $lookup_value)) {
+ // if an exact match is required, we have what we need to return an appropriate response
+ return PHPExcel_Calculation_Functions::NA();
+ } else {
+ // otherwise return the appropriate value
+ return $lookup_array[$rowNumber][$returnColumn];
+ }
+ }
+
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+
+ /**
+ * HLOOKUP
+ * The HLOOKUP function searches for value in the top-most row of lookup_array and returns the value in the same column based on the index_number.
+ * @param lookup_value The value that you want to match in lookup_array
+ * @param lookup_array The range of cells being searched
+ * @param index_number The row number in table_array from which the matching value must be returned. The first row is 1.
+ * @param not_exact_match Determines if you are looking for an exact match based on lookup_value.
+ * @return mixed The value of the found cell
+ */
+ public static function HLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match = true)
+ {
+ $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value);
+ $index_number = PHPExcel_Calculation_Functions::flattenSingleValue($index_number);
+ $not_exact_match = PHPExcel_Calculation_Functions::flattenSingleValue($not_exact_match);
+
+ // index_number must be greater than or equal to 1
+ if ($index_number < 1) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ // index_number must be less than or equal to the number of columns in lookup_array
+ if ((!is_array($lookup_array)) || (empty($lookup_array))) {
+ return PHPExcel_Calculation_Functions::REF();
+ } else {
+ $f = array_keys($lookup_array);
+ $firstRow = array_pop($f);
+ if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array[$firstRow]))) {
+ return PHPExcel_Calculation_Functions::REF();
+ } else {
+ $columnKeys = array_keys($lookup_array[$firstRow]);
+ $firstkey = $f[0] - 1;
+ $returnColumn = $firstkey + $index_number;
+ $firstColumn = array_shift($f);
+ }
+ }
+
+ if (!$not_exact_match) {
+ $firstRowH = asort($lookup_array[$firstColumn]);
+ }
+
+ $rowNumber = $rowValue = false;
+ foreach ($lookup_array[$firstColumn] as $rowKey => $rowData) {
+ if ((is_numeric($lookup_value) && is_numeric($rowData) && ($rowData > $lookup_value)) ||
+ (!is_numeric($lookup_value) && !is_numeric($rowData) && (strtolower($rowData) > strtolower($lookup_value)))) {
+ break;
+ }
+ $rowNumber = $rowKey;
+ $rowValue = $rowData;
+ }
+
+ if ($rowNumber !== false) {
+ if ((!$not_exact_match) && ($rowValue != $lookup_value)) {
+ // if an exact match is required, we have what we need to return an appropriate response
+ return PHPExcel_Calculation_Functions::NA();
+ } else {
+ // otherwise return the appropriate value
+ return $lookup_array[$returnColumn][$rowNumber];
+ }
+ }
+
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+
+ /**
+ * LOOKUP
+ * The LOOKUP function searches for value either from a one-row or one-column range or from an array.
+ * @param lookup_value The value that you want to match in lookup_array
+ * @param lookup_vector The range of cells being searched
+ * @param result_vector The column from which the matching value must be returned
+ * @return mixed The value of the found cell
+ */
+ public static function LOOKUP($lookup_value, $lookup_vector, $result_vector = null)
+ {
+ $lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value);
+
+ if (!is_array($lookup_vector)) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ $lookupRows = count($lookup_vector);
+ $l = array_keys($lookup_vector);
+ $l = array_shift($l);
+ $lookupColumns = count($lookup_vector[$l]);
+ if ((($lookupRows == 1) && ($lookupColumns > 1)) || (($lookupRows == 2) && ($lookupColumns != 2))) {
+ $lookup_vector = self::TRANSPOSE($lookup_vector);
+ $lookupRows = count($lookup_vector);
+ $l = array_keys($lookup_vector);
+ $lookupColumns = count($lookup_vector[array_shift($l)]);
+ }
+
+ if (is_null($result_vector)) {
+ $result_vector = $lookup_vector;
+ }
+ $resultRows = count($result_vector);
+ $l = array_keys($result_vector);
+ $l = array_shift($l);
+ $resultColumns = count($result_vector[$l]);
+ if ((($resultRows == 1) && ($resultColumns > 1)) || (($resultRows == 2) && ($resultColumns != 2))) {
+ $result_vector = self::TRANSPOSE($result_vector);
+ $resultRows = count($result_vector);
+ $r = array_keys($result_vector);
+ $resultColumns = count($result_vector[array_shift($r)]);
+ }
+
+ if ($lookupRows == 2) {
+ $result_vector = array_pop($lookup_vector);
+ $lookup_vector = array_shift($lookup_vector);
+ }
+ if ($lookupColumns != 2) {
+ foreach ($lookup_vector as &$value) {
+ if (is_array($value)) {
+ $k = array_keys($value);
+ $key1 = $key2 = array_shift($k);
+ $key2++;
+ $dataValue1 = $value[$key1];
+ } else {
+ $key1 = 0;
+ $key2 = 1;
+ $dataValue1 = $value;
+ }
+ $dataValue2 = array_shift($result_vector);
+ if (is_array($dataValue2)) {
+ $dataValue2 = array_shift($dataValue2);
+ }
+ $value = array($key1 => $dataValue1, $key2 => $dataValue2);
+ }
+ unset($value);
+ }
+
+ return self::VLOOKUP($lookup_value, $lookup_vector, 2);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/MathTrig.php b/extend/PHPExcel/PHPExcel/Calculation/MathTrig.php
new file mode 100755
index 0000000..894ba9c
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/MathTrig.php
@@ -0,0 +1,1459 @@
+ 1; --$i) {
+ if (($value % $i) == 0) {
+ $factorArray = array_merge($factorArray, self::factors($value / $i));
+ $factorArray = array_merge($factorArray, self::factors($i));
+ if ($i <= sqrt($value)) {
+ break;
+ }
+ }
+ }
+ if (!empty($factorArray)) {
+ rsort($factorArray);
+ return $factorArray;
+ } else {
+ return array((integer) $value);
+ }
+ }
+
+
+ private static function romanCut($num, $n)
+ {
+ return ($num - ($num % $n ) ) / $n;
+ }
+
+
+ /**
+ * ATAN2
+ *
+ * This function calculates the arc tangent of the two variables x and y. It is similar to
+ * calculating the arc tangent of y ÷ x, except that the signs of both arguments are used
+ * to determine the quadrant of the result.
+ * The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
+ * point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between
+ * -pi and pi, excluding -pi.
+ *
+ * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
+ * PHP atan2() function, so we need to reverse them here before calling the PHP atan() function.
+ *
+ * Excel Function:
+ * ATAN2(xCoordinate,yCoordinate)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $xCoordinate The x-coordinate of the point.
+ * @param float $yCoordinate The y-coordinate of the point.
+ * @return float The inverse tangent of the specified x- and y-coordinates.
+ */
+ public static function ATAN2($xCoordinate = null, $yCoordinate = null)
+ {
+ $xCoordinate = PHPExcel_Calculation_Functions::flattenSingleValue($xCoordinate);
+ $yCoordinate = PHPExcel_Calculation_Functions::flattenSingleValue($yCoordinate);
+
+ $xCoordinate = ($xCoordinate !== null) ? $xCoordinate : 0.0;
+ $yCoordinate = ($yCoordinate !== null) ? $yCoordinate : 0.0;
+
+ if (((is_numeric($xCoordinate)) || (is_bool($xCoordinate))) &&
+ ((is_numeric($yCoordinate))) || (is_bool($yCoordinate))) {
+ $xCoordinate = (float) $xCoordinate;
+ $yCoordinate = (float) $yCoordinate;
+
+ if (($xCoordinate == 0) && ($yCoordinate == 0)) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ return atan2($yCoordinate, $xCoordinate);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * CEILING
+ *
+ * Returns number rounded up, away from zero, to the nearest multiple of significance.
+ * For example, if you want to avoid using pennies in your prices and your product is
+ * priced at $4.42, use the formula =CEILING(4.42,0.05) to round prices up to the
+ * nearest nickel.
+ *
+ * Excel Function:
+ * CEILING(number[,significance])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $number The number you want to round.
+ * @param float $significance The multiple to which you want to round.
+ * @return float Rounded Number
+ */
+ public static function CEILING($number, $significance = null)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $significance = PHPExcel_Calculation_Functions::flattenSingleValue($significance);
+
+ if ((is_null($significance)) &&
+ (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
+ $significance = $number / abs($number);
+ }
+
+ if ((is_numeric($number)) && (is_numeric($significance))) {
+ if (($number == 0.0 ) || ($significance == 0.0)) {
+ return 0.0;
+ } elseif (self::SIGN($number) == self::SIGN($significance)) {
+ return ceil($number / $significance) * $significance;
+ } else {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * COMBIN
+ *
+ * Returns the number of combinations for a given number of items. Use COMBIN to
+ * determine the total possible number of groups for a given number of items.
+ *
+ * Excel Function:
+ * COMBIN(numObjs,numInSet)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param int $numObjs Number of different objects
+ * @param int $numInSet Number of objects in each combination
+ * @return int Number of combinations
+ */
+ public static function COMBIN($numObjs, $numInSet)
+ {
+ $numObjs = PHPExcel_Calculation_Functions::flattenSingleValue($numObjs);
+ $numInSet = PHPExcel_Calculation_Functions::flattenSingleValue($numInSet);
+
+ if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
+ if ($numObjs < $numInSet) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif ($numInSet < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * EVEN
+ *
+ * Returns number rounded up to the nearest even integer.
+ * You can use this function for processing items that come in twos. For example,
+ * a packing crate accepts rows of one or two items. The crate is full when
+ * the number of items, rounded up to the nearest two, matches the crate's
+ * capacity.
+ *
+ * Excel Function:
+ * EVEN(number)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $number Number to round
+ * @return int Rounded Number
+ */
+ public static function EVEN($number)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+
+ if (is_null($number)) {
+ return 0;
+ } elseif (is_bool($number)) {
+ $number = (int) $number;
+ }
+
+ if (is_numeric($number)) {
+ $significance = 2 * self::SIGN($number);
+ return (int) self::CEILING($number, $significance);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FACT
+ *
+ * Returns the factorial of a number.
+ * The factorial of a number is equal to 1*2*3*...* number.
+ *
+ * Excel Function:
+ * FACT(factVal)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $factVal Factorial Value
+ * @return int Factorial
+ */
+ public static function FACT($factVal)
+ {
+ $factVal = PHPExcel_Calculation_Functions::flattenSingleValue($factVal);
+
+ if (is_numeric($factVal)) {
+ if ($factVal < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $factLoop = floor($factVal);
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ if ($factVal > $factLoop) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+
+ $factorial = 1;
+ while ($factLoop > 1) {
+ $factorial *= $factLoop--;
+ }
+ return $factorial ;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FACTDOUBLE
+ *
+ * Returns the double factorial of a number.
+ *
+ * Excel Function:
+ * FACTDOUBLE(factVal)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $factVal Factorial Value
+ * @return int Double Factorial
+ */
+ public static function FACTDOUBLE($factVal)
+ {
+ $factLoop = PHPExcel_Calculation_Functions::flattenSingleValue($factVal);
+
+ if (is_numeric($factLoop)) {
+ $factLoop = floor($factLoop);
+ if ($factVal < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $factorial = 1;
+ while ($factLoop > 1) {
+ $factorial *= $factLoop--;
+ --$factLoop;
+ }
+ return $factorial ;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FLOOR
+ *
+ * Rounds number down, toward zero, to the nearest multiple of significance.
+ *
+ * Excel Function:
+ * FLOOR(number[,significance])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $number Number to round
+ * @param float $significance Significance
+ * @return float Rounded Number
+ */
+ public static function FLOOR($number, $significance = null)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $significance = PHPExcel_Calculation_Functions::flattenSingleValue($significance);
+
+ if ((is_null($significance)) &&
+ (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
+ $significance = $number/abs($number);
+ }
+
+ if ((is_numeric($number)) && (is_numeric($significance))) {
+ if ($significance == 0.0) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ } elseif ($number == 0.0) {
+ return 0.0;
+ } elseif (self::SIGN($number) == self::SIGN($significance)) {
+ return floor($number / $significance) * $significance;
+ } else {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * GCD
+ *
+ * Returns the greatest common divisor of a series of numbers.
+ * The greatest common divisor is the largest integer that divides both
+ * number1 and number2 without a remainder.
+ *
+ * Excel Function:
+ * GCD(number1[,number2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return integer Greatest Common Divisor
+ */
+ public static function GCD()
+ {
+ $returnValue = 1;
+ $allValuesFactors = array();
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $value) {
+ if (!is_numeric($value)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ($value == 0) {
+ continue;
+ } elseif ($value < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $myFactors = self::factors($value);
+ $myCountedFactors = array_count_values($myFactors);
+ $allValuesFactors[] = $myCountedFactors;
+ }
+ $allValuesCount = count($allValuesFactors);
+ if ($allValuesCount == 0) {
+ return 0;
+ }
+
+ $mergedArray = $allValuesFactors[0];
+ for ($i=1; $i < $allValuesCount; ++$i) {
+ $mergedArray = array_intersect_key($mergedArray, $allValuesFactors[$i]);
+ }
+ $mergedArrayValues = count($mergedArray);
+ if ($mergedArrayValues == 0) {
+ return $returnValue;
+ } elseif ($mergedArrayValues > 1) {
+ foreach ($mergedArray as $mergedKey => $mergedValue) {
+ foreach ($allValuesFactors as $highestPowerTest) {
+ foreach ($highestPowerTest as $testKey => $testValue) {
+ if (($testKey == $mergedKey) && ($testValue < $mergedValue)) {
+ $mergedArray[$mergedKey] = $testValue;
+ $mergedValue = $testValue;
+ }
+ }
+ }
+ }
+
+ $returnValue = 1;
+ foreach ($mergedArray as $key => $value) {
+ $returnValue *= pow($key, $value);
+ }
+ return $returnValue;
+ } else {
+ $keys = array_keys($mergedArray);
+ $key = $keys[0];
+ $value = $mergedArray[$key];
+ foreach ($allValuesFactors as $testValue) {
+ foreach ($testValue as $mergedKey => $mergedValue) {
+ if (($mergedKey == $key) && ($mergedValue < $value)) {
+ $value = $mergedValue;
+ }
+ }
+ }
+ return pow($key, $value);
+ }
+ }
+
+
+ /**
+ * INT
+ *
+ * Casts a floating point value to an integer
+ *
+ * Excel Function:
+ * INT(number)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $number Number to cast to an integer
+ * @return integer Integer value
+ */
+ public static function INT($number)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+
+ if (is_null($number)) {
+ return 0;
+ } elseif (is_bool($number)) {
+ return (int) $number;
+ }
+ if (is_numeric($number)) {
+ return (int) floor($number);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * LCM
+ *
+ * Returns the lowest common multiplier of a series of numbers
+ * The least common multiple is the smallest positive integer that is a multiple
+ * of all integer arguments number1, number2, and so on. Use LCM to add fractions
+ * with different denominators.
+ *
+ * Excel Function:
+ * LCM(number1[,number2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return int Lowest Common Multiplier
+ */
+ public static function LCM()
+ {
+ $returnValue = 1;
+ $allPoweredFactors = array();
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $value) {
+ if (!is_numeric($value)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if ($value == 0) {
+ return 0;
+ } elseif ($value < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $myFactors = self::factors(floor($value));
+ $myCountedFactors = array_count_values($myFactors);
+ $myPoweredFactors = array();
+ foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) {
+ $myPoweredFactors[$myCountedFactor] = pow($myCountedFactor, $myCountedPower);
+ }
+ foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) {
+ if (array_key_exists($myPoweredValue, $allPoweredFactors)) {
+ if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) {
+ $allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
+ }
+ } else {
+ $allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
+ }
+ }
+ }
+ foreach ($allPoweredFactors as $allPoweredFactor) {
+ $returnValue *= (integer) $allPoweredFactor;
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * LOG_BASE
+ *
+ * Returns the logarithm of a number to a specified base. The default base is 10.
+ *
+ * Excel Function:
+ * LOG(number[,base])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param float $number The positive real number for which you want the logarithm
+ * @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10.
+ * @return float
+ */
+ public static function LOG_BASE($number = null, $base = 10)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $base = (is_null($base)) ? 10 : (float) PHPExcel_Calculation_Functions::flattenSingleValue($base);
+
+ if ((!is_numeric($base)) || (!is_numeric($number))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (($base <= 0) || ($number <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return log($number, $base);
+ }
+
+
+ /**
+ * MDETERM
+ *
+ * Returns the matrix determinant of an array.
+ *
+ * Excel Function:
+ * MDETERM(array)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param array $matrixValues A matrix of values
+ * @return float
+ */
+ public static function MDETERM($matrixValues)
+ {
+ $matrixData = array();
+ if (!is_array($matrixValues)) {
+ $matrixValues = array(array($matrixValues));
+ }
+
+ $row = $maxColumn = 0;
+ foreach ($matrixValues as $matrixRow) {
+ if (!is_array($matrixRow)) {
+ $matrixRow = array($matrixRow);
+ }
+ $column = 0;
+ foreach ($matrixRow as $matrixCell) {
+ if ((is_string($matrixCell)) || ($matrixCell === null)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $matrixData[$column][$row] = $matrixCell;
+ ++$column;
+ }
+ if ($column > $maxColumn) {
+ $maxColumn = $column;
+ }
+ ++$row;
+ }
+ if ($row != $maxColumn) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ try {
+ $matrix = new PHPExcel_Shared_JAMA_Matrix($matrixData);
+ return $matrix->det();
+ } catch (PHPExcel_Exception $ex) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+
+
+ /**
+ * MINVERSE
+ *
+ * Returns the inverse matrix for the matrix stored in an array.
+ *
+ * Excel Function:
+ * MINVERSE(array)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param array $matrixValues A matrix of values
+ * @return array
+ */
+ public static function MINVERSE($matrixValues)
+ {
+ $matrixData = array();
+ if (!is_array($matrixValues)) {
+ $matrixValues = array(array($matrixValues));
+ }
+
+ $row = $maxColumn = 0;
+ foreach ($matrixValues as $matrixRow) {
+ if (!is_array($matrixRow)) {
+ $matrixRow = array($matrixRow);
+ }
+ $column = 0;
+ foreach ($matrixRow as $matrixCell) {
+ if ((is_string($matrixCell)) || ($matrixCell === null)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $matrixData[$column][$row] = $matrixCell;
+ ++$column;
+ }
+ if ($column > $maxColumn) {
+ $maxColumn = $column;
+ }
+ ++$row;
+ }
+ if ($row != $maxColumn) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ try {
+ $matrix = new PHPExcel_Shared_JAMA_Matrix($matrixData);
+ return $matrix->inverse()->getArray();
+ } catch (PHPExcel_Exception $ex) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+
+
+ /**
+ * MMULT
+ *
+ * @param array $matrixData1 A matrix of values
+ * @param array $matrixData2 A matrix of values
+ * @return array
+ */
+ public static function MMULT($matrixData1, $matrixData2)
+ {
+ $matrixAData = $matrixBData = array();
+ if (!is_array($matrixData1)) {
+ $matrixData1 = array(array($matrixData1));
+ }
+ if (!is_array($matrixData2)) {
+ $matrixData2 = array(array($matrixData2));
+ }
+
+ try {
+ $rowA = 0;
+ foreach ($matrixData1 as $matrixRow) {
+ if (!is_array($matrixRow)) {
+ $matrixRow = array($matrixRow);
+ }
+ $columnA = 0;
+ foreach ($matrixRow as $matrixCell) {
+ if ((!is_numeric($matrixCell)) || ($matrixCell === null)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $matrixAData[$rowA][$columnA] = $matrixCell;
+ ++$columnA;
+ }
+ ++$rowA;
+ }
+ $matrixA = new PHPExcel_Shared_JAMA_Matrix($matrixAData);
+ $rowB = 0;
+ foreach ($matrixData2 as $matrixRow) {
+ if (!is_array($matrixRow)) {
+ $matrixRow = array($matrixRow);
+ }
+ $columnB = 0;
+ foreach ($matrixRow as $matrixCell) {
+ if ((!is_numeric($matrixCell)) || ($matrixCell === null)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $matrixBData[$rowB][$columnB] = $matrixCell;
+ ++$columnB;
+ }
+ ++$rowB;
+ }
+ $matrixB = new PHPExcel_Shared_JAMA_Matrix($matrixBData);
+
+ if ($columnA != $rowB) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ return $matrixA->times($matrixB)->getArray();
+ } catch (PHPExcel_Exception $ex) {
+ var_dump($ex->getMessage());
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+
+
+ /**
+ * MOD
+ *
+ * @param int $a Dividend
+ * @param int $b Divisor
+ * @return int Remainder
+ */
+ public static function MOD($a = 1, $b = 1)
+ {
+ $a = PHPExcel_Calculation_Functions::flattenSingleValue($a);
+ $b = PHPExcel_Calculation_Functions::flattenSingleValue($b);
+
+ if ($b == 0.0) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ } elseif (($a < 0.0) && ($b > 0.0)) {
+ return $b - fmod(abs($a), $b);
+ } elseif (($a > 0.0) && ($b < 0.0)) {
+ return $b + fmod($a, abs($b));
+ }
+
+ return fmod($a, $b);
+ }
+
+
+ /**
+ * MROUND
+ *
+ * Rounds a number to the nearest multiple of a specified value
+ *
+ * @param float $number Number to round
+ * @param int $multiple Multiple to which you want to round $number
+ * @return float Rounded Number
+ */
+ public static function MROUND($number, $multiple)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $multiple = PHPExcel_Calculation_Functions::flattenSingleValue($multiple);
+
+ if ((is_numeric($number)) && (is_numeric($multiple))) {
+ if ($multiple == 0) {
+ return 0;
+ }
+ if ((self::SIGN($number)) == (self::SIGN($multiple))) {
+ $multiplier = 1 / $multiple;
+ return round($number * $multiplier) / $multiplier;
+ }
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * MULTINOMIAL
+ *
+ * Returns the ratio of the factorial of a sum of values to the product of factorials.
+ *
+ * @param array of mixed Data Series
+ * @return float
+ */
+ public static function MULTINOMIAL()
+ {
+ $summer = 0;
+ $divisor = 1;
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) {
+ // Is it a numeric value?
+ if (is_numeric($arg)) {
+ if ($arg < 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $summer += floor($arg);
+ $divisor *= self::FACT($arg);
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+
+ // Return
+ if ($summer > 0) {
+ $summer = self::FACT($summer);
+ return $summer / $divisor;
+ }
+ return 0;
+ }
+
+
+ /**
+ * ODD
+ *
+ * Returns number rounded up to the nearest odd integer.
+ *
+ * @param float $number Number to round
+ * @return int Rounded Number
+ */
+ public static function ODD($number)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+
+ if (is_null($number)) {
+ return 1;
+ } elseif (is_bool($number)) {
+ return 1;
+ } elseif (is_numeric($number)) {
+ $significance = self::SIGN($number);
+ if ($significance == 0) {
+ return 1;
+ }
+
+ $result = self::CEILING($number, $significance);
+ if ($result == self::EVEN($result)) {
+ $result += $significance;
+ }
+
+ return (int) $result;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * POWER
+ *
+ * Computes x raised to the power y.
+ *
+ * @param float $x
+ * @param float $y
+ * @return float
+ */
+ public static function POWER($x = 0, $y = 2)
+ {
+ $x = PHPExcel_Calculation_Functions::flattenSingleValue($x);
+ $y = PHPExcel_Calculation_Functions::flattenSingleValue($y);
+
+ // Validate parameters
+ if ($x == 0.0 && $y == 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif ($x == 0.0 && $y < 0.0) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ // Return
+ $result = pow($x, $y);
+ return (!is_nan($result) && !is_infinite($result)) ? $result : PHPExcel_Calculation_Functions::NaN();
+ }
+
+
+ /**
+ * PRODUCT
+ *
+ * PRODUCT returns the product of all the values and cells referenced in the argument list.
+ *
+ * Excel Function:
+ * PRODUCT(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function PRODUCT()
+ {
+ // Return value
+ $returnValue = null;
+
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = $arg;
+ } else {
+ $returnValue *= $arg;
+ }
+ }
+ }
+
+ // Return
+ if (is_null($returnValue)) {
+ return 0;
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * QUOTIENT
+ *
+ * QUOTIENT function returns the integer portion of a division. Numerator is the divided number
+ * and denominator is the divisor.
+ *
+ * Excel Function:
+ * QUOTIENT(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function QUOTIENT()
+ {
+ // Return value
+ $returnValue = null;
+
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = ($arg == 0) ? 0 : $arg;
+ } else {
+ if (($returnValue == 0) || ($arg == 0)) {
+ $returnValue = 0;
+ } else {
+ $returnValue /= $arg;
+ }
+ }
+ }
+ }
+
+ // Return
+ return intval($returnValue);
+ }
+
+
+ /**
+ * RAND
+ *
+ * @param int $min Minimal value
+ * @param int $max Maximal value
+ * @return int Random number
+ */
+ public static function RAND($min = 0, $max = 0)
+ {
+ $min = PHPExcel_Calculation_Functions::flattenSingleValue($min);
+ $max = PHPExcel_Calculation_Functions::flattenSingleValue($max);
+
+ if ($min == 0 && $max == 0) {
+ return (mt_rand(0, 10000000)) / 10000000;
+ } else {
+ return mt_rand($min, $max);
+ }
+ }
+
+
+ public static function ROMAN($aValue, $style = 0)
+ {
+ $aValue = PHPExcel_Calculation_Functions::flattenSingleValue($aValue);
+ $style = (is_null($style)) ? 0 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($style);
+ if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $aValue = (integer) $aValue;
+ if ($aValue == 0) {
+ return '';
+ }
+
+ $mill = array('', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM');
+ $cent = array('', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM');
+ $tens = array('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC');
+ $ones = array('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX');
+
+ $roman = '';
+ while ($aValue > 5999) {
+ $roman .= 'M';
+ $aValue -= 1000;
+ }
+ $m = self::romanCut($aValue, 1000);
+ $aValue %= 1000;
+ $c = self::romanCut($aValue, 100);
+ $aValue %= 100;
+ $t = self::romanCut($aValue, 10);
+ $aValue %= 10;
+
+ return $roman.$mill[$m].$cent[$c].$tens[$t].$ones[$aValue];
+ }
+
+
+ /**
+ * ROUNDUP
+ *
+ * Rounds a number up to a specified number of decimal places
+ *
+ * @param float $number Number to round
+ * @param int $digits Number of digits to which you want to round $number
+ * @return float Rounded Number
+ */
+ public static function ROUNDUP($number, $digits)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $digits = PHPExcel_Calculation_Functions::flattenSingleValue($digits);
+
+ if ((is_numeric($number)) && (is_numeric($digits))) {
+ $significance = pow(10, (int) $digits);
+ if ($number < 0.0) {
+ return floor($number * $significance) / $significance;
+ } else {
+ return ceil($number * $significance) / $significance;
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * ROUNDDOWN
+ *
+ * Rounds a number down to a specified number of decimal places
+ *
+ * @param float $number Number to round
+ * @param int $digits Number of digits to which you want to round $number
+ * @return float Rounded Number
+ */
+ public static function ROUNDDOWN($number, $digits)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+ $digits = PHPExcel_Calculation_Functions::flattenSingleValue($digits);
+
+ if ((is_numeric($number)) && (is_numeric($digits))) {
+ $significance = pow(10, (int) $digits);
+ if ($number < 0.0) {
+ return ceil($number * $significance) / $significance;
+ } else {
+ return floor($number * $significance) / $significance;
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SERIESSUM
+ *
+ * Returns the sum of a power series
+ *
+ * @param float $x Input value to the power series
+ * @param float $n Initial power to which you want to raise $x
+ * @param float $m Step by which to increase $n for each term in the series
+ * @param array of mixed Data Series
+ * @return float
+ */
+ public static function SERIESSUM()
+ {
+ $returnValue = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ $x = array_shift($aArgs);
+ $n = array_shift($aArgs);
+ $m = array_shift($aArgs);
+
+ if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
+ // Calculate
+ $i = 0;
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $returnValue += $arg * pow($x, $n + ($m * $i++));
+ } else {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ }
+ return $returnValue;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SIGN
+ *
+ * Determines the sign of a number. Returns 1 if the number is positive, zero (0)
+ * if the number is 0, and -1 if the number is negative.
+ *
+ * @param float $number Number to round
+ * @return int sign value
+ */
+ public static function SIGN($number)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+
+ if (is_bool($number)) {
+ return (int) $number;
+ }
+ if (is_numeric($number)) {
+ if ($number == 0.0) {
+ return 0;
+ }
+ return $number / abs($number);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SQRTPI
+ *
+ * Returns the square root of (number * pi).
+ *
+ * @param float $number Number
+ * @return float Square Root of Number * Pi
+ */
+ public static function SQRTPI($number)
+ {
+ $number = PHPExcel_Calculation_Functions::flattenSingleValue($number);
+
+ if (is_numeric($number)) {
+ if ($number < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return sqrt($number * M_PI) ;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SUBTOTAL
+ *
+ * Returns a subtotal in a list or database.
+ *
+ * @param int the number 1 to 11 that specifies which function to
+ * use in calculating subtotals within a list.
+ * @param array of mixed Data Series
+ * @return float
+ */
+ public static function SUBTOTAL()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $subtotal = array_shift($aArgs);
+
+ if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
+ switch ($subtotal) {
+ case 1:
+ return PHPExcel_Calculation_Statistical::AVERAGE($aArgs);
+ case 2:
+ return PHPExcel_Calculation_Statistical::COUNT($aArgs);
+ case 3:
+ return PHPExcel_Calculation_Statistical::COUNTA($aArgs);
+ case 4:
+ return PHPExcel_Calculation_Statistical::MAX($aArgs);
+ case 5:
+ return PHPExcel_Calculation_Statistical::MIN($aArgs);
+ case 6:
+ return self::PRODUCT($aArgs);
+ case 7:
+ return PHPExcel_Calculation_Statistical::STDEV($aArgs);
+ case 8:
+ return PHPExcel_Calculation_Statistical::STDEVP($aArgs);
+ case 9:
+ return self::SUM($aArgs);
+ case 10:
+ return PHPExcel_Calculation_Statistical::VARFunc($aArgs);
+ case 11:
+ return PHPExcel_Calculation_Statistical::VARP($aArgs);
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SUM
+ *
+ * SUM computes the sum of all the values and cells referenced in the argument list.
+ *
+ * Excel Function:
+ * SUM(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function SUM()
+ {
+ $returnValue = 0;
+
+ // Loop through the arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $returnValue += $arg;
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * SUMIF
+ *
+ * Counts the number of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * SUMIF(value1[,value2[, ...]],condition)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @param string $condition The criteria that defines which cells will be summed.
+ * @return float
+ */
+ public static function SUMIF($aArgs, $condition, $sumArgs = array())
+ {
+ $returnValue = 0;
+
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
+ $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs);
+ if (empty($sumArgs)) {
+ $sumArgs = $aArgs;
+ }
+ $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
+ // Loop through arguments
+ foreach ($aArgs as $key => $arg) {
+ if (!is_numeric($arg)) {
+ $arg = str_replace('"', '""', $arg);
+ $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
+ }
+
+ $testCondition = '='.$arg.$condition;
+ if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
+ // Is it a value within our criteria
+ $returnValue += $sumArgs[$key];
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * SUMIFS
+ *
+ * Counts the number of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * SUMIFS(value1[,value2[, ...]],condition)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @param string $condition The criteria that defines which cells will be summed.
+ * @return float
+ */
+ public static function SUMIFS() {
+ $arrayList = func_get_args();
+
+ $sumArgs = PHPExcel_Calculation_Functions::flattenArray(array_shift($arrayList));
+
+ while (count($arrayList) > 0) {
+ $aArgsArray[] = PHPExcel_Calculation_Functions::flattenArray(array_shift($arrayList));
+ $conditions[] = PHPExcel_Calculation_Functions::ifCondition(array_shift($arrayList));
+ }
+
+ // Loop through each set of arguments and conditions
+ foreach ($conditions as $index => $condition) {
+ $aArgs = $aArgsArray[$index];
+ $wildcard = false;
+ if ((strpos($condition, '*') !== false) || (strpos($condition, '?') !== false)) {
+ // * and ? are wildcard characters.
+ // Use ~* and ~? for literal star and question mark
+ // Code logic doesn't yet handle escaping
+ $condition = trim(ltrim($condition, '=<>'), '"');
+ $wildcard = true;
+ }
+ // Loop through arguments
+ foreach ($aArgs as $key => $arg) {
+ if ($wildcard) {
+ if (!fnmatch($condition, $arg, FNM_CASEFOLD)) {
+ // Is it a value within our criteria
+ $sumArgs[$key] = 0.0;
+ }
+ } else {
+ if (!is_numeric($arg)) {
+ $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
+ }
+ $testCondition = '='.$arg.$condition;
+ if (!PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
+ // Is it a value within our criteria
+ $sumArgs[$key] = 0.0;
+ }
+ }
+ }
+ }
+
+ // Return
+ return array_sum($sumArgs);
+ }
+
+
+ /**
+ * SUMPRODUCT
+ *
+ * Excel Function:
+ * SUMPRODUCT(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function SUMPRODUCT()
+ {
+ $arrayList = func_get_args();
+
+ $wrkArray = PHPExcel_Calculation_Functions::flattenArray(array_shift($arrayList));
+ $wrkCellCount = count($wrkArray);
+
+ for ($i=0; $i< $wrkCellCount; ++$i) {
+ if ((!is_numeric($wrkArray[$i])) || (is_string($wrkArray[$i]))) {
+ $wrkArray[$i] = 0;
+ }
+ }
+
+ foreach ($arrayList as $matrixData) {
+ $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData);
+ $count = count($array2);
+ if ($wrkCellCount != $count) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ foreach ($array2 as $i => $val) {
+ if ((!is_numeric($val)) || (is_string($val))) {
+ $val = 0;
+ }
+ $wrkArray[$i] *= $val;
+ }
+ }
+
+ return array_sum($wrkArray);
+ }
+
+
+ /**
+ * SUMSQ
+ *
+ * SUMSQ returns the sum of the squares of the arguments
+ *
+ * Excel Function:
+ * SUMSQ(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function SUMSQ()
+ {
+ $returnValue = 0;
+
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $returnValue += ($arg * $arg);
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * SUMX2MY2
+ *
+ * @param mixed[] $matrixData1 Matrix #1
+ * @param mixed[] $matrixData2 Matrix #2
+ * @return float
+ */
+ public static function SUMX2MY2($matrixData1, $matrixData2)
+ {
+ $array1 = PHPExcel_Calculation_Functions::flattenArray($matrixData1);
+ $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData2);
+ $count = min(count($array1), count($array2));
+
+ $result = 0;
+ for ($i = 0; $i < $count; ++$i) {
+ if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
+ ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
+ $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]);
+ }
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * SUMX2PY2
+ *
+ * @param mixed[] $matrixData1 Matrix #1
+ * @param mixed[] $matrixData2 Matrix #2
+ * @return float
+ */
+ public static function SUMX2PY2($matrixData1, $matrixData2)
+ {
+ $array1 = PHPExcel_Calculation_Functions::flattenArray($matrixData1);
+ $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData2);
+ $count = min(count($array1), count($array2));
+
+ $result = 0;
+ for ($i = 0; $i < $count; ++$i) {
+ if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
+ ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
+ $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]);
+ }
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * SUMXMY2
+ *
+ * @param mixed[] $matrixData1 Matrix #1
+ * @param mixed[] $matrixData2 Matrix #2
+ * @return float
+ */
+ public static function SUMXMY2($matrixData1, $matrixData2)
+ {
+ $array1 = PHPExcel_Calculation_Functions::flattenArray($matrixData1);
+ $array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData2);
+ $count = min(count($array1), count($array2));
+
+ $result = 0;
+ for ($i = 0; $i < $count; ++$i) {
+ if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
+ ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
+ $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]);
+ }
+ }
+
+ return $result;
+ }
+
+
+ /**
+ * TRUNC
+ *
+ * Truncates value to the number of fractional digits by number_digits.
+ *
+ * @param float $value
+ * @param int $digits
+ * @return float Truncated value
+ */
+ public static function TRUNC($value = 0, $digits = 0)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $digits = PHPExcel_Calculation_Functions::flattenSingleValue($digits);
+
+ // Validate parameters
+ if ((!is_numeric($value)) || (!is_numeric($digits))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $digits = floor($digits);
+
+ // Truncate
+ $adjust = pow(10, $digits);
+
+ if (($digits > 0) && (rtrim(intval((abs($value) - abs(intval($value))) * $adjust), '0') < $adjust/10)) {
+ return $value;
+ }
+
+ return (intval($value * $adjust)) / $adjust;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Statistical.php b/extend/PHPExcel/PHPExcel/Calculation/Statistical.php
new file mode 100755
index 0000000..1a33610
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Statistical.php
@@ -0,0 +1,3745 @@
+ $value) {
+ if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
+ unset($array1[$key]);
+ unset($array2[$key]);
+ }
+ }
+ foreach ($array2 as $key => $value) {
+ if ((is_bool($value)) || (is_string($value)) || (is_null($value))) {
+ unset($array1[$key]);
+ unset($array2[$key]);
+ }
+ }
+ $array1 = array_merge($array1);
+ $array2 = array_merge($array2);
+
+ return true;
+ }
+
+
+ /**
+ * Beta function.
+ *
+ * @author Jaco van Kooten
+ *
+ * @param p require p>0
+ * @param q require q>0
+ * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
+ */
+ private static function beta($p, $q)
+ {
+ if ($p <= 0.0 || $q <= 0.0 || ($p + $q) > LOG_GAMMA_X_MAX_VALUE) {
+ return 0.0;
+ } else {
+ return exp(self::logBeta($p, $q));
+ }
+ }
+
+
+ /**
+ * Incomplete beta function
+ *
+ * @author Jaco van Kooten
+ * @author Paul Meagher
+ *
+ * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992).
+ * @param x require 0<=x<=1
+ * @param p require p>0
+ * @param q require q>0
+ * @return 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow
+ */
+ private static function incompleteBeta($x, $p, $q)
+ {
+ if ($x <= 0.0) {
+ return 0.0;
+ } elseif ($x >= 1.0) {
+ return 1.0;
+ } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
+ return 0.0;
+ }
+ $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x));
+ if ($x < ($p + 1.0) / ($p + $q + 2.0)) {
+ return $beta_gam * self::betaFraction($x, $p, $q) / $p;
+ } else {
+ return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q);
+ }
+ }
+
+
+ // Function cache for logBeta function
+ private static $logBetaCacheP = 0.0;
+ private static $logBetaCacheQ = 0.0;
+ private static $logBetaCacheResult = 0.0;
+
+ /**
+ * The natural logarithm of the beta function.
+ *
+ * @param p require p>0
+ * @param q require q>0
+ * @return 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow
+ * @author Jaco van Kooten
+ */
+ private static function logBeta($p, $q)
+ {
+ if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) {
+ self::$logBetaCacheP = $p;
+ self::$logBetaCacheQ = $q;
+ if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > LOG_GAMMA_X_MAX_VALUE)) {
+ self::$logBetaCacheResult = 0.0;
+ } else {
+ self::$logBetaCacheResult = self::logGamma($p) + self::logGamma($q) - self::logGamma($p + $q);
+ }
+ }
+ return self::$logBetaCacheResult;
+ }
+
+
+ /**
+ * Evaluates of continued fraction part of incomplete beta function.
+ * Based on an idea from Numerical Recipes (W.H. Press et al, 1992).
+ * @author Jaco van Kooten
+ */
+ private static function betaFraction($x, $p, $q)
+ {
+ $c = 1.0;
+ $sum_pq = $p + $q;
+ $p_plus = $p + 1.0;
+ $p_minus = $p - 1.0;
+ $h = 1.0 - $sum_pq * $x / $p_plus;
+ if (abs($h) < XMININ) {
+ $h = XMININ;
+ }
+ $h = 1.0 / $h;
+ $frac = $h;
+ $m = 1;
+ $delta = 0.0;
+ while ($m <= MAX_ITERATIONS && abs($delta-1.0) > PRECISION) {
+ $m2 = 2 * $m;
+ // even index for d
+ $d = $m * ($q - $m) * $x / ( ($p_minus + $m2) * ($p + $m2));
+ $h = 1.0 + $d * $h;
+ if (abs($h) < XMININ) {
+ $h = XMININ;
+ }
+ $h = 1.0 / $h;
+ $c = 1.0 + $d / $c;
+ if (abs($c) < XMININ) {
+ $c = XMININ;
+ }
+ $frac *= $h * $c;
+ // odd index for d
+ $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2));
+ $h = 1.0 + $d * $h;
+ if (abs($h) < XMININ) {
+ $h = XMININ;
+ }
+ $h = 1.0 / $h;
+ $c = 1.0 + $d / $c;
+ if (abs($c) < XMININ) {
+ $c = XMININ;
+ }
+ $delta = $h * $c;
+ $frac *= $delta;
+ ++$m;
+ }
+ return $frac;
+ }
+
+
+ /**
+ * logGamma function
+ *
+ * @version 1.1
+ * @author Jaco van Kooten
+ *
+ * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher.
+ *
+ * The natural logarithm of the gamma function.
+ * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
+ * Applied Mathematics Division
+ * Argonne National Laboratory
+ * Argonne, IL 60439
+ *
+ * References:
+ *
+ * W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural
+ * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
+ * K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
+ * Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
+ *
+ *
+ *
+ * From the original documentation:
+ *
+ *
+ * This routine calculates the LOG(GAMMA) function for a positive real argument X.
+ * Computation is based on an algorithm outlined in references 1 and 2.
+ * The program uses rational functions that theoretically approximate LOG(GAMMA)
+ * to at least 18 significant decimal digits. The approximation for X > 12 is from
+ * reference 3, while approximations for X < 12.0 are similar to those in reference
+ * 1, but are unpublished. The accuracy achieved depends on the arithmetic system,
+ * the compiler, the intrinsic functions, and proper selection of the
+ * machine-dependent constants.
+ *
+ *
+ * Error returns:
+ * The program returns the value XINF for X .LE. 0.0 or when overflow would occur.
+ * The computation is believed to be free of underflow and overflow.
+ *
+ * @return MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305
+ */
+
+ // Function cache for logGamma
+ private static $logGammaCacheResult = 0.0;
+ private static $logGammaCacheX = 0.0;
+
+ private static function logGamma($x)
+ {
+ // Log Gamma related constants
+ static $lg_d1 = -0.5772156649015328605195174;
+ static $lg_d2 = 0.4227843350984671393993777;
+ static $lg_d4 = 1.791759469228055000094023;
+
+ static $lg_p1 = array(
+ 4.945235359296727046734888,
+ 201.8112620856775083915565,
+ 2290.838373831346393026739,
+ 11319.67205903380828685045,
+ 28557.24635671635335736389,
+ 38484.96228443793359990269,
+ 26377.48787624195437963534,
+ 7225.813979700288197698961
+ );
+ static $lg_p2 = array(
+ 4.974607845568932035012064,
+ 542.4138599891070494101986,
+ 15506.93864978364947665077,
+ 184793.2904445632425417223,
+ 1088204.76946882876749847,
+ 3338152.967987029735917223,
+ 5106661.678927352456275255,
+ 3074109.054850539556250927
+ );
+ static $lg_p4 = array(
+ 14745.02166059939948905062,
+ 2426813.369486704502836312,
+ 121475557.4045093227939592,
+ 2663432449.630976949898078,
+ 29403789566.34553899906876,
+ 170266573776.5398868392998,
+ 492612579337.743088758812,
+ 560625185622.3951465078242
+ );
+ static $lg_q1 = array(
+ 67.48212550303777196073036,
+ 1113.332393857199323513008,
+ 7738.757056935398733233834,
+ 27639.87074403340708898585,
+ 54993.10206226157329794414,
+ 61611.22180066002127833352,
+ 36351.27591501940507276287,
+ 8785.536302431013170870835
+ );
+ static $lg_q2 = array(
+ 183.0328399370592604055942,
+ 7765.049321445005871323047,
+ 133190.3827966074194402448,
+ 1136705.821321969608938755,
+ 5267964.117437946917577538,
+ 13467014.54311101692290052,
+ 17827365.30353274213975932,
+ 9533095.591844353613395747
+ );
+ static $lg_q4 = array(
+ 2690.530175870899333379843,
+ 639388.5654300092398984238,
+ 41355999.30241388052042842,
+ 1120872109.61614794137657,
+ 14886137286.78813811542398,
+ 101680358627.2438228077304,
+ 341747634550.7377132798597,
+ 446315818741.9713286462081
+ );
+ static $lg_c = array(
+ -0.001910444077728,
+ 8.4171387781295e-4,
+ -5.952379913043012e-4,
+ 7.93650793500350248e-4,
+ -0.002777777777777681622553,
+ 0.08333333333333333331554247,
+ 0.0057083835261
+ );
+
+ // Rough estimate of the fourth root of logGamma_xBig
+ static $lg_frtbig = 2.25e76;
+ static $pnt68 = 0.6796875;
+
+
+ if ($x == self::$logGammaCacheX) {
+ return self::$logGammaCacheResult;
+ }
+ $y = $x;
+ if ($y > 0.0 && $y <= LOG_GAMMA_X_MAX_VALUE) {
+ if ($y <= EPS) {
+ $res = -log(y);
+ } elseif ($y <= 1.5) {
+ // ---------------------
+ // EPS .LT. X .LE. 1.5
+ // ---------------------
+ if ($y < $pnt68) {
+ $corr = -log($y);
+ $xm1 = $y;
+ } else {
+ $corr = 0.0;
+ $xm1 = $y - 1.0;
+ }
+ if ($y <= 0.5 || $y >= $pnt68) {
+ $xden = 1.0;
+ $xnum = 0.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm1 + $lg_p1[$i];
+ $xden = $xden * $xm1 + $lg_q1[$i];
+ }
+ $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden));
+ } else {
+ $xm2 = $y - 1.0;
+ $xden = 1.0;
+ $xnum = 0.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm2 + $lg_p2[$i];
+ $xden = $xden * $xm2 + $lg_q2[$i];
+ }
+ $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
+ }
+ } elseif ($y <= 4.0) {
+ // ---------------------
+ // 1.5 .LT. X .LE. 4.0
+ // ---------------------
+ $xm2 = $y - 2.0;
+ $xden = 1.0;
+ $xnum = 0.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm2 + $lg_p2[$i];
+ $xden = $xden * $xm2 + $lg_q2[$i];
+ }
+ $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden));
+ } elseif ($y <= 12.0) {
+ // ----------------------
+ // 4.0 .LT. X .LE. 12.0
+ // ----------------------
+ $xm4 = $y - 4.0;
+ $xden = -1.0;
+ $xnum = 0.0;
+ for ($i = 0; $i < 8; ++$i) {
+ $xnum = $xnum * $xm4 + $lg_p4[$i];
+ $xden = $xden * $xm4 + $lg_q4[$i];
+ }
+ $res = $lg_d4 + $xm4 * ($xnum / $xden);
+ } else {
+ // ---------------------------------
+ // Evaluate for argument .GE. 12.0
+ // ---------------------------------
+ $res = 0.0;
+ if ($y <= $lg_frtbig) {
+ $res = $lg_c[6];
+ $ysq = $y * $y;
+ for ($i = 0; $i < 6; ++$i) {
+ $res = $res / $ysq + $lg_c[$i];
+ }
+ $res /= $y;
+ $corr = log($y);
+ $res = $res + log(SQRT2PI) - 0.5 * $corr;
+ $res += $y * ($corr - 1.0);
+ }
+ }
+ } else {
+ // --------------------------
+ // Return for bad arguments
+ // --------------------------
+ $res = MAX_VALUE;
+ }
+ // ------------------------------
+ // Final adjustments and return
+ // ------------------------------
+ self::$logGammaCacheX = $x;
+ self::$logGammaCacheResult = $res;
+ return $res;
+ }
+
+
+ //
+ // Private implementation of the incomplete Gamma function
+ //
+ private static function incompleteGamma($a, $x)
+ {
+ static $max = 32;
+ $summer = 0;
+ for ($n=0; $n<=$max; ++$n) {
+ $divisor = $a;
+ for ($i=1; $i<=$n; ++$i) {
+ $divisor *= ($a + $i);
+ }
+ $summer += (pow($x, $n) / $divisor);
+ }
+ return pow($x, $a) * exp(0-$x) * $summer;
+ }
+
+
+ //
+ // Private implementation of the Gamma function
+ //
+ private static function gamma($data)
+ {
+ if ($data == 0.0) {
+ return 0;
+ }
+
+ static $p0 = 1.000000000190015;
+ static $p = array(
+ 1 => 76.18009172947146,
+ 2 => -86.50532032941677,
+ 3 => 24.01409824083091,
+ 4 => -1.231739572450155,
+ 5 => 1.208650973866179e-3,
+ 6 => -5.395239384953e-6
+ );
+
+ $y = $x = $data;
+ $tmp = $x + 5.5;
+ $tmp -= ($x + 0.5) * log($tmp);
+
+ $summer = $p0;
+ for ($j=1; $j<=6; ++$j) {
+ $summer += ($p[$j] / ++$y);
+ }
+ return exp(0 - $tmp + log(SQRT2PI * $summer / $x));
+ }
+
+
+ /***************************************************************************
+ * inverse_ncdf.php
+ * -------------------
+ * begin : Friday, January 16, 2004
+ * copyright : (C) 2004 Michael Nickerson
+ * email : nickersonm@yahoo.com
+ *
+ ***************************************************************************/
+ private static function inverseNcdf($p)
+ {
+ // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to
+ // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as
+ // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
+ // I have not checked the accuracy of this implementation. Be aware that PHP
+ // will truncate the coeficcients to 14 digits.
+
+ // You have permission to use and distribute this function freely for
+ // whatever purpose you want, but please show common courtesy and give credit
+ // where credit is due.
+
+ // Input paramater is $p - probability - where 0 < p < 1.
+
+ // Coefficients in rational approximations
+ static $a = array(
+ 1 => -3.969683028665376e+01,
+ 2 => 2.209460984245205e+02,
+ 3 => -2.759285104469687e+02,
+ 4 => 1.383577518672690e+02,
+ 5 => -3.066479806614716e+01,
+ 6 => 2.506628277459239e+00
+ );
+
+ static $b = array(
+ 1 => -5.447609879822406e+01,
+ 2 => 1.615858368580409e+02,
+ 3 => -1.556989798598866e+02,
+ 4 => 6.680131188771972e+01,
+ 5 => -1.328068155288572e+01
+ );
+
+ static $c = array(
+ 1 => -7.784894002430293e-03,
+ 2 => -3.223964580411365e-01,
+ 3 => -2.400758277161838e+00,
+ 4 => -2.549732539343734e+00,
+ 5 => 4.374664141464968e+00,
+ 6 => 2.938163982698783e+00
+ );
+
+ static $d = array(
+ 1 => 7.784695709041462e-03,
+ 2 => 3.224671290700398e-01,
+ 3 => 2.445134137142996e+00,
+ 4 => 3.754408661907416e+00
+ );
+
+ // Define lower and upper region break-points.
+ $p_low = 0.02425; //Use lower region approx. below this
+ $p_high = 1 - $p_low; //Use upper region approx. above this
+
+ if (0 < $p && $p < $p_low) {
+ // Rational approximation for lower region.
+ $q = sqrt(-2 * log($p));
+ return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
+ (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
+ } elseif ($p_low <= $p && $p <= $p_high) {
+ // Rational approximation for central region.
+ $q = $p - 0.5;
+ $r = $q * $q;
+ return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q /
+ ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1);
+ } elseif ($p_high < $p && $p < 1) {
+ // Rational approximation for upper region.
+ $q = sqrt(-2 * log(1 - $p));
+ return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) /
+ (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
+ }
+ // If 0 < p < 1, return a null value
+ return PHPExcel_Calculation_Functions::NULL();
+ }
+
+
+ private static function inverseNcdf2($prob)
+ {
+ // Approximation of inverse standard normal CDF developed by
+ // B. Moro, "The Full Monte," Risk 8(2), Feb 1995, 57-58.
+
+ $a1 = 2.50662823884;
+ $a2 = -18.61500062529;
+ $a3 = 41.39119773534;
+ $a4 = -25.44106049637;
+
+ $b1 = -8.4735109309;
+ $b2 = 23.08336743743;
+ $b3 = -21.06224101826;
+ $b4 = 3.13082909833;
+
+ $c1 = 0.337475482272615;
+ $c2 = 0.976169019091719;
+ $c3 = 0.160797971491821;
+ $c4 = 2.76438810333863E-02;
+ $c5 = 3.8405729373609E-03;
+ $c6 = 3.951896511919E-04;
+ $c7 = 3.21767881768E-05;
+ $c8 = 2.888167364E-07;
+ $c9 = 3.960315187E-07;
+
+ $y = $prob - 0.5;
+ if (abs($y) < 0.42) {
+ $z = ($y * $y);
+ $z = $y * ((($a4 * $z + $a3) * $z + $a2) * $z + $a1) / (((($b4 * $z + $b3) * $z + $b2) * $z + $b1) * $z + 1);
+ } else {
+ if ($y > 0) {
+ $z = log(-log(1 - $prob));
+ } else {
+ $z = log(-log($prob));
+ }
+ $z = $c1 + $z * ($c2 + $z * ($c3 + $z * ($c4 + $z * ($c5 + $z * ($c6 + $z * ($c7 + $z * ($c8 + $z * $c9)))))));
+ if ($y < 0) {
+ $z = -$z;
+ }
+ }
+ return $z;
+ } // function inverseNcdf2()
+
+
+ private static function inverseNcdf3($p)
+ {
+ // ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3.
+ // Produces the normal deviate Z corresponding to a given lower
+ // tail area of P; Z is accurate to about 1 part in 10**16.
+ //
+ // This is a PHP version of the original FORTRAN code that can
+ // be found at http://lib.stat.cmu.edu/apstat/
+ $split1 = 0.425;
+ $split2 = 5;
+ $const1 = 0.180625;
+ $const2 = 1.6;
+
+ // coefficients for p close to 0.5
+ $a0 = 3.3871328727963666080;
+ $a1 = 1.3314166789178437745E+2;
+ $a2 = 1.9715909503065514427E+3;
+ $a3 = 1.3731693765509461125E+4;
+ $a4 = 4.5921953931549871457E+4;
+ $a5 = 6.7265770927008700853E+4;
+ $a6 = 3.3430575583588128105E+4;
+ $a7 = 2.5090809287301226727E+3;
+
+ $b1 = 4.2313330701600911252E+1;
+ $b2 = 6.8718700749205790830E+2;
+ $b3 = 5.3941960214247511077E+3;
+ $b4 = 2.1213794301586595867E+4;
+ $b5 = 3.9307895800092710610E+4;
+ $b6 = 2.8729085735721942674E+4;
+ $b7 = 5.2264952788528545610E+3;
+
+ // coefficients for p not close to 0, 0.5 or 1.
+ $c0 = 1.42343711074968357734;
+ $c1 = 4.63033784615654529590;
+ $c2 = 5.76949722146069140550;
+ $c3 = 3.64784832476320460504;
+ $c4 = 1.27045825245236838258;
+ $c5 = 2.41780725177450611770E-1;
+ $c6 = 2.27238449892691845833E-2;
+ $c7 = 7.74545014278341407640E-4;
+
+ $d1 = 2.05319162663775882187;
+ $d2 = 1.67638483018380384940;
+ $d3 = 6.89767334985100004550E-1;
+ $d4 = 1.48103976427480074590E-1;
+ $d5 = 1.51986665636164571966E-2;
+ $d6 = 5.47593808499534494600E-4;
+ $d7 = 1.05075007164441684324E-9;
+
+ // coefficients for p near 0 or 1.
+ $e0 = 6.65790464350110377720;
+ $e1 = 5.46378491116411436990;
+ $e2 = 1.78482653991729133580;
+ $e3 = 2.96560571828504891230E-1;
+ $e4 = 2.65321895265761230930E-2;
+ $e5 = 1.24266094738807843860E-3;
+ $e6 = 2.71155556874348757815E-5;
+ $e7 = 2.01033439929228813265E-7;
+
+ $f1 = 5.99832206555887937690E-1;
+ $f2 = 1.36929880922735805310E-1;
+ $f3 = 1.48753612908506148525E-2;
+ $f4 = 7.86869131145613259100E-4;
+ $f5 = 1.84631831751005468180E-5;
+ $f6 = 1.42151175831644588870E-7;
+ $f7 = 2.04426310338993978564E-15;
+
+ $q = $p - 0.5;
+
+ // computation for p close to 0.5
+ if (abs($q) <= split1) {
+ $R = $const1 - $q * $q;
+ $z = $q * ((((((($a7 * $R + $a6) * $R + $a5) * $R + $a4) * $R + $a3) * $R + $a2) * $R + $a1) * $R + $a0) /
+ ((((((($b7 * $R + $b6) * $R + $b5) * $R + $b4) * $R + $b3) * $R + $b2) * $R + $b1) * $R + 1);
+ } else {
+ if ($q < 0) {
+ $R = $p;
+ } else {
+ $R = 1 - $p;
+ }
+ $R = pow(-log($R), 2);
+
+ // computation for p not close to 0, 0.5 or 1.
+ if ($R <= $split2) {
+ $R = $R - $const2;
+ $z = ((((((($c7 * $R + $c6) * $R + $c5) * $R + $c4) * $R + $c3) * $R + $c2) * $R + $c1) * $R + $c0) /
+ ((((((($d7 * $R + $d6) * $R + $d5) * $R + $d4) * $R + $d3) * $R + $d2) * $R + $d1) * $R + 1);
+ } else {
+ // computation for p near 0 or 1.
+ $R = $R - $split2;
+ $z = ((((((($e7 * $R + $e6) * $R + $e5) * $R + $e4) * $R + $e3) * $R + $e2) * $R + $e1) * $R + $e0) /
+ ((((((($f7 * $R + $f6) * $R + $f5) * $R + $f4) * $R + $f3) * $R + $f2) * $R + $f1) * $R + 1);
+ }
+ if ($q < 0) {
+ $z = -$z;
+ }
+ }
+ return $z;
+ }
+
+
+ /**
+ * AVEDEV
+ *
+ * Returns the average of the absolute deviations of data points from their mean.
+ * AVEDEV is a measure of the variability in a data set.
+ *
+ * Excel Function:
+ * AVEDEV(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function AVEDEV()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+
+ // Return value
+ $returnValue = null;
+
+ $aMean = self::AVERAGE($aArgs);
+ if ($aMean != PHPExcel_Calculation_Functions::DIV0()) {
+ $aCount = 0;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = abs($arg - $aMean);
+ } else {
+ $returnValue += abs($arg - $aMean);
+ }
+ ++$aCount;
+ }
+ }
+
+ // Return
+ if ($aCount == 0) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+ return $returnValue / $aCount;
+ }
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+
+ /**
+ * AVERAGE
+ *
+ * Returns the average (arithmetic mean) of the arguments
+ *
+ * Excel Function:
+ * AVERAGE(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function AVERAGE()
+ {
+ $returnValue = $aCount = 0;
+
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) {
+ if ((is_bool($arg)) &&
+ ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = $arg;
+ } else {
+ $returnValue += $arg;
+ }
+ ++$aCount;
+ }
+ }
+
+ // Return
+ if ($aCount > 0) {
+ return $returnValue / $aCount;
+ } else {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+ }
+
+
+ /**
+ * AVERAGEA
+ *
+ * Returns the average of its arguments, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * AVERAGEA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function AVERAGEA()
+ {
+ $returnValue = null;
+
+ $aCount = 0;
+ // Loop through arguments
+ foreach (PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args()) as $k => $arg) {
+ if ((is_bool($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ if (is_null($returnValue)) {
+ $returnValue = $arg;
+ } else {
+ $returnValue += $arg;
+ }
+ ++$aCount;
+ }
+ }
+ }
+
+ if ($aCount > 0) {
+ return $returnValue / $aCount;
+ } else {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+ }
+
+
+ /**
+ * AVERAGEIF
+ *
+ * Returns the average value from a range of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * AVERAGEIF(value1[,value2[, ...]],condition)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @param string $condition The criteria that defines which cells will be checked.
+ * @param mixed[] $averageArgs Data values
+ * @return float
+ */
+ public static function AVERAGEIF($aArgs, $condition, $averageArgs = array())
+ {
+ $returnValue = 0;
+
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
+ $averageArgs = PHPExcel_Calculation_Functions::flattenArray($averageArgs);
+ if (empty($averageArgs)) {
+ $averageArgs = $aArgs;
+ }
+ $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
+ // Loop through arguments
+ $aCount = 0;
+ foreach ($aArgs as $key => $arg) {
+ if (!is_numeric($arg)) {
+ $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
+ }
+ $testCondition = '='.$arg.$condition;
+ if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
+ if ((is_null($returnValue)) || ($arg > $returnValue)) {
+ $returnValue += $arg;
+ ++$aCount;
+ }
+ }
+ }
+
+ if ($aCount > 0) {
+ return $returnValue / $aCount;
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * BETADIST
+ *
+ * Returns the beta distribution.
+ *
+ * @param float $value Value at which you want to evaluate the distribution
+ * @param float $alpha Parameter to the distribution
+ * @param float $beta Parameter to the distribution
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
+ $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
+ $rMin = PHPExcel_Calculation_Functions::flattenSingleValue($rMin);
+ $rMax = PHPExcel_Calculation_Functions::flattenSingleValue($rMax);
+
+ if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
+ if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($rMin > $rMax) {
+ $tmp = $rMin;
+ $rMin = $rMax;
+ $rMax = $tmp;
+ }
+ $value -= $rMin;
+ $value /= ($rMax - $rMin);
+ return self::incompleteBeta($value, $alpha, $beta);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * BETAINV
+ *
+ * Returns the inverse of the beta distribution.
+ *
+ * @param float $probability Probability at which you want to evaluate the distribution
+ * @param float $alpha Parameter to the distribution
+ * @param float $beta Parameter to the distribution
+ * @param float $rMin Minimum value
+ * @param float $rMax Maximum value
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1)
+ {
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
+ $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
+ $rMin = PHPExcel_Calculation_Functions::flattenSingleValue($rMin);
+ $rMax = PHPExcel_Calculation_Functions::flattenSingleValue($rMax);
+
+ if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) {
+ if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($rMin > $rMax) {
+ $tmp = $rMin;
+ $rMin = $rMax;
+ $rMax = $tmp;
+ }
+ $a = 0;
+ $b = 2;
+
+ $i = 0;
+ while ((($b - $a) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
+ $guess = ($a + $b) / 2;
+ $result = self::BETADIST($guess, $alpha, $beta);
+ if (($result == $probability) || ($result == 0)) {
+ $b = $a;
+ } elseif ($result > $probability) {
+ $b = $guess;
+ } else {
+ $a = $guess;
+ }
+ }
+ if ($i == MAX_ITERATIONS) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ return round($rMin + $guess * ($rMax - $rMin), 12);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * BINOMDIST
+ *
+ * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with
+ * a fixed number of tests or trials, when the outcomes of any trial are only success or failure,
+ * when trials are independent, and when the probability of success is constant throughout the
+ * experiment. For example, BINOMDIST can calculate the probability that two of the next three
+ * babies born are male.
+ *
+ * @param float $value Number of successes in trials
+ * @param float $trials Number of trials
+ * @param float $probability Probability of success on each trial
+ * @param boolean $cumulative
+ * @return float
+ *
+ * @todo Cumulative distribution function
+ *
+ */
+ public static function BINOMDIST($value, $trials, $probability, $cumulative)
+ {
+ $value = floor(PHPExcel_Calculation_Functions::flattenSingleValue($value));
+ $trials = floor(PHPExcel_Calculation_Functions::flattenSingleValue($trials));
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+
+ if ((is_numeric($value)) && (is_numeric($trials)) && (is_numeric($probability))) {
+ if (($value < 0) || ($value > $trials)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (($probability < 0) || ($probability > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
+ if ($cumulative) {
+ $summer = 0;
+ for ($i = 0; $i <= $value; ++$i) {
+ $summer += PHPExcel_Calculation_MathTrig::COMBIN($trials, $i) * pow($probability, $i) * pow(1 - $probability, $trials - $i);
+ }
+ return $summer;
+ } else {
+ return PHPExcel_Calculation_MathTrig::COMBIN($trials, $value) * pow($probability, $value) * pow(1 - $probability, $trials - $value) ;
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * CHIDIST
+ *
+ * Returns the one-tailed probability of the chi-squared distribution.
+ *
+ * @param float $value Value for the function
+ * @param float $degrees degrees of freedom
+ * @return float
+ */
+ public static function CHIDIST($value, $degrees)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
+
+ if ((is_numeric($value)) && (is_numeric($degrees))) {
+ if ($degrees < 1) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($value < 0) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ return 1;
+ }
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return 1 - (self::incompleteGamma($degrees/2, $value/2) / self::gamma($degrees/2));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * CHIINV
+ *
+ * Returns the one-tailed probability of the chi-squared distribution.
+ *
+ * @param float $probability Probability for the function
+ * @param float $degrees degrees of freedom
+ * @return float
+ */
+ public static function CHIINV($probability, $degrees)
+ {
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
+
+ if ((is_numeric($probability)) && (is_numeric($degrees))) {
+ $xLo = 100;
+ $xHi = 0;
+
+ $x = $xNew = 1;
+ $dx = 1;
+ $i = 0;
+
+ while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
+ // Apply Newton-Raphson step
+ $result = self::CHIDIST($x, $degrees);
+ $error = $result - $probability;
+ if ($error == 0.0) {
+ $dx = 0;
+ } elseif ($error < 0.0) {
+ $xLo = $x;
+ } else {
+ $xHi = $x;
+ }
+ // Avoid division by zero
+ if ($result != 0.0) {
+ $dx = $error / $result;
+ $xNew = $x - $dx;
+ }
+ // If the NR fails to converge (which for example may be the
+ // case if the initial guess is too rough) we apply a bisection
+ // step to determine a more narrow interval around the root.
+ if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
+ $xNew = ($xLo + $xHi) / 2;
+ $dx = $xNew - $x;
+ }
+ $x = $xNew;
+ }
+ if ($i == MAX_ITERATIONS) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ return round($x, 12);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * CONFIDENCE
+ *
+ * Returns the confidence interval for a population mean
+ *
+ * @param float $alpha
+ * @param float $stdDev Standard Deviation
+ * @param float $size
+ * @return float
+ *
+ */
+ public static function CONFIDENCE($alpha, $stdDev, $size)
+ {
+ $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
+ $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
+ $size = floor(PHPExcel_Calculation_Functions::flattenSingleValue($size));
+
+ if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) {
+ if (($alpha <= 0) || ($alpha >= 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (($stdDev <= 0) || ($size < 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * CORREL
+ *
+ * Returns covariance, the average of the products of deviations for each data point pair.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function CORREL($yValues, $xValues = null)
+ {
+ if ((is_null($xValues)) || (!is_array($yValues)) || (!is_array($xValues))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getCorrelation();
+ }
+
+
+ /**
+ * COUNT
+ *
+ * Counts the number of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * COUNT(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return int
+ */
+ public static function COUNT()
+ {
+ $returnValue = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ ++$returnValue;
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * COUNTA
+ *
+ * Counts the number of cells that are not empty within the list of arguments
+ *
+ * Excel Function:
+ * COUNTA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return int
+ */
+ public static function COUNTA()
+ {
+ $returnValue = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a numeric, boolean or string value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
+ ++$returnValue;
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * COUNTBLANK
+ *
+ * Counts the number of empty cells within the list of arguments
+ *
+ * Excel Function:
+ * COUNTBLANK(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return int
+ */
+ public static function COUNTBLANK()
+ {
+ $returnValue = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a blank cell?
+ if ((is_null($arg)) || ((is_string($arg)) && ($arg == ''))) {
+ ++$returnValue;
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * COUNTIF
+ *
+ * Counts the number of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * COUNTIF(value1[,value2[, ...]],condition)
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @param string $condition The criteria that defines which cells will be counted.
+ * @return int
+ */
+ public static function COUNTIF($aArgs, $condition)
+ {
+ $returnValue = 0;
+
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
+ $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
+ // Loop through arguments
+ foreach ($aArgs as $arg) {
+ if (!is_numeric($arg)) {
+ $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
+ }
+ $testCondition = '='.$arg.$condition;
+ if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
+ // Is it a value within our criteria
+ ++$returnValue;
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * COVAR
+ *
+ * Returns covariance, the average of the products of deviations for each data point pair.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function COVAR($yValues, $xValues)
+ {
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getCovariance();
+ }
+
+
+ /**
+ * CRITBINOM
+ *
+ * Returns the smallest value for which the cumulative binomial distribution is greater
+ * than or equal to a criterion value
+ *
+ * See http://support.microsoft.com/kb/828117/ for details of the algorithm used
+ *
+ * @param float $trials number of Bernoulli trials
+ * @param float $probability probability of a success on each trial
+ * @param float $alpha criterion value
+ * @return int
+ *
+ * @todo Warning. This implementation differs from the algorithm detailed on the MS
+ * web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess
+ * This eliminates a potential endless loop error, but may have an adverse affect on the
+ * accuracy of the function (although all my tests have so far returned correct results).
+ *
+ */
+ public static function CRITBINOM($trials, $probability, $alpha)
+ {
+ $trials = floor(PHPExcel_Calculation_Functions::flattenSingleValue($trials));
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
+
+ if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) {
+ if ($trials < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (($probability < 0) || ($probability > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (($alpha < 0) || ($alpha > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif ($alpha <= 0.5) {
+ $t = sqrt(log(1 / ($alpha * $alpha)));
+ $trialsApprox = 0 - ($t + (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t));
+ } else {
+ $t = sqrt(log(1 / pow(1 - $alpha, 2)));
+ $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t);
+ }
+ $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability)));
+ if ($Guess < 0) {
+ $Guess = 0;
+ } elseif ($Guess > $trials) {
+ $Guess = $trials;
+ }
+
+ $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0;
+ $EssentiallyZero = 10e-12;
+
+ $m = floor($trials * $probability);
+ ++$TotalUnscaledProbability;
+ if ($m == $Guess) {
+ ++$UnscaledPGuess;
+ }
+ if ($m <= $Guess) {
+ ++$UnscaledCumPGuess;
+ }
+
+ $PreviousValue = 1;
+ $Done = false;
+ $k = $m + 1;
+ while ((!$Done) && ($k <= $trials)) {
+ $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability));
+ $TotalUnscaledProbability += $CurrentValue;
+ if ($k == $Guess) {
+ $UnscaledPGuess += $CurrentValue;
+ }
+ if ($k <= $Guess) {
+ $UnscaledCumPGuess += $CurrentValue;
+ }
+ if ($CurrentValue <= $EssentiallyZero) {
+ $Done = true;
+ }
+ $PreviousValue = $CurrentValue;
+ ++$k;
+ }
+
+ $PreviousValue = 1;
+ $Done = false;
+ $k = $m - 1;
+ while ((!$Done) && ($k >= 0)) {
+ $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability);
+ $TotalUnscaledProbability += $CurrentValue;
+ if ($k == $Guess) {
+ $UnscaledPGuess += $CurrentValue;
+ }
+ if ($k <= $Guess) {
+ $UnscaledCumPGuess += $CurrentValue;
+ }
+ if ($CurrentValue <= $EssentiallyZero) {
+ $Done = true;
+ }
+ $PreviousValue = $CurrentValue;
+ --$k;
+ }
+
+ $PGuess = $UnscaledPGuess / $TotalUnscaledProbability;
+ $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability;
+
+// $CumPGuessMinus1 = $CumPGuess - $PGuess;
+ $CumPGuessMinus1 = $CumPGuess - 1;
+
+ while (true) {
+ if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) {
+ return $Guess;
+ } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) {
+ $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability);
+ $CumPGuessMinus1 = $CumPGuess;
+ $CumPGuess = $CumPGuess + $PGuessPlus1;
+ $PGuess = $PGuessPlus1;
+ ++$Guess;
+ } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) {
+ $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability;
+ $CumPGuess = $CumPGuessMinus1;
+ $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess;
+ $PGuess = $PGuessMinus1;
+ --$Guess;
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * DEVSQ
+ *
+ * Returns the sum of squares of deviations of data points from their sample mean.
+ *
+ * Excel Function:
+ * DEVSQ(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function DEVSQ()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+
+ // Return value
+ $returnValue = null;
+
+ $aMean = self::AVERAGE($aArgs);
+ if ($aMean != PHPExcel_Calculation_Functions::DIV0()) {
+ $aCount = -1;
+ foreach ($aArgs as $k => $arg) {
+ // Is it a numeric value?
+ if ((is_bool($arg)) &&
+ ((!PHPExcel_Calculation_Functions::isCellValue($k)) ||
+ (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
+ $arg = (integer) $arg;
+ }
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = pow(($arg - $aMean), 2);
+ } else {
+ $returnValue += pow(($arg - $aMean), 2);
+ }
+ ++$aCount;
+ }
+ }
+
+ // Return
+ if (is_null($returnValue)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } else {
+ return $returnValue;
+ }
+ }
+ return self::NA();
+ }
+
+
+ /**
+ * EXPONDIST
+ *
+ * Returns the exponential distribution. Use EXPONDIST to model the time between events,
+ * such as how long an automated bank teller takes to deliver cash. For example, you can
+ * use EXPONDIST to determine the probability that the process takes at most 1 minute.
+ *
+ * @param float $value Value of the function
+ * @param float $lambda The parameter value
+ * @param boolean $cumulative
+ * @return float
+ */
+ public static function EXPONDIST($value, $lambda, $cumulative)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $lambda = PHPExcel_Calculation_Functions::flattenSingleValue($lambda);
+ $cumulative = PHPExcel_Calculation_Functions::flattenSingleValue($cumulative);
+
+ if ((is_numeric($value)) && (is_numeric($lambda))) {
+ if (($value < 0) || ($lambda < 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
+ if ($cumulative) {
+ return 1 - exp(0-$value*$lambda);
+ } else {
+ return $lambda * exp(0-$value*$lambda);
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FISHER
+ *
+ * Returns the Fisher transformation at x. This transformation produces a function that
+ * is normally distributed rather than skewed. Use this function to perform hypothesis
+ * testing on the correlation coefficient.
+ *
+ * @param float $value
+ * @return float
+ */
+ public static function FISHER($value)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+ if (is_numeric($value)) {
+ if (($value <= -1) || ($value >= 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return 0.5 * log((1+$value)/(1-$value));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FISHERINV
+ *
+ * Returns the inverse of the Fisher transformation. Use this transformation when
+ * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then
+ * FISHERINV(y) = x.
+ *
+ * @param float $value
+ * @return float
+ */
+ public static function FISHERINV($value)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+ if (is_numeric($value)) {
+ return (exp(2 * $value) - 1) / (exp(2 * $value) + 1);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FORECAST
+ *
+ * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value.
+ *
+ * @param float Value of X for which we want to find Y
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function FORECAST($xValue, $yValues, $xValues)
+ {
+ $xValue = PHPExcel_Calculation_Functions::flattenSingleValue($xValue);
+ if (!is_numeric($xValue)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getValueOfYForX($xValue);
+ }
+
+
+ /**
+ * GAMMADIST
+ *
+ * Returns the gamma distribution.
+ *
+ * @param float $value Value at which you want to evaluate the distribution
+ * @param float $a Parameter to the distribution
+ * @param float $b Parameter to the distribution
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function GAMMADIST($value, $a, $b, $cumulative)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $a = PHPExcel_Calculation_Functions::flattenSingleValue($a);
+ $b = PHPExcel_Calculation_Functions::flattenSingleValue($b);
+
+ if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) {
+ if (($value < 0) || ($a <= 0) || ($b <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
+ if ($cumulative) {
+ return self::incompleteGamma($a, $value / $b) / self::gamma($a);
+ } else {
+ return (1 / (pow($b, $a) * self::gamma($a))) * pow($value, $a-1) * exp(0-($value / $b));
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * GAMMAINV
+ *
+ * Returns the inverse of the beta distribution.
+ *
+ * @param float $probability Probability at which you want to evaluate the distribution
+ * @param float $alpha Parameter to the distribution
+ * @param float $beta Parameter to the distribution
+ * @return float
+ *
+ */
+ public static function GAMMAINV($probability, $alpha, $beta)
+ {
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
+ $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
+
+ if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) {
+ if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $xLo = 0;
+ $xHi = $alpha * $beta * 5;
+
+ $x = $xNew = 1;
+ $error = $pdf = 0;
+ $dx = 1024;
+ $i = 0;
+
+ while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
+ // Apply Newton-Raphson step
+ $error = self::GAMMADIST($x, $alpha, $beta, true) - $probability;
+ if ($error < 0.0) {
+ $xLo = $x;
+ } else {
+ $xHi = $x;
+ }
+ $pdf = self::GAMMADIST($x, $alpha, $beta, false);
+ // Avoid division by zero
+ if ($pdf != 0.0) {
+ $dx = $error / $pdf;
+ $xNew = $x - $dx;
+ }
+ // If the NR fails to converge (which for example may be the
+ // case if the initial guess is too rough) we apply a bisection
+ // step to determine a more narrow interval around the root.
+ if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) {
+ $xNew = ($xLo + $xHi) / 2;
+ $dx = $xNew - $x;
+ }
+ $x = $xNew;
+ }
+ if ($i == MAX_ITERATIONS) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ return $x;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * GAMMALN
+ *
+ * Returns the natural logarithm of the gamma function.
+ *
+ * @param float $value
+ * @return float
+ */
+ public static function GAMMALN($value)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+ if (is_numeric($value)) {
+ if ($value <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return log(self::gamma($value));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * GEOMEAN
+ *
+ * Returns the geometric mean of an array or range of positive data. For example, you
+ * can use GEOMEAN to calculate average growth rate given compound interest with
+ * variable rates.
+ *
+ * Excel Function:
+ * GEOMEAN(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function GEOMEAN()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ $aMean = PHPExcel_Calculation_MathTrig::PRODUCT($aArgs);
+ if (is_numeric($aMean) && ($aMean > 0)) {
+ $aCount = self::COUNT($aArgs) ;
+ if (self::MIN($aArgs) > 0) {
+ return pow($aMean, (1 / $aCount));
+ }
+ }
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+
+ /**
+ * GROWTH
+ *
+ * Returns values along a predicted emponential trend
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @param array of mixed Values of X for which we want to find Y
+ * @param boolean A logical value specifying whether to force the intersect to equal 0.
+ * @return array of float
+ */
+ public static function GROWTH($yValues, $xValues = array(), $newValues = array(), $const = true)
+ {
+ $yValues = PHPExcel_Calculation_Functions::flattenArray($yValues);
+ $xValues = PHPExcel_Calculation_Functions::flattenArray($xValues);
+ $newValues = PHPExcel_Calculation_Functions::flattenArray($newValues);
+ $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
+
+ $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL, $yValues, $xValues, $const);
+ if (empty($newValues)) {
+ $newValues = $bestFitExponential->getXValues();
+ }
+
+ $returnArray = array();
+ foreach ($newValues as $xValue) {
+ $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue);
+ }
+
+ return $returnArray;
+ }
+
+
+ /**
+ * HARMEAN
+ *
+ * Returns the harmonic mean of a data set. The harmonic mean is the reciprocal of the
+ * arithmetic mean of reciprocals.
+ *
+ * Excel Function:
+ * HARMEAN(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function HARMEAN()
+ {
+ // Return value
+ $returnValue = PHPExcel_Calculation_Functions::NA();
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ if (self::MIN($aArgs) < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $aCount = 0;
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if ($arg <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (is_null($returnValue)) {
+ $returnValue = (1 / $arg);
+ } else {
+ $returnValue += (1 / $arg);
+ }
+ ++$aCount;
+ }
+ }
+
+ // Return
+ if ($aCount > 0) {
+ return 1 / ($returnValue / $aCount);
+ } else {
+ return $returnValue;
+ }
+ }
+
+
+ /**
+ * HYPGEOMDIST
+ *
+ * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of
+ * sample successes, given the sample size, population successes, and population size.
+ *
+ * @param float $sampleSuccesses Number of successes in the sample
+ * @param float $sampleNumber Size of the sample
+ * @param float $populationSuccesses Number of successes in the population
+ * @param float $populationNumber Population size
+ * @return float
+ *
+ */
+ public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber)
+ {
+ $sampleSuccesses = floor(PHPExcel_Calculation_Functions::flattenSingleValue($sampleSuccesses));
+ $sampleNumber = floor(PHPExcel_Calculation_Functions::flattenSingleValue($sampleNumber));
+ $populationSuccesses = floor(PHPExcel_Calculation_Functions::flattenSingleValue($populationSuccesses));
+ $populationNumber = floor(PHPExcel_Calculation_Functions::flattenSingleValue($populationNumber));
+
+ if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) {
+ if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return PHPExcel_Calculation_MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) *
+ PHPExcel_Calculation_MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) /
+ PHPExcel_Calculation_MathTrig::COMBIN($populationNumber, $sampleNumber);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * INTERCEPT
+ *
+ * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function INTERCEPT($yValues, $xValues)
+ {
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getIntersect();
+ }
+
+
+ /**
+ * KURT
+ *
+ * Returns the kurtosis of a data set. Kurtosis characterizes the relative peakedness
+ * or flatness of a distribution compared with the normal distribution. Positive
+ * kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a
+ * relatively flat distribution.
+ *
+ * @param array Data Series
+ * @return float
+ */
+ public static function KURT()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+ $mean = self::AVERAGE($aArgs);
+ $stdDev = self::STDEV($aArgs);
+
+ if ($stdDev > 0) {
+ $count = $summer = 0;
+ // Loop through arguments
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $summer += pow((($arg - $mean) / $stdDev), 4);
+ ++$count;
+ }
+ }
+ }
+
+ // Return
+ if ($count > 3) {
+ return $summer * ($count * ($count+1) / (($count-1) * ($count-2) * ($count-3))) - (3 * pow($count-1, 2) / (($count-2) * ($count-3)));
+ }
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * LARGE
+ *
+ * Returns the nth largest value in a data set. You can use this function to
+ * select a value based on its relative standing.
+ *
+ * Excel Function:
+ * LARGE(value1[,value2[, ...]],entry)
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @param int $entry Position (ordered from the largest) in the array or range of data to return
+ * @return float
+ *
+ */
+ public static function LARGE()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $entry = floor(array_pop($aArgs));
+
+ if ((is_numeric($entry)) && (!is_string($entry))) {
+ $mArgs = array();
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $mArgs[] = $arg;
+ }
+ }
+ $count = self::COUNT($mArgs);
+ $entry = floor(--$entry);
+ if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ rsort($mArgs);
+ return $mArgs[$entry];
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * LINEST
+ *
+ * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data,
+ * and then returns an array that describes the line.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @param boolean A logical value specifying whether to force the intersect to equal 0.
+ * @param boolean A logical value specifying whether to return additional regression statistics.
+ * @return array
+ */
+ public static function LINEST($yValues, $xValues = null, $const = true, $stats = false)
+ {
+ $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
+ $stats = (is_null($stats)) ? false : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($stats);
+ if (is_null($xValues)) {
+ $xValues = range(1, count(PHPExcel_Calculation_Functions::flattenArray($yValues)));
+ }
+
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return 0;
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues, $const);
+ if ($stats) {
+ return array(
+ array(
+ $bestFitLinear->getSlope(),
+ $bestFitLinear->getSlopeSE(),
+ $bestFitLinear->getGoodnessOfFit(),
+ $bestFitLinear->getF(),
+ $bestFitLinear->getSSRegression(),
+ ),
+ array(
+ $bestFitLinear->getIntersect(),
+ $bestFitLinear->getIntersectSE(),
+ $bestFitLinear->getStdevOfResiduals(),
+ $bestFitLinear->getDFResiduals(),
+ $bestFitLinear->getSSResiduals()
+ )
+ );
+ } else {
+ return array(
+ $bestFitLinear->getSlope(),
+ $bestFitLinear->getIntersect()
+ );
+ }
+ }
+
+
+ /**
+ * LOGEST
+ *
+ * Calculates an exponential curve that best fits the X and Y data series,
+ * and then returns an array that describes the line.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @param boolean A logical value specifying whether to force the intersect to equal 0.
+ * @param boolean A logical value specifying whether to return additional regression statistics.
+ * @return array
+ */
+ public static function LOGEST($yValues, $xValues = null, $const = true, $stats = false)
+ {
+ $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
+ $stats = (is_null($stats)) ? false : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($stats);
+ if (is_null($xValues)) {
+ $xValues = range(1, count(PHPExcel_Calculation_Functions::flattenArray($yValues)));
+ }
+
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ foreach ($yValues as $value) {
+ if ($value <= 0.0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return 1;
+ }
+
+ $bestFitExponential = trendClass::calculate(trendClass::TREND_EXPONENTIAL, $yValues, $xValues, $const);
+ if ($stats) {
+ return array(
+ array(
+ $bestFitExponential->getSlope(),
+ $bestFitExponential->getSlopeSE(),
+ $bestFitExponential->getGoodnessOfFit(),
+ $bestFitExponential->getF(),
+ $bestFitExponential->getSSRegression(),
+ ),
+ array(
+ $bestFitExponential->getIntersect(),
+ $bestFitExponential->getIntersectSE(),
+ $bestFitExponential->getStdevOfResiduals(),
+ $bestFitExponential->getDFResiduals(),
+ $bestFitExponential->getSSResiduals()
+ )
+ );
+ } else {
+ return array(
+ $bestFitExponential->getSlope(),
+ $bestFitExponential->getIntersect()
+ );
+ }
+ }
+
+
+ /**
+ * LOGINV
+ *
+ * Returns the inverse of the normal cumulative distribution
+ *
+ * @param float $probability
+ * @param float $mean
+ * @param float $stdDev
+ * @return float
+ *
+ * @todo Try implementing P J Acklam's refinement algorithm for greater
+ * accuracy if I can get my head round the mathematics
+ * (as described at) http://home.online.no/~pjacklam/notes/invnorm/
+ */
+ public static function LOGINV($probability, $mean, $stdDev)
+ {
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
+ $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
+
+ if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
+ if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return exp($mean + $stdDev * self::NORMSINV($probability));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * LOGNORMDIST
+ *
+ * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
+ * with parameters mean and standard_dev.
+ *
+ * @param float $value
+ * @param float $mean
+ * @param float $stdDev
+ * @return float
+ */
+ public static function LOGNORMDIST($value, $mean, $stdDev)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
+ $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
+
+ if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
+ if (($value <= 0) || ($stdDev <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return self::NORMSDIST((log($value) - $mean) / $stdDev);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * MAX
+ *
+ * MAX returns the value of the element of the values passed that has the highest value,
+ * with negative numbers considered smaller than positive numbers.
+ *
+ * Excel Function:
+ * MAX(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function MAX()
+ {
+ $returnValue = null;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if ((is_null($returnValue)) || ($arg > $returnValue)) {
+ $returnValue = $arg;
+ }
+ }
+ }
+
+ if (is_null($returnValue)) {
+ return 0;
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * MAXA
+ *
+ * Returns the greatest value in a list of arguments, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * MAXA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function MAXA()
+ {
+ $returnValue = null;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ if ((is_null($returnValue)) || ($arg > $returnValue)) {
+ $returnValue = $arg;
+ }
+ }
+ }
+
+ if (is_null($returnValue)) {
+ return 0;
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * MAXIF
+ *
+ * Counts the maximum value within a range of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * MAXIF(value1[,value2[, ...]],condition)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @param string $condition The criteria that defines which cells will be checked.
+ * @return float
+ */
+ public static function MAXIF($aArgs, $condition, $sumArgs = array())
+ {
+ $returnValue = null;
+
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
+ $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs);
+ if (empty($sumArgs)) {
+ $sumArgs = $aArgs;
+ }
+ $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
+ // Loop through arguments
+ foreach ($aArgs as $key => $arg) {
+ if (!is_numeric($arg)) {
+ $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
+ }
+ $testCondition = '='.$arg.$condition;
+ if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
+ if ((is_null($returnValue)) || ($arg > $returnValue)) {
+ $returnValue = $arg;
+ }
+ }
+ }
+
+ return $returnValue;
+ }
+
+ /**
+ * MEDIAN
+ *
+ * Returns the median of the given numbers. The median is the number in the middle of a set of numbers.
+ *
+ * Excel Function:
+ * MEDIAN(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function MEDIAN()
+ {
+ $returnValue = PHPExcel_Calculation_Functions::NaN();
+
+ $mArgs = array();
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $mArgs[] = $arg;
+ }
+ }
+
+ $mValueCount = count($mArgs);
+ if ($mValueCount > 0) {
+ sort($mArgs, SORT_NUMERIC);
+ $mValueCount = $mValueCount / 2;
+ if ($mValueCount == floor($mValueCount)) {
+ $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2;
+ } else {
+ $mValueCount = floor($mValueCount);
+ $returnValue = $mArgs[$mValueCount];
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * MIN
+ *
+ * MIN returns the value of the element of the values passed that has the smallest value,
+ * with negative numbers considered smaller than positive numbers.
+ *
+ * Excel Function:
+ * MIN(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function MIN()
+ {
+ $returnValue = null;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if ((is_null($returnValue)) || ($arg < $returnValue)) {
+ $returnValue = $arg;
+ }
+ }
+ }
+
+ if (is_null($returnValue)) {
+ return 0;
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * MINA
+ *
+ * Returns the smallest value in a list of arguments, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * MINA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function MINA()
+ {
+ $returnValue = null;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ if ((is_null($returnValue)) || ($arg < $returnValue)) {
+ $returnValue = $arg;
+ }
+ }
+ }
+
+ if (is_null($returnValue)) {
+ return 0;
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * MINIF
+ *
+ * Returns the minimum value within a range of cells that contain numbers within the list of arguments
+ *
+ * Excel Function:
+ * MINIF(value1[,value2[, ...]],condition)
+ *
+ * @access public
+ * @category Mathematical and Trigonometric Functions
+ * @param mixed $arg,... Data values
+ * @param string $condition The criteria that defines which cells will be checked.
+ * @return float
+ */
+ public static function MINIF($aArgs, $condition, $sumArgs = array())
+ {
+ $returnValue = null;
+
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
+ $sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs);
+ if (empty($sumArgs)) {
+ $sumArgs = $aArgs;
+ }
+ $condition = PHPExcel_Calculation_Functions::ifCondition($condition);
+ // Loop through arguments
+ foreach ($aArgs as $key => $arg) {
+ if (!is_numeric($arg)) {
+ $arg = PHPExcel_Calculation::wrapResult(strtoupper($arg));
+ }
+ $testCondition = '='.$arg.$condition;
+ if (PHPExcel_Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
+ if ((is_null($returnValue)) || ($arg < $returnValue)) {
+ $returnValue = $arg;
+ }
+ }
+ }
+
+ return $returnValue;
+ }
+
+
+ //
+ // Special variant of array_count_values that isn't limited to strings and integers,
+ // but can work with floating point numbers as values
+ //
+ private static function modeCalc($data)
+ {
+ $frequencyArray = array();
+ foreach ($data as $datum) {
+ $found = false;
+ foreach ($frequencyArray as $key => $value) {
+ if ((string) $value['value'] == (string) $datum) {
+ ++$frequencyArray[$key]['frequency'];
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) {
+ $frequencyArray[] = array(
+ 'value' => $datum,
+ 'frequency' => 1
+ );
+ }
+ }
+
+ foreach ($frequencyArray as $key => $value) {
+ $frequencyList[$key] = $value['frequency'];
+ $valueList[$key] = $value['value'];
+ }
+ array_multisort($frequencyList, SORT_DESC, $valueList, SORT_ASC, SORT_NUMERIC, $frequencyArray);
+
+ if ($frequencyArray[0]['frequency'] == 1) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ return $frequencyArray[0]['value'];
+ }
+
+
+ /**
+ * MODE
+ *
+ * Returns the most frequently occurring, or repetitive, value in an array or range of data
+ *
+ * Excel Function:
+ * MODE(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function MODE()
+ {
+ $returnValue = PHPExcel_Calculation_Functions::NA();
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ $mArgs = array();
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $mArgs[] = $arg;
+ }
+ }
+
+ if (!empty($mArgs)) {
+ return self::modeCalc($mArgs);
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * NEGBINOMDIST
+ *
+ * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that
+ * there will be number_f failures before the number_s-th success, when the constant
+ * probability of a success is probability_s. This function is similar to the binomial
+ * distribution, except that the number of successes is fixed, and the number of trials is
+ * variable. Like the binomial, trials are assumed to be independent.
+ *
+ * @param float $failures Number of Failures
+ * @param float $successes Threshold number of Successes
+ * @param float $probability Probability of success on each trial
+ * @return float
+ *
+ */
+ public static function NEGBINOMDIST($failures, $successes, $probability)
+ {
+ $failures = floor(PHPExcel_Calculation_Functions::flattenSingleValue($failures));
+ $successes = floor(PHPExcel_Calculation_Functions::flattenSingleValue($successes));
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+
+ if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) {
+ if (($failures < 0) || ($successes < 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ } elseif (($probability < 0) || ($probability > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
+ if (($failures + $successes - 1) <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+ return (PHPExcel_Calculation_MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * (pow($probability, $successes)) * (pow(1 - $probability, $failures));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * NORMDIST
+ *
+ * Returns the normal distribution for the specified mean and standard deviation. This
+ * function has a very wide range of applications in statistics, including hypothesis
+ * testing.
+ *
+ * @param float $value
+ * @param float $mean Mean Value
+ * @param float $stdDev Standard Deviation
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function NORMDIST($value, $mean, $stdDev, $cumulative)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
+ $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
+
+ if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
+ if ($stdDev < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
+ if ($cumulative) {
+ return 0.5 * (1 + PHPExcel_Calculation_Engineering::erfVal(($value - $mean) / ($stdDev * sqrt(2))));
+ } else {
+ return (1 / (SQRT2PI * $stdDev)) * exp(0 - (pow($value - $mean, 2) / (2 * ($stdDev * $stdDev))));
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * NORMINV
+ *
+ * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
+ *
+ * @param float $value
+ * @param float $mean Mean Value
+ * @param float $stdDev Standard Deviation
+ * @return float
+ *
+ */
+ public static function NORMINV($probability, $mean, $stdDev)
+ {
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
+ $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
+
+ if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
+ if (($probability < 0) || ($probability > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ($stdDev < 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return (self::inverseNcdf($probability) * $stdDev) + $mean;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * NORMSDIST
+ *
+ * Returns the standard normal cumulative distribution function. The distribution has
+ * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
+ * table of standard normal curve areas.
+ *
+ * @param float $value
+ * @return float
+ */
+ public static function NORMSDIST($value)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+ return self::NORMDIST($value, 0, 1, true);
+ }
+
+
+ /**
+ * NORMSINV
+ *
+ * Returns the inverse of the standard normal cumulative distribution
+ *
+ * @param float $value
+ * @return float
+ */
+ public static function NORMSINV($value)
+ {
+ return self::NORMINV($value, 0, 1);
+ }
+
+
+ /**
+ * PERCENTILE
+ *
+ * Returns the nth percentile of values in a range..
+ *
+ * Excel Function:
+ * PERCENTILE(value1[,value2[, ...]],entry)
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @param float $entry Percentile value in the range 0..1, inclusive.
+ * @return float
+ */
+ public static function PERCENTILE()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $entry = array_pop($aArgs);
+
+ if ((is_numeric($entry)) && (!is_string($entry))) {
+ if (($entry < 0) || ($entry > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $mArgs = array();
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $mArgs[] = $arg;
+ }
+ }
+ $mValueCount = count($mArgs);
+ if ($mValueCount > 0) {
+ sort($mArgs);
+ $count = self::COUNT($mArgs);
+ $index = $entry * ($count-1);
+ $iBase = floor($index);
+ if ($index == $iBase) {
+ return $mArgs[$index];
+ } else {
+ $iNext = $iBase + 1;
+ $iProportion = $index - $iBase;
+ return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion) ;
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * PERCENTRANK
+ *
+ * Returns the rank of a value in a data set as a percentage of the data set.
+ *
+ * @param array of number An array of, or a reference to, a list of numbers.
+ * @param number The number whose rank you want to find.
+ * @param number The number of significant digits for the returned percentage value.
+ * @return float
+ */
+ public static function PERCENTRANK($valueSet, $value, $significance = 3)
+ {
+ $valueSet = PHPExcel_Calculation_Functions::flattenArray($valueSet);
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $significance = (is_null($significance)) ? 3 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($significance);
+
+ foreach ($valueSet as $key => $valueEntry) {
+ if (!is_numeric($valueEntry)) {
+ unset($valueSet[$key]);
+ }
+ }
+ sort($valueSet, SORT_NUMERIC);
+ $valueCount = count($valueSet);
+ if ($valueCount == 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+
+ $valueAdjustor = $valueCount - 1;
+ if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+ $pos = array_search($value, $valueSet);
+ if ($pos === false) {
+ $pos = 0;
+ $testValue = $valueSet[0];
+ while ($testValue < $value) {
+ $testValue = $valueSet[++$pos];
+ }
+ --$pos;
+ $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos]));
+ }
+
+ return round($pos / $valueAdjustor, $significance);
+ }
+
+
+ /**
+ * PERMUT
+ *
+ * Returns the number of permutations for a given number of objects that can be
+ * selected from number objects. A permutation is any set or subset of objects or
+ * events where internal order is significant. Permutations are different from
+ * combinations, for which the internal order is not significant. Use this function
+ * for lottery-style probability calculations.
+ *
+ * @param int $numObjs Number of different objects
+ * @param int $numInSet Number of objects in each permutation
+ * @return int Number of permutations
+ */
+ public static function PERMUT($numObjs, $numInSet)
+ {
+ $numObjs = PHPExcel_Calculation_Functions::flattenSingleValue($numObjs);
+ $numInSet = PHPExcel_Calculation_Functions::flattenSingleValue($numInSet);
+
+ if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
+ $numInSet = floor($numInSet);
+ if ($numObjs < $numInSet) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return round(PHPExcel_Calculation_MathTrig::FACT($numObjs) / PHPExcel_Calculation_MathTrig::FACT($numObjs - $numInSet));
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * POISSON
+ *
+ * Returns the Poisson distribution. A common application of the Poisson distribution
+ * is predicting the number of events over a specific time, such as the number of
+ * cars arriving at a toll plaza in 1 minute.
+ *
+ * @param float $value
+ * @param float $mean Mean Value
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function POISSON($value, $mean, $cumulative)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
+
+ if ((is_numeric($value)) && (is_numeric($mean))) {
+ if (($value < 0) || ($mean <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
+ if ($cumulative) {
+ $summer = 0;
+ for ($i = 0; $i <= floor($value); ++$i) {
+ $summer += pow($mean, $i) / PHPExcel_Calculation_MathTrig::FACT($i);
+ }
+ return exp(0-$mean) * $summer;
+ } else {
+ return (exp(0-$mean) * pow($mean, $value)) / PHPExcel_Calculation_MathTrig::FACT($value);
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * QUARTILE
+ *
+ * Returns the quartile of a data set.
+ *
+ * Excel Function:
+ * QUARTILE(value1[,value2[, ...]],entry)
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @param int $entry Quartile value in the range 1..3, inclusive.
+ * @return float
+ */
+ public static function QUARTILE()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $entry = floor(array_pop($aArgs));
+
+ if ((is_numeric($entry)) && (!is_string($entry))) {
+ $entry /= 4;
+ if (($entry < 0) || ($entry > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return self::PERCENTILE($aArgs, $entry);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * RANK
+ *
+ * Returns the rank of a number in a list of numbers.
+ *
+ * @param number The number whose rank you want to find.
+ * @param array of number An array of, or a reference to, a list of numbers.
+ * @param mixed Order to sort the values in the value set
+ * @return float
+ */
+ public static function RANK($value, $valueSet, $order = 0)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $valueSet = PHPExcel_Calculation_Functions::flattenArray($valueSet);
+ $order = (is_null($order)) ? 0 : (integer) PHPExcel_Calculation_Functions::flattenSingleValue($order);
+
+ foreach ($valueSet as $key => $valueEntry) {
+ if (!is_numeric($valueEntry)) {
+ unset($valueSet[$key]);
+ }
+ }
+
+ if ($order == 0) {
+ rsort($valueSet, SORT_NUMERIC);
+ } else {
+ sort($valueSet, SORT_NUMERIC);
+ }
+ $pos = array_search($value, $valueSet);
+ if ($pos === false) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+
+ return ++$pos;
+ }
+
+
+ /**
+ * RSQ
+ *
+ * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function RSQ($yValues, $xValues)
+ {
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getGoodnessOfFit();
+ }
+
+
+ /**
+ * SKEW
+ *
+ * Returns the skewness of a distribution. Skewness characterizes the degree of asymmetry
+ * of a distribution around its mean. Positive skewness indicates a distribution with an
+ * asymmetric tail extending toward more positive values. Negative skewness indicates a
+ * distribution with an asymmetric tail extending toward more negative values.
+ *
+ * @param array Data Series
+ * @return float
+ */
+ public static function SKEW()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+ $mean = self::AVERAGE($aArgs);
+ $stdDev = self::STDEV($aArgs);
+
+ $count = $summer = 0;
+ // Loop through arguments
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $summer += pow((($arg - $mean) / $stdDev), 3);
+ ++$count;
+ }
+ }
+ }
+
+ if ($count > 2) {
+ return $summer * ($count / (($count-1) * ($count-2)));
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * SLOPE
+ *
+ * Returns the slope of the linear regression line through data points in known_y's and known_x's.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function SLOPE($yValues, $xValues)
+ {
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getSlope();
+ }
+
+
+ /**
+ * SMALL
+ *
+ * Returns the nth smallest value in a data set. You can use this function to
+ * select a value based on its relative standing.
+ *
+ * Excel Function:
+ * SMALL(value1[,value2[, ...]],entry)
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @param int $entry Position (ordered from the smallest) in the array or range of data to return
+ * @return float
+ */
+ public static function SMALL()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $entry = array_pop($aArgs);
+
+ if ((is_numeric($entry)) && (!is_string($entry))) {
+ $mArgs = array();
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $mArgs[] = $arg;
+ }
+ }
+ $count = self::COUNT($mArgs);
+ $entry = floor(--$entry);
+ if (($entry < 0) || ($entry >= $count) || ($count == 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ sort($mArgs);
+ return $mArgs[$entry];
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * STANDARDIZE
+ *
+ * Returns a normalized value from a distribution characterized by mean and standard_dev.
+ *
+ * @param float $value Value to normalize
+ * @param float $mean Mean Value
+ * @param float $stdDev Standard Deviation
+ * @return float Standardized value
+ */
+ public static function STANDARDIZE($value, $mean, $stdDev)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $mean = PHPExcel_Calculation_Functions::flattenSingleValue($mean);
+ $stdDev = PHPExcel_Calculation_Functions::flattenSingleValue($stdDev);
+
+ if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) {
+ if ($stdDev <= 0) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ return ($value - $mean) / $stdDev ;
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * STDEV
+ *
+ * Estimates standard deviation based on a sample. The standard deviation is a measure of how
+ * widely values are dispersed from the average value (the mean).
+ *
+ * Excel Function:
+ * STDEV(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function STDEV()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+
+ // Return value
+ $returnValue = null;
+
+ $aMean = self::AVERAGE($aArgs);
+ if (!is_null($aMean)) {
+ $aCount = -1;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = pow(($arg - $aMean), 2);
+ } else {
+ $returnValue += pow(($arg - $aMean), 2);
+ }
+ ++$aCount;
+ }
+ }
+
+ // Return
+ if (($aCount > 0) && ($returnValue >= 0)) {
+ return sqrt($returnValue / $aCount);
+ }
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * STDEVA
+ *
+ * Estimates standard deviation based on a sample, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * STDEVA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function STDEVA()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+
+ $returnValue = null;
+
+ $aMean = self::AVERAGEA($aArgs);
+ if (!is_null($aMean)) {
+ $aCount = -1;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ if (is_null($returnValue)) {
+ $returnValue = pow(($arg - $aMean), 2);
+ } else {
+ $returnValue += pow(($arg - $aMean), 2);
+ }
+ ++$aCount;
+ }
+ }
+ }
+
+ if (($aCount > 0) && ($returnValue >= 0)) {
+ return sqrt($returnValue / $aCount);
+ }
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * STDEVP
+ *
+ * Calculates standard deviation based on the entire population
+ *
+ * Excel Function:
+ * STDEVP(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function STDEVP()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+
+ $returnValue = null;
+
+ $aMean = self::AVERAGE($aArgs);
+ if (!is_null($aMean)) {
+ $aCount = 0;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ ((!PHPExcel_Calculation_Functions::isCellValue($k)) || (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE))) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ if (is_null($returnValue)) {
+ $returnValue = pow(($arg - $aMean), 2);
+ } else {
+ $returnValue += pow(($arg - $aMean), 2);
+ }
+ ++$aCount;
+ }
+ }
+
+ if (($aCount > 0) && ($returnValue >= 0)) {
+ return sqrt($returnValue / $aCount);
+ }
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * STDEVPA
+ *
+ * Calculates standard deviation based on the entire population, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * STDEVPA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function STDEVPA()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+
+ $returnValue = null;
+
+ $aMean = self::AVERAGEA($aArgs);
+ if (!is_null($aMean)) {
+ $aCount = 0;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_bool($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ if (is_null($returnValue)) {
+ $returnValue = pow(($arg - $aMean), 2);
+ } else {
+ $returnValue += pow(($arg - $aMean), 2);
+ }
+ ++$aCount;
+ }
+ }
+ }
+
+ if (($aCount > 0) && ($returnValue >= 0)) {
+ return sqrt($returnValue / $aCount);
+ }
+ }
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+
+ /**
+ * STEYX
+ *
+ * Returns the standard error of the predicted y-value for each x in the regression.
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @return float
+ */
+ public static function STEYX($yValues, $xValues)
+ {
+ if (!self::checkTrendArrays($yValues, $xValues)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $yValueCount = count($yValues);
+ $xValueCount = count($xValues);
+
+ if (($yValueCount == 0) || ($yValueCount != $xValueCount)) {
+ return PHPExcel_Calculation_Functions::NA();
+ } elseif ($yValueCount == 1) {
+ return PHPExcel_Calculation_Functions::DIV0();
+ }
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues);
+ return $bestFitLinear->getStdevOfResiduals();
+ }
+
+
+ /**
+ * TDIST
+ *
+ * Returns the probability of Student's T distribution.
+ *
+ * @param float $value Value for the function
+ * @param float $degrees degrees of freedom
+ * @param float $tails number of tails (1 or 2)
+ * @return float
+ */
+ public static function TDIST($value, $degrees, $tails)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
+ $tails = floor(PHPExcel_Calculation_Functions::flattenSingleValue($tails));
+
+ if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) {
+ if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ // tdist, which finds the probability that corresponds to a given value
+ // of t with k degrees of freedom. This algorithm is translated from a
+ // pascal function on p81 of "Statistical Computing in Pascal" by D
+ // Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd:
+ // London). The above Pascal algorithm is itself a translation of the
+ // fortran algoritm "AS 3" by B E Cooper of the Atlas Computer
+ // Laboratory as reported in (among other places) "Applied Statistics
+ // Algorithms", editied by P Griffiths and I D Hill (1985; Ellis
+ // Horwood Ltd.; W. Sussex, England).
+ $tterm = $degrees;
+ $ttheta = atan2($value, sqrt($tterm));
+ $tc = cos($ttheta);
+ $ts = sin($ttheta);
+ $tsum = 0;
+
+ if (($degrees % 2) == 1) {
+ $ti = 3;
+ $tterm = $tc;
+ } else {
+ $ti = 2;
+ $tterm = 1;
+ }
+
+ $tsum = $tterm;
+ while ($ti < $degrees) {
+ $tterm *= $tc * $tc * ($ti - 1) / $ti;
+ $tsum += $tterm;
+ $ti += 2;
+ }
+ $tsum *= $ts;
+ if (($degrees % 2) == 1) {
+ $tsum = M_2DIVPI * ($tsum + $ttheta);
+ }
+ $tValue = 0.5 * (1 + $tsum);
+ if ($tails == 1) {
+ return 1 - abs($tValue);
+ } else {
+ return 1 - abs((1 - $tValue) - $tValue);
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * TINV
+ *
+ * Returns the one-tailed probability of the chi-squared distribution.
+ *
+ * @param float $probability Probability for the function
+ * @param float $degrees degrees of freedom
+ * @return float
+ */
+ public static function TINV($probability, $degrees)
+ {
+ $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability);
+ $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees));
+
+ if ((is_numeric($probability)) && (is_numeric($degrees))) {
+ $xLo = 100;
+ $xHi = 0;
+
+ $x = $xNew = 1;
+ $dx = 1;
+ $i = 0;
+
+ while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) {
+ // Apply Newton-Raphson step
+ $result = self::TDIST($x, $degrees, 2);
+ $error = $result - $probability;
+ if ($error == 0.0) {
+ $dx = 0;
+ } elseif ($error < 0.0) {
+ $xLo = $x;
+ } else {
+ $xHi = $x;
+ }
+ // Avoid division by zero
+ if ($result != 0.0) {
+ $dx = $error / $result;
+ $xNew = $x - $dx;
+ }
+ // If the NR fails to converge (which for example may be the
+ // case if the initial guess is too rough) we apply a bisection
+ // step to determine a more narrow interval around the root.
+ if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
+ $xNew = ($xLo + $xHi) / 2;
+ $dx = $xNew - $x;
+ }
+ $x = $xNew;
+ }
+ if ($i == MAX_ITERATIONS) {
+ return PHPExcel_Calculation_Functions::NA();
+ }
+ return round($x, 12);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * TREND
+ *
+ * Returns values along a linear trend
+ *
+ * @param array of mixed Data Series Y
+ * @param array of mixed Data Series X
+ * @param array of mixed Values of X for which we want to find Y
+ * @param boolean A logical value specifying whether to force the intersect to equal 0.
+ * @return array of float
+ */
+ public static function TREND($yValues, $xValues = array(), $newValues = array(), $const = true)
+ {
+ $yValues = PHPExcel_Calculation_Functions::flattenArray($yValues);
+ $xValues = PHPExcel_Calculation_Functions::flattenArray($xValues);
+ $newValues = PHPExcel_Calculation_Functions::flattenArray($newValues);
+ $const = (is_null($const)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($const);
+
+ $bestFitLinear = trendClass::calculate(trendClass::TREND_LINEAR, $yValues, $xValues, $const);
+ if (empty($newValues)) {
+ $newValues = $bestFitLinear->getXValues();
+ }
+
+ $returnArray = array();
+ foreach ($newValues as $xValue) {
+ $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue);
+ }
+
+ return $returnArray;
+ }
+
+
+ /**
+ * TRIMMEAN
+ *
+ * Returns the mean of the interior of a data set. TRIMMEAN calculates the mean
+ * taken by excluding a percentage of data points from the top and bottom tails
+ * of a data set.
+ *
+ * Excel Function:
+ * TRIMEAN(value1[,value2[, ...]], $discard)
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @param float $discard Percentage to discard
+ * @return float
+ */
+ public static function TRIMMEAN()
+ {
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+
+ // Calculate
+ $percent = array_pop($aArgs);
+
+ if ((is_numeric($percent)) && (!is_string($percent))) {
+ if (($percent < 0) || ($percent > 1)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $mArgs = array();
+ foreach ($aArgs as $arg) {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $mArgs[] = $arg;
+ }
+ }
+ $discard = floor(self::COUNT($mArgs) * $percent / 2);
+ sort($mArgs);
+ for ($i=0; $i < $discard; ++$i) {
+ array_pop($mArgs);
+ array_shift($mArgs);
+ }
+ return self::AVERAGE($mArgs);
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * VARFunc
+ *
+ * Estimates variance based on a sample.
+ *
+ * Excel Function:
+ * VAR(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function VARFunc()
+ {
+ $returnValue = PHPExcel_Calculation_Functions::DIV0();
+
+ $summerA = $summerB = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ $aCount = 0;
+ foreach ($aArgs as $arg) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $summerA += ($arg * $arg);
+ $summerB += $arg;
+ ++$aCount;
+ }
+ }
+
+ if ($aCount > 1) {
+ $summerA *= $aCount;
+ $summerB *= $summerB;
+ $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * VARA
+ *
+ * Estimates variance based on a sample, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * VARA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function VARA()
+ {
+ $returnValue = PHPExcel_Calculation_Functions::DIV0();
+
+ $summerA = $summerB = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+ $aCount = 0;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_string($arg)) &&
+ (PHPExcel_Calculation_Functions::isValue($k))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ((is_string($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ $summerA += ($arg * $arg);
+ $summerB += $arg;
+ ++$aCount;
+ }
+ }
+ }
+
+ if ($aCount > 1) {
+ $summerA *= $aCount;
+ $summerB *= $summerB;
+ $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1));
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * VARP
+ *
+ * Calculates variance based on the entire population
+ *
+ * Excel Function:
+ * VARP(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function VARP()
+ {
+ // Return value
+ $returnValue = PHPExcel_Calculation_Functions::DIV0();
+
+ $summerA = $summerB = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ $aCount = 0;
+ foreach ($aArgs as $arg) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ }
+ // Is it a numeric value?
+ if ((is_numeric($arg)) && (!is_string($arg))) {
+ $summerA += ($arg * $arg);
+ $summerB += $arg;
+ ++$aCount;
+ }
+ }
+
+ if ($aCount > 0) {
+ $summerA *= $aCount;
+ $summerB *= $summerB;
+ $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * VARPA
+ *
+ * Calculates variance based on the entire population, including numbers, text, and logical values
+ *
+ * Excel Function:
+ * VARPA(value1[,value2[, ...]])
+ *
+ * @access public
+ * @category Statistical Functions
+ * @param mixed $arg,... Data values
+ * @return float
+ */
+ public static function VARPA()
+ {
+ $returnValue = PHPExcel_Calculation_Functions::DIV0();
+
+ $summerA = $summerB = 0;
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArrayIndexed(func_get_args());
+ $aCount = 0;
+ foreach ($aArgs as $k => $arg) {
+ if ((is_string($arg)) &&
+ (PHPExcel_Calculation_Functions::isValue($k))) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ } elseif ((is_string($arg)) &&
+ (!PHPExcel_Calculation_Functions::isMatrixValue($k))) {
+ } else {
+ // Is it a numeric value?
+ if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) {
+ if (is_bool($arg)) {
+ $arg = (integer) $arg;
+ } elseif (is_string($arg)) {
+ $arg = 0;
+ }
+ $summerA += ($arg * $arg);
+ $summerB += $arg;
+ ++$aCount;
+ }
+ }
+ }
+
+ if ($aCount > 0) {
+ $summerA *= $aCount;
+ $summerB *= $summerB;
+ $returnValue = ($summerA - $summerB) / ($aCount * $aCount);
+ }
+ return $returnValue;
+ }
+
+
+ /**
+ * WEIBULL
+ *
+ * Returns the Weibull distribution. Use this distribution in reliability
+ * analysis, such as calculating a device's mean time to failure.
+ *
+ * @param float $value
+ * @param float $alpha Alpha Parameter
+ * @param float $beta Beta Parameter
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function WEIBULL($value, $alpha, $beta, $cumulative)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $alpha = PHPExcel_Calculation_Functions::flattenSingleValue($alpha);
+ $beta = PHPExcel_Calculation_Functions::flattenSingleValue($beta);
+
+ if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) {
+ if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ if ((is_numeric($cumulative)) || (is_bool($cumulative))) {
+ if ($cumulative) {
+ return 1 - exp(0 - pow($value / $beta, $alpha));
+ } else {
+ return ($alpha / pow($beta, $alpha)) * pow($value, $alpha - 1) * exp(0 - pow($value / $beta, $alpha));
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * ZTEST
+ *
+ * Returns the Weibull distribution. Use this distribution in reliability
+ * analysis, such as calculating a device's mean time to failure.
+ *
+ * @param float $dataSet
+ * @param float $m0 Alpha Parameter
+ * @param float $sigma Beta Parameter
+ * @param boolean $cumulative
+ * @return float
+ *
+ */
+ public static function ZTEST($dataSet, $m0, $sigma = null)
+ {
+ $dataSet = PHPExcel_Calculation_Functions::flattenArrayIndexed($dataSet);
+ $m0 = PHPExcel_Calculation_Functions::flattenSingleValue($m0);
+ $sigma = PHPExcel_Calculation_Functions::flattenSingleValue($sigma);
+
+ if (is_null($sigma)) {
+ $sigma = self::STDEV($dataSet);
+ }
+ $n = count($dataSet);
+
+ return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0) / ($sigma / SQRT($n)));
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/TextData.php b/extend/PHPExcel/PHPExcel/Calculation/TextData.php
new file mode 100755
index 0000000..6461d06
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/TextData.php
@@ -0,0 +1,651 @@
+=0 && ord($c{0}) <= 127) {
+ return ord($c{0});
+ } elseif (ord($c{0}) >= 192 && ord($c{0}) <= 223) {
+ return (ord($c{0})-192)*64 + (ord($c{1})-128);
+ } elseif (ord($c{0}) >= 224 && ord($c{0}) <= 239) {
+ return (ord($c{0})-224)*4096 + (ord($c{1})-128)*64 + (ord($c{2})-128);
+ } elseif (ord($c{0}) >= 240 && ord($c{0}) <= 247) {
+ return (ord($c{0})-240)*262144 + (ord($c{1})-128)*4096 + (ord($c{2})-128)*64 + (ord($c{3})-128);
+ } elseif (ord($c{0}) >= 248 && ord($c{0}) <= 251) {
+ return (ord($c{0})-248)*16777216 + (ord($c{1})-128)*262144 + (ord($c{2})-128)*4096 + (ord($c{3})-128)*64 + (ord($c{4})-128);
+ } elseif (ord($c{0}) >= 252 && ord($c{0}) <= 253) {
+ return (ord($c{0})-252)*1073741824 + (ord($c{1})-128)*16777216 + (ord($c{2})-128)*262144 + (ord($c{3})-128)*4096 + (ord($c{4})-128)*64 + (ord($c{5})-128);
+ } elseif (ord($c{0}) >= 254 && ord($c{0}) <= 255) {
+ // error
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ return 0;
+ }
+
+ /**
+ * CHARACTER
+ *
+ * @param string $character Value
+ * @return int
+ */
+ public static function CHARACTER($character)
+ {
+ $character = PHPExcel_Calculation_Functions::flattenSingleValue($character);
+
+ if ((!is_numeric($character)) || ($character < 0)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (function_exists('mb_convert_encoding')) {
+ return mb_convert_encoding(''.intval($character).';', 'UTF-8', 'HTML-ENTITIES');
+ } else {
+ return chr(intval($character));
+ }
+ }
+
+
+ /**
+ * TRIMNONPRINTABLE
+ *
+ * @param mixed $stringValue Value to check
+ * @return string
+ */
+ public static function TRIMNONPRINTABLE($stringValue = '')
+ {
+ $stringValue = PHPExcel_Calculation_Functions::flattenSingleValue($stringValue);
+
+ if (is_bool($stringValue)) {
+ return ($stringValue) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (self::$invalidChars == null) {
+ self::$invalidChars = range(chr(0), chr(31));
+ }
+
+ if (is_string($stringValue) || is_numeric($stringValue)) {
+ return str_replace(self::$invalidChars, '', trim($stringValue, "\x00..\x1F"));
+ }
+ return null;
+ }
+
+
+ /**
+ * TRIMSPACES
+ *
+ * @param mixed $stringValue Value to check
+ * @return string
+ */
+ public static function TRIMSPACES($stringValue = '')
+ {
+ $stringValue = PHPExcel_Calculation_Functions::flattenSingleValue($stringValue);
+ if (is_bool($stringValue)) {
+ return ($stringValue) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (is_string($stringValue) || is_numeric($stringValue)) {
+ return trim(preg_replace('/ +/', ' ', trim($stringValue, ' ')), ' ');
+ }
+ return null;
+ }
+
+
+ /**
+ * ASCIICODE
+ *
+ * @param string $characters Value
+ * @return int
+ */
+ public static function ASCIICODE($characters)
+ {
+ if (($characters === null) || ($characters === '')) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ $characters = PHPExcel_Calculation_Functions::flattenSingleValue($characters);
+ if (is_bool($characters)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $characters = (int) $characters;
+ } else {
+ $characters = ($characters) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+ }
+
+ $character = $characters;
+ if ((function_exists('mb_strlen')) && (function_exists('mb_substr'))) {
+ if (mb_strlen($characters, 'UTF-8') > 1) {
+ $character = mb_substr($characters, 0, 1, 'UTF-8');
+ }
+ return self::unicodeToOrd($character);
+ } else {
+ if (strlen($characters) > 0) {
+ $character = substr($characters, 0, 1);
+ }
+ return ord($character);
+ }
+ }
+
+
+ /**
+ * CONCATENATE
+ *
+ * @return string
+ */
+ public static function CONCATENATE()
+ {
+ $returnValue = '';
+
+ // Loop through arguments
+ $aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
+ foreach ($aArgs as $arg) {
+ if (is_bool($arg)) {
+ if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
+ $arg = (int) $arg;
+ } else {
+ $arg = ($arg) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+ }
+ $returnValue .= $arg;
+ }
+
+ return $returnValue;
+ }
+
+
+ /**
+ * DOLLAR
+ *
+ * This function converts a number to text using currency format, with the decimals rounded to the specified place.
+ * The format used is $#,##0.00_);($#,##0.00)..
+ *
+ * @param float $value The value to format
+ * @param int $decimals The number of digits to display to the right of the decimal point.
+ * If decimals is negative, number is rounded to the left of the decimal point.
+ * If you omit decimals, it is assumed to be 2
+ * @return string
+ */
+ public static function DOLLAR($value = 0, $decimals = 2)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $decimals = is_null($decimals) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($decimals);
+
+ // Validate parameters
+ if (!is_numeric($value) || !is_numeric($decimals)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $decimals = floor($decimals);
+
+ $mask = '$#,##0';
+ if ($decimals > 0) {
+ $mask .= '.' . str_repeat('0', $decimals);
+ } else {
+ $round = pow(10, abs($decimals));
+ if ($value < 0) {
+ $round = 0-$round;
+ }
+ $value = PHPExcel_Calculation_MathTrig::MROUND($value, $round);
+ }
+
+ return PHPExcel_Style_NumberFormat::toFormattedString($value, $mask);
+
+ }
+
+
+ /**
+ * SEARCHSENSITIVE
+ *
+ * @param string $needle The string to look for
+ * @param string $haystack The string in which to look
+ * @param int $offset Offset within $haystack
+ * @return string
+ */
+ public static function SEARCHSENSITIVE($needle, $haystack, $offset = 1)
+ {
+ $needle = PHPExcel_Calculation_Functions::flattenSingleValue($needle);
+ $haystack = PHPExcel_Calculation_Functions::flattenSingleValue($haystack);
+ $offset = PHPExcel_Calculation_Functions::flattenSingleValue($offset);
+
+ if (!is_bool($needle)) {
+ if (is_bool($haystack)) {
+ $haystack = ($haystack) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (($offset > 0) && (PHPExcel_Shared_String::CountCharacters($haystack) > $offset)) {
+ if (PHPExcel_Shared_String::CountCharacters($needle) == 0) {
+ return $offset;
+ }
+ if (function_exists('mb_strpos')) {
+ $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8');
+ } else {
+ $pos = strpos($haystack, $needle, --$offset);
+ }
+ if ($pos !== false) {
+ return ++$pos;
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * SEARCHINSENSITIVE
+ *
+ * @param string $needle The string to look for
+ * @param string $haystack The string in which to look
+ * @param int $offset Offset within $haystack
+ * @return string
+ */
+ public static function SEARCHINSENSITIVE($needle, $haystack, $offset = 1)
+ {
+ $needle = PHPExcel_Calculation_Functions::flattenSingleValue($needle);
+ $haystack = PHPExcel_Calculation_Functions::flattenSingleValue($haystack);
+ $offset = PHPExcel_Calculation_Functions::flattenSingleValue($offset);
+
+ if (!is_bool($needle)) {
+ if (is_bool($haystack)) {
+ $haystack = ($haystack) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (($offset > 0) && (PHPExcel_Shared_String::CountCharacters($haystack) > $offset)) {
+ if (PHPExcel_Shared_String::CountCharacters($needle) == 0) {
+ return $offset;
+ }
+ if (function_exists('mb_stripos')) {
+ $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8');
+ } else {
+ $pos = stripos($haystack, $needle, --$offset);
+ }
+ if ($pos !== false) {
+ return ++$pos;
+ }
+ }
+ }
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+
+ /**
+ * FIXEDFORMAT
+ *
+ * @param mixed $value Value to check
+ * @param integer $decimals
+ * @param boolean $no_commas
+ * @return boolean
+ */
+ public static function FIXEDFORMAT($value, $decimals = 2, $no_commas = false)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $decimals = PHPExcel_Calculation_Functions::flattenSingleValue($decimals);
+ $no_commas = PHPExcel_Calculation_Functions::flattenSingleValue($no_commas);
+
+ // Validate parameters
+ if (!is_numeric($value) || !is_numeric($decimals)) {
+ return PHPExcel_Calculation_Functions::NaN();
+ }
+ $decimals = floor($decimals);
+
+ $valueResult = round($value, $decimals);
+ if ($decimals < 0) {
+ $decimals = 0;
+ }
+ if (!$no_commas) {
+ $valueResult = number_format($valueResult, $decimals);
+ }
+
+ return (string) $valueResult;
+ }
+
+
+ /**
+ * LEFT
+ *
+ * @param string $value Value
+ * @param int $chars Number of characters
+ * @return string
+ */
+ public static function LEFT($value = '', $chars = 1)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars);
+
+ if ($chars < 0) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (is_bool($value)) {
+ $value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (function_exists('mb_substr')) {
+ return mb_substr($value, 0, $chars, 'UTF-8');
+ } else {
+ return substr($value, 0, $chars);
+ }
+ }
+
+
+ /**
+ * MID
+ *
+ * @param string $value Value
+ * @param int $start Start character
+ * @param int $chars Number of characters
+ * @return string
+ */
+ public static function MID($value = '', $start = 1, $chars = null)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $start = PHPExcel_Calculation_Functions::flattenSingleValue($start);
+ $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars);
+
+ if (($start < 1) || ($chars < 0)) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (is_bool($value)) {
+ $value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (function_exists('mb_substr')) {
+ return mb_substr($value, --$start, $chars, 'UTF-8');
+ } else {
+ return substr($value, --$start, $chars);
+ }
+ }
+
+
+ /**
+ * RIGHT
+ *
+ * @param string $value Value
+ * @param int $chars Number of characters
+ * @return string
+ */
+ public static function RIGHT($value = '', $chars = 1)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars);
+
+ if ($chars < 0) {
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+
+ if (is_bool($value)) {
+ $value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) {
+ return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8');
+ } else {
+ return substr($value, strlen($value) - $chars);
+ }
+ }
+
+
+ /**
+ * STRINGLENGTH
+ *
+ * @param string $value Value
+ * @return string
+ */
+ public static function STRINGLENGTH($value = '')
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+ if (is_bool($value)) {
+ $value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ if (function_exists('mb_strlen')) {
+ return mb_strlen($value, 'UTF-8');
+ } else {
+ return strlen($value);
+ }
+ }
+
+
+ /**
+ * LOWERCASE
+ *
+ * Converts a string value to upper case.
+ *
+ * @param string $mixedCaseString
+ * @return string
+ */
+ public static function LOWERCASE($mixedCaseString)
+ {
+ $mixedCaseString = PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString);
+
+ if (is_bool($mixedCaseString)) {
+ $mixedCaseString = ($mixedCaseString) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ return PHPExcel_Shared_String::StrToLower($mixedCaseString);
+ }
+
+
+ /**
+ * UPPERCASE
+ *
+ * Converts a string value to upper case.
+ *
+ * @param string $mixedCaseString
+ * @return string
+ */
+ public static function UPPERCASE($mixedCaseString)
+ {
+ $mixedCaseString = PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString);
+
+ if (is_bool($mixedCaseString)) {
+ $mixedCaseString = ($mixedCaseString) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ return PHPExcel_Shared_String::StrToUpper($mixedCaseString);
+ }
+
+
+ /**
+ * PROPERCASE
+ *
+ * Converts a string value to upper case.
+ *
+ * @param string $mixedCaseString
+ * @return string
+ */
+ public static function PROPERCASE($mixedCaseString)
+ {
+ $mixedCaseString = PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString);
+
+ if (is_bool($mixedCaseString)) {
+ $mixedCaseString = ($mixedCaseString) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+ }
+
+ return PHPExcel_Shared_String::StrToTitle($mixedCaseString);
+ }
+
+
+ /**
+ * REPLACE
+ *
+ * @param string $oldText String to modify
+ * @param int $start Start character
+ * @param int $chars Number of characters
+ * @param string $newText String to replace in defined position
+ * @return string
+ */
+ public static function REPLACE($oldText = '', $start = 1, $chars = null, $newText)
+ {
+ $oldText = PHPExcel_Calculation_Functions::flattenSingleValue($oldText);
+ $start = PHPExcel_Calculation_Functions::flattenSingleValue($start);
+ $chars = PHPExcel_Calculation_Functions::flattenSingleValue($chars);
+ $newText = PHPExcel_Calculation_Functions::flattenSingleValue($newText);
+
+ $left = self::LEFT($oldText, $start-1);
+ $right = self::RIGHT($oldText, self::STRINGLENGTH($oldText)-($start+$chars)+1);
+
+ return $left.$newText.$right;
+ }
+
+
+ /**
+ * SUBSTITUTE
+ *
+ * @param string $text Value
+ * @param string $fromText From Value
+ * @param string $toText To Value
+ * @param integer $instance Instance Number
+ * @return string
+ */
+ public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0)
+ {
+ $text = PHPExcel_Calculation_Functions::flattenSingleValue($text);
+ $fromText = PHPExcel_Calculation_Functions::flattenSingleValue($fromText);
+ $toText = PHPExcel_Calculation_Functions::flattenSingleValue($toText);
+ $instance = floor(PHPExcel_Calculation_Functions::flattenSingleValue($instance));
+
+ if ($instance == 0) {
+ if (function_exists('mb_str_replace')) {
+ return mb_str_replace($fromText, $toText, $text);
+ } else {
+ return str_replace($fromText, $toText, $text);
+ }
+ } else {
+ $pos = -1;
+ while ($instance > 0) {
+ if (function_exists('mb_strpos')) {
+ $pos = mb_strpos($text, $fromText, $pos+1, 'UTF-8');
+ } else {
+ $pos = strpos($text, $fromText, $pos+1);
+ }
+ if ($pos === false) {
+ break;
+ }
+ --$instance;
+ }
+ if ($pos !== false) {
+ if (function_exists('mb_strlen')) {
+ return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText);
+ } else {
+ return self::REPLACE($text, ++$pos, strlen($fromText), $toText);
+ }
+ }
+ }
+
+ return $text;
+ }
+
+
+ /**
+ * RETURNSTRING
+ *
+ * @param mixed $testValue Value to check
+ * @return boolean
+ */
+ public static function RETURNSTRING($testValue = '')
+ {
+ $testValue = PHPExcel_Calculation_Functions::flattenSingleValue($testValue);
+
+ if (is_string($testValue)) {
+ return $testValue;
+ }
+ return null;
+ }
+
+
+ /**
+ * TEXTFORMAT
+ *
+ * @param mixed $value Value to check
+ * @param string $format Format mask to use
+ * @return boolean
+ */
+ public static function TEXTFORMAT($value, $format)
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+ $format = PHPExcel_Calculation_Functions::flattenSingleValue($format);
+
+ if ((is_string($value)) && (!is_numeric($value)) && PHPExcel_Shared_Date::isDateTimeFormatCode($format)) {
+ $value = PHPExcel_Calculation_DateTime::DATEVALUE($value);
+ }
+
+ return (string) PHPExcel_Style_NumberFormat::toFormattedString($value, $format);
+ }
+
+ /**
+ * VALUE
+ *
+ * @param mixed $value Value to check
+ * @return boolean
+ */
+ public static function VALUE($value = '')
+ {
+ $value = PHPExcel_Calculation_Functions::flattenSingleValue($value);
+
+ if (!is_numeric($value)) {
+ $numberValue = str_replace(
+ PHPExcel_Shared_String::getThousandsSeparator(),
+ '',
+ trim($value, " \t\n\r\0\x0B" . PHPExcel_Shared_String::getCurrencyCode())
+ );
+ if (is_numeric($numberValue)) {
+ return (float) $numberValue;
+ }
+
+ $dateSetting = PHPExcel_Calculation_Functions::getReturnDateType();
+ PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL);
+
+ if (strpos($value, ':') !== false) {
+ $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($value);
+ if ($timeValue !== PHPExcel_Calculation_Functions::VALUE()) {
+ PHPExcel_Calculation_Functions::setReturnDateType($dateSetting);
+ return $timeValue;
+ }
+ }
+ $dateValue = PHPExcel_Calculation_DateTime::DATEVALUE($value);
+ if ($dateValue !== PHPExcel_Calculation_Functions::VALUE()) {
+ PHPExcel_Calculation_Functions::setReturnDateType($dateSetting);
+ return $dateValue;
+ }
+ PHPExcel_Calculation_Functions::setReturnDateType($dateSetting);
+
+ return PHPExcel_Calculation_Functions::VALUE();
+ }
+ return (float) $value;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/Token/Stack.php b/extend/PHPExcel/PHPExcel/Calculation/Token/Stack.php
new file mode 100755
index 0000000..02ed5aa
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/Token/Stack.php
@@ -0,0 +1,111 @@
+count;
+ }
+
+ /**
+ * Push a new entry onto the stack
+ *
+ * @param mixed $type
+ * @param mixed $value
+ * @param mixed $reference
+ */
+ public function push($type, $value, $reference = null)
+ {
+ $this->stack[$this->count++] = array(
+ 'type' => $type,
+ 'value' => $value,
+ 'reference' => $reference
+ );
+ if ($type == 'Function') {
+ $localeFunction = PHPExcel_Calculation::localeFunc($value);
+ if ($localeFunction != $value) {
+ $this->stack[($this->count - 1)]['localeValue'] = $localeFunction;
+ }
+ }
+ }
+
+ /**
+ * Pop the last entry from the stack
+ *
+ * @return mixed
+ */
+ public function pop()
+ {
+ if ($this->count > 0) {
+ return $this->stack[--$this->count];
+ }
+ return null;
+ }
+
+ /**
+ * Return an entry from the stack without removing it
+ *
+ * @param integer $n number indicating how far back in the stack we want to look
+ * @return mixed
+ */
+ public function last($n = 1)
+ {
+ if ($this->count - $n < 0) {
+ return null;
+ }
+ return $this->stack[$this->count - $n];
+ }
+
+ /**
+ * Clear the stack
+ */
+ public function clear()
+ {
+ $this->stack = array();
+ $this->count = 0;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Calculation/functionlist.txt b/extend/PHPExcel/PHPExcel/Calculation/functionlist.txt
new file mode 100755
index 0000000..67dbd49
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Calculation/functionlist.txt
@@ -0,0 +1,351 @@
+ABS
+ACCRINT
+ACCRINTM
+ACOS
+ACOSH
+ADDRESS
+AMORDEGRC
+AMORLINC
+AND
+AREAS
+ASC
+ASIN
+ASINH
+ATAN
+ATAN2
+ATANH
+AVEDEV
+AVERAGE
+AVERAGEA
+AVERAGEIF
+AVERAGEIFS
+BAHTTEXT
+BESSELI
+BESSELJ
+BESSELK
+BESSELY
+BETADIST
+BETAINV
+BIN2DEC
+BIN2HEX
+BIN2OCT
+BINOMDIST
+CEILING
+CELL
+CHAR
+CHIDIST
+CHIINV
+CHITEST
+CHOOSE
+CLEAN
+CODE
+COLUMN
+COLUMNS
+COMBIN
+COMPLEX
+CONCATENATE
+CONFIDENCE
+CONVERT
+CORREL
+COS
+COSH
+COUNT
+COUNTA
+COUNTBLANK
+COUNTIF
+COUNTIFS
+COUPDAYBS
+COUPDAYBS
+COUPDAYSNC
+COUPNCD
+COUPNUM
+COUPPCD
+COVAR
+CRITBINOM
+CUBEKPIMEMBER
+CUBEMEMBER
+CUBEMEMBERPROPERTY
+CUBERANKEDMEMBER
+CUBESET
+CUBESETCOUNT
+CUBEVALUE
+CUMIPMT
+CUMPRINC
+DATE
+DATEDIF
+DATEVALUE
+DAVERAGE
+DAY
+DAYS360
+DB
+DCOUNT
+DCOUNTA
+DDB
+DEC2BIN
+DEC2HEX
+DEC2OCT
+DEGREES
+DELTA
+DEVSQ
+DGET
+DISC
+DMAX
+DMIN
+DOLLAR
+DOLLARDE
+DOLLARFR
+DPRODUCT
+DSTDEV
+DSTDEVP
+DSUM
+DURATION
+DVAR
+DVARP
+EDATE
+EFFECT
+EOMONTH
+ERF
+ERFC
+ERROR.TYPE
+EVEN
+EXACT
+EXP
+EXPONDIST
+FACT
+FACTDOUBLE
+FALSE
+FDIST
+FIND
+FINDB
+FINV
+FISHER
+FISHERINV
+FIXED
+FLOOR
+FORECAST
+FREQUENCY
+FTEST
+FV
+FVSCHEDULE
+GAMAMDIST
+GAMMAINV
+GAMMALN
+GCD
+GEOMEAN
+GESTEP
+GETPIVOTDATA
+GROWTH
+HARMEAN
+HEX2BIN
+HEX2OCT
+HLOOKUP
+HOUR
+HYPERLINK
+HYPGEOMDIST
+IF
+IFERROR
+IMABS
+IMAGINARY
+IMARGUMENT
+IMCONJUGATE
+IMCOS
+IMEXP
+IMLN
+IMLOG10
+IMLOG2
+IMPOWER
+IMPRODUCT
+IMREAL
+IMSIN
+IMSQRT
+IMSUB
+IMSUM
+INDEX
+INDIRECT
+INFO
+INT
+INTERCEPT
+INTRATE
+IPMT
+IRR
+ISBLANK
+ISERR
+ISERROR
+ISEVEN
+ISLOGICAL
+ISNA
+ISNONTEXT
+ISNUMBER
+ISODD
+ISPMT
+ISREF
+ISTEXT
+JIS
+KURT
+LARGE
+LCM
+LEFT
+LEFTB
+LEN
+LENB
+LINEST
+LN
+LOG
+LOG10
+LOGEST
+LOGINV
+LOGNORMDIST
+LOOKUP
+LOWER
+MATCH
+MAX
+MAXA
+MDETERM
+MDURATION
+MEDIAN
+MID
+MIDB
+MIN
+MINA
+MINUTE
+MINVERSE
+MIRR
+MMULT
+MOD
+MODE
+MONTH
+MROUND
+MULTINOMIAL
+N
+NA
+NEGBINOMDIST
+NETWORKDAYS
+NOMINAL
+NORMDIST
+NORMINV
+NORMSDIST
+NORMSINV
+NOT
+NOW
+NPER
+NPV
+OCT2BIN
+OCT2DEC
+OCT2HEX
+ODD
+ODDFPRICE
+ODDFYIELD
+ODDLPRICE
+ODDLYIELD
+OFFSET
+OR
+PEARSON
+PERCENTILE
+PERCENTRANK
+PERMUT
+PHONETIC
+PI
+PMT
+POISSON
+POWER
+PPMT
+PRICE
+PRICEDISC
+PRICEMAT
+PROB
+PRODUCT
+PROPER
+PV
+QUARTILE
+QUOTIENT
+RADIANS
+RAND
+RANDBETWEEN
+RANK
+RATE
+RECEIVED
+REPLACE
+REPLACEB
+REPT
+RIGHT
+RIGHTB
+ROMAN
+ROUND
+ROUNDDOWN
+ROUNDUP
+ROW
+ROWS
+RSQ
+RTD
+SEARCH
+SEARCHB
+SECOND
+SERIESSUM
+SIGN
+SIN
+SINH
+SKEW
+SLN
+SLOPE
+SMALL
+SQRT
+SQRTPI
+STANDARDIZE
+STDEV
+STDEVA
+STDEVP
+STDEVPA
+STEYX
+SUBSTITUTE
+SUBTOTAL
+SUM
+SUMIF
+SUMIFS
+SUMPRODUCT
+SUMSQ
+SUMX2MY2
+SUMX2PY2
+SUMXMY2
+SYD
+T
+TAN
+TANH
+TBILLEQ
+TBILLPRICE
+TBILLYIELD
+TDIST
+TEXT
+TIME
+TIMEVALUE
+TINV
+TODAY
+TRANSPOSE
+TREND
+TRIM
+TRIMMEAN
+TRUE
+TRUNC
+TTEST
+TYPE
+UPPER
+USDOLLAR
+VALUE
+VAR
+VARA
+VARP
+VARPA
+VDB
+VERSION
+VLOOKUP
+WEEKDAY
+WEEKNUM
+WEIBULL
+WORKDAY
+XIRR
+XNPV
+YEAR
+YEARFRAC
+YIELD
+YIELDDISC
+YIELDMAT
+ZTEST
diff --git a/extend/PHPExcel/PHPExcel/Cell.php b/extend/PHPExcel/PHPExcel/Cell.php
new file mode 100755
index 0000000..c99a3c8
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell.php
@@ -0,0 +1,1032 @@
+parent->updateCacheData($this);
+
+ return $this;
+ }
+
+ public function detach()
+ {
+ $this->parent = null;
+ }
+
+ public function attach(PHPExcel_CachedObjectStorage_CacheBase $parent)
+ {
+ $this->parent = $parent;
+ }
+
+
+ /**
+ * Create a new Cell
+ *
+ * @param mixed $pValue
+ * @param string $pDataType
+ * @param PHPExcel_Worksheet $pSheet
+ * @throws PHPExcel_Exception
+ */
+ public function __construct($pValue = null, $pDataType = null, PHPExcel_Worksheet $pSheet = null)
+ {
+ // Initialise cell value
+ $this->value = $pValue;
+
+ // Set worksheet cache
+ $this->parent = $pSheet->getCellCacheController();
+
+ // Set datatype?
+ if ($pDataType !== null) {
+ if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2) {
+ $pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
+ }
+ $this->dataType = $pDataType;
+ } elseif (!self::getValueBinder()->bindValue($this, $pValue)) {
+ throw new PHPExcel_Exception("Value could not be bound to cell.");
+ }
+ }
+
+ /**
+ * Get cell coordinate column
+ *
+ * @return string
+ */
+ public function getColumn()
+ {
+ return $this->parent->getCurrentColumn();
+ }
+
+ /**
+ * Get cell coordinate row
+ *
+ * @return int
+ */
+ public function getRow()
+ {
+ return $this->parent->getCurrentRow();
+ }
+
+ /**
+ * Get cell coordinate
+ *
+ * @return string
+ */
+ public function getCoordinate()
+ {
+ return $this->parent->getCurrentAddress();
+ }
+
+ /**
+ * Get cell value
+ *
+ * @return mixed
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Get cell value with formatting
+ *
+ * @return string
+ */
+ public function getFormattedValue()
+ {
+ return (string) PHPExcel_Style_NumberFormat::toFormattedString(
+ $this->getCalculatedValue(),
+ $this->getStyle()
+ ->getNumberFormat()->getFormatCode()
+ );
+ }
+
+ /**
+ * Set cell value
+ *
+ * Sets the value for a cell, automatically determining the datatype using the value binder
+ *
+ * @param mixed $pValue Value
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function setValue($pValue = null)
+ {
+ if (!self::getValueBinder()->bindValue($this, $pValue)) {
+ throw new PHPExcel_Exception("Value could not be bound to cell.");
+ }
+ return $this;
+ }
+
+ /**
+ * Set the value for a cell, with the explicit data type passed to the method (bypassing any use of the value binder)
+ *
+ * @param mixed $pValue Value
+ * @param string $pDataType Explicit data type
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function setValueExplicit($pValue = null, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
+ {
+ // set the value according to data type
+ switch ($pDataType) {
+ case PHPExcel_Cell_DataType::TYPE_NULL:
+ $this->value = $pValue;
+ break;
+ case PHPExcel_Cell_DataType::TYPE_STRING2:
+ $pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
+ // no break
+ case PHPExcel_Cell_DataType::TYPE_STRING:
+ // Synonym for string
+ case PHPExcel_Cell_DataType::TYPE_INLINE:
+ // Rich text
+ $this->value = PHPExcel_Cell_DataType::checkString($pValue);
+ break;
+ case PHPExcel_Cell_DataType::TYPE_NUMERIC:
+ $this->value = (float) $pValue;
+ break;
+ case PHPExcel_Cell_DataType::TYPE_FORMULA:
+ $this->value = (string) $pValue;
+ break;
+ case PHPExcel_Cell_DataType::TYPE_BOOL:
+ $this->value = (bool) $pValue;
+ break;
+ case PHPExcel_Cell_DataType::TYPE_ERROR:
+ $this->value = PHPExcel_Cell_DataType::checkErrorCode($pValue);
+ break;
+ default:
+ throw new PHPExcel_Exception('Invalid datatype: ' . $pDataType);
+ break;
+ }
+
+ // set the datatype
+ $this->dataType = $pDataType;
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * Get calculated cell value
+ *
+ * @deprecated Since version 1.7.8 for planned changes to cell for array formula handling
+ *
+ * @param boolean $resetLog Whether the calculation engine logger should be reset or not
+ * @return mixed
+ * @throws PHPExcel_Exception
+ */
+ public function getCalculatedValue($resetLog = true)
+ {
+//echo 'Cell '.$this->getCoordinate().' value is a '.$this->dataType.' with a value of '.$this->getValue().PHP_EOL;
+ if ($this->dataType == PHPExcel_Cell_DataType::TYPE_FORMULA) {
+ try {
+//echo 'Cell value for '.$this->getCoordinate().' is a formula: Calculating value'.PHP_EOL;
+ $result = PHPExcel_Calculation::getInstance(
+ $this->getWorksheet()->getParent()
+ )->calculateCellValue($this, $resetLog);
+//echo $this->getCoordinate().' calculation result is '.$result.PHP_EOL;
+ // We don't yet handle array returns
+ if (is_array($result)) {
+ while (is_array($result)) {
+ $result = array_pop($result);
+ }
+ }
+ } catch (PHPExcel_Exception $ex) {
+ if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->calculatedValue !== null)) {
+//echo 'Returning fallback value of '.$this->calculatedValue.' for cell '.$this->getCoordinate().PHP_EOL;
+ return $this->calculatedValue; // Fallback for calculations referencing external files.
+ }
+//echo 'Calculation Exception: '.$ex->getMessage().PHP_EOL;
+ $result = '#N/A';
+ throw new PHPExcel_Calculation_Exception(
+ $this->getWorksheet()->getTitle().'!'.$this->getCoordinate().' -> '.$ex->getMessage()
+ );
+ }
+
+ if ($result === '#Not Yet Implemented') {
+//echo 'Returning fallback value of '.$this->calculatedValue.' for cell '.$this->getCoordinate().PHP_EOL;
+ return $this->calculatedValue; // Fallback if calculation engine does not support the formula.
+ }
+//echo 'Returning calculated value of '.$result.' for cell '.$this->getCoordinate().PHP_EOL;
+ return $result;
+ } elseif ($this->value instanceof PHPExcel_RichText) {
+// echo 'Cell value for '.$this->getCoordinate().' is rich text: Returning data value of '.$this->value.' ';
+ return $this->value->getPlainText();
+ }
+// echo 'Cell value for '.$this->getCoordinate().' is not a formula: Returning data value of '.$this->value.' ';
+ return $this->value;
+ }
+
+ /**
+ * Set old calculated value (cached)
+ *
+ * @param mixed $pValue Value
+ * @return PHPExcel_Cell
+ */
+ public function setCalculatedValue($pValue = null)
+ {
+ if ($pValue !== null) {
+ $this->calculatedValue = (is_numeric($pValue)) ? (float) $pValue : $pValue;
+ }
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * Get old calculated value (cached)
+ * This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
+ * create the original spreadsheet file.
+ * Note that this value is not guaranteed to refelect the actual calculated value because it is
+ * possible that auto-calculation was disabled in the original spreadsheet, and underlying data
+ * values used by the formula have changed since it was last calculated.
+ *
+ * @return mixed
+ */
+ public function getOldCalculatedValue()
+ {
+ return $this->calculatedValue;
+ }
+
+ /**
+ * Get cell data type
+ *
+ * @return string
+ */
+ public function getDataType()
+ {
+ return $this->dataType;
+ }
+
+ /**
+ * Set cell data type
+ *
+ * @param string $pDataType
+ * @return PHPExcel_Cell
+ */
+ public function setDataType($pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
+ {
+ if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2) {
+ $pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
+ }
+ $this->dataType = $pDataType;
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * Identify if the cell contains a formula
+ *
+ * @return boolean
+ */
+ public function isFormula()
+ {
+ return $this->dataType == PHPExcel_Cell_DataType::TYPE_FORMULA;
+ }
+
+ /**
+ * Does this cell contain Data validation rules?
+ *
+ * @return boolean
+ * @throws PHPExcel_Exception
+ */
+ public function hasDataValidation()
+ {
+ if (!isset($this->parent)) {
+ throw new PHPExcel_Exception('Cannot check for data validation when cell is not bound to a worksheet');
+ }
+
+ return $this->getWorksheet()->dataValidationExists($this->getCoordinate());
+ }
+
+ /**
+ * Get Data validation rules
+ *
+ * @return PHPExcel_Cell_DataValidation
+ * @throws PHPExcel_Exception
+ */
+ public function getDataValidation()
+ {
+ if (!isset($this->parent)) {
+ throw new PHPExcel_Exception('Cannot get data validation for cell that is not bound to a worksheet');
+ }
+
+ return $this->getWorksheet()->getDataValidation($this->getCoordinate());
+ }
+
+ /**
+ * Set Data validation rules
+ *
+ * @param PHPExcel_Cell_DataValidation $pDataValidation
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function setDataValidation(PHPExcel_Cell_DataValidation $pDataValidation = null)
+ {
+ if (!isset($this->parent)) {
+ throw new PHPExcel_Exception('Cannot set data validation for cell that is not bound to a worksheet');
+ }
+
+ $this->getWorksheet()->setDataValidation($this->getCoordinate(), $pDataValidation);
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * Does this cell contain a Hyperlink?
+ *
+ * @return boolean
+ * @throws PHPExcel_Exception
+ */
+ public function hasHyperlink()
+ {
+ if (!isset($this->parent)) {
+ throw new PHPExcel_Exception('Cannot check for hyperlink when cell is not bound to a worksheet');
+ }
+
+ return $this->getWorksheet()->hyperlinkExists($this->getCoordinate());
+ }
+
+ /**
+ * Get Hyperlink
+ *
+ * @return PHPExcel_Cell_Hyperlink
+ * @throws PHPExcel_Exception
+ */
+ public function getHyperlink()
+ {
+ if (!isset($this->parent)) {
+ throw new PHPExcel_Exception('Cannot get hyperlink for cell that is not bound to a worksheet');
+ }
+
+ return $this->getWorksheet()->getHyperlink($this->getCoordinate());
+ }
+
+ /**
+ * Set Hyperlink
+ *
+ * @param PHPExcel_Cell_Hyperlink $pHyperlink
+ * @return PHPExcel_Cell
+ * @throws PHPExcel_Exception
+ */
+ public function setHyperlink(PHPExcel_Cell_Hyperlink $pHyperlink = null)
+ {
+ if (!isset($this->parent)) {
+ throw new PHPExcel_Exception('Cannot set hyperlink for cell that is not bound to a worksheet');
+ }
+
+ $this->getWorksheet()->setHyperlink($this->getCoordinate(), $pHyperlink);
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * Get parent worksheet
+ *
+ * @return PHPExcel_CachedObjectStorage_CacheBase
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Get parent worksheet
+ *
+ * @return PHPExcel_Worksheet
+ */
+ public function getWorksheet()
+ {
+ return $this->parent->getParent();
+ }
+
+ /**
+ * Is this cell in a merge range
+ *
+ * @return boolean
+ */
+ public function isInMergeRange()
+ {
+ return (boolean) $this->getMergeRange();
+ }
+
+ /**
+ * Is this cell the master (top left cell) in a merge range (that holds the actual data value)
+ *
+ * @return boolean
+ */
+ public function isMergeRangeValueCell()
+ {
+ if ($mergeRange = $this->getMergeRange()) {
+ $mergeRange = PHPExcel_Cell::splitRange($mergeRange);
+ list($startCell) = $mergeRange[0];
+ if ($this->getCoordinate() === $startCell) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * If this cell is in a merge range, then return the range
+ *
+ * @return string
+ */
+ public function getMergeRange()
+ {
+ foreach ($this->getWorksheet()->getMergeCells() as $mergeRange) {
+ if ($this->isInRange($mergeRange)) {
+ return $mergeRange;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get cell style
+ *
+ * @return PHPExcel_Style
+ */
+ public function getStyle()
+ {
+ return $this->getWorksheet()->getStyle($this->getCoordinate());
+ }
+
+ /**
+ * Re-bind parent
+ *
+ * @param PHPExcel_Worksheet $parent
+ * @return PHPExcel_Cell
+ */
+ public function rebindParent(PHPExcel_Worksheet $parent)
+ {
+ $this->parent = $parent->getCellCacheController();
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * Is cell in a specific range?
+ *
+ * @param string $pRange Cell range (e.g. A1:A1)
+ * @return boolean
+ */
+ public function isInRange($pRange = 'A1:A1')
+ {
+ list($rangeStart, $rangeEnd) = self::rangeBoundaries($pRange);
+
+ // Translate properties
+ $myColumn = self::columnIndexFromString($this->getColumn());
+ $myRow = $this->getRow();
+
+ // Verify if cell is in range
+ return (($rangeStart[0] <= $myColumn) && ($rangeEnd[0] >= $myColumn) &&
+ ($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow)
+ );
+ }
+
+ /**
+ * Coordinate from string
+ *
+ * @param string $pCoordinateString
+ * @return array Array containing column and row (indexes 0 and 1)
+ * @throws PHPExcel_Exception
+ */
+ public static function coordinateFromString($pCoordinateString = 'A1')
+ {
+ if (preg_match("/^([$]?[A-Z]{1,3})([$]?\d{1,7})$/", $pCoordinateString, $matches)) {
+ return array($matches[1],$matches[2]);
+ } elseif ((strpos($pCoordinateString, ':') !== false) || (strpos($pCoordinateString, ',') !== false)) {
+ throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
+ } elseif ($pCoordinateString == '') {
+ throw new PHPExcel_Exception('Cell coordinate can not be zero-length string');
+ }
+
+ throw new PHPExcel_Exception('Invalid cell coordinate '.$pCoordinateString);
+ }
+
+ /**
+ * Make string row, column or cell coordinate absolute
+ *
+ * @param string $pCoordinateString e.g. 'A' or '1' or 'A1'
+ * Note that this value can be a row or column reference as well as a cell reference
+ * @return string Absolute coordinate e.g. '$A' or '$1' or '$A$1'
+ * @throws PHPExcel_Exception
+ */
+ public static function absoluteReference($pCoordinateString = 'A1')
+ {
+ if (strpos($pCoordinateString, ':') === false && strpos($pCoordinateString, ',') === false) {
+ // Split out any worksheet name from the reference
+ $worksheet = '';
+ $cellAddress = explode('!', $pCoordinateString);
+ if (count($cellAddress) > 1) {
+ list($worksheet, $pCoordinateString) = $cellAddress;
+ }
+ if ($worksheet > '') {
+ $worksheet .= '!';
+ }
+
+ // Create absolute coordinate
+ if (ctype_digit($pCoordinateString)) {
+ return $worksheet . '$' . $pCoordinateString;
+ } elseif (ctype_alpha($pCoordinateString)) {
+ return $worksheet . '$' . strtoupper($pCoordinateString);
+ }
+ return $worksheet . self::absoluteCoordinate($pCoordinateString);
+ }
+
+ throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
+ }
+
+ /**
+ * Make string coordinate absolute
+ *
+ * @param string $pCoordinateString e.g. 'A1'
+ * @return string Absolute coordinate e.g. '$A$1'
+ * @throws PHPExcel_Exception
+ */
+ public static function absoluteCoordinate($pCoordinateString = 'A1')
+ {
+ if (strpos($pCoordinateString, ':') === false && strpos($pCoordinateString, ',') === false) {
+ // Split out any worksheet name from the coordinate
+ $worksheet = '';
+ $cellAddress = explode('!', $pCoordinateString);
+ if (count($cellAddress) > 1) {
+ list($worksheet, $pCoordinateString) = $cellAddress;
+ }
+ if ($worksheet > '') {
+ $worksheet .= '!';
+ }
+
+ // Create absolute coordinate
+ list($column, $row) = self::coordinateFromString($pCoordinateString);
+ $column = ltrim($column, '$');
+ $row = ltrim($row, '$');
+ return $worksheet . '$' . $column . '$' . $row;
+ }
+
+ throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
+ }
+
+ /**
+ * Split range into coordinate strings
+ *
+ * @param string $pRange e.g. 'B4:D9' or 'B4:D9,H2:O11' or 'B4'
+ * @return array Array containg one or more arrays containing one or two coordinate strings
+ * e.g. array('B4','D9') or array(array('B4','D9'),array('H2','O11'))
+ * or array('B4')
+ */
+ public static function splitRange($pRange = 'A1:A1')
+ {
+ // Ensure $pRange is a valid range
+ if (empty($pRange)) {
+ $pRange = self::DEFAULT_RANGE;
+ }
+
+ $exploded = explode(',', $pRange);
+ $counter = count($exploded);
+ for ($i = 0; $i < $counter; ++$i) {
+ $exploded[$i] = explode(':', $exploded[$i]);
+ }
+ return $exploded;
+ }
+
+ /**
+ * Build range from coordinate strings
+ *
+ * @param array $pRange Array containg one or more arrays containing one or two coordinate strings
+ * @return string String representation of $pRange
+ * @throws PHPExcel_Exception
+ */
+ public static function buildRange($pRange)
+ {
+ // Verify range
+ if (!is_array($pRange) || empty($pRange) || !is_array($pRange[0])) {
+ throw new PHPExcel_Exception('Range does not contain any information');
+ }
+
+ // Build range
+ $imploded = array();
+ $counter = count($pRange);
+ for ($i = 0; $i < $counter; ++$i) {
+ $pRange[$i] = implode(':', $pRange[$i]);
+ }
+ $imploded = implode(',', $pRange);
+
+ return $imploded;
+ }
+
+ /**
+ * Calculate range boundaries
+ *
+ * @param string $pRange Cell range (e.g. A1:A1)
+ * @return array Range coordinates array(Start Cell, End Cell)
+ * where Start Cell and End Cell are arrays (Column Number, Row Number)
+ */
+ public static function rangeBoundaries($pRange = 'A1:A1')
+ {
+ // Ensure $pRange is a valid range
+ if (empty($pRange)) {
+ $pRange = self::DEFAULT_RANGE;
+ }
+
+ // Uppercase coordinate
+ $pRange = strtoupper($pRange);
+
+ // Extract range
+ if (strpos($pRange, ':') === false) {
+ $rangeA = $rangeB = $pRange;
+ } else {
+ list($rangeA, $rangeB) = explode(':', $pRange);
+ }
+
+ // Calculate range outer borders
+ $rangeStart = self::coordinateFromString($rangeA);
+ $rangeEnd = self::coordinateFromString($rangeB);
+
+ // Translate column into index
+ $rangeStart[0] = self::columnIndexFromString($rangeStart[0]);
+ $rangeEnd[0] = self::columnIndexFromString($rangeEnd[0]);
+
+ return array($rangeStart, $rangeEnd);
+ }
+
+ /**
+ * Calculate range dimension
+ *
+ * @param string $pRange Cell range (e.g. A1:A1)
+ * @return array Range dimension (width, height)
+ */
+ public static function rangeDimension($pRange = 'A1:A1')
+ {
+ // Calculate range outer borders
+ list($rangeStart, $rangeEnd) = self::rangeBoundaries($pRange);
+
+ return array( ($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1) );
+ }
+
+ /**
+ * Calculate range boundaries
+ *
+ * @param string $pRange Cell range (e.g. A1:A1)
+ * @return array Range coordinates array(Start Cell, End Cell)
+ * where Start Cell and End Cell are arrays (Column ID, Row Number)
+ */
+ public static function getRangeBoundaries($pRange = 'A1:A1')
+ {
+ // Ensure $pRange is a valid range
+ if (empty($pRange)) {
+ $pRange = self::DEFAULT_RANGE;
+ }
+
+ // Uppercase coordinate
+ $pRange = strtoupper($pRange);
+
+ // Extract range
+ if (strpos($pRange, ':') === false) {
+ $rangeA = $rangeB = $pRange;
+ } else {
+ list($rangeA, $rangeB) = explode(':', $pRange);
+ }
+
+ return array( self::coordinateFromString($rangeA), self::coordinateFromString($rangeB));
+ }
+
+ /**
+ * Column index from string
+ *
+ * @param string $pString
+ * @return int Column index (base 1 !!!)
+ */
+ public static function columnIndexFromString($pString = 'A')
+ {
+ // Using a lookup cache adds a slight memory overhead, but boosts speed
+ // caching using a static within the method is faster than a class static,
+ // though it's additional memory overhead
+ static $_indexCache = array();
+
+ if (isset($_indexCache[$pString])) {
+ return $_indexCache[$pString];
+ }
+ // It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array rather than use ord()
+ // and make it case insensitive to get rid of the strtoupper() as well. Because it's a static, there's no significant
+ // memory overhead either
+ static $_columnLookup = array(
+ 'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8, 'I' => 9, 'J' => 10, 'K' => 11, 'L' => 12, 'M' => 13,
+ 'N' => 14, 'O' => 15, 'P' => 16, 'Q' => 17, 'R' => 18, 'S' => 19, 'T' => 20, 'U' => 21, 'V' => 22, 'W' => 23, 'X' => 24, 'Y' => 25, 'Z' => 26,
+ 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8, 'i' => 9, 'j' => 10, 'k' => 11, 'l' => 12, 'm' => 13,
+ 'n' => 14, 'o' => 15, 'p' => 16, 'q' => 17, 'r' => 18, 's' => 19, 't' => 20, 'u' => 21, 'v' => 22, 'w' => 23, 'x' => 24, 'y' => 25, 'z' => 26
+ );
+
+ // We also use the language construct isset() rather than the more costly strlen() function to match the length of $pString
+ // for improved performance
+ if (isset($pString{0})) {
+ if (!isset($pString{1})) {
+ $_indexCache[$pString] = $_columnLookup[$pString];
+ return $_indexCache[$pString];
+ } elseif (!isset($pString{2})) {
+ $_indexCache[$pString] = $_columnLookup[$pString{0}] * 26 + $_columnLookup[$pString{1}];
+ return $_indexCache[$pString];
+ } elseif (!isset($pString{3})) {
+ $_indexCache[$pString] = $_columnLookup[$pString{0}] * 676 + $_columnLookup[$pString{1}] * 26 + $_columnLookup[$pString{2}];
+ return $_indexCache[$pString];
+ }
+ }
+ throw new PHPExcel_Exception("Column string index can not be " . ((isset($pString{0})) ? "longer than 3 characters" : "empty"));
+ }
+
+ /**
+ * String from columnindex
+ *
+ * @param int $pColumnIndex Column index (base 0 !!!)
+ * @return string
+ */
+ public static function stringFromColumnIndex($pColumnIndex = 0)
+ {
+ // Using a lookup cache adds a slight memory overhead, but boosts speed
+ // caching using a static within the method is faster than a class static,
+ // though it's additional memory overhead
+ static $_indexCache = array();
+
+ if (!isset($_indexCache[$pColumnIndex])) {
+ // Determine column string
+ if ($pColumnIndex < 26) {
+ $_indexCache[$pColumnIndex] = chr(65 + $pColumnIndex);
+ } elseif ($pColumnIndex < 702) {
+ $_indexCache[$pColumnIndex] = chr(64 + ($pColumnIndex / 26)) .
+ chr(65 + $pColumnIndex % 26);
+ } else {
+ $_indexCache[$pColumnIndex] = chr(64 + (($pColumnIndex - 26) / 676)) .
+ chr(65 + ((($pColumnIndex - 26) % 676) / 26)) .
+ chr(65 + $pColumnIndex % 26);
+ }
+ }
+ return $_indexCache[$pColumnIndex];
+ }
+
+ /**
+ * Extract all cell references in range
+ *
+ * @param string $pRange Range (e.g. A1 or A1:C10 or A1:E10 A20:E25)
+ * @return array Array containing single cell references
+ */
+ public static function extractAllCellReferencesInRange($pRange = 'A1')
+ {
+ // Returnvalue
+ $returnValue = array();
+
+ // Explode spaces
+ $cellBlocks = explode(' ', str_replace('$', '', strtoupper($pRange)));
+ foreach ($cellBlocks as $cellBlock) {
+ // Single cell?
+ if (strpos($cellBlock, ':') === false && strpos($cellBlock, ',') === false) {
+ $returnValue[] = $cellBlock;
+ continue;
+ }
+
+ // Range...
+ $ranges = self::splitRange($cellBlock);
+ foreach ($ranges as $range) {
+ // Single cell?
+ if (!isset($range[1])) {
+ $returnValue[] = $range[0];
+ continue;
+ }
+
+ // Range...
+ list($rangeStart, $rangeEnd) = $range;
+ sscanf($rangeStart, '%[A-Z]%d', $startCol, $startRow);
+ sscanf($rangeEnd, '%[A-Z]%d', $endCol, $endRow);
+ ++$endCol;
+
+ // Current data
+ $currentCol = $startCol;
+ $currentRow = $startRow;
+
+ // Loop cells
+ while ($currentCol != $endCol) {
+ while ($currentRow <= $endRow) {
+ $returnValue[] = $currentCol.$currentRow;
+ ++$currentRow;
+ }
+ ++$currentCol;
+ $currentRow = $startRow;
+ }
+ }
+ }
+
+ // Sort the result by column and row
+ $sortKeys = array();
+ foreach (array_unique($returnValue) as $coord) {
+ sscanf($coord, '%[A-Z]%d', $column, $row);
+ $sortKeys[sprintf('%3s%09d', $column, $row)] = $coord;
+ }
+ ksort($sortKeys);
+
+ // Return value
+ return array_values($sortKeys);
+ }
+
+ /**
+ * Compare 2 cells
+ *
+ * @param PHPExcel_Cell $a Cell a
+ * @param PHPExcel_Cell $b Cell b
+ * @return int Result of comparison (always -1 or 1, never zero!)
+ */
+ public static function compareCells(PHPExcel_Cell $a, PHPExcel_Cell $b)
+ {
+ if ($a->getRow() < $b->getRow()) {
+ return -1;
+ } elseif ($a->getRow() > $b->getRow()) {
+ return 1;
+ } elseif (self::columnIndexFromString($a->getColumn()) < self::columnIndexFromString($b->getColumn())) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Get value binder to use
+ *
+ * @return PHPExcel_Cell_IValueBinder
+ */
+ public static function getValueBinder()
+ {
+ if (self::$valueBinder === null) {
+ self::$valueBinder = new PHPExcel_Cell_DefaultValueBinder();
+ }
+
+ return self::$valueBinder;
+ }
+
+ /**
+ * Set value binder to use
+ *
+ * @param PHPExcel_Cell_IValueBinder $binder
+ * @throws PHPExcel_Exception
+ */
+ public static function setValueBinder(PHPExcel_Cell_IValueBinder $binder = null)
+ {
+ if ($binder === null) {
+ throw new PHPExcel_Exception("A PHPExcel_Cell_IValueBinder is required for PHPExcel to function correctly.");
+ }
+
+ self::$valueBinder = $binder;
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if ((is_object($value)) && ($key != 'parent')) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+
+ /**
+ * Get index to cellXf
+ *
+ * @return int
+ */
+ public function getXfIndex()
+ {
+ return $this->xfIndex;
+ }
+
+ /**
+ * Set index to cellXf
+ *
+ * @param int $pValue
+ * @return PHPExcel_Cell
+ */
+ public function setXfIndex($pValue = 0)
+ {
+ $this->xfIndex = $pValue;
+
+ return $this->notifyCacheController();
+ }
+
+ /**
+ * @deprecated Since version 1.7.8 for planned changes to cell for array formula handling
+ */
+ public function setFormulaAttributes($pAttributes)
+ {
+ $this->formulaAttributes = $pAttributes;
+ return $this;
+ }
+
+ /**
+ * @deprecated Since version 1.7.8 for planned changes to cell for array formula handling
+ */
+ public function getFormulaAttributes()
+ {
+ return $this->formulaAttributes;
+ }
+
+ /**
+ * Convert to string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return (string) $this->getValue();
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php b/extend/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php
new file mode 100755
index 0000000..061d04e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell/AdvancedValueBinder.php
@@ -0,0 +1,187 @@
+setValueExplicit(true, PHPExcel_Cell_DataType::TYPE_BOOL);
+ return true;
+ } elseif ($value == PHPExcel_Calculation::getFALSE()) {
+ $cell->setValueExplicit(false, PHPExcel_Cell_DataType::TYPE_BOOL);
+ return true;
+ }
+
+ // Check for number in scientific format
+ if (preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NUMBER.'$/', $value)) {
+ $cell->setValueExplicit((float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ return true;
+ }
+
+ // Check for fraction
+ if (preg_match('/^([+-]?)\s*([0-9]+)\s?\/\s*([0-9]+)$/', $value, $matches)) {
+ // Convert value to number
+ $value = $matches[2] / $matches[3];
+ if ($matches[1] == '-') {
+ $value = 0 - $value;
+ }
+ $cell->setValueExplicit((float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode('??/??');
+ return true;
+ } elseif (preg_match('/^([+-]?)([0-9]*) +([0-9]*)\s?\/\s*([0-9]*)$/', $value, $matches)) {
+ // Convert value to number
+ $value = $matches[2] + ($matches[3] / $matches[4]);
+ if ($matches[1] == '-') {
+ $value = 0 - $value;
+ }
+ $cell->setValueExplicit((float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode('# ??/??');
+ return true;
+ }
+
+ // Check for percentage
+ if (preg_match('/^\-?[0-9]*\.?[0-9]*\s?\%$/', $value)) {
+ // Convert value to number
+ $value = (float) str_replace('%', '', $value) / 100;
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00);
+ return true;
+ }
+
+ // Check for currency
+ $currencyCode = PHPExcel_Shared_String::getCurrencyCode();
+ $decimalSeparator = PHPExcel_Shared_String::getDecimalSeparator();
+ $thousandsSeparator = PHPExcel_Shared_String::getThousandsSeparator();
+ if (preg_match('/^'.preg_quote($currencyCode).' *(\d{1,3}('.preg_quote($thousandsSeparator).'\d{3})*|(\d+))('.preg_quote($decimalSeparator).'\d{2})?$/', $value)) {
+ // Convert value to number
+ $value = (float) trim(str_replace(array($currencyCode, $thousandsSeparator, $decimalSeparator), array('', '', '.'), $value));
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode(
+ str_replace('$', $currencyCode, PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE)
+ );
+ return true;
+ } elseif (preg_match('/^\$ *(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/', $value)) {
+ // Convert value to number
+ $value = (float) trim(str_replace(array('$',','), '', $value));
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE);
+ return true;
+ }
+
+ // Check for time without seconds e.g. '9:45', '09:45'
+ if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
+ // Convert value to number
+ list($h, $m) = explode(':', $value);
+ $days = $h / 24 + $m / 1440;
+ $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3);
+ return true;
+ }
+
+ // Check for time with seconds '9:45:59', '09:45:59'
+ if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
+ // Convert value to number
+ list($h, $m, $s) = explode(':', $value);
+ $days = $h / 24 + $m / 1440 + $s / 86400;
+ // Convert value to number
+ $cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4);
+ return true;
+ }
+
+ // Check for datetime, e.g. '2008-12-31', '2008-12-31 15:59', '2008-12-31 15:59:10'
+ if (($d = PHPExcel_Shared_Date::stringToExcel($value)) !== false) {
+ // Convert value to number
+ $cell->setValueExplicit($d, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ // Determine style. Either there is a time part or not. Look for ':'
+ if (strpos($value, ':') !== false) {
+ $formatCode = 'yyyy-mm-dd h:mm';
+ } else {
+ $formatCode = 'yyyy-mm-dd';
+ }
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getNumberFormat()->setFormatCode($formatCode);
+ return true;
+ }
+
+ // Check for newline character "\n"
+ if (strpos($value, "\n") !== false) {
+ $value = PHPExcel_Shared_String::SanitizeUTF8($value);
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
+ // Set style
+ $cell->getWorksheet()->getStyle($cell->getCoordinate())
+ ->getAlignment()->setWrapText(true);
+ return true;
+ }
+ }
+
+ // Not bound yet? Use parent...
+ return parent::bindValue($cell, $value);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Cell/DataType.php b/extend/PHPExcel/PHPExcel/Cell/DataType.php
new file mode 100755
index 0000000..fc010e6
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell/DataType.php
@@ -0,0 +1,115 @@
+ 0,
+ '#DIV/0!' => 1,
+ '#VALUE!' => 2,
+ '#REF!' => 3,
+ '#NAME?' => 4,
+ '#NUM!' => 5,
+ '#N/A' => 6
+ );
+
+ /**
+ * Get list of error codes
+ *
+ * @return array
+ */
+ public static function getErrorCodes()
+ {
+ return self::$errorCodes;
+ }
+
+ /**
+ * DataType for value
+ *
+ * @deprecated Replaced by PHPExcel_Cell_IValueBinder infrastructure, will be removed in version 1.8.0
+ * @param mixed $pValue
+ * @return string
+ */
+ public static function dataTypeForValue($pValue = null)
+ {
+ return PHPExcel_Cell_DefaultValueBinder::dataTypeForValue($pValue);
+ }
+
+ /**
+ * Check a string that it satisfies Excel requirements
+ *
+ * @param mixed Value to sanitize to an Excel string
+ * @return mixed Sanitized value
+ */
+ public static function checkString($pValue = null)
+ {
+ if ($pValue instanceof PHPExcel_RichText) {
+ // TODO: Sanitize Rich-Text string (max. character count is 32,767)
+ return $pValue;
+ }
+
+ // string must never be longer than 32,767 characters, truncate if necessary
+ $pValue = PHPExcel_Shared_String::Substring($pValue, 0, 32767);
+
+ // we require that newline is represented as "\n" in core, not as "\r\n" or "\r"
+ $pValue = str_replace(array("\r\n", "\r"), "\n", $pValue);
+
+ return $pValue;
+ }
+
+ /**
+ * Check a value that it is a valid error code
+ *
+ * @param mixed Value to sanitize to an Excel error code
+ * @return string Sanitized value
+ */
+ public static function checkErrorCode($pValue = null)
+ {
+ $pValue = (string) $pValue;
+
+ if (!array_key_exists($pValue, self::$errorCodes)) {
+ $pValue = '#NULL!';
+ }
+
+ return $pValue;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Cell/DataValidation.php b/extend/PHPExcel/PHPExcel/Cell/DataValidation.php
new file mode 100755
index 0000000..9883633
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell/DataValidation.php
@@ -0,0 +1,492 @@
+formula1 = '';
+ $this->formula2 = '';
+ $this->type = PHPExcel_Cell_DataValidation::TYPE_NONE;
+ $this->errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;
+ $this->operator = '';
+ $this->allowBlank = false;
+ $this->showDropDown = false;
+ $this->showInputMessage = false;
+ $this->showErrorMessage = false;
+ $this->errorTitle = '';
+ $this->error = '';
+ $this->promptTitle = '';
+ $this->prompt = '';
+ }
+
+ /**
+ * Get Formula 1
+ *
+ * @return string
+ */
+ public function getFormula1()
+ {
+ return $this->formula1;
+ }
+
+ /**
+ * Set Formula 1
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setFormula1($value = '')
+ {
+ $this->formula1 = $value;
+ return $this;
+ }
+
+ /**
+ * Get Formula 2
+ *
+ * @return string
+ */
+ public function getFormula2()
+ {
+ return $this->formula2;
+ }
+
+ /**
+ * Set Formula 2
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setFormula2($value = '')
+ {
+ $this->formula2 = $value;
+ return $this;
+ }
+
+ /**
+ * Get Type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set Type
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setType($value = PHPExcel_Cell_DataValidation::TYPE_NONE)
+ {
+ $this->type = $value;
+ return $this;
+ }
+
+ /**
+ * Get Error style
+ *
+ * @return string
+ */
+ public function getErrorStyle()
+ {
+ return $this->errorStyle;
+ }
+
+ /**
+ * Set Error style
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setErrorStyle($value = PHPExcel_Cell_DataValidation::STYLE_STOP)
+ {
+ $this->errorStyle = $value;
+ return $this;
+ }
+
+ /**
+ * Get Operator
+ *
+ * @return string
+ */
+ public function getOperator()
+ {
+ return $this->operator;
+ }
+
+ /**
+ * Set Operator
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setOperator($value = '')
+ {
+ $this->operator = $value;
+ return $this;
+ }
+
+ /**
+ * Get Allow Blank
+ *
+ * @return boolean
+ */
+ public function getAllowBlank()
+ {
+ return $this->allowBlank;
+ }
+
+ /**
+ * Set Allow Blank
+ *
+ * @param boolean $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setAllowBlank($value = false)
+ {
+ $this->allowBlank = $value;
+ return $this;
+ }
+
+ /**
+ * Get Show DropDown
+ *
+ * @return boolean
+ */
+ public function getShowDropDown()
+ {
+ return $this->showDropDown;
+ }
+
+ /**
+ * Set Show DropDown
+ *
+ * @param boolean $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setShowDropDown($value = false)
+ {
+ $this->showDropDown = $value;
+ return $this;
+ }
+
+ /**
+ * Get Show InputMessage
+ *
+ * @return boolean
+ */
+ public function getShowInputMessage()
+ {
+ return $this->showInputMessage;
+ }
+
+ /**
+ * Set Show InputMessage
+ *
+ * @param boolean $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setShowInputMessage($value = false)
+ {
+ $this->showInputMessage = $value;
+ return $this;
+ }
+
+ /**
+ * Get Show ErrorMessage
+ *
+ * @return boolean
+ */
+ public function getShowErrorMessage()
+ {
+ return $this->showErrorMessage;
+ }
+
+ /**
+ * Set Show ErrorMessage
+ *
+ * @param boolean $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setShowErrorMessage($value = false)
+ {
+ $this->showErrorMessage = $value;
+ return $this;
+ }
+
+ /**
+ * Get Error title
+ *
+ * @return string
+ */
+ public function getErrorTitle()
+ {
+ return $this->errorTitle;
+ }
+
+ /**
+ * Set Error title
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setErrorTitle($value = '')
+ {
+ $this->errorTitle = $value;
+ return $this;
+ }
+
+ /**
+ * Get Error
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Set Error
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setError($value = '')
+ {
+ $this->error = $value;
+ return $this;
+ }
+
+ /**
+ * Get Prompt title
+ *
+ * @return string
+ */
+ public function getPromptTitle()
+ {
+ return $this->promptTitle;
+ }
+
+ /**
+ * Set Prompt title
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setPromptTitle($value = '')
+ {
+ $this->promptTitle = $value;
+ return $this;
+ }
+
+ /**
+ * Get Prompt
+ *
+ * @return string
+ */
+ public function getPrompt()
+ {
+ return $this->prompt;
+ }
+
+ /**
+ * Set Prompt
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_DataValidation
+ */
+ public function setPrompt($value = '')
+ {
+ $this->prompt = $value;
+ return $this;
+ }
+
+ /**
+ * Get hash code
+ *
+ * @return string Hash code
+ */
+ public function getHashCode()
+ {
+ return md5(
+ $this->formula1 .
+ $this->formula2 .
+ $this->type = PHPExcel_Cell_DataValidation::TYPE_NONE .
+ $this->errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP .
+ $this->operator .
+ ($this->allowBlank ? 't' : 'f') .
+ ($this->showDropDown ? 't' : 'f') .
+ ($this->showInputMessage ? 't' : 'f') .
+ ($this->showErrorMessage ? 't' : 'f') .
+ $this->errorTitle .
+ $this->error .
+ $this->promptTitle .
+ $this->prompt .
+ __CLASS__
+ );
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php b/extend/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php
new file mode 100755
index 0000000..dc19e6c
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell/DefaultValueBinder.php
@@ -0,0 +1,102 @@
+format('Y-m-d H:i:s');
+ } elseif (!($value instanceof PHPExcel_RichText)) {
+ $value = (string) $value;
+ }
+ }
+
+ // Set value explicit
+ $cell->setValueExplicit($value, self::dataTypeForValue($value));
+
+ // Done!
+ return true;
+ }
+
+ /**
+ * DataType for value
+ *
+ * @param mixed $pValue
+ * @return string
+ */
+ public static function dataTypeForValue($pValue = null)
+ {
+ // Match the value against a few data types
+ if ($pValue === null) {
+ return PHPExcel_Cell_DataType::TYPE_NULL;
+ } elseif ($pValue === '') {
+ return PHPExcel_Cell_DataType::TYPE_STRING;
+ } elseif ($pValue instanceof PHPExcel_RichText) {
+ return PHPExcel_Cell_DataType::TYPE_INLINE;
+ } elseif ($pValue{0} === '=' && strlen($pValue) > 1) {
+ return PHPExcel_Cell_DataType::TYPE_FORMULA;
+ } elseif (is_bool($pValue)) {
+ return PHPExcel_Cell_DataType::TYPE_BOOL;
+ } elseif (is_float($pValue) || is_int($pValue)) {
+ return PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ } elseif (preg_match('/^[\+\-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) {
+ $tValue = ltrim($pValue, '+-');
+ if (is_string($pValue) && $tValue{0} === '0' && strlen($tValue) > 1 && $tValue{1} !== '.') {
+ return PHPExcel_Cell_DataType::TYPE_STRING;
+ } elseif ((strpos($pValue, '.') === false) && ($pValue > PHP_INT_MAX)) {
+ return PHPExcel_Cell_DataType::TYPE_STRING;
+ }
+ return PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ } elseif (is_string($pValue) && array_key_exists($pValue, PHPExcel_Cell_DataType::getErrorCodes())) {
+ return PHPExcel_Cell_DataType::TYPE_ERROR;
+ }
+
+ return PHPExcel_Cell_DataType::TYPE_STRING;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Cell/Hyperlink.php b/extend/PHPExcel/PHPExcel/Cell/Hyperlink.php
new file mode 100755
index 0000000..daab54c
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell/Hyperlink.php
@@ -0,0 +1,124 @@
+url = $pUrl;
+ $this->tooltip = $pTooltip;
+ }
+
+ /**
+ * Get URL
+ *
+ * @return string
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Set URL
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_Hyperlink
+ */
+ public function setUrl($value = '')
+ {
+ $this->url = $value;
+ return $this;
+ }
+
+ /**
+ * Get tooltip
+ *
+ * @return string
+ */
+ public function getTooltip()
+ {
+ return $this->tooltip;
+ }
+
+ /**
+ * Set tooltip
+ *
+ * @param string $value
+ * @return PHPExcel_Cell_Hyperlink
+ */
+ public function setTooltip($value = '')
+ {
+ $this->tooltip = $value;
+ return $this;
+ }
+
+ /**
+ * Is this hyperlink internal? (to another worksheet)
+ *
+ * @return boolean
+ */
+ public function isInternal()
+ {
+ return strpos($this->url, 'sheet://') !== false;
+ }
+
+ /**
+ * Get hash code
+ *
+ * @return string Hash code
+ */
+ public function getHashCode()
+ {
+ return md5(
+ $this->url .
+ $this->tooltip .
+ __CLASS__
+ );
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Cell/IValueBinder.php b/extend/PHPExcel/PHPExcel/Cell/IValueBinder.php
new file mode 100755
index 0000000..de2d0ac
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Cell/IValueBinder.php
@@ -0,0 +1,47 @@
+name = $name;
+ $this->title = $title;
+ $this->legend = $legend;
+ $this->xAxisLabel = $xAxisLabel;
+ $this->yAxisLabel = $yAxisLabel;
+ $this->plotArea = $plotArea;
+ $this->plotVisibleOnly = $plotVisibleOnly;
+ $this->displayBlanksAs = $displayBlanksAs;
+ $this->xAxis = $xAxis;
+ $this->yAxis = $yAxis;
+ $this->majorGridlines = $majorGridlines;
+ $this->minorGridlines = $minorGridlines;
+ }
+
+ /**
+ * Get Name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get Worksheet
+ *
+ * @return PHPExcel_Worksheet
+ */
+ public function getWorksheet()
+ {
+ return $this->worksheet;
+ }
+
+ /**
+ * Set Worksheet
+ *
+ * @param PHPExcel_Worksheet $pValue
+ * @throws PHPExcel_Chart_Exception
+ * @return PHPExcel_Chart
+ */
+ public function setWorksheet(PHPExcel_Worksheet $pValue = null)
+ {
+ $this->worksheet = $pValue;
+
+ return $this;
+ }
+
+ /**
+ * Get Title
+ *
+ * @return PHPExcel_Chart_Title
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * Set Title
+ *
+ * @param PHPExcel_Chart_Title $title
+ * @return PHPExcel_Chart
+ */
+ public function setTitle(PHPExcel_Chart_Title $title)
+ {
+ $this->title = $title;
+
+ return $this;
+ }
+
+ /**
+ * Get Legend
+ *
+ * @return PHPExcel_Chart_Legend
+ */
+ public function getLegend()
+ {
+ return $this->legend;
+ }
+
+ /**
+ * Set Legend
+ *
+ * @param PHPExcel_Chart_Legend $legend
+ * @return PHPExcel_Chart
+ */
+ public function setLegend(PHPExcel_Chart_Legend $legend)
+ {
+ $this->legend = $legend;
+
+ return $this;
+ }
+
+ /**
+ * Get X-Axis Label
+ *
+ * @return PHPExcel_Chart_Title
+ */
+ public function getXAxisLabel()
+ {
+ return $this->xAxisLabel;
+ }
+
+ /**
+ * Set X-Axis Label
+ *
+ * @param PHPExcel_Chart_Title $label
+ * @return PHPExcel_Chart
+ */
+ public function setXAxisLabel(PHPExcel_Chart_Title $label)
+ {
+ $this->xAxisLabel = $label;
+
+ return $this;
+ }
+
+ /**
+ * Get Y-Axis Label
+ *
+ * @return PHPExcel_Chart_Title
+ */
+ public function getYAxisLabel()
+ {
+ return $this->yAxisLabel;
+ }
+
+ /**
+ * Set Y-Axis Label
+ *
+ * @param PHPExcel_Chart_Title $label
+ * @return PHPExcel_Chart
+ */
+ public function setYAxisLabel(PHPExcel_Chart_Title $label)
+ {
+ $this->yAxisLabel = $label;
+
+ return $this;
+ }
+
+ /**
+ * Get Plot Area
+ *
+ * @return PHPExcel_Chart_PlotArea
+ */
+ public function getPlotArea()
+ {
+ return $this->plotArea;
+ }
+
+ /**
+ * Get Plot Visible Only
+ *
+ * @return boolean
+ */
+ public function getPlotVisibleOnly()
+ {
+ return $this->plotVisibleOnly;
+ }
+
+ /**
+ * Set Plot Visible Only
+ *
+ * @param boolean $plotVisibleOnly
+ * @return PHPExcel_Chart
+ */
+ public function setPlotVisibleOnly($plotVisibleOnly = true)
+ {
+ $this->plotVisibleOnly = $plotVisibleOnly;
+
+ return $this;
+ }
+
+ /**
+ * Get Display Blanks as
+ *
+ * @return string
+ */
+ public function getDisplayBlanksAs()
+ {
+ return $this->displayBlanksAs;
+ }
+
+ /**
+ * Set Display Blanks as
+ *
+ * @param string $displayBlanksAs
+ * @return PHPExcel_Chart
+ */
+ public function setDisplayBlanksAs($displayBlanksAs = '0')
+ {
+ $this->displayBlanksAs = $displayBlanksAs;
+ }
+
+
+ /**
+ * Get yAxis
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ public function getChartAxisY()
+ {
+ if ($this->yAxis !== null) {
+ return $this->yAxis;
+ }
+
+ return new PHPExcel_Chart_Axis();
+ }
+
+ /**
+ * Get xAxis
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ public function getChartAxisX()
+ {
+ if ($this->xAxis !== null) {
+ return $this->xAxis;
+ }
+
+ return new PHPExcel_Chart_Axis();
+ }
+
+ /**
+ * Get Major Gridlines
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+ public function getMajorGridlines()
+ {
+ if ($this->majorGridlines !== null) {
+ return $this->majorGridlines;
+ }
+
+ return new PHPExcel_Chart_GridLines();
+ }
+
+ /**
+ * Get Minor Gridlines
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+ public function getMinorGridlines()
+ {
+ if ($this->minorGridlines !== null) {
+ return $this->minorGridlines;
+ }
+
+ return new PHPExcel_Chart_GridLines();
+ }
+
+
+ /**
+ * Set the Top Left position for the chart
+ *
+ * @param string $cell
+ * @param integer $xOffset
+ * @param integer $yOffset
+ * @return PHPExcel_Chart
+ */
+ public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
+ {
+ $this->topLeftCellRef = $cell;
+ if (!is_null($xOffset)) {
+ $this->setTopLeftXOffset($xOffset);
+ }
+ if (!is_null($yOffset)) {
+ $this->setTopLeftYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the top left position of the chart
+ *
+ * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+ */
+ public function getTopLeftPosition()
+ {
+ return array(
+ 'cell' => $this->topLeftCellRef,
+ 'xOffset' => $this->topLeftXOffset,
+ 'yOffset' => $this->topLeftYOffset
+ );
+ }
+
+ /**
+ * Get the cell address where the top left of the chart is fixed
+ *
+ * @return string
+ */
+ public function getTopLeftCell()
+ {
+ return $this->topLeftCellRef;
+ }
+
+ /**
+ * Set the Top Left cell position for the chart
+ *
+ * @param string $cell
+ * @return PHPExcel_Chart
+ */
+ public function setTopLeftCell($cell)
+ {
+ $this->topLeftCellRef = $cell;
+
+ return $this;
+ }
+
+ /**
+ * Set the offset position within the Top Left cell for the chart
+ *
+ * @param integer $xOffset
+ * @param integer $yOffset
+ * @return PHPExcel_Chart
+ */
+ public function setTopLeftOffset($xOffset = null, $yOffset = null)
+ {
+ if (!is_null($xOffset)) {
+ $this->setTopLeftXOffset($xOffset);
+ }
+ if (!is_null($yOffset)) {
+ $this->setTopLeftYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the offset position within the Top Left cell for the chart
+ *
+ * @return integer[]
+ */
+ public function getTopLeftOffset()
+ {
+ return array(
+ 'X' => $this->topLeftXOffset,
+ 'Y' => $this->topLeftYOffset
+ );
+ }
+
+ public function setTopLeftXOffset($xOffset)
+ {
+ $this->topLeftXOffset = $xOffset;
+
+ return $this;
+ }
+
+ public function getTopLeftXOffset()
+ {
+ return $this->topLeftXOffset;
+ }
+
+ public function setTopLeftYOffset($yOffset)
+ {
+ $this->topLeftYOffset = $yOffset;
+
+ return $this;
+ }
+
+ public function getTopLeftYOffset()
+ {
+ return $this->topLeftYOffset;
+ }
+
+ /**
+ * Set the Bottom Right position of the chart
+ *
+ * @param string $cell
+ * @param integer $xOffset
+ * @param integer $yOffset
+ * @return PHPExcel_Chart
+ */
+ public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
+ {
+ $this->bottomRightCellRef = $cell;
+ if (!is_null($xOffset)) {
+ $this->setBottomRightXOffset($xOffset);
+ }
+ if (!is_null($yOffset)) {
+ $this->setBottomRightYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the bottom right position of the chart
+ *
+ * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+ */
+ public function getBottomRightPosition()
+ {
+ return array(
+ 'cell' => $this->bottomRightCellRef,
+ 'xOffset' => $this->bottomRightXOffset,
+ 'yOffset' => $this->bottomRightYOffset
+ );
+ }
+
+ public function setBottomRightCell($cell)
+ {
+ $this->bottomRightCellRef = $cell;
+
+ return $this;
+ }
+
+ /**
+ * Get the cell address where the bottom right of the chart is fixed
+ *
+ * @return string
+ */
+ public function getBottomRightCell()
+ {
+ return $this->bottomRightCellRef;
+ }
+
+ /**
+ * Set the offset position within the Bottom Right cell for the chart
+ *
+ * @param integer $xOffset
+ * @param integer $yOffset
+ * @return PHPExcel_Chart
+ */
+ public function setBottomRightOffset($xOffset = null, $yOffset = null)
+ {
+ if (!is_null($xOffset)) {
+ $this->setBottomRightXOffset($xOffset);
+ }
+ if (!is_null($yOffset)) {
+ $this->setBottomRightYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the offset position within the Bottom Right cell for the chart
+ *
+ * @return integer[]
+ */
+ public function getBottomRightOffset()
+ {
+ return array(
+ 'X' => $this->bottomRightXOffset,
+ 'Y' => $this->bottomRightYOffset
+ );
+ }
+
+ public function setBottomRightXOffset($xOffset)
+ {
+ $this->bottomRightXOffset = $xOffset;
+
+ return $this;
+ }
+
+ public function getBottomRightXOffset()
+ {
+ return $this->bottomRightXOffset;
+ }
+
+ public function setBottomRightYOffset($yOffset)
+ {
+ $this->bottomRightYOffset = $yOffset;
+
+ return $this;
+ }
+
+ public function getBottomRightYOffset()
+ {
+ return $this->bottomRightYOffset;
+ }
+
+
+ public function refresh()
+ {
+ if ($this->worksheet !== null) {
+ $this->plotArea->refresh($this->worksheet);
+ }
+ }
+
+ public function render($outputDestination = null)
+ {
+ $libraryName = PHPExcel_Settings::getChartRendererName();
+ if (is_null($libraryName)) {
+ return false;
+ }
+ // Ensure that data series values are up-to-date before we render
+ $this->refresh();
+
+ $libraryPath = PHPExcel_Settings::getChartRendererPath();
+ $includePath = str_replace('\\', '/', get_include_path());
+ $rendererPath = str_replace('\\', '/', $libraryPath);
+ if (strpos($rendererPath, $includePath) === false) {
+ set_include_path(get_include_path() . PATH_SEPARATOR . $libraryPath);
+ }
+
+ $rendererName = 'PHPExcel_Chart_Renderer_'.$libraryName;
+ $renderer = new $rendererName($this);
+
+ if ($outputDestination == 'php://output') {
+ $outputDestination = null;
+ }
+ return $renderer->render($outputDestination);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Axis.php b/extend/PHPExcel/PHPExcel/Chart/Axis.php
new file mode 100755
index 0000000..9aeafc6
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Axis.php
@@ -0,0 +1,561 @@
+ self::FORMAT_CODE_GENERAL,
+ 'source_linked' => 1
+ );
+
+ /**
+ * Axis Options
+ *
+ * @var array of mixed
+ */
+ private $axisOptions = array(
+ 'minimum' => null,
+ 'maximum' => null,
+ 'major_unit' => null,
+ 'minor_unit' => null,
+ 'orientation' => self::ORIENTATION_NORMAL,
+ 'minor_tick_mark' => self::TICK_MARK_NONE,
+ 'major_tick_mark' => self::TICK_MARK_NONE,
+ 'axis_labels' => self::AXIS_LABELS_NEXT_TO,
+ 'horizontal_crosses' => self::HORIZONTAL_CROSSES_AUTOZERO,
+ 'horizontal_crosses_value' => null
+ );
+
+ /**
+ * Fill Properties
+ *
+ * @var array of mixed
+ */
+ private $fillProperties = array(
+ 'type' => self::EXCEL_COLOR_TYPE_ARGB,
+ 'value' => null,
+ 'alpha' => 0
+ );
+
+ /**
+ * Line Properties
+ *
+ * @var array of mixed
+ */
+ private $lineProperties = array(
+ 'type' => self::EXCEL_COLOR_TYPE_ARGB,
+ 'value' => null,
+ 'alpha' => 0
+ );
+
+ /**
+ * Line Style Properties
+ *
+ * @var array of mixed
+ */
+ private $lineStyleProperties = array(
+ 'width' => '9525',
+ 'compound' => self::LINE_STYLE_COMPOUND_SIMPLE,
+ 'dash' => self::LINE_STYLE_DASH_SOLID,
+ 'cap' => self::LINE_STYLE_CAP_FLAT,
+ 'join' => self::LINE_STYLE_JOIN_BEVEL,
+ 'arrow' => array(
+ 'head' => array(
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_5
+ ),
+ 'end' => array(
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_8
+ ),
+ )
+ );
+
+ /**
+ * Shadow Properties
+ *
+ * @var array of mixed
+ */
+ private $shadowProperties = array(
+ 'presets' => self::SHADOW_PRESETS_NOSHADOW,
+ 'effect' => null,
+ 'color' => array(
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 40,
+ ),
+ 'size' => array(
+ 'sx' => null,
+ 'sy' => null,
+ 'kx' => null
+ ),
+ 'blur' => null,
+ 'direction' => null,
+ 'distance' => null,
+ 'algn' => null,
+ 'rotWithShape' => null
+ );
+
+ /**
+ * Glow Properties
+ *
+ * @var array of mixed
+ */
+ private $glowProperties = array(
+ 'size' => null,
+ 'color' => array(
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 40
+ )
+ );
+
+ /**
+ * Soft Edge Properties
+ *
+ * @var array of mixed
+ */
+ private $softEdges = array(
+ 'size' => null
+ );
+
+ /**
+ * Get Series Data Type
+ *
+ * @return string
+ */
+ public function setAxisNumberProperties($format_code)
+ {
+ $this->axisNumber['format'] = (string) $format_code;
+ $this->axisNumber['source_linked'] = 0;
+ }
+
+ /**
+ * Get Axis Number Format Data Type
+ *
+ * @return string
+ */
+ public function getAxisNumberFormat()
+ {
+ return $this->axisNumber['format'];
+ }
+
+ /**
+ * Get Axis Number Source Linked
+ *
+ * @return string
+ */
+ public function getAxisNumberSourceLinked()
+ {
+ return (string) $this->axisNumber['source_linked'];
+ }
+
+ /**
+ * Set Axis Options Properties
+ *
+ * @param string $axis_labels
+ * @param string $horizontal_crosses_value
+ * @param string $horizontal_crosses
+ * @param string $axis_orientation
+ * @param string $major_tmt
+ * @param string $minor_tmt
+ * @param string $minimum
+ * @param string $maximum
+ * @param string $major_unit
+ * @param string $minor_unit
+ *
+ */
+ public function setAxisOptionsProperties($axis_labels, $horizontal_crosses_value = null, $horizontal_crosses = null, $axis_orientation = null, $major_tmt = null, $minor_tmt = null, $minimum = null, $maximum = null, $major_unit = null, $minor_unit = null)
+ {
+ $this->axisOptions['axis_labels'] = (string) $axis_labels;
+ ($horizontal_crosses_value !== null) ? $this->axisOptions['horizontal_crosses_value'] = (string) $horizontal_crosses_value : null;
+ ($horizontal_crosses !== null) ? $this->axisOptions['horizontal_crosses'] = (string) $horizontal_crosses : null;
+ ($axis_orientation !== null) ? $this->axisOptions['orientation'] = (string) $axis_orientation : null;
+ ($major_tmt !== null) ? $this->axisOptions['major_tick_mark'] = (string) $major_tmt : null;
+ ($minor_tmt !== null) ? $this->axisOptions['minor_tick_mark'] = (string) $minor_tmt : null;
+ ($minor_tmt !== null) ? $this->axisOptions['minor_tick_mark'] = (string) $minor_tmt : null;
+ ($minimum !== null) ? $this->axisOptions['minimum'] = (string) $minimum : null;
+ ($maximum !== null) ? $this->axisOptions['maximum'] = (string) $maximum : null;
+ ($major_unit !== null) ? $this->axisOptions['major_unit'] = (string) $major_unit : null;
+ ($minor_unit !== null) ? $this->axisOptions['minor_unit'] = (string) $minor_unit : null;
+ }
+
+ /**
+ * Get Axis Options Property
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getAxisOptionsProperty($property)
+ {
+ return $this->axisOptions[$property];
+ }
+
+ /**
+ * Set Axis Orientation Property
+ *
+ * @param string $orientation
+ *
+ */
+ public function setAxisOrientation($orientation)
+ {
+ $this->orientation = (string) $orientation;
+ }
+
+ /**
+ * Set Fill Property
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ */
+ public function setFillParameters($color, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_ARGB)
+ {
+ $this->fillProperties = $this->setColorProperties($color, $alpha, $type);
+ }
+
+ /**
+ * Set Line Property
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ */
+ public function setLineParameters($color, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_ARGB)
+ {
+ $this->lineProperties = $this->setColorProperties($color, $alpha, $type);
+ }
+
+ /**
+ * Get Fill Property
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getFillProperty($property)
+ {
+ return $this->fillProperties[$property];
+ }
+
+ /**
+ * Get Line Property
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getLineProperty($property)
+ {
+ return $this->lineProperties[$property];
+ }
+
+ /**
+ * Set Line Style Properties
+ *
+ * @param float $line_width
+ * @param string $compound_type
+ * @param string $dash_type
+ * @param string $cap_type
+ * @param string $join_type
+ * @param string $head_arrow_type
+ * @param string $head_arrow_size
+ * @param string $end_arrow_type
+ * @param string $end_arrow_size
+ *
+ */
+ public function setLineStyleProperties($line_width = null, $compound_type = null, $dash_type = null, $cap_type = null, $join_type = null, $head_arrow_type = null, $head_arrow_size = null, $end_arrow_type = null, $end_arrow_size = null)
+ {
+ (!is_null($line_width)) ? $this->lineStyleProperties['width'] = $this->getExcelPointsWidth((float) $line_width) : null;
+ (!is_null($compound_type)) ? $this->lineStyleProperties['compound'] = (string) $compound_type : null;
+ (!is_null($dash_type)) ? $this->lineStyleProperties['dash'] = (string) $dash_type : null;
+ (!is_null($cap_type)) ? $this->lineStyleProperties['cap'] = (string) $cap_type : null;
+ (!is_null($join_type)) ? $this->lineStyleProperties['join'] = (string) $join_type : null;
+ (!is_null($head_arrow_type)) ? $this->lineStyleProperties['arrow']['head']['type'] = (string) $head_arrow_type : null;
+ (!is_null($head_arrow_size)) ? $this->lineStyleProperties['arrow']['head']['size'] = (string) $head_arrow_size : null;
+ (!is_null($end_arrow_type)) ? $this->lineStyleProperties['arrow']['end']['type'] = (string) $end_arrow_type : null;
+ (!is_null($end_arrow_size)) ? $this->lineStyleProperties['arrow']['end']['size'] = (string) $end_arrow_size : null;
+ }
+
+ /**
+ * Get Line Style Property
+ *
+ * @param array|string $elements
+ *
+ * @return string
+ */
+ public function getLineStyleProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->lineStyleProperties, $elements);
+ }
+
+ /**
+ * Get Line Style Arrow Excel Width
+ *
+ * @param string $arrow
+ *
+ * @return string
+ */
+ public function getLineStyleArrowWidth($arrow)
+ {
+ return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'w');
+ }
+
+ /**
+ * Get Line Style Arrow Excel Length
+ *
+ * @param string $arrow
+ *
+ * @return string
+ */
+ public function getLineStyleArrowLength($arrow)
+ {
+ return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'len');
+ }
+
+ /**
+ * Set Shadow Properties
+ *
+ * @param int $shadow_presets
+ * @param string $sh_color_value
+ * @param string $sh_color_type
+ * @param string $sh_color_alpha
+ * @param float $sh_blur
+ * @param int $sh_angle
+ * @param float $sh_distance
+ *
+ */
+ public function setShadowProperties($sh_presets, $sh_color_value = null, $sh_color_type = null, $sh_color_alpha = null, $sh_blur = null, $sh_angle = null, $sh_distance = null)
+ {
+ $this->setShadowPresetsProperties((int) $sh_presets)
+ ->setShadowColor(
+ is_null($sh_color_value) ? $this->shadowProperties['color']['value'] : $sh_color_value,
+ is_null($sh_color_alpha) ? (int) $this->shadowProperties['color']['alpha'] : $sh_color_alpha,
+ is_null($sh_color_type) ? $this->shadowProperties['color']['type'] : $sh_color_type
+ )
+ ->setShadowBlur($sh_blur)
+ ->setShadowAngle($sh_angle)
+ ->setShadowDistance($sh_distance);
+ }
+
+ /**
+ * Set Shadow Color
+ *
+ * @param int $shadow_presets
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setShadowPresetsProperties($shadow_presets)
+ {
+ $this->shadowProperties['presets'] = $shadow_presets;
+ $this->setShadowProperiesMapValues($this->getShadowPresetsMap($shadow_presets));
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Properties from Maped Values
+ *
+ * @param array $properties_map
+ * @param * $reference
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
+ {
+ $base_reference = $reference;
+ foreach ($properties_map as $property_key => $property_val) {
+ if (is_array($property_val)) {
+ if ($reference === null) {
+ $reference = & $this->shadowProperties[$property_key];
+ } else {
+ $reference = & $reference[$property_key];
+ }
+ $this->setShadowProperiesMapValues($property_val, $reference);
+ } else {
+ if ($base_reference === null) {
+ $this->shadowProperties[$property_key] = $property_val;
+ } else {
+ $reference[$property_key] = $property_val;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Color
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setShadowColor($color, $alpha, $type)
+ {
+ $this->shadowProperties['color'] = $this->setColorProperties($color, $alpha, $type);
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Blur
+ *
+ * @param float $blur
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setShadowBlur($blur)
+ {
+ if ($blur !== null) {
+ $this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Angle
+ *
+ * @param int $angle
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setShadowAngle($angle)
+ {
+ if ($angle !== null) {
+ $this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Distance
+ *
+ * @param float $distance
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setShadowDistance($distance)
+ {
+ if ($distance !== null) {
+ $this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Glow Property
+ *
+ * @param float $size
+ * @param string $color_value
+ * @param int $color_alpha
+ * @param string $color_type
+ */
+ public function getShadowProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->shadowProperties, $elements);
+ }
+
+ /**
+ * Set Glow Properties
+ *
+ * @param float $size
+ * @param string $color_value
+ * @param int $color_alpha
+ * @param string $color_type
+ */
+ public function setGlowProperties($size, $color_value = null, $color_alpha = null, $color_type = null)
+ {
+ $this->setGlowSize($size)
+ ->setGlowColor(
+ is_null($color_value) ? $this->glowProperties['color']['value'] : $color_value,
+ is_null($color_alpha) ? (int) $this->glowProperties['color']['alpha'] : $color_alpha,
+ is_null($color_type) ? $this->glowProperties['color']['type'] : $color_type
+ );
+ }
+
+ /**
+ * Get Glow Property
+ *
+ * @param array|string $property
+ *
+ * @return string
+ */
+ public function getGlowProperty($property)
+ {
+ return $this->getArrayElementsValue($this->glowProperties, $property);
+ }
+
+ /**
+ * Set Glow Color
+ *
+ * @param float $size
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setGlowSize($size)
+ {
+ if (!is_null($size)) {
+ $this->glowProperties['size'] = $this->getExcelPointsWidth($size);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Glow Color
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return PHPExcel_Chart_Axis
+ */
+ private function setGlowColor($color, $alpha, $type)
+ {
+ $this->glowProperties['color'] = $this->setColorProperties($color, $alpha, $type);
+
+ return $this;
+ }
+
+ /**
+ * Set Soft Edges Size
+ *
+ * @param float $size
+ */
+ public function setSoftEdges($size)
+ {
+ if (!is_null($size)) {
+ $softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+ }
+ }
+
+ /**
+ * Get Soft Edges Size
+ *
+ * @return string
+ */
+ public function getSoftEdgesSize()
+ {
+ return $this->softEdges['size'];
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/DataSeries.php b/extend/PHPExcel/PHPExcel/Chart/DataSeries.php
new file mode 100755
index 0000000..9ecd543
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/DataSeries.php
@@ -0,0 +1,390 @@
+plotType = $plotType;
+ $this->plotGrouping = $plotGrouping;
+ $this->plotOrder = $plotOrder;
+ $keys = array_keys($plotValues);
+ $this->plotValues = $plotValues;
+ if ((count($plotLabel) == 0) || (is_null($plotLabel[$keys[0]]))) {
+ $plotLabel[$keys[0]] = new PHPExcel_Chart_DataSeriesValues();
+ }
+
+ $this->plotLabel = $plotLabel;
+ if ((count($plotCategory) == 0) || (is_null($plotCategory[$keys[0]]))) {
+ $plotCategory[$keys[0]] = new PHPExcel_Chart_DataSeriesValues();
+ }
+ $this->plotCategory = $plotCategory;
+ $this->smoothLine = $smoothLine;
+ $this->plotStyle = $plotStyle;
+
+ if (is_null($plotDirection)) {
+ $plotDirection = self::DIRECTION_COL;
+ }
+ $this->plotDirection = $plotDirection;
+ }
+
+ /**
+ * Get Plot Type
+ *
+ * @return string
+ */
+ public function getPlotType()
+ {
+ return $this->plotType;
+ }
+
+ /**
+ * Set Plot Type
+ *
+ * @param string $plotType
+ * @return PHPExcel_Chart_DataSeries
+ */
+ public function setPlotType($plotType = '')
+ {
+ $this->plotType = $plotType;
+ return $this;
+ }
+
+ /**
+ * Get Plot Grouping Type
+ *
+ * @return string
+ */
+ public function getPlotGrouping()
+ {
+ return $this->plotGrouping;
+ }
+
+ /**
+ * Set Plot Grouping Type
+ *
+ * @param string $groupingType
+ * @return PHPExcel_Chart_DataSeries
+ */
+ public function setPlotGrouping($groupingType = null)
+ {
+ $this->plotGrouping = $groupingType;
+ return $this;
+ }
+
+ /**
+ * Get Plot Direction
+ *
+ * @return string
+ */
+ public function getPlotDirection()
+ {
+ return $this->plotDirection;
+ }
+
+ /**
+ * Set Plot Direction
+ *
+ * @param string $plotDirection
+ * @return PHPExcel_Chart_DataSeries
+ */
+ public function setPlotDirection($plotDirection = null)
+ {
+ $this->plotDirection = $plotDirection;
+ return $this;
+ }
+
+ /**
+ * Get Plot Order
+ *
+ * @return string
+ */
+ public function getPlotOrder()
+ {
+ return $this->plotOrder;
+ }
+
+ /**
+ * Get Plot Labels
+ *
+ * @return array of PHPExcel_Chart_DataSeriesValues
+ */
+ public function getPlotLabels()
+ {
+ return $this->plotLabel;
+ }
+
+ /**
+ * Get Plot Label by Index
+ *
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function getPlotLabelByIndex($index)
+ {
+ $keys = array_keys($this->plotLabel);
+ if (in_array($index, $keys)) {
+ return $this->plotLabel[$index];
+ } elseif (isset($keys[$index])) {
+ return $this->plotLabel[$keys[$index]];
+ }
+ return false;
+ }
+
+ /**
+ * Get Plot Categories
+ *
+ * @return array of PHPExcel_Chart_DataSeriesValues
+ */
+ public function getPlotCategories()
+ {
+ return $this->plotCategory;
+ }
+
+ /**
+ * Get Plot Category by Index
+ *
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function getPlotCategoryByIndex($index)
+ {
+ $keys = array_keys($this->plotCategory);
+ if (in_array($index, $keys)) {
+ return $this->plotCategory[$index];
+ } elseif (isset($keys[$index])) {
+ return $this->plotCategory[$keys[$index]];
+ }
+ return false;
+ }
+
+ /**
+ * Get Plot Style
+ *
+ * @return string
+ */
+ public function getPlotStyle()
+ {
+ return $this->plotStyle;
+ }
+
+ /**
+ * Set Plot Style
+ *
+ * @param string $plotStyle
+ * @return PHPExcel_Chart_DataSeries
+ */
+ public function setPlotStyle($plotStyle = null)
+ {
+ $this->plotStyle = $plotStyle;
+ return $this;
+ }
+
+ /**
+ * Get Plot Values
+ *
+ * @return array of PHPExcel_Chart_DataSeriesValues
+ */
+ public function getPlotValues()
+ {
+ return $this->plotValues;
+ }
+
+ /**
+ * Get Plot Values by Index
+ *
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function getPlotValuesByIndex($index)
+ {
+ $keys = array_keys($this->plotValues);
+ if (in_array($index, $keys)) {
+ return $this->plotValues[$index];
+ } elseif (isset($keys[$index])) {
+ return $this->plotValues[$keys[$index]];
+ }
+ return false;
+ }
+
+ /**
+ * Get Number of Plot Series
+ *
+ * @return integer
+ */
+ public function getPlotSeriesCount()
+ {
+ return count($this->plotValues);
+ }
+
+ /**
+ * Get Smooth Line
+ *
+ * @return boolean
+ */
+ public function getSmoothLine()
+ {
+ return $this->smoothLine;
+ }
+
+ /**
+ * Set Smooth Line
+ *
+ * @param boolean $smoothLine
+ * @return PHPExcel_Chart_DataSeries
+ */
+ public function setSmoothLine($smoothLine = true)
+ {
+ $this->smoothLine = $smoothLine;
+ return $this;
+ }
+
+ public function refresh(PHPExcel_Worksheet $worksheet)
+ {
+ foreach ($this->plotValues as $plotValues) {
+ if ($plotValues !== null) {
+ $plotValues->refresh($worksheet, true);
+ }
+ }
+ foreach ($this->plotLabel as $plotValues) {
+ if ($plotValues !== null) {
+ $plotValues->refresh($worksheet, true);
+ }
+ }
+ foreach ($this->plotCategory as $plotValues) {
+ if ($plotValues !== null) {
+ $plotValues->refresh($worksheet, false);
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/DataSeriesValues.php b/extend/PHPExcel/PHPExcel/Chart/DataSeriesValues.php
new file mode 100755
index 0000000..ea57e52
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/DataSeriesValues.php
@@ -0,0 +1,333 @@
+setDataType($dataType);
+ $this->dataSource = $dataSource;
+ $this->formatCode = $formatCode;
+ $this->pointCount = $pointCount;
+ $this->dataValues = $dataValues;
+ $this->pointMarker = $marker;
+ }
+
+ /**
+ * Get Series Data Type
+ *
+ * @return string
+ */
+ public function getDataType()
+ {
+ return $this->dataType;
+ }
+
+ /**
+ * Set Series Data Type
+ *
+ * @param string $dataType Datatype of this data series
+ * Typical values are:
+ * PHPExcel_Chart_DataSeriesValues::DATASERIES_TYPE_STRING
+ * Normally used for axis point values
+ * PHPExcel_Chart_DataSeriesValues::DATASERIES_TYPE_NUMBER
+ * Normally used for chart data values
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function setDataType($dataType = self::DATASERIES_TYPE_NUMBER)
+ {
+ if (!in_array($dataType, self::$dataTypeValues)) {
+ throw new PHPExcel_Chart_Exception('Invalid datatype for chart data series values');
+ }
+ $this->dataType = $dataType;
+
+ return $this;
+ }
+
+ /**
+ * Get Series Data Source (formula)
+ *
+ * @return string
+ */
+ public function getDataSource()
+ {
+ return $this->dataSource;
+ }
+
+ /**
+ * Set Series Data Source (formula)
+ *
+ * @param string $dataSource
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function setDataSource($dataSource = null, $refreshDataValues = true)
+ {
+ $this->dataSource = $dataSource;
+
+ if ($refreshDataValues) {
+ // TO DO
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Point Marker
+ *
+ * @return string
+ */
+ public function getPointMarker()
+ {
+ return $this->pointMarker;
+ }
+
+ /**
+ * Set Point Marker
+ *
+ * @param string $marker
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function setPointMarker($marker = null)
+ {
+ $this->pointMarker = $marker;
+
+ return $this;
+ }
+
+ /**
+ * Get Series Format Code
+ *
+ * @return string
+ */
+ public function getFormatCode()
+ {
+ return $this->formatCode;
+ }
+
+ /**
+ * Set Series Format Code
+ *
+ * @param string $formatCode
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function setFormatCode($formatCode = null)
+ {
+ $this->formatCode = $formatCode;
+
+ return $this;
+ }
+
+ /**
+ * Get Series Point Count
+ *
+ * @return integer
+ */
+ public function getPointCount()
+ {
+ return $this->pointCount;
+ }
+
+ /**
+ * Identify if the Data Series is a multi-level or a simple series
+ *
+ * @return boolean
+ */
+ public function isMultiLevelSeries()
+ {
+ if (count($this->dataValues) > 0) {
+ return is_array($this->dataValues[0]);
+ }
+ return null;
+ }
+
+ /**
+ * Return the level count of a multi-level Data Series
+ *
+ * @return boolean
+ */
+ public function multiLevelCount()
+ {
+ $levelCount = 0;
+ foreach ($this->dataValues as $dataValueSet) {
+ $levelCount = max($levelCount, count($dataValueSet));
+ }
+ return $levelCount;
+ }
+
+ /**
+ * Get Series Data Values
+ *
+ * @return array of mixed
+ */
+ public function getDataValues()
+ {
+ return $this->dataValues;
+ }
+
+ /**
+ * Get the first Series Data value
+ *
+ * @return mixed
+ */
+ public function getDataValue()
+ {
+ $count = count($this->dataValues);
+ if ($count == 0) {
+ return null;
+ } elseif ($count == 1) {
+ return $this->dataValues[0];
+ }
+ return $this->dataValues;
+ }
+
+ /**
+ * Set Series Data Values
+ *
+ * @param array $dataValues
+ * @param boolean $refreshDataSource
+ * TRUE - refresh the value of dataSource based on the values of $dataValues
+ * FALSE - don't change the value of dataSource
+ * @return PHPExcel_Chart_DataSeriesValues
+ */
+ public function setDataValues($dataValues = array(), $refreshDataSource = true)
+ {
+ $this->dataValues = PHPExcel_Calculation_Functions::flattenArray($dataValues);
+ $this->pointCount = count($dataValues);
+
+ if ($refreshDataSource) {
+ // TO DO
+ }
+
+ return $this;
+ }
+
+ private function stripNulls($var)
+ {
+ return $var !== null;
+ }
+
+ public function refresh(PHPExcel_Worksheet $worksheet, $flatten = true)
+ {
+ if ($this->dataSource !== null) {
+ $calcEngine = PHPExcel_Calculation::getInstance($worksheet->getParent());
+ $newDataValues = PHPExcel_Calculation::unwrapResult(
+ $calcEngine->_calculateFormulaValue(
+ '='.$this->dataSource,
+ null,
+ $worksheet->getCell('A1')
+ )
+ );
+ if ($flatten) {
+ $this->dataValues = PHPExcel_Calculation_Functions::flattenArray($newDataValues);
+ foreach ($this->dataValues as &$dataValue) {
+ if ((!empty($dataValue)) && ($dataValue[0] == '#')) {
+ $dataValue = 0.0;
+ }
+ }
+ unset($dataValue);
+ } else {
+ $cellRange = explode('!', $this->dataSource);
+ if (count($cellRange) > 1) {
+ list(, $cellRange) = $cellRange;
+ }
+
+ $dimensions = PHPExcel_Cell::rangeDimension(str_replace('$', '', $cellRange));
+ if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
+ $this->dataValues = PHPExcel_Calculation_Functions::flattenArray($newDataValues);
+ } else {
+ $newArray = array_values(array_shift($newDataValues));
+ foreach ($newArray as $i => $newDataSet) {
+ $newArray[$i] = array($newDataSet);
+ }
+
+ foreach ($newDataValues as $newDataSet) {
+ $i = 0;
+ foreach ($newDataSet as $newDataVal) {
+ array_unshift($newArray[$i++], $newDataVal);
+ }
+ }
+ $this->dataValues = $newArray;
+ }
+ }
+ $this->pointCount = count($this->dataValues);
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Exception.php b/extend/PHPExcel/PHPExcel/Chart/Exception.php
new file mode 100755
index 0000000..e20dfa5
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Exception.php
@@ -0,0 +1,46 @@
+line = $line;
+ $e->file = $file;
+ throw $e;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/GridLines.php b/extend/PHPExcel/PHPExcel/Chart/GridLines.php
new file mode 100755
index 0000000..898012e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/GridLines.php
@@ -0,0 +1,472 @@
+ array(
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => null,
+ 'alpha' => 0
+ ),
+ 'style' => array(
+ 'width' => '9525',
+ 'compound' => self::LINE_STYLE_COMPOUND_SIMPLE,
+ 'dash' => self::LINE_STYLE_DASH_SOLID,
+ 'cap' => self::LINE_STYLE_CAP_FLAT,
+ 'join' => self::LINE_STYLE_JOIN_BEVEL,
+ 'arrow' => array(
+ 'head' => array(
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_5
+ ),
+ 'end' => array(
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_8
+ ),
+ )
+ )
+ );
+
+ private $shadowProperties = array(
+ 'presets' => self::SHADOW_PRESETS_NOSHADOW,
+ 'effect' => null,
+ 'color' => array(
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 85,
+ ),
+ 'size' => array(
+ 'sx' => null,
+ 'sy' => null,
+ 'kx' => null
+ ),
+ 'blur' => null,
+ 'direction' => null,
+ 'distance' => null,
+ 'algn' => null,
+ 'rotWithShape' => null
+ );
+
+ private $glowProperties = array(
+ 'size' => null,
+ 'color' => array(
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 40
+ )
+ );
+
+ private $softEdges = array(
+ 'size' => null
+ );
+
+ /**
+ * Get Object State
+ *
+ * @return bool
+ */
+
+ public function getObjectState()
+ {
+ return $this->objectState;
+ }
+
+ /**
+ * Change Object State to True
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+
+ private function activateObject()
+ {
+ $this->objectState = true;
+
+ return $this;
+ }
+
+ /**
+ * Set Line Color Properties
+ *
+ * @param string $value
+ * @param int $alpha
+ * @param string $type
+ */
+
+ public function setLineColorProperties($value, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_STANDARD)
+ {
+ $this->activateObject()
+ ->lineProperties['color'] = $this->setColorProperties(
+ $value,
+ $alpha,
+ $type
+ );
+ }
+
+ /**
+ * Set Line Color Properties
+ *
+ * @param float $line_width
+ * @param string $compound_type
+ * @param string $dash_type
+ * @param string $cap_type
+ * @param string $join_type
+ * @param string $head_arrow_type
+ * @param string $head_arrow_size
+ * @param string $end_arrow_type
+ * @param string $end_arrow_size
+ */
+
+ public function setLineStyleProperties($line_width = null, $compound_type = null, $dash_type = null, $cap_type = null, $join_type = null, $head_arrow_type = null, $head_arrow_size = null, $end_arrow_type = null, $end_arrow_size = null)
+ {
+ $this->activateObject();
+ (!is_null($line_width))
+ ? $this->lineProperties['style']['width'] = $this->getExcelPointsWidth((float) $line_width)
+ : null;
+ (!is_null($compound_type))
+ ? $this->lineProperties['style']['compound'] = (string) $compound_type
+ : null;
+ (!is_null($dash_type))
+ ? $this->lineProperties['style']['dash'] = (string) $dash_type
+ : null;
+ (!is_null($cap_type))
+ ? $this->lineProperties['style']['cap'] = (string) $cap_type
+ : null;
+ (!is_null($join_type))
+ ? $this->lineProperties['style']['join'] = (string) $join_type
+ : null;
+ (!is_null($head_arrow_type))
+ ? $this->lineProperties['style']['arrow']['head']['type'] = (string) $head_arrow_type
+ : null;
+ (!is_null($head_arrow_size))
+ ? $this->lineProperties['style']['arrow']['head']['size'] = (string) $head_arrow_size
+ : null;
+ (!is_null($end_arrow_type))
+ ? $this->lineProperties['style']['arrow']['end']['type'] = (string) $end_arrow_type
+ : null;
+ (!is_null($end_arrow_size))
+ ? $this->lineProperties['style']['arrow']['end']['size'] = (string) $end_arrow_size
+ : null;
+ }
+
+ /**
+ * Get Line Color Property
+ *
+ * @param string $parameter
+ *
+ * @return string
+ */
+
+ public function getLineColorProperty($parameter)
+ {
+ return $this->lineProperties['color'][$parameter];
+ }
+
+ /**
+ * Get Line Style Property
+ *
+ * @param array|string $elements
+ *
+ * @return string
+ */
+
+ public function getLineStyleProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->lineProperties['style'], $elements);
+ }
+
+ /**
+ * Set Glow Properties
+ *
+ * @param float $size
+ * @param string $color_value
+ * @param int $color_alpha
+ * @param string $color_type
+ *
+ */
+
+ public function setGlowProperties($size, $color_value = null, $color_alpha = null, $color_type = null)
+ {
+ $this
+ ->activateObject()
+ ->setGlowSize($size)
+ ->setGlowColor($color_value, $color_alpha, $color_type);
+ }
+
+ /**
+ * Get Glow Color Property
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+
+ public function getGlowColor($property)
+ {
+ return $this->glowProperties['color'][$property];
+ }
+
+ /**
+ * Get Glow Size
+ *
+ * @return string
+ */
+
+ public function getGlowSize()
+ {
+ return $this->glowProperties['size'];
+ }
+
+ /**
+ * Set Glow Size
+ *
+ * @param float $size
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+
+ private function setGlowSize($size)
+ {
+ $this->glowProperties['size'] = $this->getExcelPointsWidth((float) $size);
+
+ return $this;
+ }
+
+ /**
+ * Set Glow Color
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+
+ private function setGlowColor($color, $alpha, $type)
+ {
+ if (!is_null($color)) {
+ $this->glowProperties['color']['value'] = (string) $color;
+ }
+ if (!is_null($alpha)) {
+ $this->glowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha);
+ }
+ if (!is_null($type)) {
+ $this->glowProperties['color']['type'] = (string) $type;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Line Style Arrow Parameters
+ *
+ * @param string $arrow_selector
+ * @param string $property_selector
+ *
+ * @return string
+ */
+
+ public function getLineStyleArrowParameters($arrow_selector, $property_selector)
+ {
+ return $this->getLineStyleArrowSize($this->lineProperties['style']['arrow'][$arrow_selector]['size'], $property_selector);
+ }
+
+ /**
+ * Set Shadow Properties
+ *
+ * @param int $sh_presets
+ * @param string $sh_color_value
+ * @param string $sh_color_type
+ * @param int $sh_color_alpha
+ * @param string $sh_blur
+ * @param int $sh_angle
+ * @param float $sh_distance
+ *
+ */
+
+ public function setShadowProperties($sh_presets, $sh_color_value = null, $sh_color_type = null, $sh_color_alpha = null, $sh_blur = null, $sh_angle = null, $sh_distance = null)
+ {
+ $this->activateObject()
+ ->setShadowPresetsProperties((int) $sh_presets)
+ ->setShadowColor(
+ is_null($sh_color_value) ? $this->shadowProperties['color']['value'] : $sh_color_value,
+ is_null($sh_color_alpha) ? (int) $this->shadowProperties['color']['alpha'] : $this->getTrueAlpha($sh_color_alpha),
+ is_null($sh_color_type) ? $this->shadowProperties['color']['type'] : $sh_color_type
+ )
+ ->setShadowBlur($sh_blur)
+ ->setShadowAngle($sh_angle)
+ ->setShadowDistance($sh_distance);
+ }
+
+ /**
+ * Set Shadow Presets Properties
+ *
+ * @param int $shadow_presets
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+
+ private function setShadowPresetsProperties($shadow_presets)
+ {
+ $this->shadowProperties['presets'] = $shadow_presets;
+ $this->setShadowProperiesMapValues($this->getShadowPresetsMap($shadow_presets));
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Properties Values
+ *
+ * @param array $properties_map
+ * @param * $reference
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+
+ private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
+ {
+ $base_reference = $reference;
+ foreach ($properties_map as $property_key => $property_val) {
+ if (is_array($property_val)) {
+ if ($reference === null) {
+ $reference = & $this->shadowProperties[$property_key];
+ } else {
+ $reference = & $reference[$property_key];
+ }
+ $this->setShadowProperiesMapValues($property_val, $reference);
+ } else {
+ if ($base_reference === null) {
+ $this->shadowProperties[$property_key] = $property_val;
+ } else {
+ $reference[$property_key] = $property_val;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Color
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ * @return PHPExcel_Chart_GridLines
+ */
+ private function setShadowColor($color, $alpha, $type)
+ {
+ if (!is_null($color)) {
+ $this->shadowProperties['color']['value'] = (string) $color;
+ }
+ if (!is_null($alpha)) {
+ $this->shadowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha);
+ }
+ if (!is_null($type)) {
+ $this->shadowProperties['color']['type'] = (string) $type;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Blur
+ *
+ * @param float $blur
+ *
+ * @return PHPExcel_Chart_GridLines
+ */
+ private function setShadowBlur($blur)
+ {
+ if ($blur !== null) {
+ $this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Angle
+ *
+ * @param int $angle
+ * @return PHPExcel_Chart_GridLines
+ */
+
+ private function setShadowAngle($angle)
+ {
+ if ($angle !== null) {
+ $this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Distance
+ *
+ * @param float $distance
+ * @return PHPExcel_Chart_GridLines
+ */
+ private function setShadowDistance($distance)
+ {
+ if ($distance !== null) {
+ $this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Shadow Property
+ *
+ * @param string $elements
+ * @param array $elements
+ * @return string
+ */
+ public function getShadowProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->shadowProperties, $elements);
+ }
+
+ /**
+ * Set Soft Edges Size
+ *
+ * @param float $size
+ */
+ public function setSoftEdgesSize($size)
+ {
+ if (!is_null($size)) {
+ $this->activateObject();
+ $softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+ }
+ }
+
+ /**
+ * Get Soft Edges Size
+ *
+ * @return string
+ */
+ public function getSoftEdgesSize()
+ {
+ return $this->softEdges['size'];
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Layout.php b/extend/PHPExcel/PHPExcel/Chart/Layout.php
new file mode 100755
index 0000000..7fef074
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Layout.php
@@ -0,0 +1,486 @@
+layoutTarget = $layout['layoutTarget'];
+ }
+ if (isset($layout['xMode'])) {
+ $this->xMode = $layout['xMode'];
+ }
+ if (isset($layout['yMode'])) {
+ $this->yMode = $layout['yMode'];
+ }
+ if (isset($layout['x'])) {
+ $this->xPos = (float) $layout['x'];
+ }
+ if (isset($layout['y'])) {
+ $this->yPos = (float) $layout['y'];
+ }
+ if (isset($layout['w'])) {
+ $this->width = (float) $layout['w'];
+ }
+ if (isset($layout['h'])) {
+ $this->height = (float) $layout['h'];
+ }
+ }
+
+ /**
+ * Get Layout Target
+ *
+ * @return string
+ */
+ public function getLayoutTarget()
+ {
+ return $this->layoutTarget;
+ }
+
+ /**
+ * Set Layout Target
+ *
+ * @param Layout Target $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setLayoutTarget($value)
+ {
+ $this->layoutTarget = $value;
+ return $this;
+ }
+
+ /**
+ * Get X-Mode
+ *
+ * @return string
+ */
+ public function getXMode()
+ {
+ return $this->xMode;
+ }
+
+ /**
+ * Set X-Mode
+ *
+ * @param X-Mode $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setXMode($value)
+ {
+ $this->xMode = $value;
+ return $this;
+ }
+
+ /**
+ * Get Y-Mode
+ *
+ * @return string
+ */
+ public function getYMode()
+ {
+ return $this->yMode;
+ }
+
+ /**
+ * Set Y-Mode
+ *
+ * @param Y-Mode $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setYMode($value)
+ {
+ $this->yMode = $value;
+ return $this;
+ }
+
+ /**
+ * Get X-Position
+ *
+ * @return number
+ */
+ public function getXPosition()
+ {
+ return $this->xPos;
+ }
+
+ /**
+ * Set X-Position
+ *
+ * @param X-Position $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setXPosition($value)
+ {
+ $this->xPos = $value;
+ return $this;
+ }
+
+ /**
+ * Get Y-Position
+ *
+ * @return number
+ */
+ public function getYPosition()
+ {
+ return $this->yPos;
+ }
+
+ /**
+ * Set Y-Position
+ *
+ * @param Y-Position $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setYPosition($value)
+ {
+ $this->yPos = $value;
+ return $this;
+ }
+
+ /**
+ * Get Width
+ *
+ * @return number
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * Set Width
+ *
+ * @param Width $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setWidth($value)
+ {
+ $this->width = $value;
+ return $this;
+ }
+
+ /**
+ * Get Height
+ *
+ * @return number
+ */
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ /**
+ * Set Height
+ *
+ * @param Height $value
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setHeight($value)
+ {
+ $this->height = $value;
+ return $this;
+ }
+
+
+ /**
+ * Get show legend key
+ *
+ * @return boolean
+ */
+ public function getShowLegendKey()
+ {
+ return $this->showLegendKey;
+ }
+
+ /**
+ * Set show legend key
+ * Specifies that legend keys should be shown in data labels.
+ *
+ * @param boolean $value Show legend key
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowLegendKey($value)
+ {
+ $this->showLegendKey = $value;
+ return $this;
+ }
+
+ /**
+ * Get show value
+ *
+ * @return boolean
+ */
+ public function getShowVal()
+ {
+ return $this->showVal;
+ }
+
+ /**
+ * Set show val
+ * Specifies that the value should be shown in data labels.
+ *
+ * @param boolean $value Show val
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowVal($value)
+ {
+ $this->showVal = $value;
+ return $this;
+ }
+
+ /**
+ * Get show category name
+ *
+ * @return boolean
+ */
+ public function getShowCatName()
+ {
+ return $this->showCatName;
+ }
+
+ /**
+ * Set show cat name
+ * Specifies that the category name should be shown in data labels.
+ *
+ * @param boolean $value Show cat name
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowCatName($value)
+ {
+ $this->showCatName = $value;
+ return $this;
+ }
+
+ /**
+ * Get show data series name
+ *
+ * @return boolean
+ */
+ public function getShowSerName()
+ {
+ return $this->showSerName;
+ }
+
+ /**
+ * Set show ser name
+ * Specifies that the series name should be shown in data labels.
+ *
+ * @param boolean $value Show series name
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowSerName($value)
+ {
+ $this->showSerName = $value;
+ return $this;
+ }
+
+ /**
+ * Get show percentage
+ *
+ * @return boolean
+ */
+ public function getShowPercent()
+ {
+ return $this->showPercent;
+ }
+
+ /**
+ * Set show percentage
+ * Specifies that the percentage should be shown in data labels.
+ *
+ * @param boolean $value Show percentage
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowPercent($value)
+ {
+ $this->showPercent = $value;
+ return $this;
+ }
+
+ /**
+ * Get show bubble size
+ *
+ * @return boolean
+ */
+ public function getShowBubbleSize()
+ {
+ return $this->showBubbleSize;
+ }
+
+ /**
+ * Set show bubble size
+ * Specifies that the bubble size should be shown in data labels.
+ *
+ * @param boolean $value Show bubble size
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowBubbleSize($value)
+ {
+ $this->showBubbleSize = $value;
+ return $this;
+ }
+
+ /**
+ * Get show leader lines
+ *
+ * @return boolean
+ */
+ public function getShowLeaderLines()
+ {
+ return $this->showLeaderLines;
+ }
+
+ /**
+ * Set show leader lines
+ * Specifies that leader lines should be shown in data labels.
+ *
+ * @param boolean $value Show leader lines
+ * @return PHPExcel_Chart_Layout
+ */
+ public function setShowLeaderLines($value)
+ {
+ $this->showLeaderLines = $value;
+ return $this;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Legend.php b/extend/PHPExcel/PHPExcel/Chart/Legend.php
new file mode 100755
index 0000000..e850eb5
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Legend.php
@@ -0,0 +1,170 @@
+ self::POSITION_BOTTOM,
+ self::xlLegendPositionCorner => self::POSITION_TOPRIGHT,
+ self::xlLegendPositionCustom => '??',
+ self::xlLegendPositionLeft => self::POSITION_LEFT,
+ self::xlLegendPositionRight => self::POSITION_RIGHT,
+ self::xlLegendPositionTop => self::POSITION_TOP
+ );
+
+ /**
+ * Legend position
+ *
+ * @var string
+ */
+ private $position = self::POSITION_RIGHT;
+
+ /**
+ * Allow overlay of other elements?
+ *
+ * @var boolean
+ */
+ private $overlay = true;
+
+ /**
+ * Legend Layout
+ *
+ * @var PHPExcel_Chart_Layout
+ */
+ private $layout = null;
+
+
+ /**
+ * Create a new PHPExcel_Chart_Legend
+ */
+ public function __construct($position = self::POSITION_RIGHT, PHPExcel_Chart_Layout $layout = null, $overlay = false)
+ {
+ $this->setPosition($position);
+ $this->layout = $layout;
+ $this->setOverlay($overlay);
+ }
+
+ /**
+ * Get legend position as an excel string value
+ *
+ * @return string
+ */
+ public function getPosition()
+ {
+ return $this->position;
+ }
+
+ /**
+ * Get legend position using an excel string value
+ *
+ * @param string $position
+ */
+ public function setPosition($position = self::POSITION_RIGHT)
+ {
+ if (!in_array($position, self::$positionXLref)) {
+ return false;
+ }
+
+ $this->position = $position;
+ return true;
+ }
+
+ /**
+ * Get legend position as an Excel internal numeric value
+ *
+ * @return number
+ */
+ public function getPositionXL()
+ {
+ return array_search($this->position, self::$positionXLref);
+ }
+
+ /**
+ * Set legend position using an Excel internal numeric value
+ *
+ * @param number $positionXL
+ */
+ public function setPositionXL($positionXL = self::xlLegendPositionRight)
+ {
+ if (!array_key_exists($positionXL, self::$positionXLref)) {
+ return false;
+ }
+
+ $this->position = self::$positionXLref[$positionXL];
+ return true;
+ }
+
+ /**
+ * Get allow overlay of other elements?
+ *
+ * @return boolean
+ */
+ public function getOverlay()
+ {
+ return $this->overlay;
+ }
+
+ /**
+ * Set allow overlay of other elements?
+ *
+ * @param boolean $overlay
+ * @return boolean
+ */
+ public function setOverlay($overlay = false)
+ {
+ if (!is_bool($overlay)) {
+ return false;
+ }
+
+ $this->overlay = $overlay;
+ return true;
+ }
+
+ /**
+ * Get Layout
+ *
+ * @return PHPExcel_Chart_Layout
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/PlotArea.php b/extend/PHPExcel/PHPExcel/Chart/PlotArea.php
new file mode 100755
index 0000000..551cc51
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/PlotArea.php
@@ -0,0 +1,126 @@
+layout = $layout;
+ $this->plotSeries = $plotSeries;
+ }
+
+ /**
+ * Get Layout
+ *
+ * @return PHPExcel_Chart_Layout
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+
+ /**
+ * Get Number of Plot Groups
+ *
+ * @return array of PHPExcel_Chart_DataSeries
+ */
+ public function getPlotGroupCount()
+ {
+ return count($this->plotSeries);
+ }
+
+ /**
+ * Get Number of Plot Series
+ *
+ * @return integer
+ */
+ public function getPlotSeriesCount()
+ {
+ $seriesCount = 0;
+ foreach ($this->plotSeries as $plot) {
+ $seriesCount += $plot->getPlotSeriesCount();
+ }
+ return $seriesCount;
+ }
+
+ /**
+ * Get Plot Series
+ *
+ * @return array of PHPExcel_Chart_DataSeries
+ */
+ public function getPlotGroup()
+ {
+ return $this->plotSeries;
+ }
+
+ /**
+ * Get Plot Series by Index
+ *
+ * @return PHPExcel_Chart_DataSeries
+ */
+ public function getPlotGroupByIndex($index)
+ {
+ return $this->plotSeries[$index];
+ }
+
+ /**
+ * Set Plot Series
+ *
+ * @param [PHPExcel_Chart_DataSeries]
+ * @return PHPExcel_Chart_PlotArea
+ */
+ public function setPlotSeries($plotSeries = array())
+ {
+ $this->plotSeries = $plotSeries;
+
+ return $this;
+ }
+
+ public function refresh(PHPExcel_Worksheet $worksheet)
+ {
+ foreach ($this->plotSeries as $plotSeries) {
+ $plotSeries->refresh($worksheet);
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Properties.php b/extend/PHPExcel/PHPExcel/Chart/Properties.php
new file mode 100755
index 0000000..9bb6e93
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Properties.php
@@ -0,0 +1,363 @@
+ (string) $type,
+ 'value' => (string) $color,
+ 'alpha' => (string) $this->getTrueAlpha($alpha)
+ );
+ }
+
+ protected function getLineStyleArrowSize($array_selector, $array_kay_selector)
+ {
+ $sizes = array(
+ 1 => array('w' => 'sm', 'len' => 'sm'),
+ 2 => array('w' => 'sm', 'len' => 'med'),
+ 3 => array('w' => 'sm', 'len' => 'lg'),
+ 4 => array('w' => 'med', 'len' => 'sm'),
+ 5 => array('w' => 'med', 'len' => 'med'),
+ 6 => array('w' => 'med', 'len' => 'lg'),
+ 7 => array('w' => 'lg', 'len' => 'sm'),
+ 8 => array('w' => 'lg', 'len' => 'med'),
+ 9 => array('w' => 'lg', 'len' => 'lg')
+ );
+
+ return $sizes[$array_selector][$array_kay_selector];
+ }
+
+ protected function getShadowPresetsMap($shadow_presets_option)
+ {
+ $presets_options = array(
+ //OUTER
+ 1 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '2700000',
+ 'algn' => 'tl',
+ 'rotWithShape' => '0'
+ ),
+ 2 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '5400000',
+ 'algn' => 't',
+ 'rotWithShape' => '0'
+ ),
+ 3 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '8100000',
+ 'algn' => 'tr',
+ 'rotWithShape' => '0'
+ ),
+ 4 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'algn' => 'l',
+ 'rotWithShape' => '0'
+ ),
+ 5 => array(
+ 'effect' => 'outerShdw',
+ 'size' => array(
+ 'sx' => '102000',
+ 'sy' => '102000'
+ )
+ ,
+ 'blur' => '63500',
+ 'distance' => '38100',
+ 'algn' => 'ctr',
+ 'rotWithShape' => '0'
+ ),
+ 6 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '10800000',
+ 'algn' => 'r',
+ 'rotWithShape' => '0'
+ ),
+ 7 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '18900000',
+ 'algn' => 'bl',
+ 'rotWithShape' => '0'
+ ),
+ 8 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '16200000',
+ 'rotWithShape' => '0'
+ ),
+ 9 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '13500000',
+ 'algn' => 'br',
+ 'rotWithShape' => '0'
+ ),
+ //INNER
+ 10 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '2700000',
+ ),
+ 11 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '5400000',
+ ),
+ 12 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '8100000',
+ ),
+ 13 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ ),
+ 14 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '114300',
+ ),
+ 15 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '10800000',
+ ),
+ 16 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '18900000',
+ ),
+ 17 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '16200000',
+ ),
+ 18 => array(
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '13500000',
+ ),
+ //perspective
+ 19 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '152400',
+ 'distance' => '317500',
+ 'size' => array(
+ 'sx' => '90000',
+ 'sy' => '-19000',
+ ),
+ 'direction' => '5400000',
+ 'rotWithShape' => '0',
+ ),
+ 20 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'direction' => '18900000',
+ 'size' => array(
+ 'sy' => '23000',
+ 'kx' => '-1200000',
+ ),
+ 'algn' => 'bl',
+ 'rotWithShape' => '0',
+ ),
+ 21 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'direction' => '13500000',
+ 'size' => array(
+ 'sy' => '23000',
+ 'kx' => '1200000',
+ ),
+ 'algn' => 'br',
+ 'rotWithShape' => '0',
+ ),
+ 22 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'distance' => '12700',
+ 'direction' => '2700000',
+ 'size' => array(
+ 'sy' => '-23000',
+ 'kx' => '-800400',
+ ),
+ 'algn' => 'bl',
+ 'rotWithShape' => '0',
+ ),
+ 23 => array(
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'distance' => '12700',
+ 'direction' => '8100000',
+ 'size' => array(
+ 'sy' => '-23000',
+ 'kx' => '800400',
+ ),
+ 'algn' => 'br',
+ 'rotWithShape' => '0',
+ ),
+ );
+
+ return $presets_options[$shadow_presets_option];
+ }
+
+ protected function getArrayElementsValue($properties, $elements)
+ {
+ $reference = & $properties;
+ if (!is_array($elements)) {
+ return $reference[$elements];
+ } else {
+ foreach ($elements as $keys) {
+ $reference = & $reference[$keys];
+ }
+ return $reference;
+ }
+ return $this;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt b/extend/PHPExcel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt
new file mode 100755
index 0000000..9334f68
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt
@@ -0,0 +1,20 @@
+ChartDirector
+ http://www.advsofteng.com/cdphp.html
+
+GraPHPite
+ http://graphpite.sourceforge.net/
+
+JpGraph
+ http://www.aditus.nu/jpgraph/
+
+LibChart
+ http://naku.dohcrew.com/libchart/pages/introduction/
+
+pChart
+ http://pchart.sourceforge.net/
+
+TeeChart
+ http://www.steema.com/products/teechart/overview.html
+
+PHPGraphLib
+ http://www.ebrueggeman.com/phpgraphlib
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Chart/Renderer/jpgraph.php b/extend/PHPExcel/PHPExcel/Chart/Renderer/jpgraph.php
new file mode 100755
index 0000000..b3d7396
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Renderer/jpgraph.php
@@ -0,0 +1,883 @@
+ MARK_DIAMOND,
+ 'square' => MARK_SQUARE,
+ 'triangle' => MARK_UTRIANGLE,
+ 'x' => MARK_X,
+ 'star' => MARK_STAR,
+ 'dot' => MARK_FILLEDCIRCLE,
+ 'dash' => MARK_DTRIANGLE,
+ 'circle' => MARK_CIRCLE,
+ 'plus' => MARK_CROSS
+ );
+
+
+ private $chart;
+
+ private $graph;
+
+ private static $plotColour = 0;
+
+ private static $plotMark = 0;
+
+
+ private function formatPointMarker($seriesPlot, $markerID)
+ {
+ $plotMarkKeys = array_keys(self::$markSet);
+ if (is_null($markerID)) {
+ // Use default plot marker (next marker in the series)
+ self::$plotMark %= count(self::$markSet);
+ $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
+ } elseif ($markerID !== 'none') {
+ // Use specified plot marker (if it exists)
+ if (isset(self::$markSet[$markerID])) {
+ $seriesPlot->mark->SetType(self::$markSet[$markerID]);
+ } else {
+ // If the specified plot marker doesn't exist, use default plot marker (next marker in the series)
+ self::$plotMark %= count(self::$markSet);
+ $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
+ }
+ } else {
+ // Hide plot marker
+ $seriesPlot->mark->Hide();
+ }
+ $seriesPlot->mark->SetColor(self::$colourSet[self::$plotColour]);
+ $seriesPlot->mark->SetFillColor(self::$colourSet[self::$plotColour]);
+ $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+
+ return $seriesPlot;
+ }
+
+
+ private function formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation = '')
+ {
+ $datasetLabelFormatCode = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode();
+ if (!is_null($datasetLabelFormatCode)) {
+ // Retrieve any label formatting code
+ $datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
+ }
+
+ $testCurrentIndex = 0;
+ foreach ($datasetLabels as $i => $datasetLabel) {
+ if (is_array($datasetLabel)) {
+ if ($rotation == 'bar') {
+ $datasetLabels[$i] = implode(" ", $datasetLabel);
+ } else {
+ $datasetLabel = array_reverse($datasetLabel);
+ $datasetLabels[$i] = implode("\n", $datasetLabel);
+ }
+ } else {
+ // Format labels according to any formatting code
+ if (!is_null($datasetLabelFormatCode)) {
+ $datasetLabels[$i] = PHPExcel_Style_NumberFormat::toFormattedString($datasetLabel, $datasetLabelFormatCode);
+ }
+ }
+ ++$testCurrentIndex;
+ }
+
+ return $datasetLabels;
+ }
+
+
+ private function percentageSumCalculation($groupID, $seriesCount)
+ {
+ // Adjust our values to a percentage value across all series in the group
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ if ($i == 0) {
+ $sumValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ } else {
+ $nextValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ foreach ($nextValues as $k => $value) {
+ if (isset($sumValues[$k])) {
+ $sumValues[$k] += $value;
+ } else {
+ $sumValues[$k] = $value;
+ }
+ }
+ }
+ }
+
+ return $sumValues;
+ }
+
+
+ private function percentageAdjustValues($dataValues, $sumValues)
+ {
+ foreach ($dataValues as $k => $dataValue) {
+ $dataValues[$k] = $dataValue / $sumValues[$k] * 100;
+ }
+
+ return $dataValues;
+ }
+
+
+ private function getCaption($captionElement)
+ {
+ // Read any caption
+ $caption = (!is_null($captionElement)) ? $captionElement->getCaption() : null;
+ // Test if we have a title caption to display
+ if (!is_null($caption)) {
+ // If we do, it could be a plain string or an array
+ if (is_array($caption)) {
+ // Implode an array to a plain string
+ $caption = implode('', $caption);
+ }
+ }
+ return $caption;
+ }
+
+
+ private function renderTitle()
+ {
+ $title = $this->getCaption($this->chart->getTitle());
+ if (!is_null($title)) {
+ $this->graph->title->Set($title);
+ }
+ }
+
+
+ private function renderLegend()
+ {
+ $legend = $this->chart->getLegend();
+ if (!is_null($legend)) {
+ $legendPosition = $legend->getPosition();
+ $legendOverlay = $legend->getOverlay();
+ switch ($legendPosition) {
+ case 'r':
+ $this->graph->legend->SetPos(0.01, 0.5, 'right', 'center'); // right
+ $this->graph->legend->SetColumns(1);
+ break;
+ case 'l':
+ $this->graph->legend->SetPos(0.01, 0.5, 'left', 'center'); // left
+ $this->graph->legend->SetColumns(1);
+ break;
+ case 't':
+ $this->graph->legend->SetPos(0.5, 0.01, 'center', 'top'); // top
+ break;
+ case 'b':
+ $this->graph->legend->SetPos(0.5, 0.99, 'center', 'bottom'); // bottom
+ break;
+ default:
+ $this->graph->legend->SetPos(0.01, 0.01, 'right', 'top'); // top-right
+ $this->graph->legend->SetColumns(1);
+ break;
+ }
+ } else {
+ $this->graph->legend->Hide();
+ }
+ }
+
+
+ private function renderCartesianPlotArea($type = 'textlin')
+ {
+ $this->graph = new Graph(self::$width, self::$height);
+ $this->graph->SetScale($type);
+
+ $this->renderTitle();
+
+ // Rotate for bar rather than column chart
+ $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotDirection();
+ $reverse = ($rotation == 'bar') ? true : false;
+
+ $xAxisLabel = $this->chart->getXAxisLabel();
+ if (!is_null($xAxisLabel)) {
+ $title = $this->getCaption($xAxisLabel);
+ if (!is_null($title)) {
+ $this->graph->xaxis->SetTitle($title, 'center');
+ $this->graph->xaxis->title->SetMargin(35);
+ if ($reverse) {
+ $this->graph->xaxis->title->SetAngle(90);
+ $this->graph->xaxis->title->SetMargin(90);
+ }
+ }
+ }
+
+ $yAxisLabel = $this->chart->getYAxisLabel();
+ if (!is_null($yAxisLabel)) {
+ $title = $this->getCaption($yAxisLabel);
+ if (!is_null($title)) {
+ $this->graph->yaxis->SetTitle($title, 'center');
+ if ($reverse) {
+ $this->graph->yaxis->title->SetAngle(0);
+ $this->graph->yaxis->title->SetMargin(-55);
+ }
+ }
+ }
+ }
+
+
+ private function renderPiePlotArea($doughnut = false)
+ {
+ $this->graph = new PieGraph(self::$width, self::$height);
+
+ $this->renderTitle();
+ }
+
+
+ private function renderRadarPlotArea()
+ {
+ $this->graph = new RadarGraph(self::$width, self::$height);
+ $this->graph->SetScale('lin');
+
+ $this->renderTitle();
+ }
+
+
+ private function renderPlotLine($groupID, $filled = false, $combination = false, $dimensions = '2d')
+ {
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+ $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+ $this->graph->xaxis->SetTickLabels($datasetLabels);
+ }
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = array();
+ if ($grouping == 'percentStacked') {
+ $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
+ }
+
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+ if ($grouping == 'percentStacked') {
+ $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
+ }
+
+ // Fill in any missing values in the $dataValues array
+ $testCurrentIndex = 0;
+ foreach ($dataValues as $k => $dataValue) {
+ while ($k != $testCurrentIndex) {
+ $dataValues[$testCurrentIndex] = null;
+ ++$testCurrentIndex;
+ }
+ ++$testCurrentIndex;
+ }
+
+ $seriesPlot = new LinePlot($dataValues);
+ if ($combination) {
+ $seriesPlot->SetBarCenter();
+ }
+
+ if ($filled) {
+ $seriesPlot->SetFilled(true);
+ $seriesPlot->SetColor('black');
+ $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
+ } else {
+ // Set the appropriate plot marker
+ $this->formatPointMarker($seriesPlot, $marker);
+ }
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+ $seriesPlot->SetLegend($dataLabel);
+
+ $seriesPlots[] = $seriesPlot;
+ }
+
+ if ($grouping == 'standard') {
+ $groupPlot = $seriesPlots;
+ } else {
+ $groupPlot = new AccLinePlot($seriesPlots);
+ }
+ $this->graph->Add($groupPlot);
+ }
+
+
+ private function renderPlotBar($groupID, $dimensions = '2d')
+ {
+ $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotDirection();
+ // Rotate for bar rather than column chart
+ if (($groupID == 0) && ($rotation == 'bar')) {
+ $this->graph->Set90AndMargin();
+ }
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+ $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation);
+ // Rotate for bar rather than column chart
+ if ($rotation == 'bar') {
+ $datasetLabels = array_reverse($datasetLabels);
+ $this->graph->yaxis->SetPos('max');
+ $this->graph->yaxis->SetLabelAlign('center', 'top');
+ $this->graph->yaxis->SetLabelSide(SIDE_RIGHT);
+ }
+ $this->graph->xaxis->SetTickLabels($datasetLabels);
+ }
+
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = array();
+ if ($grouping == 'percentStacked') {
+ $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
+ }
+
+ // Loop through each data series in turn
+ for ($j = 0; $j < $seriesCount; ++$j) {
+ $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+ if ($grouping == 'percentStacked') {
+ $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
+ }
+
+ // Fill in any missing values in the $dataValues array
+ $testCurrentIndex = 0;
+ foreach ($dataValues as $k => $dataValue) {
+ while ($k != $testCurrentIndex) {
+ $dataValues[$testCurrentIndex] = null;
+ ++$testCurrentIndex;
+ }
+ ++$testCurrentIndex;
+ }
+
+ // Reverse the $dataValues order for bar rather than column chart
+ if ($rotation == 'bar') {
+ $dataValues = array_reverse($dataValues);
+ }
+ $seriesPlot = new BarPlot($dataValues);
+ $seriesPlot->SetColor('black');
+ $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
+ if ($dimensions == '3d') {
+ $seriesPlot->SetShadow();
+ }
+ if (!$this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
+ $dataLabel = '';
+ } else {
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
+ }
+ $seriesPlot->SetLegend($dataLabel);
+
+ $seriesPlots[] = $seriesPlot;
+ }
+ // Reverse the plot order for bar rather than column chart
+ if (($rotation == 'bar') && (!($grouping == 'percentStacked'))) {
+ $seriesPlots = array_reverse($seriesPlots);
+ }
+
+ if ($grouping == 'clustered') {
+ $groupPlot = new GroupBarPlot($seriesPlots);
+ } elseif ($grouping == 'standard') {
+ $groupPlot = new GroupBarPlot($seriesPlots);
+ } else {
+ $groupPlot = new AccBarPlot($seriesPlots);
+ if ($dimensions == '3d') {
+ $groupPlot->SetShadow();
+ }
+ }
+
+ $this->graph->Add($groupPlot);
+ }
+
+
+ private function renderPlotScatter($groupID, $bubble)
+ {
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+ $scatterStyle = $bubbleSize = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = array();
+
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+ foreach ($dataValuesY as $k => $dataValueY) {
+ $dataValuesY[$k] = $k;
+ }
+
+ $seriesPlot = new ScatterPlot($dataValuesX, $dataValuesY);
+ if ($scatterStyle == 'lineMarker') {
+ $seriesPlot->SetLinkPoints();
+ $seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
+ } elseif ($scatterStyle == 'smoothMarker') {
+ $spline = new Spline($dataValuesY, $dataValuesX);
+ list($splineDataY, $splineDataX) = $spline->Get(count($dataValuesX) * self::$width / 20);
+ $lplot = new LinePlot($splineDataX, $splineDataY);
+ $lplot->SetColor(self::$colourSet[self::$plotColour]);
+
+ $this->graph->Add($lplot);
+ }
+
+ if ($bubble) {
+ $this->formatPointMarker($seriesPlot, 'dot');
+ $seriesPlot->mark->SetColor('black');
+ $seriesPlot->mark->SetSize($bubbleSize);
+ } else {
+ $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+ $this->formatPointMarker($seriesPlot, $marker);
+ }
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+ $seriesPlot->SetLegend($dataLabel);
+
+ $this->graph->Add($seriesPlot);
+ }
+ }
+
+
+ private function renderPlotRadar($groupID)
+ {
+ $radarStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = array();
+
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+ $dataValues = array();
+ foreach ($dataValuesY as $k => $dataValueY) {
+ $dataValues[$k] = implode(' ', array_reverse($dataValueY));
+ }
+ $tmp = array_shift($dataValues);
+ $dataValues[] = $tmp;
+ $tmp = array_shift($dataValuesX);
+ $dataValuesX[] = $tmp;
+
+ $this->graph->SetTitles(array_reverse($dataValues));
+
+ $seriesPlot = new RadarPlot(array_reverse($dataValuesX));
+
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+ $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+ if ($radarStyle == 'filled') {
+ $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour]);
+ }
+ $this->formatPointMarker($seriesPlot, $marker);
+ $seriesPlot->SetLegend($dataLabel);
+
+ $this->graph->Add($seriesPlot);
+ }
+ }
+
+
+ private function renderPlotContour($groupID)
+ {
+ $contourStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = array();
+
+ $dataValues = array();
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+ $dataValues[$i] = $dataValuesX;
+ }
+ $seriesPlot = new ContourPlot($dataValues);
+
+ $this->graph->Add($seriesPlot);
+ }
+
+
+ private function renderPlotStock($groupID)
+ {
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $plotOrder = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder();
+
+ $dataValues = array();
+ // Loop through each data series in turn and build the plot arrays
+ foreach ($plotOrder as $i => $v) {
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($v)->getDataValues();
+ foreach ($dataValuesX as $j => $dataValueX) {
+ $dataValues[$plotOrder[$i]][$j] = $dataValueX;
+ }
+ }
+ if (empty($dataValues)) {
+ return;
+ }
+
+ $dataValuesPlot = array();
+ // Flatten the plot arrays to a single dimensional array to work with jpgraph
+ for ($j = 0; $j < count($dataValues[0]); ++$j) {
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesPlot[] = $dataValues[$i][$j];
+ }
+ }
+
+ // Set the x-axis labels
+ $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+ $this->graph->xaxis->SetTickLabels($datasetLabels);
+ }
+
+ $seriesPlot = new StockPlot($dataValuesPlot);
+ $seriesPlot->SetWidth(20);
+
+ $this->graph->Add($seriesPlot);
+ }
+
+
+ private function renderAreaChart($groupCount, $dimensions = '2d')
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotLine($i, true, false, $dimensions);
+ }
+ }
+
+
+ private function renderLineChart($groupCount, $dimensions = '2d')
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotLine($i, false, false, $dimensions);
+ }
+ }
+
+
+ private function renderBarChart($groupCount, $dimensions = '2d')
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_bar.php');
+
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotBar($i, $dimensions);
+ }
+ }
+
+
+ private function renderScatterChart($groupCount)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_regstat.php');
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+ $this->renderCartesianPlotArea('linlin');
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotScatter($i, false);
+ }
+ }
+
+
+ private function renderBubbleChart($groupCount)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
+
+ $this->renderCartesianPlotArea('linlin');
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotScatter($i, true);
+ }
+ }
+
+
+ private function renderPieChart($groupCount, $dimensions = '2d', $doughnut = false, $multiplePlots = false)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_pie.php');
+ if ($dimensions == '3d') {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_pie3d.php');
+ }
+
+ $this->renderPiePlotArea($doughnut);
+
+ $iLimit = ($multiplePlots) ? $groupCount : 1;
+ for ($groupID = 0; $groupID < $iLimit; ++$groupID) {
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+ $exploded = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+ if ($groupID == 0) {
+ $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+ }
+ }
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = array();
+ // For pie charts, we only display the first series: doughnut charts generally display all series
+ $jLimit = ($multiplePlots) ? $seriesCount : 1;
+ // Loop through each data series in turn
+ for ($j = 0; $j < $jLimit; ++$j) {
+ $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+
+ // Fill in any missing values in the $dataValues array
+ $testCurrentIndex = 0;
+ foreach ($dataValues as $k => $dataValue) {
+ while ($k != $testCurrentIndex) {
+ $dataValues[$testCurrentIndex] = null;
+ ++$testCurrentIndex;
+ }
+ ++$testCurrentIndex;
+ }
+
+ if ($dimensions == '3d') {
+ $seriesPlot = new PiePlot3D($dataValues);
+ } else {
+ if ($doughnut) {
+ $seriesPlot = new PiePlotC($dataValues);
+ } else {
+ $seriesPlot = new PiePlot($dataValues);
+ }
+ }
+
+ if ($multiplePlots) {
+ $seriesPlot->SetSize(($jLimit-$j) / ($jLimit * 4));
+ }
+
+ if ($doughnut) {
+ $seriesPlot->SetMidColor('white');
+ }
+
+ $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+ if (count($datasetLabels) > 0) {
+ $seriesPlot->SetLabels(array_fill(0, count($datasetLabels), ''));
+ }
+ if ($dimensions != '3d') {
+ $seriesPlot->SetGuideLines(false);
+ }
+ if ($j == 0) {
+ if ($exploded) {
+ $seriesPlot->ExplodeAll();
+ }
+ $seriesPlot->SetLegends($datasetLabels);
+ }
+
+ $this->graph->Add($seriesPlot);
+ }
+ }
+ }
+
+
+ private function renderRadarChart($groupCount)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_radar.php');
+
+ $this->renderRadarPlotArea();
+
+ for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
+ $this->renderPlotRadar($groupID);
+ }
+ }
+
+
+ private function renderStockChart($groupCount)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_stock.php');
+
+ $this->renderCartesianPlotArea('intint');
+
+ for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
+ $this->renderPlotStock($groupID);
+ }
+ }
+
+
+ private function renderContourChart($groupCount, $dimensions)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_contour.php');
+
+ $this->renderCartesianPlotArea('intint');
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotContour($i);
+ }
+ }
+
+
+ private function renderCombinationChart($groupCount, $dimensions, $outputDestination)
+ {
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_bar.php');
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_regstat.php');
+ require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
+
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $dimensions = null;
+ $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+ switch ($chartType) {
+ case 'area3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'areaChart':
+ $this->renderPlotLine($i, true, true, $dimensions);
+ break;
+ case 'bar3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'barChart':
+ $this->renderPlotBar($i, $dimensions);
+ break;
+ case 'line3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'lineChart':
+ $this->renderPlotLine($i, false, true, $dimensions);
+ break;
+ case 'scatterChart':
+ $this->renderPlotScatter($i, false);
+ break;
+ case 'bubbleChart':
+ $this->renderPlotScatter($i, true);
+ break;
+ default:
+ $this->graph = null;
+ return false;
+ }
+ }
+
+ $this->renderLegend();
+
+ $this->graph->Stroke($outputDestination);
+ return true;
+ }
+
+
+ public function render($outputDestination)
+ {
+ self::$plotColour = 0;
+
+ $groupCount = $this->chart->getPlotArea()->getPlotGroupCount();
+
+ $dimensions = null;
+ if ($groupCount == 1) {
+ $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType();
+ } else {
+ $chartTypes = array();
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $chartTypes[] = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+ }
+ $chartTypes = array_unique($chartTypes);
+ if (count($chartTypes) == 1) {
+ $chartType = array_pop($chartTypes);
+ } elseif (count($chartTypes) == 0) {
+ echo 'Chart is not yet implemented ';
+ return false;
+ } else {
+ return $this->renderCombinationChart($groupCount, $dimensions, $outputDestination);
+ }
+ }
+
+ switch ($chartType) {
+ case 'area3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'areaChart':
+ $this->renderAreaChart($groupCount, $dimensions);
+ break;
+ case 'bar3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'barChart':
+ $this->renderBarChart($groupCount, $dimensions);
+ break;
+ case 'line3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'lineChart':
+ $this->renderLineChart($groupCount, $dimensions);
+ break;
+ case 'pie3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'pieChart':
+ $this->renderPieChart($groupCount, $dimensions, false, false);
+ break;
+ case 'doughnut3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'doughnutChart':
+ $this->renderPieChart($groupCount, $dimensions, true, true);
+ break;
+ case 'scatterChart':
+ $this->renderScatterChart($groupCount);
+ break;
+ case 'bubbleChart':
+ $this->renderBubbleChart($groupCount);
+ break;
+ case 'radarChart':
+ $this->renderRadarChart($groupCount);
+ break;
+ case 'surface3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'surfaceChart':
+ $this->renderContourChart($groupCount, $dimensions);
+ break;
+ case 'stockChart':
+ $this->renderStockChart($groupCount, $dimensions);
+ break;
+ default:
+ echo $chartType.' is not yet implemented ';
+ return false;
+ }
+ $this->renderLegend();
+
+ $this->graph->Stroke($outputDestination);
+ return true;
+ }
+
+
+ /**
+ * Create a new PHPExcel_Chart_Renderer_jpgraph
+ */
+ public function __construct(PHPExcel_Chart $chart)
+ {
+ $this->graph = null;
+ $this->chart = $chart;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Chart/Title.php b/extend/PHPExcel/PHPExcel/Chart/Title.php
new file mode 100755
index 0000000..d8dc14f
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Chart/Title.php
@@ -0,0 +1,86 @@
+caption = $caption;
+ $this->layout = $layout;
+ }
+
+ /**
+ * Get caption
+ *
+ * @return string
+ */
+ public function getCaption()
+ {
+ return $this->caption;
+ }
+
+ /**
+ * Set caption
+ *
+ * @param string $caption
+ * @return PHPExcel_Chart_Title
+ */
+ public function setCaption($caption = null)
+ {
+ $this->caption = $caption;
+
+ return $this;
+ }
+
+ /**
+ * Get Layout
+ *
+ * @return PHPExcel_Chart_Layout
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Comment.php b/extend/PHPExcel/PHPExcel/Comment.php
new file mode 100755
index 0000000..d55363f
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Comment.php
@@ -0,0 +1,338 @@
+author = 'Author';
+ $this->text = new PHPExcel_RichText();
+ $this->fillColor = new PHPExcel_Style_Color('FFFFFFE1');
+ $this->alignment = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL;
+ }
+
+ /**
+ * Get Author
+ *
+ * @return string
+ */
+ public function getAuthor()
+ {
+ return $this->author;
+ }
+
+ /**
+ * Set Author
+ *
+ * @param string $pValue
+ * @return PHPExcel_Comment
+ */
+ public function setAuthor($pValue = '')
+ {
+ $this->author = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Rich text comment
+ *
+ * @return PHPExcel_RichText
+ */
+ public function getText()
+ {
+ return $this->text;
+ }
+
+ /**
+ * Set Rich text comment
+ *
+ * @param PHPExcel_RichText $pValue
+ * @return PHPExcel_Comment
+ */
+ public function setText(PHPExcel_RichText $pValue)
+ {
+ $this->text = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get comment width (CSS style, i.e. XXpx or YYpt)
+ *
+ * @return string
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * Set comment width (CSS style, i.e. XXpx or YYpt)
+ *
+ * @param string $value
+ * @return PHPExcel_Comment
+ */
+ public function setWidth($value = '96pt')
+ {
+ $this->width = $value;
+ return $this;
+ }
+
+ /**
+ * Get comment height (CSS style, i.e. XXpx or YYpt)
+ *
+ * @return string
+ */
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ /**
+ * Set comment height (CSS style, i.e. XXpx or YYpt)
+ *
+ * @param string $value
+ * @return PHPExcel_Comment
+ */
+ public function setHeight($value = '55.5pt')
+ {
+ $this->height = $value;
+ return $this;
+ }
+
+ /**
+ * Get left margin (CSS style, i.e. XXpx or YYpt)
+ *
+ * @return string
+ */
+ public function getMarginLeft()
+ {
+ return $this->marginLeft;
+ }
+
+ /**
+ * Set left margin (CSS style, i.e. XXpx or YYpt)
+ *
+ * @param string $value
+ * @return PHPExcel_Comment
+ */
+ public function setMarginLeft($value = '59.25pt')
+ {
+ $this->marginLeft = $value;
+ return $this;
+ }
+
+ /**
+ * Get top margin (CSS style, i.e. XXpx or YYpt)
+ *
+ * @return string
+ */
+ public function getMarginTop()
+ {
+ return $this->marginTop;
+ }
+
+ /**
+ * Set top margin (CSS style, i.e. XXpx or YYpt)
+ *
+ * @param string $value
+ * @return PHPExcel_Comment
+ */
+ public function setMarginTop($value = '1.5pt')
+ {
+ $this->marginTop = $value;
+ return $this;
+ }
+
+ /**
+ * Is the comment visible by default?
+ *
+ * @return boolean
+ */
+ public function getVisible()
+ {
+ return $this->visible;
+ }
+
+ /**
+ * Set comment default visibility
+ *
+ * @param boolean $value
+ * @return PHPExcel_Comment
+ */
+ public function setVisible($value = false)
+ {
+ $this->visible = $value;
+ return $this;
+ }
+
+ /**
+ * Get fill color
+ *
+ * @return PHPExcel_Style_Color
+ */
+ public function getFillColor()
+ {
+ return $this->fillColor;
+ }
+
+ /**
+ * Set Alignment
+ *
+ * @param string $pValue
+ * @return PHPExcel_Comment
+ */
+ public function setAlignment($pValue = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL)
+ {
+ $this->alignment = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Alignment
+ *
+ * @return string
+ */
+ public function getAlignment()
+ {
+ return $this->alignment;
+ }
+
+ /**
+ * Get hash code
+ *
+ * @return string Hash code
+ */
+ public function getHashCode()
+ {
+ return md5(
+ $this->author .
+ $this->text->getHashCode() .
+ $this->width .
+ $this->height .
+ $this->marginLeft .
+ $this->marginTop .
+ ($this->visible ? 1 : 0) .
+ $this->fillColor->getHashCode() .
+ $this->alignment .
+ __CLASS__
+ );
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+
+ /**
+ * Convert to string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->text->getPlainText();
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/DocumentProperties.php b/extend/PHPExcel/PHPExcel/DocumentProperties.php
new file mode 100755
index 0000000..2395ba9
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/DocumentProperties.php
@@ -0,0 +1,611 @@
+lastModifiedBy = $this->creator;
+ $this->created = time();
+ $this->modified = time();
+ }
+
+ /**
+ * Get Creator
+ *
+ * @return string
+ */
+ public function getCreator()
+ {
+ return $this->creator;
+ }
+
+ /**
+ * Set Creator
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setCreator($pValue = '')
+ {
+ $this->creator = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Last Modified By
+ *
+ * @return string
+ */
+ public function getLastModifiedBy()
+ {
+ return $this->lastModifiedBy;
+ }
+
+ /**
+ * Set Last Modified By
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setLastModifiedBy($pValue = '')
+ {
+ $this->lastModifiedBy = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Created
+ *
+ * @return datetime
+ */
+ public function getCreated()
+ {
+ return $this->created;
+ }
+
+ /**
+ * Set Created
+ *
+ * @param datetime $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setCreated($pValue = null)
+ {
+ if ($pValue === null) {
+ $pValue = time();
+ } elseif (is_string($pValue)) {
+ if (is_numeric($pValue)) {
+ $pValue = intval($pValue);
+ } else {
+ $pValue = strtotime($pValue);
+ }
+ }
+
+ $this->created = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Modified
+ *
+ * @return datetime
+ */
+ public function getModified()
+ {
+ return $this->modified;
+ }
+
+ /**
+ * Set Modified
+ *
+ * @param datetime $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setModified($pValue = null)
+ {
+ if ($pValue === null) {
+ $pValue = time();
+ } elseif (is_string($pValue)) {
+ if (is_numeric($pValue)) {
+ $pValue = intval($pValue);
+ } else {
+ $pValue = strtotime($pValue);
+ }
+ }
+
+ $this->modified = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Title
+ *
+ * @return string
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * Set Title
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setTitle($pValue = '')
+ {
+ $this->title = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Description
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ /**
+ * Set Description
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setDescription($pValue = '')
+ {
+ $this->description = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Subject
+ *
+ * @return string
+ */
+ public function getSubject()
+ {
+ return $this->subject;
+ }
+
+ /**
+ * Set Subject
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setSubject($pValue = '')
+ {
+ $this->subject = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Keywords
+ *
+ * @return string
+ */
+ public function getKeywords()
+ {
+ return $this->keywords;
+ }
+
+ /**
+ * Set Keywords
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setKeywords($pValue = '')
+ {
+ $this->keywords = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Category
+ *
+ * @return string
+ */
+ public function getCategory()
+ {
+ return $this->category;
+ }
+
+ /**
+ * Set Category
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setCategory($pValue = '')
+ {
+ $this->category = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Company
+ *
+ * @return string
+ */
+ public function getCompany()
+ {
+ return $this->company;
+ }
+
+ /**
+ * Set Company
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setCompany($pValue = '')
+ {
+ $this->company = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get Manager
+ *
+ * @return string
+ */
+ public function getManager()
+ {
+ return $this->manager;
+ }
+
+ /**
+ * Set Manager
+ *
+ * @param string $pValue
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setManager($pValue = '')
+ {
+ $this->manager = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get a List of Custom Property Names
+ *
+ * @return array of string
+ */
+ public function getCustomProperties()
+ {
+ return array_keys($this->customProperties);
+ }
+
+ /**
+ * Check if a Custom Property is defined
+ *
+ * @param string $propertyName
+ * @return boolean
+ */
+ public function isCustomPropertySet($propertyName)
+ {
+ return isset($this->customProperties[$propertyName]);
+ }
+
+ /**
+ * Get a Custom Property Value
+ *
+ * @param string $propertyName
+ * @return string
+ */
+ public function getCustomPropertyValue($propertyName)
+ {
+ if (isset($this->customProperties[$propertyName])) {
+ return $this->customProperties[$propertyName]['value'];
+ }
+
+ }
+
+ /**
+ * Get a Custom Property Type
+ *
+ * @param string $propertyName
+ * @return string
+ */
+ public function getCustomPropertyType($propertyName)
+ {
+ if (isset($this->customProperties[$propertyName])) {
+ return $this->customProperties[$propertyName]['type'];
+ }
+
+ }
+
+ /**
+ * Set a Custom Property
+ *
+ * @param string $propertyName
+ * @param mixed $propertyValue
+ * @param string $propertyType
+ * 'i' : Integer
+ * 'f' : Floating Point
+ * 's' : String
+ * 'd' : Date/Time
+ * 'b' : Boolean
+ * @return PHPExcel_DocumentProperties
+ */
+ public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
+ {
+ if (($propertyType === null) || (!in_array($propertyType, array(self::PROPERTY_TYPE_INTEGER,
+ self::PROPERTY_TYPE_FLOAT,
+ self::PROPERTY_TYPE_STRING,
+ self::PROPERTY_TYPE_DATE,
+ self::PROPERTY_TYPE_BOOLEAN)))) {
+ if ($propertyValue === null) {
+ $propertyType = self::PROPERTY_TYPE_STRING;
+ } elseif (is_float($propertyValue)) {
+ $propertyType = self::PROPERTY_TYPE_FLOAT;
+ } elseif (is_int($propertyValue)) {
+ $propertyType = self::PROPERTY_TYPE_INTEGER;
+ } elseif (is_bool($propertyValue)) {
+ $propertyType = self::PROPERTY_TYPE_BOOLEAN;
+ } else {
+ $propertyType = self::PROPERTY_TYPE_STRING;
+ }
+ }
+
+ $this->customProperties[$propertyName] = array(
+ 'value' => $propertyValue,
+ 'type' => $propertyType
+ );
+ return $this;
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+
+ public static function convertProperty($propertyValue, $propertyType)
+ {
+ switch ($propertyType) {
+ case 'empty': // Empty
+ return '';
+ break;
+ case 'null': // Null
+ return null;
+ break;
+ case 'i1': // 1-Byte Signed Integer
+ case 'i2': // 2-Byte Signed Integer
+ case 'i4': // 4-Byte Signed Integer
+ case 'i8': // 8-Byte Signed Integer
+ case 'int': // Integer
+ return (int) $propertyValue;
+ break;
+ case 'ui1': // 1-Byte Unsigned Integer
+ case 'ui2': // 2-Byte Unsigned Integer
+ case 'ui4': // 4-Byte Unsigned Integer
+ case 'ui8': // 8-Byte Unsigned Integer
+ case 'uint': // Unsigned Integer
+ return abs((int) $propertyValue);
+ break;
+ case 'r4': // 4-Byte Real Number
+ case 'r8': // 8-Byte Real Number
+ case 'decimal': // Decimal
+ return (float) $propertyValue;
+ break;
+ case 'lpstr': // LPSTR
+ case 'lpwstr': // LPWSTR
+ case 'bstr': // Basic String
+ return $propertyValue;
+ break;
+ case 'date': // Date and Time
+ case 'filetime': // File Time
+ return strtotime($propertyValue);
+ break;
+ case 'bool': // Boolean
+ return ($propertyValue == 'true') ? true : false;
+ break;
+ case 'cy': // Currency
+ case 'error': // Error Status Code
+ case 'vector': // Vector
+ case 'array': // Array
+ case 'blob': // Binary Blob
+ case 'oblob': // Binary Blob Object
+ case 'stream': // Binary Stream
+ case 'ostream': // Binary Stream Object
+ case 'storage': // Binary Storage
+ case 'ostorage': // Binary Storage Object
+ case 'vstream': // Binary Versioned Stream
+ case 'clsid': // Class ID
+ case 'cf': // Clipboard Data
+ return $propertyValue;
+ break;
+ }
+ return $propertyValue;
+ }
+
+ public static function convertPropertyType($propertyType)
+ {
+ switch ($propertyType) {
+ case 'i1': // 1-Byte Signed Integer
+ case 'i2': // 2-Byte Signed Integer
+ case 'i4': // 4-Byte Signed Integer
+ case 'i8': // 8-Byte Signed Integer
+ case 'int': // Integer
+ case 'ui1': // 1-Byte Unsigned Integer
+ case 'ui2': // 2-Byte Unsigned Integer
+ case 'ui4': // 4-Byte Unsigned Integer
+ case 'ui8': // 8-Byte Unsigned Integer
+ case 'uint': // Unsigned Integer
+ return self::PROPERTY_TYPE_INTEGER;
+ break;
+ case 'r4': // 4-Byte Real Number
+ case 'r8': // 8-Byte Real Number
+ case 'decimal': // Decimal
+ return self::PROPERTY_TYPE_FLOAT;
+ break;
+ case 'empty': // Empty
+ case 'null': // Null
+ case 'lpstr': // LPSTR
+ case 'lpwstr': // LPWSTR
+ case 'bstr': // Basic String
+ return self::PROPERTY_TYPE_STRING;
+ break;
+ case 'date': // Date and Time
+ case 'filetime': // File Time
+ return self::PROPERTY_TYPE_DATE;
+ break;
+ case 'bool': // Boolean
+ return self::PROPERTY_TYPE_BOOLEAN;
+ break;
+ case 'cy': // Currency
+ case 'error': // Error Status Code
+ case 'vector': // Vector
+ case 'array': // Array
+ case 'blob': // Binary Blob
+ case 'oblob': // Binary Blob Object
+ case 'stream': // Binary Stream
+ case 'ostream': // Binary Stream Object
+ case 'storage': // Binary Storage
+ case 'ostorage': // Binary Storage Object
+ case 'vstream': // Binary Versioned Stream
+ case 'clsid': // Class ID
+ case 'cf': // Clipboard Data
+ return self::PROPERTY_TYPE_UNKNOWN;
+ break;
+ }
+ return self::PROPERTY_TYPE_UNKNOWN;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/DocumentSecurity.php b/extend/PHPExcel/PHPExcel/DocumentSecurity.php
new file mode 100755
index 0000000..ecea0da
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/DocumentSecurity.php
@@ -0,0 +1,222 @@
+lockRevision = false;
+ $this->lockStructure = false;
+ $this->lockWindows = false;
+ $this->revisionsPassword = '';
+ $this->workbookPassword = '';
+ }
+
+ /**
+ * Is some sort of document security enabled?
+ *
+ * @return boolean
+ */
+ public function isSecurityEnabled()
+ {
+ return $this->lockRevision ||
+ $this->lockStructure ||
+ $this->lockWindows;
+ }
+
+ /**
+ * Get LockRevision
+ *
+ * @return boolean
+ */
+ public function getLockRevision()
+ {
+ return $this->lockRevision;
+ }
+
+ /**
+ * Set LockRevision
+ *
+ * @param boolean $pValue
+ * @return PHPExcel_DocumentSecurity
+ */
+ public function setLockRevision($pValue = false)
+ {
+ $this->lockRevision = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get LockStructure
+ *
+ * @return boolean
+ */
+ public function getLockStructure()
+ {
+ return $this->lockStructure;
+ }
+
+ /**
+ * Set LockStructure
+ *
+ * @param boolean $pValue
+ * @return PHPExcel_DocumentSecurity
+ */
+ public function setLockStructure($pValue = false)
+ {
+ $this->lockStructure = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get LockWindows
+ *
+ * @return boolean
+ */
+ public function getLockWindows()
+ {
+ return $this->lockWindows;
+ }
+
+ /**
+ * Set LockWindows
+ *
+ * @param boolean $pValue
+ * @return PHPExcel_DocumentSecurity
+ */
+ public function setLockWindows($pValue = false)
+ {
+ $this->lockWindows = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get RevisionsPassword (hashed)
+ *
+ * @return string
+ */
+ public function getRevisionsPassword()
+ {
+ return $this->revisionsPassword;
+ }
+
+ /**
+ * Set RevisionsPassword
+ *
+ * @param string $pValue
+ * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true
+ * @return PHPExcel_DocumentSecurity
+ */
+ public function setRevisionsPassword($pValue = '', $pAlreadyHashed = false)
+ {
+ if (!$pAlreadyHashed) {
+ $pValue = PHPExcel_Shared_PasswordHasher::hashPassword($pValue);
+ }
+ $this->revisionsPassword = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get WorkbookPassword (hashed)
+ *
+ * @return string
+ */
+ public function getWorkbookPassword()
+ {
+ return $this->workbookPassword;
+ }
+
+ /**
+ * Set WorkbookPassword
+ *
+ * @param string $pValue
+ * @param boolean $pAlreadyHashed If the password has already been hashed, set this to true
+ * @return PHPExcel_DocumentSecurity
+ */
+ public function setWorkbookPassword($pValue = '', $pAlreadyHashed = false)
+ {
+ if (!$pAlreadyHashed) {
+ $pValue = PHPExcel_Shared_PasswordHasher::hashPassword($pValue);
+ }
+ $this->workbookPassword = $pValue;
+ return $this;
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Exception.php b/extend/PHPExcel/PHPExcel/Exception.php
new file mode 100755
index 0000000..b27750e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Exception.php
@@ -0,0 +1,54 @@
+line = $line;
+ $e->file = $file;
+ throw $e;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/HashTable.php b/extend/PHPExcel/PHPExcel/HashTable.php
new file mode 100755
index 0000000..c21d18c
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/HashTable.php
@@ -0,0 +1,204 @@
+addFromSource($pSource);
+ }
+ }
+
+ /**
+ * Add HashTable items from source
+ *
+ * @param PHPExcel_IComparable[] $pSource Source array to create HashTable from
+ * @throws PHPExcel_Exception
+ */
+ public function addFromSource($pSource = null)
+ {
+ // Check if an array was passed
+ if ($pSource == null) {
+ return;
+ } elseif (!is_array($pSource)) {
+ throw new PHPExcel_Exception('Invalid array parameter passed.');
+ }
+
+ foreach ($pSource as $item) {
+ $this->add($item);
+ }
+ }
+
+ /**
+ * Add HashTable item
+ *
+ * @param PHPExcel_IComparable $pSource Item to add
+ * @throws PHPExcel_Exception
+ */
+ public function add(PHPExcel_IComparable $pSource = null)
+ {
+ $hash = $pSource->getHashCode();
+ if (!isset($this->items[$hash])) {
+ $this->items[$hash] = $pSource;
+ $this->keyMap[count($this->items) - 1] = $hash;
+ }
+ }
+
+ /**
+ * Remove HashTable item
+ *
+ * @param PHPExcel_IComparable $pSource Item to remove
+ * @throws PHPExcel_Exception
+ */
+ public function remove(PHPExcel_IComparable $pSource = null)
+ {
+ $hash = $pSource->getHashCode();
+ if (isset($this->items[$hash])) {
+ unset($this->items[$hash]);
+
+ $deleteKey = -1;
+ foreach ($this->keyMap as $key => $value) {
+ if ($deleteKey >= 0) {
+ $this->keyMap[$key - 1] = $value;
+ }
+
+ if ($value == $hash) {
+ $deleteKey = $key;
+ }
+ }
+ unset($this->keyMap[count($this->keyMap) - 1]);
+ }
+ }
+
+ /**
+ * Clear HashTable
+ *
+ */
+ public function clear()
+ {
+ $this->items = array();
+ $this->keyMap = array();
+ }
+
+ /**
+ * Count
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->items);
+ }
+
+ /**
+ * Get index for hash code
+ *
+ * @param string $pHashCode
+ * @return int Index
+ */
+ public function getIndexForHashCode($pHashCode = '')
+ {
+ return array_search($pHashCode, $this->keyMap);
+ }
+
+ /**
+ * Get by index
+ *
+ * @param int $pIndex
+ * @return PHPExcel_IComparable
+ *
+ */
+ public function getByIndex($pIndex = 0)
+ {
+ if (isset($this->keyMap[$pIndex])) {
+ return $this->getByHashCode($this->keyMap[$pIndex]);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get by hashcode
+ *
+ * @param string $pHashCode
+ * @return PHPExcel_IComparable
+ *
+ */
+ public function getByHashCode($pHashCode = '')
+ {
+ if (isset($this->items[$pHashCode])) {
+ return $this->items[$pHashCode];
+ }
+
+ return null;
+ }
+
+ /**
+ * HashTable to array
+ *
+ * @return PHPExcel_IComparable[]
+ */
+ public function toArray()
+ {
+ return $this->items;
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Helper/HTML.php b/extend/PHPExcel/PHPExcel/Helper/HTML.php
new file mode 100755
index 0000000..a78f11c
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Helper/HTML.php
@@ -0,0 +1,808 @@
+ 'f0f8ff',
+ 'antiquewhite' => 'faebd7',
+ 'antiquewhite1' => 'ffefdb',
+ 'antiquewhite2' => 'eedfcc',
+ 'antiquewhite3' => 'cdc0b0',
+ 'antiquewhite4' => '8b8378',
+ 'aqua' => '00ffff',
+ 'aquamarine1' => '7fffd4',
+ 'aquamarine2' => '76eec6',
+ 'aquamarine4' => '458b74',
+ 'azure1' => 'f0ffff',
+ 'azure2' => 'e0eeee',
+ 'azure3' => 'c1cdcd',
+ 'azure4' => '838b8b',
+ 'beige' => 'f5f5dc',
+ 'bisque1' => 'ffe4c4',
+ 'bisque2' => 'eed5b7',
+ 'bisque3' => 'cdb79e',
+ 'bisque4' => '8b7d6b',
+ 'black' => '000000',
+ 'blanchedalmond' => 'ffebcd',
+ 'blue' => '0000ff',
+ 'blue1' => '0000ff',
+ 'blue2' => '0000ee',
+ 'blue4' => '00008b',
+ 'blueviolet' => '8a2be2',
+ 'brown' => 'a52a2a',
+ 'brown1' => 'ff4040',
+ 'brown2' => 'ee3b3b',
+ 'brown3' => 'cd3333',
+ 'brown4' => '8b2323',
+ 'burlywood' => 'deb887',
+ 'burlywood1' => 'ffd39b',
+ 'burlywood2' => 'eec591',
+ 'burlywood3' => 'cdaa7d',
+ 'burlywood4' => '8b7355',
+ 'cadetblue' => '5f9ea0',
+ 'cadetblue1' => '98f5ff',
+ 'cadetblue2' => '8ee5ee',
+ 'cadetblue3' => '7ac5cd',
+ 'cadetblue4' => '53868b',
+ 'chartreuse1' => '7fff00',
+ 'chartreuse2' => '76ee00',
+ 'chartreuse3' => '66cd00',
+ 'chartreuse4' => '458b00',
+ 'chocolate' => 'd2691e',
+ 'chocolate1' => 'ff7f24',
+ 'chocolate2' => 'ee7621',
+ 'chocolate3' => 'cd661d',
+ 'coral' => 'ff7f50',
+ 'coral1' => 'ff7256',
+ 'coral2' => 'ee6a50',
+ 'coral3' => 'cd5b45',
+ 'coral4' => '8b3e2f',
+ 'cornflowerblue' => '6495ed',
+ 'cornsilk1' => 'fff8dc',
+ 'cornsilk2' => 'eee8cd',
+ 'cornsilk3' => 'cdc8b1',
+ 'cornsilk4' => '8b8878',
+ 'cyan1' => '00ffff',
+ 'cyan2' => '00eeee',
+ 'cyan3' => '00cdcd',
+ 'cyan4' => '008b8b',
+ 'darkgoldenrod' => 'b8860b',
+ 'darkgoldenrod1' => 'ffb90f',
+ 'darkgoldenrod2' => 'eead0e',
+ 'darkgoldenrod3' => 'cd950c',
+ 'darkgoldenrod4' => '8b6508',
+ 'darkgreen' => '006400',
+ 'darkkhaki' => 'bdb76b',
+ 'darkolivegreen' => '556b2f',
+ 'darkolivegreen1' => 'caff70',
+ 'darkolivegreen2' => 'bcee68',
+ 'darkolivegreen3' => 'a2cd5a',
+ 'darkolivegreen4' => '6e8b3d',
+ 'darkorange' => 'ff8c00',
+ 'darkorange1' => 'ff7f00',
+ 'darkorange2' => 'ee7600',
+ 'darkorange3' => 'cd6600',
+ 'darkorange4' => '8b4500',
+ 'darkorchid' => '9932cc',
+ 'darkorchid1' => 'bf3eff',
+ 'darkorchid2' => 'b23aee',
+ 'darkorchid3' => '9a32cd',
+ 'darkorchid4' => '68228b',
+ 'darksalmon' => 'e9967a',
+ 'darkseagreen' => '8fbc8f',
+ 'darkseagreen1' => 'c1ffc1',
+ 'darkseagreen2' => 'b4eeb4',
+ 'darkseagreen3' => '9bcd9b',
+ 'darkseagreen4' => '698b69',
+ 'darkslateblue' => '483d8b',
+ 'darkslategray' => '2f4f4f',
+ 'darkslategray1' => '97ffff',
+ 'darkslategray2' => '8deeee',
+ 'darkslategray3' => '79cdcd',
+ 'darkslategray4' => '528b8b',
+ 'darkturquoise' => '00ced1',
+ 'darkviolet' => '9400d3',
+ 'deeppink1' => 'ff1493',
+ 'deeppink2' => 'ee1289',
+ 'deeppink3' => 'cd1076',
+ 'deeppink4' => '8b0a50',
+ 'deepskyblue1' => '00bfff',
+ 'deepskyblue2' => '00b2ee',
+ 'deepskyblue3' => '009acd',
+ 'deepskyblue4' => '00688b',
+ 'dimgray' => '696969',
+ 'dodgerblue1' => '1e90ff',
+ 'dodgerblue2' => '1c86ee',
+ 'dodgerblue3' => '1874cd',
+ 'dodgerblue4' => '104e8b',
+ 'firebrick' => 'b22222',
+ 'firebrick1' => 'ff3030',
+ 'firebrick2' => 'ee2c2c',
+ 'firebrick3' => 'cd2626',
+ 'firebrick4' => '8b1a1a',
+ 'floralwhite' => 'fffaf0',
+ 'forestgreen' => '228b22',
+ 'fuchsia' => 'ff00ff',
+ 'gainsboro' => 'dcdcdc',
+ 'ghostwhite' => 'f8f8ff',
+ 'gold1' => 'ffd700',
+ 'gold2' => 'eec900',
+ 'gold3' => 'cdad00',
+ 'gold4' => '8b7500',
+ 'goldenrod' => 'daa520',
+ 'goldenrod1' => 'ffc125',
+ 'goldenrod2' => 'eeb422',
+ 'goldenrod3' => 'cd9b1d',
+ 'goldenrod4' => '8b6914',
+ 'gray' => 'bebebe',
+ 'gray1' => '030303',
+ 'gray10' => '1a1a1a',
+ 'gray11' => '1c1c1c',
+ 'gray12' => '1f1f1f',
+ 'gray13' => '212121',
+ 'gray14' => '242424',
+ 'gray15' => '262626',
+ 'gray16' => '292929',
+ 'gray17' => '2b2b2b',
+ 'gray18' => '2e2e2e',
+ 'gray19' => '303030',
+ 'gray2' => '050505',
+ 'gray20' => '333333',
+ 'gray21' => '363636',
+ 'gray22' => '383838',
+ 'gray23' => '3b3b3b',
+ 'gray24' => '3d3d3d',
+ 'gray25' => '404040',
+ 'gray26' => '424242',
+ 'gray27' => '454545',
+ 'gray28' => '474747',
+ 'gray29' => '4a4a4a',
+ 'gray3' => '080808',
+ 'gray30' => '4d4d4d',
+ 'gray31' => '4f4f4f',
+ 'gray32' => '525252',
+ 'gray33' => '545454',
+ 'gray34' => '575757',
+ 'gray35' => '595959',
+ 'gray36' => '5c5c5c',
+ 'gray37' => '5e5e5e',
+ 'gray38' => '616161',
+ 'gray39' => '636363',
+ 'gray4' => '0a0a0a',
+ 'gray40' => '666666',
+ 'gray41' => '696969',
+ 'gray42' => '6b6b6b',
+ 'gray43' => '6e6e6e',
+ 'gray44' => '707070',
+ 'gray45' => '737373',
+ 'gray46' => '757575',
+ 'gray47' => '787878',
+ 'gray48' => '7a7a7a',
+ 'gray49' => '7d7d7d',
+ 'gray5' => '0d0d0d',
+ 'gray50' => '7f7f7f',
+ 'gray51' => '828282',
+ 'gray52' => '858585',
+ 'gray53' => '878787',
+ 'gray54' => '8a8a8a',
+ 'gray55' => '8c8c8c',
+ 'gray56' => '8f8f8f',
+ 'gray57' => '919191',
+ 'gray58' => '949494',
+ 'gray59' => '969696',
+ 'gray6' => '0f0f0f',
+ 'gray60' => '999999',
+ 'gray61' => '9c9c9c',
+ 'gray62' => '9e9e9e',
+ 'gray63' => 'a1a1a1',
+ 'gray64' => 'a3a3a3',
+ 'gray65' => 'a6a6a6',
+ 'gray66' => 'a8a8a8',
+ 'gray67' => 'ababab',
+ 'gray68' => 'adadad',
+ 'gray69' => 'b0b0b0',
+ 'gray7' => '121212',
+ 'gray70' => 'b3b3b3',
+ 'gray71' => 'b5b5b5',
+ 'gray72' => 'b8b8b8',
+ 'gray73' => 'bababa',
+ 'gray74' => 'bdbdbd',
+ 'gray75' => 'bfbfbf',
+ 'gray76' => 'c2c2c2',
+ 'gray77' => 'c4c4c4',
+ 'gray78' => 'c7c7c7',
+ 'gray79' => 'c9c9c9',
+ 'gray8' => '141414',
+ 'gray80' => 'cccccc',
+ 'gray81' => 'cfcfcf',
+ 'gray82' => 'd1d1d1',
+ 'gray83' => 'd4d4d4',
+ 'gray84' => 'd6d6d6',
+ 'gray85' => 'd9d9d9',
+ 'gray86' => 'dbdbdb',
+ 'gray87' => 'dedede',
+ 'gray88' => 'e0e0e0',
+ 'gray89' => 'e3e3e3',
+ 'gray9' => '171717',
+ 'gray90' => 'e5e5e5',
+ 'gray91' => 'e8e8e8',
+ 'gray92' => 'ebebeb',
+ 'gray93' => 'ededed',
+ 'gray94' => 'f0f0f0',
+ 'gray95' => 'f2f2f2',
+ 'gray97' => 'f7f7f7',
+ 'gray98' => 'fafafa',
+ 'gray99' => 'fcfcfc',
+ 'green' => '00ff00',
+ 'green1' => '00ff00',
+ 'green2' => '00ee00',
+ 'green3' => '00cd00',
+ 'green4' => '008b00',
+ 'greenyellow' => 'adff2f',
+ 'honeydew1' => 'f0fff0',
+ 'honeydew2' => 'e0eee0',
+ 'honeydew3' => 'c1cdc1',
+ 'honeydew4' => '838b83',
+ 'hotpink' => 'ff69b4',
+ 'hotpink1' => 'ff6eb4',
+ 'hotpink2' => 'ee6aa7',
+ 'hotpink3' => 'cd6090',
+ 'hotpink4' => '8b3a62',
+ 'indianred' => 'cd5c5c',
+ 'indianred1' => 'ff6a6a',
+ 'indianred2' => 'ee6363',
+ 'indianred3' => 'cd5555',
+ 'indianred4' => '8b3a3a',
+ 'ivory1' => 'fffff0',
+ 'ivory2' => 'eeeee0',
+ 'ivory3' => 'cdcdc1',
+ 'ivory4' => '8b8b83',
+ 'khaki' => 'f0e68c',
+ 'khaki1' => 'fff68f',
+ 'khaki2' => 'eee685',
+ 'khaki3' => 'cdc673',
+ 'khaki4' => '8b864e',
+ 'lavender' => 'e6e6fa',
+ 'lavenderblush1' => 'fff0f5',
+ 'lavenderblush2' => 'eee0e5',
+ 'lavenderblush3' => 'cdc1c5',
+ 'lavenderblush4' => '8b8386',
+ 'lawngreen' => '7cfc00',
+ 'lemonchiffon1' => 'fffacd',
+ 'lemonchiffon2' => 'eee9bf',
+ 'lemonchiffon3' => 'cdc9a5',
+ 'lemonchiffon4' => '8b8970',
+ 'light' => 'eedd82',
+ 'lightblue' => 'add8e6',
+ 'lightblue1' => 'bfefff',
+ 'lightblue2' => 'b2dfee',
+ 'lightblue3' => '9ac0cd',
+ 'lightblue4' => '68838b',
+ 'lightcoral' => 'f08080',
+ 'lightcyan1' => 'e0ffff',
+ 'lightcyan2' => 'd1eeee',
+ 'lightcyan3' => 'b4cdcd',
+ 'lightcyan4' => '7a8b8b',
+ 'lightgoldenrod1' => 'ffec8b',
+ 'lightgoldenrod2' => 'eedc82',
+ 'lightgoldenrod3' => 'cdbe70',
+ 'lightgoldenrod4' => '8b814c',
+ 'lightgoldenrodyellow' => 'fafad2',
+ 'lightgray' => 'd3d3d3',
+ 'lightpink' => 'ffb6c1',
+ 'lightpink1' => 'ffaeb9',
+ 'lightpink2' => 'eea2ad',
+ 'lightpink3' => 'cd8c95',
+ 'lightpink4' => '8b5f65',
+ 'lightsalmon1' => 'ffa07a',
+ 'lightsalmon2' => 'ee9572',
+ 'lightsalmon3' => 'cd8162',
+ 'lightsalmon4' => '8b5742',
+ 'lightseagreen' => '20b2aa',
+ 'lightskyblue' => '87cefa',
+ 'lightskyblue1' => 'b0e2ff',
+ 'lightskyblue2' => 'a4d3ee',
+ 'lightskyblue3' => '8db6cd',
+ 'lightskyblue4' => '607b8b',
+ 'lightslateblue' => '8470ff',
+ 'lightslategray' => '778899',
+ 'lightsteelblue' => 'b0c4de',
+ 'lightsteelblue1' => 'cae1ff',
+ 'lightsteelblue2' => 'bcd2ee',
+ 'lightsteelblue3' => 'a2b5cd',
+ 'lightsteelblue4' => '6e7b8b',
+ 'lightyellow1' => 'ffffe0',
+ 'lightyellow2' => 'eeeed1',
+ 'lightyellow3' => 'cdcdb4',
+ 'lightyellow4' => '8b8b7a',
+ 'lime' => '00ff00',
+ 'limegreen' => '32cd32',
+ 'linen' => 'faf0e6',
+ 'magenta' => 'ff00ff',
+ 'magenta2' => 'ee00ee',
+ 'magenta3' => 'cd00cd',
+ 'magenta4' => '8b008b',
+ 'maroon' => 'b03060',
+ 'maroon1' => 'ff34b3',
+ 'maroon2' => 'ee30a7',
+ 'maroon3' => 'cd2990',
+ 'maroon4' => '8b1c62',
+ 'medium' => '66cdaa',
+ 'mediumaquamarine' => '66cdaa',
+ 'mediumblue' => '0000cd',
+ 'mediumorchid' => 'ba55d3',
+ 'mediumorchid1' => 'e066ff',
+ 'mediumorchid2' => 'd15fee',
+ 'mediumorchid3' => 'b452cd',
+ 'mediumorchid4' => '7a378b',
+ 'mediumpurple' => '9370db',
+ 'mediumpurple1' => 'ab82ff',
+ 'mediumpurple2' => '9f79ee',
+ 'mediumpurple3' => '8968cd',
+ 'mediumpurple4' => '5d478b',
+ 'mediumseagreen' => '3cb371',
+ 'mediumslateblue' => '7b68ee',
+ 'mediumspringgreen' => '00fa9a',
+ 'mediumturquoise' => '48d1cc',
+ 'mediumvioletred' => 'c71585',
+ 'midnightblue' => '191970',
+ 'mintcream' => 'f5fffa',
+ 'mistyrose1' => 'ffe4e1',
+ 'mistyrose2' => 'eed5d2',
+ 'mistyrose3' => 'cdb7b5',
+ 'mistyrose4' => '8b7d7b',
+ 'moccasin' => 'ffe4b5',
+ 'navajowhite1' => 'ffdead',
+ 'navajowhite2' => 'eecfa1',
+ 'navajowhite3' => 'cdb38b',
+ 'navajowhite4' => '8b795e',
+ 'navy' => '000080',
+ 'navyblue' => '000080',
+ 'oldlace' => 'fdf5e6',
+ 'olive' => '808000',
+ 'olivedrab' => '6b8e23',
+ 'olivedrab1' => 'c0ff3e',
+ 'olivedrab2' => 'b3ee3a',
+ 'olivedrab4' => '698b22',
+ 'orange' => 'ffa500',
+ 'orange1' => 'ffa500',
+ 'orange2' => 'ee9a00',
+ 'orange3' => 'cd8500',
+ 'orange4' => '8b5a00',
+ 'orangered1' => 'ff4500',
+ 'orangered2' => 'ee4000',
+ 'orangered3' => 'cd3700',
+ 'orangered4' => '8b2500',
+ 'orchid' => 'da70d6',
+ 'orchid1' => 'ff83fa',
+ 'orchid2' => 'ee7ae9',
+ 'orchid3' => 'cd69c9',
+ 'orchid4' => '8b4789',
+ 'pale' => 'db7093',
+ 'palegoldenrod' => 'eee8aa',
+ 'palegreen' => '98fb98',
+ 'palegreen1' => '9aff9a',
+ 'palegreen2' => '90ee90',
+ 'palegreen3' => '7ccd7c',
+ 'palegreen4' => '548b54',
+ 'paleturquoise' => 'afeeee',
+ 'paleturquoise1' => 'bbffff',
+ 'paleturquoise2' => 'aeeeee',
+ 'paleturquoise3' => '96cdcd',
+ 'paleturquoise4' => '668b8b',
+ 'palevioletred' => 'db7093',
+ 'palevioletred1' => 'ff82ab',
+ 'palevioletred2' => 'ee799f',
+ 'palevioletred3' => 'cd6889',
+ 'palevioletred4' => '8b475d',
+ 'papayawhip' => 'ffefd5',
+ 'peachpuff1' => 'ffdab9',
+ 'peachpuff2' => 'eecbad',
+ 'peachpuff3' => 'cdaf95',
+ 'peachpuff4' => '8b7765',
+ 'pink' => 'ffc0cb',
+ 'pink1' => 'ffb5c5',
+ 'pink2' => 'eea9b8',
+ 'pink3' => 'cd919e',
+ 'pink4' => '8b636c',
+ 'plum' => 'dda0dd',
+ 'plum1' => 'ffbbff',
+ 'plum2' => 'eeaeee',
+ 'plum3' => 'cd96cd',
+ 'plum4' => '8b668b',
+ 'powderblue' => 'b0e0e6',
+ 'purple' => 'a020f0',
+ 'rebeccapurple' => '663399',
+ 'purple1' => '9b30ff',
+ 'purple2' => '912cee',
+ 'purple3' => '7d26cd',
+ 'purple4' => '551a8b',
+ 'red' => 'ff0000',
+ 'red1' => 'ff0000',
+ 'red2' => 'ee0000',
+ 'red3' => 'cd0000',
+ 'red4' => '8b0000',
+ 'rosybrown' => 'bc8f8f',
+ 'rosybrown1' => 'ffc1c1',
+ 'rosybrown2' => 'eeb4b4',
+ 'rosybrown3' => 'cd9b9b',
+ 'rosybrown4' => '8b6969',
+ 'royalblue' => '4169e1',
+ 'royalblue1' => '4876ff',
+ 'royalblue2' => '436eee',
+ 'royalblue3' => '3a5fcd',
+ 'royalblue4' => '27408b',
+ 'saddlebrown' => '8b4513',
+ 'salmon' => 'fa8072',
+ 'salmon1' => 'ff8c69',
+ 'salmon2' => 'ee8262',
+ 'salmon3' => 'cd7054',
+ 'salmon4' => '8b4c39',
+ 'sandybrown' => 'f4a460',
+ 'seagreen1' => '54ff9f',
+ 'seagreen2' => '4eee94',
+ 'seagreen3' => '43cd80',
+ 'seagreen4' => '2e8b57',
+ 'seashell1' => 'fff5ee',
+ 'seashell2' => 'eee5de',
+ 'seashell3' => 'cdc5bf',
+ 'seashell4' => '8b8682',
+ 'sienna' => 'a0522d',
+ 'sienna1' => 'ff8247',
+ 'sienna2' => 'ee7942',
+ 'sienna3' => 'cd6839',
+ 'sienna4' => '8b4726',
+ 'silver' => 'c0c0c0',
+ 'skyblue' => '87ceeb',
+ 'skyblue1' => '87ceff',
+ 'skyblue2' => '7ec0ee',
+ 'skyblue3' => '6ca6cd',
+ 'skyblue4' => '4a708b',
+ 'slateblue' => '6a5acd',
+ 'slateblue1' => '836fff',
+ 'slateblue2' => '7a67ee',
+ 'slateblue3' => '6959cd',
+ 'slateblue4' => '473c8b',
+ 'slategray' => '708090',
+ 'slategray1' => 'c6e2ff',
+ 'slategray2' => 'b9d3ee',
+ 'slategray3' => '9fb6cd',
+ 'slategray4' => '6c7b8b',
+ 'snow1' => 'fffafa',
+ 'snow2' => 'eee9e9',
+ 'snow3' => 'cdc9c9',
+ 'snow4' => '8b8989',
+ 'springgreen1' => '00ff7f',
+ 'springgreen2' => '00ee76',
+ 'springgreen3' => '00cd66',
+ 'springgreen4' => '008b45',
+ 'steelblue' => '4682b4',
+ 'steelblue1' => '63b8ff',
+ 'steelblue2' => '5cacee',
+ 'steelblue3' => '4f94cd',
+ 'steelblue4' => '36648b',
+ 'tan' => 'd2b48c',
+ 'tan1' => 'ffa54f',
+ 'tan2' => 'ee9a49',
+ 'tan3' => 'cd853f',
+ 'tan4' => '8b5a2b',
+ 'teal' => '008080',
+ 'thistle' => 'd8bfd8',
+ 'thistle1' => 'ffe1ff',
+ 'thistle2' => 'eed2ee',
+ 'thistle3' => 'cdb5cd',
+ 'thistle4' => '8b7b8b',
+ 'tomato1' => 'ff6347',
+ 'tomato2' => 'ee5c42',
+ 'tomato3' => 'cd4f39',
+ 'tomato4' => '8b3626',
+ 'turquoise' => '40e0d0',
+ 'turquoise1' => '00f5ff',
+ 'turquoise2' => '00e5ee',
+ 'turquoise3' => '00c5cd',
+ 'turquoise4' => '00868b',
+ 'violet' => 'ee82ee',
+ 'violetred' => 'd02090',
+ 'violetred1' => 'ff3e96',
+ 'violetred2' => 'ee3a8c',
+ 'violetred3' => 'cd3278',
+ 'violetred4' => '8b2252',
+ 'wheat' => 'f5deb3',
+ 'wheat1' => 'ffe7ba',
+ 'wheat2' => 'eed8ae',
+ 'wheat3' => 'cdba96',
+ 'wheat4' => '8b7e66',
+ 'white' => 'ffffff',
+ 'whitesmoke' => 'f5f5f5',
+ 'yellow' => 'ffff00',
+ 'yellow1' => 'ffff00',
+ 'yellow2' => 'eeee00',
+ 'yellow3' => 'cdcd00',
+ 'yellow4' => '8b8b00',
+ 'yellowgreen' => '9acd32',
+ );
+
+ protected $face;
+ protected $size;
+ protected $color;
+
+ protected $bold = false;
+ protected $italic = false;
+ protected $underline = false;
+ protected $superscript = false;
+ protected $subscript = false;
+ protected $strikethrough = false;
+
+ protected $startTagCallbacks = array(
+ 'font' => 'startFontTag',
+ 'b' => 'startBoldTag',
+ 'strong' => 'startBoldTag',
+ 'i' => 'startItalicTag',
+ 'em' => 'startItalicTag',
+ 'u' => 'startUnderlineTag',
+ 'ins' => 'startUnderlineTag',
+ 'del' => 'startStrikethruTag',
+ 'sup' => 'startSuperscriptTag',
+ 'sub' => 'startSubscriptTag',
+ );
+
+ protected $endTagCallbacks = array(
+ 'font' => 'endFontTag',
+ 'b' => 'endBoldTag',
+ 'strong' => 'endBoldTag',
+ 'i' => 'endItalicTag',
+ 'em' => 'endItalicTag',
+ 'u' => 'endUnderlineTag',
+ 'ins' => 'endUnderlineTag',
+ 'del' => 'endStrikethruTag',
+ 'sup' => 'endSuperscriptTag',
+ 'sub' => 'endSubscriptTag',
+ 'br' => 'breakTag',
+ 'p' => 'breakTag',
+ 'h1' => 'breakTag',
+ 'h2' => 'breakTag',
+ 'h3' => 'breakTag',
+ 'h4' => 'breakTag',
+ 'h5' => 'breakTag',
+ 'h6' => 'breakTag',
+ );
+
+ protected $stack = array();
+
+ protected $stringData = '';
+
+ protected $richTextObject;
+
+ protected function initialise()
+ {
+ $this->face = $this->size = $this->color = null;
+ $this->bold = $this->italic = $this->underline = $this->superscript = $this->subscript = $this->strikethrough = false;
+
+ $this->stack = array();
+
+ $this->stringData = '';
+ }
+
+ public function toRichTextObject($html)
+ {
+ $this->initialise();
+
+ // Create a new DOM object
+ $dom = new \DOMDocument;
+ // Load the HTML file into the DOM object
+ // Note the use of error suppression, because typically this will be an html fragment, so not fully valid markup
+ $loaded = @$dom->loadHTML($html);
+
+ // Discard excess white space
+ $dom->preserveWhiteSpace = false;
+
+ $this->richTextObject = new PHPExcel_RichText();;
+ $this->parseElements($dom);
+
+ // Clean any further spurious whitespace
+ $this->cleanWhitespace();
+
+ return $this->richTextObject;
+ }
+
+ protected function cleanWhitespace()
+ {
+ foreach ($this->richTextObject->getRichTextElements() as $key => $element) {
+ $text = $element->getText();
+ // Trim any leading spaces on the first run
+ if ($key == 0) {
+ $text = ltrim($text);
+ }
+ // Trim any spaces immediately after a line break
+ $text = preg_replace('/\n */mu', "\n", $text);
+ $element->setText($text);
+ }
+ }
+
+ protected function buildTextRun()
+ {
+ $text = $this->stringData;
+ if (trim($text) === '') {
+ return;
+ }
+
+ $richtextRun = $this->richTextObject->createTextRun($this->stringData);
+ if ($this->face) {
+ $richtextRun->getFont()->setName($this->face);
+ }
+ if ($this->size) {
+ $richtextRun->getFont()->setSize($this->size);
+ }
+ if ($this->color) {
+ $richtextRun->getFont()->setColor(new PHPExcel_Style_Color('ff' . $this->color));
+ }
+ if ($this->bold) {
+ $richtextRun->getFont()->setBold(true);
+ }
+ if ($this->italic) {
+ $richtextRun->getFont()->setItalic(true);
+ }
+ if ($this->underline) {
+ $richtextRun->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+ }
+ if ($this->superscript) {
+ $richtextRun->getFont()->setSuperScript(true);
+ }
+ if ($this->subscript) {
+ $richtextRun->getFont()->setSubScript(true);
+ }
+ if ($this->strikethrough) {
+ $richtextRun->getFont()->setStrikethrough(true);
+ }
+ $this->stringData = '';
+ }
+
+ protected function rgbToColour($rgb)
+ {
+ preg_match_all('/\d+/', $rgb, $values);
+ foreach ($values[0] as &$value) {
+ $value = str_pad(dechex($value), 2, '0', STR_PAD_LEFT);
+ }
+ return implode($values[0]);
+ }
+
+ protected function colourNameLookup($rgb)
+ {
+ return self::$colourMap[$rgb];
+ }
+
+ protected function startFontTag($tag)
+ {
+ foreach ($tag->attributes as $attribute) {
+ $attributeName = strtolower($attribute->name);
+ $attributeValue = $attribute->value;
+
+ if ($attributeName == 'color') {
+ if (preg_match('/rgb\s*\(/', $attributeValue)) {
+ $this->$attributeName = $this->rgbToColour($attributeValue);
+ } elseif (strpos(trim($attributeValue), '#') === 0) {
+ $this->$attributeName = ltrim($attributeValue, '#');
+ } else {
+ $this->$attributeName = $this->colourNameLookup($attributeValue);
+ }
+ } else {
+ $this->$attributeName = $attributeValue;
+ }
+ }
+ }
+
+ protected function endFontTag()
+ {
+ $this->face = $this->size = $this->color = null;
+ }
+
+ protected function startBoldTag()
+ {
+ $this->bold = true;
+ }
+
+ protected function endBoldTag()
+ {
+ $this->bold = false;
+ }
+
+ protected function startItalicTag()
+ {
+ $this->italic = true;
+ }
+
+ protected function endItalicTag()
+ {
+ $this->italic = false;
+ }
+
+ protected function startUnderlineTag()
+ {
+ $this->underline = true;
+ }
+
+ protected function endUnderlineTag()
+ {
+ $this->underline = false;
+ }
+
+ protected function startSubscriptTag()
+ {
+ $this->subscript = true;
+ }
+
+ protected function endSubscriptTag()
+ {
+ $this->subscript = false;
+ }
+
+ protected function startSuperscriptTag()
+ {
+ $this->superscript = true;
+ }
+
+ protected function endSuperscriptTag()
+ {
+ $this->superscript = false;
+ }
+
+ protected function startStrikethruTag()
+ {
+ $this->strikethrough = true;
+ }
+
+ protected function endStrikethruTag()
+ {
+ $this->strikethrough = false;
+ }
+
+ protected function breakTag()
+ {
+ $this->stringData .= "\n";
+ }
+
+ protected function parseTextNode(DOMText $textNode)
+ {
+ $domText = preg_replace(
+ '/\s+/u',
+ ' ',
+ str_replace(array("\r", "\n"), ' ', $textNode->nodeValue)
+ );
+ $this->stringData .= $domText;
+ $this->buildTextRun();
+ }
+
+ protected function handleCallback($element, $callbackTag, $callbacks)
+ {
+ if (isset($callbacks[$callbackTag])) {
+ $elementHandler = $callbacks[$callbackTag];
+ if (method_exists($this, $elementHandler)) {
+ call_user_func(array($this, $elementHandler), $element);
+ }
+ }
+ }
+
+ protected function parseElementNode(DOMElement $element)
+ {
+ $callbackTag = strtolower($element->nodeName);
+ $this->stack[] = $callbackTag;
+
+ $this->handleCallback($element, $callbackTag, $this->startTagCallbacks);
+
+ $this->parseElements($element);
+ array_pop($this->stack);
+
+ $this->handleCallback($element, $callbackTag, $this->endTagCallbacks);
+ }
+
+ protected function parseElements(DOMNode $element)
+ {
+ foreach ($element->childNodes as $child) {
+ if ($child instanceof DOMText) {
+ $this->parseTextNode($child);
+ } elseif ($child instanceof DOMElement) {
+ $this->parseElementNode($child);
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/IComparable.php b/extend/PHPExcel/PHPExcel/IComparable.php
new file mode 100755
index 0000000..6dc36a9
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/IComparable.php
@@ -0,0 +1,34 @@
+ 'IWriter', 'path' => 'PHPExcel/Writer/{0}.php', 'class' => 'PHPExcel_Writer_{0}' ),
+ array( 'type' => 'IReader', 'path' => 'PHPExcel/Reader/{0}.php', 'class' => 'PHPExcel_Reader_{0}' )
+ );
+
+ /**
+ * Autoresolve classes
+ *
+ * @var array
+ * @access private
+ * @static
+ */
+ private static $autoResolveClasses = array(
+ 'Excel2007',
+ 'Excel5',
+ 'Excel2003XML',
+ 'OOCalc',
+ 'SYLK',
+ 'Gnumeric',
+ 'HTML',
+ 'CSV',
+ );
+
+ /**
+ * Private constructor for PHPExcel_IOFactory
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Get search locations
+ *
+ * @static
+ * @access public
+ * @return array
+ */
+ public static function getSearchLocations()
+ {
+ return self::$searchLocations;
+ }
+
+ /**
+ * Set search locations
+ *
+ * @static
+ * @access public
+ * @param array $value
+ * @throws PHPExcel_Reader_Exception
+ */
+ public static function setSearchLocations($value)
+ {
+ if (is_array($value)) {
+ self::$searchLocations = $value;
+ } else {
+ throw new PHPExcel_Reader_Exception('Invalid parameter passed.');
+ }
+ }
+
+ /**
+ * Add search location
+ *
+ * @static
+ * @access public
+ * @param string $type Example: IWriter
+ * @param string $location Example: PHPExcel/Writer/{0}.php
+ * @param string $classname Example: PHPExcel_Writer_{0}
+ */
+ public static function addSearchLocation($type = '', $location = '', $classname = '')
+ {
+ self::$searchLocations[] = array( 'type' => $type, 'path' => $location, 'class' => $classname );
+ }
+
+ /**
+ * Create PHPExcel_Writer_IWriter
+ *
+ * @static
+ * @access public
+ * @param PHPExcel $phpExcel
+ * @param string $writerType Example: Excel2007
+ * @return PHPExcel_Writer_IWriter
+ * @throws PHPExcel_Reader_Exception
+ */
+ public static function createWriter(PHPExcel $phpExcel, $writerType = '')
+ {
+ // Search type
+ $searchType = 'IWriter';
+
+ // Include class
+ foreach (self::$searchLocations as $searchLocation) {
+ if ($searchLocation['type'] == $searchType) {
+ $className = str_replace('{0}', $writerType, $searchLocation['class']);
+
+ $instance = new $className($phpExcel);
+ if ($instance !== null) {
+ return $instance;
+ }
+ }
+ }
+
+ // Nothing found...
+ throw new PHPExcel_Reader_Exception("No $searchType found for type $writerType");
+ }
+
+ /**
+ * Create PHPExcel_Reader_IReader
+ *
+ * @static
+ * @access public
+ * @param string $readerType Example: Excel2007
+ * @return PHPExcel_Reader_IReader
+ * @throws PHPExcel_Reader_Exception
+ */
+ public static function createReader($readerType = '')
+ {
+ // Search type
+ $searchType = 'IReader';
+
+ // Include class
+ foreach (self::$searchLocations as $searchLocation) {
+ if ($searchLocation['type'] == $searchType) {
+ $className = str_replace('{0}', $readerType, $searchLocation['class']);
+
+ $instance = new $className();
+ if ($instance !== null) {
+ return $instance;
+ }
+ }
+ }
+
+ // Nothing found...
+ throw new PHPExcel_Reader_Exception("No $searchType found for type $readerType");
+ }
+
+ /**
+ * Loads PHPExcel from file using automatic PHPExcel_Reader_IReader resolution
+ *
+ * @static
+ * @access public
+ * @param string $pFilename The name of the spreadsheet file
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public static function load($pFilename)
+ {
+ $reader = self::createReaderForFile($pFilename);
+ return $reader->load($pFilename);
+ }
+
+ /**
+ * Identify file type using automatic PHPExcel_Reader_IReader resolution
+ *
+ * @static
+ * @access public
+ * @param string $pFilename The name of the spreadsheet file to identify
+ * @return string
+ * @throws PHPExcel_Reader_Exception
+ */
+ public static function identify($pFilename)
+ {
+ $reader = self::createReaderForFile($pFilename);
+ $className = get_class($reader);
+ $classType = explode('_', $className);
+ unset($reader);
+ return array_pop($classType);
+ }
+
+ /**
+ * Create PHPExcel_Reader_IReader for file using automatic PHPExcel_Reader_IReader resolution
+ *
+ * @static
+ * @access public
+ * @param string $pFilename The name of the spreadsheet file
+ * @return PHPExcel_Reader_IReader
+ * @throws PHPExcel_Reader_Exception
+ */
+ public static function createReaderForFile($pFilename)
+ {
+ // First, lucky guess by inspecting file extension
+ $pathinfo = pathinfo($pFilename);
+
+ $extensionType = null;
+ if (isset($pathinfo['extension'])) {
+ switch (strtolower($pathinfo['extension'])) {
+ case 'xlsx': // Excel (OfficeOpenXML) Spreadsheet
+ case 'xlsm': // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
+ case 'xltx': // Excel (OfficeOpenXML) Template
+ case 'xltm': // Excel (OfficeOpenXML) Macro Template (macros will be discarded)
+ $extensionType = 'Excel2007';
+ break;
+ case 'xls': // Excel (BIFF) Spreadsheet
+ case 'xlt': // Excel (BIFF) Template
+ $extensionType = 'Excel5';
+ break;
+ case 'ods': // Open/Libre Offic Calc
+ case 'ots': // Open/Libre Offic Calc Template
+ $extensionType = 'OOCalc';
+ break;
+ case 'slk':
+ $extensionType = 'SYLK';
+ break;
+ case 'xml': // Excel 2003 SpreadSheetML
+ $extensionType = 'Excel2003XML';
+ break;
+ case 'gnumeric':
+ $extensionType = 'Gnumeric';
+ break;
+ case 'htm':
+ case 'html':
+ $extensionType = 'HTML';
+ break;
+ case 'csv':
+ // Do nothing
+ // We must not try to use CSV reader since it loads
+ // all files including Excel files etc.
+ break;
+ default:
+ break;
+ }
+
+ if ($extensionType !== null) {
+ $reader = self::createReader($extensionType);
+ // Let's see if we are lucky
+ if (isset($reader) && $reader->canRead($pFilename)) {
+ return $reader;
+ }
+ }
+ }
+
+ // If we reach here then "lucky guess" didn't give any result
+ // Try walking through all the options in self::$autoResolveClasses
+ foreach (self::$autoResolveClasses as $autoResolveClass) {
+ // Ignore our original guess, we know that won't work
+ if ($autoResolveClass !== $extensionType) {
+ $reader = self::createReader($autoResolveClass);
+ if ($reader->canRead($pFilename)) {
+ return $reader;
+ }
+ }
+ }
+
+ throw new PHPExcel_Reader_Exception('Unable to identify a reader for this file');
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/NamedRange.php b/extend/PHPExcel/PHPExcel/NamedRange.php
new file mode 100755
index 0000000..2848db8
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/NamedRange.php
@@ -0,0 +1,249 @@
+worksheet)
+ *
+ * @var bool
+ */
+ private $localOnly;
+
+ /**
+ * Scope
+ *
+ * @var PHPExcel_Worksheet
+ */
+ private $scope;
+
+ /**
+ * Create a new NamedRange
+ *
+ * @param string $pName
+ * @param PHPExcel_Worksheet $pWorksheet
+ * @param string $pRange
+ * @param bool $pLocalOnly
+ * @param PHPExcel_Worksheet|null $pScope Scope. Only applies when $pLocalOnly = true. Null for global scope.
+ * @throws PHPExcel_Exception
+ */
+ public function __construct($pName = null, PHPExcel_Worksheet $pWorksheet, $pRange = 'A1', $pLocalOnly = false, $pScope = null)
+ {
+ // Validate data
+ if (($pName === null) || ($pWorksheet === null) || ($pRange === null)) {
+ throw new PHPExcel_Exception('Parameters can not be null.');
+ }
+
+ // Set local members
+ $this->name = $pName;
+ $this->worksheet = $pWorksheet;
+ $this->range = $pRange;
+ $this->localOnly = $pLocalOnly;
+ $this->scope = ($pLocalOnly == true) ? (($pScope == null) ? $pWorksheet : $pScope) : null;
+ }
+
+ /**
+ * Get name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Set name
+ *
+ * @param string $value
+ * @return PHPExcel_NamedRange
+ */
+ public function setName($value = null)
+ {
+ if ($value !== null) {
+ // Old title
+ $oldTitle = $this->name;
+
+ // Re-attach
+ if ($this->worksheet !== null) {
+ $this->worksheet->getParent()->removeNamedRange($this->name, $this->worksheet);
+ }
+ $this->name = $value;
+
+ if ($this->worksheet !== null) {
+ $this->worksheet->getParent()->addNamedRange($this);
+ }
+
+ // New title
+ $newTitle = $this->name;
+ PHPExcel_ReferenceHelper::getInstance()->updateNamedFormulas($this->worksheet->getParent(), $oldTitle, $newTitle);
+ }
+ return $this;
+ }
+
+ /**
+ * Get worksheet
+ *
+ * @return PHPExcel_Worksheet
+ */
+ public function getWorksheet()
+ {
+ return $this->worksheet;
+ }
+
+ /**
+ * Set worksheet
+ *
+ * @param PHPExcel_Worksheet $value
+ * @return PHPExcel_NamedRange
+ */
+ public function setWorksheet(PHPExcel_Worksheet $value = null)
+ {
+ if ($value !== null) {
+ $this->worksheet = $value;
+ }
+ return $this;
+ }
+
+ /**
+ * Get range
+ *
+ * @return string
+ */
+ public function getRange()
+ {
+ return $this->range;
+ }
+
+ /**
+ * Set range
+ *
+ * @param string $value
+ * @return PHPExcel_NamedRange
+ */
+ public function setRange($value = null)
+ {
+ if ($value !== null) {
+ $this->range = $value;
+ }
+ return $this;
+ }
+
+ /**
+ * Get localOnly
+ *
+ * @return bool
+ */
+ public function getLocalOnly()
+ {
+ return $this->localOnly;
+ }
+
+ /**
+ * Set localOnly
+ *
+ * @param bool $value
+ * @return PHPExcel_NamedRange
+ */
+ public function setLocalOnly($value = false)
+ {
+ $this->localOnly = $value;
+ $this->scope = $value ? $this->worksheet : null;
+ return $this;
+ }
+
+ /**
+ * Get scope
+ *
+ * @return PHPExcel_Worksheet|null
+ */
+ public function getScope()
+ {
+ return $this->scope;
+ }
+
+ /**
+ * Set scope
+ *
+ * @param PHPExcel_Worksheet|null $value
+ * @return PHPExcel_NamedRange
+ */
+ public function setScope(PHPExcel_Worksheet $value = null)
+ {
+ $this->scope = $value;
+ $this->localOnly = ($value == null) ? false : true;
+ return $this;
+ }
+
+ /**
+ * Resolve a named range to a regular cell range
+ *
+ * @param string $pNamedRange Named range
+ * @param PHPExcel_Worksheet|null $pSheet Scope. Use null for global scope
+ * @return PHPExcel_NamedRange
+ */
+ public static function resolveRange($pNamedRange = '', PHPExcel_Worksheet $pSheet)
+ {
+ return $pSheet->getParent()->getNamedRange($pNamedRange, $pSheet);
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Abstract.php b/extend/PHPExcel/PHPExcel/Reader/Abstract.php
new file mode 100755
index 0000000..189c70a
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Abstract.php
@@ -0,0 +1,289 @@
+readDataOnly;
+ }
+
+ /**
+ * Set read data only
+ * Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
+ * Set to false (the default) to advise the Reader to read both data and formatting for cells.
+ *
+ * @param boolean $pValue
+ *
+ * @return PHPExcel_Reader_IReader
+ */
+ public function setReadDataOnly($pValue = false)
+ {
+ $this->readDataOnly = $pValue;
+ return $this;
+ }
+
+ /**
+ * Read empty cells?
+ * If this is true (the default), then the Reader will read data values for all cells, irrespective of value.
+ * If false it will not read data for cells containing a null value or an empty string.
+ *
+ * @return boolean
+ */
+ public function getReadEmptyCells()
+ {
+ return $this->readEmptyCells;
+ }
+
+ /**
+ * Set read empty cells
+ * Set to true (the default) to advise the Reader read data values for all cells, irrespective of value.
+ * Set to false to advise the Reader to ignore cells containing a null value or an empty string.
+ *
+ * @param boolean $pValue
+ *
+ * @return PHPExcel_Reader_IReader
+ */
+ public function setReadEmptyCells($pValue = true)
+ {
+ $this->readEmptyCells = $pValue;
+ return $this;
+ }
+
+ /**
+ * Read charts in workbook?
+ * If this is true, then the Reader will include any charts that exist in the workbook.
+ * Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+ * If false (the default) it will ignore any charts defined in the workbook file.
+ *
+ * @return boolean
+ */
+ public function getIncludeCharts()
+ {
+ return $this->includeCharts;
+ }
+
+ /**
+ * Set read charts in workbook
+ * Set to true, to advise the Reader to include any charts that exist in the workbook.
+ * Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+ * Set to false (the default) to discard charts.
+ *
+ * @param boolean $pValue
+ *
+ * @return PHPExcel_Reader_IReader
+ */
+ public function setIncludeCharts($pValue = false)
+ {
+ $this->includeCharts = (boolean) $pValue;
+ return $this;
+ }
+
+ /**
+ * Get which sheets to load
+ * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
+ * indicating that all worksheets in the workbook should be loaded.
+ *
+ * @return mixed
+ */
+ public function getLoadSheetsOnly()
+ {
+ return $this->loadSheetsOnly;
+ }
+
+ /**
+ * Set which sheets to load
+ *
+ * @param mixed $value
+ * This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
+ * If NULL, then it tells the Reader to read all worksheets in the workbook
+ *
+ * @return PHPExcel_Reader_IReader
+ */
+ public function setLoadSheetsOnly($value = null)
+ {
+ if ($value === null) {
+ return $this->setLoadAllSheets();
+ }
+
+ $this->loadSheetsOnly = is_array($value) ? $value : array($value);
+ return $this;
+ }
+
+ /**
+ * Set all sheets to load
+ * Tells the Reader to load all worksheets from the workbook.
+ *
+ * @return PHPExcel_Reader_IReader
+ */
+ public function setLoadAllSheets()
+ {
+ $this->loadSheetsOnly = null;
+ return $this;
+ }
+
+ /**
+ * Read filter
+ *
+ * @return PHPExcel_Reader_IReadFilter
+ */
+ public function getReadFilter()
+ {
+ return $this->readFilter;
+ }
+
+ /**
+ * Set read filter
+ *
+ * @param PHPExcel_Reader_IReadFilter $pValue
+ * @return PHPExcel_Reader_IReader
+ */
+ public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue)
+ {
+ $this->readFilter = $pValue;
+ return $this;
+ }
+
+ /**
+ * Open file for reading
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ * @return resource
+ */
+ protected function openFile($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename) || !is_readable($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ // Open file
+ $this->fileHandle = fopen($pFilename, 'r');
+ if ($this->fileHandle === false) {
+ throw new PHPExcel_Reader_Exception("Could not open file " . $pFilename . " for reading.");
+ }
+ }
+
+ /**
+ * Can the current PHPExcel_Reader_IReader read the file?
+ *
+ * @param string $pFilename
+ * @return boolean
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function canRead($pFilename)
+ {
+ // Check if file exists
+ try {
+ $this->openFile($pFilename);
+ } catch (Exception $e) {
+ return false;
+ }
+
+ $readable = $this->isValidFormat();
+ fclose($this->fileHandle);
+ return $readable;
+ }
+
+ /**
+ * Scan theXML for use of securityScan(file_get_contents($filestream));
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/CSV.php b/extend/PHPExcel/PHPExcel/Reader/CSV.php
new file mode 100755
index 0000000..21329da
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/CSV.php
@@ -0,0 +1,406 @@
+readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ }
+
+ /**
+ * Validate that the current file is a CSV file
+ *
+ * @return boolean
+ */
+ protected function isValidFormat()
+ {
+ return true;
+ }
+
+ /**
+ * Set input encoding
+ *
+ * @param string $pValue Input encoding
+ */
+ public function setInputEncoding($pValue = 'UTF-8')
+ {
+ $this->inputEncoding = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get input encoding
+ *
+ * @return string
+ */
+ public function getInputEncoding()
+ {
+ return $this->inputEncoding;
+ }
+
+ /**
+ * Move filepointer past any BOM marker
+ *
+ */
+ protected function skipBOM()
+ {
+ rewind($this->fileHandle);
+
+ switch ($this->inputEncoding) {
+ case 'UTF-8':
+ fgets($this->fileHandle, 4) == "\xEF\xBB\xBF" ?
+ fseek($this->fileHandle, 3) : fseek($this->fileHandle, 0);
+ break;
+ case 'UTF-16LE':
+ fgets($this->fileHandle, 3) == "\xFF\xFE" ?
+ fseek($this->fileHandle, 2) : fseek($this->fileHandle, 0);
+ break;
+ case 'UTF-16BE':
+ fgets($this->fileHandle, 3) == "\xFE\xFF" ?
+ fseek($this->fileHandle, 2) : fseek($this->fileHandle, 0);
+ break;
+ case 'UTF-32LE':
+ fgets($this->fileHandle, 5) == "\xFF\xFE\x00\x00" ?
+ fseek($this->fileHandle, 4) : fseek($this->fileHandle, 0);
+ break;
+ case 'UTF-32BE':
+ fgets($this->fileHandle, 5) == "\x00\x00\xFE\xFF" ?
+ fseek($this->fileHandle, 4) : fseek($this->fileHandle, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Identify any separator that is explicitly set in the file
+ *
+ */
+ protected function checkSeparator()
+ {
+ $line = fgets($this->fileHandle);
+ if ($line === false) {
+ return;
+ }
+
+ if ((strlen(trim($line, "\r\n")) == 5) && (stripos($line, 'sep=') === 0)) {
+ $this->delimiter = substr($line, 4, 1);
+ return;
+ }
+ return $this->skipBOM();
+ }
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Open file
+ $this->openFile($pFilename);
+ if (!$this->isValidFormat()) {
+ fclose($this->fileHandle);
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+ }
+ $fileHandle = $this->fileHandle;
+
+ // Skip BOM, if any
+ $this->skipBOM();
+ $this->checkSeparator();
+
+ $escapeEnclosures = array( "\\" . $this->enclosure, $this->enclosure . $this->enclosure );
+
+ $worksheetInfo = array();
+ $worksheetInfo[0]['worksheetName'] = 'Worksheet';
+ $worksheetInfo[0]['lastColumnLetter'] = 'A';
+ $worksheetInfo[0]['lastColumnIndex'] = 0;
+ $worksheetInfo[0]['totalRows'] = 0;
+ $worksheetInfo[0]['totalColumns'] = 0;
+
+ // Loop through each line of the file in turn
+ while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
+ $worksheetInfo[0]['totalRows']++;
+ $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
+ }
+
+ $worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
+ $worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
+
+ // Close file
+ fclose($fileHandle);
+
+ return $worksheetInfo;
+ }
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Create new PHPExcel
+ $objPHPExcel = new PHPExcel();
+
+ // Load into this instance
+ return $this->loadIntoExisting($pFilename, $objPHPExcel);
+ }
+
+ /**
+ * Loads PHPExcel from file into PHPExcel instance
+ *
+ * @param string $pFilename
+ * @param PHPExcel $objPHPExcel
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+ {
+ $lineEnding = ini_get('auto_detect_line_endings');
+ ini_set('auto_detect_line_endings', true);
+
+ // Open file
+ $this->openFile($pFilename);
+ if (!$this->isValidFormat()) {
+ fclose($this->fileHandle);
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+ }
+ $fileHandle = $this->fileHandle;
+
+ // Skip BOM, if any
+ $this->skipBOM();
+ $this->checkSeparator();
+
+ // Create new PHPExcel object
+ while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
+ $objPHPExcel->createSheet();
+ }
+ $sheet = $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
+
+ $escapeEnclosures = array( "\\" . $this->enclosure,
+ $this->enclosure . $this->enclosure
+ );
+
+ // Set our starting row based on whether we're in contiguous mode or not
+ $currentRow = 1;
+ if ($this->contiguous) {
+ $currentRow = ($this->contiguousRow == -1) ? $sheet->getHighestRow(): $this->contiguousRow;
+ }
+
+ // Loop through each line of the file in turn
+ while (($rowData = fgetcsv($fileHandle, 0, $this->delimiter, $this->enclosure)) !== false) {
+ $columnLetter = 'A';
+ foreach ($rowData as $rowDatum) {
+ if ($rowDatum != '' && $this->readFilter->readCell($columnLetter, $currentRow)) {
+ // Unescape enclosures
+ $rowDatum = str_replace($escapeEnclosures, $this->enclosure, $rowDatum);
+
+ // Convert encoding if necessary
+ if ($this->inputEncoding !== 'UTF-8') {
+ $rowDatum = PHPExcel_Shared_String::ConvertEncoding($rowDatum, 'UTF-8', $this->inputEncoding);
+ }
+
+ // Set cell value
+ $sheet->getCell($columnLetter . $currentRow)->setValue($rowDatum);
+ }
+ ++$columnLetter;
+ }
+ ++$currentRow;
+ }
+
+ // Close file
+ fclose($fileHandle);
+
+ if ($this->contiguous) {
+ $this->contiguousRow = $currentRow;
+ }
+
+ ini_set('auto_detect_line_endings', $lineEnding);
+
+ // Return
+ return $objPHPExcel;
+ }
+
+ /**
+ * Get delimiter
+ *
+ * @return string
+ */
+ public function getDelimiter()
+ {
+ return $this->delimiter;
+ }
+
+ /**
+ * Set delimiter
+ *
+ * @param string $pValue Delimiter, defaults to ,
+ * @return PHPExcel_Reader_CSV
+ */
+ public function setDelimiter($pValue = ',')
+ {
+ $this->delimiter = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get enclosure
+ *
+ * @return string
+ */
+ public function getEnclosure()
+ {
+ return $this->enclosure;
+ }
+
+ /**
+ * Set enclosure
+ *
+ * @param string $pValue Enclosure, defaults to "
+ * @return PHPExcel_Reader_CSV
+ */
+ public function setEnclosure($pValue = '"')
+ {
+ if ($pValue == '') {
+ $pValue = '"';
+ }
+ $this->enclosure = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get sheet index
+ *
+ * @return integer
+ */
+ public function getSheetIndex()
+ {
+ return $this->sheetIndex;
+ }
+
+ /**
+ * Set sheet index
+ *
+ * @param integer $pValue Sheet index
+ * @return PHPExcel_Reader_CSV
+ */
+ public function setSheetIndex($pValue = 0)
+ {
+ $this->sheetIndex = $pValue;
+ return $this;
+ }
+
+ /**
+ * Set Contiguous
+ *
+ * @param boolean $contiguous
+ */
+ public function setContiguous($contiguous = false)
+ {
+ $this->contiguous = (bool) $contiguous;
+ if (!$contiguous) {
+ $this->contiguousRow = -1;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Contiguous
+ *
+ * @return boolean
+ */
+ public function getContiguous()
+ {
+ return $this->contiguous;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php b/extend/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php
new file mode 100755
index 0000000..ea25f63
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/DefaultReadFilter.php
@@ -0,0 +1,51 @@
+readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ }
+
+
+ /**
+ * Can the current PHPExcel_Reader_IReader read the file?
+ *
+ * @param string $pFilename
+ * @return boolean
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function canRead($pFilename)
+ {
+
+ // Office xmlns:o="urn:schemas-microsoft-com:office:office"
+ // Excel xmlns:x="urn:schemas-microsoft-com:office:excel"
+ // XML Spreadsheet xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
+ // Spreadsheet component xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet"
+ // XML schema xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
+ // XML data type xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
+ // MS-persist recordset xmlns:rs="urn:schemas-microsoft-com:rowset"
+ // Rowset xmlns:z="#RowsetSchema"
+ //
+
+ $signature = array(
+ ''
+ );
+
+ // Open file
+ $this->openFile($pFilename);
+ $fileHandle = $this->fileHandle;
+
+ // Read sample data (first 2 KB will do)
+ $data = fread($fileHandle, 2048);
+ fclose($fileHandle);
+
+ $valid = true;
+ foreach ($signature as $match) {
+ // every part of the signature must be present
+ if (strpos($data, $match) === false) {
+ $valid = false;
+ break;
+ }
+ }
+
+ // Retrieve charset encoding
+ if (preg_match('//um', $data, $matches)) {
+ $this->charSet = strtoupper($matches[1]);
+ }
+// echo 'Character Set is ', $this->charSet,' ';
+
+ return $valid;
+ }
+
+
+ /**
+ * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetNames($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+ if (!$this->canRead($pFilename)) {
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+ }
+
+ $worksheetNames = array();
+
+ $xml = simplexml_load_string($this->securityScan(file_get_contents($pFilename)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespaces = $xml->getNamespaces(true);
+
+ $xml_ss = $xml->children($namespaces['ss']);
+ foreach ($xml_ss->Worksheet as $worksheet) {
+ $worksheet_ss = $worksheet->attributes($namespaces['ss']);
+ $worksheetNames[] = self::convertStringEncoding((string) $worksheet_ss['Name'], $this->charSet);
+ }
+
+ return $worksheetNames;
+ }
+
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $worksheetInfo = array();
+
+ $xml = simplexml_load_string($this->securityScan(file_get_contents($pFilename)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespaces = $xml->getNamespaces(true);
+
+ $worksheetID = 1;
+ $xml_ss = $xml->children($namespaces['ss']);
+ foreach ($xml_ss->Worksheet as $worksheet) {
+ $worksheet_ss = $worksheet->attributes($namespaces['ss']);
+
+ $tmpInfo = array();
+ $tmpInfo['worksheetName'] = '';
+ $tmpInfo['lastColumnLetter'] = 'A';
+ $tmpInfo['lastColumnIndex'] = 0;
+ $tmpInfo['totalRows'] = 0;
+ $tmpInfo['totalColumns'] = 0;
+
+ if (isset($worksheet_ss['Name'])) {
+ $tmpInfo['worksheetName'] = (string) $worksheet_ss['Name'];
+ } else {
+ $tmpInfo['worksheetName'] = "Worksheet_{$worksheetID}";
+ }
+
+ if (isset($worksheet->Table->Row)) {
+ $rowIndex = 0;
+
+ foreach ($worksheet->Table->Row as $rowData) {
+ $columnIndex = 0;
+ $rowHasData = false;
+
+ foreach ($rowData->Cell as $cell) {
+ if (isset($cell->Data)) {
+ $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+ $rowHasData = true;
+ }
+
+ ++$columnIndex;
+ }
+
+ ++$rowIndex;
+
+ if ($rowHasData) {
+ $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+ }
+ }
+ }
+
+ $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+ $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+ $worksheetInfo[] = $tmpInfo;
+ ++$worksheetID;
+ }
+
+ return $worksheetInfo;
+ }
+
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Create new PHPExcel
+ $objPHPExcel = new PHPExcel();
+ $objPHPExcel->removeSheetByIndex(0);
+
+ // Load into this instance
+ return $this->loadIntoExisting($pFilename, $objPHPExcel);
+ }
+
+ protected static function identifyFixedStyleValue($styleList, &$styleAttributeValue)
+ {
+ $styleAttributeValue = strtolower($styleAttributeValue);
+ foreach ($styleList as $style) {
+ if ($styleAttributeValue == strtolower($style)) {
+ $styleAttributeValue = $style;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * pixel units to excel width units(units of 1/256th of a character width)
+ * @param pxs
+ * @return
+ */
+ protected static function pixel2WidthUnits($pxs)
+ {
+ $UNIT_OFFSET_MAP = array(0, 36, 73, 109, 146, 182, 219);
+
+ $widthUnits = 256 * ($pxs / 7);
+ $widthUnits += $UNIT_OFFSET_MAP[($pxs % 7)];
+ return $widthUnits;
+ }
+
+ /**
+ * excel width units(units of 1/256th of a character width) to pixel units
+ * @param widthUnits
+ * @return
+ */
+ protected static function widthUnits2Pixel($widthUnits)
+ {
+ $pixels = ($widthUnits / 256) * 7;
+ $offsetWidthUnits = $widthUnits % 256;
+ $pixels += round($offsetWidthUnits / (256 / 7));
+ return $pixels;
+ }
+
+ protected static function hex2str($hex)
+ {
+ return chr(hexdec($hex[1]));
+ }
+
+ /**
+ * Loads PHPExcel from file into PHPExcel instance
+ *
+ * @param string $pFilename
+ * @param PHPExcel $objPHPExcel
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+ {
+ $fromFormats = array('\-', '\ ');
+ $toFormats = array('-', ' ');
+
+ $underlineStyles = array (
+ PHPExcel_Style_Font::UNDERLINE_NONE,
+ PHPExcel_Style_Font::UNDERLINE_DOUBLE,
+ PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING,
+ PHPExcel_Style_Font::UNDERLINE_SINGLE,
+ PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING
+ );
+ $verticalAlignmentStyles = array (
+ PHPExcel_Style_Alignment::VERTICAL_BOTTOM,
+ PHPExcel_Style_Alignment::VERTICAL_TOP,
+ PHPExcel_Style_Alignment::VERTICAL_CENTER,
+ PHPExcel_Style_Alignment::VERTICAL_JUSTIFY
+ );
+ $horizontalAlignmentStyles = array (
+ PHPExcel_Style_Alignment::HORIZONTAL_GENERAL,
+ PHPExcel_Style_Alignment::HORIZONTAL_LEFT,
+ PHPExcel_Style_Alignment::HORIZONTAL_RIGHT,
+ PHPExcel_Style_Alignment::HORIZONTAL_CENTER,
+ PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS,
+ PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY
+ );
+
+ $timezoneObj = new DateTimeZone('Europe/London');
+ $GMT = new DateTimeZone('UTC');
+
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ if (!$this->canRead($pFilename)) {
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+ }
+
+ $xml = simplexml_load_string($this->securityScan(file_get_contents($pFilename)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespaces = $xml->getNamespaces(true);
+
+ $docProps = $objPHPExcel->getProperties();
+ if (isset($xml->DocumentProperties[0])) {
+ foreach ($xml->DocumentProperties[0] as $propertyName => $propertyValue) {
+ switch ($propertyName) {
+ case 'Title':
+ $docProps->setTitle(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Subject':
+ $docProps->setSubject(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Author':
+ $docProps->setCreator(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Created':
+ $creationDate = strtotime($propertyValue);
+ $docProps->setCreated($creationDate);
+ break;
+ case 'LastAuthor':
+ $docProps->setLastModifiedBy(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'LastSaved':
+ $lastSaveDate = strtotime($propertyValue);
+ $docProps->setModified($lastSaveDate);
+ break;
+ case 'Company':
+ $docProps->setCompany(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Category':
+ $docProps->setCategory(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Manager':
+ $docProps->setManager(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Keywords':
+ $docProps->setKeywords(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ case 'Description':
+ $docProps->setDescription(self::convertStringEncoding($propertyValue, $this->charSet));
+ break;
+ }
+ }
+ }
+ if (isset($xml->CustomDocumentProperties)) {
+ foreach ($xml->CustomDocumentProperties[0] as $propertyName => $propertyValue) {
+ $propertyAttributes = $propertyValue->attributes($namespaces['dt']);
+ $propertyName = preg_replace_callback('/_x([0-9a-z]{4})_/', 'PHPExcel_Reader_Excel2003XML::hex2str', $propertyName);
+ $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_UNKNOWN;
+ switch ((string) $propertyAttributes) {
+ case 'string':
+ $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING;
+ $propertyValue = trim($propertyValue);
+ break;
+ case 'boolean':
+ $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_BOOLEAN;
+ $propertyValue = (bool) $propertyValue;
+ break;
+ case 'integer':
+ $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_INTEGER;
+ $propertyValue = intval($propertyValue);
+ break;
+ case 'float':
+ $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_FLOAT;
+ $propertyValue = floatval($propertyValue);
+ break;
+ case 'dateTime.tz':
+ $propertyType = PHPExcel_DocumentProperties::PROPERTY_TYPE_DATE;
+ $propertyValue = strtotime(trim($propertyValue));
+ break;
+ }
+ $docProps->setCustomProperty($propertyName, $propertyValue, $propertyType);
+ }
+ }
+
+ foreach ($xml->Styles[0] as $style) {
+ $style_ss = $style->attributes($namespaces['ss']);
+ $styleID = (string) $style_ss['ID'];
+// echo 'Style ID = '.$styleID.' ';
+ $this->styles[$styleID] = (isset($this->styles['Default'])) ? $this->styles['Default'] : array();
+ foreach ($style as $styleType => $styleData) {
+ $styleAttributes = $styleData->attributes($namespaces['ss']);
+// echo $styleType.' ';
+ switch ($styleType) {
+ case 'Alignment':
+ foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+// echo $styleAttributeKey.' = '.$styleAttributeValue.' ';
+ $styleAttributeValue = (string) $styleAttributeValue;
+ switch ($styleAttributeKey) {
+ case 'Vertical':
+ if (self::identifyFixedStyleValue($verticalAlignmentStyles, $styleAttributeValue)) {
+ $this->styles[$styleID]['alignment']['vertical'] = $styleAttributeValue;
+ }
+ break;
+ case 'Horizontal':
+ if (self::identifyFixedStyleValue($horizontalAlignmentStyles, $styleAttributeValue)) {
+ $this->styles[$styleID]['alignment']['horizontal'] = $styleAttributeValue;
+ }
+ break;
+ case 'WrapText':
+ $this->styles[$styleID]['alignment']['wrap'] = true;
+ break;
+ }
+ }
+ break;
+ case 'Borders':
+ foreach ($styleData->Border as $borderStyle) {
+ $borderAttributes = $borderStyle->attributes($namespaces['ss']);
+ $thisBorder = array();
+ foreach ($borderAttributes as $borderStyleKey => $borderStyleValue) {
+// echo $borderStyleKey.' = '.$borderStyleValue.' ';
+ switch ($borderStyleKey) {
+ case 'LineStyle':
+ $thisBorder['style'] = PHPExcel_Style_Border::BORDER_MEDIUM;
+// $thisBorder['style'] = $borderStyleValue;
+ break;
+ case 'Weight':
+// $thisBorder['style'] = $borderStyleValue;
+ break;
+ case 'Position':
+ $borderPosition = strtolower($borderStyleValue);
+ break;
+ case 'Color':
+ $borderColour = substr($borderStyleValue, 1);
+ $thisBorder['color']['rgb'] = $borderColour;
+ break;
+ }
+ }
+ if (!empty($thisBorder)) {
+ if (($borderPosition == 'left') || ($borderPosition == 'right') || ($borderPosition == 'top') || ($borderPosition == 'bottom')) {
+ $this->styles[$styleID]['borders'][$borderPosition] = $thisBorder;
+ }
+ }
+ }
+ break;
+ case 'Font':
+ foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+// echo $styleAttributeKey.' = '.$styleAttributeValue.' ';
+ $styleAttributeValue = (string) $styleAttributeValue;
+ switch ($styleAttributeKey) {
+ case 'FontName':
+ $this->styles[$styleID]['font']['name'] = $styleAttributeValue;
+ break;
+ case 'Size':
+ $this->styles[$styleID]['font']['size'] = $styleAttributeValue;
+ break;
+ case 'Color':
+ $this->styles[$styleID]['font']['color']['rgb'] = substr($styleAttributeValue, 1);
+ break;
+ case 'Bold':
+ $this->styles[$styleID]['font']['bold'] = true;
+ break;
+ case 'Italic':
+ $this->styles[$styleID]['font']['italic'] = true;
+ break;
+ case 'Underline':
+ if (self::identifyFixedStyleValue($underlineStyles, $styleAttributeValue)) {
+ $this->styles[$styleID]['font']['underline'] = $styleAttributeValue;
+ }
+ break;
+ }
+ }
+ break;
+ case 'Interior':
+ foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+// echo $styleAttributeKey.' = '.$styleAttributeValue.' ';
+ switch ($styleAttributeKey) {
+ case 'Color':
+ $this->styles[$styleID]['fill']['color']['rgb'] = substr($styleAttributeValue, 1);
+ break;
+ }
+ }
+ break;
+ case 'NumberFormat':
+ foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+// echo $styleAttributeKey.' = '.$styleAttributeValue.' ';
+ $styleAttributeValue = str_replace($fromFormats, $toFormats, $styleAttributeValue);
+ switch ($styleAttributeValue) {
+ case 'Short Date':
+ $styleAttributeValue = 'dd/mm/yyyy';
+ break;
+ }
+ if ($styleAttributeValue > '') {
+ $this->styles[$styleID]['numberformat']['code'] = $styleAttributeValue;
+ }
+ }
+ break;
+ case 'Protection':
+ foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) {
+// echo $styleAttributeKey.' = '.$styleAttributeValue.' ';
+ }
+ break;
+ }
+ }
+// print_r($this->styles[$styleID]);
+// echo ' ';
+ }
+// echo ' ';
+
+ $worksheetID = 0;
+ $xml_ss = $xml->children($namespaces['ss']);
+
+ foreach ($xml_ss->Worksheet as $worksheet) {
+ $worksheet_ss = $worksheet->attributes($namespaces['ss']);
+
+ if ((isset($this->loadSheetsOnly)) && (isset($worksheet_ss['Name'])) &&
+ (!in_array($worksheet_ss['Name'], $this->loadSheetsOnly))) {
+ continue;
+ }
+
+// echo 'Worksheet: ', $worksheet_ss['Name'],'';
+//
+ // Create new Worksheet
+ $objPHPExcel->createSheet();
+ $objPHPExcel->setActiveSheetIndex($worksheetID);
+ if (isset($worksheet_ss['Name'])) {
+ $worksheetName = self::convertStringEncoding((string) $worksheet_ss['Name'], $this->charSet);
+ // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
+ // formula cells... during the load, all formulae should be correct, and we're simply bringing
+ // the worksheet name in line with the formula, not the reverse
+ $objPHPExcel->getActiveSheet()->setTitle($worksheetName, false);
+ }
+
+ $columnID = 'A';
+ if (isset($worksheet->Table->Column)) {
+ foreach ($worksheet->Table->Column as $columnData) {
+ $columnData_ss = $columnData->attributes($namespaces['ss']);
+ if (isset($columnData_ss['Index'])) {
+ $columnID = PHPExcel_Cell::stringFromColumnIndex($columnData_ss['Index']-1);
+ }
+ if (isset($columnData_ss['Width'])) {
+ $columnWidth = $columnData_ss['Width'];
+// echo 'Setting column width for '.$columnID.' to '.$columnWidth.' ';
+ $objPHPExcel->getActiveSheet()->getColumnDimension($columnID)->setWidth($columnWidth / 5.4);
+ }
+ ++$columnID;
+ }
+ }
+
+ $rowID = 1;
+ if (isset($worksheet->Table->Row)) {
+ $additionalMergedCells = 0;
+ foreach ($worksheet->Table->Row as $rowData) {
+ $rowHasData = false;
+ $row_ss = $rowData->attributes($namespaces['ss']);
+ if (isset($row_ss['Index'])) {
+ $rowID = (integer) $row_ss['Index'];
+ }
+// echo 'Row '.$rowID.' ';
+
+ $columnID = 'A';
+ foreach ($rowData->Cell as $cell) {
+ $cell_ss = $cell->attributes($namespaces['ss']);
+ if (isset($cell_ss['Index'])) {
+ $columnID = PHPExcel_Cell::stringFromColumnIndex($cell_ss['Index']-1);
+ }
+ $cellRange = $columnID.$rowID;
+
+ if ($this->getReadFilter() !== null) {
+ if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
+ continue;
+ }
+ }
+
+ if ((isset($cell_ss['MergeAcross'])) || (isset($cell_ss['MergeDown']))) {
+ $columnTo = $columnID;
+ if (isset($cell_ss['MergeAcross'])) {
+ $additionalMergedCells += (int)$cell_ss['MergeAcross'];
+ $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cell_ss['MergeAcross'] -1);
+ }
+ $rowTo = $rowID;
+ if (isset($cell_ss['MergeDown'])) {
+ $rowTo = $rowTo + $cell_ss['MergeDown'];
+ }
+ $cellRange .= ':'.$columnTo.$rowTo;
+ $objPHPExcel->getActiveSheet()->mergeCells($cellRange);
+ }
+
+ $cellIsSet = $hasCalculatedValue = false;
+ $cellDataFormula = '';
+ if (isset($cell_ss['Formula'])) {
+ $cellDataFormula = $cell_ss['Formula'];
+ // added this as a check for array formulas
+ if (isset($cell_ss['ArrayRange'])) {
+ $cellDataCSEFormula = $cell_ss['ArrayRange'];
+// echo "found an array formula at ".$columnID.$rowID." ";
+ }
+ $hasCalculatedValue = true;
+ }
+ if (isset($cell->Data)) {
+ $cellValue = $cellData = $cell->Data;
+ $type = PHPExcel_Cell_DataType::TYPE_NULL;
+ $cellData_ss = $cellData->attributes($namespaces['ss']);
+ if (isset($cellData_ss['Type'])) {
+ $cellDataType = $cellData_ss['Type'];
+ switch ($cellDataType) {
+ /*
+ const TYPE_STRING = 's';
+ const TYPE_FORMULA = 'f';
+ const TYPE_NUMERIC = 'n';
+ const TYPE_BOOL = 'b';
+ const TYPE_NULL = 'null';
+ const TYPE_INLINE = 'inlineStr';
+ const TYPE_ERROR = 'e';
+ */
+ case 'String':
+ $cellValue = self::convertStringEncoding($cellValue, $this->charSet);
+ $type = PHPExcel_Cell_DataType::TYPE_STRING;
+ break;
+ case 'Number':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $cellValue = (float) $cellValue;
+ if (floor($cellValue) == $cellValue) {
+ $cellValue = (integer) $cellValue;
+ }
+ break;
+ case 'Boolean':
+ $type = PHPExcel_Cell_DataType::TYPE_BOOL;
+ $cellValue = ($cellValue != 0);
+ break;
+ case 'DateTime':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $cellValue = PHPExcel_Shared_Date::PHPToExcel(strtotime($cellValue));
+ break;
+ case 'Error':
+ $type = PHPExcel_Cell_DataType::TYPE_ERROR;
+ break;
+ }
+ }
+
+ if ($hasCalculatedValue) {
+// echo 'FORMULA ';
+ $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+ $columnNumber = PHPExcel_Cell::columnIndexFromString($columnID);
+ if (substr($cellDataFormula, 0, 3) == 'of:') {
+ $cellDataFormula = substr($cellDataFormula, 3);
+// echo 'Before: ', $cellDataFormula,' ';
+ $temp = explode('"', $cellDataFormula);
+ $key = false;
+ foreach ($temp as &$value) {
+ // Only replace in alternate array entries (i.e. non-quoted blocks)
+ if ($key = !$key) {
+ $value = str_replace(array('[.', '.', ']'), '', $value);
+ }
+ }
+ } else {
+ // Convert R1C1 style references to A1 style references (but only when not quoted)
+// echo 'Before: ', $cellDataFormula,' ';
+ $temp = explode('"', $cellDataFormula);
+ $key = false;
+ foreach ($temp as &$value) {
+ // Only replace in alternate array entries (i.e. non-quoted blocks)
+ if ($key = !$key) {
+ preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/', $value, $cellReferences, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
+ // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
+ // through the formula from left to right. Reversing means that we work right to left.through
+ // the formula
+ $cellReferences = array_reverse($cellReferences);
+ // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
+ // then modify the formula to use that new reference
+ foreach ($cellReferences as $cellReference) {
+ $rowReference = $cellReference[2][0];
+ // Empty R reference is the current row
+ if ($rowReference == '') {
+ $rowReference = $rowID;
+ }
+ // Bracketed R references are relative to the current row
+ if ($rowReference{0} == '[') {
+ $rowReference = $rowID + trim($rowReference, '[]');
+ }
+ $columnReference = $cellReference[4][0];
+ // Empty C reference is the current column
+ if ($columnReference == '') {
+ $columnReference = $columnNumber;
+ }
+ // Bracketed C references are relative to the current column
+ if ($columnReference{0} == '[') {
+ $columnReference = $columnNumber + trim($columnReference, '[]');
+ }
+ $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference;
+ $value = substr_replace($value, $A1CellReference, $cellReference[0][1], strlen($cellReference[0][0]));
+ }
+ }
+ }
+ }
+ unset($value);
+ // Then rebuild the formula string
+ $cellDataFormula = implode('"', $temp);
+// echo 'After: ', $cellDataFormula,' ';
+ }
+
+// echo 'Cell '.$columnID.$rowID.' is a '.$type.' with a value of '.(($hasCalculatedValue) ? $cellDataFormula : $cellValue).' ';
+//
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $cellValue), $type);
+ if ($hasCalculatedValue) {
+// echo 'Formula result is '.$cellValue.' ';
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($cellValue);
+ }
+ $cellIsSet = $rowHasData = true;
+ }
+
+ if (isset($cell->Comment)) {
+// echo 'comment found ';
+ $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
+ $author = 'unknown';
+ if (isset($commentAttributes->Author)) {
+ $author = (string)$commentAttributes->Author;
+// echo 'Author: ', $author,' ';
+ }
+ $node = $cell->Comment->Data->asXML();
+// $annotation = str_replace('html:','',substr($node,49,-10));
+// echo $annotation,' ';
+ $annotation = strip_tags($node);
+// echo 'Annotation: ', $annotation,' ';
+ $objPHPExcel->getActiveSheet()->getComment($columnID.$rowID)->setAuthor(self::convertStringEncoding($author, $this->charSet))->setText($this->parseRichText($annotation));
+ }
+
+ if (($cellIsSet) && (isset($cell_ss['StyleID']))) {
+ $style = (string) $cell_ss['StyleID'];
+// echo 'Cell style for '.$columnID.$rowID.' is '.$style.' ';
+ if ((isset($this->styles[$style])) && (!empty($this->styles[$style]))) {
+// echo 'Cell '.$columnID.$rowID.' ';
+// print_r($this->styles[$style]);
+// echo ' ';
+ if (!$objPHPExcel->getActiveSheet()->cellExists($columnID.$rowID)) {
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValue(null);
+ }
+ $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($this->styles[$style]);
+ }
+ }
+ ++$columnID;
+ while ($additionalMergedCells > 0) {
+ ++$columnID;
+ $additionalMergedCells--;
+ }
+ }
+
+ if ($rowHasData) {
+ if (isset($row_ss['StyleID'])) {
+ $rowStyle = $row_ss['StyleID'];
+ }
+ if (isset($row_ss['Height'])) {
+ $rowHeight = $row_ss['Height'];
+// echo 'Setting row height to '.$rowHeight.' ';
+ $objPHPExcel->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight);
+ }
+ }
+
+ ++$rowID;
+ }
+ }
+ ++$worksheetID;
+ }
+
+ // Return
+ return $objPHPExcel;
+ }
+
+
+ protected static function convertStringEncoding($string, $charset)
+ {
+ if ($charset != 'UTF-8') {
+ return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $charset);
+ }
+ return $string;
+ }
+
+
+ protected function parseRichText($is = '')
+ {
+ $value = new PHPExcel_RichText();
+
+ $value->createText(self::convertStringEncoding($is, $this->charSet));
+
+ return $value;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel2007.php b/extend/PHPExcel/PHPExcel/Reader/Excel2007.php
new file mode 100755
index 0000000..1932df4
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel2007.php
@@ -0,0 +1,2051 @@
+readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ $this->referenceHelper = PHPExcel_ReferenceHelper::getInstance();
+ }
+
+ /**
+ * Can the current PHPExcel_Reader_IReader read the file?
+ *
+ * @param string $pFilename
+ * @return boolean
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function canRead($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ // Check if zip class exists
+// if (!class_exists($zipClass, false)) {
+// throw new PHPExcel_Reader_Exception($zipClass . " library is not enabled");
+// }
+
+ $xl = false;
+ // Load file
+ $zip = new $zipClass;
+ if ($zip->open($pFilename) === true) {
+ // check if it is an OOXML archive
+ $rels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "_rels/.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ if ($rels !== false) {
+ foreach ($rels->Relationship as $rel) {
+ switch ($rel["Type"]) {
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
+ if (basename($rel["Target"]) == 'workbook.xml') {
+ $xl = true;
+ }
+ break;
+
+ }
+ }
+ }
+ $zip->close();
+ }
+
+ return $xl;
+ }
+
+
+ /**
+ * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetNames($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $worksheetNames = array();
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ $zip = new $zipClass;
+ $zip->open($pFilename);
+
+ // The files we're looking at here are small enough that simpleXML is more efficient than XMLReader
+ $rels = simplexml_load_string(
+ $this->securityScan($this->getFromZipArchive($zip, "_rels/.rels"), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions())
+ ); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ foreach ($rels->Relationship as $rel) {
+ switch ($rel["Type"]) {
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
+ $xmlWorkbook = simplexml_load_string(
+ $this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}"), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions())
+ ); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+
+ if ($xmlWorkbook->sheets) {
+ foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
+ // Check if sheet should be skipped
+ $worksheetNames[] = (string) $eleSheet["name"];
+ }
+ }
+ }
+ }
+
+ $zip->close();
+
+ return $worksheetNames;
+ }
+
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $worksheetInfo = array();
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ $zip = new $zipClass;
+ $zip->open($pFilename);
+
+ $rels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "_rels/.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ foreach ($rels->Relationship as $rel) {
+ if ($rel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument") {
+ $dir = dirname($rel["Target"]);
+ $relsWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ $relsWorkbook->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships");
+
+ $worksheets = array();
+ foreach ($relsWorkbook->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet") {
+ $worksheets[(string) $ele["Id"]] = $ele["Target"];
+ }
+ }
+
+ $xmlWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+ if ($xmlWorkbook->sheets) {
+ $dir = dirname($rel["Target"]);
+ foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
+ $tmpInfo = array(
+ 'worksheetName' => (string) $eleSheet["name"],
+ 'lastColumnLetter' => 'A',
+ 'lastColumnIndex' => 0,
+ 'totalRows' => 0,
+ 'totalColumns' => 0,
+ );
+
+ $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
+
+ $xml = new XMLReader();
+ $res = $xml->xml($this->securityScanFile('zip://'.PHPExcel_Shared_File::realpath($pFilename).'#'."$dir/$fileWorksheet"), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+ $xml->setParserProperty(2, true);
+
+ $currCells = 0;
+ while ($xml->read()) {
+ if ($xml->name == 'row' && $xml->nodeType == XMLReader::ELEMENT) {
+ $row = $xml->getAttribute('r');
+ $tmpInfo['totalRows'] = $row;
+ $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
+ $currCells = 0;
+ } elseif ($xml->name == 'c' && $xml->nodeType == XMLReader::ELEMENT) {
+ $currCells++;
+ }
+ }
+ $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
+ $xml->close();
+
+ $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
+ $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+
+ $worksheetInfo[] = $tmpInfo;
+ }
+ }
+ }
+ }
+
+ $zip->close();
+
+ return $worksheetInfo;
+ }
+
+ private static function castToBoolean($c)
+ {
+// echo 'Initial Cast to Boolean', PHP_EOL;
+ $value = isset($c->v) ? (string) $c->v : null;
+ if ($value == '0') {
+ return false;
+ } elseif ($value == '1') {
+ return true;
+ } else {
+ return (bool)$c->v;
+ }
+ return $value;
+ }
+
+ private static function castToError($c)
+ {
+// echo 'Initial Cast to Error', PHP_EOL;
+ return isset($c->v) ? (string) $c->v : null;
+ }
+
+ private static function castToString($c)
+ {
+// echo 'Initial Cast to String, PHP_EOL;
+ return isset($c->v) ? (string) $c->v : null;
+ }
+
+ private function castToFormula($c, $r, &$cellDataType, &$value, &$calculatedValue, &$sharedFormulas, $castBaseType)
+ {
+// echo 'Formula', PHP_EOL;
+// echo '$c->f is ', $c->f, PHP_EOL;
+ $cellDataType = 'f';
+ $value = "={$c->f}";
+ $calculatedValue = self::$castBaseType($c);
+
+ // Shared formula?
+ if (isset($c->f['t']) && strtolower((string)$c->f['t']) == 'shared') {
+// echo 'SHARED FORMULA', PHP_EOL;
+ $instance = (string)$c->f['si'];
+
+// echo 'Instance ID = ', $instance, PHP_EOL;
+//
+// echo 'Shared Formula Array:', PHP_EOL;
+// print_r($sharedFormulas);
+ if (!isset($sharedFormulas[(string)$c->f['si']])) {
+// echo 'SETTING NEW SHARED FORMULA', PHP_EOL;
+// echo 'Master is ', $r, PHP_EOL;
+// echo 'Formula is ', $value, PHP_EOL;
+ $sharedFormulas[$instance] = array('master' => $r, 'formula' => $value);
+// echo 'New Shared Formula Array:', PHP_EOL;
+// print_r($sharedFormulas);
+ } else {
+// echo 'GETTING SHARED FORMULA', PHP_EOL;
+// echo 'Master is ', $sharedFormulas[$instance]['master'], PHP_EOL;
+// echo 'Formula is ', $sharedFormulas[$instance]['formula'], PHP_EOL;
+ $master = PHPExcel_Cell::coordinateFromString($sharedFormulas[$instance]['master']);
+ $current = PHPExcel_Cell::coordinateFromString($r);
+
+ $difference = array(0, 0);
+ $difference[0] = PHPExcel_Cell::columnIndexFromString($current[0]) - PHPExcel_Cell::columnIndexFromString($master[0]);
+ $difference[1] = $current[1] - $master[1];
+
+ $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]);
+// echo 'Adjusted Formula is ', $value, PHP_EOL;
+ }
+ }
+ }
+
+
+ private function getFromZipArchive($archive, $fileName = '')
+ {
+ // Root-relative paths
+ if (strpos($fileName, '//') !== false) {
+ $fileName = substr($fileName, strpos($fileName, '//') + 1);
+ }
+ $fileName = PHPExcel_Shared_File::realpath($fileName);
+
+ // Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
+ // so we need to load case-insensitively from the zip file
+
+ // Apache POI fixes
+ $contents = $archive->getFromIndex(
+ $archive->locateName($fileName, ZIPARCHIVE::FL_NOCASE)
+ );
+ if ($contents === false) {
+ $contents = $archive->getFromIndex(
+ $archive->locateName(substr($fileName, 1), ZIPARCHIVE::FL_NOCASE)
+ );
+ }
+
+ return $contents;
+ }
+
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ // Initialisations
+ $excel = new PHPExcel;
+ $excel->removeSheetByIndex(0);
+ if (!$this->readDataOnly) {
+ $excel->removeCellStyleXfByIndex(0); // remove the default style
+ $excel->removeCellXfByIndex(0); // remove the default style
+ }
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ $zip = new $zipClass;
+ $zip->open($pFilename);
+
+ // Read the theme first, because we need the colour scheme when reading the styles
+ $wbRels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "xl/_rels/workbook.xml.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ foreach ($wbRels->Relationship as $rel) {
+ switch ($rel["Type"]) {
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme":
+ $themeOrderArray = array('lt1', 'dk1', 'lt2', 'dk2');
+ $themeOrderAdditional = count($themeOrderArray);
+
+ $xmlTheme = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "xl/{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ if (is_object($xmlTheme)) {
+ $xmlThemeName = $xmlTheme->attributes();
+ $xmlTheme = $xmlTheme->children("http://schemas.openxmlformats.org/drawingml/2006/main");
+ $themeName = (string)$xmlThemeName['name'];
+
+ $colourScheme = $xmlTheme->themeElements->clrScheme->attributes();
+ $colourSchemeName = (string)$colourScheme['name'];
+ $colourScheme = $xmlTheme->themeElements->clrScheme->children("http://schemas.openxmlformats.org/drawingml/2006/main");
+
+ $themeColours = array();
+ foreach ($colourScheme as $k => $xmlColour) {
+ $themePos = array_search($k, $themeOrderArray);
+ if ($themePos === false) {
+ $themePos = $themeOrderAdditional++;
+ }
+ if (isset($xmlColour->sysClr)) {
+ $xmlColourData = $xmlColour->sysClr->attributes();
+ $themeColours[$themePos] = $xmlColourData['lastClr'];
+ } elseif (isset($xmlColour->srgbClr)) {
+ $xmlColourData = $xmlColour->srgbClr->attributes();
+ $themeColours[$themePos] = $xmlColourData['val'];
+ }
+ }
+ self::$theme = new PHPExcel_Reader_Excel2007_Theme($themeName, $colourSchemeName, $themeColours);
+ }
+ break;
+ }
+ }
+
+ $rels = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "_rels/.rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ foreach ($rels->Relationship as $rel) {
+ switch ($rel["Type"]) {
+ case "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties":
+ $xmlCore = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ if (is_object($xmlCore)) {
+ $xmlCore->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/");
+ $xmlCore->registerXPathNamespace("dcterms", "http://purl.org/dc/terms/");
+ $xmlCore->registerXPathNamespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
+ $docProps = $excel->getProperties();
+ $docProps->setCreator((string) self::getArrayItem($xmlCore->xpath("dc:creator")));
+ $docProps->setLastModifiedBy((string) self::getArrayItem($xmlCore->xpath("cp:lastModifiedBy")));
+ $docProps->setCreated(strtotime(self::getArrayItem($xmlCore->xpath("dcterms:created")))); //! respect xsi:type
+ $docProps->setModified(strtotime(self::getArrayItem($xmlCore->xpath("dcterms:modified")))); //! respect xsi:type
+ $docProps->setTitle((string) self::getArrayItem($xmlCore->xpath("dc:title")));
+ $docProps->setDescription((string) self::getArrayItem($xmlCore->xpath("dc:description")));
+ $docProps->setSubject((string) self::getArrayItem($xmlCore->xpath("dc:subject")));
+ $docProps->setKeywords((string) self::getArrayItem($xmlCore->xpath("cp:keywords")));
+ $docProps->setCategory((string) self::getArrayItem($xmlCore->xpath("cp:category")));
+ }
+ break;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties":
+ $xmlCore = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ if (is_object($xmlCore)) {
+ $docProps = $excel->getProperties();
+ if (isset($xmlCore->Company)) {
+ $docProps->setCompany((string) $xmlCore->Company);
+ }
+ if (isset($xmlCore->Manager)) {
+ $docProps->setManager((string) $xmlCore->Manager);
+ }
+ }
+ break;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties":
+ $xmlCore = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ if (is_object($xmlCore)) {
+ $docProps = $excel->getProperties();
+ foreach ($xmlCore as $xmlProperty) {
+ $cellDataOfficeAttributes = $xmlProperty->attributes();
+ if (isset($cellDataOfficeAttributes['name'])) {
+ $propertyName = (string) $cellDataOfficeAttributes['name'];
+ $cellDataOfficeChildren = $xmlProperty->children('http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
+ $attributeType = $cellDataOfficeChildren->getName();
+ $attributeValue = (string) $cellDataOfficeChildren->{$attributeType};
+ $attributeValue = PHPExcel_DocumentProperties::convertProperty($attributeValue, $attributeType);
+ $attributeType = PHPExcel_DocumentProperties::convertPropertyType($attributeType);
+ $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
+ }
+ }
+ }
+ break;
+ //Ribbon
+ case "http://schemas.microsoft.com/office/2006/relationships/ui/extensibility":
+ $customUI = $rel['Target'];
+ if (!is_null($customUI)) {
+ $this->readRibbon($excel, $customUI, $zip);
+ }
+ break;
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
+ $dir = dirname($rel["Target"]);
+ $relsWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ $relsWorkbook->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships");
+
+ $sharedStrings = array();
+ $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings']"));
+ $xmlStrings = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+ if (isset($xmlStrings) && isset($xmlStrings->si)) {
+ foreach ($xmlStrings->si as $val) {
+ if (isset($val->t)) {
+ $sharedStrings[] = PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $val->t);
+ } elseif (isset($val->r)) {
+ $sharedStrings[] = $this->parseRichText($val);
+ }
+ }
+ }
+
+ $worksheets = array();
+ $macros = $customUI = null;
+ foreach ($relsWorkbook->Relationship as $ele) {
+ switch ($ele['Type']) {
+ case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet":
+ $worksheets[(string) $ele["Id"]] = $ele["Target"];
+ break;
+ // a vbaProject ? (: some macros)
+ case "http://schemas.microsoft.com/office/2006/relationships/vbaProject":
+ $macros = $ele["Target"];
+ break;
+ }
+ }
+
+ if (!is_null($macros)) {
+ $macrosCode = $this->getFromZipArchive($zip, 'xl/vbaProject.bin');//vbaProject.bin always in 'xl' dir and always named vbaProject.bin
+ if ($macrosCode !== false) {
+ $excel->setMacrosCode($macrosCode);
+ $excel->setHasMacros(true);
+ //short-circuit : not reading vbaProject.bin.rel to get Signature =>allways vbaProjectSignature.bin in 'xl' dir
+ $Certificate = $this->getFromZipArchive($zip, 'xl/vbaProjectSignature.bin');
+ if ($Certificate !== false) {
+ $excel->setMacrosCertificate($Certificate);
+ }
+ }
+ }
+ $styles = array();
+ $cellStyles = array();
+ $xpath = self::getArrayItem($relsWorkbook->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']"));
+ $xmlStyles = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/$xpath[Target]")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+
+ $numFmts = null;
+ if ($xmlStyles && $xmlStyles->numFmts[0]) {
+ $numFmts = $xmlStyles->numFmts[0];
+ }
+ if (isset($numFmts) && ($numFmts !== null)) {
+ $numFmts->registerXPathNamespace("sml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+ }
+ if (!$this->readDataOnly && $xmlStyles) {
+ foreach ($xmlStyles->cellXfs->xf as $xf) {
+ $numFmt = PHPExcel_Style_NumberFormat::FORMAT_GENERAL;
+ if ($xf["numFmtId"]) {
+ if (isset($numFmts)) {
+ $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
+
+ if (isset($tmpNumFmt["formatCode"])) {
+ $numFmt = (string) $tmpNumFmt["formatCode"];
+ }
+ }
+
+ // We shouldn't override any of the built-in MS Excel values (values below id 164)
+ // But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used
+ // So we make allowance for them rather than lose formatting masks
+ if ((int)$xf["numFmtId"] < 164 && PHPExcel_Style_NumberFormat::builtInFormatCode((int)$xf["numFmtId"]) !== '') {
+ $numFmt = PHPExcel_Style_NumberFormat::builtInFormatCode((int)$xf["numFmtId"]);
+ }
+ }
+ $quotePrefix = false;
+ if (isset($xf["quotePrefix"])) {
+ $quotePrefix = (boolean) $xf["quotePrefix"];
+ }
+
+ $style = (object) array(
+ "numFmt" => $numFmt,
+ "font" => $xmlStyles->fonts->font[intval($xf["fontId"])],
+ "fill" => $xmlStyles->fills->fill[intval($xf["fillId"])],
+ "border" => $xmlStyles->borders->border[intval($xf["borderId"])],
+ "alignment" => $xf->alignment,
+ "protection" => $xf->protection,
+ "quotePrefix" => $quotePrefix,
+ );
+ $styles[] = $style;
+
+ // add style to cellXf collection
+ $objStyle = new PHPExcel_Style;
+ self::readStyle($objStyle, $style);
+ $excel->addCellXf($objStyle);
+ }
+
+ foreach ($xmlStyles->cellStyleXfs->xf as $xf) {
+ $numFmt = PHPExcel_Style_NumberFormat::FORMAT_GENERAL;
+ if ($numFmts && $xf["numFmtId"]) {
+ $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]"));
+ if (isset($tmpNumFmt["formatCode"])) {
+ $numFmt = (string) $tmpNumFmt["formatCode"];
+ } elseif ((int)$xf["numFmtId"] < 165) {
+ $numFmt = PHPExcel_Style_NumberFormat::builtInFormatCode((int)$xf["numFmtId"]);
+ }
+ }
+
+ $cellStyle = (object) array(
+ "numFmt" => $numFmt,
+ "font" => $xmlStyles->fonts->font[intval($xf["fontId"])],
+ "fill" => $xmlStyles->fills->fill[intval($xf["fillId"])],
+ "border" => $xmlStyles->borders->border[intval($xf["borderId"])],
+ "alignment" => $xf->alignment,
+ "protection" => $xf->protection,
+ "quotePrefix" => $quotePrefix,
+ );
+ $cellStyles[] = $cellStyle;
+
+ // add style to cellStyleXf collection
+ $objStyle = new PHPExcel_Style;
+ self::readStyle($objStyle, $cellStyle);
+ $excel->addCellStyleXf($objStyle);
+ }
+ }
+
+ $dxfs = array();
+ if (!$this->readDataOnly && $xmlStyles) {
+ // Conditional Styles
+ if ($xmlStyles->dxfs) {
+ foreach ($xmlStyles->dxfs->dxf as $dxf) {
+ $style = new PHPExcel_Style(false, true);
+ self::readStyle($style, $dxf);
+ $dxfs[] = $style;
+ }
+ }
+ // Cell Styles
+ if ($xmlStyles->cellStyles) {
+ foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
+ if (intval($cellStyle['builtinId']) == 0) {
+ if (isset($cellStyles[intval($cellStyle['xfId'])])) {
+ // Set default style
+ $style = new PHPExcel_Style;
+ self::readStyle($style, $cellStyles[intval($cellStyle['xfId'])]);
+
+ // normal style, currently not using it for anything
+ }
+ }
+ }
+ }
+ }
+
+ $xmlWorkbook = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "{$rel['Target']}")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+
+ // Set base date
+ if ($xmlWorkbook->workbookPr) {
+ PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
+ if (isset($xmlWorkbook->workbookPr['date1904'])) {
+ if (self::boolean((string) $xmlWorkbook->workbookPr['date1904'])) {
+ PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
+ }
+ }
+ }
+
+ $sheetId = 0; // keep track of new sheet id in final workbook
+ $oldSheetId = -1; // keep track of old sheet id in final workbook
+ $countSkippedSheets = 0; // keep track of number of skipped sheets
+ $mapSheetId = array(); // mapping of sheet ids from old to new
+
+ $charts = $chartDetails = array();
+
+ if ($xmlWorkbook->sheets) {
+ foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
+ ++$oldSheetId;
+
+ // Check if sheet should be skipped
+ if (isset($this->loadSheetsOnly) && !in_array((string) $eleSheet["name"], $this->loadSheetsOnly)) {
+ ++$countSkippedSheets;
+ $mapSheetId[$oldSheetId] = null;
+ continue;
+ }
+
+ // Map old sheet id in original workbook to new sheet id.
+ // They will differ if loadSheetsOnly() is being used
+ $mapSheetId[$oldSheetId] = $oldSheetId - $countSkippedSheets;
+
+ // Load sheet
+ $docSheet = $excel->createSheet();
+ // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
+ // references in formula cells... during the load, all formulae should be correct,
+ // and we're simply bringing the worksheet name in line with the formula, not the
+ // reverse
+ $docSheet->setTitle((string) $eleSheet["name"], false);
+ $fileWorksheet = $worksheets[(string) self::getArrayItem($eleSheet->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
+ $xmlSheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "$dir/$fileWorksheet")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+
+ $sharedFormulas = array();
+
+ if (isset($eleSheet["state"]) && (string) $eleSheet["state"] != '') {
+ $docSheet->setSheetState((string) $eleSheet["state"]);
+ }
+
+ if (isset($xmlSheet->sheetViews) && isset($xmlSheet->sheetViews->sheetView)) {
+ if (isset($xmlSheet->sheetViews->sheetView['zoomScale'])) {
+ $docSheet->getSheetView()->setZoomScale(intval($xmlSheet->sheetViews->sheetView['zoomScale']));
+ }
+ if (isset($xmlSheet->sheetViews->sheetView['zoomScaleNormal'])) {
+ $docSheet->getSheetView()->setZoomScaleNormal(intval($xmlSheet->sheetViews->sheetView['zoomScaleNormal']));
+ }
+ if (isset($xmlSheet->sheetViews->sheetView['view'])) {
+ $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
+ }
+ if (isset($xmlSheet->sheetViews->sheetView['showGridLines'])) {
+ $docSheet->setShowGridLines(self::boolean((string)$xmlSheet->sheetViews->sheetView['showGridLines']));
+ }
+ if (isset($xmlSheet->sheetViews->sheetView['showRowColHeaders'])) {
+ $docSheet->setShowRowColHeaders(self::boolean((string)$xmlSheet->sheetViews->sheetView['showRowColHeaders']));
+ }
+ if (isset($xmlSheet->sheetViews->sheetView['rightToLeft'])) {
+ $docSheet->setRightToLeft(self::boolean((string)$xmlSheet->sheetViews->sheetView['rightToLeft']));
+ }
+ if (isset($xmlSheet->sheetViews->sheetView->pane)) {
+ if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
+ $docSheet->freezePane((string)$xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
+ } else {
+ $xSplit = 0;
+ $ySplit = 0;
+
+ if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
+ $xSplit = 1 + intval($xmlSheet->sheetViews->sheetView->pane['xSplit']);
+ }
+
+ if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
+ $ySplit = 1 + intval($xmlSheet->sheetViews->sheetView->pane['ySplit']);
+ }
+
+ $docSheet->freezePaneByColumnAndRow($xSplit, $ySplit);
+ }
+ }
+
+ if (isset($xmlSheet->sheetViews->sheetView->selection)) {
+ if (isset($xmlSheet->sheetViews->sheetView->selection['sqref'])) {
+ $sqref = (string)$xmlSheet->sheetViews->sheetView->selection['sqref'];
+ $sqref = explode(' ', $sqref);
+ $sqref = $sqref[0];
+ $docSheet->setSelectedCells($sqref);
+ }
+ }
+ }
+
+ if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->tabColor)) {
+ if (isset($xmlSheet->sheetPr->tabColor['rgb'])) {
+ $docSheet->getTabColor()->setARGB((string)$xmlSheet->sheetPr->tabColor['rgb']);
+ }
+ }
+ if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr['codeName'])) {
+ $docSheet->setCodeName((string) $xmlSheet->sheetPr['codeName']);
+ }
+ if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->outlinePr)) {
+ if (isset($xmlSheet->sheetPr->outlinePr['summaryRight']) &&
+ !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryRight'])) {
+ $docSheet->setShowSummaryRight(false);
+ } else {
+ $docSheet->setShowSummaryRight(true);
+ }
+
+ if (isset($xmlSheet->sheetPr->outlinePr['summaryBelow']) &&
+ !self::boolean((string) $xmlSheet->sheetPr->outlinePr['summaryBelow'])) {
+ $docSheet->setShowSummaryBelow(false);
+ } else {
+ $docSheet->setShowSummaryBelow(true);
+ }
+ }
+
+ if (isset($xmlSheet->sheetPr) && isset($xmlSheet->sheetPr->pageSetUpPr)) {
+ if (isset($xmlSheet->sheetPr->pageSetUpPr['fitToPage']) &&
+ !self::boolean((string) $xmlSheet->sheetPr->pageSetUpPr['fitToPage'])) {
+ $docSheet->getPageSetup()->setFitToPage(false);
+ } else {
+ $docSheet->getPageSetup()->setFitToPage(true);
+ }
+ }
+
+ if (isset($xmlSheet->sheetFormatPr)) {
+ if (isset($xmlSheet->sheetFormatPr['customHeight']) &&
+ self::boolean((string) $xmlSheet->sheetFormatPr['customHeight']) &&
+ isset($xmlSheet->sheetFormatPr['defaultRowHeight'])) {
+ $docSheet->getDefaultRowDimension()->setRowHeight((float)$xmlSheet->sheetFormatPr['defaultRowHeight']);
+ }
+ if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
+ $docSheet->getDefaultColumnDimension()->setWidth((float)$xmlSheet->sheetFormatPr['defaultColWidth']);
+ }
+ if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
+ ((string)$xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
+ $docSheet->getDefaultRowDimension()->setZeroHeight(true);
+ }
+ }
+
+ if (isset($xmlSheet->cols) && !$this->readDataOnly) {
+ foreach ($xmlSheet->cols->col as $col) {
+ for ($i = intval($col["min"]) - 1; $i < intval($col["max"]); ++$i) {
+ if ($col["style"] && !$this->readDataOnly) {
+ $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setXfIndex(intval($col["style"]));
+ }
+ if (self::boolean($col["bestFit"])) {
+ //$docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setAutoSize(true);
+ }
+ if (self::boolean($col["hidden"])) {
+ // echo PHPExcel_Cell::stringFromColumnIndex($i), ': HIDDEN COLUMN',PHP_EOL;
+ $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setVisible(false);
+ }
+ if (self::boolean($col["collapsed"])) {
+ $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setCollapsed(true);
+ }
+ if ($col["outlineLevel"] > 0) {
+ $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setOutlineLevel(intval($col["outlineLevel"]));
+ }
+ $docSheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setWidth(floatval($col["width"]));
+
+ if (intval($col["max"]) == 16384) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (isset($xmlSheet->printOptions) && !$this->readDataOnly) {
+ if (self::boolean((string) $xmlSheet->printOptions['gridLinesSet'])) {
+ $docSheet->setShowGridlines(true);
+ }
+ if (self::boolean((string) $xmlSheet->printOptions['gridLines'])) {
+ $docSheet->setPrintGridlines(true);
+ }
+ if (self::boolean((string) $xmlSheet->printOptions['horizontalCentered'])) {
+ $docSheet->getPageSetup()->setHorizontalCentered(true);
+ }
+ if (self::boolean((string) $xmlSheet->printOptions['verticalCentered'])) {
+ $docSheet->getPageSetup()->setVerticalCentered(true);
+ }
+ }
+
+ if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
+ foreach ($xmlSheet->sheetData->row as $row) {
+ if ($row["ht"] && !$this->readDataOnly) {
+ $docSheet->getRowDimension(intval($row["r"]))->setRowHeight(floatval($row["ht"]));
+ }
+ if (self::boolean($row["hidden"]) && !$this->readDataOnly) {
+ $docSheet->getRowDimension(intval($row["r"]))->setVisible(false);
+ }
+ if (self::boolean($row["collapsed"])) {
+ $docSheet->getRowDimension(intval($row["r"]))->setCollapsed(true);
+ }
+ if ($row["outlineLevel"] > 0) {
+ $docSheet->getRowDimension(intval($row["r"]))->setOutlineLevel(intval($row["outlineLevel"]));
+ }
+ if ($row["s"] && !$this->readDataOnly) {
+ $docSheet->getRowDimension(intval($row["r"]))->setXfIndex(intval($row["s"]));
+ }
+
+ foreach ($row->c as $c) {
+ $r = (string) $c["r"];
+ $cellDataType = (string) $c["t"];
+ $value = null;
+ $calculatedValue = null;
+
+ // Read cell?
+ if ($this->getReadFilter() !== null) {
+ $coordinates = PHPExcel_Cell::coordinateFromString($r);
+
+ if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
+ continue;
+ }
+ }
+
+ // echo 'Reading cell ', $coordinates[0], $coordinates[1], PHP_EOL;
+ // print_r($c);
+ // echo PHP_EOL;
+ // echo 'Cell Data Type is ', $cellDataType, ': ';
+ //
+ // Read cell!
+ switch ($cellDataType) {
+ case "s":
+ // echo 'String', PHP_EOL;
+ if ((string)$c->v != '') {
+ $value = $sharedStrings[intval($c->v)];
+
+ if ($value instanceof PHPExcel_RichText) {
+ $value = clone $value;
+ }
+ } else {
+ $value = '';
+ }
+ break;
+ case "b":
+ // echo 'Boolean', PHP_EOL;
+ if (!isset($c->f)) {
+ $value = self::castToBoolean($c);
+ } else {
+ // Formula
+ $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToBoolean');
+ if (isset($c->f['t'])) {
+ $att = array();
+ $att = $c->f;
+ $docSheet->getCell($r)->setFormulaAttributes($att);
+ }
+ // echo '$calculatedValue = ', $calculatedValue, PHP_EOL;
+ }
+ break;
+ case "inlineStr":
+// echo 'Inline String', PHP_EOL;
+ if (isset($c->f)) {
+ $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
+ } else {
+ $value = $this->parseRichText($c->is);
+ }
+ break;
+ case "e":
+ // echo 'Error', PHP_EOL;
+ if (!isset($c->f)) {
+ $value = self::castToError($c);
+ } else {
+ // Formula
+ $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToError');
+ // echo '$calculatedValue = ', $calculatedValue, PHP_EOL;
+ }
+ break;
+ default:
+// echo 'Default', PHP_EOL;
+ if (!isset($c->f)) {
+ // echo 'Not a Formula', PHP_EOL;
+ $value = self::castToString($c);
+ } else {
+ // echo 'Treat as Formula', PHP_EOL;
+ // Formula
+ $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString');
+ // echo '$calculatedValue = ', $calculatedValue, PHP_EOL;
+ }
+ break;
+ }
+ // echo 'Value is ', $value, PHP_EOL;
+
+ // Check for numeric values
+ if (is_numeric($value) && $cellDataType != 's') {
+ if ($value == (int)$value) {
+ $value = (int)$value;
+ } elseif ($value == (float)$value) {
+ $value = (float)$value;
+ } elseif ($value == (double)$value) {
+ $value = (double)$value;
+ }
+ }
+
+ // Rich text?
+ if ($value instanceof PHPExcel_RichText && $this->readDataOnly) {
+ $value = $value->getPlainText();
+ }
+
+ $cell = $docSheet->getCell($r);
+ // Assign value
+ if ($cellDataType != '') {
+ $cell->setValueExplicit($value, $cellDataType);
+ } else {
+ $cell->setValue($value);
+ }
+ if ($calculatedValue !== null) {
+ $cell->setCalculatedValue($calculatedValue);
+ }
+
+ // Style information?
+ if ($c["s"] && !$this->readDataOnly) {
+ // no style index means 0, it seems
+ $cell->setXfIndex(isset($styles[intval($c["s"])]) ?
+ intval($c["s"]) : 0);
+ }
+ }
+ }
+ }
+
+ $conditionals = array();
+ if (!$this->readDataOnly && $xmlSheet && $xmlSheet->conditionalFormatting) {
+ foreach ($xmlSheet->conditionalFormatting as $conditional) {
+ foreach ($conditional->cfRule as $cfRule) {
+ if (((string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_NONE || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_CELLIS || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_CONTAINSTEXT || (string)$cfRule["type"] == PHPExcel_Style_Conditional::CONDITION_EXPRESSION) && isset($dxfs[intval($cfRule["dxfId"])])) {
+ $conditionals[(string) $conditional["sqref"]][intval($cfRule["priority"])] = $cfRule;
+ }
+ }
+ }
+
+ foreach ($conditionals as $ref => $cfRules) {
+ ksort($cfRules);
+ $conditionalStyles = array();
+ foreach ($cfRules as $cfRule) {
+ $objConditional = new PHPExcel_Style_Conditional();
+ $objConditional->setConditionType((string)$cfRule["type"]);
+ $objConditional->setOperatorType((string)$cfRule["operator"]);
+
+ if ((string)$cfRule["text"] != '') {
+ $objConditional->setText((string)$cfRule["text"]);
+ }
+
+ if (count($cfRule->formula) > 1) {
+ foreach ($cfRule->formula as $formula) {
+ $objConditional->addCondition((string)$formula);
+ }
+ } else {
+ $objConditional->addCondition((string)$cfRule->formula);
+ }
+ $objConditional->setStyle(clone $dxfs[intval($cfRule["dxfId"])]);
+ $conditionalStyles[] = $objConditional;
+ }
+
+ // Extract all cell references in $ref
+ $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref)));
+ foreach ($cellBlocks as $cellBlock) {
+ $docSheet->getStyle($cellBlock)->setConditionalStyles($conditionalStyles);
+ }
+ }
+ }
+
+ $aKeys = array("sheet", "objects", "scenarios", "formatCells", "formatColumns", "formatRows", "insertColumns", "insertRows", "insertHyperlinks", "deleteColumns", "deleteRows", "selectLockedCells", "sort", "autoFilter", "pivotTables", "selectUnlockedCells");
+ if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
+ foreach ($aKeys as $key) {
+ $method = "set" . ucfirst($key);
+ $docSheet->getProtection()->$method(self::boolean((string) $xmlSheet->sheetProtection[$key]));
+ }
+ }
+
+ if (!$this->readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
+ $docSheet->getProtection()->setPassword((string) $xmlSheet->sheetProtection["password"], true);
+ if ($xmlSheet->protectedRanges->protectedRange) {
+ foreach ($xmlSheet->protectedRanges->protectedRange as $protectedRange) {
+ $docSheet->protectCells((string) $protectedRange["sqref"], (string) $protectedRange["password"], true);
+ }
+ }
+ }
+
+ if ($xmlSheet && $xmlSheet->autoFilter && !$this->readDataOnly) {
+ $autoFilterRange = (string) $xmlSheet->autoFilter["ref"];
+ if (strpos($autoFilterRange, ':') !== false) {
+ $autoFilter = $docSheet->getAutoFilter();
+ $autoFilter->setRange($autoFilterRange);
+
+ foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
+ $column = $autoFilter->getColumnByOffset((integer) $filterColumn["colId"]);
+ // Check for standard filters
+ if ($filterColumn->filters) {
+ $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_FILTER);
+ $filters = $filterColumn->filters;
+ if ((isset($filters["blank"])) && ($filters["blank"] == 1)) {
+ // Operator is undefined, but always treated as EQUAL
+ $column->createRule()->setRule(null, '')->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER);
+ }
+ // Standard filters are always an OR join, so no join rule needs to be set
+ // Entries can be either filter elements
+ foreach ($filters->filter as $filterRule) {
+ // Operator is undefined, but always treated as EQUAL
+ $column->createRule()->setRule(null, (string) $filterRule["val"])->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER);
+ }
+ // Or Date Group elements
+ foreach ($filters->dateGroupItem as $dateGroupItem) {
+ $column->createRule()->setRule(
+ // Operator is undefined, but always treated as EQUAL
+ null,
+ array(
+ 'year' => (string) $dateGroupItem["year"],
+ 'month' => (string) $dateGroupItem["month"],
+ 'day' => (string) $dateGroupItem["day"],
+ 'hour' => (string) $dateGroupItem["hour"],
+ 'minute' => (string) $dateGroupItem["minute"],
+ 'second' => (string) $dateGroupItem["second"],
+ ),
+ (string) $dateGroupItem["dateTimeGrouping"]
+ )
+ ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DATEGROUP);
+ }
+ }
+ // Check for custom filters
+ if ($filterColumn->customFilters) {
+ $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
+ $customFilters = $filterColumn->customFilters;
+ // Custom filters can an AND or an OR join;
+ // and there should only ever be one or two entries
+ if ((isset($customFilters["and"])) && ($customFilters["and"] == 1)) {
+ $column->setJoin(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_COLUMN_JOIN_AND);
+ }
+ foreach ($customFilters->customFilter as $filterRule) {
+ $column->createRule()->setRule(
+ (string) $filterRule["operator"],
+ (string) $filterRule["val"]
+ )
+ ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
+ }
+ }
+ // Check for dynamic filters
+ if ($filterColumn->dynamicFilter) {
+ $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
+ // We should only ever have one dynamic filter
+ foreach ($filterColumn->dynamicFilter as $filterRule) {
+ $column->createRule()->setRule(
+ // Operator is undefined, but always treated as EQUAL
+ null,
+ (string) $filterRule["val"],
+ (string) $filterRule["type"]
+ )
+ ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
+ if (isset($filterRule["val"])) {
+ $column->setAttribute('val', (string) $filterRule["val"]);
+ }
+ if (isset($filterRule["maxVal"])) {
+ $column->setAttribute('maxVal', (string) $filterRule["maxVal"]);
+ }
+ }
+ }
+ // Check for dynamic filters
+ if ($filterColumn->top10) {
+ $column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
+ // We should only ever have one top10 filter
+ foreach ($filterColumn->top10 as $filterRule) {
+ $column->createRule()->setRule(
+ (((isset($filterRule["percent"])) && ($filterRule["percent"] == 1))
+ ? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
+ : PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
+ ),
+ (string) $filterRule["val"],
+ (((isset($filterRule["top"])) && ($filterRule["top"] == 1))
+ ? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
+ : PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
+ )
+ )
+ ->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
+ }
+ }
+ }
+ }
+ }
+
+ if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->readDataOnly) {
+ foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
+ $mergeRef = (string) $mergeCell["ref"];
+ if (strpos($mergeRef, ':') !== false) {
+ $docSheet->mergeCells((string) $mergeCell["ref"]);
+ }
+ }
+ }
+
+ if ($xmlSheet && $xmlSheet->pageMargins && !$this->readDataOnly) {
+ $docPageMargins = $docSheet->getPageMargins();
+ $docPageMargins->setLeft(floatval($xmlSheet->pageMargins["left"]));
+ $docPageMargins->setRight(floatval($xmlSheet->pageMargins["right"]));
+ $docPageMargins->setTop(floatval($xmlSheet->pageMargins["top"]));
+ $docPageMargins->setBottom(floatval($xmlSheet->pageMargins["bottom"]));
+ $docPageMargins->setHeader(floatval($xmlSheet->pageMargins["header"]));
+ $docPageMargins->setFooter(floatval($xmlSheet->pageMargins["footer"]));
+ }
+
+ if ($xmlSheet && $xmlSheet->pageSetup && !$this->readDataOnly) {
+ $docPageSetup = $docSheet->getPageSetup();
+
+ if (isset($xmlSheet->pageSetup["orientation"])) {
+ $docPageSetup->setOrientation((string) $xmlSheet->pageSetup["orientation"]);
+ }
+ if (isset($xmlSheet->pageSetup["paperSize"])) {
+ $docPageSetup->setPaperSize(intval($xmlSheet->pageSetup["paperSize"]));
+ }
+ if (isset($xmlSheet->pageSetup["scale"])) {
+ $docPageSetup->setScale(intval($xmlSheet->pageSetup["scale"]), false);
+ }
+ if (isset($xmlSheet->pageSetup["fitToHeight"]) && intval($xmlSheet->pageSetup["fitToHeight"]) >= 0) {
+ $docPageSetup->setFitToHeight(intval($xmlSheet->pageSetup["fitToHeight"]), false);
+ }
+ if (isset($xmlSheet->pageSetup["fitToWidth"]) && intval($xmlSheet->pageSetup["fitToWidth"]) >= 0) {
+ $docPageSetup->setFitToWidth(intval($xmlSheet->pageSetup["fitToWidth"]), false);
+ }
+ if (isset($xmlSheet->pageSetup["firstPageNumber"]) && isset($xmlSheet->pageSetup["useFirstPageNumber"]) &&
+ self::boolean((string) $xmlSheet->pageSetup["useFirstPageNumber"])) {
+ $docPageSetup->setFirstPageNumber(intval($xmlSheet->pageSetup["firstPageNumber"]));
+ }
+ }
+
+ if ($xmlSheet && $xmlSheet->headerFooter && !$this->readDataOnly) {
+ $docHeaderFooter = $docSheet->getHeaderFooter();
+
+ if (isset($xmlSheet->headerFooter["differentOddEven"]) &&
+ self::boolean((string)$xmlSheet->headerFooter["differentOddEven"])) {
+ $docHeaderFooter->setDifferentOddEven(true);
+ } else {
+ $docHeaderFooter->setDifferentOddEven(false);
+ }
+ if (isset($xmlSheet->headerFooter["differentFirst"]) &&
+ self::boolean((string)$xmlSheet->headerFooter["differentFirst"])) {
+ $docHeaderFooter->setDifferentFirst(true);
+ } else {
+ $docHeaderFooter->setDifferentFirst(false);
+ }
+ if (isset($xmlSheet->headerFooter["scaleWithDoc"]) &&
+ !self::boolean((string)$xmlSheet->headerFooter["scaleWithDoc"])) {
+ $docHeaderFooter->setScaleWithDocument(false);
+ } else {
+ $docHeaderFooter->setScaleWithDocument(true);
+ }
+ if (isset($xmlSheet->headerFooter["alignWithMargins"]) &&
+ !self::boolean((string)$xmlSheet->headerFooter["alignWithMargins"])) {
+ $docHeaderFooter->setAlignWithMargins(false);
+ } else {
+ $docHeaderFooter->setAlignWithMargins(true);
+ }
+
+ $docHeaderFooter->setOddHeader((string) $xmlSheet->headerFooter->oddHeader);
+ $docHeaderFooter->setOddFooter((string) $xmlSheet->headerFooter->oddFooter);
+ $docHeaderFooter->setEvenHeader((string) $xmlSheet->headerFooter->evenHeader);
+ $docHeaderFooter->setEvenFooter((string) $xmlSheet->headerFooter->evenFooter);
+ $docHeaderFooter->setFirstHeader((string) $xmlSheet->headerFooter->firstHeader);
+ $docHeaderFooter->setFirstFooter((string) $xmlSheet->headerFooter->firstFooter);
+ }
+
+ if ($xmlSheet && $xmlSheet->rowBreaks && $xmlSheet->rowBreaks->brk && !$this->readDataOnly) {
+ foreach ($xmlSheet->rowBreaks->brk as $brk) {
+ if ($brk["man"]) {
+ $docSheet->setBreak("A$brk[id]", PHPExcel_Worksheet::BREAK_ROW);
+ }
+ }
+ }
+ if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->readDataOnly) {
+ foreach ($xmlSheet->colBreaks->brk as $brk) {
+ if ($brk["man"]) {
+ $docSheet->setBreak(PHPExcel_Cell::stringFromColumnIndex((string) $brk["id"]) . "1", PHPExcel_Worksheet::BREAK_COLUMN);
+ }
+ }
+ }
+
+ if ($xmlSheet && $xmlSheet->dataValidations && !$this->readDataOnly) {
+ foreach ($xmlSheet->dataValidations->dataValidation as $dataValidation) {
+ // Uppercase coordinate
+ $range = strtoupper($dataValidation["sqref"]);
+ $rangeSet = explode(' ', $range);
+ foreach ($rangeSet as $range) {
+ $stRange = $docSheet->shrinkRangeToFit($range);
+
+ // Extract all cell references in $range
+ foreach (PHPExcel_Cell::extractAllCellReferencesInRange($stRange) as $reference) {
+ // Create validation
+ $docValidation = $docSheet->getCell($reference)->getDataValidation();
+ $docValidation->setType((string) $dataValidation["type"]);
+ $docValidation->setErrorStyle((string) $dataValidation["errorStyle"]);
+ $docValidation->setOperator((string) $dataValidation["operator"]);
+ $docValidation->setAllowBlank($dataValidation["allowBlank"] != 0);
+ $docValidation->setShowDropDown($dataValidation["showDropDown"] == 0);
+ $docValidation->setShowInputMessage($dataValidation["showInputMessage"] != 0);
+ $docValidation->setShowErrorMessage($dataValidation["showErrorMessage"] != 0);
+ $docValidation->setErrorTitle((string) $dataValidation["errorTitle"]);
+ $docValidation->setError((string) $dataValidation["error"]);
+ $docValidation->setPromptTitle((string) $dataValidation["promptTitle"]);
+ $docValidation->setPrompt((string) $dataValidation["prompt"]);
+ $docValidation->setFormula1((string) $dataValidation->formula1);
+ $docValidation->setFormula2((string) $dataValidation->formula2);
+ }
+ }
+ }
+ }
+
+ // Add hyperlinks
+ $hyperlinks = array();
+ if (!$this->readDataOnly) {
+ // Locate hyperlink relations
+ if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
+ $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ foreach ($relsWorksheet->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink") {
+ $hyperlinks[(string)$ele["Id"]] = (string)$ele["Target"];
+ }
+ }
+ }
+
+ // Loop through hyperlinks
+ if ($xmlSheet && $xmlSheet->hyperlinks) {
+ foreach ($xmlSheet->hyperlinks->hyperlink as $hyperlink) {
+ // Link url
+ $linkRel = $hyperlink->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
+
+ foreach (PHPExcel_Cell::extractAllCellReferencesInRange($hyperlink['ref']) as $cellReference) {
+ $cell = $docSheet->getCell($cellReference);
+ if (isset($linkRel['id'])) {
+ $hyperlinkUrl = $hyperlinks[ (string)$linkRel['id'] ];
+ if (isset($hyperlink['location'])) {
+ $hyperlinkUrl .= '#' . (string) $hyperlink['location'];
+ }
+ $cell->getHyperlink()->setUrl($hyperlinkUrl);
+ } elseif (isset($hyperlink['location'])) {
+ $cell->getHyperlink()->setUrl('sheet://' . (string)$hyperlink['location']);
+ }
+
+ // Tooltip
+ if (isset($hyperlink['tooltip'])) {
+ $cell->getHyperlink()->setTooltip((string)$hyperlink['tooltip']);
+ }
+ }
+ }
+ }
+ }
+
+ // Add comments
+ $comments = array();
+ $vmlComments = array();
+ if (!$this->readDataOnly) {
+ // Locate comment relations
+ if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
+ $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ foreach ($relsWorksheet->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments") {
+ $comments[(string)$ele["Id"]] = (string)$ele["Target"];
+ }
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing") {
+ $vmlComments[(string)$ele["Id"]] = (string)$ele["Target"];
+ }
+ }
+ }
+
+ // Loop through comments
+ foreach ($comments as $relName => $relPath) {
+ // Load comments file
+ $relPath = PHPExcel_Shared_File::realpath(dirname("$dir/$fileWorksheet") . "/" . $relPath);
+ $commentsFile = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $relPath)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+
+ // Utility variables
+ $authors = array();
+
+ // Loop through authors
+ foreach ($commentsFile->authors->author as $author) {
+ $authors[] = (string)$author;
+ }
+
+ // Loop through contents
+ foreach ($commentsFile->commentList->comment as $comment) {
+ if (!empty($comment['authorId'])) {
+ $docSheet->getComment((string)$comment['ref'])->setAuthor($authors[(string)$comment['authorId']]);
+ }
+ $docSheet->getComment((string)$comment['ref'])->setText($this->parseRichText($comment->text));
+ }
+ }
+
+ // Loop through VML comments
+ foreach ($vmlComments as $relName => $relPath) {
+ // Load VML comments file
+ $relPath = PHPExcel_Shared_File::realpath(dirname("$dir/$fileWorksheet") . "/" . $relPath);
+ $vmlCommentsFile = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $relPath)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $vmlCommentsFile->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
+
+ $shapes = $vmlCommentsFile->xpath('//v:shape');
+ foreach ($shapes as $shape) {
+ $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
+
+ if (isset($shape['style'])) {
+ $style = (string)$shape['style'];
+ $fillColor = strtoupper(substr((string)$shape['fillcolor'], 1));
+ $column = null;
+ $row = null;
+
+ $clientData = $shape->xpath('.//x:ClientData');
+ if (is_array($clientData) && !empty($clientData)) {
+ $clientData = $clientData[0];
+
+ if (isset($clientData['ObjectType']) && (string)$clientData['ObjectType'] == 'Note') {
+ $temp = $clientData->xpath('.//x:Row');
+ if (is_array($temp)) {
+ $row = $temp[0];
+ }
+
+ $temp = $clientData->xpath('.//x:Column');
+ if (is_array($temp)) {
+ $column = $temp[0];
+ }
+ }
+ }
+
+ if (($column !== null) && ($row !== null)) {
+ // Set comment properties
+ $comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
+ $comment->getFillColor()->setRGB($fillColor);
+
+ // Parse style
+ $styleArray = explode(';', str_replace(' ', '', $style));
+ foreach ($styleArray as $stylePair) {
+ $stylePair = explode(':', $stylePair);
+
+ if ($stylePair[0] == 'margin-left') {
+ $comment->setMarginLeft($stylePair[1]);
+ }
+ if ($stylePair[0] == 'margin-top') {
+ $comment->setMarginTop($stylePair[1]);
+ }
+ if ($stylePair[0] == 'width') {
+ $comment->setWidth($stylePair[1]);
+ }
+ if ($stylePair[0] == 'height') {
+ $comment->setHeight($stylePair[1]);
+ }
+ if ($stylePair[0] == 'visibility') {
+ $comment->setVisible($stylePair[1] == 'visible');
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Header/footer images
+ if ($xmlSheet && $xmlSheet->legacyDrawingHF && !$this->readDataOnly) {
+ if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
+ $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ $vmlRelationship = '';
+
+ foreach ($relsWorksheet->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing") {
+ $vmlRelationship = self::dirAdd("$dir/$fileWorksheet", $ele["Target"]);
+ }
+ }
+
+ if ($vmlRelationship != '') {
+ // Fetch linked images
+ $relsVML = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname($vmlRelationship) . '/_rels/' . basename($vmlRelationship) . '.rels')), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ $drawings = array();
+ foreach ($relsVML->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") {
+ $drawings[(string) $ele["Id"]] = self::dirAdd($vmlRelationship, $ele["Target"]);
+ }
+ }
+
+ // Fetch VML document
+ $vmlDrawing = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $vmlRelationship)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $vmlDrawing->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
+
+ $hfImages = array();
+
+ $shapes = $vmlDrawing->xpath('//v:shape');
+ foreach ($shapes as $idx => $shape) {
+ $shape->registerXPathNamespace('v', 'urn:schemas-microsoft-com:vml');
+ $imageData = $shape->xpath('//v:imagedata');
+ $imageData = $imageData[$idx];
+
+ $imageData = $imageData->attributes('urn:schemas-microsoft-com:office:office');
+ $style = self::toCSSArray((string)$shape['style']);
+
+ $hfImages[ (string)$shape['id'] ] = new PHPExcel_Worksheet_HeaderFooterDrawing();
+ if (isset($imageData['title'])) {
+ $hfImages[ (string)$shape['id'] ]->setName((string)$imageData['title']);
+ }
+
+ $hfImages[ (string)$shape['id'] ]->setPath("zip://".PHPExcel_Shared_File::realpath($pFilename)."#" . $drawings[(string)$imageData['relid']], false);
+ $hfImages[ (string)$shape['id'] ]->setResizeProportional(false);
+ $hfImages[ (string)$shape['id'] ]->setWidth($style['width']);
+ $hfImages[ (string)$shape['id'] ]->setHeight($style['height']);
+ if (isset($style['margin-left'])) {
+ $hfImages[ (string)$shape['id'] ]->setOffsetX($style['margin-left']);
+ }
+ $hfImages[ (string)$shape['id'] ]->setOffsetY($style['margin-top']);
+ $hfImages[ (string)$shape['id'] ]->setResizeProportional(true);
+ }
+
+ $docSheet->getHeaderFooter()->setImages($hfImages);
+ }
+ }
+ }
+
+ }
+
+ // TODO: Autoshapes from twoCellAnchors!
+ if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
+ $relsWorksheet = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ $drawings = array();
+ foreach ($relsWorksheet->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing") {
+ $drawings[(string) $ele["Id"]] = self::dirAdd("$dir/$fileWorksheet", $ele["Target"]);
+ }
+ }
+ if ($xmlSheet->drawing && !$this->readDataOnly) {
+ foreach ($xmlSheet->drawing as $drawing) {
+ $fileDrawing = $drawings[(string) self::getArrayItem($drawing->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
+ $relsDrawing = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, dirname($fileDrawing) . "/_rels/" . basename($fileDrawing) . ".rels")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions()); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+ $images = array();
+
+ if ($relsDrawing && $relsDrawing->Relationship) {
+ foreach ($relsDrawing->Relationship as $ele) {
+ if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") {
+ $images[(string) $ele["Id"]] = self::dirAdd($fileDrawing, $ele["Target"]);
+ } elseif ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart") {
+ if ($this->includeCharts) {
+ $charts[self::dirAdd($fileDrawing, $ele["Target"])] = array(
+ 'id' => (string) $ele["Id"],
+ 'sheet' => $docSheet->getTitle()
+ );
+ }
+ }
+ }
+ }
+ $xmlDrawing = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $fileDrawing)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions())->children("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing");
+
+ if ($xmlDrawing->oneCellAnchor) {
+ foreach ($xmlDrawing->oneCellAnchor as $oneCellAnchor) {
+ if ($oneCellAnchor->pic->blipFill) {
+ $blip = $oneCellAnchor->pic->blipFill->children("http://schemas.openxmlformats.org/drawingml/2006/main")->blip;
+ $xfrm = $oneCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->xfrm;
+ $outerShdw = $oneCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->effectLst->outerShdw;
+ $objDrawing = new PHPExcel_Worksheet_Drawing;
+ $objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), "name"));
+ $objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), "descr"));
+ $objDrawing->setPath("zip://".PHPExcel_Shared_File::realpath($pFilename)."#" . $images[(string) self::getArrayItem($blip->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "embed")], false);
+ $objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
+ $objDrawing->setOffsetX(PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->colOff));
+ $objDrawing->setOffsetY(PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->rowOff));
+ $objDrawing->setResizeProportional(false);
+ $objDrawing->setWidth(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cx")));
+ $objDrawing->setHeight(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cy")));
+ if ($xfrm) {
+ $objDrawing->setRotation(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), "rot")));
+ }
+ if ($outerShdw) {
+ $shadow = $objDrawing->getShadow();
+ $shadow->setVisible(true);
+ $shadow->setBlurRadius(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "blurRad")));
+ $shadow->setDistance(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "dist")));
+ $shadow->setDirection(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), "dir")));
+ $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), "algn"));
+ $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), "val"));
+ $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), "val") / 1000);
+ }
+ $objDrawing->setWorksheet($docSheet);
+ } else {
+ // ? Can charts be positioned with a oneCellAnchor ?
+ $coordinates = PHPExcel_Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1);
+ $offsetX = PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->colOff);
+ $offsetY = PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->rowOff);
+ $width = PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cx"));
+ $height = PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), "cy"));
+ }
+ }
+ }
+ if ($xmlDrawing->twoCellAnchor) {
+ foreach ($xmlDrawing->twoCellAnchor as $twoCellAnchor) {
+ if ($twoCellAnchor->pic->blipFill) {
+ $blip = $twoCellAnchor->pic->blipFill->children("http://schemas.openxmlformats.org/drawingml/2006/main")->blip;
+ $xfrm = $twoCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->xfrm;
+ $outerShdw = $twoCellAnchor->pic->spPr->children("http://schemas.openxmlformats.org/drawingml/2006/main")->effectLst->outerShdw;
+ $objDrawing = new PHPExcel_Worksheet_Drawing;
+ $objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), "name"));
+ $objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), "descr"));
+ $objDrawing->setPath("zip://".PHPExcel_Shared_File::realpath($pFilename)."#" . $images[(string) self::getArrayItem($blip->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "embed")], false);
+ $objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
+ $objDrawing->setOffsetX(PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->colOff));
+ $objDrawing->setOffsetY(PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
+ $objDrawing->setResizeProportional(false);
+
+ if ($xfrm) {
+ $objDrawing->setWidth(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), "cx")));
+ $objDrawing->setHeight(PHPExcel_Shared_Drawing::EMUToPixels(self::getArrayItem($xfrm->ext->attributes(), "cy")));
+ $objDrawing->setRotation(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($xfrm->attributes(), "rot")));
+ }
+ if ($outerShdw) {
+ $shadow = $objDrawing->getShadow();
+ $shadow->setVisible(true);
+ $shadow->setBlurRadius(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "blurRad")));
+ $shadow->setDistance(PHPExcel_Shared_Drawing::EMUTopixels(self::getArrayItem($outerShdw->attributes(), "dist")));
+ $shadow->setDirection(PHPExcel_Shared_Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), "dir")));
+ $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), "algn"));
+ $shadow->getColor()->setRGB(self::getArrayItem($outerShdw->srgbClr->attributes(), "val"));
+ $shadow->setAlpha(self::getArrayItem($outerShdw->srgbClr->alpha->attributes(), "val") / 1000);
+ }
+ $objDrawing->setWorksheet($docSheet);
+ } elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) {
+ $fromCoordinate = PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1);
+ $fromOffsetX = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->colOff);
+ $fromOffsetY = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->rowOff);
+ $toCoordinate = PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->to->col) . ($twoCellAnchor->to->row + 1);
+ $toOffsetX = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->to->colOff);
+ $toOffsetY = PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
+ $graphic = $twoCellAnchor->graphicFrame->children("http://schemas.openxmlformats.org/drawingml/2006/main")->graphic;
+ $chartRef = $graphic->graphicData->children("http://schemas.openxmlformats.org/drawingml/2006/chart")->chart;
+ $thisChart = (string) $chartRef->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
+
+ $chartDetails[$docSheet->getTitle().'!'.$thisChart] = array(
+ 'fromCoordinate' => $fromCoordinate,
+ 'fromOffsetX' => $fromOffsetX,
+ 'fromOffsetY' => $fromOffsetY,
+ 'toCoordinate' => $toCoordinate,
+ 'toOffsetX' => $toOffsetX,
+ 'toOffsetY' => $toOffsetY,
+ 'worksheetTitle' => $docSheet->getTitle()
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Loop through definedNames
+ if ($xmlWorkbook->definedNames) {
+ foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
+ // Extract range
+ $extractedRange = (string)$definedName;
+ $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange);
+ if (($spos = strpos($extractedRange, '!')) !== false) {
+ $extractedRange = substr($extractedRange, 0, $spos).str_replace('$', '', substr($extractedRange, $spos));
+ } else {
+ $extractedRange = str_replace('$', '', $extractedRange);
+ }
+
+ // Valid range?
+ if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') {
+ continue;
+ }
+
+ // Some definedNames are only applicable if we are on the same sheet...
+ if ((string)$definedName['localSheetId'] != '' && (string)$definedName['localSheetId'] == $sheetId) {
+ // Switch on type
+ switch ((string)$definedName['name']) {
+ case '_xlnm._FilterDatabase':
+ if ((string)$definedName['hidden'] !== '1') {
+ $extractedRange = explode(',', $extractedRange);
+ foreach ($extractedRange as $range) {
+ $autoFilterRange = $range;
+ if (strpos($autoFilterRange, ':') !== false) {
+ $docSheet->getAutoFilter()->setRange($autoFilterRange);
+ }
+ }
+ }
+ break;
+ case '_xlnm.Print_Titles':
+ // Split $extractedRange
+ $extractedRange = explode(',', $extractedRange);
+
+ // Set print titles
+ foreach ($extractedRange as $range) {
+ $matches = array();
+ $range = str_replace('$', '', $range);
+
+ // check for repeating columns, e g. 'A:A' or 'A:D'
+ if (preg_match('/!?([A-Z]+)\:([A-Z]+)$/', $range, $matches)) {
+ $docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($matches[1], $matches[2]));
+ } elseif (preg_match('/!?(\d+)\:(\d+)$/', $range, $matches)) {
+ // check for repeating rows, e.g. '1:1' or '1:5'
+ $docSheet->getPageSetup()->setRowsToRepeatAtTop(array($matches[1], $matches[2]));
+ }
+ }
+ break;
+ case '_xlnm.Print_Area':
+ $rangeSets = explode(',', $extractedRange); // FIXME: what if sheetname contains comma?
+ $newRangeSets = array();
+ foreach ($rangeSets as $rangeSet) {
+ $range = explode('!', $rangeSet); // FIXME: what if sheetname contains exclamation mark?
+ $rangeSet = isset($range[1]) ? $range[1] : $range[0];
+ if (strpos($rangeSet, ':') === false) {
+ $rangeSet = $rangeSet . ':' . $rangeSet;
+ }
+ $newRangeSets[] = str_replace('$', '', $rangeSet);
+ }
+ $docSheet->getPageSetup()->setPrintArea(implode(',', $newRangeSets));
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Next sheet id
+ ++$sheetId;
+ }
+
+ // Loop through definedNames
+ if ($xmlWorkbook->definedNames) {
+ foreach ($xmlWorkbook->definedNames->definedName as $definedName) {
+ // Extract range
+ $extractedRange = (string)$definedName;
+ $extractedRange = preg_replace('/\'(\w+)\'\!/', '', $extractedRange);
+ if (($spos = strpos($extractedRange, '!')) !== false) {
+ $extractedRange = substr($extractedRange, 0, $spos).str_replace('$', '', substr($extractedRange, $spos));
+ } else {
+ $extractedRange = str_replace('$', '', $extractedRange);
+ }
+
+ // Valid range?
+ if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') {
+ continue;
+ }
+
+ // Some definedNames are only applicable if we are on the same sheet...
+ if ((string)$definedName['localSheetId'] != '') {
+ // Local defined name
+ // Switch on type
+ switch ((string)$definedName['name']) {
+ case '_xlnm._FilterDatabase':
+ case '_xlnm.Print_Titles':
+ case '_xlnm.Print_Area':
+ break;
+ default:
+ if ($mapSheetId[(integer) $definedName['localSheetId']] !== null) {
+ $range = explode('!', (string)$definedName);
+ if (count($range) == 2) {
+ $range[0] = str_replace("''", "'", $range[0]);
+ $range[0] = str_replace("'", "", $range[0]);
+ if ($worksheet = $docSheet->getParent()->getSheetByName($range[0])) {
+ $extractedRange = str_replace('$', '', $range[1]);
+ $scope = $docSheet->getParent()->getSheet($mapSheetId[(integer) $definedName['localSheetId']]);
+ $excel->addNamedRange(new PHPExcel_NamedRange((string)$definedName['name'], $worksheet, $extractedRange, true, $scope));
+ }
+ }
+ }
+ break;
+ }
+ } elseif (!isset($definedName['localSheetId'])) {
+ // "Global" definedNames
+ $locatedSheet = null;
+ $extractedSheetName = '';
+ if (strpos((string)$definedName, '!') !== false) {
+ // Extract sheet name
+ $extractedSheetName = PHPExcel_Worksheet::extractSheetTitle((string)$definedName, true);
+ $extractedSheetName = $extractedSheetName[0];
+
+ // Locate sheet
+ $locatedSheet = $excel->getSheetByName($extractedSheetName);
+
+ // Modify range
+ $range = explode('!', $extractedRange);
+ $extractedRange = isset($range[1]) ? $range[1] : $range[0];
+ }
+
+ if ($locatedSheet !== null) {
+ $excel->addNamedRange(new PHPExcel_NamedRange((string)$definedName['name'], $locatedSheet, $extractedRange, false));
+ }
+ }
+ }
+ }
+ }
+
+ if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
+ // active sheet index
+ $activeTab = intval($xmlWorkbook->bookViews->workbookView["activeTab"]); // refers to old sheet index
+
+ // keep active sheet index if sheet is still loaded, else first sheet is set as the active
+ if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
+ $excel->setActiveSheetIndex($mapSheetId[$activeTab]);
+ } else {
+ if ($excel->getSheetCount() == 0) {
+ $excel->createSheet();
+ }
+ $excel->setActiveSheetIndex(0);
+ }
+ }
+ break;
+ }
+ }
+
+ if (!$this->readDataOnly) {
+ $contentTypes = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, "[Content_Types].xml")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ foreach ($contentTypes->Override as $contentType) {
+ switch ($contentType["ContentType"]) {
+ case "application/vnd.openxmlformats-officedocument.drawingml.chart+xml":
+ if ($this->includeCharts) {
+ $chartEntryRef = ltrim($contentType['PartName'], '/');
+ $chartElements = simplexml_load_string($this->securityScan($this->getFromZipArchive($zip, $chartEntryRef)), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $objChart = PHPExcel_Reader_Excel2007_Chart::readChart($chartElements, basename($chartEntryRef, '.xml'));
+
+// echo 'Chart ', $chartEntryRef, ' ';
+// var_dump($charts[$chartEntryRef]);
+//
+ if (isset($charts[$chartEntryRef])) {
+ $chartPositionRef = $charts[$chartEntryRef]['sheet'].'!'.$charts[$chartEntryRef]['id'];
+// echo 'Position Ref ', $chartPositionRef, ' ';
+ if (isset($chartDetails[$chartPositionRef])) {
+// var_dump($chartDetails[$chartPositionRef]);
+
+ $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
+ $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
+ $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']);
+ $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $zip->close();
+
+ return $excel;
+ }
+
+ private static function readColor($color, $background = false)
+ {
+ if (isset($color["rgb"])) {
+ return (string)$color["rgb"];
+ } elseif (isset($color["indexed"])) {
+ return PHPExcel_Style_Color::indexedColor($color["indexed"]-7, $background)->getARGB();
+ } elseif (isset($color["theme"])) {
+ if (self::$theme !== null) {
+ $returnColour = self::$theme->getColourByIndex((int)$color["theme"]);
+ if (isset($color["tint"])) {
+ $tintAdjust = (float) $color["tint"];
+ $returnColour = PHPExcel_Style_Color::changeBrightness($returnColour, $tintAdjust);
+ }
+ return 'FF'.$returnColour;
+ }
+ }
+
+ if ($background) {
+ return 'FFFFFFFF';
+ }
+ return 'FF000000';
+ }
+
+ private static function readStyle($docStyle, $style)
+ {
+ // format code
+// if (isset($style->numFmt)) {
+// if (isset($style->numFmt['formatCode'])) {
+// $docStyle->getNumberFormat()->setFormatCode((string) $style->numFmt['formatCode']);
+// } else {
+ $docStyle->getNumberFormat()->setFormatCode($style->numFmt);
+// }
+// }
+
+ // font
+ if (isset($style->font)) {
+ $docStyle->getFont()->setName((string) $style->font->name["val"]);
+ $docStyle->getFont()->setSize((string) $style->font->sz["val"]);
+ if (isset($style->font->b)) {
+ $docStyle->getFont()->setBold(!isset($style->font->b["val"]) || self::boolean((string) $style->font->b["val"]));
+ }
+ if (isset($style->font->i)) {
+ $docStyle->getFont()->setItalic(!isset($style->font->i["val"]) || self::boolean((string) $style->font->i["val"]));
+ }
+ if (isset($style->font->strike)) {
+ $docStyle->getFont()->setStrikethrough(!isset($style->font->strike["val"]) || self::boolean((string) $style->font->strike["val"]));
+ }
+ $docStyle->getFont()->getColor()->setARGB(self::readColor($style->font->color));
+
+ if (isset($style->font->u) && !isset($style->font->u["val"])) {
+ $docStyle->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+ } elseif (isset($style->font->u) && isset($style->font->u["val"])) {
+ $docStyle->getFont()->setUnderline((string)$style->font->u["val"]);
+ }
+
+ if (isset($style->font->vertAlign) && isset($style->font->vertAlign["val"])) {
+ $vertAlign = strtolower((string)$style->font->vertAlign["val"]);
+ if ($vertAlign == 'superscript') {
+ $docStyle->getFont()->setSuperScript(true);
+ }
+ if ($vertAlign == 'subscript') {
+ $docStyle->getFont()->setSubScript(true);
+ }
+ }
+ }
+
+ // fill
+ if (isset($style->fill)) {
+ if ($style->fill->gradientFill) {
+ $gradientFill = $style->fill->gradientFill[0];
+ if (!empty($gradientFill["type"])) {
+ $docStyle->getFill()->setFillType((string) $gradientFill["type"]);
+ }
+ $docStyle->getFill()->setRotation(floatval($gradientFill["degree"]));
+ $gradientFill->registerXPathNamespace("sml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+ $docStyle->getFill()->getStartColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath("sml:stop[@position=0]"))->color));
+ $docStyle->getFill()->getEndColor()->setARGB(self::readColor(self::getArrayItem($gradientFill->xpath("sml:stop[@position=1]"))->color));
+ } elseif ($style->fill->patternFill) {
+ $patternType = (string)$style->fill->patternFill["patternType"] != '' ? (string)$style->fill->patternFill["patternType"] : 'solid';
+ $docStyle->getFill()->setFillType($patternType);
+ if ($style->fill->patternFill->fgColor) {
+ $docStyle->getFill()->getStartColor()->setARGB(self::readColor($style->fill->patternFill->fgColor, true));
+ } else {
+ $docStyle->getFill()->getStartColor()->setARGB('FF000000');
+ }
+ if ($style->fill->patternFill->bgColor) {
+ $docStyle->getFill()->getEndColor()->setARGB(self::readColor($style->fill->patternFill->bgColor, true));
+ }
+ }
+ }
+
+ // border
+ if (isset($style->border)) {
+ $diagonalUp = self::boolean((string) $style->border["diagonalUp"]);
+ $diagonalDown = self::boolean((string) $style->border["diagonalDown"]);
+ if (!$diagonalUp && !$diagonalDown) {
+ $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
+ } elseif ($diagonalUp && !$diagonalDown) {
+ $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
+ } elseif (!$diagonalUp && $diagonalDown) {
+ $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
+ } else {
+ $docStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
+ }
+ self::readBorder($docStyle->getBorders()->getLeft(), $style->border->left);
+ self::readBorder($docStyle->getBorders()->getRight(), $style->border->right);
+ self::readBorder($docStyle->getBorders()->getTop(), $style->border->top);
+ self::readBorder($docStyle->getBorders()->getBottom(), $style->border->bottom);
+ self::readBorder($docStyle->getBorders()->getDiagonal(), $style->border->diagonal);
+ }
+
+ // alignment
+ if (isset($style->alignment)) {
+ $docStyle->getAlignment()->setHorizontal((string) $style->alignment["horizontal"]);
+ $docStyle->getAlignment()->setVertical((string) $style->alignment["vertical"]);
+
+ $textRotation = 0;
+ if ((int)$style->alignment["textRotation"] <= 90) {
+ $textRotation = (int)$style->alignment["textRotation"];
+ } elseif ((int)$style->alignment["textRotation"] > 90) {
+ $textRotation = 90 - (int)$style->alignment["textRotation"];
+ }
+
+ $docStyle->getAlignment()->setTextRotation(intval($textRotation));
+ $docStyle->getAlignment()->setWrapText(self::boolean((string) $style->alignment["wrapText"]));
+ $docStyle->getAlignment()->setShrinkToFit(self::boolean((string) $style->alignment["shrinkToFit"]));
+ $docStyle->getAlignment()->setIndent(intval((string)$style->alignment["indent"]) > 0 ? intval((string)$style->alignment["indent"]) : 0);
+ $docStyle->getAlignment()->setReadorder(intval((string)$style->alignment["readingOrder"]) > 0 ? intval((string)$style->alignment["readingOrder"]) : 0);
+ }
+
+ // protection
+ if (isset($style->protection)) {
+ if (isset($style->protection['locked'])) {
+ if (self::boolean((string) $style->protection['locked'])) {
+ $docStyle->getProtection()->setLocked(PHPExcel_Style_Protection::PROTECTION_PROTECTED);
+ } else {
+ $docStyle->getProtection()->setLocked(PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
+ }
+ }
+
+ if (isset($style->protection['hidden'])) {
+ if (self::boolean((string) $style->protection['hidden'])) {
+ $docStyle->getProtection()->setHidden(PHPExcel_Style_Protection::PROTECTION_PROTECTED);
+ } else {
+ $docStyle->getProtection()->setHidden(PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
+ }
+ }
+ }
+
+ // top-level style settings
+ if (isset($style->quotePrefix)) {
+ $docStyle->setQuotePrefix($style->quotePrefix);
+ }
+ }
+
+ private static function readBorder($docBorder, $eleBorder)
+ {
+ if (isset($eleBorder["style"])) {
+ $docBorder->setBorderStyle((string) $eleBorder["style"]);
+ }
+ if (isset($eleBorder->color)) {
+ $docBorder->getColor()->setARGB(self::readColor($eleBorder->color));
+ }
+ }
+
+ private function parseRichText($is = null)
+ {
+ $value = new PHPExcel_RichText();
+
+ if (isset($is->t)) {
+ $value->createText(PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $is->t));
+ } else {
+ if (is_object($is->r)) {
+ foreach ($is->r as $run) {
+ if (!isset($run->rPr)) {
+ $objText = $value->createText(PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $run->t));
+
+ } else {
+ $objText = $value->createTextRun(PHPExcel_Shared_String::ControlCharacterOOXML2PHP((string) $run->t));
+
+ if (isset($run->rPr->rFont["val"])) {
+ $objText->getFont()->setName((string) $run->rPr->rFont["val"]);
+ }
+ if (isset($run->rPr->sz["val"])) {
+ $objText->getFont()->setSize((string) $run->rPr->sz["val"]);
+ }
+ if (isset($run->rPr->color)) {
+ $objText->getFont()->setColor(new PHPExcel_Style_Color(self::readColor($run->rPr->color)));
+ }
+ if ((isset($run->rPr->b["val"]) && self::boolean((string) $run->rPr->b["val"])) ||
+ (isset($run->rPr->b) && !isset($run->rPr->b["val"]))) {
+ $objText->getFont()->setBold(true);
+ }
+ if ((isset($run->rPr->i["val"]) && self::boolean((string) $run->rPr->i["val"])) ||
+ (isset($run->rPr->i) && !isset($run->rPr->i["val"]))) {
+ $objText->getFont()->setItalic(true);
+ }
+ if (isset($run->rPr->vertAlign) && isset($run->rPr->vertAlign["val"])) {
+ $vertAlign = strtolower((string)$run->rPr->vertAlign["val"]);
+ if ($vertAlign == 'superscript') {
+ $objText->getFont()->setSuperScript(true);
+ }
+ if ($vertAlign == 'subscript') {
+ $objText->getFont()->setSubScript(true);
+ }
+ }
+ if (isset($run->rPr->u) && !isset($run->rPr->u["val"])) {
+ $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+ } elseif (isset($run->rPr->u) && isset($run->rPr->u["val"])) {
+ $objText->getFont()->setUnderline((string)$run->rPr->u["val"]);
+ }
+ if ((isset($run->rPr->strike["val"]) && self::boolean((string) $run->rPr->strike["val"])) ||
+ (isset($run->rPr->strike) && !isset($run->rPr->strike["val"]))) {
+ $objText->getFont()->setStrikethrough(true);
+ }
+ }
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ private function readRibbon($excel, $customUITarget, $zip)
+ {
+ $baseDir = dirname($customUITarget);
+ $nameCustomUI = basename($customUITarget);
+ // get the xml file (ribbon)
+ $localRibbon = $this->getFromZipArchive($zip, $customUITarget);
+ $customUIImagesNames = array();
+ $customUIImagesBinaries = array();
+ // something like customUI/_rels/customUI.xml.rels
+ $pathRels = $baseDir . '/_rels/' . $nameCustomUI . '.rels';
+ $dataRels = $this->getFromZipArchive($zip, $pathRels);
+ if ($dataRels) {
+ // exists and not empty if the ribbon have some pictures (other than internal MSO)
+ $UIRels = simplexml_load_string($this->securityScan($dataRels), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ if ($UIRels) {
+ // we need to save id and target to avoid parsing customUI.xml and "guess" if it's a pseudo callback who load the image
+ foreach ($UIRels->Relationship as $ele) {
+ if ($ele["Type"] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') {
+ // an image ?
+ $customUIImagesNames[(string) $ele['Id']] = (string)$ele['Target'];
+ $customUIImagesBinaries[(string)$ele['Target']] = $this->getFromZipArchive($zip, $baseDir . '/' . (string) $ele['Target']);
+ }
+ }
+ }
+ }
+ if ($localRibbon) {
+ $excel->setRibbonXMLData($customUITarget, $localRibbon);
+ if (count($customUIImagesNames) > 0 && count($customUIImagesBinaries) > 0) {
+ $excel->setRibbonBinObjects($customUIImagesNames, $customUIImagesBinaries);
+ } else {
+ $excel->setRibbonBinObjects(null);
+ }
+ } else {
+ $excel->setRibbonXMLData(null);
+ $excel->setRibbonBinObjects(null);
+ }
+ }
+
+ private static function getArrayItem($array, $key = 0)
+ {
+ return (isset($array[$key]) ? $array[$key] : null);
+ }
+
+ private static function dirAdd($base, $add)
+ {
+ return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
+ }
+
+ private static function toCSSArray($style)
+ {
+ $style = str_replace(array("\r","\n"), "", $style);
+
+ $temp = explode(';', $style);
+ $style = array();
+ foreach ($temp as $item) {
+ $item = explode(':', $item);
+
+ if (strpos($item[1], 'px') !== false) {
+ $item[1] = str_replace('px', '', $item[1]);
+ }
+ if (strpos($item[1], 'pt') !== false) {
+ $item[1] = str_replace('pt', '', $item[1]);
+ $item[1] = PHPExcel_Shared_Font::fontSizeToPixels($item[1]);
+ }
+ if (strpos($item[1], 'in') !== false) {
+ $item[1] = str_replace('in', '', $item[1]);
+ $item[1] = PHPExcel_Shared_Font::inchSizeToPixels($item[1]);
+ }
+ if (strpos($item[1], 'cm') !== false) {
+ $item[1] = str_replace('cm', '', $item[1]);
+ $item[1] = PHPExcel_Shared_Font::centimeterSizeToPixels($item[1]);
+ }
+
+ $style[$item[0]] = $item[1];
+ }
+
+ return $style;
+ }
+
+ private static function boolean($value = null)
+ {
+ if (is_object($value)) {
+ $value = (string) $value;
+ }
+ if (is_numeric($value)) {
+ return (bool) $value;
+ }
+ return ($value === 'true' || $value === 'TRUE');
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel2007/Chart.php b/extend/PHPExcel/PHPExcel/Reader/Excel2007/Chart.php
new file mode 100755
index 0000000..590bf2d
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel2007/Chart.php
@@ -0,0 +1,520 @@
+attributes();
+ if (isset($attributes[$name])) {
+ if ($format == 'string') {
+ return (string) $attributes[$name];
+ } elseif ($format == 'integer') {
+ return (integer) $attributes[$name];
+ } elseif ($format == 'boolean') {
+ return (boolean) ($attributes[$name] === '0' || $attributes[$name] !== 'true') ? false : true;
+ } else {
+ return (float) $attributes[$name];
+ }
+ }
+ return null;
+ }
+
+
+ private static function readColor($color, $background = false)
+ {
+ if (isset($color["rgb"])) {
+ return (string)$color["rgb"];
+ } elseif (isset($color["indexed"])) {
+ return PHPExcel_Style_Color::indexedColor($color["indexed"]-7, $background)->getARGB();
+ }
+ }
+
+ public static function readChart($chartElements, $chartName)
+ {
+ $namespacesChartMeta = $chartElements->getNamespaces(true);
+ $chartElementsC = $chartElements->children($namespacesChartMeta['c']);
+
+ $XaxisLabel = $YaxisLabel = $legend = $title = null;
+ $dispBlanksAs = $plotVisOnly = null;
+
+ foreach ($chartElementsC as $chartElementKey => $chartElement) {
+ switch ($chartElementKey) {
+ case "chart":
+ foreach ($chartElement as $chartDetailsKey => $chartDetails) {
+ $chartDetailsC = $chartDetails->children($namespacesChartMeta['c']);
+ switch ($chartDetailsKey) {
+ case "plotArea":
+ $plotAreaLayout = $XaxisLable = $YaxisLable = null;
+ $plotSeries = $plotAttributes = array();
+ foreach ($chartDetails as $chartDetailKey => $chartDetail) {
+ switch ($chartDetailKey) {
+ case "layout":
+ $plotAreaLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta, 'plotArea');
+ break;
+ case "catAx":
+ if (isset($chartDetail->title)) {
+ $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
+ }
+ break;
+ case "dateAx":
+ if (isset($chartDetail->title)) {
+ $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
+ }
+ break;
+ case "valAx":
+ if (isset($chartDetail->title)) {
+ $YaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
+ }
+ break;
+ case "barChart":
+ case "bar3DChart":
+ $barDirection = self::getAttribute($chartDetail->barDir, 'val', 'string');
+ $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotSer->setPlotDirection($barDirection);
+ $plotSeries[] = $plotSer;
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "lineChart":
+ case "line3DChart":
+ $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "areaChart":
+ case "area3DChart":
+ $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "doughnutChart":
+ case "pieChart":
+ case "pie3DChart":
+ $explosion = isset($chartDetail->ser->explosion);
+ $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotSer->setPlotStyle($explosion);
+ $plotSeries[] = $plotSer;
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "scatterChart":
+ $scatterStyle = self::getAttribute($chartDetail->scatterStyle, 'val', 'string');
+ $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotSer->setPlotStyle($scatterStyle);
+ $plotSeries[] = $plotSer;
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "bubbleChart":
+ $bubbleScale = self::getAttribute($chartDetail->bubbleScale, 'val', 'integer');
+ $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotSer->setPlotStyle($bubbleScale);
+ $plotSeries[] = $plotSer;
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "radarChart":
+ $radarStyle = self::getAttribute($chartDetail->radarStyle, 'val', 'string');
+ $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotSer->setPlotStyle($radarStyle);
+ $plotSeries[] = $plotSer;
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "surfaceChart":
+ case "surface3DChart":
+ $wireFrame = self::getAttribute($chartDetail->wireframe, 'val', 'boolean');
+ $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotSer->setPlotStyle($wireFrame);
+ $plotSeries[] = $plotSer;
+ $plotAttributes = self::readChartAttributes($chartDetail);
+ break;
+ case "stockChart":
+ $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
+ $plotAttributes = self::readChartAttributes($plotAreaLayout);
+ break;
+ }
+ }
+ if ($plotAreaLayout == null) {
+ $plotAreaLayout = new PHPExcel_Chart_Layout();
+ }
+ $plotArea = new PHPExcel_Chart_PlotArea($plotAreaLayout, $plotSeries);
+ self::setChartAttributes($plotAreaLayout, $plotAttributes);
+ break;
+ case "plotVisOnly":
+ $plotVisOnly = self::getAttribute($chartDetails, 'val', 'string');
+ break;
+ case "dispBlanksAs":
+ $dispBlanksAs = self::getAttribute($chartDetails, 'val', 'string');
+ break;
+ case "title":
+ $title = self::chartTitle($chartDetails, $namespacesChartMeta, 'title');
+ break;
+ case "legend":
+ $legendPos = 'r';
+ $legendLayout = null;
+ $legendOverlay = false;
+ foreach ($chartDetails as $chartDetailKey => $chartDetail) {
+ switch ($chartDetailKey) {
+ case "legendPos":
+ $legendPos = self::getAttribute($chartDetail, 'val', 'string');
+ break;
+ case "overlay":
+ $legendOverlay = self::getAttribute($chartDetail, 'val', 'boolean');
+ break;
+ case "layout":
+ $legendLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta, 'legend');
+ break;
+ }
+ }
+ $legend = new PHPExcel_Chart_Legend($legendPos, $legendLayout, $legendOverlay);
+ break;
+ }
+ }
+ }
+ }
+ $chart = new PHPExcel_Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, $dispBlanksAs, $XaxisLabel, $YaxisLabel);
+
+ return $chart;
+ }
+
+ private static function chartTitle($titleDetails, $namespacesChartMeta, $type)
+ {
+ $caption = array();
+ $titleLayout = null;
+ foreach ($titleDetails as $titleDetailKey => $chartDetail) {
+ switch ($titleDetailKey) {
+ case "tx":
+ $titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']);
+ foreach ($titleDetails as $titleKey => $titleDetail) {
+ switch ($titleKey) {
+ case "p":
+ $titleDetailPart = $titleDetail->children($namespacesChartMeta['a']);
+ $caption[] = self::parseRichText($titleDetailPart);
+ }
+ }
+ break;
+ case "layout":
+ $titleLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta);
+ break;
+ }
+ }
+
+ return new PHPExcel_Chart_Title($caption, $titleLayout);
+ }
+
+ private static function chartLayoutDetails($chartDetail, $namespacesChartMeta)
+ {
+ if (!isset($chartDetail->manualLayout)) {
+ return null;
+ }
+ $details = $chartDetail->manualLayout->children($namespacesChartMeta['c']);
+ if (is_null($details)) {
+ return null;
+ }
+ $layout = array();
+ foreach ($details as $detailKey => $detail) {
+// echo $detailKey, ' => ',self::getAttribute($detail, 'val', 'string'),PHP_EOL;
+ $layout[$detailKey] = self::getAttribute($detail, 'val', 'string');
+ }
+ return new PHPExcel_Chart_Layout($layout);
+ }
+
+ private static function chartDataSeries($chartDetail, $namespacesChartMeta, $plotType)
+ {
+ $multiSeriesType = null;
+ $smoothLine = false;
+ $seriesLabel = $seriesCategory = $seriesValues = $plotOrder = array();
+
+ $seriesDetailSet = $chartDetail->children($namespacesChartMeta['c']);
+ foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) {
+ switch ($seriesDetailKey) {
+ case "grouping":
+ $multiSeriesType = self::getAttribute($chartDetail->grouping, 'val', 'string');
+ break;
+ case "ser":
+ $marker = null;
+ foreach ($seriesDetails as $seriesKey => $seriesDetail) {
+ switch ($seriesKey) {
+ case "idx":
+ $seriesIndex = self::getAttribute($seriesDetail, 'val', 'integer');
+ break;
+ case "order":
+ $seriesOrder = self::getAttribute($seriesDetail, 'val', 'integer');
+ $plotOrder[$seriesIndex] = $seriesOrder;
+ break;
+ case "tx":
+ $seriesLabel[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
+ break;
+ case "marker":
+ $marker = self::getAttribute($seriesDetail->symbol, 'val', 'string');
+ break;
+ case "smooth":
+ $smoothLine = self::getAttribute($seriesDetail, 'val', 'boolean');
+ break;
+ case "cat":
+ $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
+ break;
+ case "val":
+ $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
+ break;
+ case "xVal":
+ $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
+ break;
+ case "yVal":
+ $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
+ break;
+ }
+ }
+ }
+ }
+ return new PHPExcel_Chart_DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine);
+ }
+
+
+ private static function chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null, $smoothLine = false)
+ {
+ if (isset($seriesDetail->strRef)) {
+ $seriesSource = (string) $seriesDetail->strRef->f;
+ $seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's');
+
+ return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+ } elseif (isset($seriesDetail->numRef)) {
+ $seriesSource = (string) $seriesDetail->numRef->f;
+ $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c']));
+
+ return new PHPExcel_Chart_DataSeriesValues('Number', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+ } elseif (isset($seriesDetail->multiLvlStrRef)) {
+ $seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
+ $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's');
+ $seriesData['pointCount'] = count($seriesData['dataValues']);
+
+ return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+ } elseif (isset($seriesDetail->multiLvlNumRef)) {
+ $seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
+ $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's');
+ $seriesData['pointCount'] = count($seriesData['dataValues']);
+
+ return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
+ }
+ return null;
+ }
+
+
+ private static function chartDataSeriesValues($seriesValueSet, $dataType = 'n')
+ {
+ $seriesVal = array();
+ $formatCode = '';
+ $pointCount = 0;
+
+ foreach ($seriesValueSet as $seriesValueIdx => $seriesValue) {
+ switch ($seriesValueIdx) {
+ case 'ptCount':
+ $pointCount = self::getAttribute($seriesValue, 'val', 'integer');
+ break;
+ case 'formatCode':
+ $formatCode = (string) $seriesValue;
+ break;
+ case 'pt':
+ $pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
+ if ($dataType == 's') {
+ $seriesVal[$pointVal] = (string) $seriesValue->v;
+ } else {
+ $seriesVal[$pointVal] = (float) $seriesValue->v;
+ }
+ break;
+ }
+ }
+
+ return array(
+ 'formatCode' => $formatCode,
+ 'pointCount' => $pointCount,
+ 'dataValues' => $seriesVal
+ );
+ }
+
+ private static function chartDataSeriesValuesMultiLevel($seriesValueSet, $dataType = 'n')
+ {
+ $seriesVal = array();
+ $formatCode = '';
+ $pointCount = 0;
+
+ foreach ($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) {
+ foreach ($seriesLevel as $seriesValueIdx => $seriesValue) {
+ switch ($seriesValueIdx) {
+ case 'ptCount':
+ $pointCount = self::getAttribute($seriesValue, 'val', 'integer');
+ break;
+ case 'formatCode':
+ $formatCode = (string) $seriesValue;
+ break;
+ case 'pt':
+ $pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
+ if ($dataType == 's') {
+ $seriesVal[$pointVal][] = (string) $seriesValue->v;
+ } else {
+ $seriesVal[$pointVal][] = (float) $seriesValue->v;
+ }
+ break;
+ }
+ }
+ }
+
+ return array(
+ 'formatCode' => $formatCode,
+ 'pointCount' => $pointCount,
+ 'dataValues' => $seriesVal
+ );
+ }
+
+ private static function parseRichText($titleDetailPart = null)
+ {
+ $value = new PHPExcel_RichText();
+
+ foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
+ if (isset($titleDetailElement->t)) {
+ $objText = $value->createTextRun((string) $titleDetailElement->t);
+ }
+ if (isset($titleDetailElement->rPr)) {
+ if (isset($titleDetailElement->rPr->rFont["val"])) {
+ $objText->getFont()->setName((string) $titleDetailElement->rPr->rFont["val"]);
+ }
+
+ $fontSize = (self::getAttribute($titleDetailElement->rPr, 'sz', 'integer'));
+ if (!is_null($fontSize)) {
+ $objText->getFont()->setSize(floor($fontSize / 100));
+ }
+
+ $fontColor = (self::getAttribute($titleDetailElement->rPr, 'color', 'string'));
+ if (!is_null($fontColor)) {
+ $objText->getFont()->setColor(new PHPExcel_Style_Color(self::readColor($fontColor)));
+ }
+
+ $bold = self::getAttribute($titleDetailElement->rPr, 'b', 'boolean');
+ if (!is_null($bold)) {
+ $objText->getFont()->setBold($bold);
+ }
+
+ $italic = self::getAttribute($titleDetailElement->rPr, 'i', 'boolean');
+ if (!is_null($italic)) {
+ $objText->getFont()->setItalic($italic);
+ }
+
+ $baseline = self::getAttribute($titleDetailElement->rPr, 'baseline', 'integer');
+ if (!is_null($baseline)) {
+ if ($baseline > 0) {
+ $objText->getFont()->setSuperScript(true);
+ } elseif ($baseline < 0) {
+ $objText->getFont()->setSubScript(true);
+ }
+ }
+
+ $underscore = (self::getAttribute($titleDetailElement->rPr, 'u', 'string'));
+ if (!is_null($underscore)) {
+ if ($underscore == 'sng') {
+ $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+ } elseif ($underscore == 'dbl') {
+ $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
+ } else {
+ $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_NONE);
+ }
+ }
+
+ $strikethrough = (self::getAttribute($titleDetailElement->rPr, 's', 'string'));
+ if (!is_null($strikethrough)) {
+ if ($strikethrough == 'noStrike') {
+ $objText->getFont()->setStrikethrough(false);
+ } else {
+ $objText->getFont()->setStrikethrough(true);
+ }
+ }
+ }
+ }
+
+ return $value;
+ }
+
+ private static function readChartAttributes($chartDetail)
+ {
+ $plotAttributes = array();
+ if (isset($chartDetail->dLbls)) {
+ if (isset($chartDetail->dLbls->howLegendKey)) {
+ $plotAttributes['showLegendKey'] = self::getAttribute($chartDetail->dLbls->showLegendKey, 'val', 'string');
+ }
+ if (isset($chartDetail->dLbls->showVal)) {
+ $plotAttributes['showVal'] = self::getAttribute($chartDetail->dLbls->showVal, 'val', 'string');
+ }
+ if (isset($chartDetail->dLbls->showCatName)) {
+ $plotAttributes['showCatName'] = self::getAttribute($chartDetail->dLbls->showCatName, 'val', 'string');
+ }
+ if (isset($chartDetail->dLbls->showSerName)) {
+ $plotAttributes['showSerName'] = self::getAttribute($chartDetail->dLbls->showSerName, 'val', 'string');
+ }
+ if (isset($chartDetail->dLbls->showPercent)) {
+ $plotAttributes['showPercent'] = self::getAttribute($chartDetail->dLbls->showPercent, 'val', 'string');
+ }
+ if (isset($chartDetail->dLbls->showBubbleSize)) {
+ $plotAttributes['showBubbleSize'] = self::getAttribute($chartDetail->dLbls->showBubbleSize, 'val', 'string');
+ }
+ if (isset($chartDetail->dLbls->showLeaderLines)) {
+ $plotAttributes['showLeaderLines'] = self::getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string');
+ }
+ }
+
+ return $plotAttributes;
+ }
+
+ private static function setChartAttributes($plotArea, $plotAttributes)
+ {
+ foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) {
+ switch ($plotAttributeKey) {
+ case 'showLegendKey':
+ $plotArea->setShowLegendKey($plotAttributeValue);
+ break;
+ case 'showVal':
+ $plotArea->setShowVal($plotAttributeValue);
+ break;
+ case 'showCatName':
+ $plotArea->setShowCatName($plotAttributeValue);
+ break;
+ case 'showSerName':
+ $plotArea->setShowSerName($plotAttributeValue);
+ break;
+ case 'showPercent':
+ $plotArea->setShowPercent($plotAttributeValue);
+ break;
+ case 'showBubbleSize':
+ $plotArea->setShowBubbleSize($plotAttributeValue);
+ break;
+ case 'showLeaderLines':
+ $plotArea->setShowLeaderLines($plotAttributeValue);
+ break;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel2007/Theme.php b/extend/PHPExcel/PHPExcel/Reader/Excel2007/Theme.php
new file mode 100755
index 0000000..134f4b6
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel2007/Theme.php
@@ -0,0 +1,127 @@
+themeName = $themeName;
+ $this->colourSchemeName = $colourSchemeName;
+ $this->colourMap = $colourMap;
+ }
+
+ /**
+ * Get Theme Name
+ *
+ * @return string
+ */
+ public function getThemeName()
+ {
+ return $this->themeName;
+ }
+
+ /**
+ * Get colour Scheme Name
+ *
+ * @return string
+ */
+ public function getColourSchemeName()
+ {
+ return $this->colourSchemeName;
+ }
+
+ /**
+ * Get colour Map Value by Position
+ *
+ * @return string
+ */
+ public function getColourByIndex($index = 0)
+ {
+ if (isset($this->colourMap[$index])) {
+ return $this->colourMap[$index];
+ }
+ return null;
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if ((is_object($value)) && ($key != '_parent')) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5.php b/extend/PHPExcel/PHPExcel/Reader/Excel5.php
new file mode 100755
index 0000000..62e971d
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5.php
@@ -0,0 +1,7594 @@
+data
+ *
+ * @var int
+ */
+ private $dataSize;
+
+ /**
+ * Current position in stream
+ *
+ * @var integer
+ */
+ private $pos;
+
+ /**
+ * Workbook to be returned by the reader.
+ *
+ * @var PHPExcel
+ */
+ private $phpExcel;
+
+ /**
+ * Worksheet that is currently being built by the reader.
+ *
+ * @var PHPExcel_Worksheet
+ */
+ private $phpSheet;
+
+ /**
+ * BIFF version
+ *
+ * @var int
+ */
+ private $version;
+
+ /**
+ * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
+ * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
+ *
+ * @var string
+ */
+ private $codepage;
+
+ /**
+ * Shared formats
+ *
+ * @var array
+ */
+ private $formats;
+
+ /**
+ * Shared fonts
+ *
+ * @var array
+ */
+ private $objFonts;
+
+ /**
+ * Color palette
+ *
+ * @var array
+ */
+ private $palette;
+
+ /**
+ * Worksheets
+ *
+ * @var array
+ */
+ private $sheets;
+
+ /**
+ * External books
+ *
+ * @var array
+ */
+ private $externalBooks;
+
+ /**
+ * REF structures. Only applies to BIFF8.
+ *
+ * @var array
+ */
+ private $ref;
+
+ /**
+ * External names
+ *
+ * @var array
+ */
+ private $externalNames;
+
+ /**
+ * Defined names
+ *
+ * @var array
+ */
+ private $definedname;
+
+ /**
+ * Shared strings. Only applies to BIFF8.
+ *
+ * @var array
+ */
+ private $sst;
+
+ /**
+ * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
+ *
+ * @var boolean
+ */
+ private $frozen;
+
+ /**
+ * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
+ *
+ * @var boolean
+ */
+ private $isFitToPages;
+
+ /**
+ * Objects. One OBJ record contributes with one entry.
+ *
+ * @var array
+ */
+ private $objs;
+
+ /**
+ * Text Objects. One TXO record corresponds with one entry.
+ *
+ * @var array
+ */
+ private $textObjects;
+
+ /**
+ * Cell Annotations (BIFF8)
+ *
+ * @var array
+ */
+ private $cellNotes;
+
+ /**
+ * The combined MSODRAWINGGROUP data
+ *
+ * @var string
+ */
+ private $drawingGroupData;
+
+ /**
+ * The combined MSODRAWING data (per sheet)
+ *
+ * @var string
+ */
+ private $drawingData;
+
+ /**
+ * Keep track of XF index
+ *
+ * @var int
+ */
+ private $xfIndex;
+
+ /**
+ * Mapping of XF index (that is a cell XF) to final index in cellXf collection
+ *
+ * @var array
+ */
+ private $mapCellXfIndex;
+
+ /**
+ * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
+ *
+ * @var array
+ */
+ private $mapCellStyleXfIndex;
+
+ /**
+ * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
+ *
+ * @var array
+ */
+ private $sharedFormulas;
+
+ /**
+ * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
+ * refers to a shared formula.
+ *
+ * @var array
+ */
+ private $sharedFormulaParts;
+
+ /**
+ * The type of encryption in use
+ *
+ * @var int
+ */
+ private $encryption = 0;
+
+ /**
+ * The position in the stream after which contents are encrypted
+ *
+ * @var int
+ */
+ private $encryptionStartPos = false;
+
+ /**
+ * The current RC4 decryption object
+ *
+ * @var PHPExcel_Reader_Excel5_RC4
+ */
+ private $rc4Key = null;
+
+ /**
+ * The position in the stream that the RC4 decryption object was left at
+ *
+ * @var int
+ */
+ private $rc4Pos = 0;
+
+ /**
+ * The current MD5 context state
+ *
+ * @var string
+ */
+ private $md5Ctxt = null;
+
+ /**
+ * Create a new PHPExcel_Reader_Excel5 instance
+ */
+ public function __construct()
+ {
+ $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ }
+
+ /**
+ * Can the current PHPExcel_Reader_IReader read the file?
+ *
+ * @param string $pFilename
+ * @return boolean
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function canRead($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ try {
+ // Use ParseXL for the hard work.
+ $ole = new PHPExcel_Shared_OLERead();
+
+ // get excel data
+ $res = $ole->read($pFilename);
+ return true;
+ } catch (PHPExcel_Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetNames($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $worksheetNames = array();
+
+ // Read the OLE file
+ $this->loadOLE($pFilename);
+
+ // total byte size of Excel data (workbook global substream + sheet substreams)
+ $this->dataSize = strlen($this->data);
+
+ $this->pos = 0;
+ $this->sheets = array();
+
+ // Parse Workbook Global Substream
+ while ($this->pos < $this->dataSize) {
+ $code = self::getInt2d($this->data, $this->pos);
+
+ switch ($code) {
+ case self::XLS_TYPE_BOF:
+ $this->readBof();
+ break;
+ case self::XLS_TYPE_SHEET:
+ $this->readSheet();
+ break;
+ case self::XLS_TYPE_EOF:
+ $this->readDefault();
+ break 2;
+ default:
+ $this->readDefault();
+ break;
+ }
+ }
+
+ foreach ($this->sheets as $sheet) {
+ if ($sheet['sheetType'] != 0x00) {
+ // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
+ continue;
+ }
+
+ $worksheetNames[] = $sheet['name'];
+ }
+
+ return $worksheetNames;
+ }
+
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $worksheetInfo = array();
+
+ // Read the OLE file
+ $this->loadOLE($pFilename);
+
+ // total byte size of Excel data (workbook global substream + sheet substreams)
+ $this->dataSize = strlen($this->data);
+
+ // initialize
+ $this->pos = 0;
+ $this->sheets = array();
+
+ // Parse Workbook Global Substream
+ while ($this->pos < $this->dataSize) {
+ $code = self::getInt2d($this->data, $this->pos);
+
+ switch ($code) {
+ case self::XLS_TYPE_BOF:
+ $this->readBof();
+ break;
+ case self::XLS_TYPE_SHEET:
+ $this->readSheet();
+ break;
+ case self::XLS_TYPE_EOF:
+ $this->readDefault();
+ break 2;
+ default:
+ $this->readDefault();
+ break;
+ }
+ }
+
+ // Parse the individual sheets
+ foreach ($this->sheets as $sheet) {
+ if ($sheet['sheetType'] != 0x00) {
+ // 0x00: Worksheet
+ // 0x02: Chart
+ // 0x06: Visual Basic module
+ continue;
+ }
+
+ $tmpInfo = array();
+ $tmpInfo['worksheetName'] = $sheet['name'];
+ $tmpInfo['lastColumnLetter'] = 'A';
+ $tmpInfo['lastColumnIndex'] = 0;
+ $tmpInfo['totalRows'] = 0;
+ $tmpInfo['totalColumns'] = 0;
+
+ $this->pos = $sheet['offset'];
+
+ while ($this->pos <= $this->dataSize - 4) {
+ $code = self::getInt2d($this->data, $this->pos);
+
+ switch ($code) {
+ case self::XLS_TYPE_RK:
+ case self::XLS_TYPE_LABELSST:
+ case self::XLS_TYPE_NUMBER:
+ case self::XLS_TYPE_FORMULA:
+ case self::XLS_TYPE_BOOLERR:
+ case self::XLS_TYPE_LABEL:
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ $rowIndex = self::getInt2d($recordData, 0) + 1;
+ $columnIndex = self::getInt2d($recordData, 2);
+
+ $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+ $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+ break;
+ case self::XLS_TYPE_BOF:
+ $this->readBof();
+ break;
+ case self::XLS_TYPE_EOF:
+ $this->readDefault();
+ break 2;
+ default:
+ $this->readDefault();
+ break;
+ }
+ }
+
+ $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+ $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+ $worksheetInfo[] = $tmpInfo;
+ }
+
+ return $worksheetInfo;
+ }
+
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Read the OLE file
+ $this->loadOLE($pFilename);
+
+ // Initialisations
+ $this->phpExcel = new PHPExcel;
+ $this->phpExcel->removeSheetByIndex(0); // remove 1st sheet
+ if (!$this->readDataOnly) {
+ $this->phpExcel->removeCellStyleXfByIndex(0); // remove the default style
+ $this->phpExcel->removeCellXfByIndex(0); // remove the default style
+ }
+
+ // Read the summary information stream (containing meta data)
+ $this->readSummaryInformation();
+
+ // Read the Additional document summary information stream (containing application-specific meta data)
+ $this->readDocumentSummaryInformation();
+
+ // total byte size of Excel data (workbook global substream + sheet substreams)
+ $this->dataSize = strlen($this->data);
+
+ // initialize
+ $this->pos = 0;
+ $this->codepage = 'CP1252';
+ $this->formats = array();
+ $this->objFonts = array();
+ $this->palette = array();
+ $this->sheets = array();
+ $this->externalBooks = array();
+ $this->ref = array();
+ $this->definedname = array();
+ $this->sst = array();
+ $this->drawingGroupData = '';
+ $this->xfIndex = '';
+ $this->mapCellXfIndex = array();
+ $this->mapCellStyleXfIndex = array();
+
+ // Parse Workbook Global Substream
+ while ($this->pos < $this->dataSize) {
+ $code = self::getInt2d($this->data, $this->pos);
+
+ switch ($code) {
+ case self::XLS_TYPE_BOF:
+ $this->readBof();
+ break;
+ case self::XLS_TYPE_FILEPASS:
+ $this->readFilepass();
+ break;
+ case self::XLS_TYPE_CODEPAGE:
+ $this->readCodepage();
+ break;
+ case self::XLS_TYPE_DATEMODE:
+ $this->readDateMode();
+ break;
+ case self::XLS_TYPE_FONT:
+ $this->readFont();
+ break;
+ case self::XLS_TYPE_FORMAT:
+ $this->readFormat();
+ break;
+ case self::XLS_TYPE_XF:
+ $this->readXf();
+ break;
+ case self::XLS_TYPE_XFEXT:
+ $this->readXfExt();
+ break;
+ case self::XLS_TYPE_STYLE:
+ $this->readStyle();
+ break;
+ case self::XLS_TYPE_PALETTE:
+ $this->readPalette();
+ break;
+ case self::XLS_TYPE_SHEET:
+ $this->readSheet();
+ break;
+ case self::XLS_TYPE_EXTERNALBOOK:
+ $this->readExternalBook();
+ break;
+ case self::XLS_TYPE_EXTERNNAME:
+ $this->readExternName();
+ break;
+ case self::XLS_TYPE_EXTERNSHEET:
+ $this->readExternSheet();
+ break;
+ case self::XLS_TYPE_DEFINEDNAME:
+ $this->readDefinedName();
+ break;
+ case self::XLS_TYPE_MSODRAWINGGROUP:
+ $this->readMsoDrawingGroup();
+ break;
+ case self::XLS_TYPE_SST:
+ $this->readSst();
+ break;
+ case self::XLS_TYPE_EOF:
+ $this->readDefault();
+ break 2;
+ default:
+ $this->readDefault();
+ break;
+ }
+ }
+
+ // Resolve indexed colors for font, fill, and border colors
+ // Cannot be resolved already in XF record, because PALETTE record comes afterwards
+ if (!$this->readDataOnly) {
+ foreach ($this->objFonts as $objFont) {
+ if (isset($objFont->colorIndex)) {
+ $color = PHPExcel_Reader_Excel5_Color::map($objFont->colorIndex, $this->palette, $this->version);
+ $objFont->getColor()->setRGB($color['rgb']);
+ }
+ }
+
+ foreach ($this->phpExcel->getCellXfCollection() as $objStyle) {
+ // fill start and end color
+ $fill = $objStyle->getFill();
+
+ if (isset($fill->startcolorIndex)) {
+ $startColor = PHPExcel_Reader_Excel5_Color::map($fill->startcolorIndex, $this->palette, $this->version);
+ $fill->getStartColor()->setRGB($startColor['rgb']);
+ }
+ if (isset($fill->endcolorIndex)) {
+ $endColor = PHPExcel_Reader_Excel5_Color::map($fill->endcolorIndex, $this->palette, $this->version);
+ $fill->getEndColor()->setRGB($endColor['rgb']);
+ }
+
+ // border colors
+ $top = $objStyle->getBorders()->getTop();
+ $right = $objStyle->getBorders()->getRight();
+ $bottom = $objStyle->getBorders()->getBottom();
+ $left = $objStyle->getBorders()->getLeft();
+ $diagonal = $objStyle->getBorders()->getDiagonal();
+
+ if (isset($top->colorIndex)) {
+ $borderTopColor = PHPExcel_Reader_Excel5_Color::map($top->colorIndex, $this->palette, $this->version);
+ $top->getColor()->setRGB($borderTopColor['rgb']);
+ }
+ if (isset($right->colorIndex)) {
+ $borderRightColor = PHPExcel_Reader_Excel5_Color::map($right->colorIndex, $this->palette, $this->version);
+ $right->getColor()->setRGB($borderRightColor['rgb']);
+ }
+ if (isset($bottom->colorIndex)) {
+ $borderBottomColor = PHPExcel_Reader_Excel5_Color::map($bottom->colorIndex, $this->palette, $this->version);
+ $bottom->getColor()->setRGB($borderBottomColor['rgb']);
+ }
+ if (isset($left->colorIndex)) {
+ $borderLeftColor = PHPExcel_Reader_Excel5_Color::map($left->colorIndex, $this->palette, $this->version);
+ $left->getColor()->setRGB($borderLeftColor['rgb']);
+ }
+ if (isset($diagonal->colorIndex)) {
+ $borderDiagonalColor = PHPExcel_Reader_Excel5_Color::map($diagonal->colorIndex, $this->palette, $this->version);
+ $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
+ }
+ }
+ }
+
+ // treat MSODRAWINGGROUP records, workbook-level Escher
+ if (!$this->readDataOnly && $this->drawingGroupData) {
+ $escherWorkbook = new PHPExcel_Shared_Escher();
+ $reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
+ $escherWorkbook = $reader->load($this->drawingGroupData);
+
+ // debug Escher stream
+ //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
+ //$debug->load($this->drawingGroupData);
+ }
+
+ // Parse the individual sheets
+ foreach ($this->sheets as $sheet) {
+ if ($sheet['sheetType'] != 0x00) {
+ // 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
+ continue;
+ }
+
+ // check if sheet should be skipped
+ if (isset($this->loadSheetsOnly) && !in_array($sheet['name'], $this->loadSheetsOnly)) {
+ continue;
+ }
+
+ // add sheet to PHPExcel object
+ $this->phpSheet = $this->phpExcel->createSheet();
+ // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
+ // cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
+ // name in line with the formula, not the reverse
+ $this->phpSheet->setTitle($sheet['name'], false);
+ $this->phpSheet->setSheetState($sheet['sheetState']);
+
+ $this->pos = $sheet['offset'];
+
+ // Initialize isFitToPages. May change after reading SHEETPR record.
+ $this->isFitToPages = false;
+
+ // Initialize drawingData
+ $this->drawingData = '';
+
+ // Initialize objs
+ $this->objs = array();
+
+ // Initialize shared formula parts
+ $this->sharedFormulaParts = array();
+
+ // Initialize shared formulas
+ $this->sharedFormulas = array();
+
+ // Initialize text objs
+ $this->textObjects = array();
+
+ // Initialize cell annotations
+ $this->cellNotes = array();
+ $this->textObjRef = -1;
+
+ while ($this->pos <= $this->dataSize - 4) {
+ $code = self::getInt2d($this->data, $this->pos);
+
+ switch ($code) {
+ case self::XLS_TYPE_BOF:
+ $this->readBof();
+ break;
+ case self::XLS_TYPE_PRINTGRIDLINES:
+ $this->readPrintGridlines();
+ break;
+ case self::XLS_TYPE_DEFAULTROWHEIGHT:
+ $this->readDefaultRowHeight();
+ break;
+ case self::XLS_TYPE_SHEETPR:
+ $this->readSheetPr();
+ break;
+ case self::XLS_TYPE_HORIZONTALPAGEBREAKS:
+ $this->readHorizontalPageBreaks();
+ break;
+ case self::XLS_TYPE_VERTICALPAGEBREAKS:
+ $this->readVerticalPageBreaks();
+ break;
+ case self::XLS_TYPE_HEADER:
+ $this->readHeader();
+ break;
+ case self::XLS_TYPE_FOOTER:
+ $this->readFooter();
+ break;
+ case self::XLS_TYPE_HCENTER:
+ $this->readHcenter();
+ break;
+ case self::XLS_TYPE_VCENTER:
+ $this->readVcenter();
+ break;
+ case self::XLS_TYPE_LEFTMARGIN:
+ $this->readLeftMargin();
+ break;
+ case self::XLS_TYPE_RIGHTMARGIN:
+ $this->readRightMargin();
+ break;
+ case self::XLS_TYPE_TOPMARGIN:
+ $this->readTopMargin();
+ break;
+ case self::XLS_TYPE_BOTTOMMARGIN:
+ $this->readBottomMargin();
+ break;
+ case self::XLS_TYPE_PAGESETUP:
+ $this->readPageSetup();
+ break;
+ case self::XLS_TYPE_PROTECT:
+ $this->readProtect();
+ break;
+ case self::XLS_TYPE_SCENPROTECT:
+ $this->readScenProtect();
+ break;
+ case self::XLS_TYPE_OBJECTPROTECT:
+ $this->readObjectProtect();
+ break;
+ case self::XLS_TYPE_PASSWORD:
+ $this->readPassword();
+ break;
+ case self::XLS_TYPE_DEFCOLWIDTH:
+ $this->readDefColWidth();
+ break;
+ case self::XLS_TYPE_COLINFO:
+ $this->readColInfo();
+ break;
+ case self::XLS_TYPE_DIMENSION:
+ $this->readDefault();
+ break;
+ case self::XLS_TYPE_ROW:
+ $this->readRow();
+ break;
+ case self::XLS_TYPE_DBCELL:
+ $this->readDefault();
+ break;
+ case self::XLS_TYPE_RK:
+ $this->readRk();
+ break;
+ case self::XLS_TYPE_LABELSST:
+ $this->readLabelSst();
+ break;
+ case self::XLS_TYPE_MULRK:
+ $this->readMulRk();
+ break;
+ case self::XLS_TYPE_NUMBER:
+ $this->readNumber();
+ break;
+ case self::XLS_TYPE_FORMULA:
+ $this->readFormula();
+ break;
+ case self::XLS_TYPE_SHAREDFMLA:
+ $this->readSharedFmla();
+ break;
+ case self::XLS_TYPE_BOOLERR:
+ $this->readBoolErr();
+ break;
+ case self::XLS_TYPE_MULBLANK:
+ $this->readMulBlank();
+ break;
+ case self::XLS_TYPE_LABEL:
+ $this->readLabel();
+ break;
+ case self::XLS_TYPE_BLANK:
+ $this->readBlank();
+ break;
+ case self::XLS_TYPE_MSODRAWING:
+ $this->readMsoDrawing();
+ break;
+ case self::XLS_TYPE_OBJ:
+ $this->readObj();
+ break;
+ case self::XLS_TYPE_WINDOW2:
+ $this->readWindow2();
+ break;
+ case self::XLS_TYPE_PAGELAYOUTVIEW:
+ $this->readPageLayoutView();
+ break;
+ case self::XLS_TYPE_SCL:
+ $this->readScl();
+ break;
+ case self::XLS_TYPE_PANE:
+ $this->readPane();
+ break;
+ case self::XLS_TYPE_SELECTION:
+ $this->readSelection();
+ break;
+ case self::XLS_TYPE_MERGEDCELLS:
+ $this->readMergedCells();
+ break;
+ case self::XLS_TYPE_HYPERLINK:
+ $this->readHyperLink();
+ break;
+ case self::XLS_TYPE_DATAVALIDATIONS:
+ $this->readDataValidations();
+ break;
+ case self::XLS_TYPE_DATAVALIDATION:
+ $this->readDataValidation();
+ break;
+ case self::XLS_TYPE_SHEETLAYOUT:
+ $this->readSheetLayout();
+ break;
+ case self::XLS_TYPE_SHEETPROTECTION:
+ $this->readSheetProtection();
+ break;
+ case self::XLS_TYPE_RANGEPROTECTION:
+ $this->readRangeProtection();
+ break;
+ case self::XLS_TYPE_NOTE:
+ $this->readNote();
+ break;
+ //case self::XLS_TYPE_IMDATA: $this->readImData(); break;
+ case self::XLS_TYPE_TXO:
+ $this->readTextObject();
+ break;
+ case self::XLS_TYPE_CONTINUE:
+ $this->readContinue();
+ break;
+ case self::XLS_TYPE_EOF:
+ $this->readDefault();
+ break 2;
+ default:
+ $this->readDefault();
+ break;
+ }
+
+ }
+
+ // treat MSODRAWING records, sheet-level Escher
+ if (!$this->readDataOnly && $this->drawingData) {
+ $escherWorksheet = new PHPExcel_Shared_Escher();
+ $reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
+ $escherWorksheet = $reader->load($this->drawingData);
+
+ // debug Escher stream
+ //$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
+ //$debug->load($this->drawingData);
+
+ // get all spContainers in one long array, so they can be mapped to OBJ records
+ $allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
+ }
+
+ // treat OBJ records
+ foreach ($this->objs as $n => $obj) {
+// echo 'Object reference is ', $n,' ';
+// var_dump($obj);
+// echo ' ';
+
+ // the first shape container never has a corresponding OBJ record, hence $n + 1
+ if (isset($allSpContainers[$n + 1]) && is_object($allSpContainers[$n + 1])) {
+ $spContainer = $allSpContainers[$n + 1];
+
+ // we skip all spContainers that are a part of a group shape since we cannot yet handle those
+ if ($spContainer->getNestingLevel() > 1) {
+ continue;
+ }
+
+ // calculate the width and height of the shape
+ list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
+ list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
+
+ $startOffsetX = $spContainer->getStartOffsetX();
+ $startOffsetY = $spContainer->getStartOffsetY();
+ $endOffsetX = $spContainer->getEndOffsetX();
+ $endOffsetY = $spContainer->getEndOffsetY();
+
+ $width = PHPExcel_Shared_Excel5::getDistanceX($this->phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
+ $height = PHPExcel_Shared_Excel5::getDistanceY($this->phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
+
+ // calculate offsetX and offsetY of the shape
+ $offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->phpSheet, $startColumn) / 1024;
+ $offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->phpSheet, $startRow) / 256;
+
+ switch ($obj['otObjType']) {
+ case 0x19:
+ // Note
+// echo 'Cell Annotation Object ';
+// echo 'Object ID is ', $obj['idObjID'],' ';
+ if (isset($this->cellNotes[$obj['idObjID']])) {
+ $cellNote = $this->cellNotes[$obj['idObjID']];
+
+ if (isset($this->textObjects[$obj['idObjID']])) {
+ $textObject = $this->textObjects[$obj['idObjID']];
+ $this->cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
+ }
+ }
+ break;
+ case 0x08:
+// echo 'Picture Object ';
+ // picture
+ // get index to BSE entry (1-based)
+ $BSEindex = $spContainer->getOPT(0x0104);
+ $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
+ $BSE = $BSECollection[$BSEindex - 1];
+ $blipType = $BSE->getBlipType();
+
+ // need check because some blip types are not supported by Escher reader such as EMF
+ if ($blip = $BSE->getBlip()) {
+ $ih = imagecreatefromstring($blip->getData());
+ $drawing = new PHPExcel_Worksheet_MemoryDrawing();
+ $drawing->setImageResource($ih);
+
+ // width, height, offsetX, offsetY
+ $drawing->setResizeProportional(false);
+ $drawing->setWidth($width);
+ $drawing->setHeight($height);
+ $drawing->setOffsetX($offsetX);
+ $drawing->setOffsetY($offsetY);
+
+ switch ($blipType) {
+ case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
+ $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
+ $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
+ break;
+ case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
+ $drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
+ $drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
+ break;
+ }
+
+ $drawing->setWorksheet($this->phpSheet);
+ $drawing->setCoordinates($spContainer->getStartCoordinates());
+ }
+ break;
+ default:
+ // other object type
+ break;
+ }
+ }
+ }
+
+ // treat SHAREDFMLA records
+ if ($this->version == self::XLS_BIFF8) {
+ foreach ($this->sharedFormulaParts as $cell => $baseCell) {
+ list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($column, $row, $this->phpSheet->getTitle())) {
+ $formula = $this->getFormulaFromStructure($this->sharedFormulas[$baseCell], $cell);
+ $this->phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
+ }
+ }
+ }
+
+ if (!empty($this->cellNotes)) {
+ foreach ($this->cellNotes as $note => $noteDetails) {
+ if (!isset($noteDetails['objTextData'])) {
+ if (isset($this->textObjects[$note])) {
+ $textObject = $this->textObjects[$note];
+ $noteDetails['objTextData'] = $textObject;
+ } else {
+ $noteDetails['objTextData']['text'] = '';
+ }
+ }
+// echo 'Cell annotation ', $note,' ';
+// var_dump($noteDetails);
+// echo ' ';
+ $cellAddress = str_replace('$', '', $noteDetails['cellRef']);
+ $this->phpSheet->getComment($cellAddress)->setAuthor($noteDetails['author'])->setText($this->parseRichText($noteDetails['objTextData']['text']));
+ }
+ }
+ }
+
+ // add the named ranges (defined names)
+ foreach ($this->definedname as $definedName) {
+ if ($definedName['isBuiltInName']) {
+ switch ($definedName['name']) {
+ case pack('C', 0x06):
+ // print area
+ // in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
+ $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
+
+ $extractedRanges = array();
+ foreach ($ranges as $range) {
+ // $range should look like one of these
+ // Foo!$C$7:$J$66
+ // Bar!$A$1:$IV$2
+ $explodes = explode('!', $range); // FIXME: what if sheetname contains exclamation mark?
+ $sheetName = trim($explodes[0], "'");
+ if (count($explodes) == 2) {
+ if (strpos($explodes[1], ':') === false) {
+ $explodes[1] = $explodes[1] . ':' . $explodes[1];
+ }
+ $extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
+ }
+ }
+ if ($docSheet = $this->phpExcel->getSheetByName($sheetName)) {
+ $docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
+ }
+ break;
+ case pack('C', 0x07):
+ // print titles (repeating rows)
+ // Assuming BIFF8, there are 3 cases
+ // 1. repeating rows
+ // formula looks like this: Sheet!$A$1:$IV$2
+ // rows 1-2 repeat
+ // 2. repeating columns
+ // formula looks like this: Sheet!$A$1:$B$65536
+ // columns A-B repeat
+ // 3. both repeating rows and repeating columns
+ // formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
+ $ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
+ foreach ($ranges as $range) {
+ // $range should look like this one of these
+ // Sheet!$A$1:$B$65536
+ // Sheet!$A$1:$IV$2
+ $explodes = explode('!', $range);
+ if (count($explodes) == 2) {
+ if ($docSheet = $this->phpExcel->getSheetByName($explodes[0])) {
+ $extractedRange = $explodes[1];
+ $extractedRange = str_replace('$', '', $extractedRange);
+
+ $coordinateStrings = explode(':', $extractedRange);
+ if (count($coordinateStrings) == 2) {
+ list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
+ list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
+
+ if ($firstColumn == 'A' and $lastColumn == 'IV') {
+ // then we have repeating rows
+ $docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
+ } elseif ($firstRow == 1 and $lastRow == 65536) {
+ // then we have repeating columns
+ $docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ } else {
+ // Extract range
+ $explodes = explode('!', $definedName['formula']);
+
+ if (count($explodes) == 2) {
+ if (($docSheet = $this->phpExcel->getSheetByName($explodes[0])) ||
+ ($docSheet = $this->phpExcel->getSheetByName(trim($explodes[0], "'")))) {
+ $extractedRange = $explodes[1];
+ $extractedRange = str_replace('$', '', $extractedRange);
+
+ $localOnly = ($definedName['scope'] == 0) ? false : true;
+
+ $scope = ($definedName['scope'] == 0) ? null : $this->phpExcel->getSheetByName($this->sheets[$definedName['scope'] - 1]['name']);
+
+ $this->phpExcel->addNamedRange(new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope));
+ }
+ } else {
+ // Named Value
+ // TODO Provide support for named values
+ }
+ }
+ }
+ $this->data = null;
+
+ return $this->phpExcel;
+ }
+
+ /**
+ * Read record data from stream, decrypting as required
+ *
+ * @param string $data Data stream to read from
+ * @param int $pos Position to start reading from
+ * @param int $length Record data length
+ *
+ * @return string Record data
+ */
+ private function readRecordData($data, $pos, $len)
+ {
+ $data = substr($data, $pos, $len);
+
+ // File not encrypted, or record before encryption start point
+ if ($this->encryption == self::MS_BIFF_CRYPTO_NONE || $pos < $this->encryptionStartPos) {
+ return $data;
+ }
+
+ $recordData = '';
+ if ($this->encryption == self::MS_BIFF_CRYPTO_RC4) {
+ $oldBlock = floor($this->rc4Pos / self::REKEY_BLOCK);
+ $block = floor($pos / self::REKEY_BLOCK);
+ $endBlock = floor(($pos + $len) / self::REKEY_BLOCK);
+
+ // Spin an RC4 decryptor to the right spot. If we have a decryptor sitting
+ // at a point earlier in the current block, re-use it as we can save some time.
+ if ($block != $oldBlock || $pos < $this->rc4Pos || !$this->rc4Key) {
+ $this->rc4Key = $this->makeKey($block, $this->md5Ctxt);
+ $step = $pos % self::REKEY_BLOCK;
+ } else {
+ $step = $pos - $this->rc4Pos;
+ }
+ $this->rc4Key->RC4(str_repeat("\0", $step));
+
+ // Decrypt record data (re-keying at the end of every block)
+ while ($block != $endBlock) {
+ $step = self::REKEY_BLOCK - ($pos % self::REKEY_BLOCK);
+ $recordData .= $this->rc4Key->RC4(substr($data, 0, $step));
+ $data = substr($data, $step);
+ $pos += $step;
+ $len -= $step;
+ $block++;
+ $this->rc4Key = $this->makeKey($block, $this->md5Ctxt);
+ }
+ $recordData .= $this->rc4Key->RC4(substr($data, 0, $len));
+
+ // Keep track of the position of this decryptor.
+ // We'll try and re-use it later if we can to speed things up
+ $this->rc4Pos = $pos + $len;
+ } elseif ($this->encryption == self::MS_BIFF_CRYPTO_XOR) {
+ throw new PHPExcel_Reader_Exception('XOr encryption not supported');
+ }
+ return $recordData;
+ }
+
+ /**
+ * Use OLE reader to extract the relevant data streams from the OLE file
+ *
+ * @param string $pFilename
+ */
+ private function loadOLE($pFilename)
+ {
+ // OLE reader
+ $ole = new PHPExcel_Shared_OLERead();
+ // get excel data,
+ $res = $ole->read($pFilename);
+ // Get workbook data: workbook stream + sheet streams
+ $this->data = $ole->getStream($ole->wrkbook);
+ // Get summary information data
+ $this->summaryInformation = $ole->getStream($ole->summaryInformation);
+ // Get additional document summary information data
+ $this->documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
+ // Get user-defined property data
+// $this->userDefinedProperties = $ole->getUserDefinedProperties();
+ }
+
+
+ /**
+ * Read summary information
+ */
+ private function readSummaryInformation()
+ {
+ if (!isset($this->summaryInformation)) {
+ return;
+ }
+
+ // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
+ // offset: 2; size: 2;
+ // offset: 4; size: 2; OS version
+ // offset: 6; size: 2; OS indicator
+ // offset: 8; size: 16
+ // offset: 24; size: 4; section count
+ $secCount = self::getInt4d($this->summaryInformation, 24);
+
+ // offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
+ // offset: 44; size: 4
+ $secOffset = self::getInt4d($this->summaryInformation, 44);
+
+ // section header
+ // offset: $secOffset; size: 4; section length
+ $secLength = self::getInt4d($this->summaryInformation, $secOffset);
+
+ // offset: $secOffset+4; size: 4; property count
+ $countProperties = self::getInt4d($this->summaryInformation, $secOffset+4);
+
+ // initialize code page (used to resolve string values)
+ $codePage = 'CP1252';
+
+ // offset: ($secOffset+8); size: var
+ // loop through property decarations and properties
+ for ($i = 0; $i < $countProperties; ++$i) {
+ // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
+ $id = self::getInt4d($this->summaryInformation, ($secOffset+8) + (8 * $i));
+
+ // Use value of property id as appropriate
+ // offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
+ $offset = self::getInt4d($this->summaryInformation, ($secOffset+12) + (8 * $i));
+
+ $type = self::getInt4d($this->summaryInformation, $secOffset + $offset);
+
+ // initialize property value
+ $value = null;
+
+ // extract property value based on property type
+ switch ($type) {
+ case 0x02: // 2 byte signed integer
+ $value = self::getInt2d($this->summaryInformation, $secOffset + 4 + $offset);
+ break;
+ case 0x03: // 4 byte signed integer
+ $value = self::getInt4d($this->summaryInformation, $secOffset + 4 + $offset);
+ break;
+ case 0x13: // 4 byte unsigned integer
+ // not needed yet, fix later if necessary
+ break;
+ case 0x1E: // null-terminated string prepended by dword string length
+ $byteLength = self::getInt4d($this->summaryInformation, $secOffset + 4 + $offset);
+ $value = substr($this->summaryInformation, $secOffset + 8 + $offset, $byteLength);
+ $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
+ $value = rtrim($value);
+ break;
+ case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
+ // PHP-time
+ $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->summaryInformation, $secOffset + 4 + $offset, 8));
+ break;
+ case 0x47: // Clipboard format
+ // not needed yet, fix later if necessary
+ break;
+ }
+
+ switch ($id) {
+ case 0x01: // Code Page
+ $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
+ break;
+ case 0x02: // Title
+ $this->phpExcel->getProperties()->setTitle($value);
+ break;
+ case 0x03: // Subject
+ $this->phpExcel->getProperties()->setSubject($value);
+ break;
+ case 0x04: // Author (Creator)
+ $this->phpExcel->getProperties()->setCreator($value);
+ break;
+ case 0x05: // Keywords
+ $this->phpExcel->getProperties()->setKeywords($value);
+ break;
+ case 0x06: // Comments (Description)
+ $this->phpExcel->getProperties()->setDescription($value);
+ break;
+ case 0x07: // Template
+ // Not supported by PHPExcel
+ break;
+ case 0x08: // Last Saved By (LastModifiedBy)
+ $this->phpExcel->getProperties()->setLastModifiedBy($value);
+ break;
+ case 0x09: // Revision
+ // Not supported by PHPExcel
+ break;
+ case 0x0A: // Total Editing Time
+ // Not supported by PHPExcel
+ break;
+ case 0x0B: // Last Printed
+ // Not supported by PHPExcel
+ break;
+ case 0x0C: // Created Date/Time
+ $this->phpExcel->getProperties()->setCreated($value);
+ break;
+ case 0x0D: // Modified Date/Time
+ $this->phpExcel->getProperties()->setModified($value);
+ break;
+ case 0x0E: // Number of Pages
+ // Not supported by PHPExcel
+ break;
+ case 0x0F: // Number of Words
+ // Not supported by PHPExcel
+ break;
+ case 0x10: // Number of Characters
+ // Not supported by PHPExcel
+ break;
+ case 0x11: // Thumbnail
+ // Not supported by PHPExcel
+ break;
+ case 0x12: // Name of creating application
+ // Not supported by PHPExcel
+ break;
+ case 0x13: // Security
+ // Not supported by PHPExcel
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Read additional document summary information
+ */
+ private function readDocumentSummaryInformation()
+ {
+ if (!isset($this->documentSummaryInformation)) {
+ return;
+ }
+
+ // offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
+ // offset: 2; size: 2;
+ // offset: 4; size: 2; OS version
+ // offset: 6; size: 2; OS indicator
+ // offset: 8; size: 16
+ // offset: 24; size: 4; section count
+ $secCount = self::getInt4d($this->documentSummaryInformation, 24);
+// echo '$secCount = ', $secCount,' ';
+
+ // offset: 28; size: 16; first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
+ // offset: 44; size: 4; first section offset
+ $secOffset = self::getInt4d($this->documentSummaryInformation, 44);
+// echo '$secOffset = ', $secOffset,' ';
+
+ // section header
+ // offset: $secOffset; size: 4; section length
+ $secLength = self::getInt4d($this->documentSummaryInformation, $secOffset);
+// echo '$secLength = ', $secLength,' ';
+
+ // offset: $secOffset+4; size: 4; property count
+ $countProperties = self::getInt4d($this->documentSummaryInformation, $secOffset+4);
+// echo '$countProperties = ', $countProperties,' ';
+
+ // initialize code page (used to resolve string values)
+ $codePage = 'CP1252';
+
+ // offset: ($secOffset+8); size: var
+ // loop through property decarations and properties
+ for ($i = 0; $i < $countProperties; ++$i) {
+// echo 'Property ', $i,' ';
+ // offset: ($secOffset+8) + (8 * $i); size: 4; property ID
+ $id = self::getInt4d($this->documentSummaryInformation, ($secOffset+8) + (8 * $i));
+// echo 'ID is ', $id,' ';
+
+ // Use value of property id as appropriate
+ // offset: 60 + 8 * $i; size: 4; offset from beginning of section (48)
+ $offset = self::getInt4d($this->documentSummaryInformation, ($secOffset+12) + (8 * $i));
+
+ $type = self::getInt4d($this->documentSummaryInformation, $secOffset + $offset);
+// echo 'Type is ', $type,', ';
+
+ // initialize property value
+ $value = null;
+
+ // extract property value based on property type
+ switch ($type) {
+ case 0x02: // 2 byte signed integer
+ $value = self::getInt2d($this->documentSummaryInformation, $secOffset + 4 + $offset);
+ break;
+ case 0x03: // 4 byte signed integer
+ $value = self::getInt4d($this->documentSummaryInformation, $secOffset + 4 + $offset);
+ break;
+ case 0x0B: // Boolean
+ $value = self::getInt2d($this->documentSummaryInformation, $secOffset + 4 + $offset);
+ $value = ($value == 0 ? false : true);
+ break;
+ case 0x13: // 4 byte unsigned integer
+ // not needed yet, fix later if necessary
+ break;
+ case 0x1E: // null-terminated string prepended by dword string length
+ $byteLength = self::getInt4d($this->documentSummaryInformation, $secOffset + 4 + $offset);
+ $value = substr($this->documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
+ $value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
+ $value = rtrim($value);
+ break;
+ case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
+ // PHP-Time
+ $value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->documentSummaryInformation, $secOffset + 4 + $offset, 8));
+ break;
+ case 0x47: // Clipboard format
+ // not needed yet, fix later if necessary
+ break;
+ }
+
+ switch ($id) {
+ case 0x01: // Code Page
+ $codePage = PHPExcel_Shared_CodePage::NumberToName($value);
+ break;
+ case 0x02: // Category
+ $this->phpExcel->getProperties()->setCategory($value);
+ break;
+ case 0x03: // Presentation Target
+ // Not supported by PHPExcel
+ break;
+ case 0x04: // Bytes
+ // Not supported by PHPExcel
+ break;
+ case 0x05: // Lines
+ // Not supported by PHPExcel
+ break;
+ case 0x06: // Paragraphs
+ // Not supported by PHPExcel
+ break;
+ case 0x07: // Slides
+ // Not supported by PHPExcel
+ break;
+ case 0x08: // Notes
+ // Not supported by PHPExcel
+ break;
+ case 0x09: // Hidden Slides
+ // Not supported by PHPExcel
+ break;
+ case 0x0A: // MM Clips
+ // Not supported by PHPExcel
+ break;
+ case 0x0B: // Scale Crop
+ // Not supported by PHPExcel
+ break;
+ case 0x0C: // Heading Pairs
+ // Not supported by PHPExcel
+ break;
+ case 0x0D: // Titles of Parts
+ // Not supported by PHPExcel
+ break;
+ case 0x0E: // Manager
+ $this->phpExcel->getProperties()->setManager($value);
+ break;
+ case 0x0F: // Company
+ $this->phpExcel->getProperties()->setCompany($value);
+ break;
+ case 0x10: // Links up-to-date
+ // Not supported by PHPExcel
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
+ */
+ private function readDefault()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+// $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+ }
+
+
+ /**
+ * The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
+ * this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
+ */
+ private function readNote()
+ {
+// echo 'Read Cell Annotation ';
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ $cellAddress = $this->readBIFF8CellAddress(substr($recordData, 0, 4));
+ if ($this->version == self::XLS_BIFF8) {
+ $noteObjID = self::getInt2d($recordData, 6);
+ $noteAuthor = self::readUnicodeStringLong(substr($recordData, 8));
+ $noteAuthor = $noteAuthor['value'];
+// echo 'Note Address=', $cellAddress,' ';
+// echo 'Note Object ID=', $noteObjID,' ';
+// echo 'Note Author=', $noteAuthor,' ';
+//
+ $this->cellNotes[$noteObjID] = array(
+ 'cellRef' => $cellAddress,
+ 'objectID' => $noteObjID,
+ 'author' => $noteAuthor
+ );
+ } else {
+ $extension = false;
+ if ($cellAddress == '$B$65536') {
+ // If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
+ // note from the previous cell annotation. We're not yet handling this, so annotations longer than the
+ // max 2048 bytes will probably throw a wobbly.
+ $row = self::getInt2d($recordData, 0);
+ $extension = true;
+ $cellAddress = array_pop(array_keys($this->phpSheet->getComments()));
+ }
+// echo 'Note Address=', $cellAddress,' ';
+
+ $cellAddress = str_replace('$', '', $cellAddress);
+ $noteLength = self::getInt2d($recordData, 4);
+ $noteText = trim(substr($recordData, 6));
+// echo 'Note Length=', $noteLength,' ';
+// echo 'Note Text=', $noteText,' ';
+
+ if ($extension) {
+ // Concatenate this extension with the currently set comment for the cell
+ $comment = $this->phpSheet->getComment($cellAddress);
+ $commentText = $comment->getText()->getPlainText();
+ $comment->setText($this->parseRichText($commentText.$noteText));
+ } else {
+ // Set comment for the cell
+ $this->phpSheet->getComment($cellAddress)->setText($this->parseRichText($noteText));
+// ->setAuthor($author)
+ }
+ }
+
+ }
+
+
+ /**
+ * The TEXT Object record contains the text associated with a cell annotation.
+ */
+ private function readTextObject()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ // recordData consists of an array of subrecords looking like this:
+ // grbit: 2 bytes; Option Flags
+ // rot: 2 bytes; rotation
+ // cchText: 2 bytes; length of the text (in the first continue record)
+ // cbRuns: 2 bytes; length of the formatting (in the second continue record)
+ // followed by the continuation records containing the actual text and formatting
+ $grbitOpts = self::getInt2d($recordData, 0);
+ $rot = self::getInt2d($recordData, 2);
+ $cchText = self::getInt2d($recordData, 10);
+ $cbRuns = self::getInt2d($recordData, 12);
+ $text = $this->getSplicedRecordData();
+
+ $this->textObjects[$this->textObjRef] = array(
+ 'text' => substr($text["recordData"], $text["spliceOffsets"][0]+1, $cchText),
+ 'format' => substr($text["recordData"], $text["spliceOffsets"][1], $cbRuns),
+ 'alignment' => $grbitOpts,
+ 'rotation' => $rot
+ );
+
+// echo '_readTextObject() ';
+// var_dump($this->textObjects[$this->textObjRef]);
+// echo ' ';
+ }
+
+
+ /**
+ * Read BOF
+ */
+ private function readBof()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = substr($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 2; size: 2; type of the following data
+ $substreamType = self::getInt2d($recordData, 2);
+
+ switch ($substreamType) {
+ case self::XLS_WorkbookGlobals:
+ $version = self::getInt2d($recordData, 0);
+ if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) {
+ throw new PHPExcel_Reader_Exception('Cannot read this Excel file. Version is too old.');
+ }
+ $this->version = $version;
+ break;
+ case self::XLS_Worksheet:
+ // do not use this version information for anything
+ // it is unreliable (OpenOffice doc, 5.8), use only version information from the global stream
+ break;
+ default:
+ // substream, e.g. chart
+ // just skip the entire substream
+ do {
+ $code = self::getInt2d($this->data, $this->pos);
+ $this->readDefault();
+ } while ($code != self::XLS_TYPE_EOF && $this->pos < $this->dataSize);
+ break;
+ }
+ }
+
+
+ /**
+ * FILEPASS
+ *
+ * This record is part of the File Protection Block. It
+ * contains information about the read/write password of the
+ * file. All record contents following this record will be
+ * encrypted.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ *
+ * The decryption functions and objects used from here on in
+ * are based on the source of Spreadsheet-ParseExcel:
+ * http://search.cpan.org/~jmcnamara/Spreadsheet-ParseExcel/
+ */
+ private function readFilepass()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+
+ if ($length != 54) {
+ throw new PHPExcel_Reader_Exception('Unexpected file pass record length');
+ }
+
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->verifyPassword('VelvetSweatshop', substr($recordData, 6, 16), substr($recordData, 22, 16), substr($recordData, 38, 16), $this->md5Ctxt)) {
+ throw new PHPExcel_Reader_Exception('Decryption password incorrect');
+ }
+
+ $this->encryption = self::MS_BIFF_CRYPTO_RC4;
+
+ // Decryption required from the record after next onwards
+ $this->encryptionStartPos = $this->pos + self::getInt2d($this->data, $this->pos + 2);
+ }
+
+ /**
+ * Make an RC4 decryptor for the given block
+ *
+ * @var int $block Block for which to create decrypto
+ * @var string $valContext MD5 context state
+ *
+ * @return PHPExcel_Reader_Excel5_RC4
+ */
+ private function makeKey($block, $valContext)
+ {
+ $pwarray = str_repeat("\0", 64);
+
+ for ($i = 0; $i < 5; $i++) {
+ $pwarray[$i] = $valContext[$i];
+ }
+
+ $pwarray[5] = chr($block & 0xff);
+ $pwarray[6] = chr(($block >> 8) & 0xff);
+ $pwarray[7] = chr(($block >> 16) & 0xff);
+ $pwarray[8] = chr(($block >> 24) & 0xff);
+
+ $pwarray[9] = "\x80";
+ $pwarray[56] = "\x48";
+
+ $md5 = new PHPExcel_Reader_Excel5_MD5();
+ $md5->add($pwarray);
+
+ $s = $md5->getContext();
+ return new PHPExcel_Reader_Excel5_RC4($s);
+ }
+
+ /**
+ * Verify RC4 file password
+ *
+ * @var string $password Password to check
+ * @var string $docid Document id
+ * @var string $salt_data Salt data
+ * @var string $hashedsalt_data Hashed salt data
+ * @var string &$valContext Set to the MD5 context of the value
+ *
+ * @return bool Success
+ */
+ private function verifyPassword($password, $docid, $salt_data, $hashedsalt_data, &$valContext)
+ {
+ $pwarray = str_repeat("\0", 64);
+
+ for ($i = 0; $i < strlen($password); $i++) {
+ $o = ord(substr($password, $i, 1));
+ $pwarray[2 * $i] = chr($o & 0xff);
+ $pwarray[2 * $i + 1] = chr(($o >> 8) & 0xff);
+ }
+ $pwarray[2 * $i] = chr(0x80);
+ $pwarray[56] = chr(($i << 4) & 0xff);
+
+ $md5 = new PHPExcel_Reader_Excel5_MD5();
+ $md5->add($pwarray);
+
+ $mdContext1 = $md5->getContext();
+
+ $offset = 0;
+ $keyoffset = 0;
+ $tocopy = 5;
+
+ $md5->reset();
+
+ while ($offset != 16) {
+ if ((64 - $offset) < 5) {
+ $tocopy = 64 - $offset;
+ }
+ for ($i = 0; $i <= $tocopy; $i++) {
+ $pwarray[$offset + $i] = $mdContext1[$keyoffset + $i];
+ }
+ $offset += $tocopy;
+
+ if ($offset == 64) {
+ $md5->add($pwarray);
+ $keyoffset = $tocopy;
+ $tocopy = 5 - $tocopy;
+ $offset = 0;
+ continue;
+ }
+
+ $keyoffset = 0;
+ $tocopy = 5;
+ for ($i = 0; $i < 16; $i++) {
+ $pwarray[$offset + $i] = $docid[$i];
+ }
+ $offset += 16;
+ }
+
+ $pwarray[16] = "\x80";
+ for ($i = 0; $i < 47; $i++) {
+ $pwarray[17 + $i] = "\0";
+ }
+ $pwarray[56] = "\x80";
+ $pwarray[57] = "\x0a";
+
+ $md5->add($pwarray);
+ $valContext = $md5->getContext();
+
+ $key = $this->makeKey(0, $valContext);
+
+ $salt = $key->RC4($salt_data);
+ $hashedsalt = $key->RC4($hashedsalt_data);
+
+ $salt .= "\x80" . str_repeat("\0", 47);
+ $salt[56] = "\x80";
+
+ $md5->reset();
+ $md5->add($salt);
+ $mdContext2 = $md5->getContext();
+
+ return $mdContext2 == $hashedsalt;
+ }
+
+ /**
+ * CODEPAGE
+ *
+ * This record stores the text encoding used to write byte
+ * strings, stored as MS Windows code page identifier.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readCodepage()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; code page identifier
+ $codepage = self::getInt2d($recordData, 0);
+
+ $this->codepage = PHPExcel_Shared_CodePage::NumberToName($codepage);
+ }
+
+
+ /**
+ * DATEMODE
+ *
+ * This record specifies the base date for displaying date
+ * values. All dates are stored as count of days past this
+ * base date. In BIFF2-BIFF4 this record is part of the
+ * Calculation Settings Block. In BIFF5-BIFF8 it is
+ * stored in the Workbook Globals Substream.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readDateMode()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; 0 = base 1900, 1 = base 1904
+ PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
+ if (ord($recordData{0}) == 1) {
+ PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
+ }
+ }
+
+
+ /**
+ * Read a FONT record
+ */
+ private function readFont()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ $objFont = new PHPExcel_Style_Font();
+
+ // offset: 0; size: 2; height of the font (in twips = 1/20 of a point)
+ $size = self::getInt2d($recordData, 0);
+ $objFont->setSize($size / 20);
+
+ // offset: 2; size: 2; option flags
+ // bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8)
+ // bit: 1; mask 0x0002; italic
+ $isItalic = (0x0002 & self::getInt2d($recordData, 2)) >> 1;
+ if ($isItalic) {
+ $objFont->setItalic(true);
+ }
+
+ // bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8)
+ // bit: 3; mask 0x0008; strike
+ $isStrike = (0x0008 & self::getInt2d($recordData, 2)) >> 3;
+ if ($isStrike) {
+ $objFont->setStrikethrough(true);
+ }
+
+ // offset: 4; size: 2; colour index
+ $colorIndex = self::getInt2d($recordData, 4);
+ $objFont->colorIndex = $colorIndex;
+
+ // offset: 6; size: 2; font weight
+ $weight = self::getInt2d($recordData, 6);
+ switch ($weight) {
+ case 0x02BC:
+ $objFont->setBold(true);
+ break;
+ }
+
+ // offset: 8; size: 2; escapement type
+ $escapement = self::getInt2d($recordData, 8);
+ switch ($escapement) {
+ case 0x0001:
+ $objFont->setSuperScript(true);
+ break;
+ case 0x0002:
+ $objFont->setSubScript(true);
+ break;
+ }
+
+ // offset: 10; size: 1; underline type
+ $underlineType = ord($recordData{10});
+ switch ($underlineType) {
+ case 0x00:
+ break; // no underline
+ case 0x01:
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+ break;
+ case 0x02:
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
+ break;
+ case 0x21:
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING);
+ break;
+ case 0x22:
+ $objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING);
+ break;
+ }
+
+ // offset: 11; size: 1; font family
+ // offset: 12; size: 1; character set
+ // offset: 13; size: 1; not used
+ // offset: 14; size: var; font name
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringShort(substr($recordData, 14));
+ } else {
+ $string = $this->readByteStringShort(substr($recordData, 14));
+ }
+ $objFont->setName($string['value']);
+
+ $this->objFonts[] = $objFont;
+ }
+ }
+
+
+ /**
+ * FORMAT
+ *
+ * This record contains information about a number format.
+ * All FORMAT records occur together in a sequential list.
+ *
+ * In BIFF2-BIFF4 other records referencing a FORMAT record
+ * contain a zero-based index into this list. From BIFF5 on
+ * the FORMAT record contains the index itself that will be
+ * used by other records.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readFormat()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ $indexCode = self::getInt2d($recordData, 0);
+
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringLong(substr($recordData, 2));
+ } else {
+ // BIFF7
+ $string = $this->readByteStringShort(substr($recordData, 2));
+ }
+
+ $formatString = $string['value'];
+ $this->formats[$indexCode] = $formatString;
+ }
+ }
+
+
+ /**
+ * XF - Extended Format
+ *
+ * This record contains formatting information for cells, rows, columns or styles.
+ * According to http://support.microsoft.com/kb/147732 there are always at least 15 cell style XF
+ * and 1 cell XF.
+ * Inspection of Excel files generated by MS Office Excel shows that XF records 0-14 are cell style XF
+ * and XF record 15 is a cell XF
+ * We only read the first cell style XF and skip the remaining cell style XF records
+ * We read all cell XF records.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readXf()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ $objStyle = new PHPExcel_Style();
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; Index to FONT record
+ if (self::getInt2d($recordData, 0) < 4) {
+ $fontIndex = self::getInt2d($recordData, 0);
+ } else {
+ // this has to do with that index 4 is omitted in all BIFF versions for some strange reason
+ // check the OpenOffice documentation of the FONT record
+ $fontIndex = self::getInt2d($recordData, 0) - 1;
+ }
+ $objStyle->setFont($this->objFonts[$fontIndex]);
+
+ // offset: 2; size: 2; Index to FORMAT record
+ $numberFormatIndex = self::getInt2d($recordData, 2);
+ if (isset($this->formats[$numberFormatIndex])) {
+ // then we have user-defined format code
+ $numberformat = array('code' => $this->formats[$numberFormatIndex]);
+ } elseif (($code = PHPExcel_Style_NumberFormat::builtInFormatCode($numberFormatIndex)) !== '') {
+ // then we have built-in format code
+ $numberformat = array('code' => $code);
+ } else {
+ // we set the general format code
+ $numberformat = array('code' => 'General');
+ }
+ $objStyle->getNumberFormat()->setFormatCode($numberformat['code']);
+
+ // offset: 4; size: 2; XF type, cell protection, and parent style XF
+ // bit 2-0; mask 0x0007; XF_TYPE_PROT
+ $xfTypeProt = self::getInt2d($recordData, 4);
+ // bit 0; mask 0x01; 1 = cell is locked
+ $isLocked = (0x01 & $xfTypeProt) >> 0;
+ $objStyle->getProtection()->setLocked($isLocked ? PHPExcel_Style_Protection::PROTECTION_INHERIT : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
+
+ // bit 1; mask 0x02; 1 = Formula is hidden
+ $isHidden = (0x02 & $xfTypeProt) >> 1;
+ $objStyle->getProtection()->setHidden($isHidden ? PHPExcel_Style_Protection::PROTECTION_PROTECTED : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
+
+ // bit 2; mask 0x04; 0 = Cell XF, 1 = Cell Style XF
+ $isCellStyleXf = (0x04 & $xfTypeProt) >> 2;
+
+ // offset: 6; size: 1; Alignment and text break
+ // bit 2-0, mask 0x07; horizontal alignment
+ $horAlign = (0x07 & ord($recordData{6})) >> 0;
+ switch ($horAlign) {
+ case 0:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
+ break;
+ case 1:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
+ break;
+ case 2:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+ break;
+ case 3:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
+ break;
+ case 4:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_FILL);
+ break;
+ case 5:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);
+ break;
+ case 6:
+ $objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS);
+ break;
+ }
+ // bit 3, mask 0x08; wrap text
+ $wrapText = (0x08 & ord($recordData{6})) >> 3;
+ switch ($wrapText) {
+ case 0:
+ $objStyle->getAlignment()->setWrapText(false);
+ break;
+ case 1:
+ $objStyle->getAlignment()->setWrapText(true);
+ break;
+ }
+ // bit 6-4, mask 0x70; vertical alignment
+ $vertAlign = (0x70 & ord($recordData{6})) >> 4;
+ switch ($vertAlign) {
+ case 0:
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
+ break;
+ case 1:
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
+ break;
+ case 2:
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);
+ break;
+ case 3:
+ $objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_JUSTIFY);
+ break;
+ }
+
+ if ($this->version == self::XLS_BIFF8) {
+ // offset: 7; size: 1; XF_ROTATION: Text rotation angle
+ $angle = ord($recordData{7});
+ $rotation = 0;
+ if ($angle <= 90) {
+ $rotation = $angle;
+ } elseif ($angle <= 180) {
+ $rotation = 90 - $angle;
+ } elseif ($angle == 255) {
+ $rotation = -165;
+ }
+ $objStyle->getAlignment()->setTextRotation($rotation);
+
+ // offset: 8; size: 1; Indentation, shrink to cell size, and text direction
+ // bit: 3-0; mask: 0x0F; indent level
+ $indent = (0x0F & ord($recordData{8})) >> 0;
+ $objStyle->getAlignment()->setIndent($indent);
+
+ // bit: 4; mask: 0x10; 1 = shrink content to fit into cell
+ $shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
+ switch ($shrinkToFit) {
+ case 0:
+ $objStyle->getAlignment()->setShrinkToFit(false);
+ break;
+ case 1:
+ $objStyle->getAlignment()->setShrinkToFit(true);
+ break;
+ }
+
+ // offset: 9; size: 1; Flags used for attribute groups
+
+ // offset: 10; size: 4; Cell border lines and background area
+ // bit: 3-0; mask: 0x0000000F; left style
+ if ($bordersLeftStyle = PHPExcel_Reader_Excel5_Style_Border::lookup((0x0000000F & self::getInt4d($recordData, 10)) >> 0)) {
+ $objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle);
+ }
+ // bit: 7-4; mask: 0x000000F0; right style
+ if ($bordersRightStyle = PHPExcel_Reader_Excel5_Style_Border::lookup((0x000000F0 & self::getInt4d($recordData, 10)) >> 4)) {
+ $objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle);
+ }
+ // bit: 11-8; mask: 0x00000F00; top style
+ if ($bordersTopStyle = PHPExcel_Reader_Excel5_Style_Border::lookup((0x00000F00 & self::getInt4d($recordData, 10)) >> 8)) {
+ $objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle);
+ }
+ // bit: 15-12; mask: 0x0000F000; bottom style
+ if ($bordersBottomStyle = PHPExcel_Reader_Excel5_Style_Border::lookup((0x0000F000 & self::getInt4d($recordData, 10)) >> 12)) {
+ $objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle);
+ }
+ // bit: 22-16; mask: 0x007F0000; left color
+ $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::getInt4d($recordData, 10)) >> 16;
+
+ // bit: 29-23; mask: 0x3F800000; right color
+ $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::getInt4d($recordData, 10)) >> 23;
+
+ // bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom
+ $diagonalDown = (0x40000000 & self::getInt4d($recordData, 10)) >> 30 ? true : false;
+
+ // bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right
+ $diagonalUp = (0x80000000 & self::getInt4d($recordData, 10)) >> 31 ? true : false;
+
+ if ($diagonalUp == false && $diagonalDown == false) {
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
+ } elseif ($diagonalUp == true && $diagonalDown == false) {
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
+ } elseif ($diagonalUp == false && $diagonalDown == true) {
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
+ } elseif ($diagonalUp == true && $diagonalDown == true) {
+ $objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
+ }
+
+ // offset: 14; size: 4;
+ // bit: 6-0; mask: 0x0000007F; top color
+ $objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::getInt4d($recordData, 14)) >> 0;
+
+ // bit: 13-7; mask: 0x00003F80; bottom color
+ $objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::getInt4d($recordData, 14)) >> 7;
+
+ // bit: 20-14; mask: 0x001FC000; diagonal color
+ $objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::getInt4d($recordData, 14)) >> 14;
+
+ // bit: 24-21; mask: 0x01E00000; diagonal style
+ if ($bordersDiagonalStyle = PHPExcel_Reader_Excel5_Style_Border::lookup((0x01E00000 & self::getInt4d($recordData, 14)) >> 21)) {
+ $objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle);
+ }
+
+ // bit: 31-26; mask: 0xFC000000 fill pattern
+ if ($fillType = PHPExcel_Reader_Excel5_Style_FillPattern::lookup((0xFC000000 & self::getInt4d($recordData, 14)) >> 26)) {
+ $objStyle->getFill()->setFillType($fillType);
+ }
+ // offset: 18; size: 2; pattern and background colour
+ // bit: 6-0; mask: 0x007F; color index for pattern color
+ $objStyle->getFill()->startcolorIndex = (0x007F & self::getInt2d($recordData, 18)) >> 0;
+
+ // bit: 13-7; mask: 0x3F80; color index for pattern background
+ $objStyle->getFill()->endcolorIndex = (0x3F80 & self::getInt2d($recordData, 18)) >> 7;
+ } else {
+ // BIFF5
+
+ // offset: 7; size: 1; Text orientation and flags
+ $orientationAndFlags = ord($recordData{7});
+
+ // bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
+ $xfOrientation = (0x03 & $orientationAndFlags) >> 0;
+ switch ($xfOrientation) {
+ case 0:
+ $objStyle->getAlignment()->setTextRotation(0);
+ break;
+ case 1:
+ $objStyle->getAlignment()->setTextRotation(-165);
+ break;
+ case 2:
+ $objStyle->getAlignment()->setTextRotation(90);
+ break;
+ case 3:
+ $objStyle->getAlignment()->setTextRotation(-90);
+ break;
+ }
+
+ // offset: 8; size: 4; cell border lines and background area
+ $borderAndBackground = self::getInt4d($recordData, 8);
+
+ // bit: 6-0; mask: 0x0000007F; color index for pattern color
+ $objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0;
+
+ // bit: 13-7; mask: 0x00003F80; color index for pattern background
+ $objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7;
+
+ // bit: 21-16; mask: 0x003F0000; fill pattern
+ $objStyle->getFill()->setFillType(PHPExcel_Reader_Excel5_Style_FillPattern::lookup((0x003F0000 & $borderAndBackground) >> 16));
+
+ // bit: 24-22; mask: 0x01C00000; bottom line style
+ $objStyle->getBorders()->getBottom()->setBorderStyle(PHPExcel_Reader_Excel5_Style_Border::lookup((0x01C00000 & $borderAndBackground) >> 22));
+
+ // bit: 31-25; mask: 0xFE000000; bottom line color
+ $objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25;
+
+ // offset: 12; size: 4; cell border lines
+ $borderLines = self::getInt4d($recordData, 12);
+
+ // bit: 2-0; mask: 0x00000007; top line style
+ $objStyle->getBorders()->getTop()->setBorderStyle(PHPExcel_Reader_Excel5_Style_Border::lookup((0x00000007 & $borderLines) >> 0));
+
+ // bit: 5-3; mask: 0x00000038; left line style
+ $objStyle->getBorders()->getLeft()->setBorderStyle(PHPExcel_Reader_Excel5_Style_Border::lookup((0x00000038 & $borderLines) >> 3));
+
+ // bit: 8-6; mask: 0x000001C0; right line style
+ $objStyle->getBorders()->getRight()->setBorderStyle(PHPExcel_Reader_Excel5_Style_Border::lookup((0x000001C0 & $borderLines) >> 6));
+
+ // bit: 15-9; mask: 0x0000FE00; top line color index
+ $objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9;
+
+ // bit: 22-16; mask: 0x007F0000; left line color index
+ $objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $borderLines) >> 16;
+
+ // bit: 29-23; mask: 0x3F800000; right line color index
+ $objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $borderLines) >> 23;
+ }
+
+ // add cellStyleXf or cellXf and update mapping
+ if ($isCellStyleXf) {
+ // we only read one style XF record which is always the first
+ if ($this->xfIndex == 0) {
+ $this->phpExcel->addCellStyleXf($objStyle);
+ $this->mapCellStyleXfIndex[$this->xfIndex] = 0;
+ }
+ } else {
+ // we read all cell XF records
+ $this->phpExcel->addCellXf($objStyle);
+ $this->mapCellXfIndex[$this->xfIndex] = count($this->phpExcel->getCellXfCollection()) - 1;
+ }
+
+ // update XF index for when we read next record
+ ++$this->xfIndex;
+ }
+ }
+
+
+ /**
+ *
+ */
+ private function readXfExt()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; 0x087D = repeated header
+
+ // offset: 2; size: 2
+
+ // offset: 4; size: 8; not used
+
+ // offset: 12; size: 2; record version
+
+ // offset: 14; size: 2; index to XF record which this record modifies
+ $ixfe = self::getInt2d($recordData, 14);
+
+ // offset: 16; size: 2; not used
+
+ // offset: 18; size: 2; number of extension properties that follow
+ $cexts = self::getInt2d($recordData, 18);
+
+ // start reading the actual extension data
+ $offset = 20;
+ while ($offset < $length) {
+ // extension type
+ $extType = self::getInt2d($recordData, $offset);
+
+ // extension length
+ $cb = self::getInt2d($recordData, $offset + 2);
+
+ // extension data
+ $extData = substr($recordData, $offset + 4, $cb);
+
+ switch ($extType) {
+ case 4: // fill start color
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $fill = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getFill();
+ $fill->getStartColor()->setRGB($rgb);
+ unset($fill->startcolorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 5: // fill end color
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $fill = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getFill();
+ $fill->getEndColor()->setRGB($rgb);
+ unset($fill->endcolorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 7: // border color top
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $top = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getBorders()->getTop();
+ $top->getColor()->setRGB($rgb);
+ unset($top->colorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 8: // border color bottom
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $bottom = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getBorders()->getBottom();
+ $bottom->getColor()->setRGB($rgb);
+ unset($bottom->colorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 9: // border color left
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $left = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getBorders()->getLeft();
+ $left->getColor()->setRGB($rgb);
+ unset($left->colorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 10: // border color right
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $right = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getBorders()->getRight();
+ $right->getColor()->setRGB($rgb);
+ unset($right->colorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 11: // border color diagonal
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $diagonal = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getBorders()->getDiagonal();
+ $diagonal->getColor()->setRGB($rgb);
+ unset($diagonal->colorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ case 13: // font color
+ $xclfType = self::getInt2d($extData, 0); // color type
+ $xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+ if ($xclfType == 2) {
+ $rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+ // modify the relevant style property
+ if (isset($this->mapCellXfIndex[$ixfe])) {
+ $font = $this->phpExcel->getCellXfByIndex($this->mapCellXfIndex[$ixfe])->getFont();
+ $font->getColor()->setRGB($rgb);
+ unset($font->colorIndex); // normal color index does not apply, discard
+ }
+ }
+ break;
+ }
+
+ $offset += $cb;
+ }
+ }
+
+ }
+
+
+ /**
+ * Read STYLE record
+ */
+ private function readStyle()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; index to XF record and flag for built-in style
+ $ixfe = self::getInt2d($recordData, 0);
+
+ // bit: 11-0; mask 0x0FFF; index to XF record
+ $xfIndex = (0x0FFF & $ixfe) >> 0;
+
+ // bit: 15; mask 0x8000; 0 = user-defined style, 1 = built-in style
+ $isBuiltIn = (bool) ((0x8000 & $ixfe) >> 15);
+
+ if ($isBuiltIn) {
+ // offset: 2; size: 1; identifier for built-in style
+ $builtInId = ord($recordData{2});
+
+ switch ($builtInId) {
+ case 0x00:
+ // currently, we are not using this for anything
+ break;
+ default:
+ break;
+ }
+ } else {
+ // user-defined; not supported by PHPExcel
+ }
+ }
+ }
+
+
+ /**
+ * Read PALETTE record
+ */
+ private function readPalette()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; number of following colors
+ $nm = self::getInt2d($recordData, 0);
+
+ // list of RGB colors
+ for ($i = 0; $i < $nm; ++$i) {
+ $rgb = substr($recordData, 2 + 4 * $i, 4);
+ $this->palette[] = self::readRGB($rgb);
+ }
+ }
+ }
+
+
+ /**
+ * SHEET
+ *
+ * This record is located in the Workbook Globals
+ * Substream and represents a sheet inside the workbook.
+ * One SHEET record is written for each sheet. It stores the
+ * sheet name and a stream offset to the BOF record of the
+ * respective Sheet Substream within the Workbook Stream.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readSheet()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // offset: 0; size: 4; absolute stream position of the BOF record of the sheet
+ // NOTE: not encrypted
+ $rec_offset = self::getInt4d($this->data, $this->pos + 4);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 4; size: 1; sheet state
+ switch (ord($recordData{4})) {
+ case 0x00:
+ $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;
+ break;
+ case 0x01:
+ $sheetState = PHPExcel_Worksheet::SHEETSTATE_HIDDEN;
+ break;
+ case 0x02:
+ $sheetState = PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN;
+ break;
+ default:
+ $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;
+ break;
+ }
+
+ // offset: 5; size: 1; sheet type
+ $sheetType = ord($recordData{5});
+
+ // offset: 6; size: var; sheet name
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringShort(substr($recordData, 6));
+ $rec_name = $string['value'];
+ } elseif ($this->version == self::XLS_BIFF7) {
+ $string = $this->readByteStringShort(substr($recordData, 6));
+ $rec_name = $string['value'];
+ }
+
+ $this->sheets[] = array(
+ 'name' => $rec_name,
+ 'offset' => $rec_offset,
+ 'sheetState' => $sheetState,
+ 'sheetType' => $sheetType,
+ );
+ }
+
+
+ /**
+ * Read EXTERNALBOOK record
+ */
+ private function readExternalBook()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset within record data
+ $offset = 0;
+
+ // there are 4 types of records
+ if (strlen($recordData) > 4) {
+ // external reference
+ // offset: 0; size: 2; number of sheet names ($nm)
+ $nm = self::getInt2d($recordData, 0);
+ $offset += 2;
+
+ // offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length)
+ $encodedUrlString = self::readUnicodeStringLong(substr($recordData, 2));
+ $offset += $encodedUrlString['size'];
+
+ // offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length)
+ $externalSheetNames = array();
+ for ($i = 0; $i < $nm; ++$i) {
+ $externalSheetNameString = self::readUnicodeStringLong(substr($recordData, $offset));
+ $externalSheetNames[] = $externalSheetNameString['value'];
+ $offset += $externalSheetNameString['size'];
+ }
+
+ // store the record data
+ $this->externalBooks[] = array(
+ 'type' => 'external',
+ 'encodedUrl' => $encodedUrlString['value'],
+ 'externalSheetNames' => $externalSheetNames,
+ );
+ } elseif (substr($recordData, 2, 2) == pack('CC', 0x01, 0x04)) {
+ // internal reference
+ // offset: 0; size: 2; number of sheet in this document
+ // offset: 2; size: 2; 0x01 0x04
+ $this->externalBooks[] = array(
+ 'type' => 'internal',
+ );
+ } elseif (substr($recordData, 0, 4) == pack('vCC', 0x0001, 0x01, 0x3A)) {
+ // add-in function
+ // offset: 0; size: 2; 0x0001
+ $this->externalBooks[] = array(
+ 'type' => 'addInFunction',
+ );
+ } elseif (substr($recordData, 0, 2) == pack('v', 0x0000)) {
+ // DDE links, OLE links
+ // offset: 0; size: 2; 0x0000
+ // offset: 2; size: var; encoded source document name
+ $this->externalBooks[] = array(
+ 'type' => 'DDEorOLE',
+ );
+ }
+ }
+
+
+ /**
+ * Read EXTERNNAME record.
+ */
+ private function readExternName()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // external sheet references provided for named cells
+ if ($this->version == self::XLS_BIFF8) {
+ // offset: 0; size: 2; options
+ $options = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2;
+
+ // offset: 4; size: 2; not used
+
+ // offset: 6; size: var
+ $nameString = self::readUnicodeStringShort(substr($recordData, 6));
+
+ // offset: var; size: var; formula data
+ $offset = 6 + $nameString['size'];
+ $formula = $this->getFormulaFromStructure(substr($recordData, $offset));
+
+ $this->externalNames[] = array(
+ 'name' => $nameString['value'],
+ 'formula' => $formula,
+ );
+ }
+ }
+
+
+ /**
+ * Read EXTERNSHEET record
+ */
+ private function readExternSheet()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // external sheet references provided for named cells
+ if ($this->version == self::XLS_BIFF8) {
+ // offset: 0; size: 2; number of following ref structures
+ $nm = self::getInt2d($recordData, 0);
+ for ($i = 0; $i < $nm; ++$i) {
+ $this->ref[] = array(
+ // offset: 2 + 6 * $i; index to EXTERNALBOOK record
+ 'externalBookIndex' => self::getInt2d($recordData, 2 + 6 * $i),
+ // offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
+ 'firstSheetIndex' => self::getInt2d($recordData, 4 + 6 * $i),
+ // offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
+ 'lastSheetIndex' => self::getInt2d($recordData, 6 + 6 * $i),
+ );
+ }
+ }
+ }
+
+
+ /**
+ * DEFINEDNAME
+ *
+ * This record is part of a Link Table. It contains the name
+ * and the token array of an internal defined name. Token
+ * arrays of defined names contain tokens with aberrant
+ * token classes.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readDefinedName()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->version == self::XLS_BIFF8) {
+ // retrieves named cells
+
+ // offset: 0; size: 2; option flags
+ $opts = self::getInt2d($recordData, 0);
+
+ // bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name
+ $isBuiltInName = (0x0020 & $opts) >> 5;
+
+ // offset: 2; size: 1; keyboard shortcut
+
+ // offset: 3; size: 1; length of the name (character count)
+ $nlen = ord($recordData{3});
+
+ // offset: 4; size: 2; size of the formula data (it can happen that this is zero)
+ // note: there can also be additional data, this is not included in $flen
+ $flen = self::getInt2d($recordData, 4);
+
+ // offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based)
+ $scope = self::getInt2d($recordData, 8);
+
+ // offset: 14; size: var; Name (Unicode string without length field)
+ $string = self::readUnicodeString(substr($recordData, 14), $nlen);
+
+ // offset: var; size: $flen; formula data
+ $offset = 14 + $string['size'];
+ $formulaStructure = pack('v', $flen) . substr($recordData, $offset);
+
+ try {
+ $formula = $this->getFormulaFromStructure($formulaStructure);
+ } catch (PHPExcel_Exception $e) {
+ $formula = '';
+ }
+
+ $this->definedname[] = array(
+ 'isBuiltInName' => $isBuiltInName,
+ 'name' => $string['value'],
+ 'formula' => $formula,
+ 'scope' => $scope,
+ );
+ }
+ }
+
+
+ /**
+ * Read MSODRAWINGGROUP record
+ */
+ private function readMsoDrawingGroup()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+
+ // get spliced record data
+ $splicedRecordData = $this->getSplicedRecordData();
+ $recordData = $splicedRecordData['recordData'];
+
+ $this->drawingGroupData .= $recordData;
+ }
+
+
+ /**
+ * SST - Shared String Table
+ *
+ * This record contains a list of all strings used anywhere
+ * in the workbook. Each string occurs only once. The
+ * workbook uses indexes into the list to reference the
+ * strings.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ **/
+ private function readSst()
+ {
+ // offset within (spliced) record data
+ $pos = 0;
+
+ // get spliced record data
+ $splicedRecordData = $this->getSplicedRecordData();
+
+ $recordData = $splicedRecordData['recordData'];
+ $spliceOffsets = $splicedRecordData['spliceOffsets'];
+
+ // offset: 0; size: 4; total number of strings in the workbook
+ $pos += 4;
+
+ // offset: 4; size: 4; number of following strings ($nm)
+ $nm = self::getInt4d($recordData, 4);
+ $pos += 4;
+
+ // loop through the Unicode strings (16-bit length)
+ for ($i = 0; $i < $nm; ++$i) {
+ // number of characters in the Unicode string
+ $numChars = self::getInt2d($recordData, $pos);
+ $pos += 2;
+
+ // option flags
+ $optionFlags = ord($recordData{$pos});
+ ++$pos;
+
+ // bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
+ $isCompressed = (($optionFlags & 0x01) == 0) ;
+
+ // bit: 2; mask: 0x02; 0 = ordinary; 1 = Asian phonetic
+ $hasAsian = (($optionFlags & 0x04) != 0);
+
+ // bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
+ $hasRichText = (($optionFlags & 0x08) != 0);
+
+ if ($hasRichText) {
+ // number of Rich-Text formatting runs
+ $formattingRuns = self::getInt2d($recordData, $pos);
+ $pos += 2;
+ }
+
+ if ($hasAsian) {
+ // size of Asian phonetic setting
+ $extendedRunLength = self::getInt4d($recordData, $pos);
+ $pos += 4;
+ }
+
+ // expected byte length of character array if not split
+ $len = ($isCompressed) ? $numChars : $numChars * 2;
+
+ // look up limit position
+ foreach ($spliceOffsets as $spliceOffset) {
+ // it can happen that the string is empty, therefore we need
+ // <= and not just <
+ if ($pos <= $spliceOffset) {
+ $limitpos = $spliceOffset;
+ break;
+ }
+ }
+
+ if ($pos + $len <= $limitpos) {
+ // character array is not split between records
+
+ $retstr = substr($recordData, $pos, $len);
+ $pos += $len;
+ } else {
+ // character array is split between records
+
+ // first part of character array
+ $retstr = substr($recordData, $pos, $limitpos - $pos);
+
+ $bytesRead = $limitpos - $pos;
+
+ // remaining characters in Unicode string
+ $charsLeft = $numChars - (($isCompressed) ? $bytesRead : ($bytesRead / 2));
+
+ $pos = $limitpos;
+
+ // keep reading the characters
+ while ($charsLeft > 0) {
+ // look up next limit position, in case the string span more than one continue record
+ foreach ($spliceOffsets as $spliceOffset) {
+ if ($pos < $spliceOffset) {
+ $limitpos = $spliceOffset;
+ break;
+ }
+ }
+
+ // repeated option flags
+ // OpenOffice.org documentation 5.21
+ $option = ord($recordData{$pos});
+ ++$pos;
+
+ if ($isCompressed && ($option == 0)) {
+ // 1st fragment compressed
+ // this fragment compressed
+ $len = min($charsLeft, $limitpos - $pos);
+ $retstr .= substr($recordData, $pos, $len);
+ $charsLeft -= $len;
+ $isCompressed = true;
+ } elseif (!$isCompressed && ($option != 0)) {
+ // 1st fragment uncompressed
+ // this fragment uncompressed
+ $len = min($charsLeft * 2, $limitpos - $pos);
+ $retstr .= substr($recordData, $pos, $len);
+ $charsLeft -= $len / 2;
+ $isCompressed = false;
+ } elseif (!$isCompressed && ($option == 0)) {
+ // 1st fragment uncompressed
+ // this fragment compressed
+ $len = min($charsLeft, $limitpos - $pos);
+ for ($j = 0; $j < $len; ++$j) {
+ $retstr .= $recordData{$pos + $j} . chr(0);
+ }
+ $charsLeft -= $len;
+ $isCompressed = false;
+ } else {
+ // 1st fragment compressed
+ // this fragment uncompressed
+ $newstr = '';
+ for ($j = 0; $j < strlen($retstr); ++$j) {
+ $newstr .= $retstr[$j] . chr(0);
+ }
+ $retstr = $newstr;
+ $len = min($charsLeft * 2, $limitpos - $pos);
+ $retstr .= substr($recordData, $pos, $len);
+ $charsLeft -= $len / 2;
+ $isCompressed = false;
+ }
+
+ $pos += $len;
+ }
+ }
+
+ // convert to UTF-8
+ $retstr = self::encodeUTF16($retstr, $isCompressed);
+
+ // read additional Rich-Text information, if any
+ $fmtRuns = array();
+ if ($hasRichText) {
+ // list of formatting runs
+ for ($j = 0; $j < $formattingRuns; ++$j) {
+ // first formatted character; zero-based
+ $charPos = self::getInt2d($recordData, $pos + $j * 4);
+
+ // index to font record
+ $fontIndex = self::getInt2d($recordData, $pos + 2 + $j * 4);
+
+ $fmtRuns[] = array(
+ 'charPos' => $charPos,
+ 'fontIndex' => $fontIndex,
+ );
+ }
+ $pos += 4 * $formattingRuns;
+ }
+
+ // read additional Asian phonetics information, if any
+ if ($hasAsian) {
+ // For Asian phonetic settings, we skip the extended string data
+ $pos += $extendedRunLength;
+ }
+
+ // store the shared sting
+ $this->sst[] = array(
+ 'value' => $retstr,
+ 'fmtRuns' => $fmtRuns,
+ );
+ }
+
+ // getSplicedRecordData() takes care of moving current position in data stream
+ }
+
+
+ /**
+ * Read PRINTGRIDLINES record
+ */
+ private function readPrintGridlines()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->version == self::XLS_BIFF8 && !$this->readDataOnly) {
+ // offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines
+ $printGridlines = (bool) self::getInt2d($recordData, 0);
+ $this->phpSheet->setPrintGridlines($printGridlines);
+ }
+ }
+
+
+ /**
+ * Read DEFAULTROWHEIGHT record
+ */
+ private function readDefaultRowHeight()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; option flags
+ // offset: 2; size: 2; default height for unused rows, (twips 1/20 point)
+ $height = self::getInt2d($recordData, 2);
+ $this->phpSheet->getDefaultRowDimension()->setRowHeight($height / 20);
+ }
+
+
+ /**
+ * Read SHEETPR record
+ */
+ private function readSheetPr()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2
+
+ // bit: 6; mask: 0x0040; 0 = outline buttons above outline group
+ $isSummaryBelow = (0x0040 & self::getInt2d($recordData, 0)) >> 6;
+ $this->phpSheet->setShowSummaryBelow($isSummaryBelow);
+
+ // bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
+ $isSummaryRight = (0x0080 & self::getInt2d($recordData, 0)) >> 7;
+ $this->phpSheet->setShowSummaryRight($isSummaryRight);
+
+ // bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
+ // this corresponds to radio button setting in page setup dialog in Excel
+ $this->isFitToPages = (bool) ((0x0100 & self::getInt2d($recordData, 0)) >> 8);
+ }
+
+
+ /**
+ * Read HORIZONTALPAGEBREAKS record
+ */
+ private function readHorizontalPageBreaks()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->version == self::XLS_BIFF8 && !$this->readDataOnly) {
+ // offset: 0; size: 2; number of the following row index structures
+ $nm = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 6 * $nm; list of $nm row index structures
+ for ($i = 0; $i < $nm; ++$i) {
+ $r = self::getInt2d($recordData, 2 + 6 * $i);
+ $cf = self::getInt2d($recordData, 2 + 6 * $i + 2);
+ $cl = self::getInt2d($recordData, 2 + 6 * $i + 4);
+
+ // not sure why two column indexes are necessary?
+ $this->phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW);
+ }
+ }
+ }
+
+
+ /**
+ * Read VERTICALPAGEBREAKS record
+ */
+ private function readVerticalPageBreaks()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->version == self::XLS_BIFF8 && !$this->readDataOnly) {
+ // offset: 0; size: 2; number of the following column index structures
+ $nm = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 6 * $nm; list of $nm row index structures
+ for ($i = 0; $i < $nm; ++$i) {
+ $c = self::getInt2d($recordData, 2 + 6 * $i);
+ $rf = self::getInt2d($recordData, 2 + 6 * $i + 2);
+ $rl = self::getInt2d($recordData, 2 + 6 * $i + 4);
+
+ // not sure why two row indexes are necessary?
+ $this->phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN);
+ }
+ }
+ }
+
+
+ /**
+ * Read HEADER record
+ */
+ private function readHeader()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: var
+ // realized that $recordData can be empty even when record exists
+ if ($recordData) {
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringLong($recordData);
+ } else {
+ $string = $this->readByteStringShort($recordData);
+ }
+
+ $this->phpSheet->getHeaderFooter()->setOddHeader($string['value']);
+ $this->phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
+ }
+ }
+ }
+
+
+ /**
+ * Read FOOTER record
+ */
+ private function readFooter()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: var
+ // realized that $recordData can be empty even when record exists
+ if ($recordData) {
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringLong($recordData);
+ } else {
+ $string = $this->readByteStringShort($recordData);
+ }
+ $this->phpSheet->getHeaderFooter()->setOddFooter($string['value']);
+ $this->phpSheet->getHeaderFooter()->setEvenFooter($string['value']);
+ }
+ }
+ }
+
+
+ /**
+ * Read HCENTER record
+ */
+ private function readHcenter()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally
+ $isHorizontalCentered = (bool) self::getInt2d($recordData, 0);
+
+ $this->phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered);
+ }
+ }
+
+
+ /**
+ * Read VCENTER record
+ */
+ private function readVcenter()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered
+ $isVerticalCentered = (bool) self::getInt2d($recordData, 0);
+
+ $this->phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered);
+ }
+ }
+
+
+ /**
+ * Read LEFTMARGIN record
+ */
+ private function readLeftMargin()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 8
+ $this->phpSheet->getPageMargins()->setLeft(self::extractNumber($recordData));
+ }
+ }
+
+
+ /**
+ * Read RIGHTMARGIN record
+ */
+ private function readRightMargin()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 8
+ $this->phpSheet->getPageMargins()->setRight(self::extractNumber($recordData));
+ }
+ }
+
+
+ /**
+ * Read TOPMARGIN record
+ */
+ private function readTopMargin()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 8
+ $this->phpSheet->getPageMargins()->setTop(self::extractNumber($recordData));
+ }
+ }
+
+
+ /**
+ * Read BOTTOMMARGIN record
+ */
+ private function readBottomMargin()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 8
+ $this->phpSheet->getPageMargins()->setBottom(self::extractNumber($recordData));
+ }
+ }
+
+
+ /**
+ * Read PAGESETUP record
+ */
+ private function readPageSetup()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; paper size
+ $paperSize = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; scaling factor
+ $scale = self::getInt2d($recordData, 2);
+
+ // offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed
+ $fitToWidth = self::getInt2d($recordData, 6);
+
+ // offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed
+ $fitToHeight = self::getInt2d($recordData, 8);
+
+ // offset: 10; size: 2; option flags
+
+ // bit: 1; mask: 0x0002; 0=landscape, 1=portrait
+ $isPortrait = (0x0002 & self::getInt2d($recordData, 10)) >> 1;
+
+ // bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init
+ // when this bit is set, do not use flags for those properties
+ $isNotInit = (0x0004 & self::getInt2d($recordData, 10)) >> 2;
+
+ if (!$isNotInit) {
+ $this->phpSheet->getPageSetup()->setPaperSize($paperSize);
+ switch ($isPortrait) {
+ case 0:
+ $this->phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE);
+ break;
+ case 1:
+ $this->phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT);
+ break;
+ }
+
+ $this->phpSheet->getPageSetup()->setScale($scale, false);
+ $this->phpSheet->getPageSetup()->setFitToPage((bool) $this->isFitToPages);
+ $this->phpSheet->getPageSetup()->setFitToWidth($fitToWidth, false);
+ $this->phpSheet->getPageSetup()->setFitToHeight($fitToHeight, false);
+ }
+
+ // offset: 16; size: 8; header margin (IEEE 754 floating-point value)
+ $marginHeader = self::extractNumber(substr($recordData, 16, 8));
+ $this->phpSheet->getPageMargins()->setHeader($marginHeader);
+
+ // offset: 24; size: 8; footer margin (IEEE 754 floating-point value)
+ $marginFooter = self::extractNumber(substr($recordData, 24, 8));
+ $this->phpSheet->getPageMargins()->setFooter($marginFooter);
+ }
+ }
+
+
+ /**
+ * PROTECT - Sheet protection (BIFF2 through BIFF8)
+ * if this record is omitted, then it also means no sheet protection
+ */
+ private function readProtect()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ // offset: 0; size: 2;
+
+ // bit 0, mask 0x01; 1 = sheet is protected
+ $bool = (0x01 & self::getInt2d($recordData, 0)) >> 0;
+ $this->phpSheet->getProtection()->setSheet((bool)$bool);
+ }
+
+
+ /**
+ * SCENPROTECT
+ */
+ private function readScenProtect()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ // offset: 0; size: 2;
+
+ // bit: 0, mask 0x01; 1 = scenarios are protected
+ $bool = (0x01 & self::getInt2d($recordData, 0)) >> 0;
+
+ $this->phpSheet->getProtection()->setScenarios((bool)$bool);
+ }
+
+
+ /**
+ * OBJECTPROTECT
+ */
+ private function readObjectProtect()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ // offset: 0; size: 2;
+
+ // bit: 0, mask 0x01; 1 = objects are protected
+ $bool = (0x01 & self::getInt2d($recordData, 0)) >> 0;
+
+ $this->phpSheet->getProtection()->setObjects((bool)$bool);
+ }
+
+
+ /**
+ * PASSWORD - Sheet protection (hashed) password (BIFF2 through BIFF8)
+ */
+ private function readPassword()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; 16-bit hash value of password
+ $password = strtoupper(dechex(self::getInt2d($recordData, 0))); // the hashed password
+ $this->phpSheet->getProtection()->setPassword($password, true);
+ }
+ }
+
+
+ /**
+ * Read DEFCOLWIDTH record
+ */
+ private function readDefColWidth()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; default column width
+ $width = self::getInt2d($recordData, 0);
+ if ($width != 8) {
+ $this->phpSheet->getDefaultColumnDimension()->setWidth($width);
+ }
+ }
+
+
+ /**
+ * Read COLINFO record
+ */
+ private function readColInfo()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; index to first column in range
+ $fc = self::getInt2d($recordData, 0); // first column index
+
+ // offset: 2; size: 2; index to last column in range
+ $lc = self::getInt2d($recordData, 2); // first column index
+
+ // offset: 4; size: 2; width of the column in 1/256 of the width of the zero character
+ $width = self::getInt2d($recordData, 4);
+
+ // offset: 6; size: 2; index to XF record for default column formatting
+ $xfIndex = self::getInt2d($recordData, 6);
+
+ // offset: 8; size: 2; option flags
+ // bit: 0; mask: 0x0001; 1= columns are hidden
+ $isHidden = (0x0001 & self::getInt2d($recordData, 8)) >> 0;
+
+ // bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline)
+ $level = (0x0700 & self::getInt2d($recordData, 8)) >> 8;
+
+ // bit: 12; mask: 0x1000; 1 = collapsed
+ $isCollapsed = (0x1000 & self::getInt2d($recordData, 8)) >> 12;
+
+ // offset: 10; size: 2; not used
+
+ for ($i = $fc; $i <= $lc; ++$i) {
+ if ($lc == 255 || $lc == 256) {
+ $this->phpSheet->getDefaultColumnDimension()->setWidth($width / 256);
+ break;
+ }
+ $this->phpSheet->getColumnDimensionByColumn($i)->setWidth($width / 256);
+ $this->phpSheet->getColumnDimensionByColumn($i)->setVisible(!$isHidden);
+ $this->phpSheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
+ $this->phpSheet->getColumnDimensionByColumn($i)->setCollapsed($isCollapsed);
+ $this->phpSheet->getColumnDimensionByColumn($i)->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+
+
+ /**
+ * ROW
+ *
+ * This record contains the properties of a single row in a
+ * sheet. Rows and cells in a sheet are divided into blocks
+ * of 32 rows.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readRow()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; index of this row
+ $r = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to column of the first cell which is described by a cell record
+
+ // offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1
+
+ // offset: 6; size: 2;
+
+ // bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
+ $height = (0x7FFF & self::getInt2d($recordData, 6)) >> 0;
+
+ // bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
+ $useDefaultHeight = (0x8000 & self::getInt2d($recordData, 6)) >> 15;
+
+ if (!$useDefaultHeight) {
+ $this->phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
+ }
+
+ // offset: 8; size: 2; not used
+
+ // offset: 10; size: 2; not used in BIFF5-BIFF8
+
+ // offset: 12; size: 4; option flags and default row formatting
+
+ // bit: 2-0: mask: 0x00000007; outline level of the row
+ $level = (0x00000007 & self::getInt4d($recordData, 12)) >> 0;
+ $this->phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);
+
+ // bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
+ $isCollapsed = (0x00000010 & self::getInt4d($recordData, 12)) >> 4;
+ $this->phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);
+
+ // bit: 5; mask: 0x00000020; 1 = row is hidden
+ $isHidden = (0x00000020 & self::getInt4d($recordData, 12)) >> 5;
+ $this->phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);
+
+ // bit: 7; mask: 0x00000080; 1 = row has explicit format
+ $hasExplicitFormat = (0x00000080 & self::getInt4d($recordData, 12)) >> 7;
+
+ // bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
+ $xfIndex = (0x0FFF0000 & self::getInt4d($recordData, 12)) >> 16;
+
+ if ($hasExplicitFormat) {
+ $this->phpSheet->getRowDimension($r + 1)->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+
+
+ /**
+ * Read RK record
+ * This record represents a cell that contains an RK value
+ * (encoded integer or floating-point value). If a
+ * floating-point value cannot be encoded to an RK value,
+ * a NUMBER record will be written. This record replaces the
+ * record INTEGER written in BIFF2.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readRk()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; index to row
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to column
+ $column = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset: 4; size: 2; index to XF record
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ // offset: 6; size: 4; RK value
+ $rknum = self::getInt4d($recordData, 6);
+ $numValue = self::getIEEE754($rknum);
+
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ if (!$this->readDataOnly) {
+ // add style information
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+
+ // add cell
+ $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ }
+ }
+
+
+ /**
+ * Read LABELSST record
+ * This record represents a cell that contains a string. It
+ * replaces the LABEL record and RSTRING record used in
+ * BIFF2-BIFF5.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readLabelSst()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; index to row
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to column
+ $column = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ $emptyCell = true;
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset: 4; size: 2; index to XF record
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ // offset: 6; size: 4; index to SST record
+ $index = self::getInt4d($recordData, 6);
+
+ // add cell
+ if (($fmtRuns = $this->sst[$index]['fmtRuns']) && !$this->readDataOnly) {
+ // then we should treat as rich text
+ $richText = new PHPExcel_RichText();
+ $charPos = 0;
+ $sstCount = count($this->sst[$index]['fmtRuns']);
+ for ($i = 0; $i <= $sstCount; ++$i) {
+ if (isset($fmtRuns[$i])) {
+ $text = PHPExcel_Shared_String::Substring($this->sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos);
+ $charPos = $fmtRuns[$i]['charPos'];
+ } else {
+ $text = PHPExcel_Shared_String::Substring($this->sst[$index]['value'], $charPos, PHPExcel_Shared_String::CountCharacters($this->sst[$index]['value']));
+ }
+
+ if (PHPExcel_Shared_String::CountCharacters($text) > 0) {
+ if ($i == 0) { // first text run, no style
+ $richText->createText($text);
+ } else {
+ $textRun = $richText->createTextRun($text);
+ if (isset($fmtRuns[$i - 1])) {
+ if ($fmtRuns[$i - 1]['fontIndex'] < 4) {
+ $fontIndex = $fmtRuns[$i - 1]['fontIndex'];
+ } else {
+ // this has to do with that index 4 is omitted in all BIFF versions for some strange reason
+ // check the OpenOffice documentation of the FONT record
+ $fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1;
+ }
+ $textRun->setFont(clone $this->objFonts[$fontIndex]);
+ }
+ }
+ }
+ }
+ if ($this->readEmptyCells || trim($richText->getPlainText()) !== '') {
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ $cell->setValueExplicit($richText, PHPExcel_Cell_DataType::TYPE_STRING);
+ $emptyCell = false;
+ }
+ } else {
+ if ($this->readEmptyCells || trim($this->sst[$index]['value']) !== '') {
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ $cell->setValueExplicit($this->sst[$index]['value'], PHPExcel_Cell_DataType::TYPE_STRING);
+ $emptyCell = false;
+ }
+ }
+
+ if (!$this->readDataOnly && !$emptyCell) {
+ // add style information
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+
+
+ /**
+ * Read MULRK record
+ * This record represents a cell range containing RK value
+ * cells. All cells are located in the same row.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readMulRk()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; index to row
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to first column
+ $colFirst = self::getInt2d($recordData, 2);
+
+ // offset: var; size: 2; index to last column
+ $colLast = self::getInt2d($recordData, $length - 2);
+ $columns = $colLast - $colFirst + 1;
+
+ // offset within record data
+ $offset = 4;
+
+ for ($i = 0; $i < $columns; ++$i) {
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($colFirst + $i);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset: var; size: 2; index to XF record
+ $xfIndex = self::getInt2d($recordData, $offset);
+
+ // offset: var; size: 4; RK value
+ $numValue = self::getIEEE754(self::getInt4d($recordData, $offset + 2));
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ if (!$this->readDataOnly) {
+ // add style
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+
+ // add cell value
+ $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ }
+
+ $offset += 6;
+ }
+ }
+
+
+ /**
+ * Read NUMBER record
+ * This record represents a cell that contains a
+ * floating-point value.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readNumber()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; index to row
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size 2; index to column
+ $column = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset 4; size: 2; index to XF record
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ $numValue = self::extractNumber(substr($recordData, 6, 8));
+
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ if (!$this->readDataOnly) {
+ // add cell style
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+
+ // add cell value
+ $cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+ }
+ }
+
+
+ /**
+ * Read FORMULA record + perhaps a following STRING record if formula result is a string
+ * This record contains the token array and the result of a
+ * formula cell.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readFormula()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; row index
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; col index
+ $column = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ // offset: 20: size: variable; formula structure
+ $formulaStructure = substr($recordData, 20);
+
+ // offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
+ $options = self::getInt2d($recordData, 14);
+
+ // bit: 0; mask: 0x0001; 1 = recalculate always
+ // bit: 1; mask: 0x0002; 1 = calculate on open
+ // bit: 2; mask: 0x0008; 1 = part of a shared formula
+ $isPartOfSharedFormula = (bool) (0x0008 & $options);
+
+ // WARNING:
+ // We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
+ // the formula data may be ordinary formula data, therefore we need to check
+ // explicitly for the tExp token (0x01)
+ $isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
+
+ if ($isPartOfSharedFormula) {
+ // part of shared formula which means there will be a formula with a tExp token and nothing else
+ // get the base cell, grab tExp token
+ $baseRow = self::getInt2d($formulaStructure, 3);
+ $baseCol = self::getInt2d($formulaStructure, 5);
+ $this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
+ }
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ if ($isPartOfSharedFormula) {
+ // formula is added to this cell after the sheet has been read
+ $this->sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
+ }
+
+ // offset: 16: size: 4; not used
+
+ // offset: 4; size: 2; XF index
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ // offset: 6; size: 8; result of the formula
+ if ((ord($recordData{6}) == 0) && (ord($recordData{12}) == 255) && (ord($recordData{13}) == 255)) {
+ // String formula. Result follows in appended STRING record
+ $dataType = PHPExcel_Cell_DataType::TYPE_STRING;
+
+ // read possible SHAREDFMLA record
+ $code = self::getInt2d($this->data, $this->pos);
+ if ($code == self::XLS_TYPE_SHAREDFMLA) {
+ $this->readSharedFmla();
+ }
+
+ // read STRING record
+ $value = $this->readString();
+ } elseif ((ord($recordData{6}) == 1)
+ && (ord($recordData{12}) == 255)
+ && (ord($recordData{13}) == 255)) {
+ // Boolean formula. Result is in +2; 0=false, 1=true
+ $dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
+ $value = (bool) ord($recordData{8});
+ } elseif ((ord($recordData{6}) == 2)
+ && (ord($recordData{12}) == 255)
+ && (ord($recordData{13}) == 255)) {
+ // Error formula. Error code is in +2
+ $dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
+ $value = PHPExcel_Reader_Excel5_ErrorCode::lookup(ord($recordData{8}));
+ } elseif ((ord($recordData{6}) == 3)
+ && (ord($recordData{12}) == 255)
+ && (ord($recordData{13}) == 255)) {
+ // Formula result is a null string
+ $dataType = PHPExcel_Cell_DataType::TYPE_NULL;
+ $value = '';
+ } else {
+ // forumla result is a number, first 14 bytes like _NUMBER record
+ $dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $value = self::extractNumber(substr($recordData, 6, 8));
+ }
+
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ if (!$this->readDataOnly) {
+ // add cell style
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+
+ // store the formula
+ if (!$isPartOfSharedFormula) {
+ // not part of shared formula
+ // add cell value. If we can read formula, populate with formula, otherwise just used cached value
+ try {
+ if ($this->version != self::XLS_BIFF8) {
+ throw new PHPExcel_Reader_Exception('Not BIFF8. Can only read BIFF8 formulas');
+ }
+ $formula = $this->getFormulaFromStructure($formulaStructure); // get formula in human language
+ $cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
+
+ } catch (PHPExcel_Exception $e) {
+ $cell->setValueExplicit($value, $dataType);
+ }
+ } else {
+ if ($this->version == self::XLS_BIFF8) {
+ // do nothing at this point, formula id added later in the code
+ } else {
+ $cell->setValueExplicit($value, $dataType);
+ }
+ }
+
+ // store the cached calculated value
+ $cell->setCalculatedValue($value);
+ }
+ }
+
+
+ /**
+ * Read a SHAREDFMLA record. This function just stores the binary shared formula in the reader,
+ * which usually contains relative references.
+ * These will be used to construct the formula in each shared formula part after the sheet is read.
+ */
+ private function readSharedFmla()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0, size: 6; cell range address of the area used by the shared formula, not used for anything
+ $cellRange = substr($recordData, 0, 6);
+ $cellRange = $this->readBIFF5CellRangeAddressFixed($cellRange); // note: even BIFF8 uses BIFF5 syntax
+
+ // offset: 6, size: 1; not used
+
+ // offset: 7, size: 1; number of existing FORMULA records for this shared formula
+ $no = ord($recordData{7});
+
+ // offset: 8, size: var; Binary token array of the shared formula
+ $formula = substr($recordData, 8);
+
+ // at this point we only store the shared formula for later use
+ $this->sharedFormulas[$this->_baseCell] = $formula;
+ }
+
+
+ /**
+ * Read a STRING record from current stream position and advance the stream pointer to next record
+ * This record is used for storing result from FORMULA record when it is a string, and
+ * it occurs directly after the FORMULA record
+ *
+ * @return string The string contents as UTF-8
+ */
+ private function readString()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringLong($recordData);
+ $value = $string['value'];
+ } else {
+ $string = $this->readByteStringLong($recordData);
+ $value = $string['value'];
+ }
+
+ return $value;
+ }
+
+
+ /**
+ * Read BOOLERR record
+ * This record represents a Boolean value or error value
+ * cell.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readBoolErr()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; row index
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; column index
+ $column = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset: 4; size: 2; index to XF record
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ // offset: 6; size: 1; the boolean value or error value
+ $boolErr = ord($recordData{6});
+
+ // offset: 7; size: 1; 0=boolean; 1=error
+ $isError = ord($recordData{7});
+
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ switch ($isError) {
+ case 0: // boolean
+ $value = (bool) $boolErr;
+
+ // add cell value
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_BOOL);
+ break;
+ case 1: // error type
+ $value = PHPExcel_Reader_Excel5_ErrorCode::lookup($boolErr);
+
+ // add cell value
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR);
+ break;
+ }
+
+ if (!$this->readDataOnly) {
+ // add cell style
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+
+
+ /**
+ * Read MULBLANK record
+ * This record represents a cell range of empty cells. All
+ * cells are located in the same row
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readMulBlank()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; index to row
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to first column
+ $fc = self::getInt2d($recordData, 2);
+
+ // offset: 4; size: 2 x nc; list of indexes to XF records
+ // add style information
+ if (!$this->readDataOnly && $this->readEmptyCells) {
+ for ($i = 0; $i < $length / 2 - 3; ++$i) {
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($fc + $i);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ $xfIndex = self::getInt2d($recordData, 4 + 2 * $i);
+ $this->phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+
+ // offset: 6; size 2; index to last column (not needed)
+ }
+
+
+ /**
+ * Read LABEL record
+ * This record represents a cell that contains a string. In
+ * BIFF8 it is usually replaced by the LABELSST record.
+ * Excel still uses this record, if it copies unformatted
+ * text cells to the clipboard.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readLabel()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; index to row
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to column
+ $column = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset: 4; size: 2; XF index
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ // add cell value
+ // todo: what if string is very long? continue record
+ if ($this->version == self::XLS_BIFF8) {
+ $string = self::readUnicodeStringLong(substr($recordData, 6));
+ $value = $string['value'];
+ } else {
+ $string = $this->readByteStringLong(substr($recordData, 6));
+ $value = $string['value'];
+ }
+ if ($this->readEmptyCells || trim($value) !== '') {
+ $cell = $this->phpSheet->getCell($columnString . ($row + 1));
+ $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
+
+ if (!$this->readDataOnly) {
+ // add cell style
+ $cell->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Read BLANK record
+ */
+ private function readBlank()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; row index
+ $row = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; col index
+ $col = self::getInt2d($recordData, 2);
+ $columnString = PHPExcel_Cell::stringFromColumnIndex($col);
+
+ // Read cell?
+ if (($this->getReadFilter() !== null) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->phpSheet->getTitle())) {
+ // offset: 4; size: 2; XF index
+ $xfIndex = self::getInt2d($recordData, 4);
+
+ // add style information
+ if (!$this->readDataOnly && $this->readEmptyCells) {
+ $this->phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->mapCellXfIndex[$xfIndex]);
+ }
+ }
+ }
+
+
+ /**
+ * Read MSODRAWING record
+ */
+ private function readMsoDrawing()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+
+ // get spliced record data
+ $splicedRecordData = $this->getSplicedRecordData();
+ $recordData = $splicedRecordData['recordData'];
+
+ $this->drawingData .= $recordData;
+ }
+
+
+ /**
+ * Read OBJ record
+ */
+ private function readObj()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly || $this->version != self::XLS_BIFF8) {
+ return;
+ }
+
+ // recordData consists of an array of subrecords looking like this:
+ // ft: 2 bytes; ftCmo type (0x15)
+ // cb: 2 bytes; size in bytes of ftCmo data
+ // ot: 2 bytes; Object Type
+ // id: 2 bytes; Object id number
+ // grbit: 2 bytes; Option Flags
+ // data: var; subrecord data
+
+ // for now, we are just interested in the second subrecord containing the object type
+ $ftCmoType = self::getInt2d($recordData, 0);
+ $cbCmoSize = self::getInt2d($recordData, 2);
+ $otObjType = self::getInt2d($recordData, 4);
+ $idObjID = self::getInt2d($recordData, 6);
+ $grbitOpts = self::getInt2d($recordData, 6);
+
+ $this->objs[] = array(
+ 'ftCmoType' => $ftCmoType,
+ 'cbCmoSize' => $cbCmoSize,
+ 'otObjType' => $otObjType,
+ 'idObjID' => $idObjID,
+ 'grbitOpts' => $grbitOpts
+ );
+ $this->textObjRef = $idObjID;
+
+// echo '_readObj() ';
+// var_dump(end($this->objs));
+// echo ' ';
+ }
+
+
+ /**
+ * Read WINDOW2 record
+ */
+ private function readWindow2()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; option flags
+ $options = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; index to first visible row
+ $firstVisibleRow = self::getInt2d($recordData, 2);
+
+ // offset: 4; size: 2; index to first visible colum
+ $firstVisibleColumn = self::getInt2d($recordData, 4);
+ if ($this->version === self::XLS_BIFF8) {
+ // offset: 8; size: 2; not used
+ // offset: 10; size: 2; cached magnification factor in page break preview (in percent); 0 = Default (60%)
+ // offset: 12; size: 2; cached magnification factor in normal view (in percent); 0 = Default (100%)
+ // offset: 14; size: 4; not used
+ $zoomscaleInPageBreakPreview = self::getInt2d($recordData, 10);
+ if ($zoomscaleInPageBreakPreview === 0) {
+ $zoomscaleInPageBreakPreview = 60;
+ }
+ $zoomscaleInNormalView = self::getInt2d($recordData, 12);
+ if ($zoomscaleInNormalView === 0) {
+ $zoomscaleInNormalView = 100;
+ }
+ }
+
+ // bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines
+ $showGridlines = (bool) ((0x0002 & $options) >> 1);
+ $this->phpSheet->setShowGridlines($showGridlines);
+
+ // bit: 2; mask: 0x0004; 0 = do not show headers, 1 = show headers
+ $showRowColHeaders = (bool) ((0x0004 & $options) >> 2);
+ $this->phpSheet->setShowRowColHeaders($showRowColHeaders);
+
+ // bit: 3; mask: 0x0008; 0 = panes are not frozen, 1 = panes are frozen
+ $this->frozen = (bool) ((0x0008 & $options) >> 3);
+
+ // bit: 6; mask: 0x0040; 0 = columns from left to right, 1 = columns from right to left
+ $this->phpSheet->setRightToLeft((bool)((0x0040 & $options) >> 6));
+
+ // bit: 10; mask: 0x0400; 0 = sheet not active, 1 = sheet active
+ $isActive = (bool) ((0x0400 & $options) >> 10);
+ if ($isActive) {
+ $this->phpExcel->setActiveSheetIndex($this->phpExcel->getIndex($this->phpSheet));
+ }
+
+ // bit: 11; mask: 0x0800; 0 = normal view, 1 = page break view
+ $isPageBreakPreview = (bool) ((0x0800 & $options) >> 11);
+
+ //FIXME: set $firstVisibleRow and $firstVisibleColumn
+
+ if ($this->phpSheet->getSheetView()->getView() !== PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT) {
+ //NOTE: this setting is inferior to page layout view(Excel2007-)
+ $view = $isPageBreakPreview ? PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_BREAK_PREVIEW : PHPExcel_Worksheet_SheetView::SHEETVIEW_NORMAL;
+ $this->phpSheet->getSheetView()->setView($view);
+ if ($this->version === self::XLS_BIFF8) {
+ $zoomScale = $isPageBreakPreview ? $zoomscaleInPageBreakPreview : $zoomscaleInNormalView;
+ $this->phpSheet->getSheetView()->setZoomScale($zoomScale);
+ $this->phpSheet->getSheetView()->setZoomScaleNormal($zoomscaleInNormalView);
+ }
+ }
+ }
+
+ /**
+ * Read PLV Record(Created by Excel2007 or upper)
+ */
+ private function readPageLayoutView()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ //var_dump(unpack("vrt/vgrbitFrt/V2reserved/vwScalePLV/vgrbit", $recordData));
+
+ // offset: 0; size: 2; rt
+ //->ignore
+ $rt = self::getInt2d($recordData, 0);
+ // offset: 2; size: 2; grbitfr
+ //->ignore
+ $grbitFrt = self::getInt2d($recordData, 2);
+ // offset: 4; size: 8; reserved
+ //->ignore
+
+ // offset: 12; size 2; zoom scale
+ $wScalePLV = self::getInt2d($recordData, 12);
+ // offset: 14; size 2; grbit
+ $grbit = self::getInt2d($recordData, 14);
+
+ // decomprise grbit
+ $fPageLayoutView = $grbit & 0x01;
+ $fRulerVisible = ($grbit >> 1) & 0x01; //no support
+ $fWhitespaceHidden = ($grbit >> 3) & 0x01; //no support
+
+ if ($fPageLayoutView === 1) {
+ $this->phpSheet->getSheetView()->setView(PHPExcel_Worksheet_SheetView::SHEETVIEW_PAGE_LAYOUT);
+ $this->phpSheet->getSheetView()->setZoomScale($wScalePLV); //set by Excel2007 only if SHEETVIEW_PAGE_LAYOUT
+ }
+ //otherwise, we cannot know whether SHEETVIEW_PAGE_LAYOUT or SHEETVIEW_PAGE_BREAK_PREVIEW.
+ }
+
+ /**
+ * Read SCL record
+ */
+ private function readScl()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // offset: 0; size: 2; numerator of the view magnification
+ $numerator = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; numerator of the view magnification
+ $denumerator = self::getInt2d($recordData, 2);
+
+ // set the zoom scale (in percent)
+ $this->phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator);
+ }
+
+
+ /**
+ * Read PANE record
+ */
+ private function readPane()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; position of vertical split
+ $px = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; position of horizontal split
+ $py = self::getInt2d($recordData, 2);
+
+ if ($this->frozen) {
+ // frozen panes
+ $this->phpSheet->freezePane(PHPExcel_Cell::stringFromColumnIndex($px) . ($py + 1));
+ } else {
+ // unfrozen panes; split windows; not supported by PHPExcel core
+ }
+ }
+ }
+
+
+ /**
+ * Read SELECTION record. There is one such record for each pane in the sheet.
+ */
+ private function readSelection()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 1; pane identifier
+ $paneId = ord($recordData{0});
+
+ // offset: 1; size: 2; index to row of the active cell
+ $r = self::getInt2d($recordData, 1);
+
+ // offset: 3; size: 2; index to column of the active cell
+ $c = self::getInt2d($recordData, 3);
+
+ // offset: 5; size: 2; index into the following cell range list to the
+ // entry that contains the active cell
+ $index = self::getInt2d($recordData, 5);
+
+ // offset: 7; size: var; cell range address list containing all selected cell ranges
+ $data = substr($recordData, 7);
+ $cellRangeAddressList = $this->readBIFF5CellRangeAddressList($data); // note: also BIFF8 uses BIFF5 syntax
+
+ $selectedCells = $cellRangeAddressList['cellRangeAddresses'][0];
+
+ // first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
+ if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
+ $selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
+ }
+
+ // first row '1' + last row '65536' indicates that full column is selected
+ if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
+ $selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
+ }
+
+ // first column 'A' + last column 'IV' indicates that full row is selected
+ if (preg_match('/^(A[0-9]+\:)IV([0-9]+)$/', $selectedCells)) {
+ $selectedCells = preg_replace('/^(A[0-9]+\:)IV([0-9]+)$/', '${1}XFD${2}', $selectedCells);
+ }
+
+ $this->phpSheet->setSelectedCells($selectedCells);
+ }
+ }
+
+
+ private function includeCellRangeFiltered($cellRangeAddress)
+ {
+ $includeCellRange = true;
+ if ($this->getReadFilter() !== null) {
+ $includeCellRange = false;
+ $rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress);
+ $rangeBoundaries[1][0]++;
+ for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) {
+ for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) {
+ if ($this->getReadFilter()->readCell($column, $row, $this->phpSheet->getTitle())) {
+ $includeCellRange = true;
+ break 2;
+ }
+ }
+ }
+ }
+ return $includeCellRange;
+ }
+
+
+ /**
+ * MERGEDCELLS
+ *
+ * This record contains the addresses of merged cell ranges
+ * in the current sheet.
+ *
+ * -- "OpenOffice.org's Documentation of the Microsoft
+ * Excel File Format"
+ */
+ private function readMergedCells()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->version == self::XLS_BIFF8 && !$this->readDataOnly) {
+ $cellRangeAddressList = $this->readBIFF8CellRangeAddressList($recordData);
+ foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) {
+ if ((strpos($cellRangeAddress, ':') !== false) &&
+ ($this->includeCellRangeFiltered($cellRangeAddress))) {
+ $this->phpSheet->mergeCells($cellRangeAddress);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Read HYPERLINK record
+ */
+ private function readHyperLink()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer forward to next record
+ $this->pos += 4 + $length;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 8; cell range address of all cells containing this hyperlink
+ try {
+ $cellRange = $this->readBIFF8CellRangeAddressFixed($recordData, 0, 8);
+ } catch (PHPExcel_Exception $e) {
+ return;
+ }
+
+ // offset: 8, size: 16; GUID of StdLink
+
+ // offset: 24, size: 4; unknown value
+
+ // offset: 28, size: 4; option flags
+ // bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL
+ $isFileLinkOrUrl = (0x00000001 & self::getInt2d($recordData, 28)) >> 0;
+
+ // bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL
+ $isAbsPathOrUrl = (0x00000001 & self::getInt2d($recordData, 28)) >> 1;
+
+ // bit: 2 (and 4); mask: 0x00000014; 0 = no description
+ $hasDesc = (0x00000014 & self::getInt2d($recordData, 28)) >> 2;
+
+ // bit: 3; mask: 0x00000008; 0 = no text, 1 = has text
+ $hasText = (0x00000008 & self::getInt2d($recordData, 28)) >> 3;
+
+ // bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame
+ $hasFrame = (0x00000080 & self::getInt2d($recordData, 28)) >> 7;
+
+ // bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name)
+ $isUNC = (0x00000100 & self::getInt2d($recordData, 28)) >> 8;
+
+ // offset within record data
+ $offset = 32;
+
+ if ($hasDesc) {
+ // offset: 32; size: var; character count of description text
+ $dl = self::getInt4d($recordData, 32);
+ // offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated
+ $desc = self::encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false);
+ $offset += 4 + 2 * $dl;
+ }
+ if ($hasFrame) {
+ $fl = self::getInt4d($recordData, $offset);
+ $offset += 4 + 2 * $fl;
+ }
+
+ // detect type of hyperlink (there are 4 types)
+ $hyperlinkType = null;
+
+ if ($isUNC) {
+ $hyperlinkType = 'UNC';
+ } elseif (!$isFileLinkOrUrl) {
+ $hyperlinkType = 'workbook';
+ } elseif (ord($recordData{$offset}) == 0x03) {
+ $hyperlinkType = 'local';
+ } elseif (ord($recordData{$offset}) == 0xE0) {
+ $hyperlinkType = 'URL';
+ }
+
+ switch ($hyperlinkType) {
+ case 'URL':
+ // section 5.58.2: Hyperlink containing a URL
+ // e.g. http://example.org/index.php
+
+ // offset: var; size: 16; GUID of URL Moniker
+ $offset += 16;
+ // offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word
+ $us = self::getInt4d($recordData, $offset);
+ $offset += 4;
+ // offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated
+ $url = self::encodeUTF16(substr($recordData, $offset, $us - 2), false);
+ $nullOffset = strpos($url, 0x00);
+ if ($nullOffset) {
+ $url = substr($url, 0, $nullOffset);
+ }
+ $url .= $hasText ? '#' : '';
+ $offset += $us;
+ break;
+ case 'local':
+ // section 5.58.3: Hyperlink to local file
+ // examples:
+ // mydoc.txt
+ // ../../somedoc.xls#Sheet!A1
+
+ // offset: var; size: 16; GUI of File Moniker
+ $offset += 16;
+
+ // offset: var; size: 2; directory up-level count.
+ $upLevelCount = self::getInt2d($recordData, $offset);
+ $offset += 2;
+
+ // offset: var; size: 4; character count of the shortened file path and name, including trailing zero word
+ $sl = self::getInt4d($recordData, $offset);
+ $offset += 4;
+
+ // offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string)
+ $shortenedFilePath = substr($recordData, $offset, $sl);
+ $shortenedFilePath = self::encodeUTF16($shortenedFilePath, true);
+ $shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero
+
+ $offset += $sl;
+
+ // offset: var; size: 24; unknown sequence
+ $offset += 24;
+
+ // extended file path
+ // offset: var; size: 4; size of the following file link field including string lenth mark
+ $sz = self::getInt4d($recordData, $offset);
+ $offset += 4;
+
+ // only present if $sz > 0
+ if ($sz > 0) {
+ // offset: var; size: 4; size of the character array of the extended file path and name
+ $xl = self::getInt4d($recordData, $offset);
+ $offset += 4;
+
+ // offset: var; size 2; unknown
+ $offset += 2;
+
+ // offset: var; size $xl; character array of the extended file path and name.
+ $extendedFilePath = substr($recordData, $offset, $xl);
+ $extendedFilePath = self::encodeUTF16($extendedFilePath, false);
+ $offset += $xl;
+ }
+
+ // construct the path
+ $url = str_repeat('..\\', $upLevelCount);
+ $url .= ($sz > 0) ? $extendedFilePath : $shortenedFilePath; // use extended path if available
+ $url .= $hasText ? '#' : '';
+
+ break;
+ case 'UNC':
+ // section 5.58.4: Hyperlink to a File with UNC (Universal Naming Convention) Path
+ // todo: implement
+ return;
+ case 'workbook':
+ // section 5.58.5: Hyperlink to the Current Workbook
+ // e.g. Sheet2!B1:C2, stored in text mark field
+ $url = 'sheet://';
+ break;
+ default:
+ return;
+ }
+
+ if ($hasText) {
+ // offset: var; size: 4; character count of text mark including trailing zero word
+ $tl = self::getInt4d($recordData, $offset);
+ $offset += 4;
+ // offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated
+ $text = self::encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false);
+ $url .= $text;
+ }
+
+ // apply the hyperlink to all the relevant cells
+ foreach (PHPExcel_Cell::extractAllCellReferencesInRange($cellRange) as $coordinate) {
+ $this->phpSheet->getCell($coordinate)->getHyperLink()->setUrl($url);
+ }
+ }
+ }
+
+
+ /**
+ * Read DATAVALIDATIONS record
+ */
+ private function readDataValidations()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer forward to next record
+ $this->pos += 4 + $length;
+ }
+
+
+ /**
+ * Read DATAVALIDATION record
+ */
+ private function readDataValidation()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer forward to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ // offset: 0; size: 4; Options
+ $options = self::getInt4d($recordData, 0);
+
+ // bit: 0-3; mask: 0x0000000F; type
+ $type = (0x0000000F & $options) >> 0;
+ switch ($type) {
+ case 0x00:
+ $type = PHPExcel_Cell_DataValidation::TYPE_NONE;
+ break;
+ case 0x01:
+ $type = PHPExcel_Cell_DataValidation::TYPE_WHOLE;
+ break;
+ case 0x02:
+ $type = PHPExcel_Cell_DataValidation::TYPE_DECIMAL;
+ break;
+ case 0x03:
+ $type = PHPExcel_Cell_DataValidation::TYPE_LIST;
+ break;
+ case 0x04:
+ $type = PHPExcel_Cell_DataValidation::TYPE_DATE;
+ break;
+ case 0x05:
+ $type = PHPExcel_Cell_DataValidation::TYPE_TIME;
+ break;
+ case 0x06:
+ $type = PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH;
+ break;
+ case 0x07:
+ $type = PHPExcel_Cell_DataValidation::TYPE_CUSTOM;
+ break;
+ }
+
+ // bit: 4-6; mask: 0x00000070; error type
+ $errorStyle = (0x00000070 & $options) >> 4;
+ switch ($errorStyle) {
+ case 0x00:
+ $errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;
+ break;
+ case 0x01:
+ $errorStyle = PHPExcel_Cell_DataValidation::STYLE_WARNING;
+ break;
+ case 0x02:
+ $errorStyle = PHPExcel_Cell_DataValidation::STYLE_INFORMATION;
+ break;
+ }
+
+ // bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list)
+ // I have only seen cases where this is 1
+ $explicitFormula = (0x00000080 & $options) >> 7;
+
+ // bit: 8; mask: 0x00000100; 1= empty cells allowed
+ $allowBlank = (0x00000100 & $options) >> 8;
+
+ // bit: 9; mask: 0x00000200; 1= suppress drop down arrow in list type validity
+ $suppressDropDown = (0x00000200 & $options) >> 9;
+
+ // bit: 18; mask: 0x00040000; 1= show prompt box if cell selected
+ $showInputMessage = (0x00040000 & $options) >> 18;
+
+ // bit: 19; mask: 0x00080000; 1= show error box if invalid values entered
+ $showErrorMessage = (0x00080000 & $options) >> 19;
+
+ // bit: 20-23; mask: 0x00F00000; condition operator
+ $operator = (0x00F00000 & $options) >> 20;
+ switch ($operator) {
+ case 0x00:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN;
+ break;
+ case 0x01:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN;
+ break;
+ case 0x02:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_EQUAL;
+ break;
+ case 0x03:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL;
+ break;
+ case 0x04:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN;
+ break;
+ case 0x05:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN;
+ break;
+ case 0x06:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL;
+ break;
+ case 0x07:
+ $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL;
+ break;
+ }
+
+ // offset: 4; size: var; title of the prompt box
+ $offset = 4;
+ $string = self::readUnicodeStringLong(substr($recordData, $offset));
+ $promptTitle = $string['value'] !== chr(0) ? $string['value'] : '';
+ $offset += $string['size'];
+
+ // offset: var; size: var; title of the error box
+ $string = self::readUnicodeStringLong(substr($recordData, $offset));
+ $errorTitle = $string['value'] !== chr(0) ? $string['value'] : '';
+ $offset += $string['size'];
+
+ // offset: var; size: var; text of the prompt box
+ $string = self::readUnicodeStringLong(substr($recordData, $offset));
+ $prompt = $string['value'] !== chr(0) ? $string['value'] : '';
+ $offset += $string['size'];
+
+ // offset: var; size: var; text of the error box
+ $string = self::readUnicodeStringLong(substr($recordData, $offset));
+ $error = $string['value'] !== chr(0) ? $string['value'] : '';
+ $offset += $string['size'];
+
+ // offset: var; size: 2; size of the formula data for the first condition
+ $sz1 = self::getInt2d($recordData, $offset);
+ $offset += 2;
+
+ // offset: var; size: 2; not used
+ $offset += 2;
+
+ // offset: var; size: $sz1; formula data for first condition (without size field)
+ $formula1 = substr($recordData, $offset, $sz1);
+ $formula1 = pack('v', $sz1) . $formula1; // prepend the length
+ try {
+ $formula1 = $this->getFormulaFromStructure($formula1);
+
+ // in list type validity, null characters are used as item separators
+ if ($type == PHPExcel_Cell_DataValidation::TYPE_LIST) {
+ $formula1 = str_replace(chr(0), ',', $formula1);
+ }
+ } catch (PHPExcel_Exception $e) {
+ return;
+ }
+ $offset += $sz1;
+
+ // offset: var; size: 2; size of the formula data for the first condition
+ $sz2 = self::getInt2d($recordData, $offset);
+ $offset += 2;
+
+ // offset: var; size: 2; not used
+ $offset += 2;
+
+ // offset: var; size: $sz2; formula data for second condition (without size field)
+ $formula2 = substr($recordData, $offset, $sz2);
+ $formula2 = pack('v', $sz2) . $formula2; // prepend the length
+ try {
+ $formula2 = $this->getFormulaFromStructure($formula2);
+ } catch (PHPExcel_Exception $e) {
+ return;
+ }
+ $offset += $sz2;
+
+ // offset: var; size: var; cell range address list with
+ $cellRangeAddressList = $this->readBIFF8CellRangeAddressList(substr($recordData, $offset));
+ $cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses'];
+
+ foreach ($cellRangeAddresses as $cellRange) {
+ $stRange = $this->phpSheet->shrinkRangeToFit($cellRange);
+ foreach (PHPExcel_Cell::extractAllCellReferencesInRange($stRange) as $coordinate) {
+ $objValidation = $this->phpSheet->getCell($coordinate)->getDataValidation();
+ $objValidation->setType($type);
+ $objValidation->setErrorStyle($errorStyle);
+ $objValidation->setAllowBlank((bool)$allowBlank);
+ $objValidation->setShowInputMessage((bool)$showInputMessage);
+ $objValidation->setShowErrorMessage((bool)$showErrorMessage);
+ $objValidation->setShowDropDown(!$suppressDropDown);
+ $objValidation->setOperator($operator);
+ $objValidation->setErrorTitle($errorTitle);
+ $objValidation->setError($error);
+ $objValidation->setPromptTitle($promptTitle);
+ $objValidation->setPrompt($prompt);
+ $objValidation->setFormula1($formula1);
+ $objValidation->setFormula2($formula2);
+ }
+ }
+ }
+
+ /**
+ * Read SHEETLAYOUT record. Stores sheet tab color information.
+ */
+ private function readSheetLayout()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // local pointer in record data
+ $offset = 0;
+
+ if (!$this->readDataOnly) {
+ // offset: 0; size: 2; repeated record identifier 0x0862
+
+ // offset: 2; size: 10; not used
+
+ // offset: 12; size: 4; size of record data
+ // Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
+ $sz = self::getInt4d($recordData, 12);
+
+ switch ($sz) {
+ case 0x14:
+ // offset: 16; size: 2; color index for sheet tab
+ $colorIndex = self::getInt2d($recordData, 16);
+ $color = PHPExcel_Reader_Excel5_Color::map($colorIndex, $this->palette, $this->version);
+ $this->phpSheet->getTabColor()->setRGB($color['rgb']);
+ break;
+ case 0x28:
+ // TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
+ return;
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Read SHEETPROTECTION record (FEATHEADR)
+ */
+ private function readSheetProtection()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ if ($this->readDataOnly) {
+ return;
+ }
+
+ // offset: 0; size: 2; repeated record header
+
+ // offset: 2; size: 2; FRT cell reference flag (=0 currently)
+
+ // offset: 4; size: 8; Currently not used and set to 0
+
+ // offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag)
+ $isf = self::getInt2d($recordData, 12);
+ if ($isf != 2) {
+ return;
+ }
+
+ // offset: 14; size: 1; =1 since this is a feat header
+
+ // offset: 15; size: 4; size of rgbHdrSData
+
+ // rgbHdrSData, assume "Enhanced Protection"
+ // offset: 19; size: 2; option flags
+ $options = self::getInt2d($recordData, 19);
+
+ // bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects
+ $bool = (0x0001 & $options) >> 0;
+ $this->phpSheet->getProtection()->setObjects(!$bool);
+
+ // bit: 1; mask 0x0002; edit scenarios
+ $bool = (0x0002 & $options) >> 1;
+ $this->phpSheet->getProtection()->setScenarios(!$bool);
+
+ // bit: 2; mask 0x0004; format cells
+ $bool = (0x0004 & $options) >> 2;
+ $this->phpSheet->getProtection()->setFormatCells(!$bool);
+
+ // bit: 3; mask 0x0008; format columns
+ $bool = (0x0008 & $options) >> 3;
+ $this->phpSheet->getProtection()->setFormatColumns(!$bool);
+
+ // bit: 4; mask 0x0010; format rows
+ $bool = (0x0010 & $options) >> 4;
+ $this->phpSheet->getProtection()->setFormatRows(!$bool);
+
+ // bit: 5; mask 0x0020; insert columns
+ $bool = (0x0020 & $options) >> 5;
+ $this->phpSheet->getProtection()->setInsertColumns(!$bool);
+
+ // bit: 6; mask 0x0040; insert rows
+ $bool = (0x0040 & $options) >> 6;
+ $this->phpSheet->getProtection()->setInsertRows(!$bool);
+
+ // bit: 7; mask 0x0080; insert hyperlinks
+ $bool = (0x0080 & $options) >> 7;
+ $this->phpSheet->getProtection()->setInsertHyperlinks(!$bool);
+
+ // bit: 8; mask 0x0100; delete columns
+ $bool = (0x0100 & $options) >> 8;
+ $this->phpSheet->getProtection()->setDeleteColumns(!$bool);
+
+ // bit: 9; mask 0x0200; delete rows
+ $bool = (0x0200 & $options) >> 9;
+ $this->phpSheet->getProtection()->setDeleteRows(!$bool);
+
+ // bit: 10; mask 0x0400; select locked cells
+ $bool = (0x0400 & $options) >> 10;
+ $this->phpSheet->getProtection()->setSelectLockedCells(!$bool);
+
+ // bit: 11; mask 0x0800; sort cell range
+ $bool = (0x0800 & $options) >> 11;
+ $this->phpSheet->getProtection()->setSort(!$bool);
+
+ // bit: 12; mask 0x1000; auto filter
+ $bool = (0x1000 & $options) >> 12;
+ $this->phpSheet->getProtection()->setAutoFilter(!$bool);
+
+ // bit: 13; mask 0x2000; pivot tables
+ $bool = (0x2000 & $options) >> 13;
+ $this->phpSheet->getProtection()->setPivotTables(!$bool);
+
+ // bit: 14; mask 0x4000; select unlocked cells
+ $bool = (0x4000 & $options) >> 14;
+ $this->phpSheet->getProtection()->setSelectUnlockedCells(!$bool);
+
+ // offset: 21; size: 2; not used
+ }
+
+
+ /**
+ * Read RANGEPROTECTION record
+ * Reading of this record is based on Microsoft Office Excel 97-2000 Binary File Format Specification,
+ * where it is referred to as FEAT record
+ */
+ private function readRangeProtection()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ // local pointer in record data
+ $offset = 0;
+
+ if (!$this->readDataOnly) {
+ $offset += 12;
+
+ // offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
+ $isf = self::getInt2d($recordData, 12);
+ if ($isf != 2) {
+ // we only read FEAT records of type 2
+ return;
+ }
+ $offset += 2;
+
+ $offset += 5;
+
+ // offset: 19; size: 2; count of ref ranges this feature is on
+ $cref = self::getInt2d($recordData, 19);
+ $offset += 2;
+
+ $offset += 6;
+
+ // offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
+ $cellRanges = array();
+ for ($i = 0; $i < $cref; ++$i) {
+ try {
+ $cellRange = $this->readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
+ } catch (PHPExcel_Exception $e) {
+ return;
+ }
+ $cellRanges[] = $cellRange;
+ $offset += 8;
+ }
+
+ // offset: var; size: var; variable length of feature specific data
+ $rgbFeat = substr($recordData, $offset);
+ $offset += 4;
+
+ // offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
+ $wPassword = self::getInt4d($recordData, $offset);
+ $offset += 4;
+
+ // Apply range protection to sheet
+ if ($cellRanges) {
+ $this->phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
+ }
+ }
+ }
+
+
+ /**
+ * Read IMDATA record
+ */
+ private function readImData()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+
+ // get spliced record data
+ $splicedRecordData = $this->getSplicedRecordData();
+ $recordData = $splicedRecordData['recordData'];
+
+ // UNDER CONSTRUCTION
+
+ // offset: 0; size: 2; image format
+ $cf = self::getInt2d($recordData, 0);
+
+ // offset: 2; size: 2; environment from which the file was written
+ $env = self::getInt2d($recordData, 2);
+
+ // offset: 4; size: 4; length of the image data
+ $lcb = self::getInt4d($recordData, 4);
+
+ // offset: 8; size: var; image data
+ $iData = substr($recordData, 8);
+
+ switch ($cf) {
+ case 0x09: // Windows bitmap format
+ // BITMAPCOREINFO
+ // 1. BITMAPCOREHEADER
+ // offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure
+ $bcSize = self::getInt4d($iData, 0);
+ // var_dump($bcSize);
+
+ // offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels
+ $bcWidth = self::getInt2d($iData, 4);
+ // var_dump($bcWidth);
+
+ // offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels.
+ $bcHeight = self::getInt2d($iData, 6);
+ // var_dump($bcHeight);
+ $ih = imagecreatetruecolor($bcWidth, $bcHeight);
+
+ // offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1
+
+ // offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24
+ $bcBitCount = self::getInt2d($iData, 10);
+ // var_dump($bcBitCount);
+
+ $rgbString = substr($iData, 12);
+ $rgbTriples = array();
+ while (strlen($rgbString) > 0) {
+ $rgbTriples[] = unpack('Cb/Cg/Cr', $rgbString);
+ $rgbString = substr($rgbString, 3);
+ }
+ $x = 0;
+ $y = 0;
+ foreach ($rgbTriples as $i => $rgbTriple) {
+ $color = imagecolorallocate($ih, $rgbTriple['r'], $rgbTriple['g'], $rgbTriple['b']);
+ imagesetpixel($ih, $x, $bcHeight - 1 - $y, $color);
+ $x = ($x + 1) % $bcWidth;
+ $y = $y + floor(($x + 1) / $bcWidth);
+ }
+ //imagepng($ih, 'image.png');
+
+ $drawing = new PHPExcel_Worksheet_Drawing();
+ $drawing->setPath($filename);
+ $drawing->setWorksheet($this->phpSheet);
+ break;
+ case 0x02: // Windows metafile or Macintosh PICT format
+ case 0x0e: // native format
+ default:
+ break;
+ }
+
+ // getSplicedRecordData() takes care of moving current position in data stream
+ }
+
+
+ /**
+ * Read a free CONTINUE record. Free CONTINUE record may be a camouflaged MSODRAWING record
+ * When MSODRAWING data on a sheet exceeds 8224 bytes, CONTINUE records are used instead. Undocumented.
+ * In this case, we must treat the CONTINUE record as a MSODRAWING record
+ */
+ private function readContinue()
+ {
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ // check if we are reading drawing data
+ // this is in case a free CONTINUE record occurs in other circumstances we are unaware of
+ if ($this->drawingData == '') {
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ return;
+ }
+
+ // check if record data is at least 4 bytes long, otherwise there is no chance this is MSODRAWING data
+ if ($length < 4) {
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+
+ return;
+ }
+
+ // dirty check to see if CONTINUE record could be a camouflaged MSODRAWING record
+ // look inside CONTINUE record to see if it looks like a part of an Escher stream
+ // we know that Escher stream may be split at least at
+ // 0xF003 MsofbtSpgrContainer
+ // 0xF004 MsofbtSpContainer
+ // 0xF00D MsofbtClientTextbox
+ $validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more
+
+ $splitPoint = self::getInt2d($recordData, 2);
+ if (in_array($splitPoint, $validSplitPoints)) {
+ // get spliced record data (and move pointer to next record)
+ $splicedRecordData = $this->getSplicedRecordData();
+ $this->drawingData .= $splicedRecordData['recordData'];
+
+ return;
+ }
+
+ // move stream pointer to next record
+ $this->pos += 4 + $length;
+ }
+
+
+ /**
+ * Reads a record from current position in data stream and continues reading data as long as CONTINUE
+ * records are found. Splices the record data pieces and returns the combined string as if record data
+ * is in one piece.
+ * Moves to next current position in data stream to start of next record different from a CONtINUE record
+ *
+ * @return array
+ */
+ private function getSplicedRecordData()
+ {
+ $data = '';
+ $spliceOffsets = array();
+
+ $i = 0;
+ $spliceOffsets[0] = 0;
+
+ do {
+ ++$i;
+
+ // offset: 0; size: 2; identifier
+ $identifier = self::getInt2d($this->data, $this->pos);
+ // offset: 2; size: 2; length
+ $length = self::getInt2d($this->data, $this->pos + 2);
+ $data .= $this->readRecordData($this->data, $this->pos + 4, $length);
+
+ $spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;
+
+ $this->pos += 4 + $length;
+ $nextIdentifier = self::getInt2d($this->data, $this->pos);
+ } while ($nextIdentifier == self::XLS_TYPE_CONTINUE);
+
+ $splicedData = array(
+ 'recordData' => $data,
+ 'spliceOffsets' => $spliceOffsets,
+ );
+
+ return $splicedData;
+
+ }
+
+
+ /**
+ * Convert formula structure into human readable Excel formula like 'A3+A5*5'
+ *
+ * @param string $formulaStructure The complete binary data for the formula
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+ * @return string Human readable formula
+ */
+ private function getFormulaFromStructure($formulaStructure, $baseCell = 'A1')
+ {
+ // offset: 0; size: 2; size of the following formula data
+ $sz = self::getInt2d($formulaStructure, 0);
+
+ // offset: 2; size: sz
+ $formulaData = substr($formulaStructure, 2, $sz);
+
+ // for debug: dump the formula data
+ //echo '';
+ //echo 'size: ' . $sz . "\n";
+ //echo 'the entire formula data: ';
+ //Debug::dump($formulaData);
+ //echo "\n----\n";
+
+ // offset: 2 + sz; size: variable (optional)
+ if (strlen($formulaStructure) > 2 + $sz) {
+ $additionalData = substr($formulaStructure, 2 + $sz);
+
+ // for debug: dump the additional data
+ //echo 'the entire additional data: ';
+ //Debug::dump($additionalData);
+ //echo "\n----\n";
+ } else {
+ $additionalData = '';
+ }
+
+ return $this->getFormulaFromData($formulaData, $additionalData, $baseCell);
+ }
+
+
+ /**
+ * Take formula data and additional data for formula and return human readable formula
+ *
+ * @param string $formulaData The binary data for the formula itself
+ * @param string $additionalData Additional binary data going with the formula
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+ * @return string Human readable formula
+ */
+ private function getFormulaFromData($formulaData, $additionalData = '', $baseCell = 'A1')
+ {
+ // start parsing the formula data
+ $tokens = array();
+
+ while (strlen($formulaData) > 0 and $token = $this->getNextToken($formulaData, $baseCell)) {
+ $tokens[] = $token;
+ $formulaData = substr($formulaData, $token['size']);
+
+ // for debug: dump the token
+ //var_dump($token);
+ }
+
+ $formulaString = $this->createFormulaFromTokens($tokens, $additionalData);
+
+ return $formulaString;
+ }
+
+
+ /**
+ * Take array of tokens together with additional data for formula and return human readable formula
+ *
+ * @param array $tokens
+ * @param array $additionalData Additional binary data going with the formula
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+ * @return string Human readable formula
+ */
+ private function createFormulaFromTokens($tokens, $additionalData)
+ {
+ // empty formula?
+ if (empty($tokens)) {
+ return '';
+ }
+
+ $formulaStrings = array();
+ foreach ($tokens as $token) {
+ // initialize spaces
+ $space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
+ $space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
+ $space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
+ $space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
+ $space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
+ $space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
+
+ switch ($token['name']) {
+ case 'tAdd': // addition
+ case 'tConcat': // addition
+ case 'tDiv': // division
+ case 'tEQ': // equality
+ case 'tGE': // greater than or equal
+ case 'tGT': // greater than
+ case 'tIsect': // intersection
+ case 'tLE': // less than or equal
+ case 'tList': // less than or equal
+ case 'tLT': // less than
+ case 'tMul': // multiplication
+ case 'tNE': // multiplication
+ case 'tPower': // power
+ case 'tRange': // range
+ case 'tSub': // subtraction
+ $op2 = array_pop($formulaStrings);
+ $op1 = array_pop($formulaStrings);
+ $formulaStrings[] = "$op1$space1$space0{$token['data']}$op2";
+ unset($space0, $space1);
+ break;
+ case 'tUplus': // unary plus
+ case 'tUminus': // unary minus
+ $op = array_pop($formulaStrings);
+ $formulaStrings[] = "$space1$space0{$token['data']}$op";
+ unset($space0, $space1);
+ break;
+ case 'tPercent': // percent sign
+ $op = array_pop($formulaStrings);
+ $formulaStrings[] = "$op$space1$space0{$token['data']}";
+ unset($space0, $space1);
+ break;
+ case 'tAttrVolatile': // indicates volatile function
+ case 'tAttrIf':
+ case 'tAttrSkip':
+ case 'tAttrChoose':
+ // token is only important for Excel formula evaluator
+ // do nothing
+ break;
+ case 'tAttrSpace': // space / carriage return
+ // space will be used when next token arrives, do not alter formulaString stack
+ switch ($token['data']['spacetype']) {
+ case 'type0':
+ $space0 = str_repeat(' ', $token['data']['spacecount']);
+ break;
+ case 'type1':
+ $space1 = str_repeat("\n", $token['data']['spacecount']);
+ break;
+ case 'type2':
+ $space2 = str_repeat(' ', $token['data']['spacecount']);
+ break;
+ case 'type3':
+ $space3 = str_repeat("\n", $token['data']['spacecount']);
+ break;
+ case 'type4':
+ $space4 = str_repeat(' ', $token['data']['spacecount']);
+ break;
+ case 'type5':
+ $space5 = str_repeat("\n", $token['data']['spacecount']);
+ break;
+ }
+ break;
+ case 'tAttrSum': // SUM function with one parameter
+ $op = array_pop($formulaStrings);
+ $formulaStrings[] = "{$space1}{$space0}SUM($op)";
+ unset($space0, $space1);
+ break;
+ case 'tFunc': // function with fixed number of arguments
+ case 'tFuncV': // function with variable number of arguments
+ if ($token['data']['function'] != '') {
+ // normal function
+ $ops = array(); // array of operators
+ for ($i = 0; $i < $token['data']['args']; ++$i) {
+ $ops[] = array_pop($formulaStrings);
+ }
+ $ops = array_reverse($ops);
+ $formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ")";
+ unset($space0, $space1);
+ } else {
+ // add-in function
+ $ops = array(); // array of operators
+ for ($i = 0; $i < $token['data']['args'] - 1; ++$i) {
+ $ops[] = array_pop($formulaStrings);
+ }
+ $ops = array_reverse($ops);
+ $function = array_pop($formulaStrings);
+ $formulaStrings[] = "$space1$space0$function(" . implode(',', $ops) . ")";
+ unset($space0, $space1);
+ }
+ break;
+ case 'tParen': // parenthesis
+ $expression = array_pop($formulaStrings);
+ $formulaStrings[] = "$space3$space2($expression$space5$space4)";
+ unset($space2, $space3, $space4, $space5);
+ break;
+ case 'tArray': // array constant
+ $constantArray = self::readBIFF8ConstantArray($additionalData);
+ $formulaStrings[] = $space1 . $space0 . $constantArray['value'];
+ $additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data
+ unset($space0, $space1);
+ break;
+ case 'tMemArea':
+ // bite off chunk of additional data
+ $cellRangeAddressList = $this->readBIFF8CellRangeAddressList($additionalData);
+ $additionalData = substr($additionalData, $cellRangeAddressList['size']);
+ $formulaStrings[] = "$space1$space0{$token['data']}";
+ unset($space0, $space1);
+ break;
+ case 'tArea': // cell range address
+ case 'tBool': // boolean
+ case 'tErr': // error code
+ case 'tInt': // integer
+ case 'tMemErr':
+ case 'tMemFunc':
+ case 'tMissArg':
+ case 'tName':
+ case 'tNameX':
+ case 'tNum': // number
+ case 'tRef': // single cell reference
+ case 'tRef3d': // 3d cell reference
+ case 'tArea3d': // 3d cell range reference
+ case 'tRefN':
+ case 'tAreaN':
+ case 'tStr': // string
+ $formulaStrings[] = "$space1$space0{$token['data']}";
+ unset($space0, $space1);
+ break;
+ }
+ }
+ $formulaString = $formulaStrings[0];
+
+ // for debug: dump the human readable formula
+ //echo '----' . "\n";
+ //echo 'Formula: ' . $formulaString;
+
+ return $formulaString;
+ }
+
+
+ /**
+ * Fetch next token from binary formula data
+ *
+ * @param string Formula data
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+ * @return array
+ * @throws PHPExcel_Reader_Exception
+ */
+ private function getNextToken($formulaData, $baseCell = 'A1')
+ {
+ // offset: 0; size: 1; token id
+ $id = ord($formulaData[0]); // token id
+ $name = false; // initialize token name
+
+ switch ($id) {
+ case 0x03:
+ $name = 'tAdd';
+ $size = 1;
+ $data = '+';
+ break;
+ case 0x04:
+ $name = 'tSub';
+ $size = 1;
+ $data = '-';
+ break;
+ case 0x05:
+ $name = 'tMul';
+ $size = 1;
+ $data = '*';
+ break;
+ case 0x06:
+ $name = 'tDiv';
+ $size = 1;
+ $data = '/';
+ break;
+ case 0x07:
+ $name = 'tPower';
+ $size = 1;
+ $data = '^';
+ break;
+ case 0x08:
+ $name = 'tConcat';
+ $size = 1;
+ $data = '&';
+ break;
+ case 0x09:
+ $name = 'tLT';
+ $size = 1;
+ $data = '<';
+ break;
+ case 0x0A:
+ $name = 'tLE';
+ $size = 1;
+ $data = '<=';
+ break;
+ case 0x0B:
+ $name = 'tEQ';
+ $size = 1;
+ $data = '=';
+ break;
+ case 0x0C:
+ $name = 'tGE';
+ $size = 1;
+ $data = '>=';
+ break;
+ case 0x0D:
+ $name = 'tGT';
+ $size = 1;
+ $data = '>';
+ break;
+ case 0x0E:
+ $name = 'tNE';
+ $size = 1;
+ $data = '<>';
+ break;
+ case 0x0F:
+ $name = 'tIsect';
+ $size = 1;
+ $data = ' ';
+ break;
+ case 0x10:
+ $name = 'tList';
+ $size = 1;
+ $data = ',';
+ break;
+ case 0x11:
+ $name = 'tRange';
+ $size = 1;
+ $data = ':';
+ break;
+ case 0x12:
+ $name = 'tUplus';
+ $size = 1;
+ $data = '+';
+ break;
+ case 0x13:
+ $name = 'tUminus';
+ $size = 1;
+ $data = '-';
+ break;
+ case 0x14:
+ $name = 'tPercent';
+ $size = 1;
+ $data = '%';
+ break;
+ case 0x15: // parenthesis
+ $name = 'tParen';
+ $size = 1;
+ $data = null;
+ break;
+ case 0x16: // missing argument
+ $name = 'tMissArg';
+ $size = 1;
+ $data = '';
+ break;
+ case 0x17: // string
+ $name = 'tStr';
+ // offset: 1; size: var; Unicode string, 8-bit string length
+ $string = self::readUnicodeStringShort(substr($formulaData, 1));
+ $size = 1 + $string['size'];
+ $data = self::UTF8toExcelDoubleQuoted($string['value']);
+ break;
+ case 0x19: // Special attribute
+ // offset: 1; size: 1; attribute type flags:
+ switch (ord($formulaData[1])) {
+ case 0x01:
+ $name = 'tAttrVolatile';
+ $size = 4;
+ $data = null;
+ break;
+ case 0x02:
+ $name = 'tAttrIf';
+ $size = 4;
+ $data = null;
+ break;
+ case 0x04:
+ $name = 'tAttrChoose';
+ // offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
+ $nc = self::getInt2d($formulaData, 2);
+ // offset: 4; size: 2 * $nc
+ // offset: 4 + 2 * $nc; size: 2
+ $size = 2 * $nc + 6;
+ $data = null;
+ break;
+ case 0x08:
+ $name = 'tAttrSkip';
+ $size = 4;
+ $data = null;
+ break;
+ case 0x10:
+ $name = 'tAttrSum';
+ $size = 4;
+ $data = null;
+ break;
+ case 0x40:
+ case 0x41:
+ $name = 'tAttrSpace';
+ $size = 4;
+ // offset: 2; size: 2; space type and position
+ switch (ord($formulaData[2])) {
+ case 0x00:
+ $spacetype = 'type0';
+ break;
+ case 0x01:
+ $spacetype = 'type1';
+ break;
+ case 0x02:
+ $spacetype = 'type2';
+ break;
+ case 0x03:
+ $spacetype = 'type3';
+ break;
+ case 0x04:
+ $spacetype = 'type4';
+ break;
+ case 0x05:
+ $spacetype = 'type5';
+ break;
+ default:
+ throw new PHPExcel_Reader_Exception('Unrecognized space type in tAttrSpace token');
+ break;
+ }
+ // offset: 3; size: 1; number of inserted spaces/carriage returns
+ $spacecount = ord($formulaData[3]);
+
+ $data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
+ break;
+ default:
+ throw new PHPExcel_Reader_Exception('Unrecognized attribute flag in tAttr token');
+ break;
+ }
+ break;
+ case 0x1C: // error code
+ // offset: 1; size: 1; error code
+ $name = 'tErr';
+ $size = 2;
+ $data = PHPExcel_Reader_Excel5_ErrorCode::lookup(ord($formulaData[1]));
+ break;
+ case 0x1D: // boolean
+ // offset: 1; size: 1; 0 = false, 1 = true;
+ $name = 'tBool';
+ $size = 2;
+ $data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
+ break;
+ case 0x1E: // integer
+ // offset: 1; size: 2; unsigned 16-bit integer
+ $name = 'tInt';
+ $size = 3;
+ $data = self::getInt2d($formulaData, 1);
+ break;
+ case 0x1F: // number
+ // offset: 1; size: 8;
+ $name = 'tNum';
+ $size = 9;
+ $data = self::extractNumber(substr($formulaData, 1));
+ $data = str_replace(',', '.', (string)$data); // in case non-English locale
+ break;
+ case 0x20: // array constant
+ case 0x40:
+ case 0x60:
+ // offset: 1; size: 7; not used
+ $name = 'tArray';
+ $size = 8;
+ $data = null;
+ break;
+ case 0x21: // function with fixed number of arguments
+ case 0x41:
+ case 0x61:
+ $name = 'tFunc';
+ $size = 3;
+ // offset: 1; size: 2; index to built-in sheet function
+ switch (self::getInt2d($formulaData, 1)) {
+ case 2:
+ $function = 'ISNA';
+ $args = 1;
+ break;
+ case 3:
+ $function = 'ISERROR';
+ $args = 1;
+ break;
+ case 10:
+ $function = 'NA';
+ $args = 0;
+ break;
+ case 15:
+ $function = 'SIN';
+ $args = 1;
+ break;
+ case 16:
+ $function = 'COS';
+ $args = 1;
+ break;
+ case 17:
+ $function = 'TAN';
+ $args = 1;
+ break;
+ case 18:
+ $function = 'ATAN';
+ $args = 1;
+ break;
+ case 19:
+ $function = 'PI';
+ $args = 0;
+ break;
+ case 20:
+ $function = 'SQRT';
+ $args = 1;
+ break;
+ case 21:
+ $function = 'EXP';
+ $args = 1;
+ break;
+ case 22:
+ $function = 'LN';
+ $args = 1;
+ break;
+ case 23:
+ $function = 'LOG10';
+ $args = 1;
+ break;
+ case 24:
+ $function = 'ABS';
+ $args = 1;
+ break;
+ case 25:
+ $function = 'INT';
+ $args = 1;
+ break;
+ case 26:
+ $function = 'SIGN';
+ $args = 1;
+ break;
+ case 27:
+ $function = 'ROUND';
+ $args = 2;
+ break;
+ case 30:
+ $function = 'REPT';
+ $args = 2;
+ break;
+ case 31:
+ $function = 'MID';
+ $args = 3;
+ break;
+ case 32:
+ $function = 'LEN';
+ $args = 1;
+ break;
+ case 33:
+ $function = 'VALUE';
+ $args = 1;
+ break;
+ case 34:
+ $function = 'TRUE';
+ $args = 0;
+ break;
+ case 35:
+ $function = 'FALSE';
+ $args = 0;
+ break;
+ case 38:
+ $function = 'NOT';
+ $args = 1;
+ break;
+ case 39:
+ $function = 'MOD';
+ $args = 2;
+ break;
+ case 40:
+ $function = 'DCOUNT';
+ $args = 3;
+ break;
+ case 41:
+ $function = 'DSUM';
+ $args = 3;
+ break;
+ case 42:
+ $function = 'DAVERAGE';
+ $args = 3;
+ break;
+ case 43:
+ $function = 'DMIN';
+ $args = 3;
+ break;
+ case 44:
+ $function = 'DMAX';
+ $args = 3;
+ break;
+ case 45:
+ $function = 'DSTDEV';
+ $args = 3;
+ break;
+ case 48:
+ $function = 'TEXT';
+ $args = 2;
+ break;
+ case 61:
+ $function = 'MIRR';
+ $args = 3;
+ break;
+ case 63:
+ $function = 'RAND';
+ $args = 0;
+ break;
+ case 65:
+ $function = 'DATE';
+ $args = 3;
+ break;
+ case 66:
+ $function = 'TIME';
+ $args = 3;
+ break;
+ case 67:
+ $function = 'DAY';
+ $args = 1;
+ break;
+ case 68:
+ $function = 'MONTH';
+ $args = 1;
+ break;
+ case 69:
+ $function = 'YEAR';
+ $args = 1;
+ break;
+ case 71:
+ $function = 'HOUR';
+ $args = 1;
+ break;
+ case 72:
+ $function = 'MINUTE';
+ $args = 1;
+ break;
+ case 73:
+ $function = 'SECOND';
+ $args = 1;
+ break;
+ case 74:
+ $function = 'NOW';
+ $args = 0;
+ break;
+ case 75:
+ $function = 'AREAS';
+ $args = 1;
+ break;
+ case 76:
+ $function = 'ROWS';
+ $args = 1;
+ break;
+ case 77:
+ $function = 'COLUMNS';
+ $args = 1;
+ break;
+ case 83:
+ $function = 'TRANSPOSE';
+ $args = 1;
+ break;
+ case 86:
+ $function = 'TYPE';
+ $args = 1;
+ break;
+ case 97:
+ $function = 'ATAN2';
+ $args = 2;
+ break;
+ case 98:
+ $function = 'ASIN';
+ $args = 1;
+ break;
+ case 99:
+ $function = 'ACOS';
+ $args = 1;
+ break;
+ case 105:
+ $function = 'ISREF';
+ $args = 1;
+ break;
+ case 111:
+ $function = 'CHAR';
+ $args = 1;
+ break;
+ case 112:
+ $function = 'LOWER';
+ $args = 1;
+ break;
+ case 113:
+ $function = 'UPPER';
+ $args = 1;
+ break;
+ case 114:
+ $function = 'PROPER';
+ $args = 1;
+ break;
+ case 117:
+ $function = 'EXACT';
+ $args = 2;
+ break;
+ case 118:
+ $function = 'TRIM';
+ $args = 1;
+ break;
+ case 119:
+ $function = 'REPLACE';
+ $args = 4;
+ break;
+ case 121:
+ $function = 'CODE';
+ $args = 1;
+ break;
+ case 126:
+ $function = 'ISERR';
+ $args = 1;
+ break;
+ case 127:
+ $function = 'ISTEXT';
+ $args = 1;
+ break;
+ case 128:
+ $function = 'ISNUMBER';
+ $args = 1;
+ break;
+ case 129:
+ $function = 'ISBLANK';
+ $args = 1;
+ break;
+ case 130:
+ $function = 'T';
+ $args = 1;
+ break;
+ case 131:
+ $function = 'N';
+ $args = 1;
+ break;
+ case 140:
+ $function = 'DATEVALUE';
+ $args = 1;
+ break;
+ case 141:
+ $function = 'TIMEVALUE';
+ $args = 1;
+ break;
+ case 142:
+ $function = 'SLN';
+ $args = 3;
+ break;
+ case 143:
+ $function = 'SYD';
+ $args = 4;
+ break;
+ case 162:
+ $function = 'CLEAN';
+ $args = 1;
+ break;
+ case 163:
+ $function = 'MDETERM';
+ $args = 1;
+ break;
+ case 164:
+ $function = 'MINVERSE';
+ $args = 1;
+ break;
+ case 165:
+ $function = 'MMULT';
+ $args = 2;
+ break;
+ case 184:
+ $function = 'FACT';
+ $args = 1;
+ break;
+ case 189:
+ $function = 'DPRODUCT';
+ $args = 3;
+ break;
+ case 190:
+ $function = 'ISNONTEXT';
+ $args = 1;
+ break;
+ case 195:
+ $function = 'DSTDEVP';
+ $args = 3;
+ break;
+ case 196:
+ $function = 'DVARP';
+ $args = 3;
+ break;
+ case 198:
+ $function = 'ISLOGICAL';
+ $args = 1;
+ break;
+ case 199:
+ $function = 'DCOUNTA';
+ $args = 3;
+ break;
+ case 207:
+ $function = 'REPLACEB';
+ $args = 4;
+ break;
+ case 210:
+ $function = 'MIDB';
+ $args = 3;
+ break;
+ case 211:
+ $function = 'LENB';
+ $args = 1;
+ break;
+ case 212:
+ $function = 'ROUNDUP';
+ $args = 2;
+ break;
+ case 213:
+ $function = 'ROUNDDOWN';
+ $args = 2;
+ break;
+ case 214:
+ $function = 'ASC';
+ $args = 1;
+ break;
+ case 215:
+ $function = 'DBCS';
+ $args = 1;
+ break;
+ case 221:
+ $function = 'TODAY';
+ $args = 0;
+ break;
+ case 229:
+ $function = 'SINH';
+ $args = 1;
+ break;
+ case 230:
+ $function = 'COSH';
+ $args = 1;
+ break;
+ case 231:
+ $function = 'TANH';
+ $args = 1;
+ break;
+ case 232:
+ $function = 'ASINH';
+ $args = 1;
+ break;
+ case 233:
+ $function = 'ACOSH';
+ $args = 1;
+ break;
+ case 234:
+ $function = 'ATANH';
+ $args = 1;
+ break;
+ case 235:
+ $function = 'DGET';
+ $args = 3;
+ break;
+ case 244:
+ $function = 'INFO';
+ $args = 1;
+ break;
+ case 252:
+ $function = 'FREQUENCY';
+ $args = 2;
+ break;
+ case 261:
+ $function = 'ERROR.TYPE';
+ $args = 1;
+ break;
+ case 271:
+ $function = 'GAMMALN';
+ $args = 1;
+ break;
+ case 273:
+ $function = 'BINOMDIST';
+ $args = 4;
+ break;
+ case 274:
+ $function = 'CHIDIST';
+ $args = 2;
+ break;
+ case 275:
+ $function = 'CHIINV';
+ $args = 2;
+ break;
+ case 276:
+ $function = 'COMBIN';
+ $args = 2;
+ break;
+ case 277:
+ $function = 'CONFIDENCE';
+ $args = 3;
+ break;
+ case 278:
+ $function = 'CRITBINOM';
+ $args = 3;
+ break;
+ case 279:
+ $function = 'EVEN';
+ $args = 1;
+ break;
+ case 280:
+ $function = 'EXPONDIST';
+ $args = 3;
+ break;
+ case 281:
+ $function = 'FDIST';
+ $args = 3;
+ break;
+ case 282:
+ $function = 'FINV';
+ $args = 3;
+ break;
+ case 283:
+ $function = 'FISHER';
+ $args = 1;
+ break;
+ case 284:
+ $function = 'FISHERINV';
+ $args = 1;
+ break;
+ case 285:
+ $function = 'FLOOR';
+ $args = 2;
+ break;
+ case 286:
+ $function = 'GAMMADIST';
+ $args = 4;
+ break;
+ case 287:
+ $function = 'GAMMAINV';
+ $args = 3;
+ break;
+ case 288:
+ $function = 'CEILING';
+ $args = 2;
+ break;
+ case 289:
+ $function = 'HYPGEOMDIST';
+ $args = 4;
+ break;
+ case 290:
+ $function = 'LOGNORMDIST';
+ $args = 3;
+ break;
+ case 291:
+ $function = 'LOGINV';
+ $args = 3;
+ break;
+ case 292:
+ $function = 'NEGBINOMDIST';
+ $args = 3;
+ break;
+ case 293:
+ $function = 'NORMDIST';
+ $args = 4;
+ break;
+ case 294:
+ $function = 'NORMSDIST';
+ $args = 1;
+ break;
+ case 295:
+ $function = 'NORMINV';
+ $args = 3;
+ break;
+ case 296:
+ $function = 'NORMSINV';
+ $args = 1;
+ break;
+ case 297:
+ $function = 'STANDARDIZE';
+ $args = 3;
+ break;
+ case 298:
+ $function = 'ODD';
+ $args = 1;
+ break;
+ case 299:
+ $function = 'PERMUT';
+ $args = 2;
+ break;
+ case 300:
+ $function = 'POISSON';
+ $args = 3;
+ break;
+ case 301:
+ $function = 'TDIST';
+ $args = 3;
+ break;
+ case 302:
+ $function = 'WEIBULL';
+ $args = 4;
+ break;
+ case 303:
+ $function = 'SUMXMY2';
+ $args = 2;
+ break;
+ case 304:
+ $function = 'SUMX2MY2';
+ $args = 2;
+ break;
+ case 305:
+ $function = 'SUMX2PY2';
+ $args = 2;
+ break;
+ case 306:
+ $function = 'CHITEST';
+ $args = 2;
+ break;
+ case 307:
+ $function = 'CORREL';
+ $args = 2;
+ break;
+ case 308:
+ $function = 'COVAR';
+ $args = 2;
+ break;
+ case 309:
+ $function = 'FORECAST';
+ $args = 3;
+ break;
+ case 310:
+ $function = 'FTEST';
+ $args = 2;
+ break;
+ case 311:
+ $function = 'INTERCEPT';
+ $args = 2;
+ break;
+ case 312:
+ $function = 'PEARSON';
+ $args = 2;
+ break;
+ case 313:
+ $function = 'RSQ';
+ $args = 2;
+ break;
+ case 314:
+ $function = 'STEYX';
+ $args = 2;
+ break;
+ case 315:
+ $function = 'SLOPE';
+ $args = 2;
+ break;
+ case 316:
+ $function = 'TTEST';
+ $args = 4;
+ break;
+ case 325:
+ $function = 'LARGE';
+ $args = 2;
+ break;
+ case 326:
+ $function = 'SMALL';
+ $args = 2;
+ break;
+ case 327:
+ $function = 'QUARTILE';
+ $args = 2;
+ break;
+ case 328:
+ $function = 'PERCENTILE';
+ $args = 2;
+ break;
+ case 331:
+ $function = 'TRIMMEAN';
+ $args = 2;
+ break;
+ case 332:
+ $function = 'TINV';
+ $args = 2;
+ break;
+ case 337:
+ $function = 'POWER';
+ $args = 2;
+ break;
+ case 342:
+ $function = 'RADIANS';
+ $args = 1;
+ break;
+ case 343:
+ $function = 'DEGREES';
+ $args = 1;
+ break;
+ case 346:
+ $function = 'COUNTIF';
+ $args = 2;
+ break;
+ case 347:
+ $function = 'COUNTBLANK';
+ $args = 1;
+ break;
+ case 350:
+ $function = 'ISPMT';
+ $args = 4;
+ break;
+ case 351:
+ $function = 'DATEDIF';
+ $args = 3;
+ break;
+ case 352:
+ $function = 'DATESTRING';
+ $args = 1;
+ break;
+ case 353:
+ $function = 'NUMBERSTRING';
+ $args = 2;
+ break;
+ case 360:
+ $function = 'PHONETIC';
+ $args = 1;
+ break;
+ case 368:
+ $function = 'BAHTTEXT';
+ $args = 1;
+ break;
+ default:
+ throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
+ break;
+ }
+ $data = array('function' => $function, 'args' => $args);
+ break;
+ case 0x22: // function with variable number of arguments
+ case 0x42:
+ case 0x62:
+ $name = 'tFuncV';
+ $size = 4;
+ // offset: 1; size: 1; number of arguments
+ $args = ord($formulaData[1]);
+ // offset: 2: size: 2; index to built-in sheet function
+ $index = self::getInt2d($formulaData, 2);
+ switch ($index) {
+ case 0:
+ $function = 'COUNT';
+ break;
+ case 1:
+ $function = 'IF';
+ break;
+ case 4:
+ $function = 'SUM';
+ break;
+ case 5:
+ $function = 'AVERAGE';
+ break;
+ case 6:
+ $function = 'MIN';
+ break;
+ case 7:
+ $function = 'MAX';
+ break;
+ case 8:
+ $function = 'ROW';
+ break;
+ case 9:
+ $function = 'COLUMN';
+ break;
+ case 11:
+ $function = 'NPV';
+ break;
+ case 12:
+ $function = 'STDEV';
+ break;
+ case 13:
+ $function = 'DOLLAR';
+ break;
+ case 14:
+ $function = 'FIXED';
+ break;
+ case 28:
+ $function = 'LOOKUP';
+ break;
+ case 29:
+ $function = 'INDEX';
+ break;
+ case 36:
+ $function = 'AND';
+ break;
+ case 37:
+ $function = 'OR';
+ break;
+ case 46:
+ $function = 'VAR';
+ break;
+ case 49:
+ $function = 'LINEST';
+ break;
+ case 50:
+ $function = 'TREND';
+ break;
+ case 51:
+ $function = 'LOGEST';
+ break;
+ case 52:
+ $function = 'GROWTH';
+ break;
+ case 56:
+ $function = 'PV';
+ break;
+ case 57:
+ $function = 'FV';
+ break;
+ case 58:
+ $function = 'NPER';
+ break;
+ case 59:
+ $function = 'PMT';
+ break;
+ case 60:
+ $function = 'RATE';
+ break;
+ case 62:
+ $function = 'IRR';
+ break;
+ case 64:
+ $function = 'MATCH';
+ break;
+ case 70:
+ $function = 'WEEKDAY';
+ break;
+ case 78:
+ $function = 'OFFSET';
+ break;
+ case 82:
+ $function = 'SEARCH';
+ break;
+ case 100:
+ $function = 'CHOOSE';
+ break;
+ case 101:
+ $function = 'HLOOKUP';
+ break;
+ case 102:
+ $function = 'VLOOKUP';
+ break;
+ case 109:
+ $function = 'LOG';
+ break;
+ case 115:
+ $function = 'LEFT';
+ break;
+ case 116:
+ $function = 'RIGHT';
+ break;
+ case 120:
+ $function = 'SUBSTITUTE';
+ break;
+ case 124:
+ $function = 'FIND';
+ break;
+ case 125:
+ $function = 'CELL';
+ break;
+ case 144:
+ $function = 'DDB';
+ break;
+ case 148:
+ $function = 'INDIRECT';
+ break;
+ case 167:
+ $function = 'IPMT';
+ break;
+ case 168:
+ $function = 'PPMT';
+ break;
+ case 169:
+ $function = 'COUNTA';
+ break;
+ case 183:
+ $function = 'PRODUCT';
+ break;
+ case 193:
+ $function = 'STDEVP';
+ break;
+ case 194:
+ $function = 'VARP';
+ break;
+ case 197:
+ $function = 'TRUNC';
+ break;
+ case 204:
+ $function = 'USDOLLAR';
+ break;
+ case 205:
+ $function = 'FINDB';
+ break;
+ case 206:
+ $function = 'SEARCHB';
+ break;
+ case 208:
+ $function = 'LEFTB';
+ break;
+ case 209:
+ $function = 'RIGHTB';
+ break;
+ case 216:
+ $function = 'RANK';
+ break;
+ case 219:
+ $function = 'ADDRESS';
+ break;
+ case 220:
+ $function = 'DAYS360';
+ break;
+ case 222:
+ $function = 'VDB';
+ break;
+ case 227:
+ $function = 'MEDIAN';
+ break;
+ case 228:
+ $function = 'SUMPRODUCT';
+ break;
+ case 247:
+ $function = 'DB';
+ break;
+ case 255:
+ $function = '';
+ break;
+ case 269:
+ $function = 'AVEDEV';
+ break;
+ case 270:
+ $function = 'BETADIST';
+ break;
+ case 272:
+ $function = 'BETAINV';
+ break;
+ case 317:
+ $function = 'PROB';
+ break;
+ case 318:
+ $function = 'DEVSQ';
+ break;
+ case 319:
+ $function = 'GEOMEAN';
+ break;
+ case 320:
+ $function = 'HARMEAN';
+ break;
+ case 321:
+ $function = 'SUMSQ';
+ break;
+ case 322:
+ $function = 'KURT';
+ break;
+ case 323:
+ $function = 'SKEW';
+ break;
+ case 324:
+ $function = 'ZTEST';
+ break;
+ case 329:
+ $function = 'PERCENTRANK';
+ break;
+ case 330:
+ $function = 'MODE';
+ break;
+ case 336:
+ $function = 'CONCATENATE';
+ break;
+ case 344:
+ $function = 'SUBTOTAL';
+ break;
+ case 345:
+ $function = 'SUMIF';
+ break;
+ case 354:
+ $function = 'ROMAN';
+ break;
+ case 358:
+ $function = 'GETPIVOTDATA';
+ break;
+ case 359:
+ $function = 'HYPERLINK';
+ break;
+ case 361:
+ $function = 'AVERAGEA';
+ break;
+ case 362:
+ $function = 'MAXA';
+ break;
+ case 363:
+ $function = 'MINA';
+ break;
+ case 364:
+ $function = 'STDEVPA';
+ break;
+ case 365:
+ $function = 'VARPA';
+ break;
+ case 366:
+ $function = 'STDEVA';
+ break;
+ case 367:
+ $function = 'VARA';
+ break;
+ default:
+ throw new PHPExcel_Reader_Exception('Unrecognized function in formula');
+ break;
+ }
+ $data = array('function' => $function, 'args' => $args);
+ break;
+ case 0x23: // index to defined name
+ case 0x43:
+ case 0x63:
+ $name = 'tName';
+ $size = 5;
+ // offset: 1; size: 2; one-based index to definedname record
+ $definedNameIndex = self::getInt2d($formulaData, 1) - 1;
+ // offset: 2; size: 2; not used
+ $data = $this->definedname[$definedNameIndex]['name'];
+ break;
+ case 0x24: // single cell reference e.g. A5
+ case 0x44:
+ case 0x64:
+ $name = 'tRef';
+ $size = 5;
+ $data = $this->readBIFF8CellAddress(substr($formulaData, 1, 4));
+ break;
+ case 0x25: // cell range reference to cells in the same sheet (2d)
+ case 0x45:
+ case 0x65:
+ $name = 'tArea';
+ $size = 9;
+ $data = $this->readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
+ break;
+ case 0x26: // Constant reference sub-expression
+ case 0x46:
+ case 0x66:
+ $name = 'tMemArea';
+ // offset: 1; size: 4; not used
+ // offset: 5; size: 2; size of the following subexpression
+ $subSize = self::getInt2d($formulaData, 5);
+ $size = 7 + $subSize;
+ $data = $this->getFormulaFromData(substr($formulaData, 7, $subSize));
+ break;
+ case 0x27: // Deleted constant reference sub-expression
+ case 0x47:
+ case 0x67:
+ $name = 'tMemErr';
+ // offset: 1; size: 4; not used
+ // offset: 5; size: 2; size of the following subexpression
+ $subSize = self::getInt2d($formulaData, 5);
+ $size = 7 + $subSize;
+ $data = $this->getFormulaFromData(substr($formulaData, 7, $subSize));
+ break;
+ case 0x29: // Variable reference sub-expression
+ case 0x49:
+ case 0x69:
+ $name = 'tMemFunc';
+ // offset: 1; size: 2; size of the following sub-expression
+ $subSize = self::getInt2d($formulaData, 1);
+ $size = 3 + $subSize;
+ $data = $this->getFormulaFromData(substr($formulaData, 3, $subSize));
+ break;
+ case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
+ case 0x4C:
+ case 0x6C:
+ $name = 'tRefN';
+ $size = 5;
+ $data = $this->readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
+ break;
+ case 0x2D: // Relative 2d range reference
+ case 0x4D:
+ case 0x6D:
+ $name = 'tAreaN';
+ $size = 9;
+ $data = $this->readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
+ break;
+ case 0x39: // External name
+ case 0x59:
+ case 0x79:
+ $name = 'tNameX';
+ $size = 7;
+ // offset: 1; size: 2; index to REF entry in EXTERNSHEET record
+ // offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
+ $index = self::getInt2d($formulaData, 3);
+ // assume index is to EXTERNNAME record
+ $data = $this->externalNames[$index - 1]['name'];
+ // offset: 5; size: 2; not used
+ break;
+ case 0x3A: // 3d reference to cell
+ case 0x5A:
+ case 0x7A:
+ $name = 'tRef3d';
+ $size = 7;
+
+ try {
+ // offset: 1; size: 2; index to REF entry
+ $sheetRange = $this->readSheetRangeByRefIndex(self::getInt2d($formulaData, 1));
+ // offset: 3; size: 4; cell address
+ $cellAddress = $this->readBIFF8CellAddress(substr($formulaData, 3, 4));
+
+ $data = "$sheetRange!$cellAddress";
+ } catch (PHPExcel_Exception $e) {
+ // deleted sheet reference
+ $data = '#REF!';
+ }
+ break;
+ case 0x3B: // 3d reference to cell range
+ case 0x5B:
+ case 0x7B:
+ $name = 'tArea3d';
+ $size = 11;
+
+ try {
+ // offset: 1; size: 2; index to REF entry
+ $sheetRange = $this->readSheetRangeByRefIndex(self::getInt2d($formulaData, 1));
+ // offset: 3; size: 8; cell address
+ $cellRangeAddress = $this->readBIFF8CellRangeAddress(substr($formulaData, 3, 8));
+
+ $data = "$sheetRange!$cellRangeAddress";
+ } catch (PHPExcel_Exception $e) {
+ // deleted sheet reference
+ $data = '#REF!';
+ }
+ break;
+ // Unknown cases // don't know how to deal with
+ default:
+ throw new PHPExcel_Reader_Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
+ break;
+ }
+
+ return array(
+ 'id' => $id,
+ 'name' => $name,
+ 'size' => $size,
+ 'data' => $data,
+ );
+ }
+
+
+ /**
+ * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2'
+ * section 3.3.4
+ *
+ * @param string $cellAddressStructure
+ * @return string
+ */
+ private function readBIFF8CellAddress($cellAddressStructure)
+ {
+ // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
+ $row = self::getInt2d($cellAddressStructure, 0) + 1;
+
+ // offset: 2; size: 2; index to column or column offset + relative flags
+ // bit: 7-0; mask 0x00FF; column index
+ $column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::getInt2d($cellAddressStructure, 2));
+
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+ if (!(0x4000 & self::getInt2d($cellAddressStructure, 2))) {
+ $column = '$' . $column;
+ }
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+ if (!(0x8000 & self::getInt2d($cellAddressStructure, 2))) {
+ $row = '$' . $row;
+ }
+
+ return $column . $row;
+ }
+
+
+ /**
+ * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column
+ * to indicate offsets from a base cell
+ * section 3.3.4
+ *
+ * @param string $cellAddressStructure
+ * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+ * @return string
+ */
+ private function readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
+ {
+ list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
+ $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
+
+ // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
+ $rowIndex = self::getInt2d($cellAddressStructure, 0);
+ $row = self::getInt2d($cellAddressStructure, 0) + 1;
+
+ // offset: 2; size: 2; index to column or column offset + relative flags
+ // bit: 7-0; mask 0x00FF; column index
+ $colIndex = 0x00FF & self::getInt2d($cellAddressStructure, 2);
+
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+ if (!(0x4000 & self::getInt2d($cellAddressStructure, 2))) {
+ $column = PHPExcel_Cell::stringFromColumnIndex($colIndex);
+ $column = '$' . $column;
+ } else {
+ $colIndex = ($colIndex <= 127) ? $colIndex : $colIndex - 256;
+ $column = PHPExcel_Cell::stringFromColumnIndex($baseCol + $colIndex);
+ }
+
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+ if (!(0x8000 & self::getInt2d($cellAddressStructure, 2))) {
+ $row = '$' . $row;
+ } else {
+ $rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536;
+ $row = $baseRow + $rowIndex;
+ }
+
+ return $column . $row;
+ }
+
+
+ /**
+ * Reads a cell range address in BIFF5 e.g. 'A2:B6' or 'A1'
+ * always fixed range
+ * section 2.5.14
+ *
+ * @param string $subData
+ * @return string
+ * @throws PHPExcel_Reader_Exception
+ */
+ private function readBIFF5CellRangeAddressFixed($subData)
+ {
+ // offset: 0; size: 2; index to first row
+ $fr = self::getInt2d($subData, 0) + 1;
+
+ // offset: 2; size: 2; index to last row
+ $lr = self::getInt2d($subData, 2) + 1;
+
+ // offset: 4; size: 1; index to first column
+ $fc = ord($subData{4});
+
+ // offset: 5; size: 1; index to last column
+ $lc = ord($subData{5});
+
+ // check values
+ if ($fr > $lr || $fc > $lc) {
+ throw new PHPExcel_Reader_Exception('Not a cell range address');
+ }
+
+ // column index to letter
+ $fc = PHPExcel_Cell::stringFromColumnIndex($fc);
+ $lc = PHPExcel_Cell::stringFromColumnIndex($lc);
+
+ if ($fr == $lr and $fc == $lc) {
+ return "$fc$fr";
+ }
+ return "$fc$fr:$lc$lr";
+ }
+
+
+ /**
+ * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1'
+ * always fixed range
+ * section 2.5.14
+ *
+ * @param string $subData
+ * @return string
+ * @throws PHPExcel_Reader_Exception
+ */
+ private function readBIFF8CellRangeAddressFixed($subData)
+ {
+ // offset: 0; size: 2; index to first row
+ $fr = self::getInt2d($subData, 0) + 1;
+
+ // offset: 2; size: 2; index to last row
+ $lr = self::getInt2d($subData, 2) + 1;
+
+ // offset: 4; size: 2; index to first column
+ $fc = self::getInt2d($subData, 4);
+
+ // offset: 6; size: 2; index to last column
+ $lc = self::getInt2d($subData, 6);
+
+ // check values
+ if ($fr > $lr || $fc > $lc) {
+ throw new PHPExcel_Reader_Exception('Not a cell range address');
+ }
+
+ // column index to letter
+ $fc = PHPExcel_Cell::stringFromColumnIndex($fc);
+ $lc = PHPExcel_Cell::stringFromColumnIndex($lc);
+
+ if ($fr == $lr and $fc == $lc) {
+ return "$fc$fr";
+ }
+ return "$fc$fr:$lc$lr";
+ }
+
+
+ /**
+ * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6'
+ * there are flags indicating whether column/row index is relative
+ * section 3.3.4
+ *
+ * @param string $subData
+ * @return string
+ */
+ private function readBIFF8CellRangeAddress($subData)
+ {
+ // todo: if cell range is just a single cell, should this funciton
+ // not just return e.g. 'A1' and not 'A1:A1' ?
+
+ // offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
+ $fr = self::getInt2d($subData, 0) + 1;
+
+ // offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
+ $lr = self::getInt2d($subData, 2) + 1;
+
+ // offset: 4; size: 2; index to first column or column offset + relative flags
+
+ // bit: 7-0; mask 0x00FF; column index
+ $fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::getInt2d($subData, 4));
+
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+ if (!(0x4000 & self::getInt2d($subData, 4))) {
+ $fc = '$' . $fc;
+ }
+
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+ if (!(0x8000 & self::getInt2d($subData, 4))) {
+ $fr = '$' . $fr;
+ }
+
+ // offset: 6; size: 2; index to last column or column offset + relative flags
+
+ // bit: 7-0; mask 0x00FF; column index
+ $lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::getInt2d($subData, 6));
+
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+ if (!(0x4000 & self::getInt2d($subData, 6))) {
+ $lc = '$' . $lc;
+ }
+
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+ if (!(0x8000 & self::getInt2d($subData, 6))) {
+ $lr = '$' . $lr;
+ }
+
+ return "$fc$fr:$lc$lr";
+ }
+
+
+ /**
+ * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column
+ * to indicate offsets from a base cell
+ * section 3.3.4
+ *
+ * @param string $subData
+ * @param string $baseCell Base cell
+ * @return string Cell range address
+ */
+ private function readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
+ {
+ list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
+ $baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
+
+ // TODO: if cell range is just a single cell, should this funciton
+ // not just return e.g. 'A1' and not 'A1:A1' ?
+
+ // offset: 0; size: 2; first row
+ $frIndex = self::getInt2d($subData, 0); // adjust below
+
+ // offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767)
+ $lrIndex = self::getInt2d($subData, 2); // adjust below
+
+ // offset: 4; size: 2; first column with relative/absolute flags
+
+ // bit: 7-0; mask 0x00FF; column index
+ $fcIndex = 0x00FF & self::getInt2d($subData, 4);
+
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+ if (!(0x4000 & self::getInt2d($subData, 4))) {
+ // absolute column index
+ $fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex);
+ $fc = '$' . $fc;
+ } else {
+ // column offset
+ $fcIndex = ($fcIndex <= 127) ? $fcIndex : $fcIndex - 256;
+ $fc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $fcIndex);
+ }
+
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+ if (!(0x8000 & self::getInt2d($subData, 4))) {
+ // absolute row index
+ $fr = $frIndex + 1;
+ $fr = '$' . $fr;
+ } else {
+ // row offset
+ $frIndex = ($frIndex <= 32767) ? $frIndex : $frIndex - 65536;
+ $fr = $baseRow + $frIndex;
+ }
+
+ // offset: 6; size: 2; last column with relative/absolute flags
+
+ // bit: 7-0; mask 0x00FF; column index
+ $lcIndex = 0x00FF & self::getInt2d($subData, 6);
+ $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
+ $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
+
+ // bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+ if (!(0x4000 & self::getInt2d($subData, 6))) {
+ // absolute column index
+ $lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex);
+ $lc = '$' . $lc;
+ } else {
+ // column offset
+ $lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
+ $lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
+ }
+
+ // bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+ if (!(0x8000 & self::getInt2d($subData, 6))) {
+ // absolute row index
+ $lr = $lrIndex + 1;
+ $lr = '$' . $lr;
+ } else {
+ // row offset
+ $lrIndex = ($lrIndex <= 32767) ? $lrIndex : $lrIndex - 65536;
+ $lr = $baseRow + $lrIndex;
+ }
+
+ return "$fc$fr:$lc$lr";
+ }
+
+
+ /**
+ * Read BIFF8 cell range address list
+ * section 2.5.15
+ *
+ * @param string $subData
+ * @return array
+ */
+ private function readBIFF8CellRangeAddressList($subData)
+ {
+ $cellRangeAddresses = array();
+
+ // offset: 0; size: 2; number of the following cell range addresses
+ $nm = self::getInt2d($subData, 0);
+
+ $offset = 2;
+ // offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses
+ for ($i = 0; $i < $nm; ++$i) {
+ $cellRangeAddresses[] = $this->readBIFF8CellRangeAddressFixed(substr($subData, $offset, 8));
+ $offset += 8;
+ }
+
+ return array(
+ 'size' => 2 + 8 * $nm,
+ 'cellRangeAddresses' => $cellRangeAddresses,
+ );
+ }
+
+
+ /**
+ * Read BIFF5 cell range address list
+ * section 2.5.15
+ *
+ * @param string $subData
+ * @return array
+ */
+ private function readBIFF5CellRangeAddressList($subData)
+ {
+ $cellRangeAddresses = array();
+
+ // offset: 0; size: 2; number of the following cell range addresses
+ $nm = self::getInt2d($subData, 0);
+
+ $offset = 2;
+ // offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses
+ for ($i = 0; $i < $nm; ++$i) {
+ $cellRangeAddresses[] = $this->readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6));
+ $offset += 6;
+ }
+
+ return array(
+ 'size' => 2 + 6 * $nm,
+ 'cellRangeAddresses' => $cellRangeAddresses,
+ );
+ }
+
+
+ /**
+ * Get a sheet range like Sheet1:Sheet3 from REF index
+ * Note: If there is only one sheet in the range, one gets e.g Sheet1
+ * It can also happen that the REF structure uses the -1 (FFFF) code to indicate deleted sheets,
+ * in which case an PHPExcel_Reader_Exception is thrown
+ *
+ * @param int $index
+ * @return string|false
+ * @throws PHPExcel_Reader_Exception
+ */
+ private function readSheetRangeByRefIndex($index)
+ {
+ if (isset($this->ref[$index])) {
+ $type = $this->externalBooks[$this->ref[$index]['externalBookIndex']]['type'];
+
+ switch ($type) {
+ case 'internal':
+ // check if we have a deleted 3d reference
+ if ($this->ref[$index]['firstSheetIndex'] == 0xFFFF or $this->ref[$index]['lastSheetIndex'] == 0xFFFF) {
+ throw new PHPExcel_Reader_Exception('Deleted sheet reference');
+ }
+
+ // we have normal sheet range (collapsed or uncollapsed)
+ $firstSheetName = $this->sheets[$this->ref[$index]['firstSheetIndex']]['name'];
+ $lastSheetName = $this->sheets[$this->ref[$index]['lastSheetIndex']]['name'];
+
+ if ($firstSheetName == $lastSheetName) {
+ // collapsed sheet range
+ $sheetRange = $firstSheetName;
+ } else {
+ $sheetRange = "$firstSheetName:$lastSheetName";
+ }
+
+ // escape the single-quotes
+ $sheetRange = str_replace("'", "''", $sheetRange);
+
+ // if there are special characters, we need to enclose the range in single-quotes
+ // todo: check if we have identified the whole set of special characters
+ // it seems that the following characters are not accepted for sheet names
+ // and we may assume that they are not present: []*/:\?
+ if (preg_match("/[ !\"@#£$%&{()}<>=+'|^,;-]/", $sheetRange)) {
+ $sheetRange = "'$sheetRange'";
+ }
+
+ return $sheetRange;
+ break;
+ default:
+ // TODO: external sheet support
+ throw new PHPExcel_Reader_Exception('Excel5 reader only supports internal sheets in fomulas');
+ break;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * read BIFF8 constant value array from array data
+ * returns e.g. array('value' => '{1,2;3,4}', 'size' => 40}
+ * section 2.5.8
+ *
+ * @param string $arrayData
+ * @return array
+ */
+ private static function readBIFF8ConstantArray($arrayData)
+ {
+ // offset: 0; size: 1; number of columns decreased by 1
+ $nc = ord($arrayData[0]);
+
+ // offset: 1; size: 2; number of rows decreased by 1
+ $nr = self::getInt2d($arrayData, 1);
+ $size = 3; // initialize
+ $arrayData = substr($arrayData, 3);
+
+ // offset: 3; size: var; list of ($nc + 1) * ($nr + 1) constant values
+ $matrixChunks = array();
+ for ($r = 1; $r <= $nr + 1; ++$r) {
+ $items = array();
+ for ($c = 1; $c <= $nc + 1; ++$c) {
+ $constant = self::readBIFF8Constant($arrayData);
+ $items[] = $constant['value'];
+ $arrayData = substr($arrayData, $constant['size']);
+ $size += $constant['size'];
+ }
+ $matrixChunks[] = implode(',', $items); // looks like e.g. '1,"hello"'
+ }
+ $matrix = '{' . implode(';', $matrixChunks) . '}';
+
+ return array(
+ 'value' => $matrix,
+ 'size' => $size,
+ );
+ }
+
+
+ /**
+ * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value'
+ * section 2.5.7
+ * returns e.g. array('value' => '5', 'size' => 9)
+ *
+ * @param string $valueData
+ * @return array
+ */
+ private static function readBIFF8Constant($valueData)
+ {
+ // offset: 0; size: 1; identifier for type of constant
+ $identifier = ord($valueData[0]);
+
+ switch ($identifier) {
+ case 0x00: // empty constant (what is this?)
+ $value = '';
+ $size = 9;
+ break;
+ case 0x01: // number
+ // offset: 1; size: 8; IEEE 754 floating-point value
+ $value = self::extractNumber(substr($valueData, 1, 8));
+ $size = 9;
+ break;
+ case 0x02: // string value
+ // offset: 1; size: var; Unicode string, 16-bit string length
+ $string = self::readUnicodeStringLong(substr($valueData, 1));
+ $value = '"' . $string['value'] . '"';
+ $size = 1 + $string['size'];
+ break;
+ case 0x04: // boolean
+ // offset: 1; size: 1; 0 = FALSE, 1 = TRUE
+ if (ord($valueData[1])) {
+ $value = 'TRUE';
+ } else {
+ $value = 'FALSE';
+ }
+ $size = 9;
+ break;
+ case 0x10: // error code
+ // offset: 1; size: 1; error code
+ $value = PHPExcel_Reader_Excel5_ErrorCode::lookup(ord($valueData[1]));
+ $size = 9;
+ break;
+ }
+ return array(
+ 'value' => $value,
+ 'size' => $size,
+ );
+ }
+
+
+ /**
+ * Extract RGB color
+ * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4
+ *
+ * @param string $rgb Encoded RGB value (4 bytes)
+ * @return array
+ */
+ private static function readRGB($rgb)
+ {
+ // offset: 0; size 1; Red component
+ $r = ord($rgb{0});
+
+ // offset: 1; size: 1; Green component
+ $g = ord($rgb{1});
+
+ // offset: 2; size: 1; Blue component
+ $b = ord($rgb{2});
+
+ // HEX notation, e.g. 'FF00FC'
+ $rgb = sprintf('%02X%02X%02X', $r, $g, $b);
+
+ return array('rgb' => $rgb);
+ }
+
+
+ /**
+ * Read byte string (8-bit string length)
+ * OpenOffice documentation: 2.5.2
+ *
+ * @param string $subData
+ * @return array
+ */
+ private function readByteStringShort($subData)
+ {
+ // offset: 0; size: 1; length of the string (character count)
+ $ln = ord($subData[0]);
+
+ // offset: 1: size: var; character array (8-bit characters)
+ $value = $this->decodeCodepage(substr($subData, 1, $ln));
+
+ return array(
+ 'value' => $value,
+ 'size' => 1 + $ln, // size in bytes of data structure
+ );
+ }
+
+
+ /**
+ * Read byte string (16-bit string length)
+ * OpenOffice documentation: 2.5.2
+ *
+ * @param string $subData
+ * @return array
+ */
+ private function readByteStringLong($subData)
+ {
+ // offset: 0; size: 2; length of the string (character count)
+ $ln = self::getInt2d($subData, 0);
+
+ // offset: 2: size: var; character array (8-bit characters)
+ $value = $this->decodeCodepage(substr($subData, 2));
+
+ //return $string;
+ return array(
+ 'value' => $value,
+ 'size' => 2 + $ln, // size in bytes of data structure
+ );
+ }
+
+
+ /**
+ * Extracts an Excel Unicode short string (8-bit string length)
+ * OpenOffice documentation: 2.5.3
+ * function will automatically find out where the Unicode string ends.
+ *
+ * @param string $subData
+ * @return array
+ */
+ private static function readUnicodeStringShort($subData)
+ {
+ $value = '';
+
+ // offset: 0: size: 1; length of the string (character count)
+ $characterCount = ord($subData[0]);
+
+ $string = self::readUnicodeString(substr($subData, 1), $characterCount);
+
+ // add 1 for the string length
+ $string['size'] += 1;
+
+ return $string;
+ }
+
+
+ /**
+ * Extracts an Excel Unicode long string (16-bit string length)
+ * OpenOffice documentation: 2.5.3
+ * this function is under construction, needs to support rich text, and Asian phonetic settings
+ *
+ * @param string $subData
+ * @return array
+ */
+ private static function readUnicodeStringLong($subData)
+ {
+ $value = '';
+
+ // offset: 0: size: 2; length of the string (character count)
+ $characterCount = self::getInt2d($subData, 0);
+
+ $string = self::readUnicodeString(substr($subData, 2), $characterCount);
+
+ // add 2 for the string length
+ $string['size'] += 2;
+
+ return $string;
+ }
+
+
+ /**
+ * Read Unicode string with no string length field, but with known character count
+ * this function is under construction, needs to support rich text, and Asian phonetic settings
+ * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3
+ *
+ * @param string $subData
+ * @param int $characterCount
+ * @return array
+ */
+ private static function readUnicodeString($subData, $characterCount)
+ {
+ $value = '';
+
+ // offset: 0: size: 1; option flags
+ // bit: 0; mask: 0x01; character compression (0 = compressed 8-bit, 1 = uncompressed 16-bit)
+ $isCompressed = !((0x01 & ord($subData[0])) >> 0);
+
+ // bit: 2; mask: 0x04; Asian phonetic settings
+ $hasAsian = (0x04) & ord($subData[0]) >> 2;
+
+ // bit: 3; mask: 0x08; Rich-Text settings
+ $hasRichText = (0x08) & ord($subData[0]) >> 3;
+
+ // offset: 1: size: var; character array
+ // this offset assumes richtext and Asian phonetic settings are off which is generally wrong
+ // needs to be fixed
+ $value = self::encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed);
+
+ return array(
+ 'value' => $value,
+ 'size' => $isCompressed ? 1 + $characterCount : 1 + 2 * $characterCount, // the size in bytes including the option flags
+ );
+ }
+
+
+ /**
+ * Convert UTF-8 string to string surounded by double quotes. Used for explicit string tokens in formulas.
+ * Example: hello"world --> "hello""world"
+ *
+ * @param string $value UTF-8 encoded string
+ * @return string
+ */
+ private static function UTF8toExcelDoubleQuoted($value)
+ {
+ return '"' . str_replace('"', '""', $value) . '"';
+ }
+
+
+ /**
+ * Reads first 8 bytes of a string and return IEEE 754 float
+ *
+ * @param string $data Binary string that is at least 8 bytes long
+ * @return float
+ */
+ private static function extractNumber($data)
+ {
+ $rknumhigh = self::getInt4d($data, 4);
+ $rknumlow = self::getInt4d($data, 0);
+ $sign = ($rknumhigh & 0x80000000) >> 31;
+ $exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023;
+ $mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
+ $mantissalow1 = ($rknumlow & 0x80000000) >> 31;
+ $mantissalow2 = ($rknumlow & 0x7fffffff);
+ $value = $mantissa / pow(2, (20 - $exp));
+
+ if ($mantissalow1 != 0) {
+ $value += 1 / pow(2, (21 - $exp));
+ }
+
+ $value += $mantissalow2 / pow(2, (52 - $exp));
+ if ($sign) {
+ $value *= -1;
+ }
+
+ return $value;
+ }
+
+
+ private static function getIEEE754($rknum)
+ {
+ if (($rknum & 0x02) != 0) {
+ $value = $rknum >> 2;
+ } else {
+ // changes by mmp, info on IEEE754 encoding from
+ // research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
+ // The RK format calls for using only the most significant 30 bits
+ // of the 64 bit floating point value. The other 34 bits are assumed
+ // to be 0 so we use the upper 30 bits of $rknum as follows...
+ $sign = ($rknum & 0x80000000) >> 31;
+ $exp = ($rknum & 0x7ff00000) >> 20;
+ $mantissa = (0x100000 | ($rknum & 0x000ffffc));
+ $value = $mantissa / pow(2, (20- ($exp - 1023)));
+ if ($sign) {
+ $value = -1 * $value;
+ }
+ //end of changes by mmp
+ }
+ if (($rknum & 0x01) != 0) {
+ $value /= 100;
+ }
+ return $value;
+ }
+
+
+ /**
+ * Get UTF-8 string from (compressed or uncompressed) UTF-16 string
+ *
+ * @param string $string
+ * @param bool $compressed
+ * @return string
+ */
+ private static function encodeUTF16($string, $compressed = '')
+ {
+ if ($compressed) {
+ $string = self::uncompressByteString($string);
+ }
+
+ return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE');
+ }
+
+ /**
+ * Convert UTF-16 string in compressed notation to uncompressed form. Only used for BIFF8.
+ *
+ * @param string $string
+ * @return string
+ */
+ private static function uncompressByteString($string)
+ {
+ $uncompressedString = '';
+ $strLen = strlen($string);
+ for ($i = 0; $i < $strLen; ++$i) {
+ $uncompressedString .= $string[$i] . "\0";
+ }
+
+ return $uncompressedString;
+ }
+
+ /**
+ * Convert string to UTF-8. Only used for BIFF5.
+ *
+ * @param string $string
+ * @return string
+ */
+ private function decodeCodepage($string)
+ {
+ return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->codepage);
+ }
+
+ /**
+ * Read 16-bit unsigned integer
+ *
+ * @param string $data
+ * @param int $pos
+ * @return int
+ */
+ public static function getInt2d($data, $pos)
+ {
+ return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
+ }
+
+ /**
+ * Read 32-bit signed integer
+ *
+ * @param string $data
+ * @param int $pos
+ * @return int
+ */
+ public static function getInt4d($data, $pos)
+ {
+ // FIX: represent numbers correctly on 64-bit system
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
+ // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
+ $_or_24 = ord($data[$pos + 3]);
+ if ($_or_24 >= 128) {
+ // negative number
+ $_ord_24 = -abs((256 - $_or_24) << 24);
+ } else {
+ $_ord_24 = ($_or_24 & 127) << 24;
+ }
+ return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24;
+ }
+
+ private function parseRichText($is = '')
+ {
+ $value = new PHPExcel_RichText();
+ $value->createText($is);
+
+ return $value;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Color.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color.php
new file mode 100755
index 0000000..1801df5
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color.php
@@ -0,0 +1,32 @@
+ 'FF0000')
+ */
+ public static function map($color, $palette, $version)
+ {
+ if ($color <= 0x07 || $color >= 0x40) {
+ // special built-in color
+ return PHPExcel_Reader_Excel5_Color_BuiltIn::lookup($color);
+ } elseif (isset($palette) && isset($palette[$color - 8])) {
+ // palette color, color index 0x08 maps to pallete index 0
+ return $palette[$color - 8];
+ } else {
+ // default color table
+ if ($version == PHPExcel_Reader_Excel5::XLS_BIFF8) {
+ return PHPExcel_Reader_Excel5_Color_BIFF8::lookup($color);
+ } else {
+ // BIFF5
+ return PHPExcel_Reader_Excel5_Color_BIFF5::lookup($color);
+ }
+ }
+
+ return $color;
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BIFF5.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BIFF5.php
new file mode 100755
index 0000000..159c27f
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BIFF5.php
@@ -0,0 +1,77 @@
+ '000000',
+ 0x09 => 'FFFFFF',
+ 0x0A => 'FF0000',
+ 0x0B => '00FF00',
+ 0x0C => '0000FF',
+ 0x0D => 'FFFF00',
+ 0x0E => 'FF00FF',
+ 0x0F => '00FFFF',
+ 0x10 => '800000',
+ 0x11 => '008000',
+ 0x12 => '000080',
+ 0x13 => '808000',
+ 0x14 => '800080',
+ 0x15 => '008080',
+ 0x16 => 'C0C0C0',
+ 0x17 => '808080',
+ 0x18 => '8080FF',
+ 0x19 => '802060',
+ 0x1A => 'FFFFC0',
+ 0x1B => 'A0E0F0',
+ 0x1C => '600080',
+ 0x1D => 'FF8080',
+ 0x1E => '0080C0',
+ 0x1F => 'C0C0FF',
+ 0x20 => '000080',
+ 0x21 => 'FF00FF',
+ 0x22 => 'FFFF00',
+ 0x23 => '00FFFF',
+ 0x24 => '800080',
+ 0x25 => '800000',
+ 0x26 => '008080',
+ 0x27 => '0000FF',
+ 0x28 => '00CFFF',
+ 0x29 => '69FFFF',
+ 0x2A => 'E0FFE0',
+ 0x2B => 'FFFF80',
+ 0x2C => 'A6CAF0',
+ 0x2D => 'DD9CB3',
+ 0x2E => 'B38FEE',
+ 0x2F => 'E3E3E3',
+ 0x30 => '2A6FF9',
+ 0x31 => '3FB8CD',
+ 0x32 => '488436',
+ 0x33 => '958C41',
+ 0x34 => '8E5E42',
+ 0x35 => 'A0627A',
+ 0x36 => '624FAC',
+ 0x37 => '969696',
+ 0x38 => '1D2FBE',
+ 0x39 => '286676',
+ 0x3A => '004500',
+ 0x3B => '453E01',
+ 0x3C => '6A2813',
+ 0x3D => '85396A',
+ 0x3E => '4A3285',
+ 0x3F => '424242',
+ );
+
+ /**
+ * Map color array from BIFF5 built-in color index
+ *
+ * @param int $color
+ * @return array
+ */
+ public static function lookup($color)
+ {
+ if (isset(self::$map[$color])) {
+ return array('rgb' => self::$map[$color]);
+ }
+ return array('rgb' => '000000');
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BIFF8.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BIFF8.php
new file mode 100755
index 0000000..4d3f2d0
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BIFF8.php
@@ -0,0 +1,77 @@
+ '000000',
+ 0x09 => 'FFFFFF',
+ 0x0A => 'FF0000',
+ 0x0B => '00FF00',
+ 0x0C => '0000FF',
+ 0x0D => 'FFFF00',
+ 0x0E => 'FF00FF',
+ 0x0F => '00FFFF',
+ 0x10 => '800000',
+ 0x11 => '008000',
+ 0x12 => '000080',
+ 0x13 => '808000',
+ 0x14 => '800080',
+ 0x15 => '008080',
+ 0x16 => 'C0C0C0',
+ 0x17 => '808080',
+ 0x18 => '9999FF',
+ 0x19 => '993366',
+ 0x1A => 'FFFFCC',
+ 0x1B => 'CCFFFF',
+ 0x1C => '660066',
+ 0x1D => 'FF8080',
+ 0x1E => '0066CC',
+ 0x1F => 'CCCCFF',
+ 0x20 => '000080',
+ 0x21 => 'FF00FF',
+ 0x22 => 'FFFF00',
+ 0x23 => '00FFFF',
+ 0x24 => '800080',
+ 0x25 => '800000',
+ 0x26 => '008080',
+ 0x27 => '0000FF',
+ 0x28 => '00CCFF',
+ 0x29 => 'CCFFFF',
+ 0x2A => 'CCFFCC',
+ 0x2B => 'FFFF99',
+ 0x2C => '99CCFF',
+ 0x2D => 'FF99CC',
+ 0x2E => 'CC99FF',
+ 0x2F => 'FFCC99',
+ 0x30 => '3366FF',
+ 0x31 => '33CCCC',
+ 0x32 => '99CC00',
+ 0x33 => 'FFCC00',
+ 0x34 => 'FF9900',
+ 0x35 => 'FF6600',
+ 0x36 => '666699',
+ 0x37 => '969696',
+ 0x38 => '003366',
+ 0x39 => '339966',
+ 0x3A => '003300',
+ 0x3B => '333300',
+ 0x3C => '993300',
+ 0x3D => '993366',
+ 0x3E => '333399',
+ 0x3F => '333333',
+ );
+
+ /**
+ * Map color array from BIFF8 built-in color index
+ *
+ * @param int $color
+ * @return array
+ */
+ public static function lookup($color)
+ {
+ if (isset(self::$map[$color])) {
+ return array('rgb' => self::$map[$color]);
+ }
+ return array('rgb' => '000000');
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BuiltIn.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BuiltIn.php
new file mode 100755
index 0000000..a5b7e59
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Color/BuiltIn.php
@@ -0,0 +1,31 @@
+ '000000',
+ 0x01 => 'FFFFFF',
+ 0x02 => 'FF0000',
+ 0x03 => '00FF00',
+ 0x04 => '0000FF',
+ 0x05 => 'FFFF00',
+ 0x06 => 'FF00FF',
+ 0x07 => '00FFFF',
+ 0x40 => '000000', // system window text color
+ 0x41 => 'FFFFFF', // system window background color
+ );
+
+ /**
+ * Map built-in color to RGB value
+ *
+ * @param int $color Indexed color
+ * @return array
+ */
+ public static function lookup($color)
+ {
+ if (isset(self::$map[$color])) {
+ return array('rgb' => self::$map[$color]);
+ }
+ return array('rgb' => '000000');
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/ErrorCode.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/ErrorCode.php
new file mode 100755
index 0000000..f1d1cb6
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/ErrorCode.php
@@ -0,0 +1,28 @@
+ '#NULL!',
+ 0x07 => '#DIV/0!',
+ 0x0F => '#VALUE!',
+ 0x17 => '#REF!',
+ 0x1D => '#NAME?',
+ 0x24 => '#NUM!',
+ 0x2A => '#N/A',
+ );
+
+ /**
+ * Map error code, e.g. '#N/A'
+ *
+ * @param int $code
+ * @return string
+ */
+ public static function lookup($code)
+ {
+ if (isset(self::$map[$code])) {
+ return self::$map[$code];
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Escher.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Escher.php
new file mode 100755
index 0000000..2b99e22
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Escher.php
@@ -0,0 +1,669 @@
+object = $object;
+ }
+
+ /**
+ * Load Escher stream data. May be a partial Escher stream.
+ *
+ * @param string $data
+ */
+ public function load($data)
+ {
+ $this->data = $data;
+
+ // total byte size of Excel data (workbook global substream + sheet substreams)
+ $this->dataSize = strlen($this->data);
+
+ $this->pos = 0;
+
+ // Parse Escher stream
+ while ($this->pos < $this->dataSize) {
+ // offset: 2; size: 2: Record Type
+ $fbt = PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos + 2);
+
+ switch ($fbt) {
+ case self::DGGCONTAINER:
+ $this->readDggContainer();
+ break;
+ case self::DGG:
+ $this->readDgg();
+ break;
+ case self::BSTORECONTAINER:
+ $this->readBstoreContainer();
+ break;
+ case self::BSE:
+ $this->readBSE();
+ break;
+ case self::BLIPJPEG:
+ $this->readBlipJPEG();
+ break;
+ case self::BLIPPNG:
+ $this->readBlipPNG();
+ break;
+ case self::OPT:
+ $this->readOPT();
+ break;
+ case self::TERTIARYOPT:
+ $this->readTertiaryOPT();
+ break;
+ case self::SPLITMENUCOLORS:
+ $this->readSplitMenuColors();
+ break;
+ case self::DGCONTAINER:
+ $this->readDgContainer();
+ break;
+ case self::DG:
+ $this->readDg();
+ break;
+ case self::SPGRCONTAINER:
+ $this->readSpgrContainer();
+ break;
+ case self::SPCONTAINER:
+ $this->readSpContainer();
+ break;
+ case self::SPGR:
+ $this->readSpgr();
+ break;
+ case self::SP:
+ $this->readSp();
+ break;
+ case self::CLIENTTEXTBOX:
+ $this->readClientTextbox();
+ break;
+ case self::CLIENTANCHOR:
+ $this->readClientAnchor();
+ break;
+ case self::CLIENTDATA:
+ $this->readClientData();
+ break;
+ default:
+ $this->readDefault();
+ break;
+ }
+ }
+
+ return $this->object;
+ }
+
+ /**
+ * Read a generic record
+ */
+ private function readDefault()
+ {
+ // offset 0; size: 2; recVer and recInstance
+ $verInstance = PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos);
+
+ // offset: 2; size: 2: Record Type
+ $fbt = PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos + 2);
+
+ // bit: 0-3; mask: 0x000F; recVer
+ $recVer = (0x000F & $verInstance) >> 0;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read DggContainer record (Drawing Group Container)
+ */
+ private function readDggContainer()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // record is a container, read contents
+ $dggContainer = new PHPExcel_Shared_Escher_DggContainer();
+ $this->object->setDggContainer($dggContainer);
+ $reader = new PHPExcel_Reader_Excel5_Escher($dggContainer);
+ $reader->load($recordData);
+ }
+
+ /**
+ * Read Dgg record (Drawing Group)
+ */
+ private function readDgg()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read BstoreContainer record (Blip Store Container)
+ */
+ private function readBstoreContainer()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // record is a container, read contents
+ $bstoreContainer = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer();
+ $this->object->setBstoreContainer($bstoreContainer);
+ $reader = new PHPExcel_Reader_Excel5_Escher($bstoreContainer);
+ $reader->load($recordData);
+ }
+
+ /**
+ * Read BSE record
+ */
+ private function readBSE()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // add BSE to BstoreContainer
+ $BSE = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE();
+ $this->object->addBSE($BSE);
+
+ $BSE->setBLIPType($recInstance);
+
+ // offset: 0; size: 1; btWin32 (MSOBLIPTYPE)
+ $btWin32 = ord($recordData[0]);
+
+ // offset: 1; size: 1; btWin32 (MSOBLIPTYPE)
+ $btMacOS = ord($recordData[1]);
+
+ // offset: 2; size: 16; MD4 digest
+ $rgbUid = substr($recordData, 2, 16);
+
+ // offset: 18; size: 2; tag
+ $tag = PHPExcel_Reader_Excel5::getInt2d($recordData, 18);
+
+ // offset: 20; size: 4; size of BLIP in bytes
+ $size = PHPExcel_Reader_Excel5::getInt4d($recordData, 20);
+
+ // offset: 24; size: 4; number of references to this BLIP
+ $cRef = PHPExcel_Reader_Excel5::getInt4d($recordData, 24);
+
+ // offset: 28; size: 4; MSOFO file offset
+ $foDelay = PHPExcel_Reader_Excel5::getInt4d($recordData, 28);
+
+ // offset: 32; size: 1; unused1
+ $unused1 = ord($recordData{32});
+
+ // offset: 33; size: 1; size of nameData in bytes (including null terminator)
+ $cbName = ord($recordData{33});
+
+ // offset: 34; size: 1; unused2
+ $unused2 = ord($recordData{34});
+
+ // offset: 35; size: 1; unused3
+ $unused3 = ord($recordData{35});
+
+ // offset: 36; size: $cbName; nameData
+ $nameData = substr($recordData, 36, $cbName);
+
+ // offset: 36 + $cbName, size: var; the BLIP data
+ $blipData = substr($recordData, 36 + $cbName);
+
+ // record is a container, read contents
+ $reader = new PHPExcel_Reader_Excel5_Escher($BSE);
+ $reader->load($blipData);
+ }
+
+ /**
+ * Read BlipJPEG record. Holds raw JPEG image data
+ */
+ private function readBlipJPEG()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ $pos = 0;
+
+ // offset: 0; size: 16; rgbUid1 (MD4 digest of)
+ $rgbUid1 = substr($recordData, 0, 16);
+ $pos += 16;
+
+ // offset: 16; size: 16; rgbUid2 (MD4 digest), only if $recInstance = 0x46B or 0x6E3
+ if (in_array($recInstance, array(0x046B, 0x06E3))) {
+ $rgbUid2 = substr($recordData, 16, 16);
+ $pos += 16;
+ }
+
+ // offset: var; size: 1; tag
+ $tag = ord($recordData{$pos});
+ $pos += 1;
+
+ // offset: var; size: var; the raw image data
+ $data = substr($recordData, $pos);
+
+ $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
+ $blip->setData($data);
+
+ $this->object->setBlip($blip);
+ }
+
+ /**
+ * Read BlipPNG record. Holds raw PNG image data
+ */
+ private function readBlipPNG()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ $pos = 0;
+
+ // offset: 0; size: 16; rgbUid1 (MD4 digest of)
+ $rgbUid1 = substr($recordData, 0, 16);
+ $pos += 16;
+
+ // offset: 16; size: 16; rgbUid2 (MD4 digest), only if $recInstance = 0x46B or 0x6E3
+ if ($recInstance == 0x06E1) {
+ $rgbUid2 = substr($recordData, 16, 16);
+ $pos += 16;
+ }
+
+ // offset: var; size: 1; tag
+ $tag = ord($recordData{$pos});
+ $pos += 1;
+
+ // offset: var; size: var; the raw image data
+ $data = substr($recordData, $pos);
+
+ $blip = new PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip();
+ $blip->setData($data);
+
+ $this->object->setBlip($blip);
+ }
+
+ /**
+ * Read OPT record. This record may occur within DggContainer record or SpContainer
+ */
+ private function readOPT()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ $this->readOfficeArtRGFOPTE($recordData, $recInstance);
+ }
+
+ /**
+ * Read TertiaryOPT record
+ */
+ private function readTertiaryOPT()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read SplitMenuColors record
+ */
+ private function readSplitMenuColors()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read DgContainer record (Drawing Container)
+ */
+ private function readDgContainer()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // record is a container, read contents
+ $dgContainer = new PHPExcel_Shared_Escher_DgContainer();
+ $this->object->setDgContainer($dgContainer);
+ $reader = new PHPExcel_Reader_Excel5_Escher($dgContainer);
+ $escher = $reader->load($recordData);
+ }
+
+ /**
+ * Read Dg record (Drawing)
+ */
+ private function readDg()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read SpgrContainer record (Shape Group Container)
+ */
+ private function readSpgrContainer()
+ {
+ // context is either context DgContainer or SpgrContainer
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // record is a container, read contents
+ $spgrContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();
+
+ if ($this->object instanceof PHPExcel_Shared_Escher_DgContainer) {
+ // DgContainer
+ $this->object->setSpgrContainer($spgrContainer);
+ } else {
+ // SpgrContainer
+ $this->object->addChild($spgrContainer);
+ }
+
+ $reader = new PHPExcel_Reader_Excel5_Escher($spgrContainer);
+ $escher = $reader->load($recordData);
+ }
+
+ /**
+ * Read SpContainer record (Shape Container)
+ */
+ private function readSpContainer()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // add spContainer to spgrContainer
+ $spContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer();
+ $this->object->addChild($spContainer);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // record is a container, read contents
+ $reader = new PHPExcel_Reader_Excel5_Escher($spContainer);
+ $escher = $reader->load($recordData);
+ }
+
+ /**
+ * Read Spgr record (Shape Group)
+ */
+ private function readSpgr()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read Sp record (Shape)
+ */
+ private function readSp()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read ClientTextbox record
+ */
+ private function readClientTextbox()
+ {
+ // offset: 0; size: 2; recVer and recInstance
+
+ // bit: 4-15; mask: 0xFFF0; recInstance
+ $recInstance = (0xFFF0 & PHPExcel_Reader_Excel5::getInt2d($this->data, $this->pos)) >> 4;
+
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read ClientAnchor record. This record holds information about where the shape is anchored in worksheet
+ */
+ private function readClientAnchor()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+
+ // offset: 2; size: 2; upper-left corner column index (0-based)
+ $c1 = PHPExcel_Reader_Excel5::getInt2d($recordData, 2);
+
+ // offset: 4; size: 2; upper-left corner horizontal offset in 1/1024 of column width
+ $startOffsetX = PHPExcel_Reader_Excel5::getInt2d($recordData, 4);
+
+ // offset: 6; size: 2; upper-left corner row index (0-based)
+ $r1 = PHPExcel_Reader_Excel5::getInt2d($recordData, 6);
+
+ // offset: 8; size: 2; upper-left corner vertical offset in 1/256 of row height
+ $startOffsetY = PHPExcel_Reader_Excel5::getInt2d($recordData, 8);
+
+ // offset: 10; size: 2; bottom-right corner column index (0-based)
+ $c2 = PHPExcel_Reader_Excel5::getInt2d($recordData, 10);
+
+ // offset: 12; size: 2; bottom-right corner horizontal offset in 1/1024 of column width
+ $endOffsetX = PHPExcel_Reader_Excel5::getInt2d($recordData, 12);
+
+ // offset: 14; size: 2; bottom-right corner row index (0-based)
+ $r2 = PHPExcel_Reader_Excel5::getInt2d($recordData, 14);
+
+ // offset: 16; size: 2; bottom-right corner vertical offset in 1/256 of row height
+ $endOffsetY = PHPExcel_Reader_Excel5::getInt2d($recordData, 16);
+
+ // set the start coordinates
+ $this->object->setStartCoordinates(PHPExcel_Cell::stringFromColumnIndex($c1) . ($r1 + 1));
+
+ // set the start offsetX
+ $this->object->setStartOffsetX($startOffsetX);
+
+ // set the start offsetY
+ $this->object->setStartOffsetY($startOffsetY);
+
+ // set the end coordinates
+ $this->object->setEndCoordinates(PHPExcel_Cell::stringFromColumnIndex($c2) . ($r2 + 1));
+
+ // set the end offsetX
+ $this->object->setEndOffsetX($endOffsetX);
+
+ // set the end offsetY
+ $this->object->setEndOffsetY($endOffsetY);
+ }
+
+ /**
+ * Read ClientData record
+ */
+ private function readClientData()
+ {
+ $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
+ $recordData = substr($this->data, $this->pos + 8, $length);
+
+ // move stream pointer to next record
+ $this->pos += 8 + $length;
+ }
+
+ /**
+ * Read OfficeArtRGFOPTE table of property-value pairs
+ *
+ * @param string $data Binary data
+ * @param int $n Number of properties
+ */
+ private function readOfficeArtRGFOPTE($data, $n)
+ {
+ $splicedComplexData = substr($data, 6 * $n);
+
+ // loop through property-value pairs
+ for ($i = 0; $i < $n; ++$i) {
+ // read 6 bytes at a time
+ $fopte = substr($data, 6 * $i, 6);
+
+ // offset: 0; size: 2; opid
+ $opid = PHPExcel_Reader_Excel5::getInt2d($fopte, 0);
+
+ // bit: 0-13; mask: 0x3FFF; opid.opid
+ $opidOpid = (0x3FFF & $opid) >> 0;
+
+ // bit: 14; mask 0x4000; 1 = value in op field is BLIP identifier
+ $opidFBid = (0x4000 & $opid) >> 14;
+
+ // bit: 15; mask 0x8000; 1 = this is a complex property, op field specifies size of complex data
+ $opidFComplex = (0x8000 & $opid) >> 15;
+
+ // offset: 2; size: 4; the value for this property
+ $op = PHPExcel_Reader_Excel5::getInt4d($fopte, 2);
+
+ if ($opidFComplex) {
+ $complexData = substr($splicedComplexData, 0, $op);
+ $splicedComplexData = substr($splicedComplexData, $op);
+
+ // we store string value with complex data
+ $value = $complexData;
+ } else {
+ // we store integer value
+ $value = $op;
+ }
+
+ $this->object->setOPT($opidOpid, $value);
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/MD5.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/MD5.php
new file mode 100755
index 0000000..f14ea94
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/MD5.php
@@ -0,0 +1,203 @@
+reset();
+ }
+
+ /**
+ * Reset the MD5 stream context
+ */
+ public function reset()
+ {
+ $this->a = 0x67452301;
+ $this->b = 0xEFCDAB89;
+ $this->c = 0x98BADCFE;
+ $this->d = 0x10325476;
+ }
+
+ /**
+ * Get MD5 stream context
+ *
+ * @return string
+ */
+ public function getContext()
+ {
+ $s = '';
+ foreach (array('a', 'b', 'c', 'd') as $i) {
+ $v = $this->{$i};
+ $s .= chr($v & 0xff);
+ $s .= chr(($v >> 8) & 0xff);
+ $s .= chr(($v >> 16) & 0xff);
+ $s .= chr(($v >> 24) & 0xff);
+ }
+
+ return $s;
+ }
+
+ /**
+ * Add data to context
+ *
+ * @param string $data Data to add
+ */
+ public function add($data)
+ {
+ $words = array_values(unpack('V16', $data));
+
+ $A = $this->a;
+ $B = $this->b;
+ $C = $this->c;
+ $D = $this->d;
+
+ $F = array('PHPExcel_Reader_Excel5_MD5','f');
+ $G = array('PHPExcel_Reader_Excel5_MD5','g');
+ $H = array('PHPExcel_Reader_Excel5_MD5','h');
+ $I = array('PHPExcel_Reader_Excel5_MD5','i');
+
+ /* ROUND 1 */
+ self::step($F, $A, $B, $C, $D, $words[0], 7, 0xd76aa478);
+ self::step($F, $D, $A, $B, $C, $words[1], 12, 0xe8c7b756);
+ self::step($F, $C, $D, $A, $B, $words[2], 17, 0x242070db);
+ self::step($F, $B, $C, $D, $A, $words[3], 22, 0xc1bdceee);
+ self::step($F, $A, $B, $C, $D, $words[4], 7, 0xf57c0faf);
+ self::step($F, $D, $A, $B, $C, $words[5], 12, 0x4787c62a);
+ self::step($F, $C, $D, $A, $B, $words[6], 17, 0xa8304613);
+ self::step($F, $B, $C, $D, $A, $words[7], 22, 0xfd469501);
+ self::step($F, $A, $B, $C, $D, $words[8], 7, 0x698098d8);
+ self::step($F, $D, $A, $B, $C, $words[9], 12, 0x8b44f7af);
+ self::step($F, $C, $D, $A, $B, $words[10], 17, 0xffff5bb1);
+ self::step($F, $B, $C, $D, $A, $words[11], 22, 0x895cd7be);
+ self::step($F, $A, $B, $C, $D, $words[12], 7, 0x6b901122);
+ self::step($F, $D, $A, $B, $C, $words[13], 12, 0xfd987193);
+ self::step($F, $C, $D, $A, $B, $words[14], 17, 0xa679438e);
+ self::step($F, $B, $C, $D, $A, $words[15], 22, 0x49b40821);
+
+ /* ROUND 2 */
+ self::step($G, $A, $B, $C, $D, $words[1], 5, 0xf61e2562);
+ self::step($G, $D, $A, $B, $C, $words[6], 9, 0xc040b340);
+ self::step($G, $C, $D, $A, $B, $words[11], 14, 0x265e5a51);
+ self::step($G, $B, $C, $D, $A, $words[0], 20, 0xe9b6c7aa);
+ self::step($G, $A, $B, $C, $D, $words[5], 5, 0xd62f105d);
+ self::step($G, $D, $A, $B, $C, $words[10], 9, 0x02441453);
+ self::step($G, $C, $D, $A, $B, $words[15], 14, 0xd8a1e681);
+ self::step($G, $B, $C, $D, $A, $words[4], 20, 0xe7d3fbc8);
+ self::step($G, $A, $B, $C, $D, $words[9], 5, 0x21e1cde6);
+ self::step($G, $D, $A, $B, $C, $words[14], 9, 0xc33707d6);
+ self::step($G, $C, $D, $A, $B, $words[3], 14, 0xf4d50d87);
+ self::step($G, $B, $C, $D, $A, $words[8], 20, 0x455a14ed);
+ self::step($G, $A, $B, $C, $D, $words[13], 5, 0xa9e3e905);
+ self::step($G, $D, $A, $B, $C, $words[2], 9, 0xfcefa3f8);
+ self::step($G, $C, $D, $A, $B, $words[7], 14, 0x676f02d9);
+ self::step($G, $B, $C, $D, $A, $words[12], 20, 0x8d2a4c8a);
+
+ /* ROUND 3 */
+ self::step($H, $A, $B, $C, $D, $words[5], 4, 0xfffa3942);
+ self::step($H, $D, $A, $B, $C, $words[8], 11, 0x8771f681);
+ self::step($H, $C, $D, $A, $B, $words[11], 16, 0x6d9d6122);
+ self::step($H, $B, $C, $D, $A, $words[14], 23, 0xfde5380c);
+ self::step($H, $A, $B, $C, $D, $words[1], 4, 0xa4beea44);
+ self::step($H, $D, $A, $B, $C, $words[4], 11, 0x4bdecfa9);
+ self::step($H, $C, $D, $A, $B, $words[7], 16, 0xf6bb4b60);
+ self::step($H, $B, $C, $D, $A, $words[10], 23, 0xbebfbc70);
+ self::step($H, $A, $B, $C, $D, $words[13], 4, 0x289b7ec6);
+ self::step($H, $D, $A, $B, $C, $words[0], 11, 0xeaa127fa);
+ self::step($H, $C, $D, $A, $B, $words[3], 16, 0xd4ef3085);
+ self::step($H, $B, $C, $D, $A, $words[6], 23, 0x04881d05);
+ self::step($H, $A, $B, $C, $D, $words[9], 4, 0xd9d4d039);
+ self::step($H, $D, $A, $B, $C, $words[12], 11, 0xe6db99e5);
+ self::step($H, $C, $D, $A, $B, $words[15], 16, 0x1fa27cf8);
+ self::step($H, $B, $C, $D, $A, $words[2], 23, 0xc4ac5665);
+
+ /* ROUND 4 */
+ self::step($I, $A, $B, $C, $D, $words[0], 6, 0xf4292244);
+ self::step($I, $D, $A, $B, $C, $words[7], 10, 0x432aff97);
+ self::step($I, $C, $D, $A, $B, $words[14], 15, 0xab9423a7);
+ self::step($I, $B, $C, $D, $A, $words[5], 21, 0xfc93a039);
+ self::step($I, $A, $B, $C, $D, $words[12], 6, 0x655b59c3);
+ self::step($I, $D, $A, $B, $C, $words[3], 10, 0x8f0ccc92);
+ self::step($I, $C, $D, $A, $B, $words[10], 15, 0xffeff47d);
+ self::step($I, $B, $C, $D, $A, $words[1], 21, 0x85845dd1);
+ self::step($I, $A, $B, $C, $D, $words[8], 6, 0x6fa87e4f);
+ self::step($I, $D, $A, $B, $C, $words[15], 10, 0xfe2ce6e0);
+ self::step($I, $C, $D, $A, $B, $words[6], 15, 0xa3014314);
+ self::step($I, $B, $C, $D, $A, $words[13], 21, 0x4e0811a1);
+ self::step($I, $A, $B, $C, $D, $words[4], 6, 0xf7537e82);
+ self::step($I, $D, $A, $B, $C, $words[11], 10, 0xbd3af235);
+ self::step($I, $C, $D, $A, $B, $words[2], 15, 0x2ad7d2bb);
+ self::step($I, $B, $C, $D, $A, $words[9], 21, 0xeb86d391);
+
+ $this->a = ($this->a + $A) & 0xffffffff;
+ $this->b = ($this->b + $B) & 0xffffffff;
+ $this->c = ($this->c + $C) & 0xffffffff;
+ $this->d = ($this->d + $D) & 0xffffffff;
+ }
+
+ private static function f($X, $Y, $Z)
+ {
+ return (($X & $Y) | ((~ $X) & $Z)); // X AND Y OR NOT X AND Z
+ }
+
+ private static function g($X, $Y, $Z)
+ {
+ return (($X & $Z) | ($Y & (~ $Z))); // X AND Z OR Y AND NOT Z
+ }
+
+ private static function h($X, $Y, $Z)
+ {
+ return ($X ^ $Y ^ $Z); // X XOR Y XOR Z
+ }
+
+ private static function i($X, $Y, $Z)
+ {
+ return ($Y ^ ($X | (~ $Z))) ; // Y XOR (X OR NOT Z)
+ }
+
+ private static function step($func, &$A, $B, $C, $D, $M, $s, $t)
+ {
+ $A = ($A + call_user_func($func, $B, $C, $D) + $M + $t) & 0xffffffff;
+ $A = self::rotate($A, $s);
+ $A = ($B + $A) & 0xffffffff;
+ }
+
+ private static function rotate($decimal, $bits)
+ {
+ $binary = str_pad(decbin($decimal), 32, "0", STR_PAD_LEFT);
+ return bindec(substr($binary, $bits).substr($binary, 0, $bits));
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/RC4.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/RC4.php
new file mode 100755
index 0000000..5640539
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/RC4.php
@@ -0,0 +1,81 @@
+i = 0; $this->i < 256; $this->i++) {
+ $this->s[$this->i] = $this->i;
+ }
+
+ $this->j = 0;
+ for ($this->i = 0; $this->i < 256; $this->i++) {
+ $this->j = ($this->j + $this->s[$this->i] + ord($key[$this->i % $len])) % 256;
+ $t = $this->s[$this->i];
+ $this->s[$this->i] = $this->s[$this->j];
+ $this->s[$this->j] = $t;
+ }
+ $this->i = $this->j = 0;
+ }
+
+ /**
+ * Symmetric decryption/encryption function
+ *
+ * @param string $data Data to encrypt/decrypt
+ *
+ * @return string
+ */
+ public function RC4($data)
+ {
+ $len = strlen($data);
+ for ($c = 0; $c < $len; $c++) {
+ $this->i = ($this->i + 1) % 256;
+ $this->j = ($this->j + $this->s[$this->i]) % 256;
+ $t = $this->s[$this->i];
+ $this->s[$this->i] = $this->s[$this->j];
+ $this->s[$this->j] = $t;
+
+ $t = ($this->s[$this->i] + $this->s[$this->j]) % 256;
+
+ $data[$c] = chr(ord($data[$c]) ^ $this->s[$t]);
+ }
+ return $data;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Style/Border.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Style/Border.php
new file mode 100755
index 0000000..fb45b9d
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Style/Border.php
@@ -0,0 +1,36 @@
+ PHPExcel_Style_Border::BORDER_NONE,
+ 0x01 => PHPExcel_Style_Border::BORDER_THIN,
+ 0x02 => PHPExcel_Style_Border::BORDER_MEDIUM,
+ 0x03 => PHPExcel_Style_Border::BORDER_DASHED,
+ 0x04 => PHPExcel_Style_Border::BORDER_DOTTED,
+ 0x05 => PHPExcel_Style_Border::BORDER_THICK,
+ 0x06 => PHPExcel_Style_Border::BORDER_DOUBLE,
+ 0x07 => PHPExcel_Style_Border::BORDER_HAIR,
+ 0x08 => PHPExcel_Style_Border::BORDER_MEDIUMDASHED,
+ 0x09 => PHPExcel_Style_Border::BORDER_DASHDOT,
+ 0x0A => PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT,
+ 0x0B => PHPExcel_Style_Border::BORDER_DASHDOTDOT,
+ 0x0C => PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT,
+ 0x0D => PHPExcel_Style_Border::BORDER_SLANTDASHDOT,
+ );
+
+ /**
+ * Map border style
+ * OpenOffice documentation: 2.5.11
+ *
+ * @param int $index
+ * @return string
+ */
+ public static function lookup($index)
+ {
+ if (isset(self::$map[$index])) {
+ return self::$map[$index];
+ }
+ return PHPExcel_Style_Border::BORDER_NONE;
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Excel5/Style/FillPattern.php b/extend/PHPExcel/PHPExcel/Reader/Excel5/Style/FillPattern.php
new file mode 100755
index 0000000..c92d19a
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Excel5/Style/FillPattern.php
@@ -0,0 +1,41 @@
+ PHPExcel_Style_Fill::FILL_NONE,
+ 0x01 => PHPExcel_Style_Fill::FILL_SOLID,
+ 0x02 => PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY,
+ 0x03 => PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY,
+ 0x04 => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY,
+ 0x05 => PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL,
+ 0x06 => PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL,
+ 0x07 => PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN,
+ 0x08 => PHPExcel_Style_Fill::FILL_PATTERN_DARKUP,
+ 0x09 => PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID,
+ 0x0A => PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS,
+ 0x0B => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL,
+ 0x0C => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL,
+ 0x0D => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN,
+ 0x0E => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP,
+ 0x0F => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID,
+ 0x10 => PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS,
+ 0x11 => PHPExcel_Style_Fill::FILL_PATTERN_GRAY125,
+ 0x12 => PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625,
+ );
+
+ /**
+ * Get fill pattern from index
+ * OpenOffice documentation: 2.5.12
+ *
+ * @param int $index
+ * @return string
+ */
+ public static function lookup($index)
+ {
+ if (isset(self::$map[$index])) {
+ return self::$map[$index];
+ }
+ return PHPExcel_Style_Fill::FILL_NONE;
+ }
+}
\ No newline at end of file
diff --git a/extend/PHPExcel/PHPExcel/Reader/Exception.php b/extend/PHPExcel/PHPExcel/Reader/Exception.php
new file mode 100755
index 0000000..48b3f82
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Exception.php
@@ -0,0 +1,46 @@
+line = $line;
+ $e->file = $file;
+ throw $e;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/Gnumeric.php b/extend/PHPExcel/PHPExcel/Reader/Gnumeric.php
new file mode 100755
index 0000000..913e52b
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/Gnumeric.php
@@ -0,0 +1,850 @@
+readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ $this->referenceHelper = PHPExcel_ReferenceHelper::getInstance();
+ }
+
+ /**
+ * Can the current PHPExcel_Reader_IReader read the file?
+ *
+ * @param string $pFilename
+ * @return boolean
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function canRead($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ // Check if gzlib functions are available
+ if (!function_exists('gzread')) {
+ throw new PHPExcel_Reader_Exception("gzlib library is not enabled");
+ }
+
+ // Read signature data (first 3 bytes)
+ $fh = fopen($pFilename, 'r');
+ $data = fread($fh, 2);
+ fclose($fh);
+
+ if ($data != chr(0x1F).chr(0x8B)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetNames($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $xml = new XMLReader();
+ $xml->xml($this->securityScanFile('compress.zlib://'.realpath($pFilename)), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+ $xml->setParserProperty(2, true);
+
+ $worksheetNames = array();
+ while ($xml->read()) {
+ if ($xml->name == 'gnm:SheetName' && $xml->nodeType == XMLReader::ELEMENT) {
+ $xml->read(); // Move onto the value node
+ $worksheetNames[] = (string) $xml->value;
+ } elseif ($xml->name == 'gnm:Sheets') {
+ // break out of the loop once we've got our sheet names rather than parse the entire file
+ break;
+ }
+ }
+
+ return $worksheetNames;
+ }
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $xml = new XMLReader();
+ $xml->xml($this->securityScanFile('compress.zlib://'.realpath($pFilename)), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+ $xml->setParserProperty(2, true);
+
+ $worksheetInfo = array();
+ while ($xml->read()) {
+ if ($xml->name == 'gnm:Sheet' && $xml->nodeType == XMLReader::ELEMENT) {
+ $tmpInfo = array(
+ 'worksheetName' => '',
+ 'lastColumnLetter' => 'A',
+ 'lastColumnIndex' => 0,
+ 'totalRows' => 0,
+ 'totalColumns' => 0,
+ );
+
+ while ($xml->read()) {
+ if ($xml->name == 'gnm:Name' && $xml->nodeType == XMLReader::ELEMENT) {
+ $xml->read(); // Move onto the value node
+ $tmpInfo['worksheetName'] = (string) $xml->value;
+ } elseif ($xml->name == 'gnm:MaxCol' && $xml->nodeType == XMLReader::ELEMENT) {
+ $xml->read(); // Move onto the value node
+ $tmpInfo['lastColumnIndex'] = (int) $xml->value;
+ $tmpInfo['totalColumns'] = (int) $xml->value + 1;
+ } elseif ($xml->name == 'gnm:MaxRow' && $xml->nodeType == XMLReader::ELEMENT) {
+ $xml->read(); // Move onto the value node
+ $tmpInfo['totalRows'] = (int) $xml->value + 1;
+ break;
+ }
+ }
+ $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+ $worksheetInfo[] = $tmpInfo;
+ }
+ }
+
+ return $worksheetInfo;
+ }
+
+ private function gzfileGetContents($filename)
+ {
+ $file = @gzopen($filename, 'rb');
+ if ($file !== false) {
+ $data = '';
+ while (!gzeof($file)) {
+ $data .= gzread($file, 1024);
+ }
+ gzclose($file);
+ }
+ return $data;
+ }
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Create new PHPExcel
+ $objPHPExcel = new PHPExcel();
+
+ // Load into this instance
+ return $this->loadIntoExisting($pFilename, $objPHPExcel);
+ }
+
+ /**
+ * Loads PHPExcel from file into PHPExcel instance
+ *
+ * @param string $pFilename
+ * @param PHPExcel $objPHPExcel
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $timezoneObj = new DateTimeZone('Europe/London');
+ $GMT = new DateTimeZone('UTC');
+
+ $gFileData = $this->gzfileGetContents($pFilename);
+
+// echo '';
+// echo htmlentities($gFileData,ENT_QUOTES,'UTF-8');
+// echo ' ';
+//
+ $xml = simplexml_load_string($this->securityScan($gFileData), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespacesMeta = $xml->getNamespaces(true);
+
+// var_dump($namespacesMeta);
+//
+ $gnmXML = $xml->children($namespacesMeta['gnm']);
+
+ $docProps = $objPHPExcel->getProperties();
+ // Document Properties are held differently, depending on the version of Gnumeric
+ if (isset($namespacesMeta['office'])) {
+ $officeXML = $xml->children($namespacesMeta['office']);
+ $officeDocXML = $officeXML->{'document-meta'};
+ $officeDocMetaXML = $officeDocXML->meta;
+
+ foreach ($officeDocMetaXML as $officePropertyData) {
+ $officePropertyDC = array();
+ if (isset($namespacesMeta['dc'])) {
+ $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']);
+ }
+ foreach ($officePropertyDC as $propertyName => $propertyValue) {
+ $propertyValue = (string) $propertyValue;
+ switch ($propertyName) {
+ case 'title':
+ $docProps->setTitle(trim($propertyValue));
+ break;
+ case 'subject':
+ $docProps->setSubject(trim($propertyValue));
+ break;
+ case 'creator':
+ $docProps->setCreator(trim($propertyValue));
+ $docProps->setLastModifiedBy(trim($propertyValue));
+ break;
+ case 'date':
+ $creationDate = strtotime(trim($propertyValue));
+ $docProps->setCreated($creationDate);
+ $docProps->setModified($creationDate);
+ break;
+ case 'description':
+ $docProps->setDescription(trim($propertyValue));
+ break;
+ }
+ }
+ $officePropertyMeta = array();
+ if (isset($namespacesMeta['meta'])) {
+ $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
+ }
+ foreach ($officePropertyMeta as $propertyName => $propertyValue) {
+ $attributes = $propertyValue->attributes($namespacesMeta['meta']);
+ $propertyValue = (string) $propertyValue;
+ switch ($propertyName) {
+ case 'keyword':
+ $docProps->setKeywords(trim($propertyValue));
+ break;
+ case 'initial-creator':
+ $docProps->setCreator(trim($propertyValue));
+ $docProps->setLastModifiedBy(trim($propertyValue));
+ break;
+ case 'creation-date':
+ $creationDate = strtotime(trim($propertyValue));
+ $docProps->setCreated($creationDate);
+ $docProps->setModified($creationDate);
+ break;
+ case 'user-defined':
+ list(, $attrName) = explode(':', $attributes['name']);
+ switch ($attrName) {
+ case 'publisher':
+ $docProps->setCompany(trim($propertyValue));
+ break;
+ case 'category':
+ $docProps->setCategory(trim($propertyValue));
+ break;
+ case 'manager':
+ $docProps->setManager(trim($propertyValue));
+ break;
+ }
+ break;
+ }
+ }
+ }
+ } elseif (isset($gnmXML->Summary)) {
+ foreach ($gnmXML->Summary->Item as $summaryItem) {
+ $propertyName = $summaryItem->name;
+ $propertyValue = $summaryItem->{'val-string'};
+ switch ($propertyName) {
+ case 'title':
+ $docProps->setTitle(trim($propertyValue));
+ break;
+ case 'comments':
+ $docProps->setDescription(trim($propertyValue));
+ break;
+ case 'keywords':
+ $docProps->setKeywords(trim($propertyValue));
+ break;
+ case 'category':
+ $docProps->setCategory(trim($propertyValue));
+ break;
+ case 'manager':
+ $docProps->setManager(trim($propertyValue));
+ break;
+ case 'author':
+ $docProps->setCreator(trim($propertyValue));
+ $docProps->setLastModifiedBy(trim($propertyValue));
+ break;
+ case 'company':
+ $docProps->setCompany(trim($propertyValue));
+ break;
+ }
+ }
+ }
+
+ $worksheetID = 0;
+ foreach ($gnmXML->Sheets->Sheet as $sheet) {
+ $worksheetName = (string) $sheet->Name;
+// echo 'Worksheet: ', $worksheetName,' ';
+ if ((isset($this->loadSheetsOnly)) && (!in_array($worksheetName, $this->loadSheetsOnly))) {
+ continue;
+ }
+
+ $maxRow = $maxCol = 0;
+
+ // Create new Worksheet
+ $objPHPExcel->createSheet();
+ $objPHPExcel->setActiveSheetIndex($worksheetID);
+ // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
+ // cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
+ // name in line with the formula, not the reverse
+ $objPHPExcel->getActiveSheet()->setTitle($worksheetName, false);
+
+ if ((!$this->readDataOnly) && (isset($sheet->PrintInformation))) {
+ if (isset($sheet->PrintInformation->Margins)) {
+ foreach ($sheet->PrintInformation->Margins->children('gnm', true) as $key => $margin) {
+ $marginAttributes = $margin->attributes();
+ $marginSize = 72 / 100; // Default
+ switch ($marginAttributes['PrefUnit']) {
+ case 'mm':
+ $marginSize = intval($marginAttributes['Points']) / 100;
+ break;
+ }
+ switch ($key) {
+ case 'top':
+ $objPHPExcel->getActiveSheet()->getPageMargins()->setTop($marginSize);
+ break;
+ case 'bottom':
+ $objPHPExcel->getActiveSheet()->getPageMargins()->setBottom($marginSize);
+ break;
+ case 'left':
+ $objPHPExcel->getActiveSheet()->getPageMargins()->setLeft($marginSize);
+ break;
+ case 'right':
+ $objPHPExcel->getActiveSheet()->getPageMargins()->setRight($marginSize);
+ break;
+ case 'header':
+ $objPHPExcel->getActiveSheet()->getPageMargins()->setHeader($marginSize);
+ break;
+ case 'footer':
+ $objPHPExcel->getActiveSheet()->getPageMargins()->setFooter($marginSize);
+ break;
+ }
+ }
+ }
+ }
+
+ foreach ($sheet->Cells->Cell as $cell) {
+ $cellAttributes = $cell->attributes();
+ $row = (int) $cellAttributes->Row + 1;
+ $column = (int) $cellAttributes->Col;
+
+ if ($row > $maxRow) {
+ $maxRow = $row;
+ }
+ if ($column > $maxCol) {
+ $maxCol = $column;
+ }
+
+ $column = PHPExcel_Cell::stringFromColumnIndex($column);
+
+ // Read cell?
+ if ($this->getReadFilter() !== null) {
+ if (!$this->getReadFilter()->readCell($column, $row, $worksheetName)) {
+ continue;
+ }
+ }
+
+ $ValueType = $cellAttributes->ValueType;
+ $ExprID = (string) $cellAttributes->ExprID;
+// echo 'Cell ', $column, $row,' ';
+// echo 'Type is ', $ValueType,' ';
+// echo 'Value is ', $cell,' ';
+ $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+ if ($ExprID > '') {
+ if (((string) $cell) > '') {
+ $this->expressions[$ExprID] = array(
+ 'column' => $cellAttributes->Col,
+ 'row' => $cellAttributes->Row,
+ 'formula' => (string) $cell
+ );
+// echo 'NEW EXPRESSION ', $ExprID,' ';
+ } else {
+ $expression = $this->expressions[$ExprID];
+
+ $cell = $this->referenceHelper->updateFormulaReferences(
+ $expression['formula'],
+ 'A1',
+ $cellAttributes->Col - $expression['column'],
+ $cellAttributes->Row - $expression['row'],
+ $worksheetName
+ );
+// echo 'SHARED EXPRESSION ', $ExprID,' ';
+// echo 'New Value is ', $cell,' ';
+ }
+ $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+ } else {
+ switch ($ValueType) {
+ case '10': // NULL
+ $type = PHPExcel_Cell_DataType::TYPE_NULL;
+ break;
+ case '20': // Boolean
+ $type = PHPExcel_Cell_DataType::TYPE_BOOL;
+ $cell = ($cell == 'TRUE') ? true: false;
+ break;
+ case '30': // Integer
+ $cell = intval($cell);
+ // Excel 2007+ doesn't differentiate between integer and float, so set the value and dropthru to the next (numeric) case
+ case '40': // Float
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ break;
+ case '50': // Error
+ $type = PHPExcel_Cell_DataType::TYPE_ERROR;
+ break;
+ case '60': // String
+ $type = PHPExcel_Cell_DataType::TYPE_STRING;
+ break;
+ case '70': // Cell Range
+ case '80': // Array
+ }
+ }
+ $objPHPExcel->getActiveSheet()->getCell($column.$row)->setValueExplicit($cell, $type);
+ }
+
+ if ((!$this->readDataOnly) && (isset($sheet->Objects))) {
+ foreach ($sheet->Objects->children('gnm', true) as $key => $comment) {
+ $commentAttributes = $comment->attributes();
+ // Only comment objects are handled at the moment
+ if ($commentAttributes->Text) {
+ $objPHPExcel->getActiveSheet()->getComment((string)$commentAttributes->ObjectBound)->setAuthor((string)$commentAttributes->Author)->setText($this->parseRichText((string)$commentAttributes->Text));
+ }
+ }
+ }
+// echo '$maxCol=', $maxCol,'; $maxRow=', $maxRow,' ';
+//
+ foreach ($sheet->Styles->StyleRegion as $styleRegion) {
+ $styleAttributes = $styleRegion->attributes();
+ if (($styleAttributes['startRow'] <= $maxRow) &&
+ ($styleAttributes['startCol'] <= $maxCol)) {
+ $startColumn = PHPExcel_Cell::stringFromColumnIndex((int) $styleAttributes['startCol']);
+ $startRow = $styleAttributes['startRow'] + 1;
+
+ $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol'];
+ $endColumn = PHPExcel_Cell::stringFromColumnIndex($endColumn);
+ $endRow = ($styleAttributes['endRow'] > $maxRow) ? $maxRow : $styleAttributes['endRow'];
+ $endRow += 1;
+ $cellRange = $startColumn.$startRow.':'.$endColumn.$endRow;
+// echo $cellRange,' ';
+
+ $styleAttributes = $styleRegion->Style->attributes();
+// var_dump($styleAttributes);
+// echo ' ';
+
+ // We still set the number format mask for date/time values, even if readDataOnly is true
+ if ((!$this->readDataOnly) ||
+ (PHPExcel_Shared_Date::isDateTimeFormatCode((string) $styleAttributes['Format']))) {
+ $styleArray = array();
+ $styleArray['numberformat']['code'] = (string) $styleAttributes['Format'];
+ // If readDataOnly is false, we set all formatting information
+ if (!$this->readDataOnly) {
+ switch ($styleAttributes['HAlign']) {
+ case '1':
+ $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL;
+ break;
+ case '2':
+ $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_LEFT;
+ break;
+ case '4':
+ $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT;
+ break;
+ case '8':
+ $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_CENTER;
+ break;
+ case '16':
+ case '64':
+ $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS;
+ break;
+ case '32':
+ $styleArray['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY;
+ break;
+ }
+
+ switch ($styleAttributes['VAlign']) {
+ case '1':
+ $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_TOP;
+ break;
+ case '2':
+ $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_BOTTOM;
+ break;
+ case '4':
+ $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_CENTER;
+ break;
+ case '8':
+ $styleArray['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY;
+ break;
+ }
+
+ $styleArray['alignment']['wrap'] = ($styleAttributes['WrapText'] == '1') ? true : false;
+ $styleArray['alignment']['shrinkToFit'] = ($styleAttributes['ShrinkToFit'] == '1') ? true : false;
+ $styleArray['alignment']['indent'] = (intval($styleAttributes["Indent"]) > 0) ? $styleAttributes["indent"] : 0;
+
+ $RGB = self::parseGnumericColour($styleAttributes["Fore"]);
+ $styleArray['font']['color']['rgb'] = $RGB;
+ $RGB = self::parseGnumericColour($styleAttributes["Back"]);
+ $shade = $styleAttributes["Shade"];
+ if (($RGB != '000000') || ($shade != '0')) {
+ $styleArray['fill']['color']['rgb'] = $styleArray['fill']['startcolor']['rgb'] = $RGB;
+ $RGB2 = self::parseGnumericColour($styleAttributes["PatternColor"]);
+ $styleArray['fill']['endcolor']['rgb'] = $RGB2;
+ switch ($shade) {
+ case '1':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_SOLID;
+ break;
+ case '2':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR;
+ break;
+ case '3':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_GRADIENT_PATH;
+ break;
+ case '4':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN;
+ break;
+ case '5':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY;
+ break;
+ case '6':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID;
+ break;
+ case '7':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL;
+ break;
+ case '8':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS;
+ break;
+ case '9':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKUP;
+ break;
+ case '10':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL;
+ break;
+ case '11':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625;
+ break;
+ case '12':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_GRAY125;
+ break;
+ case '13':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN;
+ break;
+ case '14':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY;
+ break;
+ case '15':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID;
+ break;
+ case '16':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL;
+ break;
+ case '17':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS;
+ break;
+ case '18':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP;
+ break;
+ case '19':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL;
+ break;
+ case '20':
+ $styleArray['fill']['type'] = PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY;
+ break;
+ }
+ }
+
+ $fontAttributes = $styleRegion->Style->Font->attributes();
+// var_dump($fontAttributes);
+// echo ' ';
+ $styleArray['font']['name'] = (string) $styleRegion->Style->Font;
+ $styleArray['font']['size'] = intval($fontAttributes['Unit']);
+ $styleArray['font']['bold'] = ($fontAttributes['Bold'] == '1') ? true : false;
+ $styleArray['font']['italic'] = ($fontAttributes['Italic'] == '1') ? true : false;
+ $styleArray['font']['strike'] = ($fontAttributes['StrikeThrough'] == '1') ? true : false;
+ switch ($fontAttributes['Underline']) {
+ case '1':
+ $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_SINGLE;
+ break;
+ case '2':
+ $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_DOUBLE;
+ break;
+ case '3':
+ $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING;
+ break;
+ case '4':
+ $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING;
+ break;
+ default:
+ $styleArray['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_NONE;
+ break;
+ }
+ switch ($fontAttributes['Script']) {
+ case '1':
+ $styleArray['font']['superScript'] = true;
+ break;
+ case '-1':
+ $styleArray['font']['subScript'] = true;
+ break;
+ }
+
+ if (isset($styleRegion->Style->StyleBorder)) {
+ if (isset($styleRegion->Style->StyleBorder->Top)) {
+ $styleArray['borders']['top'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Top->attributes());
+ }
+ if (isset($styleRegion->Style->StyleBorder->Bottom)) {
+ $styleArray['borders']['bottom'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Bottom->attributes());
+ }
+ if (isset($styleRegion->Style->StyleBorder->Left)) {
+ $styleArray['borders']['left'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Left->attributes());
+ }
+ if (isset($styleRegion->Style->StyleBorder->Right)) {
+ $styleArray['borders']['right'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Right->attributes());
+ }
+ if ((isset($styleRegion->Style->StyleBorder->Diagonal)) && (isset($styleRegion->Style->StyleBorder->{'Rev-Diagonal'}))) {
+ $styleArray['borders']['diagonal'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Diagonal->attributes());
+ $styleArray['borders']['diagonaldirection'] = PHPExcel_Style_Borders::DIAGONAL_BOTH;
+ } elseif (isset($styleRegion->Style->StyleBorder->Diagonal)) {
+ $styleArray['borders']['diagonal'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->Diagonal->attributes());
+ $styleArray['borders']['diagonaldirection'] = PHPExcel_Style_Borders::DIAGONAL_UP;
+ } elseif (isset($styleRegion->Style->StyleBorder->{'Rev-Diagonal'})) {
+ $styleArray['borders']['diagonal'] = self::parseBorderAttributes($styleRegion->Style->StyleBorder->{'Rev-Diagonal'}->attributes());
+ $styleArray['borders']['diagonaldirection'] = PHPExcel_Style_Borders::DIAGONAL_DOWN;
+ }
+ }
+ if (isset($styleRegion->Style->HyperLink)) {
+ // TO DO
+ $hyperlink = $styleRegion->Style->HyperLink->attributes();
+ }
+ }
+// var_dump($styleArray);
+// echo ' ';
+ $objPHPExcel->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray);
+ }
+ }
+ }
+
+ if ((!$this->readDataOnly) && (isset($sheet->Cols))) {
+ // Column Widths
+ $columnAttributes = $sheet->Cols->attributes();
+ $defaultWidth = $columnAttributes['DefaultSizePts'] / 5.4;
+ $c = 0;
+ foreach ($sheet->Cols->ColInfo as $columnOverride) {
+ $columnAttributes = $columnOverride->attributes();
+ $column = $columnAttributes['No'];
+ $columnWidth = $columnAttributes['Unit'] / 5.4;
+ $hidden = ((isset($columnAttributes['Hidden'])) && ($columnAttributes['Hidden'] == '1')) ? true : false;
+ $columnCount = (isset($columnAttributes['Count'])) ? $columnAttributes['Count'] : 1;
+ while ($c < $column) {
+ $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setWidth($defaultWidth);
+ ++$c;
+ }
+ while (($c < ($column+$columnCount)) && ($c <= $maxCol)) {
+ $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setWidth($columnWidth);
+ if ($hidden) {
+ $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setVisible(false);
+ }
+ ++$c;
+ }
+ }
+ while ($c <= $maxCol) {
+ $objPHPExcel->getActiveSheet()->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($c))->setWidth($defaultWidth);
+ ++$c;
+ }
+ }
+
+ if ((!$this->readDataOnly) && (isset($sheet->Rows))) {
+ // Row Heights
+ $rowAttributes = $sheet->Rows->attributes();
+ $defaultHeight = $rowAttributes['DefaultSizePts'];
+ $r = 0;
+
+ foreach ($sheet->Rows->RowInfo as $rowOverride) {
+ $rowAttributes = $rowOverride->attributes();
+ $row = $rowAttributes['No'];
+ $rowHeight = $rowAttributes['Unit'];
+ $hidden = ((isset($rowAttributes['Hidden'])) && ($rowAttributes['Hidden'] == '1')) ? true : false;
+ $rowCount = (isset($rowAttributes['Count'])) ? $rowAttributes['Count'] : 1;
+ while ($r < $row) {
+ ++$r;
+ $objPHPExcel->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight);
+ }
+ while (($r < ($row+$rowCount)) && ($r < $maxRow)) {
+ ++$r;
+ $objPHPExcel->getActiveSheet()->getRowDimension($r)->setRowHeight($rowHeight);
+ if ($hidden) {
+ $objPHPExcel->getActiveSheet()->getRowDimension($r)->setVisible(false);
+ }
+ }
+ }
+ while ($r < $maxRow) {
+ ++$r;
+ $objPHPExcel->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight);
+ }
+ }
+
+ // Handle Merged Cells in this worksheet
+ if (isset($sheet->MergedRegions)) {
+ foreach ($sheet->MergedRegions->Merge as $mergeCells) {
+ if (strpos($mergeCells, ':') !== false) {
+ $objPHPExcel->getActiveSheet()->mergeCells($mergeCells);
+ }
+ }
+ }
+
+ $worksheetID++;
+ }
+
+ // Loop through definedNames (global named ranges)
+ if (isset($gnmXML->Names)) {
+ foreach ($gnmXML->Names->Name as $namedRange) {
+ $name = (string) $namedRange->name;
+ $range = (string) $namedRange->value;
+ if (stripos($range, '#REF!') !== false) {
+ continue;
+ }
+
+ $range = explode('!', $range);
+ $range[0] = trim($range[0], "'");
+ if ($worksheet = $objPHPExcel->getSheetByName($range[0])) {
+ $extractedRange = str_replace('$', '', $range[1]);
+ $objPHPExcel->addNamedRange(new PHPExcel_NamedRange($name, $worksheet, $extractedRange));
+ }
+ }
+ }
+
+ // Return
+ return $objPHPExcel;
+ }
+
+ private static function parseBorderAttributes($borderAttributes)
+ {
+ $styleArray = array();
+ if (isset($borderAttributes["Color"])) {
+ $styleArray['color']['rgb'] = self::parseGnumericColour($borderAttributes["Color"]);
+ }
+
+ switch ($borderAttributes["Style"]) {
+ case '0':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_NONE;
+ break;
+ case '1':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_THIN;
+ break;
+ case '2':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUM;
+ break;
+ case '3':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
+ break;
+ case '4':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_DASHED;
+ break;
+ case '5':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_THICK;
+ break;
+ case '6':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_DOUBLE;
+ break;
+ case '7':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_DOTTED;
+ break;
+ case '8':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
+ break;
+ case '9':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_DASHDOT;
+ break;
+ case '10':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
+ break;
+ case '11':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_DASHDOTDOT;
+ break;
+ case '12':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
+ break;
+ case '13':
+ $styleArray['style'] = PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
+ break;
+ }
+ return $styleArray;
+ }
+
+ private function parseRichText($is = '')
+ {
+ $value = new PHPExcel_RichText();
+ $value->createText($is);
+
+ return $value;
+ }
+
+ private static function parseGnumericColour($gnmColour)
+ {
+ list($gnmR, $gnmG, $gnmB) = explode(':', $gnmColour);
+ $gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
+ $gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
+ $gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);
+ return $gnmR . $gnmG . $gnmB;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/HTML.php b/extend/PHPExcel/PHPExcel/Reader/HTML.php
new file mode 100755
index 0000000..ac762a4
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/HTML.php
@@ -0,0 +1,549 @@
+ array(
+ 'font' => array(
+ 'bold' => true,
+ 'size' => 24,
+ ),
+ ), // Bold, 24pt
+ 'h2' => array(
+ 'font' => array(
+ 'bold' => true,
+ 'size' => 18,
+ ),
+ ), // Bold, 18pt
+ 'h3' => array(
+ 'font' => array(
+ 'bold' => true,
+ 'size' => 13.5,
+ ),
+ ), // Bold, 13.5pt
+ 'h4' => array(
+ 'font' => array(
+ 'bold' => true,
+ 'size' => 12,
+ ),
+ ), // Bold, 12pt
+ 'h5' => array(
+ 'font' => array(
+ 'bold' => true,
+ 'size' => 10,
+ ),
+ ), // Bold, 10pt
+ 'h6' => array(
+ 'font' => array(
+ 'bold' => true,
+ 'size' => 7.5,
+ ),
+ ), // Bold, 7.5pt
+ 'a' => array(
+ 'font' => array(
+ 'underline' => true,
+ 'color' => array(
+ 'argb' => PHPExcel_Style_Color::COLOR_BLUE,
+ ),
+ ),
+ ), // Blue underlined
+ 'hr' => array(
+ 'borders' => array(
+ 'bottom' => array(
+ 'style' => PHPExcel_Style_Border::BORDER_THIN,
+ 'color' => array(
+ PHPExcel_Style_Color::COLOR_BLACK,
+ ),
+ ),
+ ),
+ ), // Bottom border
+ );
+
+ protected $rowspan = array();
+
+ /**
+ * Create a new PHPExcel_Reader_HTML
+ */
+ public function __construct()
+ {
+ $this->readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ }
+
+ /**
+ * Validate that the current file is an HTML file
+ *
+ * @return boolean
+ */
+ protected function isValidFormat()
+ {
+ // Reading 2048 bytes should be enough to validate that the format is HTML
+ $data = fread($this->fileHandle, 2048);
+ if ((strpos($data, '<') !== false) &&
+ (strlen($data) !== strlen(strip_tags($data)))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Create new PHPExcel
+ $objPHPExcel = new PHPExcel();
+
+ // Load into this instance
+ return $this->loadIntoExisting($pFilename, $objPHPExcel);
+ }
+
+ /**
+ * Set input encoding
+ *
+ * @param string $pValue Input encoding
+ */
+ public function setInputEncoding($pValue = 'ANSI')
+ {
+ $this->inputEncoding = $pValue;
+
+ return $this;
+ }
+
+ /**
+ * Get input encoding
+ *
+ * @return string
+ */
+ public function getInputEncoding()
+ {
+ return $this->inputEncoding;
+ }
+
+ // Data Array used for testing only, should write to PHPExcel object on completion of tests
+ protected $dataArray = array();
+ protected $tableLevel = 0;
+ protected $nestedColumn = array('A');
+
+ protected function setTableStartColumn($column)
+ {
+ if ($this->tableLevel == 0) {
+ $column = 'A';
+ }
+ ++$this->tableLevel;
+ $this->nestedColumn[$this->tableLevel] = $column;
+
+ return $this->nestedColumn[$this->tableLevel];
+ }
+
+ protected function getTableStartColumn()
+ {
+ return $this->nestedColumn[$this->tableLevel];
+ }
+
+ protected function releaseTableStartColumn()
+ {
+ --$this->tableLevel;
+
+ return array_pop($this->nestedColumn);
+ }
+
+ protected function flushCell($sheet, $column, $row, &$cellContent)
+ {
+ if (is_string($cellContent)) {
+ // Simple String content
+ if (trim($cellContent) > '') {
+ // Only actually write it if there's content in the string
+// echo 'FLUSH CELL: ' , $column , $row , ' => ' , $cellContent , ' ';
+ // Write to worksheet to be done here...
+ // ... we return the cell so we can mess about with styles more easily
+ $sheet->setCellValue($column . $row, $cellContent, true);
+ $this->dataArray[$row][$column] = $cellContent;
+ }
+ } else {
+ // We have a Rich Text run
+ // TODO
+ $this->dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
+ }
+ $cellContent = (string) '';
+ }
+
+ protected function processDomElement(DOMNode $element, $sheet, &$row, &$column, &$cellContent, $format = null)
+ {
+ foreach ($element->childNodes as $child) {
+ if ($child instanceof DOMText) {
+ $domText = preg_replace('/\s+/u', ' ', trim($child->nodeValue));
+ if (is_string($cellContent)) {
+ // simply append the text if the cell content is a plain text string
+ $cellContent .= $domText;
+ } else {
+ // but if we have a rich text run instead, we need to append it correctly
+ // TODO
+ }
+ } elseif ($child instanceof DOMElement) {
+// echo 'DOM ELEMENT: ' , strtoupper($child->nodeName) , ' ';
+
+ $attributeArray = array();
+ foreach ($child->attributes as $attribute) {
+// echo 'ATTRIBUTE: ' , $attribute->name , ' => ' , $attribute->value , ' ';
+ $attributeArray[$attribute->name] = $attribute->value;
+ }
+
+ switch ($child->nodeName) {
+ case 'meta':
+ foreach ($attributeArray as $attributeName => $attributeValue) {
+ switch ($attributeName) {
+ case 'content':
+ // TODO
+ // Extract character set, so we can convert to UTF-8 if required
+ break;
+ }
+ }
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ break;
+ case 'title':
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ $sheet->setTitle($cellContent);
+ $cellContent = '';
+ break;
+ case 'span':
+ case 'div':
+ case 'font':
+ case 'i':
+ case 'em':
+ case 'strong':
+ case 'b':
+// echo 'STYLING, SPAN OR DIV ';
+ if ($cellContent > '') {
+ $cellContent .= ' ';
+ }
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ if ($cellContent > '') {
+ $cellContent .= ' ';
+ }
+// echo 'END OF STYLING, SPAN OR DIV ';
+ break;
+ case 'hr':
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ ++$row;
+ if (isset($this->formats[$child->nodeName])) {
+ $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+ } else {
+ $cellContent = '----------';
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ }
+ ++$row;
+ // Add a break after a horizontal rule, simply by allowing the code to dropthru
+ case 'br':
+ if ($this->tableLevel > 0) {
+ // If we're inside a table, replace with a \n
+ $cellContent .= "\n";
+ } else {
+ // Otherwise flush our existing content and move the row cursor on
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ ++$row;
+ }
+// echo 'HARD LINE BREAK: ' , ' ';
+ break;
+ case 'a':
+// echo 'START OF HYPERLINK: ' , ' ';
+ foreach ($attributeArray as $attributeName => $attributeValue) {
+ switch ($attributeName) {
+ case 'href':
+// echo 'Link to ' , $attributeValue , ' ';
+ $sheet->getCell($column . $row)->getHyperlink()->setUrl($attributeValue);
+ if (isset($this->formats[$child->nodeName])) {
+ $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+ }
+ break;
+ }
+ }
+ $cellContent .= ' ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF HYPERLINK:' , ' ';
+ break;
+ case 'h1':
+ case 'h2':
+ case 'h3':
+ case 'h4':
+ case 'h5':
+ case 'h6':
+ case 'ol':
+ case 'ul':
+ case 'p':
+ if ($this->tableLevel > 0) {
+ // If we're inside a table, replace with a \n
+ $cellContent .= "\n";
+// echo 'LIST ENTRY: ' , ' ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF LIST ENTRY:' , ' ';
+ } else {
+ if ($cellContent > '') {
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ $row++;
+ }
+// echo 'START OF PARAGRAPH: ' , ' ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF PARAGRAPH:' , ' ';
+ $this->flushCell($sheet, $column, $row, $cellContent);
+
+ if (isset($this->formats[$child->nodeName])) {
+ $sheet->getStyle($column . $row)->applyFromArray($this->formats[$child->nodeName]);
+ }
+
+ $row++;
+ $column = 'A';
+ }
+ break;
+ case 'li':
+ if ($this->tableLevel > 0) {
+ // If we're inside a table, replace with a \n
+ $cellContent .= "\n";
+// echo 'LIST ENTRY: ' , ' ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF LIST ENTRY:' , ' ';
+ } else {
+ if ($cellContent > '') {
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ }
+ ++$row;
+// echo 'LIST ENTRY: ' , ' ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF LIST ENTRY:' , ' ';
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ $column = 'A';
+ }
+ break;
+ case 'table':
+ $this->flushCell($sheet, $column, $row, $cellContent);
+ $column = $this->setTableStartColumn($column);
+// echo 'START OF TABLE LEVEL ' , $this->tableLevel , ' ';
+ if ($this->tableLevel > 1) {
+ --$row;
+ }
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF TABLE LEVEL ' , $this->tableLevel , ' ';
+ $column = $this->releaseTableStartColumn();
+ if ($this->tableLevel > 1) {
+ ++$column;
+ } else {
+ ++$row;
+ }
+ break;
+ case 'thead':
+ case 'tbody':
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ break;
+ case 'tr':
+ $column = $this->getTableStartColumn();
+ $cellContent = '';
+// echo 'START OF TABLE ' , $this->tableLevel , ' ROW ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ ++$row;
+// echo 'END OF TABLE ' , $this->tableLevel , ' ROW ';
+ break;
+ case 'th':
+ case 'td':
+// echo 'START OF TABLE ' , $this->tableLevel , ' CELL ';
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+// echo 'END OF TABLE ' , $this->tableLevel , ' CELL ';
+
+ while (isset($this->rowspan[$column . $row])) {
+ ++$column;
+ }
+
+ $this->flushCell($sheet, $column, $row, $cellContent);
+
+// if (isset($attributeArray['style']) && !empty($attributeArray['style'])) {
+// $styleAry = $this->getPhpExcelStyleArray($attributeArray['style']);
+//
+// if (!empty($styleAry)) {
+// $sheet->getStyle($column . $row)->applyFromArray($styleAry);
+// }
+// }
+
+ if (isset($attributeArray['rowspan']) && isset($attributeArray['colspan'])) {
+ //create merging rowspan and colspan
+ $columnTo = $column;
+ for ($i = 0; $i < $attributeArray['colspan'] - 1; $i++) {
+ ++$columnTo;
+ }
+ $range = $column . $row . ':' . $columnTo . ($row + $attributeArray['rowspan'] - 1);
+ foreach (\PHPExcel_Cell::extractAllCellReferencesInRange($range) as $value) {
+ $this->rowspan[$value] = true;
+ }
+ $sheet->mergeCells($range);
+ $column = $columnTo;
+ } elseif (isset($attributeArray['rowspan'])) {
+ //create merging rowspan
+ $range = $column . $row . ':' . $column . ($row + $attributeArray['rowspan'] - 1);
+ foreach (\PHPExcel_Cell::extractAllCellReferencesInRange($range) as $value) {
+ $this->rowspan[$value] = true;
+ }
+ $sheet->mergeCells($range);
+ } elseif (isset($attributeArray['colspan'])) {
+ //create merging colspan
+ $columnTo = $column;
+ for ($i = 0; $i < $attributeArray['colspan'] - 1; $i++) {
+ ++$columnTo;
+ }
+ $sheet->mergeCells($column . $row . ':' . $columnTo . $row);
+ $column = $columnTo;
+ }
+ ++$column;
+ break;
+ case 'body':
+ $row = 1;
+ $column = 'A';
+ $content = '';
+ $this->tableLevel = 0;
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ break;
+ default:
+ $this->processDomElement($child, $sheet, $row, $column, $cellContent);
+ }
+ }
+ }
+ }
+
+ /**
+ * Loads PHPExcel from file into PHPExcel instance
+ *
+ * @param string $pFilename
+ * @param PHPExcel $objPHPExcel
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+ {
+ // Open file to validate
+ $this->openFile($pFilename);
+ if (!$this->isValidFormat()) {
+ fclose($this->fileHandle);
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid HTML file.");
+ }
+ // Close after validating
+ fclose($this->fileHandle);
+
+ // Create new PHPExcel
+ while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
+ $objPHPExcel->createSheet();
+ }
+ $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
+
+ // Create a new DOM object
+ $dom = new domDocument;
+ // Reload the HTML file into the DOM object
+ $loaded = $dom->loadHTML(mb_convert_encoding($this->securityScanFile($pFilename), 'HTML-ENTITIES', 'UTF-8'));
+ if ($loaded === false) {
+ throw new PHPExcel_Reader_Exception('Failed to load ' . $pFilename . ' as a DOM Document');
+ }
+
+ // Discard white space
+ $dom->preserveWhiteSpace = false;
+
+ $row = 0;
+ $column = 'A';
+ $content = '';
+ $this->processDomElement($dom, $objPHPExcel->getActiveSheet(), $row, $column, $content);
+
+ // Return
+ return $objPHPExcel;
+ }
+
+ /**
+ * Get sheet index
+ *
+ * @return int
+ */
+ public function getSheetIndex()
+ {
+ return $this->sheetIndex;
+ }
+
+ /**
+ * Set sheet index
+ *
+ * @param int $pValue Sheet index
+ * @return PHPExcel_Reader_HTML
+ */
+ public function setSheetIndex($pValue = 0)
+ {
+ $this->sheetIndex = $pValue;
+
+ return $this;
+ }
+
+ /**
+ * Scan theXML for use of readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ }
+
+ /**
+ * Can the current PHPExcel_Reader_IReader read the file?
+ *
+ * @param string $pFilename
+ * @return boolean
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function canRead($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ // Check if zip class exists
+// if (!class_exists($zipClass, false)) {
+// throw new PHPExcel_Reader_Exception($zipClass . " library is not enabled");
+// }
+
+ $mimeType = 'UNKNOWN';
+ // Load file
+ $zip = new $zipClass;
+ if ($zip->open($pFilename) === true) {
+ // check if it is an OOXML archive
+ $stat = $zip->statName('mimetype');
+ if ($stat && ($stat['size'] <= 255)) {
+ $mimeType = $zip->getFromName($stat['name']);
+ } elseif ($stat = $zip->statName('META-INF/manifest.xml')) {
+ $xml = simplexml_load_string($this->securityScan($zip->getFromName('META-INF/manifest.xml')), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespacesContent = $xml->getNamespaces(true);
+ if (isset($namespacesContent['manifest'])) {
+ $manifest = $xml->children($namespacesContent['manifest']);
+ foreach ($manifest as $manifestDataSet) {
+ $manifestAttributes = $manifestDataSet->attributes($namespacesContent['manifest']);
+ if ($manifestAttributes->{'full-path'} == '/') {
+ $mimeType = (string) $manifestAttributes->{'media-type'};
+ break;
+ }
+ }
+ }
+ }
+
+ $zip->close();
+
+ return ($mimeType === 'application/vnd.oasis.opendocument.spreadsheet');
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetNames($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ $zip = new $zipClass;
+ if (!$zip->open($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! Error opening file.");
+ }
+
+ $worksheetNames = array();
+
+ $xml = new XMLReader();
+ $res = $xml->xml($this->securityScanFile('zip://'.realpath($pFilename).'#content.xml'), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+ $xml->setParserProperty(2, true);
+
+ // Step into the first level of content of the XML
+ $xml->read();
+ while ($xml->read()) {
+ // Quickly jump through to the office:body node
+ while ($xml->name !== 'office:body') {
+ if ($xml->isEmptyElement) {
+ $xml->read();
+ } else {
+ $xml->next();
+ }
+ }
+ // Now read each node until we find our first table:table node
+ while ($xml->read()) {
+ if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
+ // Loop through each table:table node reading the table:name attribute for each worksheet name
+ do {
+ $worksheetNames[] = $xml->getAttribute('table:name');
+ $xml->next();
+ } while ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT);
+ }
+ }
+ }
+
+ return $worksheetNames;
+ }
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $worksheetInfo = array();
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ $zip = new $zipClass;
+ if (!$zip->open($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! Error opening file.");
+ }
+
+ $xml = new XMLReader();
+ $res = $xml->xml($this->securityScanFile('zip://'.realpath($pFilename).'#content.xml'), null, PHPExcel_Settings::getLibXmlLoaderOptions());
+ $xml->setParserProperty(2, true);
+
+ // Step into the first level of content of the XML
+ $xml->read();
+ while ($xml->read()) {
+ // Quickly jump through to the office:body node
+ while ($xml->name !== 'office:body') {
+ if ($xml->isEmptyElement) {
+ $xml->read();
+ } else {
+ $xml->next();
+ }
+ }
+ // Now read each node until we find our first table:table node
+ while ($xml->read()) {
+ if ($xml->name == 'table:table' && $xml->nodeType == XMLReader::ELEMENT) {
+ $worksheetNames[] = $xml->getAttribute('table:name');
+
+ $tmpInfo = array(
+ 'worksheetName' => $xml->getAttribute('table:name'),
+ 'lastColumnLetter' => 'A',
+ 'lastColumnIndex' => 0,
+ 'totalRows' => 0,
+ 'totalColumns' => 0,
+ );
+
+ // Loop through each child node of the table:table element reading
+ $currCells = 0;
+ do {
+ $xml->read();
+ if ($xml->name == 'table:table-row' && $xml->nodeType == XMLReader::ELEMENT) {
+ $rowspan = $xml->getAttribute('table:number-rows-repeated');
+ $rowspan = empty($rowspan) ? 1 : $rowspan;
+ $tmpInfo['totalRows'] += $rowspan;
+ $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
+ $currCells = 0;
+ // Step into the row
+ $xml->read();
+ do {
+ if ($xml->name == 'table:table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
+ if (!$xml->isEmptyElement) {
+ $currCells++;
+ $xml->next();
+ } else {
+ $xml->read();
+ }
+ } elseif ($xml->name == 'table:covered-table-cell' && $xml->nodeType == XMLReader::ELEMENT) {
+ $mergeSize = $xml->getAttribute('table:number-columns-repeated');
+ $currCells += $mergeSize;
+ $xml->read();
+ }
+ } while ($xml->name != 'table:table-row');
+ }
+ } while ($xml->name != 'table:table');
+
+ $tmpInfo['totalColumns'] = max($tmpInfo['totalColumns'], $currCells);
+ $tmpInfo['lastColumnIndex'] = $tmpInfo['totalColumns'] - 1;
+ $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+ $worksheetInfo[] = $tmpInfo;
+ }
+ }
+
+// foreach ($workbookData->table as $worksheetDataSet) {
+// $worksheetData = $worksheetDataSet->children($namespacesContent['table']);
+// $worksheetDataAttributes = $worksheetDataSet->attributes($namespacesContent['table']);
+//
+// $rowIndex = 0;
+// foreach ($worksheetData as $key => $rowData) {
+// switch ($key) {
+// case 'table-row' :
+// $rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
+// $rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ?
+// $rowDataTableAttributes['number-rows-repeated'] : 1;
+// $columnIndex = 0;
+//
+// foreach ($rowData as $key => $cellData) {
+// $cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
+// $colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ?
+// $cellDataTableAttributes['number-columns-repeated'] : 1;
+// $cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
+// if (isset($cellDataOfficeAttributes['value-type'])) {
+// $tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex + $colRepeats - 1);
+// $tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex + $rowRepeats);
+// }
+// $columnIndex += $colRepeats;
+// }
+// $rowIndex += $rowRepeats;
+// break;
+// }
+// }
+//
+// $tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+// $tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+//
+// }
+// }
+ }
+
+ return $worksheetInfo;
+ }
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Create new PHPExcel
+ $objPHPExcel = new PHPExcel();
+
+ // Load into this instance
+ return $this->loadIntoExisting($pFilename, $objPHPExcel);
+ }
+
+ private static function identifyFixedStyleValue($styleList, &$styleAttributeValue)
+ {
+ $styleAttributeValue = strtolower($styleAttributeValue);
+ foreach ($styleList as $style) {
+ if ($styleAttributeValue == strtolower($style)) {
+ $styleAttributeValue = $style;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Loads PHPExcel from file into PHPExcel instance
+ *
+ * @param string $pFilename
+ * @param PHPExcel $objPHPExcel
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+ {
+ // Check if file exists
+ if (!file_exists($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+ }
+
+ $timezoneObj = new DateTimeZone('Europe/London');
+ $GMT = new DateTimeZone('UTC');
+
+ $zipClass = PHPExcel_Settings::getZipClass();
+
+ $zip = new $zipClass;
+ if (!$zip->open($pFilename)) {
+ throw new PHPExcel_Reader_Exception("Could not open " . $pFilename . " for reading! Error opening file.");
+ }
+
+// echo 'Meta Information ';
+ $xml = simplexml_load_string($this->securityScan($zip->getFromName("meta.xml")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespacesMeta = $xml->getNamespaces(true);
+// echo '';
+// print_r($namespacesMeta);
+// echo ' ';
+
+ $docProps = $objPHPExcel->getProperties();
+ $officeProperty = $xml->children($namespacesMeta['office']);
+ foreach ($officeProperty as $officePropertyData) {
+ $officePropertyDC = array();
+ if (isset($namespacesMeta['dc'])) {
+ $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']);
+ }
+ foreach ($officePropertyDC as $propertyName => $propertyValue) {
+ $propertyValue = (string) $propertyValue;
+ switch ($propertyName) {
+ case 'title':
+ $docProps->setTitle($propertyValue);
+ break;
+ case 'subject':
+ $docProps->setSubject($propertyValue);
+ break;
+ case 'creator':
+ $docProps->setCreator($propertyValue);
+ $docProps->setLastModifiedBy($propertyValue);
+ break;
+ case 'date':
+ $creationDate = strtotime($propertyValue);
+ $docProps->setCreated($creationDate);
+ $docProps->setModified($creationDate);
+ break;
+ case 'description':
+ $docProps->setDescription($propertyValue);
+ break;
+ }
+ }
+ $officePropertyMeta = array();
+ if (isset($namespacesMeta['dc'])) {
+ $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']);
+ }
+ foreach ($officePropertyMeta as $propertyName => $propertyValue) {
+ $propertyValueAttributes = $propertyValue->attributes($namespacesMeta['meta']);
+ $propertyValue = (string) $propertyValue;
+ switch ($propertyName) {
+ case 'initial-creator':
+ $docProps->setCreator($propertyValue);
+ break;
+ case 'keyword':
+ $docProps->setKeywords($propertyValue);
+ break;
+ case 'creation-date':
+ $creationDate = strtotime($propertyValue);
+ $docProps->setCreated($creationDate);
+ break;
+ case 'user-defined':
+ $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING;
+ foreach ($propertyValueAttributes as $key => $value) {
+ if ($key == 'name') {
+ $propertyValueName = (string) $value;
+ } elseif ($key == 'value-type') {
+ switch ($value) {
+ case 'date':
+ $propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue, 'date');
+ $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_DATE;
+ break;
+ case 'boolean':
+ $propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue, 'bool');
+ $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_BOOLEAN;
+ break;
+ case 'float':
+ $propertyValue = PHPExcel_DocumentProperties::convertProperty($propertyValue, 'r4');
+ $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_FLOAT;
+ break;
+ default:
+ $propertyValueType = PHPExcel_DocumentProperties::PROPERTY_TYPE_STRING;
+ }
+ }
+ }
+ $docProps->setCustomProperty($propertyValueName, $propertyValue, $propertyValueType);
+ break;
+ }
+ }
+ }
+
+
+// echo 'Workbook Content ';
+ $xml = simplexml_load_string($this->securityScan($zip->getFromName("content.xml")), 'SimpleXMLElement', PHPExcel_Settings::getLibXmlLoaderOptions());
+ $namespacesContent = $xml->getNamespaces(true);
+// echo '';
+// print_r($namespacesContent);
+// echo ' ';
+
+ $workbook = $xml->children($namespacesContent['office']);
+ foreach ($workbook->body->spreadsheet as $workbookData) {
+ $workbookData = $workbookData->children($namespacesContent['table']);
+ $worksheetID = 0;
+ foreach ($workbookData->table as $worksheetDataSet) {
+ $worksheetData = $worksheetDataSet->children($namespacesContent['table']);
+// print_r($worksheetData);
+// echo ' ';
+ $worksheetDataAttributes = $worksheetDataSet->attributes($namespacesContent['table']);
+// print_r($worksheetDataAttributes);
+// echo ' ';
+ if ((isset($this->loadSheetsOnly)) && (isset($worksheetDataAttributes['name'])) &&
+ (!in_array($worksheetDataAttributes['name'], $this->loadSheetsOnly))) {
+ continue;
+ }
+
+// echo 'Worksheet '.$worksheetDataAttributes['name'].' ';
+ // Create new Worksheet
+ $objPHPExcel->createSheet();
+ $objPHPExcel->setActiveSheetIndex($worksheetID);
+ if (isset($worksheetDataAttributes['name'])) {
+ $worksheetName = (string) $worksheetDataAttributes['name'];
+ // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
+ // formula cells... during the load, all formulae should be correct, and we're simply
+ // bringing the worksheet name in line with the formula, not the reverse
+ $objPHPExcel->getActiveSheet()->setTitle($worksheetName, false);
+ }
+
+ $rowID = 1;
+ foreach ($worksheetData as $key => $rowData) {
+// echo ''.$key.' ';
+ switch ($key) {
+ case 'table-header-rows':
+ foreach ($rowData as $key => $cellData) {
+ $rowData = $cellData;
+ break;
+ }
+ case 'table-row':
+ $rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
+ $rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ? $rowDataTableAttributes['number-rows-repeated'] : 1;
+ $columnID = 'A';
+ foreach ($rowData as $key => $cellData) {
+ if ($this->getReadFilter() !== null) {
+ if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
+ continue;
+ }
+ }
+
+// echo ''.$columnID.$rowID.' ';
+ $cellDataText = (isset($namespacesContent['text'])) ? $cellData->children($namespacesContent['text']) : '';
+ $cellDataOffice = $cellData->children($namespacesContent['office']);
+ $cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
+ $cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
+
+// echo 'Office Attributes: ';
+// print_r($cellDataOfficeAttributes);
+// echo ' Table Attributes: ';
+// print_r($cellDataTableAttributes);
+// echo ' Cell Data Text';
+// print_r($cellDataText);
+// echo ' ';
+//
+ $type = $formatting = $hyperlink = null;
+ $hasCalculatedValue = false;
+ $cellDataFormula = '';
+ if (isset($cellDataTableAttributes['formula'])) {
+ $cellDataFormula = $cellDataTableAttributes['formula'];
+ $hasCalculatedValue = true;
+ }
+
+ if (isset($cellDataOffice->annotation)) {
+// echo 'Cell has comment ';
+ $annotationText = $cellDataOffice->annotation->children($namespacesContent['text']);
+ $textArray = array();
+ foreach ($annotationText as $t) {
+ if (isset($t->span)) {
+ foreach ($t->span as $text) {
+ $textArray[] = (string)$text;
+ }
+ } else {
+ $textArray[] = (string) $t;
+ }
+ }
+ $text = implode("\n", $textArray);
+// echo $text, ' ';
+ $objPHPExcel->getActiveSheet()->getComment($columnID.$rowID)->setText($this->parseRichText($text));
+// ->setAuthor( $author )
+ }
+
+ if (isset($cellDataText->p)) {
+ // Consolidate if there are multiple p records (maybe with spans as well)
+ $dataArray = array();
+ // Text can have multiple text:p and within those, multiple text:span.
+ // text:p newlines, but text:span does not.
+ // Also, here we assume there is no text data is span fields are specified, since
+ // we have no way of knowing proper positioning anyway.
+ foreach ($cellDataText->p as $pData) {
+ if (isset($pData->span)) {
+ // span sections do not newline, so we just create one large string here
+ $spanSection = "";
+ foreach ($pData->span as $spanData) {
+ $spanSection .= $spanData;
+ }
+ array_push($dataArray, $spanSection);
+ } else {
+ array_push($dataArray, $pData);
+ }
+ }
+ $allCellDataText = implode($dataArray, "\n");
+
+// echo 'Value Type is '.$cellDataOfficeAttributes['value-type'].' ';
+ switch ($cellDataOfficeAttributes['value-type']) {
+ case 'string':
+ $type = PHPExcel_Cell_DataType::TYPE_STRING;
+ $dataValue = $allCellDataText;
+ if (isset($dataValue->a)) {
+ $dataValue = $dataValue->a;
+ $cellXLinkAttributes = $dataValue->attributes($namespacesContent['xlink']);
+ $hyperlink = $cellXLinkAttributes['href'];
+ }
+ break;
+ case 'boolean':
+ $type = PHPExcel_Cell_DataType::TYPE_BOOL;
+ $dataValue = ($allCellDataText == 'TRUE') ? true : false;
+ break;
+ case 'percentage':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $dataValue = (float) $cellDataOfficeAttributes['value'];
+ if (floor($dataValue) == $dataValue) {
+ $dataValue = (integer) $dataValue;
+ }
+ $formatting = PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00;
+ break;
+ case 'currency':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $dataValue = (float) $cellDataOfficeAttributes['value'];
+ if (floor($dataValue) == $dataValue) {
+ $dataValue = (integer) $dataValue;
+ }
+ $formatting = PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE;
+ break;
+ case 'float':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $dataValue = (float) $cellDataOfficeAttributes['value'];
+ if (floor($dataValue) == $dataValue) {
+ if ($dataValue == (integer) $dataValue) {
+ $dataValue = (integer) $dataValue;
+ } else {
+ $dataValue = (float) $dataValue;
+ }
+ }
+ break;
+ case 'date':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $dateObj = new DateTime($cellDataOfficeAttributes['date-value'], $GMT);
+ $dateObj->setTimeZone($timezoneObj);
+ list($year, $month, $day, $hour, $minute, $second) = explode(' ', $dateObj->format('Y m d H i s'));
+ $dataValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day, $hour, $minute, $second);
+ if ($dataValue != floor($dataValue)) {
+ $formatting = PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15.' '.PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4;
+ } else {
+ $formatting = PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15;
+ }
+ break;
+ case 'time':
+ $type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+ $dataValue = PHPExcel_Shared_Date::PHPToExcel(strtotime('01-01-1970 '.implode(':', sscanf($cellDataOfficeAttributes['time-value'], 'PT%dH%dM%dS'))));
+ $formatting = PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4;
+ break;
+ }
+// echo 'Data value is '.$dataValue.' ';
+// if ($hyperlink !== null) {
+// echo 'Hyperlink is '.$hyperlink.' ';
+// }
+ } else {
+ $type = PHPExcel_Cell_DataType::TYPE_NULL;
+ $dataValue = null;
+ }
+
+ if ($hasCalculatedValue) {
+ $type = PHPExcel_Cell_DataType::TYPE_FORMULA;
+// echo 'Formula: ', $cellDataFormula, PHP_EOL;
+ $cellDataFormula = substr($cellDataFormula, strpos($cellDataFormula, ':=')+1);
+ $temp = explode('"', $cellDataFormula);
+ $tKey = false;
+ foreach ($temp as &$value) {
+ // Only replace in alternate array entries (i.e. non-quoted blocks)
+ if ($tKey = !$tKey) {
+ $value = preg_replace('/\[([^\.]+)\.([^\.]+):\.([^\.]+)\]/Ui', '$1!$2:$3', $value); // Cell range reference in another sheet
+ $value = preg_replace('/\[([^\.]+)\.([^\.]+)\]/Ui', '$1!$2', $value); // Cell reference in another sheet
+ $value = preg_replace('/\[\.([^\.]+):\.([^\.]+)\]/Ui', '$1:$2', $value); // Cell range reference
+ $value = preg_replace('/\[\.([^\.]+)\]/Ui', '$1', $value); // Simple cell reference
+ $value = PHPExcel_Calculation::translateSeparator(';', ',', $value, $inBraces);
+ }
+ }
+ unset($value);
+ // Then rebuild the formula string
+ $cellDataFormula = implode('"', $temp);
+// echo 'Adjusted Formula: ', $cellDataFormula, PHP_EOL;
+ }
+
+ $colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ? $cellDataTableAttributes['number-columns-repeated'] : 1;
+ if ($type !== null) {
+ for ($i = 0; $i < $colRepeats; ++$i) {
+ if ($i > 0) {
+ ++$columnID;
+ }
+ if ($type !== PHPExcel_Cell_DataType::TYPE_NULL) {
+ for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) {
+ $rID = $rowID + $rowAdjust;
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $dataValue), $type);
+ if ($hasCalculatedValue) {
+// echo 'Forumla result is '.$dataValue.' ';
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setCalculatedValue($dataValue);
+ }
+ if ($formatting !== null) {
+ $objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode($formatting);
+ } else {
+ $objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_GENERAL);
+ }
+ if ($hyperlink !== null) {
+ $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->getHyperlink()->setUrl($hyperlink);
+ }
+ }
+ }
+ }
+ }
+
+ // Merged cells
+ if ((isset($cellDataTableAttributes['number-columns-spanned'])) || (isset($cellDataTableAttributes['number-rows-spanned']))) {
+ if (($type !== PHPExcel_Cell_DataType::TYPE_NULL) || (!$this->readDataOnly)) {
+ $columnTo = $columnID;
+ if (isset($cellDataTableAttributes['number-columns-spanned'])) {
+ $columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-spanned'] -2);
+ }
+ $rowTo = $rowID;
+ if (isset($cellDataTableAttributes['number-rows-spanned'])) {
+ $rowTo = $rowTo + $cellDataTableAttributes['number-rows-spanned'] - 1;
+ }
+ $cellRange = $columnID.$rowID.':'.$columnTo.$rowTo;
+ $objPHPExcel->getActiveSheet()->mergeCells($cellRange);
+ }
+ }
+
+ ++$columnID;
+ }
+ $rowID += $rowRepeats;
+ break;
+ }
+ }
+ ++$worksheetID;
+ }
+ }
+
+ // Return
+ return $objPHPExcel;
+ }
+
+ private function parseRichText($is = '')
+ {
+ $value = new PHPExcel_RichText();
+
+ $value->createText($is);
+
+ return $value;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Reader/SYLK.php b/extend/PHPExcel/PHPExcel/Reader/SYLK.php
new file mode 100755
index 0000000..eb7ef1a
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Reader/SYLK.php
@@ -0,0 +1,478 @@
+readFilter = new PHPExcel_Reader_DefaultReadFilter();
+ }
+
+ /**
+ * Validate that the current file is a SYLK file
+ *
+ * @return boolean
+ */
+ protected function isValidFormat()
+ {
+ // Read sample data (first 2 KB will do)
+ $data = fread($this->fileHandle, 2048);
+
+ // Count delimiters in file
+ $delimiterCount = substr_count($data, ';');
+ if ($delimiterCount < 1) {
+ return false;
+ }
+
+ // Analyze first line looking for ID; signature
+ $lines = explode("\n", $data);
+ if (substr($lines[0], 0, 4) != 'ID;P') {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Set input encoding
+ *
+ * @param string $pValue Input encoding
+ */
+ public function setInputEncoding($pValue = 'ANSI')
+ {
+ $this->inputEncoding = $pValue;
+ return $this;
+ }
+
+ /**
+ * Get input encoding
+ *
+ * @return string
+ */
+ public function getInputEncoding()
+ {
+ return $this->inputEncoding;
+ }
+
+ /**
+ * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+ *
+ * @param string $pFilename
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function listWorksheetInfo($pFilename)
+ {
+ // Open file
+ $this->openFile($pFilename);
+ if (!$this->isValidFormat()) {
+ fclose($this->fileHandle);
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+ }
+ $fileHandle = $this->fileHandle;
+ rewind($fileHandle);
+
+ $worksheetInfo = array();
+ $worksheetInfo[0]['worksheetName'] = 'Worksheet';
+ $worksheetInfo[0]['lastColumnLetter'] = 'A';
+ $worksheetInfo[0]['lastColumnIndex'] = 0;
+ $worksheetInfo[0]['totalRows'] = 0;
+ $worksheetInfo[0]['totalColumns'] = 0;
+
+ // Loop through file
+ $rowData = array();
+
+ // loop through one row (line) at a time in the file
+ $rowIndex = 0;
+ while (($rowData = fgets($fileHandle)) !== false) {
+ $columnIndex = 0;
+
+ // convert SYLK encoded $rowData to UTF-8
+ $rowData = PHPExcel_Shared_String::SYLKtoUTF8($rowData);
+
+ // explode each row at semicolons while taking into account that literal semicolon (;)
+ // is escaped like this (;;)
+ $rowData = explode("\t", str_replace('¤', ';', str_replace(';', "\t", str_replace(';;', '¤', rtrim($rowData)))));
+
+ $dataType = array_shift($rowData);
+ if ($dataType == 'C') {
+ // Read cell value data
+ foreach ($rowData as $rowDatum) {
+ switch ($rowDatum{0}) {
+ case 'C':
+ case 'X':
+ $columnIndex = substr($rowDatum, 1) - 1;
+ break;
+ case 'R':
+ case 'Y':
+ $rowIndex = substr($rowDatum, 1);
+ break;
+ }
+
+ $worksheetInfo[0]['totalRows'] = max($worksheetInfo[0]['totalRows'], $rowIndex);
+ $worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], $columnIndex);
+ }
+ }
+ }
+
+ $worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
+ $worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
+
+ // Close file
+ fclose($fileHandle);
+
+ return $worksheetInfo;
+ }
+
+ /**
+ * Loads PHPExcel from file
+ *
+ * @param string $pFilename
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function load($pFilename)
+ {
+ // Create new PHPExcel
+ $objPHPExcel = new PHPExcel();
+
+ // Load into this instance
+ return $this->loadIntoExisting($pFilename, $objPHPExcel);
+ }
+
+ /**
+ * Loads PHPExcel from file into PHPExcel instance
+ *
+ * @param string $pFilename
+ * @param PHPExcel $objPHPExcel
+ * @return PHPExcel
+ * @throws PHPExcel_Reader_Exception
+ */
+ public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+ {
+ // Open file
+ $this->openFile($pFilename);
+ if (!$this->isValidFormat()) {
+ fclose($this->fileHandle);
+ throw new PHPExcel_Reader_Exception($pFilename . " is an Invalid Spreadsheet file.");
+ }
+ $fileHandle = $this->fileHandle;
+ rewind($fileHandle);
+
+ // Create new PHPExcel
+ while ($objPHPExcel->getSheetCount() <= $this->sheetIndex) {
+ $objPHPExcel->createSheet();
+ }
+ $objPHPExcel->setActiveSheetIndex($this->sheetIndex);
+
+ $fromFormats = array('\-', '\ ');
+ $toFormats = array('-', ' ');
+
+ // Loop through file
+ $rowData = array();
+ $column = $row = '';
+
+ // loop through one row (line) at a time in the file
+ while (($rowData = fgets($fileHandle)) !== false) {
+ // convert SYLK encoded $rowData to UTF-8
+ $rowData = PHPExcel_Shared_String::SYLKtoUTF8($rowData);
+
+ // explode each row at semicolons while taking into account that literal semicolon (;)
+ // is escaped like this (;;)
+ $rowData = explode("\t", str_replace('¤', ';', str_replace(';', "\t", str_replace(';;', '¤', rtrim($rowData)))));
+
+ $dataType = array_shift($rowData);
+ // Read shared styles
+ if ($dataType == 'P') {
+ $formatArray = array();
+ foreach ($rowData as $rowDatum) {
+ switch ($rowDatum{0}) {
+ case 'P':
+ $formatArray['numberformat']['code'] = str_replace($fromFormats, $toFormats, substr($rowDatum, 1));
+ break;
+ case 'E':
+ case 'F':
+ $formatArray['font']['name'] = substr($rowDatum, 1);
+ break;
+ case 'L':
+ $formatArray['font']['size'] = substr($rowDatum, 1);
+ break;
+ case 'S':
+ $styleSettings = substr($rowDatum, 1);
+ for ($i=0; $iformats['P'.$this->format++] = $formatArray;
+ // Read cell value data
+ } elseif ($dataType == 'C') {
+ $hasCalculatedValue = false;
+ $cellData = $cellDataFormula = '';
+ foreach ($rowData as $rowDatum) {
+ switch ($rowDatum{0}) {
+ case 'C':
+ case 'X':
+ $column = substr($rowDatum, 1);
+ break;
+ case 'R':
+ case 'Y':
+ $row = substr($rowDatum, 1);
+ break;
+ case 'K':
+ $cellData = substr($rowDatum, 1);
+ break;
+ case 'E':
+ $cellDataFormula = '='.substr($rowDatum, 1);
+ // Convert R1C1 style references to A1 style references (but only when not quoted)
+ $temp = explode('"', $cellDataFormula);
+ $key = false;
+ foreach ($temp as &$value) {
+ // Only count/replace in alternate array entries
+ if ($key = !$key) {
+ preg_match_all('/(R(\[?-?\d*\]?))(C(\[?-?\d*\]?))/', $value, $cellReferences, PREG_SET_ORDER+PREG_OFFSET_CAPTURE);
+ // Reverse the matches array, otherwise all our offsets will become incorrect if we modify our way
+ // through the formula from left to right. Reversing means that we work right to left.through
+ // the formula
+ $cellReferences = array_reverse($cellReferences);
+ // Loop through each R1C1 style reference in turn, converting it to its A1 style equivalent,
+ // then modify the formula to use that new reference
+ foreach ($cellReferences as $cellReference) {
+ $rowReference = $cellReference[2][0];
+ // Empty R reference is the current row
+ if ($rowReference == '') {
+ $rowReference = $row;
+ }
+ // Bracketed R references are relative to the current row
+ if ($rowReference{0} == '[') {
+ $rowReference = $row + trim($rowReference, '[]');
+ }
+ $columnReference = $cellReference[4][0];
+ // Empty C reference is the current column
+ if ($columnReference == '') {
+ $columnReference = $column;
+ }
+ // Bracketed C references are relative to the current column
+ if ($columnReference{0} == '[') {
+ $columnReference = $column + trim($columnReference, '[]');
+ }
+ $A1CellReference = PHPExcel_Cell::stringFromColumnIndex($columnReference-1).$rowReference;
+
+ $value = substr_replace($value, $A1CellReference, $cellReference[0][1], strlen($cellReference[0][0]));
+ }
+ }
+ }
+ unset($value);
+ // Then rebuild the formula string
+ $cellDataFormula = implode('"', $temp);
+ $hasCalculatedValue = true;
+ break;
+ }
+ }
+ $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
+ $cellData = PHPExcel_Calculation::unwrapResult($cellData);
+
+ // Set cell value
+ $objPHPExcel->getActiveSheet()->getCell($columnLetter.$row)->setValue(($hasCalculatedValue) ? $cellDataFormula : $cellData);
+ if ($hasCalculatedValue) {
+ $cellData = PHPExcel_Calculation::unwrapResult($cellData);
+ $objPHPExcel->getActiveSheet()->getCell($columnLetter.$row)->setCalculatedValue($cellData);
+ }
+ // Read cell formatting
+ } elseif ($dataType == 'F') {
+ $formatStyle = $columnWidth = $styleSettings = '';
+ $styleData = array();
+ foreach ($rowData as $rowDatum) {
+ switch ($rowDatum{0}) {
+ case 'C':
+ case 'X':
+ $column = substr($rowDatum, 1);
+ break;
+ case 'R':
+ case 'Y':
+ $row = substr($rowDatum, 1);
+ break;
+ case 'P':
+ $formatStyle = $rowDatum;
+ break;
+ case 'W':
+ list($startCol, $endCol, $columnWidth) = explode(' ', substr($rowDatum, 1));
+ break;
+ case 'S':
+ $styleSettings = substr($rowDatum, 1);
+ for ($i=0; $i '') && ($column > '') && ($row > '')) {
+ $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
+ if (isset($this->formats[$formatStyle])) {
+ $objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($this->formats[$formatStyle]);
+ }
+ }
+ if ((!empty($styleData)) && ($column > '') && ($row > '')) {
+ $columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
+ $objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($styleData);
+ }
+ if ($columnWidth > '') {
+ if ($startCol == $endCol) {
+ $startCol = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
+ $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth);
+ } else {
+ $startCol = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
+ $endCol = PHPExcel_Cell::stringFromColumnIndex($endCol-1);
+ $objPHPExcel->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth);
+ do {
+ $objPHPExcel->getActiveSheet()->getColumnDimension(++$startCol)->setWidth($columnWidth);
+ } while ($startCol != $endCol);
+ }
+ }
+ } else {
+ foreach ($rowData as $rowDatum) {
+ switch ($rowDatum{0}) {
+ case 'C':
+ case 'X':
+ $column = substr($rowDatum, 1);
+ break;
+ case 'R':
+ case 'Y':
+ $row = substr($rowDatum, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ // Close file
+ fclose($fileHandle);
+
+ // Return
+ return $objPHPExcel;
+ }
+
+ /**
+ * Get sheet index
+ *
+ * @return int
+ */
+ public function getSheetIndex()
+ {
+ return $this->sheetIndex;
+ }
+
+ /**
+ * Set sheet index
+ *
+ * @param int $pValue Sheet index
+ * @return PHPExcel_Reader_SYLK
+ */
+ public function setSheetIndex($pValue = 0)
+ {
+ $this->sheetIndex = $pValue;
+ return $this;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/ReferenceHelper.php b/extend/PHPExcel/PHPExcel/ReferenceHelper.php
new file mode 100755
index 0000000..7d7de93
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/ReferenceHelper.php
@@ -0,0 +1,913 @@
+= ($beforeRow + $pNumRows)) &&
+ ($cellRow < $beforeRow)) {
+ return true;
+ } elseif ($pNumCols < 0 &&
+ ($cellColumnIndex >= ($beforeColumnIndex + $pNumCols)) &&
+ ($cellColumnIndex < $beforeColumnIndex)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Update page breaks when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustPageBreaks(PHPExcel_Worksheet $pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aBreaks = $pSheet->getBreaks();
+ ($pNumCols > 0 || $pNumRows > 0) ?
+ uksort($aBreaks, array('PHPExcel_ReferenceHelper','cellReverseSort')) :
+ uksort($aBreaks, array('PHPExcel_ReferenceHelper','cellSort'));
+
+ foreach ($aBreaks as $key => $value) {
+ if (self::cellAddressInDeleteRange($key, $beforeRow, $pNumRows, $beforeColumnIndex, $pNumCols)) {
+ // If we're deleting, then clear any defined breaks that are within the range
+ // of rows/columns that we're deleting
+ $pSheet->setBreak($key, PHPExcel_Worksheet::BREAK_NONE);
+ } else {
+ // Otherwise update any affected breaks by inserting a new break at the appropriate point
+ // and removing the old affected break
+ $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows);
+ if ($key != $newReference) {
+ $pSheet->setBreak($newReference, $value)
+ ->setBreak($key, PHPExcel_Worksheet::BREAK_NONE);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update cell comments when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustComments($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aComments = $pSheet->getComments();
+ $aNewComments = array(); // the new array of all comments
+
+ foreach ($aComments as $key => &$value) {
+ // Any comments inside a deleted range will be ignored
+ if (!self::cellAddressInDeleteRange($key, $beforeRow, $pNumRows, $beforeColumnIndex, $pNumCols)) {
+ // Otherwise build a new array of comments indexed by the adjusted cell reference
+ $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows);
+ $aNewComments[$newReference] = $value;
+ }
+ }
+ // Replace the comments array with the new set of comments
+ $pSheet->setComments($aNewComments);
+ }
+
+ /**
+ * Update hyperlinks when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustHyperlinks($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aHyperlinkCollection = $pSheet->getHyperlinkCollection();
+ ($pNumCols > 0 || $pNumRows > 0) ? uksort($aHyperlinkCollection, array('PHPExcel_ReferenceHelper','cellReverseSort')) : uksort($aHyperlinkCollection, array('PHPExcel_ReferenceHelper','cellSort'));
+
+ foreach ($aHyperlinkCollection as $key => $value) {
+ $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows);
+ if ($key != $newReference) {
+ $pSheet->setHyperlink($newReference, $value);
+ $pSheet->setHyperlink($key, null);
+ }
+ }
+ }
+
+ /**
+ * Update data validations when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustDataValidations($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aDataValidationCollection = $pSheet->getDataValidationCollection();
+ ($pNumCols > 0 || $pNumRows > 0) ? uksort($aDataValidationCollection, array('PHPExcel_ReferenceHelper','cellReverseSort')) : uksort($aDataValidationCollection, array('PHPExcel_ReferenceHelper','cellSort'));
+
+ foreach ($aDataValidationCollection as $key => $value) {
+ $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows);
+ if ($key != $newReference) {
+ $pSheet->setDataValidation($newReference, $value);
+ $pSheet->setDataValidation($key, null);
+ }
+ }
+ }
+
+ /**
+ * Update merged cells when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustMergeCells($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aMergeCells = $pSheet->getMergeCells();
+ $aNewMergeCells = array(); // the new array of all merge cells
+ foreach ($aMergeCells as $key => &$value) {
+ $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows);
+ $aNewMergeCells[$newReference] = $newReference;
+ }
+ $pSheet->setMergeCells($aNewMergeCells); // replace the merge cells array
+ }
+
+ /**
+ * Update protected cells when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustProtectedCells($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aProtectedCells = $pSheet->getProtectedCells();
+ ($pNumCols > 0 || $pNumRows > 0) ?
+ uksort($aProtectedCells, array('PHPExcel_ReferenceHelper','cellReverseSort')) :
+ uksort($aProtectedCells, array('PHPExcel_ReferenceHelper','cellSort'));
+ foreach ($aProtectedCells as $key => $value) {
+ $newReference = $this->updateCellReference($key, $pBefore, $pNumCols, $pNumRows);
+ if ($key != $newReference) {
+ $pSheet->protectCells($newReference, $value, true);
+ $pSheet->unprotectCells($key);
+ }
+ }
+ }
+
+ /**
+ * Update column dimensions when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustColumnDimensions($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aColumnDimensions = array_reverse($pSheet->getColumnDimensions(), true);
+ if (!empty($aColumnDimensions)) {
+ foreach ($aColumnDimensions as $objColumnDimension) {
+ $newReference = $this->updateCellReference($objColumnDimension->getColumnIndex() . '1', $pBefore, $pNumCols, $pNumRows);
+ list($newReference) = PHPExcel_Cell::coordinateFromString($newReference);
+ if ($objColumnDimension->getColumnIndex() != $newReference) {
+ $objColumnDimension->setColumnIndex($newReference);
+ }
+ }
+ $pSheet->refreshColumnDimensions();
+ }
+ }
+
+ /**
+ * Update row dimensions when inserting/deleting rows/columns
+ *
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @param string $pBefore Insert/Delete before this cell address (e.g. 'A1')
+ * @param integer $beforeColumnIndex Index number of the column we're inserting/deleting before
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $beforeRow Number of the row we're inserting/deleting before
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ */
+ protected function adjustRowDimensions($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows)
+ {
+ $aRowDimensions = array_reverse($pSheet->getRowDimensions(), true);
+ if (!empty($aRowDimensions)) {
+ foreach ($aRowDimensions as $objRowDimension) {
+ $newReference = $this->updateCellReference('A' . $objRowDimension->getRowIndex(), $pBefore, $pNumCols, $pNumRows);
+ list(, $newReference) = PHPExcel_Cell::coordinateFromString($newReference);
+ if ($objRowDimension->getRowIndex() != $newReference) {
+ $objRowDimension->setRowIndex($newReference);
+ }
+ }
+ $pSheet->refreshRowDimensions();
+
+ $copyDimension = $pSheet->getRowDimension($beforeRow - 1);
+ for ($i = $beforeRow; $i <= $beforeRow - 1 + $pNumRows; ++$i) {
+ $newDimension = $pSheet->getRowDimension($i);
+ $newDimension->setRowHeight($copyDimension->getRowHeight());
+ $newDimension->setVisible($copyDimension->getVisible());
+ $newDimension->setOutlineLevel($copyDimension->getOutlineLevel());
+ $newDimension->setCollapsed($copyDimension->getCollapsed());
+ }
+ }
+ }
+
+ /**
+ * Insert a new column or row, updating all possible related data
+ *
+ * @param string $pBefore Insert before this cell address (e.g. 'A1')
+ * @param integer $pNumCols Number of columns to insert/delete (negative values indicate deletion)
+ * @param integer $pNumRows Number of rows to insert/delete (negative values indicate deletion)
+ * @param PHPExcel_Worksheet $pSheet The worksheet that we're editing
+ * @throws PHPExcel_Exception
+ */
+ public function insertNewBefore($pBefore = 'A1', $pNumCols = 0, $pNumRows = 0, PHPExcel_Worksheet $pSheet = null)
+ {
+ $remove = ($pNumCols < 0 || $pNumRows < 0);
+ $aCellCollection = $pSheet->getCellCollection();
+
+ // Get coordinates of $pBefore
+ $beforeColumn = 'A';
+ $beforeRow = 1;
+ list($beforeColumn, $beforeRow) = PHPExcel_Cell::coordinateFromString($pBefore);
+ $beforeColumnIndex = PHPExcel_Cell::columnIndexFromString($beforeColumn);
+
+ // Clear cells if we are removing columns or rows
+ $highestColumn = $pSheet->getHighestColumn();
+ $highestRow = $pSheet->getHighestRow();
+
+ // 1. Clear column strips if we are removing columns
+ if ($pNumCols < 0 && $beforeColumnIndex - 2 + $pNumCols > 0) {
+ for ($i = 1; $i <= $highestRow - 1; ++$i) {
+ for ($j = $beforeColumnIndex - 1 + $pNumCols; $j <= $beforeColumnIndex - 2; ++$j) {
+ $coordinate = PHPExcel_Cell::stringFromColumnIndex($j) . $i;
+ $pSheet->removeConditionalStyles($coordinate);
+ if ($pSheet->cellExists($coordinate)) {
+ $pSheet->getCell($coordinate)->setValueExplicit('', PHPExcel_Cell_DataType::TYPE_NULL);
+ $pSheet->getCell($coordinate)->setXfIndex(0);
+ }
+ }
+ }
+ }
+
+ // 2. Clear row strips if we are removing rows
+ if ($pNumRows < 0 && $beforeRow - 1 + $pNumRows > 0) {
+ for ($i = $beforeColumnIndex - 1; $i <= PHPExcel_Cell::columnIndexFromString($highestColumn) - 1; ++$i) {
+ for ($j = $beforeRow + $pNumRows; $j <= $beforeRow - 1; ++$j) {
+ $coordinate = PHPExcel_Cell::stringFromColumnIndex($i) . $j;
+ $pSheet->removeConditionalStyles($coordinate);
+ if ($pSheet->cellExists($coordinate)) {
+ $pSheet->getCell($coordinate)->setValueExplicit('', PHPExcel_Cell_DataType::TYPE_NULL);
+ $pSheet->getCell($coordinate)->setXfIndex(0);
+ }
+ }
+ }
+ }
+
+ // Loop through cells, bottom-up, and change cell coordinates
+ if ($remove) {
+ // It's faster to reverse and pop than to use unshift, especially with large cell collections
+ $aCellCollection = array_reverse($aCellCollection);
+ }
+ while ($cellID = array_pop($aCellCollection)) {
+ $cell = $pSheet->getCell($cellID);
+ $cellIndex = PHPExcel_Cell::columnIndexFromString($cell->getColumn());
+
+ if ($cellIndex-1 + $pNumCols < 0) {
+ continue;
+ }
+
+ // New coordinates
+ $newCoordinates = PHPExcel_Cell::stringFromColumnIndex($cellIndex-1 + $pNumCols) . ($cell->getRow() + $pNumRows);
+
+ // Should the cell be updated? Move value and cellXf index from one cell to another.
+ if (($cellIndex >= $beforeColumnIndex) && ($cell->getRow() >= $beforeRow)) {
+ // Update cell styles
+ $pSheet->getCell($newCoordinates)->setXfIndex($cell->getXfIndex());
+
+ // Insert this cell at its new location
+ if ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA) {
+ // Formula should be adjusted
+ $pSheet->getCell($newCoordinates)
+ ->setValue($this->updateFormulaReferences($cell->getValue(), $pBefore, $pNumCols, $pNumRows, $pSheet->getTitle()));
+ } else {
+ // Formula should not be adjusted
+ $pSheet->getCell($newCoordinates)->setValue($cell->getValue());
+ }
+
+ // Clear the original cell
+ $pSheet->getCellCacheController()->deleteCacheData($cellID);
+ } else {
+ /* We don't need to update styles for rows/columns before our insertion position,
+ but we do still need to adjust any formulae in those cells */
+ if ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA) {
+ // Formula should be adjusted
+ $cell->setValue($this->updateFormulaReferences($cell->getValue(), $pBefore, $pNumCols, $pNumRows, $pSheet->getTitle()));
+ }
+
+ }
+ }
+
+ // Duplicate styles for the newly inserted cells
+ $highestColumn = $pSheet->getHighestColumn();
+ $highestRow = $pSheet->getHighestRow();
+
+ if ($pNumCols > 0 && $beforeColumnIndex - 2 > 0) {
+ for ($i = $beforeRow; $i <= $highestRow - 1; ++$i) {
+ // Style
+ $coordinate = PHPExcel_Cell::stringFromColumnIndex($beforeColumnIndex - 2) . $i;
+ if ($pSheet->cellExists($coordinate)) {
+ $xfIndex = $pSheet->getCell($coordinate)->getXfIndex();
+ $conditionalStyles = $pSheet->conditionalStylesExists($coordinate) ?
+ $pSheet->getConditionalStyles($coordinate) : false;
+ for ($j = $beforeColumnIndex - 1; $j <= $beforeColumnIndex - 2 + $pNumCols; ++$j) {
+ $pSheet->getCellByColumnAndRow($j, $i)->setXfIndex($xfIndex);
+ if ($conditionalStyles) {
+ $cloned = array();
+ foreach ($conditionalStyles as $conditionalStyle) {
+ $cloned[] = clone $conditionalStyle;
+ }
+ $pSheet->setConditionalStyles(PHPExcel_Cell::stringFromColumnIndex($j) . $i, $cloned);
+ }
+ }
+ }
+
+ }
+ }
+
+ if ($pNumRows > 0 && $beforeRow - 1 > 0) {
+ for ($i = $beforeColumnIndex - 1; $i <= PHPExcel_Cell::columnIndexFromString($highestColumn) - 1; ++$i) {
+ // Style
+ $coordinate = PHPExcel_Cell::stringFromColumnIndex($i) . ($beforeRow - 1);
+ if ($pSheet->cellExists($coordinate)) {
+ $xfIndex = $pSheet->getCell($coordinate)->getXfIndex();
+ $conditionalStyles = $pSheet->conditionalStylesExists($coordinate) ?
+ $pSheet->getConditionalStyles($coordinate) : false;
+ for ($j = $beforeRow; $j <= $beforeRow - 1 + $pNumRows; ++$j) {
+ $pSheet->getCell(PHPExcel_Cell::stringFromColumnIndex($i) . $j)->setXfIndex($xfIndex);
+ if ($conditionalStyles) {
+ $cloned = array();
+ foreach ($conditionalStyles as $conditionalStyle) {
+ $cloned[] = clone $conditionalStyle;
+ }
+ $pSheet->setConditionalStyles(PHPExcel_Cell::stringFromColumnIndex($i) . $j, $cloned);
+ }
+ }
+ }
+ }
+ }
+
+ // Update worksheet: column dimensions
+ $this->adjustColumnDimensions($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: row dimensions
+ $this->adjustRowDimensions($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: page breaks
+ $this->adjustPageBreaks($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: comments
+ $this->adjustComments($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: hyperlinks
+ $this->adjustHyperlinks($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: data validations
+ $this->adjustDataValidations($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: merge cells
+ $this->adjustMergeCells($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: protected cells
+ $this->adjustProtectedCells($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows);
+
+ // Update worksheet: autofilter
+ $autoFilter = $pSheet->getAutoFilter();
+ $autoFilterRange = $autoFilter->getRange();
+ if (!empty($autoFilterRange)) {
+ if ($pNumCols != 0) {
+ $autoFilterColumns = array_keys($autoFilter->getColumns());
+ if (count($autoFilterColumns) > 0) {
+ sscanf($pBefore, '%[A-Z]%d', $column, $row);
+ $columnIndex = PHPExcel_Cell::columnIndexFromString($column);
+ list($rangeStart, $rangeEnd) = PHPExcel_Cell::rangeBoundaries($autoFilterRange);
+ if ($columnIndex <= $rangeEnd[0]) {
+ if ($pNumCols < 0) {
+ // If we're actually deleting any columns that fall within the autofilter range,
+ // then we delete any rules for those columns
+ $deleteColumn = $columnIndex + $pNumCols - 1;
+ $deleteCount = abs($pNumCols);
+ for ($i = 1; $i <= $deleteCount; ++$i) {
+ if (in_array(PHPExcel_Cell::stringFromColumnIndex($deleteColumn), $autoFilterColumns)) {
+ $autoFilter->clearColumn(PHPExcel_Cell::stringFromColumnIndex($deleteColumn));
+ }
+ ++$deleteColumn;
+ }
+ }
+ $startCol = ($columnIndex > $rangeStart[0]) ? $columnIndex : $rangeStart[0];
+
+ // Shuffle columns in autofilter range
+ if ($pNumCols > 0) {
+ // For insert, we shuffle from end to beginning to avoid overwriting
+ $startColID = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
+ $toColID = PHPExcel_Cell::stringFromColumnIndex($startCol+$pNumCols-1);
+ $endColID = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0]);
+
+ $startColRef = $startCol;
+ $endColRef = $rangeEnd[0];
+ $toColRef = $rangeEnd[0]+$pNumCols;
+
+ do {
+ $autoFilter->shiftColumn(PHPExcel_Cell::stringFromColumnIndex($endColRef-1), PHPExcel_Cell::stringFromColumnIndex($toColRef-1));
+ --$endColRef;
+ --$toColRef;
+ } while ($startColRef <= $endColRef);
+ } else {
+ // For delete, we shuffle from beginning to end to avoid overwriting
+ $startColID = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
+ $toColID = PHPExcel_Cell::stringFromColumnIndex($startCol+$pNumCols-1);
+ $endColID = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0]);
+ do {
+ $autoFilter->shiftColumn($startColID, $toColID);
+ ++$startColID;
+ ++$toColID;
+ } while ($startColID != $endColID);
+ }
+ }
+ }
+ }
+ $pSheet->setAutoFilter($this->updateCellReference($autoFilterRange, $pBefore, $pNumCols, $pNumRows));
+ }
+
+ // Update worksheet: freeze pane
+ if ($pSheet->getFreezePane() != '') {
+ $pSheet->freezePane($this->updateCellReference($pSheet->getFreezePane(), $pBefore, $pNumCols, $pNumRows));
+ }
+
+ // Page setup
+ if ($pSheet->getPageSetup()->isPrintAreaSet()) {
+ $pSheet->getPageSetup()->setPrintArea($this->updateCellReference($pSheet->getPageSetup()->getPrintArea(), $pBefore, $pNumCols, $pNumRows));
+ }
+
+ // Update worksheet: drawings
+ $aDrawings = $pSheet->getDrawingCollection();
+ foreach ($aDrawings as $objDrawing) {
+ $newReference = $this->updateCellReference($objDrawing->getCoordinates(), $pBefore, $pNumCols, $pNumRows);
+ if ($objDrawing->getCoordinates() != $newReference) {
+ $objDrawing->setCoordinates($newReference);
+ }
+ }
+
+ // Update workbook: named ranges
+ if (count($pSheet->getParent()->getNamedRanges()) > 0) {
+ foreach ($pSheet->getParent()->getNamedRanges() as $namedRange) {
+ if ($namedRange->getWorksheet()->getHashCode() == $pSheet->getHashCode()) {
+ $namedRange->setRange($this->updateCellReference($namedRange->getRange(), $pBefore, $pNumCols, $pNumRows));
+ }
+ }
+ }
+
+ // Garbage collect
+ $pSheet->garbageCollect();
+ }
+
+ /**
+ * Update references within formulas
+ *
+ * @param string $pFormula Formula to update
+ * @param int $pBefore Insert before this one
+ * @param int $pNumCols Number of columns to insert
+ * @param int $pNumRows Number of rows to insert
+ * @param string $sheetName Worksheet name/title
+ * @return string Updated formula
+ * @throws PHPExcel_Exception
+ */
+ public function updateFormulaReferences($pFormula = '', $pBefore = 'A1', $pNumCols = 0, $pNumRows = 0, $sheetName = '')
+ {
+ // Update cell references in the formula
+ $formulaBlocks = explode('"', $pFormula);
+ $i = false;
+ foreach ($formulaBlocks as &$formulaBlock) {
+ // Ignore blocks that were enclosed in quotes (alternating entries in the $formulaBlocks array after the explode)
+ if ($i = !$i) {
+ $adjustCount = 0;
+ $newCellTokens = $cellTokens = array();
+ // Search for row ranges (e.g. 'Sheet1'!3:5 or 3:5) with or without $ absolutes (e.g. $3:5)
+ $matchCount = preg_match_all('/'.self::REFHELPER_REGEXP_ROWRANGE.'/i', ' '.$formulaBlock.' ', $matches, PREG_SET_ORDER);
+ if ($matchCount > 0) {
+ foreach ($matches as $match) {
+ $fromString = ($match[2] > '') ? $match[2].'!' : '';
+ $fromString .= $match[3].':'.$match[4];
+ $modified3 = substr($this->updateCellReference('$A'.$match[3], $pBefore, $pNumCols, $pNumRows), 2);
+ $modified4 = substr($this->updateCellReference('$A'.$match[4], $pBefore, $pNumCols, $pNumRows), 2);
+
+ if ($match[3].':'.$match[4] !== $modified3.':'.$modified4) {
+ if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
+ $toString = ($match[2] > '') ? $match[2].'!' : '';
+ $toString .= $modified3.':'.$modified4;
+ // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
+ $column = 100000;
+ $row = 10000000 + trim($match[3], '$');
+ $cellIndex = $column.$row;
+
+ $newCellTokens[$cellIndex] = preg_quote($toString);
+ $cellTokens[$cellIndex] = '/(? 0) {
+ foreach ($matches as $match) {
+ $fromString = ($match[2] > '') ? $match[2].'!' : '';
+ $fromString .= $match[3].':'.$match[4];
+ $modified3 = substr($this->updateCellReference($match[3].'$1', $pBefore, $pNumCols, $pNumRows), 0, -2);
+ $modified4 = substr($this->updateCellReference($match[4].'$1', $pBefore, $pNumCols, $pNumRows), 0, -2);
+
+ if ($match[3].':'.$match[4] !== $modified3.':'.$modified4) {
+ if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
+ $toString = ($match[2] > '') ? $match[2].'!' : '';
+ $toString .= $modified3.':'.$modified4;
+ // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
+ $column = PHPExcel_Cell::columnIndexFromString(trim($match[3], '$')) + 100000;
+ $row = 10000000;
+ $cellIndex = $column.$row;
+
+ $newCellTokens[$cellIndex] = preg_quote($toString);
+ $cellTokens[$cellIndex] = '/(? 0) {
+ foreach ($matches as $match) {
+ $fromString = ($match[2] > '') ? $match[2].'!' : '';
+ $fromString .= $match[3].':'.$match[4];
+ $modified3 = $this->updateCellReference($match[3], $pBefore, $pNumCols, $pNumRows);
+ $modified4 = $this->updateCellReference($match[4], $pBefore, $pNumCols, $pNumRows);
+
+ if ($match[3].$match[4] !== $modified3.$modified4) {
+ if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
+ $toString = ($match[2] > '') ? $match[2].'!' : '';
+ $toString .= $modified3.':'.$modified4;
+ list($column, $row) = PHPExcel_Cell::coordinateFromString($match[3]);
+ // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
+ $column = PHPExcel_Cell::columnIndexFromString(trim($column, '$')) + 100000;
+ $row = trim($row, '$') + 10000000;
+ $cellIndex = $column.$row;
+
+ $newCellTokens[$cellIndex] = preg_quote($toString);
+ $cellTokens[$cellIndex] = '/(? 0) {
+ foreach ($matches as $match) {
+ $fromString = ($match[2] > '') ? $match[2].'!' : '';
+ $fromString .= $match[3];
+
+ $modified3 = $this->updateCellReference($match[3], $pBefore, $pNumCols, $pNumRows);
+ if ($match[3] !== $modified3) {
+ if (($match[2] == '') || (trim($match[2], "'") == $sheetName)) {
+ $toString = ($match[2] > '') ? $match[2].'!' : '';
+ $toString .= $modified3;
+ list($column, $row) = PHPExcel_Cell::coordinateFromString($match[3]);
+ // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more
+ $column = PHPExcel_Cell::columnIndexFromString(trim($column, '$')) + 100000;
+ $row = trim($row, '$') + 10000000;
+ $cellIndex = $row . $column;
+
+ $newCellTokens[$cellIndex] = preg_quote($toString);
+ $cellTokens[$cellIndex] = '/(? 0) {
+ if ($pNumCols > 0 || $pNumRows > 0) {
+ krsort($cellTokens);
+ krsort($newCellTokens);
+ } else {
+ ksort($cellTokens);
+ ksort($newCellTokens);
+ } // Update cell references in the formula
+ $formulaBlock = str_replace('\\', '', preg_replace($cellTokens, $newCellTokens, $formulaBlock));
+ }
+ }
+ }
+ unset($formulaBlock);
+
+ // Then rebuild the formula string
+ return implode('"', $formulaBlocks);
+ }
+
+ /**
+ * Update cell reference
+ *
+ * @param string $pCellRange Cell range
+ * @param int $pBefore Insert before this one
+ * @param int $pNumCols Number of columns to increment
+ * @param int $pNumRows Number of rows to increment
+ * @return string Updated cell range
+ * @throws PHPExcel_Exception
+ */
+ public function updateCellReference($pCellRange = 'A1', $pBefore = 'A1', $pNumCols = 0, $pNumRows = 0)
+ {
+ // Is it in another worksheet? Will not have to update anything.
+ if (strpos($pCellRange, "!") !== false) {
+ return $pCellRange;
+ // Is it a range or a single cell?
+ } elseif (strpos($pCellRange, ':') === false && strpos($pCellRange, ',') === false) {
+ // Single cell
+ return $this->updateSingleCellReference($pCellRange, $pBefore, $pNumCols, $pNumRows);
+ } elseif (strpos($pCellRange, ':') !== false || strpos($pCellRange, ',') !== false) {
+ // Range
+ return $this->updateCellRange($pCellRange, $pBefore, $pNumCols, $pNumRows);
+ } else {
+ // Return original
+ return $pCellRange;
+ }
+ }
+
+ /**
+ * Update named formulas (i.e. containing worksheet references / named ranges)
+ *
+ * @param PHPExcel $pPhpExcel Object to update
+ * @param string $oldName Old name (name to replace)
+ * @param string $newName New name
+ */
+ public function updateNamedFormulas(PHPExcel $pPhpExcel, $oldName = '', $newName = '')
+ {
+ if ($oldName == '') {
+ return;
+ }
+
+ foreach ($pPhpExcel->getWorksheetIterator() as $sheet) {
+ foreach ($sheet->getCellCollection(false) as $cellID) {
+ $cell = $sheet->getCell($cellID);
+ if (($cell !== null) && ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA)) {
+ $formula = $cell->getValue();
+ if (strpos($formula, $oldName) !== false) {
+ $formula = str_replace("'" . $oldName . "'!", "'" . $newName . "'!", $formula);
+ $formula = str_replace($oldName . "!", $newName . "!", $formula);
+ $cell->setValueExplicit($formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Update cell range
+ *
+ * @param string $pCellRange Cell range (e.g. 'B2:D4', 'B:C' or '2:3')
+ * @param int $pBefore Insert before this one
+ * @param int $pNumCols Number of columns to increment
+ * @param int $pNumRows Number of rows to increment
+ * @return string Updated cell range
+ * @throws PHPExcel_Exception
+ */
+ private function updateCellRange($pCellRange = 'A1:A1', $pBefore = 'A1', $pNumCols = 0, $pNumRows = 0)
+ {
+ if (strpos($pCellRange, ':') !== false || strpos($pCellRange, ',') !== false) {
+ // Update range
+ $range = PHPExcel_Cell::splitRange($pCellRange);
+ $ic = count($range);
+ for ($i = 0; $i < $ic; ++$i) {
+ $jc = count($range[$i]);
+ for ($j = 0; $j < $jc; ++$j) {
+ if (ctype_alpha($range[$i][$j])) {
+ $r = PHPExcel_Cell::coordinateFromString($this->updateSingleCellReference($range[$i][$j].'1', $pBefore, $pNumCols, $pNumRows));
+ $range[$i][$j] = $r[0];
+ } elseif (ctype_digit($range[$i][$j])) {
+ $r = PHPExcel_Cell::coordinateFromString($this->updateSingleCellReference('A'.$range[$i][$j], $pBefore, $pNumCols, $pNumRows));
+ $range[$i][$j] = $r[1];
+ } else {
+ $range[$i][$j] = $this->updateSingleCellReference($range[$i][$j], $pBefore, $pNumCols, $pNumRows);
+ }
+ }
+ }
+
+ // Recreate range string
+ return PHPExcel_Cell::buildRange($range);
+ } else {
+ throw new PHPExcel_Exception("Only cell ranges may be passed to this method.");
+ }
+ }
+
+ /**
+ * Update single cell reference
+ *
+ * @param string $pCellReference Single cell reference
+ * @param int $pBefore Insert before this one
+ * @param int $pNumCols Number of columns to increment
+ * @param int $pNumRows Number of rows to increment
+ * @return string Updated cell reference
+ * @throws PHPExcel_Exception
+ */
+ private function updateSingleCellReference($pCellReference = 'A1', $pBefore = 'A1', $pNumCols = 0, $pNumRows = 0)
+ {
+ if (strpos($pCellReference, ':') === false && strpos($pCellReference, ',') === false) {
+ // Get coordinates of $pBefore
+ list($beforeColumn, $beforeRow) = PHPExcel_Cell::coordinateFromString($pBefore);
+
+ // Get coordinates of $pCellReference
+ list($newColumn, $newRow) = PHPExcel_Cell::coordinateFromString($pCellReference);
+
+ // Verify which parts should be updated
+ $updateColumn = (($newColumn{0} != '$') && ($beforeColumn{0} != '$') && (PHPExcel_Cell::columnIndexFromString($newColumn) >= PHPExcel_Cell::columnIndexFromString($beforeColumn)));
+ $updateRow = (($newRow{0} != '$') && ($beforeRow{0} != '$') && $newRow >= $beforeRow);
+
+ // Create new column reference
+ if ($updateColumn) {
+ $newColumn = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($newColumn) - 1 + $pNumCols);
+ }
+
+ // Create new row reference
+ if ($updateRow) {
+ $newRow = $newRow + $pNumRows;
+ }
+
+ // Return new reference
+ return $newColumn . $newRow;
+ } else {
+ throw new PHPExcel_Exception("Only single cell references may be passed to this method.");
+ }
+ }
+
+ /**
+ * __clone implementation. Cloning should not be allowed in a Singleton!
+ *
+ * @throws PHPExcel_Exception
+ */
+ final public function __clone()
+ {
+ throw new PHPExcel_Exception("Cloning a Singleton is not allowed!");
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/RichText.php b/extend/PHPExcel/PHPExcel/RichText.php
new file mode 100755
index 0000000..74a3534
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/RichText.php
@@ -0,0 +1,191 @@
+richTextElements = array();
+
+ // Rich-Text string attached to cell?
+ if ($pCell !== null) {
+ // Add cell text and style
+ if ($pCell->getValue() != "") {
+ $objRun = new PHPExcel_RichText_Run($pCell->getValue());
+ $objRun->setFont(clone $pCell->getParent()->getStyle($pCell->getCoordinate())->getFont());
+ $this->addText($objRun);
+ }
+
+ // Set parent value
+ $pCell->setValueExplicit($this, PHPExcel_Cell_DataType::TYPE_STRING);
+ }
+ }
+
+ /**
+ * Add text
+ *
+ * @param PHPExcel_RichText_ITextElement $pText Rich text element
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_RichText
+ */
+ public function addText(PHPExcel_RichText_ITextElement $pText = null)
+ {
+ $this->richTextElements[] = $pText;
+ return $this;
+ }
+
+ /**
+ * Create text
+ *
+ * @param string $pText Text
+ * @return PHPExcel_RichText_TextElement
+ * @throws PHPExcel_Exception
+ */
+ public function createText($pText = '')
+ {
+ $objText = new PHPExcel_RichText_TextElement($pText);
+ $this->addText($objText);
+ return $objText;
+ }
+
+ /**
+ * Create text run
+ *
+ * @param string $pText Text
+ * @return PHPExcel_RichText_Run
+ * @throws PHPExcel_Exception
+ */
+ public function createTextRun($pText = '')
+ {
+ $objText = new PHPExcel_RichText_Run($pText);
+ $this->addText($objText);
+ return $objText;
+ }
+
+ /**
+ * Get plain text
+ *
+ * @return string
+ */
+ public function getPlainText()
+ {
+ // Return value
+ $returnValue = '';
+
+ // Loop through all PHPExcel_RichText_ITextElement
+ foreach ($this->richTextElements as $text) {
+ $returnValue .= $text->getText();
+ }
+
+ // Return
+ return $returnValue;
+ }
+
+ /**
+ * Convert to string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getPlainText();
+ }
+
+ /**
+ * Get Rich Text elements
+ *
+ * @return PHPExcel_RichText_ITextElement[]
+ */
+ public function getRichTextElements()
+ {
+ return $this->richTextElements;
+ }
+
+ /**
+ * Set Rich Text elements
+ *
+ * @param PHPExcel_RichText_ITextElement[] $pElements Array of elements
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_RichText
+ */
+ public function setRichTextElements($pElements = null)
+ {
+ if (is_array($pElements)) {
+ $this->richTextElements = $pElements;
+ } else {
+ throw new PHPExcel_Exception("Invalid PHPExcel_RichText_ITextElement[] array passed.");
+ }
+ return $this;
+ }
+
+ /**
+ * Get hash code
+ *
+ * @return string Hash code
+ */
+ public function getHashCode()
+ {
+ $hashElements = '';
+ foreach ($this->richTextElements as $element) {
+ $hashElements .= $element->getHashCode();
+ }
+
+ return md5(
+ $hashElements .
+ __CLASS__
+ );
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/RichText/ITextElement.php b/extend/PHPExcel/PHPExcel/RichText/ITextElement.php
new file mode 100755
index 0000000..5db3432
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/RichText/ITextElement.php
@@ -0,0 +1,56 @@
+setText($pText);
+ $this->font = new PHPExcel_Style_Font();
+ }
+
+ /**
+ * Get font
+ *
+ * @return PHPExcel_Style_Font
+ */
+ public function getFont()
+ {
+ return $this->font;
+ }
+
+ /**
+ * Set font
+ *
+ * @param PHPExcel_Style_Font $pFont Font
+ * @throws PHPExcel_Exception
+ * @return PHPExcel_RichText_ITextElement
+ */
+ public function setFont(PHPExcel_Style_Font $pFont = null)
+ {
+ $this->font = $pFont;
+ return $this;
+ }
+
+ /**
+ * Get hash code
+ *
+ * @return string Hash code
+ */
+ public function getHashCode()
+ {
+ return md5(
+ $this->getText() .
+ $this->font->getHashCode() .
+ __CLASS__
+ );
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/RichText/TextElement.php b/extend/PHPExcel/PHPExcel/RichText/TextElement.php
new file mode 100755
index 0000000..f86e703
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/RichText/TextElement.php
@@ -0,0 +1,105 @@
+text = $pText;
+ }
+
+ /**
+ * Get text
+ *
+ * @return string Text
+ */
+ public function getText()
+ {
+ return $this->text;
+ }
+
+ /**
+ * Set text
+ *
+ * @param $pText string Text
+ * @return PHPExcel_RichText_ITextElement
+ */
+ public function setText($pText = '')
+ {
+ $this->text = $pText;
+ return $this;
+ }
+
+ /**
+ * Get font
+ *
+ * @return PHPExcel_Style_Font
+ */
+ public function getFont()
+ {
+ return null;
+ }
+
+ /**
+ * Get hash code
+ *
+ * @return string Hash code
+ */
+ public function getHashCode()
+ {
+ return md5(
+ $this->text .
+ __CLASS__
+ );
+ }
+
+ /**
+ * Implement PHP __clone to create a deep clone, not just a shallow copy.
+ */
+ public function __clone()
+ {
+ $vars = get_object_vars($this);
+ foreach ($vars as $key => $value) {
+ if (is_object($value)) {
+ $this->$key = clone $value;
+ } else {
+ $this->$key = $value;
+ }
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Settings.php b/extend/PHPExcel/PHPExcel/Settings.php
new file mode 100755
index 0000000..dcbc89f
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Settings.php
@@ -0,0 +1,389 @@
+setLocale($locale);
+ }
+
+
+ /**
+ * Set details of the external library that PHPExcel should use for rendering charts
+ *
+ * @param string $libraryName Internal reference name of the library
+ * e.g. PHPExcel_Settings::CHART_RENDERER_JPGRAPH
+ * @param string $libraryBaseDir Directory path to the library's base folder
+ *
+ * @return boolean Success or failure
+ */
+ public static function setChartRenderer($libraryName, $libraryBaseDir)
+ {
+ if (!self::setChartRendererName($libraryName)) {
+ return false;
+ }
+ return self::setChartRendererPath($libraryBaseDir);
+ }
+
+
+ /**
+ * Identify to PHPExcel the external library to use for rendering charts
+ *
+ * @param string $libraryName Internal reference name of the library
+ * e.g. PHPExcel_Settings::CHART_RENDERER_JPGRAPH
+ *
+ * @return boolean Success or failure
+ */
+ public static function setChartRendererName($libraryName)
+ {
+ if (!in_array($libraryName, self::$chartRenderers)) {
+ return false;
+ }
+ self::$chartRendererName = $libraryName;
+
+ return true;
+ }
+
+
+ /**
+ * Tell PHPExcel where to find the external library to use for rendering charts
+ *
+ * @param string $libraryBaseDir Directory path to the library's base folder
+ * @return boolean Success or failure
+ */
+ public static function setChartRendererPath($libraryBaseDir)
+ {
+ if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) {
+ return false;
+ }
+ self::$chartRendererPath = $libraryBaseDir;
+
+ return true;
+ }
+
+
+ /**
+ * Return the Chart Rendering Library that PHPExcel is currently configured to use (e.g. jpgraph)
+ *
+ * @return string|NULL Internal reference name of the Chart Rendering Library that PHPExcel is
+ * currently configured to use
+ * e.g. PHPExcel_Settings::CHART_RENDERER_JPGRAPH
+ */
+ public static function getChartRendererName()
+ {
+ return self::$chartRendererName;
+ }
+
+
+ /**
+ * Return the directory path to the Chart Rendering Library that PHPExcel is currently configured to use
+ *
+ * @return string|NULL Directory Path to the Chart Rendering Library that PHPExcel is
+ * currently configured to use
+ */
+ public static function getChartRendererPath()
+ {
+ return self::$chartRendererPath;
+ }
+
+
+ /**
+ * Set details of the external library that PHPExcel should use for rendering PDF files
+ *
+ * @param string $libraryName Internal reference name of the library
+ * e.g. PHPExcel_Settings::PDF_RENDERER_TCPDF,
+ * PHPExcel_Settings::PDF_RENDERER_DOMPDF
+ * or PHPExcel_Settings::PDF_RENDERER_MPDF
+ * @param string $libraryBaseDir Directory path to the library's base folder
+ *
+ * @return boolean Success or failure
+ */
+ public static function setPdfRenderer($libraryName, $libraryBaseDir)
+ {
+ if (!self::setPdfRendererName($libraryName)) {
+ return false;
+ }
+ return self::setPdfRendererPath($libraryBaseDir);
+ }
+
+
+ /**
+ * Identify to PHPExcel the external library to use for rendering PDF files
+ *
+ * @param string $libraryName Internal reference name of the library
+ * e.g. PHPExcel_Settings::PDF_RENDERER_TCPDF,
+ * PHPExcel_Settings::PDF_RENDERER_DOMPDF
+ * or PHPExcel_Settings::PDF_RENDERER_MPDF
+ *
+ * @return boolean Success or failure
+ */
+ public static function setPdfRendererName($libraryName)
+ {
+ if (!in_array($libraryName, self::$pdfRenderers)) {
+ return false;
+ }
+ self::$pdfRendererName = $libraryName;
+
+ return true;
+ }
+
+
+ /**
+ * Tell PHPExcel where to find the external library to use for rendering PDF files
+ *
+ * @param string $libraryBaseDir Directory path to the library's base folder
+ * @return boolean Success or failure
+ */
+ public static function setPdfRendererPath($libraryBaseDir)
+ {
+ if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) {
+ return false;
+ }
+ self::$pdfRendererPath = $libraryBaseDir;
+
+ return true;
+ }
+
+
+ /**
+ * Return the PDF Rendering Library that PHPExcel is currently configured to use (e.g. dompdf)
+ *
+ * @return string|NULL Internal reference name of the PDF Rendering Library that PHPExcel is
+ * currently configured to use
+ * e.g. PHPExcel_Settings::PDF_RENDERER_TCPDF,
+ * PHPExcel_Settings::PDF_RENDERER_DOMPDF
+ * or PHPExcel_Settings::PDF_RENDERER_MPDF
+ */
+ public static function getPdfRendererName()
+ {
+ return self::$pdfRendererName;
+ }
+
+ /**
+ * Return the directory path to the PDF Rendering Library that PHPExcel is currently configured to use
+ *
+ * @return string|NULL Directory Path to the PDF Rendering Library that PHPExcel is
+ * currently configured to use
+ */
+ public static function getPdfRendererPath()
+ {
+ return self::$pdfRendererPath;
+ }
+
+ /**
+ * Set options for libxml loader
+ *
+ * @param int $options Options for libxml loader
+ */
+ public static function setLibXmlLoaderOptions($options = null)
+ {
+ if (is_null($options) && defined('LIBXML_DTDLOAD')) {
+ $options = LIBXML_DTDLOAD | LIBXML_DTDATTR;
+ }
+ if (version_compare(PHP_VERSION, '5.2.11') >= 0) {
+ @libxml_disable_entity_loader((bool) $options);
+ }
+ self::$libXmlLoaderOptions = $options;
+ }
+
+ /**
+ * Get defined options for libxml loader.
+ * Defaults to LIBXML_DTDLOAD | LIBXML_DTDATTR when not set explicitly.
+ *
+ * @return int Default options for libxml loader
+ */
+ public static function getLibXmlLoaderOptions()
+ {
+ if (is_null(self::$libXmlLoaderOptions) && defined('LIBXML_DTDLOAD')) {
+ self::setLibXmlLoaderOptions(LIBXML_DTDLOAD | LIBXML_DTDATTR);
+ } elseif (is_null(self::$libXmlLoaderOptions)) {
+ self::$libXmlLoaderOptions = true;
+ }
+ if (version_compare(PHP_VERSION, '5.2.11') >= 0) {
+ @libxml_disable_entity_loader((bool) self::$libXmlLoaderOptions);
+ }
+ return self::$libXmlLoaderOptions;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/CodePage.php b/extend/PHPExcel/PHPExcel/Shared/CodePage.php
new file mode 100755
index 0000000..b3e440e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/CodePage.php
@@ -0,0 +1,156 @@
+ 'January',
+ 'Feb' => 'February',
+ 'Mar' => 'March',
+ 'Apr' => 'April',
+ 'May' => 'May',
+ 'Jun' => 'June',
+ 'Jul' => 'July',
+ 'Aug' => 'August',
+ 'Sep' => 'September',
+ 'Oct' => 'October',
+ 'Nov' => 'November',
+ 'Dec' => 'December',
+ );
+
+ /*
+ * Names of the months of the year, indexed by shortname
+ * Planned usage for locale settings
+ *
+ * @public
+ * @var string[]
+ */
+ public static $numberSuffixes = array(
+ 'st',
+ 'nd',
+ 'rd',
+ 'th',
+ );
+
+ /*
+ * Base calendar year to use for calculations
+ *
+ * @private
+ * @var int
+ */
+ protected static $excelBaseDate = self::CALENDAR_WINDOWS_1900;
+
+ /**
+ * Set the Excel calendar (Windows 1900 or Mac 1904)
+ *
+ * @param integer $baseDate Excel base date (1900 or 1904)
+ * @return boolean Success or failure
+ */
+ public static function setExcelCalendar($baseDate)
+ {
+ if (($baseDate == self::CALENDAR_WINDOWS_1900) ||
+ ($baseDate == self::CALENDAR_MAC_1904)) {
+ self::$excelBaseDate = $baseDate;
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Return the Excel calendar (Windows 1900 or Mac 1904)
+ *
+ * @return integer Excel base date (1900 or 1904)
+ */
+ public static function getExcelCalendar()
+ {
+ return self::$excelBaseDate;
+ }
+
+
+ /**
+ * Convert a date from Excel to PHP
+ *
+ * @param integer $dateValue Excel date/time value
+ * @param boolean $adjustToTimezone Flag indicating whether $dateValue should be treated as
+ * a UST timestamp, or adjusted to UST
+ * @param string $timezone The timezone for finding the adjustment from UST
+ * @return integer PHP serialized date/time
+ */
+ public static function ExcelToPHP($dateValue = 0, $adjustToTimezone = false, $timezone = null)
+ {
+ if (self::$excelBaseDate == self::CALENDAR_WINDOWS_1900) {
+ $myexcelBaseDate = 25569;
+ // Adjust for the spurious 29-Feb-1900 (Day 60)
+ if ($dateValue < 60) {
+ --$myexcelBaseDate;
+ }
+ } else {
+ $myexcelBaseDate = 24107;
+ }
+
+ // Perform conversion
+ if ($dateValue >= 1) {
+ $utcDays = $dateValue - $myexcelBaseDate;
+ $returnValue = round($utcDays * 86400);
+ if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
+ $returnValue = (integer) $returnValue;
+ }
+ } else {
+ $hours = round($dateValue * 24);
+ $mins = round($dateValue * 1440) - round($hours * 60);
+ $secs = round($dateValue * 86400) - round($hours * 3600) - round($mins * 60);
+ $returnValue = (integer) gmmktime($hours, $mins, $secs);
+ }
+
+ $timezoneAdjustment = ($adjustToTimezone) ?
+ PHPExcel_Shared_TimeZone::getTimezoneAdjustment($timezone, $returnValue) :
+ 0;
+
+ return $returnValue + $timezoneAdjustment;
+ }
+
+
+ /**
+ * Convert a date from Excel to a PHP Date/Time object
+ *
+ * @param integer $dateValue Excel date/time value
+ * @return DateTime PHP date/time object
+ */
+ public static function ExcelToPHPObject($dateValue = 0)
+ {
+ $dateTime = self::ExcelToPHP($dateValue);
+ $days = floor($dateTime / 86400);
+ $time = round((($dateTime / 86400) - $days) * 86400);
+ $hours = round($time / 3600);
+ $minutes = round($time / 60) - ($hours * 60);
+ $seconds = round($time) - ($hours * 3600) - ($minutes * 60);
+
+ $dateObj = date_create('1-Jan-1970+'.$days.' days');
+ $dateObj->setTime($hours, $minutes, $seconds);
+
+ return $dateObj;
+ }
+
+
+ /**
+ * Convert a date from PHP to Excel
+ *
+ * @param mixed $dateValue PHP serialized date/time or date object
+ * @param boolean $adjustToTimezone Flag indicating whether $dateValue should be treated as
+ * a UST timestamp, or adjusted to UST
+ * @param string $timezone The timezone for finding the adjustment from UST
+ * @return mixed Excel date/time value
+ * or boolean FALSE on failure
+ */
+ public static function PHPToExcel($dateValue = 0, $adjustToTimezone = false, $timezone = null)
+ {
+ $saveTimeZone = date_default_timezone_get();
+ date_default_timezone_set('UTC');
+
+ $timezoneAdjustment = ($adjustToTimezone) ?
+ PHPExcel_Shared_TimeZone::getTimezoneAdjustment($timezone ? $timezone : $saveTimeZone, $dateValue) :
+ 0;
+
+ $retValue = false;
+ if ((is_object($dateValue)) && ($dateValue instanceof DateTime)) {
+ $dateValue->add(new DateInterval('PT' . $timezoneAdjustment . 'S'));
+ $retValue = self::FormattedPHPToExcel($dateValue->format('Y'), $dateValue->format('m'), $dateValue->format('d'), $dateValue->format('H'), $dateValue->format('i'), $dateValue->format('s'));
+ } elseif (is_numeric($dateValue)) {
+ $dateValue += $timezoneAdjustment;
+ $retValue = self::FormattedPHPToExcel(date('Y', $dateValue), date('m', $dateValue), date('d', $dateValue), date('H', $dateValue), date('i', $dateValue), date('s', $dateValue));
+ } elseif (is_string($dateValue)) {
+ $retValue = self::stringToExcel($dateValue);
+ }
+ date_default_timezone_set($saveTimeZone);
+
+ return $retValue;
+ }
+
+
+ /**
+ * FormattedPHPToExcel
+ *
+ * @param integer $year
+ * @param integer $month
+ * @param integer $day
+ * @param integer $hours
+ * @param integer $minutes
+ * @param integer $seconds
+ * @return integer Excel date/time value
+ */
+ public static function FormattedPHPToExcel($year, $month, $day, $hours = 0, $minutes = 0, $seconds = 0)
+ {
+ if (self::$excelBaseDate == self::CALENDAR_WINDOWS_1900) {
+ //
+ // Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
+ // This affects every date following 28th February 1900
+ //
+ $excel1900isLeapYear = true;
+ if (($year == 1900) && ($month <= 2)) {
+ $excel1900isLeapYear = false;
+ }
+ $myexcelBaseDate = 2415020;
+ } else {
+ $myexcelBaseDate = 2416481;
+ $excel1900isLeapYear = false;
+ }
+
+ // Julian base date Adjustment
+ if ($month > 2) {
+ $month -= 3;
+ } else {
+ $month += 9;
+ --$year;
+ }
+
+ // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
+ $century = substr($year, 0, 2);
+ $decade = substr($year, 2, 2);
+ $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myexcelBaseDate + $excel1900isLeapYear;
+
+ $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
+
+ return (float) $excelDate + $excelTime;
+ }
+
+
+ /**
+ * Is a given cell a date/time?
+ *
+ * @param PHPExcel_Cell $pCell
+ * @return boolean
+ */
+ public static function isDateTime(PHPExcel_Cell $pCell)
+ {
+ return self::isDateTimeFormat(
+ $pCell->getWorksheet()->getStyle(
+ $pCell->getCoordinate()
+ )->getNumberFormat()
+ );
+ }
+
+
+ /**
+ * Is a given number format a date/time?
+ *
+ * @param PHPExcel_Style_NumberFormat $pFormat
+ * @return boolean
+ */
+ public static function isDateTimeFormat(PHPExcel_Style_NumberFormat $pFormat)
+ {
+ return self::isDateTimeFormatCode($pFormat->getFormatCode());
+ }
+
+
+ private static $possibleDateFormatCharacters = 'eymdHs';
+
+ /**
+ * Is a given number format code a date/time?
+ *
+ * @param string $pFormatCode
+ * @return boolean
+ */
+ public static function isDateTimeFormatCode($pFormatCode = '')
+ {
+ if (strtolower($pFormatCode) === strtolower(PHPExcel_Style_NumberFormat::FORMAT_GENERAL)) {
+ // "General" contains an epoch letter 'e', so we trap for it explicitly here (case-insensitive check)
+ return false;
+ }
+ if (preg_match('/[0#]E[+-]0/i', $pFormatCode)) {
+ // Scientific format
+ return false;
+ }
+
+ // Switch on formatcode
+ switch ($pFormatCode) {
+ // Explicitly defined date formats
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYSLASH:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYMINUS:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DMMINUS:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_MYMINUS:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME1:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME2:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME5:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME6:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME7:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME8:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX14:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17:
+ case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22:
+ return true;
+ }
+
+ // Typically number, currency or accounting (or occasionally fraction) formats
+ if ((substr($pFormatCode, 0, 1) == '_') || (substr($pFormatCode, 0, 2) == '0 ')) {
+ return false;
+ }
+ // Try checking for any of the date formatting characters that don't appear within square braces
+ if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i', $pFormatCode)) {
+ // We might also have a format mask containing quoted strings...
+ // we don't want to test for any of our characters within the quoted blocks
+ if (strpos($pFormatCode, '"') !== false) {
+ $segMatcher = false;
+ foreach (explode('"', $pFormatCode) as $subVal) {
+ // Only test in alternate array entries (the non-quoted blocks)
+ if (($segMatcher = !$segMatcher) &&
+ (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i', $subVal))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ // No date...
+ return false;
+ }
+
+
+ /**
+ * Convert a date/time string to Excel time
+ *
+ * @param string $dateValue Examples: '2009-12-31', '2009-12-31 15:59', '2009-12-31 15:59:10'
+ * @return float|FALSE Excel date/time serial value
+ */
+ public static function stringToExcel($dateValue = '')
+ {
+ if (strlen($dateValue) < 2) {
+ return false;
+ }
+ if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue)) {
+ return false;
+ }
+
+ $dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue);
+
+ if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) {
+ return false;
+ }
+
+ if (strpos($dateValue, ':') !== false) {
+ $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue);
+ if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) {
+ return false;
+ }
+ $dateValueNew += $timeValue;
+ }
+ return $dateValueNew;
+ }
+
+ /**
+ * Converts a month name (either a long or a short name) to a month number
+ *
+ * @param string $month Month name or abbreviation
+ * @return integer|string Month number (1 - 12), or the original string argument if it isn't a valid month name
+ */
+ public static function monthStringToNumber($month)
+ {
+ $monthIndex = 1;
+ foreach (self::$monthNames as $shortMonthName => $longMonthName) {
+ if (($month === $longMonthName) || ($month === $shortMonthName)) {
+ return $monthIndex;
+ }
+ ++$monthIndex;
+ }
+ return $month;
+ }
+
+ /**
+ * Strips an ordinal froma numeric value
+ *
+ * @param string $day Day number with an ordinal
+ * @return integer|string The integer value with any ordinal stripped, or the original string argument if it isn't a valid numeric
+ */
+ public static function dayStringToNumber($day)
+ {
+ $strippedDayValue = (str_replace(self::$numberSuffixes, '', $day));
+ if (is_numeric($strippedDayValue)) {
+ return (integer) $strippedDayValue;
+ }
+ return $day;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Drawing.php b/extend/PHPExcel/PHPExcel/Shared/Drawing.php
new file mode 100755
index 0000000..3e027b4
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Drawing.php
@@ -0,0 +1,270 @@
+getName();
+ $size = $pDefaultFont->getSize();
+
+ if (isset(PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size])) {
+ // Exact width can be determined
+ $colWidth = $pValue * PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['width'] / PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['px'];
+ } else {
+ // We don't have data for this particular font and size, use approximation by
+ // extrapolating from Calibri 11
+ $colWidth = $pValue * 11 * PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['width'] / PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['px'] / $size;
+ }
+
+ return $colWidth;
+ }
+
+ /**
+ * Convert column width from (intrinsic) Excel units to pixels
+ *
+ * @param float $pValue Value in cell dimension
+ * @param PHPExcel_Style_Font $pDefaultFont Default font of the workbook
+ * @return int Value in pixels
+ */
+ public static function cellDimensionToPixels($pValue = 0, PHPExcel_Style_Font $pDefaultFont)
+ {
+ // Font name and size
+ $name = $pDefaultFont->getName();
+ $size = $pDefaultFont->getSize();
+
+ if (isset(PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size])) {
+ // Exact width can be determined
+ $colWidth = $pValue * PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['px'] / PHPExcel_Shared_Font::$defaultColumnWidths[$name][$size]['width'];
+ } else {
+ // We don't have data for this particular font and size, use approximation by
+ // extrapolating from Calibri 11
+ $colWidth = $pValue * $size * PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['px'] / PHPExcel_Shared_Font::$defaultColumnWidths['Calibri'][11]['width'] / 11;
+ }
+
+ // Round pixels to closest integer
+ $colWidth = (int) round($colWidth);
+
+ return $colWidth;
+ }
+
+ /**
+ * Convert pixels to points
+ *
+ * @param int $pValue Value in pixels
+ * @return int Value in points
+ */
+ public static function pixelsToPoints($pValue = 0)
+ {
+ return $pValue * 0.67777777;
+ }
+
+ /**
+ * Convert points to pixels
+ *
+ * @param int $pValue Value in points
+ * @return int Value in pixels
+ */
+ public static function pointsToPixels($pValue = 0)
+ {
+ if ($pValue != 0) {
+ return (int) ceil($pValue * 1.333333333);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Convert degrees to angle
+ *
+ * @param int $pValue Degrees
+ * @return int Angle
+ */
+ public static function degreesToAngle($pValue = 0)
+ {
+ return (int)round($pValue * 60000);
+ }
+
+ /**
+ * Convert angle to degrees
+ *
+ * @param int $pValue Angle
+ * @return int Degrees
+ */
+ public static function angleToDegrees($pValue = 0)
+ {
+ if ($pValue != 0) {
+ return round($pValue / 60000);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Create a new image from file. By alexander at alexauto dot nl
+ *
+ * @link http://www.php.net/manual/en/function.imagecreatefromwbmp.php#86214
+ * @param string $filename Path to Windows DIB (BMP) image
+ * @return resource
+ */
+ public static function imagecreatefrombmp($p_sFile)
+ {
+ // Load the image into a string
+ $file = fopen($p_sFile, "rb");
+ $read = fread($file, 10);
+ while (!feof($file) && ($read<>"")) {
+ $read .= fread($file, 1024);
+ }
+
+ $temp = unpack("H*", $read);
+ $hex = $temp[1];
+ $header = substr($hex, 0, 108);
+
+ // Process the header
+ // Structure: http://www.fastgraph.com/help/bmp_header_format.html
+ if (substr($header, 0, 4)=="424d") {
+ // Cut it in parts of 2 bytes
+ $header_parts = str_split($header, 2);
+
+ // Get the width 4 bytes
+ $width = hexdec($header_parts[19].$header_parts[18]);
+
+ // Get the height 4 bytes
+ $height = hexdec($header_parts[23].$header_parts[22]);
+
+ // Unset the header params
+ unset($header_parts);
+ }
+
+ // Define starting X and Y
+ $x = 0;
+ $y = 1;
+
+ // Create newimage
+ $image = imagecreatetruecolor($width, $height);
+
+ // Grab the body from the image
+ $body = substr($hex, 108);
+
+ // Calculate if padding at the end-line is needed
+ // Divided by two to keep overview.
+ // 1 byte = 2 HEX-chars
+ $body_size = (strlen($body)/2);
+ $header_size = ($width*$height);
+
+ // Use end-line padding? Only when needed
+ $usePadding = ($body_size>($header_size*3)+4);
+
+ // Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
+ // Calculate the next DWORD-position in the body
+ for ($i = 0; $i < $body_size; $i += 3) {
+ // Calculate line-ending and padding
+ if ($x >= $width) {
+ // If padding needed, ignore image-padding
+ // Shift i to the ending of the current 32-bit-block
+ if ($usePadding) {
+ $i += $width%4;
+ }
+
+ // Reset horizontal position
+ $x = 0;
+
+ // Raise the height-position (bottom-up)
+ $y++;
+
+ // Reached the image-height? Break the for-loop
+ if ($y > $height) {
+ break;
+ }
+ }
+
+ // Calculation of the RGB-pixel (defined as BGR in image-data)
+ // Define $i_pos as absolute position in the body
+ $i_pos = $i * 2;
+ $r = hexdec($body[$i_pos+4].$body[$i_pos+5]);
+ $g = hexdec($body[$i_pos+2].$body[$i_pos+3]);
+ $b = hexdec($body[$i_pos].$body[$i_pos+1]);
+
+ // Calculate and draw the pixel
+ $color = imagecolorallocate($image, $r, $g, $b);
+ imagesetpixel($image, $x, $height-$y, $color);
+
+ // Raise the horizontal position
+ $x++;
+ }
+
+ // Unset the body / free the memory
+ unset($body);
+
+ // Return image-object
+ return $image;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher.php b/extend/PHPExcel/PHPExcel/Shared/Escher.php
new file mode 100755
index 0000000..1aedb9d
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher.php
@@ -0,0 +1,83 @@
+dggContainer;
+ }
+
+ /**
+ * Set Drawing Group Container
+ *
+ * @param PHPExcel_Shared_Escher_DggContainer $dggContainer
+ */
+ public function setDggContainer($dggContainer)
+ {
+ return $this->dggContainer = $dggContainer;
+ }
+
+ /**
+ * Get Drawing Container
+ *
+ * @return PHPExcel_Shared_Escher_DgContainer
+ */
+ public function getDgContainer()
+ {
+ return $this->dgContainer;
+ }
+
+ /**
+ * Set Drawing Container
+ *
+ * @param PHPExcel_Shared_Escher_DgContainer $dgContainer
+ */
+ public function setDgContainer($dgContainer)
+ {
+ return $this->dgContainer = $dgContainer;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php
new file mode 100755
index 0000000..739cd90
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer.php
@@ -0,0 +1,75 @@
+dgId;
+ }
+
+ public function setDgId($value)
+ {
+ $this->dgId = $value;
+ }
+
+ public function getLastSpId()
+ {
+ return $this->lastSpId;
+ }
+
+ public function setLastSpId($value)
+ {
+ $this->lastSpId = $value;
+ }
+
+ public function getSpgrContainer()
+ {
+ return $this->spgrContainer;
+ }
+
+ public function setSpgrContainer($spgrContainer)
+ {
+ return $this->spgrContainer = $spgrContainer;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php
new file mode 100755
index 0000000..49e7d68
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php
@@ -0,0 +1,102 @@
+parent = $parent;
+ }
+
+ /**
+ * Get the parent Shape Group Container if any
+ *
+ * @return PHPExcel_Shared_Escher_DgContainer_SpgrContainer|null
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Add a child. This will be either spgrContainer or spContainer
+ *
+ * @param mixed $child
+ */
+ public function addChild($child)
+ {
+ $this->children[] = $child;
+ $child->setParent($this);
+ }
+
+ /**
+ * Get collection of Shape Containers
+ */
+ public function getChildren()
+ {
+ return $this->children;
+ }
+
+ /**
+ * Recursively get all spContainers within this spgrContainer
+ *
+ * @return PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer[]
+ */
+ public function getAllSpContainers()
+ {
+ $allSpContainers = array();
+
+ foreach ($this->children as $child) {
+ if ($child instanceof PHPExcel_Shared_Escher_DgContainer_SpgrContainer) {
+ $allSpContainers = array_merge($allSpContainers, $child->getAllSpContainers());
+ } else {
+ $allSpContainers[] = $child;
+ }
+ }
+
+ return $allSpContainers;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php
new file mode 100755
index 0000000..a1f1a46
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php
@@ -0,0 +1,388 @@
+parent = $parent;
+ }
+
+ /**
+ * Get the parent Shape Group Container
+ *
+ * @return PHPExcel_Shared_Escher_DgContainer_SpgrContainer
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Set whether this is a group shape
+ *
+ * @param boolean $value
+ */
+ public function setSpgr($value = false)
+ {
+ $this->spgr = $value;
+ }
+
+ /**
+ * Get whether this is a group shape
+ *
+ * @return boolean
+ */
+ public function getSpgr()
+ {
+ return $this->spgr;
+ }
+
+ /**
+ * Set the shape type
+ *
+ * @param int $value
+ */
+ public function setSpType($value)
+ {
+ $this->spType = $value;
+ }
+
+ /**
+ * Get the shape type
+ *
+ * @return int
+ */
+ public function getSpType()
+ {
+ return $this->spType;
+ }
+
+ /**
+ * Set the shape flag
+ *
+ * @param int $value
+ */
+ public function setSpFlag($value)
+ {
+ $this->spFlag = $value;
+ }
+
+ /**
+ * Get the shape flag
+ *
+ * @return int
+ */
+ public function getSpFlag()
+ {
+ return $this->spFlag;
+ }
+
+ /**
+ * Set the shape index
+ *
+ * @param int $value
+ */
+ public function setSpId($value)
+ {
+ $this->spId = $value;
+ }
+
+ /**
+ * Get the shape index
+ *
+ * @return int
+ */
+ public function getSpId()
+ {
+ return $this->spId;
+ }
+
+ /**
+ * Set an option for the Shape Group Container
+ *
+ * @param int $property The number specifies the option
+ * @param mixed $value
+ */
+ public function setOPT($property, $value)
+ {
+ $this->OPT[$property] = $value;
+ }
+
+ /**
+ * Get an option for the Shape Group Container
+ *
+ * @param int $property The number specifies the option
+ * @return mixed
+ */
+ public function getOPT($property)
+ {
+ if (isset($this->OPT[$property])) {
+ return $this->OPT[$property];
+ }
+ return null;
+ }
+
+ /**
+ * Get the collection of options
+ *
+ * @return array
+ */
+ public function getOPTCollection()
+ {
+ return $this->OPT;
+ }
+
+ /**
+ * Set cell coordinates of upper-left corner of shape
+ *
+ * @param string $value
+ */
+ public function setStartCoordinates($value = 'A1')
+ {
+ $this->startCoordinates = $value;
+ }
+
+ /**
+ * Get cell coordinates of upper-left corner of shape
+ *
+ * @return string
+ */
+ public function getStartCoordinates()
+ {
+ return $this->startCoordinates;
+ }
+
+ /**
+ * Set offset in x-direction of upper-left corner of shape measured in 1/1024 of column width
+ *
+ * @param int $startOffsetX
+ */
+ public function setStartOffsetX($startOffsetX = 0)
+ {
+ $this->startOffsetX = $startOffsetX;
+ }
+
+ /**
+ * Get offset in x-direction of upper-left corner of shape measured in 1/1024 of column width
+ *
+ * @return int
+ */
+ public function getStartOffsetX()
+ {
+ return $this->startOffsetX;
+ }
+
+ /**
+ * Set offset in y-direction of upper-left corner of shape measured in 1/256 of row height
+ *
+ * @param int $startOffsetY
+ */
+ public function setStartOffsetY($startOffsetY = 0)
+ {
+ $this->startOffsetY = $startOffsetY;
+ }
+
+ /**
+ * Get offset in y-direction of upper-left corner of shape measured in 1/256 of row height
+ *
+ * @return int
+ */
+ public function getStartOffsetY()
+ {
+ return $this->startOffsetY;
+ }
+
+ /**
+ * Set cell coordinates of bottom-right corner of shape
+ *
+ * @param string $value
+ */
+ public function setEndCoordinates($value = 'A1')
+ {
+ $this->endCoordinates = $value;
+ }
+
+ /**
+ * Get cell coordinates of bottom-right corner of shape
+ *
+ * @return string
+ */
+ public function getEndCoordinates()
+ {
+ return $this->endCoordinates;
+ }
+
+ /**
+ * Set offset in x-direction of bottom-right corner of shape measured in 1/1024 of column width
+ *
+ * @param int $startOffsetX
+ */
+ public function setEndOffsetX($endOffsetX = 0)
+ {
+ $this->endOffsetX = $endOffsetX;
+ }
+
+ /**
+ * Get offset in x-direction of bottom-right corner of shape measured in 1/1024 of column width
+ *
+ * @return int
+ */
+ public function getEndOffsetX()
+ {
+ return $this->endOffsetX;
+ }
+
+ /**
+ * Set offset in y-direction of bottom-right corner of shape measured in 1/256 of row height
+ *
+ * @param int $endOffsetY
+ */
+ public function setEndOffsetY($endOffsetY = 0)
+ {
+ $this->endOffsetY = $endOffsetY;
+ }
+
+ /**
+ * Get offset in y-direction of bottom-right corner of shape measured in 1/256 of row height
+ *
+ * @return int
+ */
+ public function getEndOffsetY()
+ {
+ return $this->endOffsetY;
+ }
+
+ /**
+ * Get the nesting level of this spContainer. This is the number of spgrContainers between this spContainer and
+ * the dgContainer. A value of 1 = immediately within first spgrContainer
+ * Higher nesting level occurs if and only if spContainer is part of a shape group
+ *
+ * @return int Nesting level
+ */
+ public function getNestingLevel()
+ {
+ $nestingLevel = 0;
+
+ $parent = $this->getParent();
+ while ($parent instanceof PHPExcel_Shared_Escher_DgContainer_SpgrContainer) {
+ ++$nestingLevel;
+ $parent = $parent->getParent();
+ }
+
+ return $nestingLevel;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php
new file mode 100755
index 0000000..b116b1b
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer.php
@@ -0,0 +1,196 @@
+spIdMax;
+ }
+
+ /**
+ * Set maximum shape index of all shapes in all drawings (plus one)
+ *
+ * @param int
+ */
+ public function setSpIdMax($value)
+ {
+ $this->spIdMax = $value;
+ }
+
+ /**
+ * Get total number of drawings saved
+ *
+ * @return int
+ */
+ public function getCDgSaved()
+ {
+ return $this->cDgSaved;
+ }
+
+ /**
+ * Set total number of drawings saved
+ *
+ * @param int
+ */
+ public function setCDgSaved($value)
+ {
+ $this->cDgSaved = $value;
+ }
+
+ /**
+ * Get total number of shapes saved (including group shapes)
+ *
+ * @return int
+ */
+ public function getCSpSaved()
+ {
+ return $this->cSpSaved;
+ }
+
+ /**
+ * Set total number of shapes saved (including group shapes)
+ *
+ * @param int
+ */
+ public function setCSpSaved($value)
+ {
+ $this->cSpSaved = $value;
+ }
+
+ /**
+ * Get BLIP Store Container
+ *
+ * @return PHPExcel_Shared_Escher_DggContainer_BstoreContainer
+ */
+ public function getBstoreContainer()
+ {
+ return $this->bstoreContainer;
+ }
+
+ /**
+ * Set BLIP Store Container
+ *
+ * @param PHPExcel_Shared_Escher_DggContainer_BstoreContainer $bstoreContainer
+ */
+ public function setBstoreContainer($bstoreContainer)
+ {
+ $this->bstoreContainer = $bstoreContainer;
+ }
+
+ /**
+ * Set an option for the drawing group
+ *
+ * @param int $property The number specifies the option
+ * @param mixed $value
+ */
+ public function setOPT($property, $value)
+ {
+ $this->OPT[$property] = $value;
+ }
+
+ /**
+ * Get an option for the drawing group
+ *
+ * @param int $property The number specifies the option
+ * @return mixed
+ */
+ public function getOPT($property)
+ {
+ if (isset($this->OPT[$property])) {
+ return $this->OPT[$property];
+ }
+ return null;
+ }
+
+ /**
+ * Get identifier clusters
+ *
+ * @return array
+ */
+ public function getIDCLs()
+ {
+ return $this->IDCLs;
+ }
+
+ /**
+ * Set identifier clusters. array( => , ...)
+ *
+ * @param array $pValue
+ */
+ public function setIDCLs($pValue)
+ {
+ $this->IDCLs = $pValue;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php
new file mode 100755
index 0000000..1af2432
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php
@@ -0,0 +1,57 @@
+BSECollection[] = $BSE;
+ $BSE->setParent($this);
+ }
+
+ /**
+ * Get the collection of BLIP Store Entries
+ *
+ * @return PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE[]
+ */
+ public function getBSECollection()
+ {
+ return $this->BSECollection;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php
new file mode 100755
index 0000000..d17e91e
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php
@@ -0,0 +1,112 @@
+parent = $parent;
+ }
+
+ /**
+ * Get the BLIP
+ *
+ * @return PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip
+ */
+ public function getBlip()
+ {
+ return $this->blip;
+ }
+
+ /**
+ * Set the BLIP
+ *
+ * @param PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip $blip
+ */
+ public function setBlip($blip)
+ {
+ $this->blip = $blip;
+ $blip->setParent($this);
+ }
+
+ /**
+ * Get the BLIP type
+ *
+ * @return int
+ */
+ public function getBlipType()
+ {
+ return $this->blipType;
+ }
+
+ /**
+ * Set the BLIP type
+ *
+ * @param int
+ */
+ public function setBlipType($blipType)
+ {
+ $this->blipType = $blipType;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php
new file mode 100755
index 0000000..3bcbbbe
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php
@@ -0,0 +1,83 @@
+data;
+ }
+
+ /**
+ * Set the raw image data
+ *
+ * @param string
+ */
+ public function setData($data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * Set parent BSE
+ *
+ * @param PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE $parent
+ */
+ public function setParent($parent)
+ {
+ $this->parent = $parent;
+ }
+
+ /**
+ * Get parent BSE
+ *
+ * @return PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE $parent
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Excel5.php b/extend/PHPExcel/PHPExcel/Shared/Excel5.php
new file mode 100755
index 0000000..c3ff209
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Excel5.php
@@ -0,0 +1,298 @@
+getParent()->getDefaultStyle()->getFont();
+
+ $columnDimensions = $sheet->getColumnDimensions();
+
+ // first find the true column width in pixels (uncollapsed and unhidden)
+ if (isset($columnDimensions[$col]) and $columnDimensions[$col]->getWidth() != -1) {
+ // then we have column dimension with explicit width
+ $columnDimension = $columnDimensions[$col];
+ $width = $columnDimension->getWidth();
+ $pixelWidth = PHPExcel_Shared_Drawing::cellDimensionToPixels($width, $font);
+ } elseif ($sheet->getDefaultColumnDimension()->getWidth() != -1) {
+ // then we have default column dimension with explicit width
+ $defaultColumnDimension = $sheet->getDefaultColumnDimension();
+ $width = $defaultColumnDimension->getWidth();
+ $pixelWidth = PHPExcel_Shared_Drawing::cellDimensionToPixels($width, $font);
+ } else {
+ // we don't even have any default column dimension. Width depends on default font
+ $pixelWidth = PHPExcel_Shared_Font::getDefaultColumnWidthByFont($font, true);
+ }
+
+ // now find the effective column width in pixels
+ if (isset($columnDimensions[$col]) and !$columnDimensions[$col]->getVisible()) {
+ $effectivePixelWidth = 0;
+ } else {
+ $effectivePixelWidth = $pixelWidth;
+ }
+
+ return $effectivePixelWidth;
+ }
+
+ /**
+ * Convert the height of a cell from user's units to pixels. By interpolation
+ * the relationship is: y = 4/3x. If the height hasn't been set by the user we
+ * use the default value. If the row is hidden we use a value of zero.
+ *
+ * @param PHPExcel_Worksheet $sheet The sheet
+ * @param integer $row The row index (1-based)
+ * @return integer The width in pixels
+ */
+ public static function sizeRow($sheet, $row = 1)
+ {
+ // default font of the workbook
+ $font = $sheet->getParent()->getDefaultStyle()->getFont();
+
+ $rowDimensions = $sheet->getRowDimensions();
+
+ // first find the true row height in pixels (uncollapsed and unhidden)
+ if (isset($rowDimensions[$row]) and $rowDimensions[$row]->getRowHeight() != -1) {
+ // then we have a row dimension
+ $rowDimension = $rowDimensions[$row];
+ $rowHeight = $rowDimension->getRowHeight();
+ $pixelRowHeight = (int) ceil(4 * $rowHeight / 3); // here we assume Arial 10
+ } elseif ($sheet->getDefaultRowDimension()->getRowHeight() != -1) {
+ // then we have a default row dimension with explicit height
+ $defaultRowDimension = $sheet->getDefaultRowDimension();
+ $rowHeight = $defaultRowDimension->getRowHeight();
+ $pixelRowHeight = PHPExcel_Shared_Drawing::pointsToPixels($rowHeight);
+ } else {
+ // we don't even have any default row dimension. Height depends on default font
+ $pointRowHeight = PHPExcel_Shared_Font::getDefaultRowHeightByFont($font);
+ $pixelRowHeight = PHPExcel_Shared_Font::fontSizeToPixels($pointRowHeight);
+ }
+
+ // now find the effective row height in pixels
+ if (isset($rowDimensions[$row]) and !$rowDimensions[$row]->getVisible()) {
+ $effectivePixelRowHeight = 0;
+ } else {
+ $effectivePixelRowHeight = $pixelRowHeight;
+ }
+
+ return $effectivePixelRowHeight;
+ }
+
+ /**
+ * Get the horizontal distance in pixels between two anchors
+ * The distanceX is found as sum of all the spanning columns widths minus correction for the two offsets
+ *
+ * @param PHPExcel_Worksheet $sheet
+ * @param string $startColumn
+ * @param integer $startOffsetX Offset within start cell measured in 1/1024 of the cell width
+ * @param string $endColumn
+ * @param integer $endOffsetX Offset within end cell measured in 1/1024 of the cell width
+ * @return integer Horizontal measured in pixels
+ */
+ public static function getDistanceX(PHPExcel_Worksheet $sheet, $startColumn = 'A', $startOffsetX = 0, $endColumn = 'A', $endOffsetX = 0)
+ {
+ $distanceX = 0;
+
+ // add the widths of the spanning columns
+ $startColumnIndex = PHPExcel_Cell::columnIndexFromString($startColumn) - 1; // 1-based
+ $endColumnIndex = PHPExcel_Cell::columnIndexFromString($endColumn) - 1; // 1-based
+ for ($i = $startColumnIndex; $i <= $endColumnIndex; ++$i) {
+ $distanceX += self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($i));
+ }
+
+ // correct for offsetX in startcell
+ $distanceX -= (int) floor(self::sizeCol($sheet, $startColumn) * $startOffsetX / 1024);
+
+ // correct for offsetX in endcell
+ $distanceX -= (int) floor(self::sizeCol($sheet, $endColumn) * (1 - $endOffsetX / 1024));
+
+ return $distanceX;
+ }
+
+ /**
+ * Get the vertical distance in pixels between two anchors
+ * The distanceY is found as sum of all the spanning rows minus two offsets
+ *
+ * @param PHPExcel_Worksheet $sheet
+ * @param integer $startRow (1-based)
+ * @param integer $startOffsetY Offset within start cell measured in 1/256 of the cell height
+ * @param integer $endRow (1-based)
+ * @param integer $endOffsetY Offset within end cell measured in 1/256 of the cell height
+ * @return integer Vertical distance measured in pixels
+ */
+ public static function getDistanceY(PHPExcel_Worksheet $sheet, $startRow = 1, $startOffsetY = 0, $endRow = 1, $endOffsetY = 0)
+ {
+ $distanceY = 0;
+
+ // add the widths of the spanning rows
+ for ($row = $startRow; $row <= $endRow; ++$row) {
+ $distanceY += self::sizeRow($sheet, $row);
+ }
+
+ // correct for offsetX in startcell
+ $distanceY -= (int) floor(self::sizeRow($sheet, $startRow) * $startOffsetY / 256);
+
+ // correct for offsetX in endcell
+ $distanceY -= (int) floor(self::sizeRow($sheet, $endRow) * (1 - $endOffsetY / 256));
+
+ return $distanceY;
+ }
+
+ /**
+ * Convert 1-cell anchor coordinates to 2-cell anchor coordinates
+ * This function is ported from PEAR Spreadsheet_Writer_Excel with small modifications
+ *
+ * Calculate the vertices that define the position of the image as required by
+ * the OBJ record.
+ *
+ * +------------+------------+
+ * | A | B |
+ * +-----+------------+------------+
+ * | |(x1,y1) | |
+ * | 1 |(A1)._______|______ |
+ * | | | | |
+ * | | | | |
+ * +-----+----| BITMAP |-----+
+ * | | | | |
+ * | 2 | |______________. |
+ * | | | (B2)|
+ * | | | (x2,y2)|
+ * +---- +------------+------------+
+ *
+ * Example of a bitmap that covers some of the area from cell A1 to cell B2.
+ *
+ * Based on the width and height of the bitmap we need to calculate 8 vars:
+ * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2.
+ * The width and height of the cells are also variable and have to be taken into
+ * account.
+ * The values of $col_start and $row_start are passed in from the calling
+ * function. The values of $col_end and $row_end are calculated by subtracting
+ * the width and height of the bitmap from the width and height of the
+ * underlying cells.
+ * The vertices are expressed as a percentage of the underlying cell width as
+ * follows (rhs values are in pixels):
+ *
+ * x1 = X / W *1024
+ * y1 = Y / H *256
+ * x2 = (X-1) / W *1024
+ * y2 = (Y-1) / H *256
+ *
+ * Where: X is distance from the left side of the underlying cell
+ * Y is distance from the top of the underlying cell
+ * W is the width of the cell
+ * H is the height of the cell
+ *
+ * @param PHPExcel_Worksheet $sheet
+ * @param string $coordinates E.g. 'A1'
+ * @param integer $offsetX Horizontal offset in pixels
+ * @param integer $offsetY Vertical offset in pixels
+ * @param integer $width Width in pixels
+ * @param integer $height Height in pixels
+ * @return array
+ */
+ public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height)
+ {
+ list($column, $row) = PHPExcel_Cell::coordinateFromString($coordinates);
+ $col_start = PHPExcel_Cell::columnIndexFromString($column) - 1;
+ $row_start = $row - 1;
+
+ $x1 = $offsetX;
+ $y1 = $offsetY;
+
+ // Initialise end cell to the same as the start cell
+ $col_end = $col_start; // Col containing lower right corner of object
+ $row_end = $row_start; // Row containing bottom right corner of object
+
+ // Zero the specified offset if greater than the cell dimensions
+ if ($x1 >= self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_start))) {
+ $x1 = 0;
+ }
+ if ($y1 >= self::sizeRow($sheet, $row_start + 1)) {
+ $y1 = 0;
+ }
+
+ $width = $width + $x1 -1;
+ $height = $height + $y1 -1;
+
+ // Subtract the underlying cell widths to find the end cell of the image
+ while ($width >= self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end))) {
+ $width -= self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end));
+ ++$col_end;
+ }
+
+ // Subtract the underlying cell heights to find the end cell of the image
+ while ($height >= self::sizeRow($sheet, $row_end + 1)) {
+ $height -= self::sizeRow($sheet, $row_end + 1);
+ ++$row_end;
+ }
+
+ // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
+ // with zero height or width.
+ if (self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_start)) == 0) {
+ return;
+ }
+ if (self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end)) == 0) {
+ return;
+ }
+ if (self::sizeRow($sheet, $row_start + 1) == 0) {
+ return;
+ }
+ if (self::sizeRow($sheet, $row_end + 1) == 0) {
+ return;
+ }
+
+ // Convert the pixel values to the percentage value expected by Excel
+ $x1 = $x1 / self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_start)) * 1024;
+ $y1 = $y1 / self::sizeRow($sheet, $row_start + 1) * 256;
+ $x2 = ($width + 1) / self::sizeCol($sheet, PHPExcel_Cell::stringFromColumnIndex($col_end)) * 1024; // Distance to right side of object
+ $y2 = ($height + 1) / self::sizeRow($sheet, $row_end + 1) * 256; // Distance to bottom of object
+
+ $startCoordinates = PHPExcel_Cell::stringFromColumnIndex($col_start) . ($row_start + 1);
+ $endCoordinates = PHPExcel_Cell::stringFromColumnIndex($col_end) . ($row_end + 1);
+
+ $twoAnchor = array(
+ 'startCoordinates' => $startCoordinates,
+ 'startOffsetX' => $x1,
+ 'startOffsetY' => $y1,
+ 'endCoordinates' => $endCoordinates,
+ 'endOffsetX' => $x2,
+ 'endOffsetY' => $y2,
+ );
+
+ return $twoAnchor;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/File.php b/extend/PHPExcel/PHPExcel/Shared/File.php
new file mode 100755
index 0000000..a62df75
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/File.php
@@ -0,0 +1,180 @@
+open($zipFile) === true) {
+ $returnValue = ($zip->getFromName($archiveFile) !== false);
+ $zip->close();
+ return $returnValue;
+ } else {
+ return false;
+ }
+ } else {
+ // Regular file_exists
+ return file_exists($pFilename);
+ }
+ }
+
+ /**
+ * Returns canonicalized absolute pathname, also for ZIP archives
+ *
+ * @param string $pFilename
+ * @return string
+ */
+ public static function realpath($pFilename)
+ {
+ // Returnvalue
+ $returnValue = '';
+
+ // Try using realpath()
+ if (file_exists($pFilename)) {
+ $returnValue = realpath($pFilename);
+ }
+
+ // Found something?
+ if ($returnValue == '' || ($returnValue === null)) {
+ $pathArray = explode('/', $pFilename);
+ while (in_array('..', $pathArray) && $pathArray[0] != '..') {
+ for ($i = 0; $i < count($pathArray); ++$i) {
+ if ($pathArray[$i] == '..' && $i > 0) {
+ unset($pathArray[$i]);
+ unset($pathArray[$i - 1]);
+ break;
+ }
+ }
+ }
+ $returnValue = implode('/', $pathArray);
+ }
+
+ // Return
+ return $returnValue;
+ }
+
+ /**
+ * Get the systems temporary directory.
+ *
+ * @return string
+ */
+ public static function sys_get_temp_dir()
+ {
+ if (self::$useUploadTempDirectory) {
+ // use upload-directory when defined to allow running on environments having very restricted
+ // open_basedir configs
+ if (ini_get('upload_tmp_dir') !== false) {
+ if ($temp = ini_get('upload_tmp_dir')) {
+ if (file_exists($temp)) {
+ return realpath($temp);
+ }
+ }
+ }
+ }
+
+ // sys_get_temp_dir is only available since PHP 5.2.1
+ // http://php.net/manual/en/function.sys-get-temp-dir.php#94119
+ if (!function_exists('sys_get_temp_dir')) {
+ if ($temp = getenv('TMP')) {
+ if ((!empty($temp)) && (file_exists($temp))) {
+ return realpath($temp);
+ }
+ }
+ if ($temp = getenv('TEMP')) {
+ if ((!empty($temp)) && (file_exists($temp))) {
+ return realpath($temp);
+ }
+ }
+ if ($temp = getenv('TMPDIR')) {
+ if ((!empty($temp)) && (file_exists($temp))) {
+ return realpath($temp);
+ }
+ }
+
+ // trick for creating a file in system's temporary dir
+ // without knowing the path of the system's temporary dir
+ $temp = tempnam(__FILE__, '');
+ if (file_exists($temp)) {
+ unlink($temp);
+ return realpath(dirname($temp));
+ }
+
+ return null;
+ }
+
+ // use ordinary built-in PHP function
+ // There should be no problem with the 5.2.4 Suhosin realpath() bug, because this line should only
+ // be called if we're running 5.2.1 or earlier
+ return realpath(sys_get_temp_dir());
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/Font.php b/extend/PHPExcel/PHPExcel/Shared/Font.php
new file mode 100755
index 0000000..7efb3c9
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/Font.php
@@ -0,0 +1,741 @@
+ array(
+ 1 => array('px' => 24, 'width' => 12.00000000),
+ 2 => array('px' => 24, 'width' => 12.00000000),
+ 3 => array('px' => 32, 'width' => 10.66406250),
+ 4 => array('px' => 32, 'width' => 10.66406250),
+ 5 => array('px' => 40, 'width' => 10.00000000),
+ 6 => array('px' => 48, 'width' => 9.59765625),
+ 7 => array('px' => 48, 'width' => 9.59765625),
+ 8 => array('px' => 56, 'width' => 9.33203125),
+ 9 => array('px' => 64, 'width' => 9.14062500),
+ 10 => array('px' => 64, 'width' => 9.14062500),
+ ),
+ 'Calibri' => array(
+ 1 => array('px' => 24, 'width' => 12.00000000),
+ 2 => array('px' => 24, 'width' => 12.00000000),
+ 3 => array('px' => 32, 'width' => 10.66406250),
+ 4 => array('px' => 32, 'width' => 10.66406250),
+ 5 => array('px' => 40, 'width' => 10.00000000),
+ 6 => array('px' => 48, 'width' => 9.59765625),
+ 7 => array('px' => 48, 'width' => 9.59765625),
+ 8 => array('px' => 56, 'width' => 9.33203125),
+ 9 => array('px' => 56, 'width' => 9.33203125),
+ 10 => array('px' => 64, 'width' => 9.14062500),
+ 11 => array('px' => 64, 'width' => 9.14062500),
+ ),
+ 'Verdana' => array(
+ 1 => array('px' => 24, 'width' => 12.00000000),
+ 2 => array('px' => 24, 'width' => 12.00000000),
+ 3 => array('px' => 32, 'width' => 10.66406250),
+ 4 => array('px' => 32, 'width' => 10.66406250),
+ 5 => array('px' => 40, 'width' => 10.00000000),
+ 6 => array('px' => 48, 'width' => 9.59765625),
+ 7 => array('px' => 48, 'width' => 9.59765625),
+ 8 => array('px' => 64, 'width' => 9.14062500),
+ 9 => array('px' => 72, 'width' => 9.00000000),
+ 10 => array('px' => 72, 'width' => 9.00000000),
+ ),
+ );
+
+ /**
+ * Set autoSize method
+ *
+ * @param string $pValue
+ * @return boolean Success or failure
+ */
+ public static function setAutoSizeMethod($pValue = self::AUTOSIZE_METHOD_APPROX)
+ {
+ if (!in_array($pValue, self::$autoSizeMethods)) {
+ return false;
+ }
+ self::$autoSizeMethod = $pValue;
+
+ return true;
+ }
+
+ /**
+ * Get autoSize method
+ *
+ * @return string
+ */
+ public static function getAutoSizeMethod()
+ {
+ return self::$autoSizeMethod;
+ }
+
+ /**
+ * Set the path to the folder containing .ttf files. There should be a trailing slash.
+ * Typical locations on variout some platforms:
+ *
+ * C:/Windows/Fonts/
+ * /usr/share/fonts/truetype/
+ * ~/.fonts/
+ *
+ *
+ * @param string $pValue
+ */
+ public static function setTrueTypeFontPath($pValue = '')
+ {
+ self::$trueTypeFontPath = $pValue;
+ }
+
+ /**
+ * Get the path to the folder containing .ttf files.
+ *
+ * @return string
+ */
+ public static function getTrueTypeFontPath()
+ {
+ return self::$trueTypeFontPath;
+ }
+
+ /**
+ * Calculate an (approximate) OpenXML column width, based on font size and text contained
+ *
+ * @param PHPExcel_Style_Font $font Font object
+ * @param PHPExcel_RichText|string $cellText Text to calculate width
+ * @param integer $rotation Rotation angle
+ * @param PHPExcel_Style_Font|NULL $defaultFont Font object
+ * @return integer Column width
+ */
+ public static function calculateColumnWidth(PHPExcel_Style_Font $font, $cellText = '', $rotation = 0, PHPExcel_Style_Font $defaultFont = null)
+ {
+ // If it is rich text, use plain text
+ if ($cellText instanceof PHPExcel_RichText) {
+ $cellText = $cellText->getPlainText();
+ }
+
+ // Special case if there are one or more newline characters ("\n")
+ if (strpos($cellText, "\n") !== false) {
+ $lineTexts = explode("\n", $cellText);
+ $lineWidths = array();
+ foreach ($lineTexts as $lineText) {
+ $lineWidths[] = self::calculateColumnWidth($font, $lineText, $rotation = 0, $defaultFont);
+ }
+ return max($lineWidths); // width of longest line in cell
+ }
+
+ // Try to get the exact text width in pixels
+ $approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX;
+ if (!$approximate) {
+ $columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07);
+ try {
+ // Width of text in pixels excl. padding
+ // and addition because Excel adds some padding, just use approx width of 'n' glyph
+ $columnWidth = self::getTextWidthPixelsExact($cellText, $font, $rotation) + $columnWidthAdjust;
+ } catch (PHPExcel_Exception $e) {
+ $approximate = true;
+ }
+ }
+
+ if ($approximate) {
+ $columnWidthAdjust = self::getTextWidthPixelsApprox('n', $font, 0);
+ // Width of text in pixels excl. padding, approximation
+ // and addition because Excel adds some padding, just use approx width of 'n' glyph
+ $columnWidth = self::getTextWidthPixelsApprox($cellText, $font, $rotation) + $columnWidthAdjust;
+ }
+
+ // Convert from pixel width to column width
+ $columnWidth = PHPExcel_Shared_Drawing::pixelsToCellDimension($columnWidth, $defaultFont);
+
+ // Return
+ return round($columnWidth, 6);
+ }
+
+ /**
+ * Get GD text width in pixels for a string of text in a certain font at a certain rotation angle
+ *
+ * @param string $text
+ * @param PHPExcel_Style_Font
+ * @param int $rotation
+ * @return int
+ * @throws PHPExcel_Exception
+ */
+ public static function getTextWidthPixelsExact($text, PHPExcel_Style_Font $font, $rotation = 0)
+ {
+ if (!function_exists('imagettfbbox')) {
+ throw new PHPExcel_Exception('GD library needs to be enabled');
+ }
+
+ // font size should really be supplied in pixels in GD2,
+ // but since GD2 seems to assume 72dpi, pixels and points are the same
+ $fontFile = self::getTrueTypeFontFileFromFont($font);
+ $textBox = imagettfbbox($font->getSize(), $rotation, $fontFile, $text);
+
+ // Get corners positions
+ $lowerLeftCornerX = $textBox[0];
+// $lowerLeftCornerY = $textBox[1];
+ $lowerRightCornerX = $textBox[2];
+// $lowerRightCornerY = $textBox[3];
+ $upperRightCornerX = $textBox[4];
+// $upperRightCornerY = $textBox[5];
+ $upperLeftCornerX = $textBox[6];
+// $upperLeftCornerY = $textBox[7];
+
+ // Consider the rotation when calculating the width
+ $textWidth = max($lowerRightCornerX - $upperLeftCornerX, $upperRightCornerX - $lowerLeftCornerX);
+
+ return $textWidth;
+ }
+
+ /**
+ * Get approximate width in pixels for a string of text in a certain font at a certain rotation angle
+ *
+ * @param string $columnText
+ * @param PHPExcel_Style_Font $font
+ * @param int $rotation
+ * @return int Text width in pixels (no padding added)
+ */
+ public static function getTextWidthPixelsApprox($columnText, PHPExcel_Style_Font $font = null, $rotation = 0)
+ {
+ $fontName = $font->getName();
+ $fontSize = $font->getSize();
+
+ // Calculate column width in pixels. We assume fixed glyph width. Result varies with font name and size.
+ switch ($fontName) {
+ case 'Calibri':
+ // value 8.26 was found via interpolation by inspecting real Excel files with Calibri 11 font.
+ $columnWidth = (int) (8.26 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
+ break;
+
+ case 'Arial':
+ // value 7 was found via interpolation by inspecting real Excel files with Arial 10 font.
+// $columnWidth = (int) (7 * PHPExcel_Shared_String::CountCharacters($columnText));
+ // value 8 was set because of experience in different exports at Arial 10 font.
+ $columnWidth = (int) (8 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
+ break;
+
+ case 'Verdana':
+ // value 8 was found via interpolation by inspecting real Excel files with Verdana 10 font.
+ $columnWidth = (int) (8 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 10; // extrapolate from font size
+ break;
+
+ default:
+ // just assume Calibri
+ $columnWidth = (int) (8.26 * PHPExcel_Shared_String::CountCharacters($columnText));
+ $columnWidth = $columnWidth * $fontSize / 11; // extrapolate from font size
+ break;
+ }
+
+ // Calculate approximate rotated column width
+ if ($rotation !== 0) {
+ if ($rotation == -165) {
+ // stacked text
+ $columnWidth = 4; // approximation
+ } else {
+ // rotated text
+ $columnWidth = $columnWidth * cos(deg2rad($rotation))
+ + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation
+ }
+ }
+
+ // pixel width is an integer
+ return (int) $columnWidth;
+ }
+
+ /**
+ * Calculate an (approximate) pixel size, based on a font points size
+ *
+ * @param int $fontSizeInPoints Font size (in points)
+ * @return int Font size (in pixels)
+ */
+ public static function fontSizeToPixels($fontSizeInPoints = 11)
+ {
+ return (int) ((4 / 3) * $fontSizeInPoints);
+ }
+
+ /**
+ * Calculate an (approximate) pixel size, based on inch size
+ *
+ * @param int $sizeInInch Font size (in inch)
+ * @return int Size (in pixels)
+ */
+ public static function inchSizeToPixels($sizeInInch = 1)
+ {
+ return ($sizeInInch * 96);
+ }
+
+ /**
+ * Calculate an (approximate) pixel size, based on centimeter size
+ *
+ * @param int $sizeInCm Font size (in centimeters)
+ * @return int Size (in pixels)
+ */
+ public static function centimeterSizeToPixels($sizeInCm = 1)
+ {
+ return ($sizeInCm * 37.795275591);
+ }
+
+ /**
+ * Returns the font path given the font
+ *
+ * @param PHPExcel_Style_Font
+ * @return string Path to TrueType font file
+ */
+ public static function getTrueTypeFontFileFromFont($font)
+ {
+ if (!file_exists(self::$trueTypeFontPath) || !is_dir(self::$trueTypeFontPath)) {
+ throw new PHPExcel_Exception('Valid directory to TrueType Font files not specified');
+ }
+
+ $name = $font->getName();
+ $bold = $font->getBold();
+ $italic = $font->getItalic();
+
+ // Check if we can map font to true type font file
+ switch ($name) {
+ case 'Arial':
+ $fontFile = (
+ $bold ? ($italic ? self::ARIAL_BOLD_ITALIC : self::ARIAL_BOLD)
+ : ($italic ? self::ARIAL_ITALIC : self::ARIAL)
+ );
+ break;
+ case 'Calibri':
+ $fontFile = (
+ $bold ? ($italic ? self::CALIBRI_BOLD_ITALIC : self::CALIBRI_BOLD)
+ : ($italic ? self::CALIBRI_ITALIC : self::CALIBRI)
+ );
+ break;
+ case 'Courier New':
+ $fontFile = (
+ $bold ? ($italic ? self::COURIER_NEW_BOLD_ITALIC : self::COURIER_NEW_BOLD)
+ : ($italic ? self::COURIER_NEW_ITALIC : self::COURIER_NEW)
+ );
+ break;
+ case 'Comic Sans MS':
+ $fontFile = (
+ $bold ? self::COMIC_SANS_MS_BOLD : self::COMIC_SANS_MS
+ );
+ break;
+ case 'Georgia':
+ $fontFile = (
+ $bold ? ($italic ? self::GEORGIA_BOLD_ITALIC : self::GEORGIA_BOLD)
+ : ($italic ? self::GEORGIA_ITALIC : self::GEORGIA)
+ );
+ break;
+ case 'Impact':
+ $fontFile = self::IMPACT;
+ break;
+ case 'Liberation Sans':
+ $fontFile = (
+ $bold ? ($italic ? self::LIBERATION_SANS_BOLD_ITALIC : self::LIBERATION_SANS_BOLD)
+ : ($italic ? self::LIBERATION_SANS_ITALIC : self::LIBERATION_SANS)
+ );
+ break;
+ case 'Lucida Console':
+ $fontFile = self::LUCIDA_CONSOLE;
+ break;
+ case 'Lucida Sans Unicode':
+ $fontFile = self::LUCIDA_SANS_UNICODE;
+ break;
+ case 'Microsoft Sans Serif':
+ $fontFile = self::MICROSOFT_SANS_SERIF;
+ break;
+ case 'Palatino Linotype':
+ $fontFile = (
+ $bold ? ($italic ? self::PALATINO_LINOTYPE_BOLD_ITALIC : self::PALATINO_LINOTYPE_BOLD)
+ : ($italic ? self::PALATINO_LINOTYPE_ITALIC : self::PALATINO_LINOTYPE)
+ );
+ break;
+ case 'Symbol':
+ $fontFile = self::SYMBOL;
+ break;
+ case 'Tahoma':
+ $fontFile = (
+ $bold ? self::TAHOMA_BOLD : self::TAHOMA
+ );
+ break;
+ case 'Times New Roman':
+ $fontFile = (
+ $bold ? ($italic ? self::TIMES_NEW_ROMAN_BOLD_ITALIC : self::TIMES_NEW_ROMAN_BOLD)
+ : ($italic ? self::TIMES_NEW_ROMAN_ITALIC : self::TIMES_NEW_ROMAN)
+ );
+ break;
+ case 'Trebuchet MS':
+ $fontFile = (
+ $bold ? ($italic ? self::TREBUCHET_MS_BOLD_ITALIC : self::TREBUCHET_MS_BOLD)
+ : ($italic ? self::TREBUCHET_MS_ITALIC : self::TREBUCHET_MS)
+ );
+ break;
+ case 'Verdana':
+ $fontFile = (
+ $bold ? ($italic ? self::VERDANA_BOLD_ITALIC : self::VERDANA_BOLD)
+ : ($italic ? self::VERDANA_ITALIC : self::VERDANA)
+ );
+ break;
+ default:
+ throw new PHPExcel_Exception('Unknown font name "'. $name .'". Cannot map to TrueType font file');
+ break;
+ }
+
+ $fontFile = self::$trueTypeFontPath . $fontFile;
+
+ // Check if file actually exists
+ if (!file_exists($fontFile)) {
+ throw new PHPExcel_Exception('TrueType Font file not found');
+ }
+
+ return $fontFile;
+ }
+
+ /**
+ * Returns the associated charset for the font name.
+ *
+ * @param string $name Font name
+ * @return int Character set code
+ */
+ public static function getCharsetFromFontName($name)
+ {
+ switch ($name) {
+ // Add more cases. Check FONT records in real Excel files.
+ case 'EucrosiaUPC':
+ return self::CHARSET_ANSI_THAI;
+ case 'Wingdings':
+ return self::CHARSET_SYMBOL;
+ case 'Wingdings 2':
+ return self::CHARSET_SYMBOL;
+ case 'Wingdings 3':
+ return self::CHARSET_SYMBOL;
+ default:
+ return self::CHARSET_ANSI_LATIN;
+ }
+ }
+
+ /**
+ * Get the effective column width for columns without a column dimension or column with width -1
+ * For example, for Calibri 11 this is 9.140625 (64 px)
+ *
+ * @param PHPExcel_Style_Font $font The workbooks default font
+ * @param boolean $pPixels true = return column width in pixels, false = return in OOXML units
+ * @return mixed Column width
+ */
+ public static function getDefaultColumnWidthByFont(PHPExcel_Style_Font $font, $pPixels = false)
+ {
+ if (isset(self::$defaultColumnWidths[$font->getName()][$font->getSize()])) {
+ // Exact width can be determined
+ $columnWidth = $pPixels ?
+ self::$defaultColumnWidths[$font->getName()][$font->getSize()]['px']
+ : self::$defaultColumnWidths[$font->getName()][$font->getSize()]['width'];
+
+ } else {
+ // We don't have data for this particular font and size, use approximation by
+ // extrapolating from Calibri 11
+ $columnWidth = $pPixels ?
+ self::$defaultColumnWidths['Calibri'][11]['px']
+ : self::$defaultColumnWidths['Calibri'][11]['width'];
+ $columnWidth = $columnWidth * $font->getSize() / 11;
+
+ // Round pixels to closest integer
+ if ($pPixels) {
+ $columnWidth = (int) round($columnWidth);
+ }
+ }
+
+ return $columnWidth;
+ }
+
+ /**
+ * Get the effective row height for rows without a row dimension or rows with height -1
+ * For example, for Calibri 11 this is 15 points
+ *
+ * @param PHPExcel_Style_Font $font The workbooks default font
+ * @return float Row height in points
+ */
+ public static function getDefaultRowHeightByFont(PHPExcel_Style_Font $font)
+ {
+ switch ($font->getName()) {
+ case 'Arial':
+ switch ($font->getSize()) {
+ case 10:
+ // inspection of Arial 10 workbook says 12.75pt ~17px
+ $rowHeight = 12.75;
+ break;
+ case 9:
+ // inspection of Arial 9 workbook says 12.00pt ~16px
+ $rowHeight = 12;
+ break;
+ case 8:
+ // inspection of Arial 8 workbook says 11.25pt ~15px
+ $rowHeight = 11.25;
+ break;
+ case 7:
+ // inspection of Arial 7 workbook says 9.00pt ~12px
+ $rowHeight = 9;
+ break;
+ case 6:
+ case 5:
+ // inspection of Arial 5,6 workbook says 8.25pt ~11px
+ $rowHeight = 8.25;
+ break;
+ case 4:
+ // inspection of Arial 4 workbook says 6.75pt ~9px
+ $rowHeight = 6.75;
+ break;
+ case 3:
+ // inspection of Arial 3 workbook says 6.00pt ~8px
+ $rowHeight = 6;
+ break;
+ case 2:
+ case 1:
+ // inspection of Arial 1,2 workbook says 5.25pt ~7px
+ $rowHeight = 5.25;
+ break;
+ default:
+ // use Arial 10 workbook as an approximation, extrapolation
+ $rowHeight = 12.75 * $font->getSize() / 10;
+ break;
+ }
+ break;
+
+ case 'Calibri':
+ switch ($font->getSize()) {
+ case 11:
+ // inspection of Calibri 11 workbook says 15.00pt ~20px
+ $rowHeight = 15;
+ break;
+ case 10:
+ // inspection of Calibri 10 workbook says 12.75pt ~17px
+ $rowHeight = 12.75;
+ break;
+ case 9:
+ // inspection of Calibri 9 workbook says 12.00pt ~16px
+ $rowHeight = 12;
+ break;
+ case 8:
+ // inspection of Calibri 8 workbook says 11.25pt ~15px
+ $rowHeight = 11.25;
+ break;
+ case 7:
+ // inspection of Calibri 7 workbook says 9.00pt ~12px
+ $rowHeight = 9;
+ break;
+ case 6:
+ case 5:
+ // inspection of Calibri 5,6 workbook says 8.25pt ~11px
+ $rowHeight = 8.25;
+ break;
+ case 4:
+ // inspection of Calibri 4 workbook says 6.75pt ~9px
+ $rowHeight = 6.75;
+ break;
+ case 3:
+ // inspection of Calibri 3 workbook says 6.00pt ~8px
+ $rowHeight = 6.00;
+ break;
+ case 2:
+ case 1:
+ // inspection of Calibri 1,2 workbook says 5.25pt ~7px
+ $rowHeight = 5.25;
+ break;
+ default:
+ // use Calibri 11 workbook as an approximation, extrapolation
+ $rowHeight = 15 * $font->getSize() / 11;
+ break;
+ }
+ break;
+
+ case 'Verdana':
+ switch ($font->getSize()) {
+ case 10:
+ // inspection of Verdana 10 workbook says 12.75pt ~17px
+ $rowHeight = 12.75;
+ break;
+ case 9:
+ // inspection of Verdana 9 workbook says 11.25pt ~15px
+ $rowHeight = 11.25;
+ break;
+ case 8:
+ // inspection of Verdana 8 workbook says 10.50pt ~14px
+ $rowHeight = 10.50;
+ break;
+ case 7:
+ // inspection of Verdana 7 workbook says 9.00pt ~12px
+ $rowHeight = 9.00;
+ break;
+ case 6:
+ case 5:
+ // inspection of Verdana 5,6 workbook says 8.25pt ~11px
+ $rowHeight = 8.25;
+ break;
+ case 4:
+ // inspection of Verdana 4 workbook says 6.75pt ~9px
+ $rowHeight = 6.75;
+ break;
+ case 3:
+ // inspection of Verdana 3 workbook says 6.00pt ~8px
+ $rowHeight = 6;
+ break;
+ case 2:
+ case 1:
+ // inspection of Verdana 1,2 workbook says 5.25pt ~7px
+ $rowHeight = 5.25;
+ break;
+ default:
+ // use Verdana 10 workbook as an approximation, extrapolation
+ $rowHeight = 12.75 * $font->getSize() / 10;
+ break;
+ }
+ break;
+ default:
+ // just use Calibri as an approximation
+ $rowHeight = 15 * $font->getSize() / 11;
+ break;
+ }
+
+ return $rowHeight;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/CHANGELOG.TXT b/extend/PHPExcel/PHPExcel/Shared/JAMA/CHANGELOG.TXT
new file mode 100755
index 0000000..1c18a5d
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/CHANGELOG.TXT
@@ -0,0 +1,16 @@
+Mar 1, 2005 11:15 AST by PM
+
++ For consistency, renamed Math.php to Maths.java, utils to util,
+ tests to test, docs to doc -
+
++ Removed conditional logic from top of Matrix class.
+
++ Switched to using hypo function in Maths.php for all php-hypot calls.
+ NOTE TO SELF: Need to make sure that all decompositions have been
+ switched over to using the bundled hypo.
+
+Feb 25, 2005 at 10:00 AST by PM
+
++ Recommend using simpler Error.php instead of JAMA_Error.php but
+ can be persuaded otherwise.
+
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/CholeskyDecomposition.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/CholeskyDecomposition.php
new file mode 100755
index 0000000..d68109b
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/CholeskyDecomposition.php
@@ -0,0 +1,148 @@
+L = $A->getArray();
+ $this->m = $A->getRowDimension();
+
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = $i; $j < $this->m; ++$j) {
+ for ($sum = $this->L[$i][$j], $k = $i - 1; $k >= 0; --$k) {
+ $sum -= $this->L[$i][$k] * $this->L[$j][$k];
+ }
+ if ($i == $j) {
+ if ($sum >= 0) {
+ $this->L[$i][$i] = sqrt($sum);
+ } else {
+ $this->isspd = false;
+ }
+ } else {
+ if ($this->L[$i][$i] != 0) {
+ $this->L[$j][$i] = $sum / $this->L[$i][$i];
+ }
+ }
+ }
+
+ for ($k = $i+1; $k < $this->m; ++$k) {
+ $this->L[$i][$k] = 0.0;
+ }
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(ARGUMENT_TYPE_EXCEPTION));
+ }
+ } // function __construct()
+
+ /**
+ * Is the matrix symmetric and positive definite?
+ *
+ * @return boolean
+ */
+ public function isSPD()
+ {
+ return $this->isspd;
+ } // function isSPD()
+
+ /**
+ * getL
+ *
+ * Return triangular factor.
+ * @return Matrix Lower triangular matrix
+ */
+ public function getL()
+ {
+ return new Matrix($this->L);
+ } // function getL()
+
+ /**
+ * Solve A*X = B
+ *
+ * @param $B Row-equal matrix
+ * @return Matrix L * L' * X = B
+ */
+ public function solve($B = null)
+ {
+ if ($B instanceof Matrix) {
+ if ($B->getRowDimension() == $this->m) {
+ if ($this->isspd) {
+ $X = $B->getArrayCopy();
+ $nx = $B->getColumnDimension();
+
+ for ($k = 0; $k < $this->m; ++$k) {
+ for ($i = $k + 1; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$i][$j] -= $X[$k][$j] * $this->L[$i][$k];
+ }
+ }
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$k][$j] /= $this->L[$k][$k];
+ }
+ }
+
+ for ($k = $this->m - 1; $k >= 0; --$k) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$k][$j] /= $this->L[$k][$k];
+ }
+ for ($i = 0; $i < $k; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$i][$j] -= $X[$k][$j] * $this->L[$k][$i];
+ }
+ }
+ }
+
+ return new Matrix($X, $this->m, $nx);
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(MatrixSPDException));
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(MATRIX_DIMENSION_EXCEPTION));
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(ARGUMENT_TYPE_EXCEPTION));
+ }
+ } // function solve()
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/EigenvalueDecomposition.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/EigenvalueDecomposition.php
new file mode 100755
index 0000000..d4ae397
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/EigenvalueDecomposition.php
@@ -0,0 +1,864 @@
+d = $this->V[$this->n-1];
+ // Householder reduction to tridiagonal form.
+ for ($i = $this->n-1; $i > 0; --$i) {
+ $i_ = $i -1;
+ // Scale to avoid under/overflow.
+ $h = $scale = 0.0;
+ $scale += array_sum(array_map(abs, $this->d));
+ if ($scale == 0.0) {
+ $this->e[$i] = $this->d[$i_];
+ $this->d = array_slice($this->V[$i_], 0, $i_);
+ for ($j = 0; $j < $i; ++$j) {
+ $this->V[$j][$i] = $this->V[$i][$j] = 0.0;
+ }
+ } else {
+ // Generate Householder vector.
+ for ($k = 0; $k < $i; ++$k) {
+ $this->d[$k] /= $scale;
+ $h += pow($this->d[$k], 2);
+ }
+ $f = $this->d[$i_];
+ $g = sqrt($h);
+ if ($f > 0) {
+ $g = -$g;
+ }
+ $this->e[$i] = $scale * $g;
+ $h = $h - $f * $g;
+ $this->d[$i_] = $f - $g;
+ for ($j = 0; $j < $i; ++$j) {
+ $this->e[$j] = 0.0;
+ }
+ // Apply similarity transformation to remaining columns.
+ for ($j = 0; $j < $i; ++$j) {
+ $f = $this->d[$j];
+ $this->V[$j][$i] = $f;
+ $g = $this->e[$j] + $this->V[$j][$j] * $f;
+ for ($k = $j+1; $k <= $i_; ++$k) {
+ $g += $this->V[$k][$j] * $this->d[$k];
+ $this->e[$k] += $this->V[$k][$j] * $f;
+ }
+ $this->e[$j] = $g;
+ }
+ $f = 0.0;
+ for ($j = 0; $j < $i; ++$j) {
+ $this->e[$j] /= $h;
+ $f += $this->e[$j] * $this->d[$j];
+ }
+ $hh = $f / (2 * $h);
+ for ($j=0; $j < $i; ++$j) {
+ $this->e[$j] -= $hh * $this->d[$j];
+ }
+ for ($j = 0; $j < $i; ++$j) {
+ $f = $this->d[$j];
+ $g = $this->e[$j];
+ for ($k = $j; $k <= $i_; ++$k) {
+ $this->V[$k][$j] -= ($f * $this->e[$k] + $g * $this->d[$k]);
+ }
+ $this->d[$j] = $this->V[$i-1][$j];
+ $this->V[$i][$j] = 0.0;
+ }
+ }
+ $this->d[$i] = $h;
+ }
+
+ // Accumulate transformations.
+ for ($i = 0; $i < $this->n-1; ++$i) {
+ $this->V[$this->n-1][$i] = $this->V[$i][$i];
+ $this->V[$i][$i] = 1.0;
+ $h = $this->d[$i+1];
+ if ($h != 0.0) {
+ for ($k = 0; $k <= $i; ++$k) {
+ $this->d[$k] = $this->V[$k][$i+1] / $h;
+ }
+ for ($j = 0; $j <= $i; ++$j) {
+ $g = 0.0;
+ for ($k = 0; $k <= $i; ++$k) {
+ $g += $this->V[$k][$i+1] * $this->V[$k][$j];
+ }
+ for ($k = 0; $k <= $i; ++$k) {
+ $this->V[$k][$j] -= $g * $this->d[$k];
+ }
+ }
+ }
+ for ($k = 0; $k <= $i; ++$k) {
+ $this->V[$k][$i+1] = 0.0;
+ }
+ }
+
+ $this->d = $this->V[$this->n-1];
+ $this->V[$this->n-1] = array_fill(0, $j, 0.0);
+ $this->V[$this->n-1][$this->n-1] = 1.0;
+ $this->e[0] = 0.0;
+ }
+
+ /**
+ * Symmetric tridiagonal QL algorithm.
+ *
+ * This is derived from the Algol procedures tql2, by
+ * Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+ * Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+ * Fortran subroutine in EISPACK.
+ *
+ * @access private
+ */
+ private function tql2()
+ {
+ for ($i = 1; $i < $this->n; ++$i) {
+ $this->e[$i-1] = $this->e[$i];
+ }
+ $this->e[$this->n-1] = 0.0;
+ $f = 0.0;
+ $tst1 = 0.0;
+ $eps = pow(2.0, -52.0);
+
+ for ($l = 0; $l < $this->n; ++$l) {
+ // Find small subdiagonal element
+ $tst1 = max($tst1, abs($this->d[$l]) + abs($this->e[$l]));
+ $m = $l;
+ while ($m < $this->n) {
+ if (abs($this->e[$m]) <= $eps * $tst1) {
+ break;
+ }
+ ++$m;
+ }
+ // If m == l, $this->d[l] is an eigenvalue,
+ // otherwise, iterate.
+ if ($m > $l) {
+ $iter = 0;
+ do {
+ // Could check iteration count here.
+ $iter += 1;
+ // Compute implicit shift
+ $g = $this->d[$l];
+ $p = ($this->d[$l+1] - $g) / (2.0 * $this->e[$l]);
+ $r = hypo($p, 1.0);
+ if ($p < 0) {
+ $r *= -1;
+ }
+ $this->d[$l] = $this->e[$l] / ($p + $r);
+ $this->d[$l+1] = $this->e[$l] * ($p + $r);
+ $dl1 = $this->d[$l+1];
+ $h = $g - $this->d[$l];
+ for ($i = $l + 2; $i < $this->n; ++$i) {
+ $this->d[$i] -= $h;
+ }
+ $f += $h;
+ // Implicit QL transformation.
+ $p = $this->d[$m];
+ $c = 1.0;
+ $c2 = $c3 = $c;
+ $el1 = $this->e[$l + 1];
+ $s = $s2 = 0.0;
+ for ($i = $m-1; $i >= $l; --$i) {
+ $c3 = $c2;
+ $c2 = $c;
+ $s2 = $s;
+ $g = $c * $this->e[$i];
+ $h = $c * $p;
+ $r = hypo($p, $this->e[$i]);
+ $this->e[$i+1] = $s * $r;
+ $s = $this->e[$i] / $r;
+ $c = $p / $r;
+ $p = $c * $this->d[$i] - $s * $g;
+ $this->d[$i+1] = $h + $s * ($c * $g + $s * $this->d[$i]);
+ // Accumulate transformation.
+ for ($k = 0; $k < $this->n; ++$k) {
+ $h = $this->V[$k][$i+1];
+ $this->V[$k][$i+1] = $s * $this->V[$k][$i] + $c * $h;
+ $this->V[$k][$i] = $c * $this->V[$k][$i] - $s * $h;
+ }
+ }
+ $p = -$s * $s2 * $c3 * $el1 * $this->e[$l] / $dl1;
+ $this->e[$l] = $s * $p;
+ $this->d[$l] = $c * $p;
+ // Check for convergence.
+ } while (abs($this->e[$l]) > $eps * $tst1);
+ }
+ $this->d[$l] = $this->d[$l] + $f;
+ $this->e[$l] = 0.0;
+ }
+
+ // Sort eigenvalues and corresponding vectors.
+ for ($i = 0; $i < $this->n - 1; ++$i) {
+ $k = $i;
+ $p = $this->d[$i];
+ for ($j = $i+1; $j < $this->n; ++$j) {
+ if ($this->d[$j] < $p) {
+ $k = $j;
+ $p = $this->d[$j];
+ }
+ }
+ if ($k != $i) {
+ $this->d[$k] = $this->d[$i];
+ $this->d[$i] = $p;
+ for ($j = 0; $j < $this->n; ++$j) {
+ $p = $this->V[$j][$i];
+ $this->V[$j][$i] = $this->V[$j][$k];
+ $this->V[$j][$k] = $p;
+ }
+ }
+ }
+ }
+
+ /**
+ * Nonsymmetric reduction to Hessenberg form.
+ *
+ * This is derived from the Algol procedures orthes and ortran,
+ * by Martin and Wilkinson, Handbook for Auto. Comp.,
+ * Vol.ii-Linear Algebra, and the corresponding
+ * Fortran subroutines in EISPACK.
+ *
+ * @access private
+ */
+ private function orthes()
+ {
+ $low = 0;
+ $high = $this->n-1;
+
+ for ($m = $low+1; $m <= $high-1; ++$m) {
+ // Scale column.
+ $scale = 0.0;
+ for ($i = $m; $i <= $high; ++$i) {
+ $scale = $scale + abs($this->H[$i][$m-1]);
+ }
+ if ($scale != 0.0) {
+ // Compute Householder transformation.
+ $h = 0.0;
+ for ($i = $high; $i >= $m; --$i) {
+ $this->ort[$i] = $this->H[$i][$m-1] / $scale;
+ $h += $this->ort[$i] * $this->ort[$i];
+ }
+ $g = sqrt($h);
+ if ($this->ort[$m] > 0) {
+ $g *= -1;
+ }
+ $h -= $this->ort[$m] * $g;
+ $this->ort[$m] -= $g;
+ // Apply Householder similarity transformation
+ // H = (I -u * u' / h) * H * (I -u * u') / h)
+ for ($j = $m; $j < $this->n; ++$j) {
+ $f = 0.0;
+ for ($i = $high; $i >= $m; --$i) {
+ $f += $this->ort[$i] * $this->H[$i][$j];
+ }
+ $f /= $h;
+ for ($i = $m; $i <= $high; ++$i) {
+ $this->H[$i][$j] -= $f * $this->ort[$i];
+ }
+ }
+ for ($i = 0; $i <= $high; ++$i) {
+ $f = 0.0;
+ for ($j = $high; $j >= $m; --$j) {
+ $f += $this->ort[$j] * $this->H[$i][$j];
+ }
+ $f = $f / $h;
+ for ($j = $m; $j <= $high; ++$j) {
+ $this->H[$i][$j] -= $f * $this->ort[$j];
+ }
+ }
+ $this->ort[$m] = $scale * $this->ort[$m];
+ $this->H[$m][$m-1] = $scale * $g;
+ }
+ }
+
+ // Accumulate transformations (Algol's ortran).
+ for ($i = 0; $i < $this->n; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $this->V[$i][$j] = ($i == $j ? 1.0 : 0.0);
+ }
+ }
+ for ($m = $high-1; $m >= $low+1; --$m) {
+ if ($this->H[$m][$m-1] != 0.0) {
+ for ($i = $m+1; $i <= $high; ++$i) {
+ $this->ort[$i] = $this->H[$i][$m-1];
+ }
+ for ($j = $m; $j <= $high; ++$j) {
+ $g = 0.0;
+ for ($i = $m; $i <= $high; ++$i) {
+ $g += $this->ort[$i] * $this->V[$i][$j];
+ }
+ // Double division avoids possible underflow
+ $g = ($g / $this->ort[$m]) / $this->H[$m][$m-1];
+ for ($i = $m; $i <= $high; ++$i) {
+ $this->V[$i][$j] += $g * $this->ort[$i];
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs complex division.
+ *
+ * @access private
+ */
+ private function cdiv($xr, $xi, $yr, $yi)
+ {
+ if (abs($yr) > abs($yi)) {
+ $r = $yi / $yr;
+ $d = $yr + $r * $yi;
+ $this->cdivr = ($xr + $r * $xi) / $d;
+ $this->cdivi = ($xi - $r * $xr) / $d;
+ } else {
+ $r = $yr / $yi;
+ $d = $yi + $r * $yr;
+ $this->cdivr = ($r * $xr + $xi) / $d;
+ $this->cdivi = ($r * $xi - $xr) / $d;
+ }
+ }
+
+ /**
+ * Nonsymmetric reduction from Hessenberg to real Schur form.
+ *
+ * Code is derived from the Algol procedure hqr2,
+ * by Martin and Wilkinson, Handbook for Auto. Comp.,
+ * Vol.ii-Linear Algebra, and the corresponding
+ * Fortran subroutine in EISPACK.
+ *
+ * @access private
+ */
+ private function hqr2()
+ {
+ // Initialize
+ $nn = $this->n;
+ $n = $nn - 1;
+ $low = 0;
+ $high = $nn - 1;
+ $eps = pow(2.0, -52.0);
+ $exshift = 0.0;
+ $p = $q = $r = $s = $z = 0;
+ // Store roots isolated by balanc and compute matrix norm
+ $norm = 0.0;
+
+ for ($i = 0; $i < $nn; ++$i) {
+ if (($i < $low) or ($i > $high)) {
+ $this->d[$i] = $this->H[$i][$i];
+ $this->e[$i] = 0.0;
+ }
+ for ($j = max($i-1, 0); $j < $nn; ++$j) {
+ $norm = $norm + abs($this->H[$i][$j]);
+ }
+ }
+
+ // Outer loop over eigenvalue index
+ $iter = 0;
+ while ($n >= $low) {
+ // Look for single small sub-diagonal element
+ $l = $n;
+ while ($l > $low) {
+ $s = abs($this->H[$l-1][$l-1]) + abs($this->H[$l][$l]);
+ if ($s == 0.0) {
+ $s = $norm;
+ }
+ if (abs($this->H[$l][$l-1]) < $eps * $s) {
+ break;
+ }
+ --$l;
+ }
+ // Check for convergence
+ // One root found
+ if ($l == $n) {
+ $this->H[$n][$n] = $this->H[$n][$n] + $exshift;
+ $this->d[$n] = $this->H[$n][$n];
+ $this->e[$n] = 0.0;
+ --$n;
+ $iter = 0;
+ // Two roots found
+ } elseif ($l == $n-1) {
+ $w = $this->H[$n][$n-1] * $this->H[$n-1][$n];
+ $p = ($this->H[$n-1][$n-1] - $this->H[$n][$n]) / 2.0;
+ $q = $p * $p + $w;
+ $z = sqrt(abs($q));
+ $this->H[$n][$n] = $this->H[$n][$n] + $exshift;
+ $this->H[$n-1][$n-1] = $this->H[$n-1][$n-1] + $exshift;
+ $x = $this->H[$n][$n];
+ // Real pair
+ if ($q >= 0) {
+ if ($p >= 0) {
+ $z = $p + $z;
+ } else {
+ $z = $p - $z;
+ }
+ $this->d[$n-1] = $x + $z;
+ $this->d[$n] = $this->d[$n-1];
+ if ($z != 0.0) {
+ $this->d[$n] = $x - $w / $z;
+ }
+ $this->e[$n-1] = 0.0;
+ $this->e[$n] = 0.0;
+ $x = $this->H[$n][$n-1];
+ $s = abs($x) + abs($z);
+ $p = $x / $s;
+ $q = $z / $s;
+ $r = sqrt($p * $p + $q * $q);
+ $p = $p / $r;
+ $q = $q / $r;
+ // Row modification
+ for ($j = $n-1; $j < $nn; ++$j) {
+ $z = $this->H[$n-1][$j];
+ $this->H[$n-1][$j] = $q * $z + $p * $this->H[$n][$j];
+ $this->H[$n][$j] = $q * $this->H[$n][$j] - $p * $z;
+ }
+ // Column modification
+ for ($i = 0; $i <= $n; ++$i) {
+ $z = $this->H[$i][$n-1];
+ $this->H[$i][$n-1] = $q * $z + $p * $this->H[$i][$n];
+ $this->H[$i][$n] = $q * $this->H[$i][$n] - $p * $z;
+ }
+ // Accumulate transformations
+ for ($i = $low; $i <= $high; ++$i) {
+ $z = $this->V[$i][$n-1];
+ $this->V[$i][$n-1] = $q * $z + $p * $this->V[$i][$n];
+ $this->V[$i][$n] = $q * $this->V[$i][$n] - $p * $z;
+ }
+ // Complex pair
+ } else {
+ $this->d[$n-1] = $x + $p;
+ $this->d[$n] = $x + $p;
+ $this->e[$n-1] = $z;
+ $this->e[$n] = -$z;
+ }
+ $n = $n - 2;
+ $iter = 0;
+ // No convergence yet
+ } else {
+ // Form shift
+ $x = $this->H[$n][$n];
+ $y = 0.0;
+ $w = 0.0;
+ if ($l < $n) {
+ $y = $this->H[$n-1][$n-1];
+ $w = $this->H[$n][$n-1] * $this->H[$n-1][$n];
+ }
+ // Wilkinson's original ad hoc shift
+ if ($iter == 10) {
+ $exshift += $x;
+ for ($i = $low; $i <= $n; ++$i) {
+ $this->H[$i][$i] -= $x;
+ }
+ $s = abs($this->H[$n][$n-1]) + abs($this->H[$n-1][$n-2]);
+ $x = $y = 0.75 * $s;
+ $w = -0.4375 * $s * $s;
+ }
+ // MATLAB's new ad hoc shift
+ if ($iter == 30) {
+ $s = ($y - $x) / 2.0;
+ $s = $s * $s + $w;
+ if ($s > 0) {
+ $s = sqrt($s);
+ if ($y < $x) {
+ $s = -$s;
+ }
+ $s = $x - $w / (($y - $x) / 2.0 + $s);
+ for ($i = $low; $i <= $n; ++$i) {
+ $this->H[$i][$i] -= $s;
+ }
+ $exshift += $s;
+ $x = $y = $w = 0.964;
+ }
+ }
+ // Could check iteration count here.
+ $iter = $iter + 1;
+ // Look for two consecutive small sub-diagonal elements
+ $m = $n - 2;
+ while ($m >= $l) {
+ $z = $this->H[$m][$m];
+ $r = $x - $z;
+ $s = $y - $z;
+ $p = ($r * $s - $w) / $this->H[$m+1][$m] + $this->H[$m][$m+1];
+ $q = $this->H[$m+1][$m+1] - $z - $r - $s;
+ $r = $this->H[$m+2][$m+1];
+ $s = abs($p) + abs($q) + abs($r);
+ $p = $p / $s;
+ $q = $q / $s;
+ $r = $r / $s;
+ if ($m == $l) {
+ break;
+ }
+ if (abs($this->H[$m][$m-1]) * (abs($q) + abs($r)) <
+ $eps * (abs($p) * (abs($this->H[$m-1][$m-1]) + abs($z) + abs($this->H[$m+1][$m+1])))) {
+ break;
+ }
+ --$m;
+ }
+ for ($i = $m + 2; $i <= $n; ++$i) {
+ $this->H[$i][$i-2] = 0.0;
+ if ($i > $m+2) {
+ $this->H[$i][$i-3] = 0.0;
+ }
+ }
+ // Double QR step involving rows l:n and columns m:n
+ for ($k = $m; $k <= $n-1; ++$k) {
+ $notlast = ($k != $n-1);
+ if ($k != $m) {
+ $p = $this->H[$k][$k-1];
+ $q = $this->H[$k+1][$k-1];
+ $r = ($notlast ? $this->H[$k+2][$k-1] : 0.0);
+ $x = abs($p) + abs($q) + abs($r);
+ if ($x != 0.0) {
+ $p = $p / $x;
+ $q = $q / $x;
+ $r = $r / $x;
+ }
+ }
+ if ($x == 0.0) {
+ break;
+ }
+ $s = sqrt($p * $p + $q * $q + $r * $r);
+ if ($p < 0) {
+ $s = -$s;
+ }
+ if ($s != 0) {
+ if ($k != $m) {
+ $this->H[$k][$k-1] = -$s * $x;
+ } elseif ($l != $m) {
+ $this->H[$k][$k-1] = -$this->H[$k][$k-1];
+ }
+ $p = $p + $s;
+ $x = $p / $s;
+ $y = $q / $s;
+ $z = $r / $s;
+ $q = $q / $p;
+ $r = $r / $p;
+ // Row modification
+ for ($j = $k; $j < $nn; ++$j) {
+ $p = $this->H[$k][$j] + $q * $this->H[$k+1][$j];
+ if ($notlast) {
+ $p = $p + $r * $this->H[$k+2][$j];
+ $this->H[$k+2][$j] = $this->H[$k+2][$j] - $p * $z;
+ }
+ $this->H[$k][$j] = $this->H[$k][$j] - $p * $x;
+ $this->H[$k+1][$j] = $this->H[$k+1][$j] - $p * $y;
+ }
+ // Column modification
+ for ($i = 0; $i <= min($n, $k+3); ++$i) {
+ $p = $x * $this->H[$i][$k] + $y * $this->H[$i][$k+1];
+ if ($notlast) {
+ $p = $p + $z * $this->H[$i][$k+2];
+ $this->H[$i][$k+2] = $this->H[$i][$k+2] - $p * $r;
+ }
+ $this->H[$i][$k] = $this->H[$i][$k] - $p;
+ $this->H[$i][$k+1] = $this->H[$i][$k+1] - $p * $q;
+ }
+ // Accumulate transformations
+ for ($i = $low; $i <= $high; ++$i) {
+ $p = $x * $this->V[$i][$k] + $y * $this->V[$i][$k+1];
+ if ($notlast) {
+ $p = $p + $z * $this->V[$i][$k+2];
+ $this->V[$i][$k+2] = $this->V[$i][$k+2] - $p * $r;
+ }
+ $this->V[$i][$k] = $this->V[$i][$k] - $p;
+ $this->V[$i][$k+1] = $this->V[$i][$k+1] - $p * $q;
+ }
+ } // ($s != 0)
+ } // k loop
+ } // check convergence
+ } // while ($n >= $low)
+
+ // Backsubstitute to find vectors of upper triangular form
+ if ($norm == 0.0) {
+ return;
+ }
+
+ for ($n = $nn-1; $n >= 0; --$n) {
+ $p = $this->d[$n];
+ $q = $this->e[$n];
+ // Real vector
+ if ($q == 0) {
+ $l = $n;
+ $this->H[$n][$n] = 1.0;
+ for ($i = $n-1; $i >= 0; --$i) {
+ $w = $this->H[$i][$i] - $p;
+ $r = 0.0;
+ for ($j = $l; $j <= $n; ++$j) {
+ $r = $r + $this->H[$i][$j] * $this->H[$j][$n];
+ }
+ if ($this->e[$i] < 0.0) {
+ $z = $w;
+ $s = $r;
+ } else {
+ $l = $i;
+ if ($this->e[$i] == 0.0) {
+ if ($w != 0.0) {
+ $this->H[$i][$n] = -$r / $w;
+ } else {
+ $this->H[$i][$n] = -$r / ($eps * $norm);
+ }
+ // Solve real equations
+ } else {
+ $x = $this->H[$i][$i+1];
+ $y = $this->H[$i+1][$i];
+ $q = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i];
+ $t = ($x * $s - $z * $r) / $q;
+ $this->H[$i][$n] = $t;
+ if (abs($x) > abs($z)) {
+ $this->H[$i+1][$n] = (-$r - $w * $t) / $x;
+ } else {
+ $this->H[$i+1][$n] = (-$s - $y * $t) / $z;
+ }
+ }
+ // Overflow control
+ $t = abs($this->H[$i][$n]);
+ if (($eps * $t) * $t > 1) {
+ for ($j = $i; $j <= $n; ++$j) {
+ $this->H[$j][$n] = $this->H[$j][$n] / $t;
+ }
+ }
+ }
+ }
+ // Complex vector
+ } elseif ($q < 0) {
+ $l = $n-1;
+ // Last vector component imaginary so matrix is triangular
+ if (abs($this->H[$n][$n-1]) > abs($this->H[$n-1][$n])) {
+ $this->H[$n-1][$n-1] = $q / $this->H[$n][$n-1];
+ $this->H[$n-1][$n] = -($this->H[$n][$n] - $p) / $this->H[$n][$n-1];
+ } else {
+ $this->cdiv(0.0, -$this->H[$n-1][$n], $this->H[$n-1][$n-1] - $p, $q);
+ $this->H[$n-1][$n-1] = $this->cdivr;
+ $this->H[$n-1][$n] = $this->cdivi;
+ }
+ $this->H[$n][$n-1] = 0.0;
+ $this->H[$n][$n] = 1.0;
+ for ($i = $n-2; $i >= 0; --$i) {
+ // double ra,sa,vr,vi;
+ $ra = 0.0;
+ $sa = 0.0;
+ for ($j = $l; $j <= $n; ++$j) {
+ $ra = $ra + $this->H[$i][$j] * $this->H[$j][$n-1];
+ $sa = $sa + $this->H[$i][$j] * $this->H[$j][$n];
+ }
+ $w = $this->H[$i][$i] - $p;
+ if ($this->e[$i] < 0.0) {
+ $z = $w;
+ $r = $ra;
+ $s = $sa;
+ } else {
+ $l = $i;
+ if ($this->e[$i] == 0) {
+ $this->cdiv(-$ra, -$sa, $w, $q);
+ $this->H[$i][$n-1] = $this->cdivr;
+ $this->H[$i][$n] = $this->cdivi;
+ } else {
+ // Solve complex equations
+ $x = $this->H[$i][$i+1];
+ $y = $this->H[$i+1][$i];
+ $vr = ($this->d[$i] - $p) * ($this->d[$i] - $p) + $this->e[$i] * $this->e[$i] - $q * $q;
+ $vi = ($this->d[$i] - $p) * 2.0 * $q;
+ if ($vr == 0.0 & $vi == 0.0) {
+ $vr = $eps * $norm * (abs($w) + abs($q) + abs($x) + abs($y) + abs($z));
+ }
+ $this->cdiv($x * $r - $z * $ra + $q * $sa, $x * $s - $z * $sa - $q * $ra, $vr, $vi);
+ $this->H[$i][$n-1] = $this->cdivr;
+ $this->H[$i][$n] = $this->cdivi;
+ if (abs($x) > (abs($z) + abs($q))) {
+ $this->H[$i+1][$n-1] = (-$ra - $w * $this->H[$i][$n-1] + $q * $this->H[$i][$n]) / $x;
+ $this->H[$i+1][$n] = (-$sa - $w * $this->H[$i][$n] - $q * $this->H[$i][$n-1]) / $x;
+ } else {
+ $this->cdiv(-$r - $y * $this->H[$i][$n-1], -$s - $y * $this->H[$i][$n], $z, $q);
+ $this->H[$i+1][$n-1] = $this->cdivr;
+ $this->H[$i+1][$n] = $this->cdivi;
+ }
+ }
+ // Overflow control
+ $t = max(abs($this->H[$i][$n-1]), abs($this->H[$i][$n]));
+ if (($eps * $t) * $t > 1) {
+ for ($j = $i; $j <= $n; ++$j) {
+ $this->H[$j][$n-1] = $this->H[$j][$n-1] / $t;
+ $this->H[$j][$n] = $this->H[$j][$n] / $t;
+ }
+ }
+ } // end else
+ } // end for
+ } // end else for complex case
+ } // end for
+
+ // Vectors of isolated roots
+ for ($i = 0; $i < $nn; ++$i) {
+ if ($i < $low | $i > $high) {
+ for ($j = $i; $j < $nn; ++$j) {
+ $this->V[$i][$j] = $this->H[$i][$j];
+ }
+ }
+ }
+
+ // Back transformation to get eigenvectors of original matrix
+ for ($j = $nn-1; $j >= $low; --$j) {
+ for ($i = $low; $i <= $high; ++$i) {
+ $z = 0.0;
+ for ($k = $low; $k <= min($j, $high); ++$k) {
+ $z = $z + $this->V[$i][$k] * $this->H[$k][$j];
+ }
+ $this->V[$i][$j] = $z;
+ }
+ }
+ } // end hqr2
+
+ /**
+ * Constructor: Check for symmetry, then construct the eigenvalue decomposition
+ *
+ * @access public
+ * @param A Square matrix
+ * @return Structure to access D and V.
+ */
+ public function __construct($Arg)
+ {
+ $this->A = $Arg->getArray();
+ $this->n = $Arg->getColumnDimension();
+
+ $issymmetric = true;
+ for ($j = 0; ($j < $this->n) & $issymmetric; ++$j) {
+ for ($i = 0; ($i < $this->n) & $issymmetric; ++$i) {
+ $issymmetric = ($this->A[$i][$j] == $this->A[$j][$i]);
+ }
+ }
+
+ if ($issymmetric) {
+ $this->V = $this->A;
+ // Tridiagonalize.
+ $this->tred2();
+ // Diagonalize.
+ $this->tql2();
+ } else {
+ $this->H = $this->A;
+ $this->ort = array();
+ // Reduce to Hessenberg form.
+ $this->orthes();
+ // Reduce Hessenberg to real Schur form.
+ $this->hqr2();
+ }
+ }
+
+ /**
+ * Return the eigenvector matrix
+ *
+ * @access public
+ * @return V
+ */
+ public function getV()
+ {
+ return new Matrix($this->V, $this->n, $this->n);
+ }
+
+ /**
+ * Return the real parts of the eigenvalues
+ *
+ * @access public
+ * @return real(diag(D))
+ */
+ public function getRealEigenvalues()
+ {
+ return $this->d;
+ }
+
+ /**
+ * Return the imaginary parts of the eigenvalues
+ *
+ * @access public
+ * @return imag(diag(D))
+ */
+ public function getImagEigenvalues()
+ {
+ return $this->e;
+ }
+
+ /**
+ * Return the block diagonal eigenvalue matrix
+ *
+ * @access public
+ * @return D
+ */
+ public function getD()
+ {
+ for ($i = 0; $i < $this->n; ++$i) {
+ $D[$i] = array_fill(0, $this->n, 0.0);
+ $D[$i][$i] = $this->d[$i];
+ if ($this->e[$i] == 0) {
+ continue;
+ }
+ $o = ($this->e[$i] > 0) ? $i + 1 : $i - 1;
+ $D[$i][$o] = $this->e[$i];
+ }
+ return new Matrix($D);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php
new file mode 100755
index 0000000..2505d92
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/LUDecomposition.php
@@ -0,0 +1,257 @@
+= n, the LU decomposition is an m-by-n
+ * unit lower triangular matrix L, an n-by-n upper triangular matrix U,
+ * and a permutation vector piv of length m so that A(piv,:) = L*U.
+ * If m < n, then L is m-by-m and U is m-by-n.
+ *
+ * The LU decompostion with pivoting always exists, even if the matrix is
+ * singular, so the constructor will never fail. The primary use of the
+ * LU decomposition is in the solution of square systems of simultaneous
+ * linear equations. This will fail if isNonsingular() returns false.
+ *
+ * @author Paul Meagher
+ * @author Bartosz Matosiuk
+ * @author Michael Bommarito
+ * @version 1.1
+ * @license PHP v3.0
+ */
+class PHPExcel_Shared_JAMA_LUDecomposition
+{
+ const MATRIX_SINGULAR_EXCEPTION = "Can only perform operation on singular matrix.";
+ const MATRIX_SQUARE_EXCEPTION = "Mismatched Row dimension";
+
+ /**
+ * Decomposition storage
+ * @var array
+ */
+ private $LU = array();
+
+ /**
+ * Row dimension.
+ * @var int
+ */
+ private $m;
+
+ /**
+ * Column dimension.
+ * @var int
+ */
+ private $n;
+
+ /**
+ * Pivot sign.
+ * @var int
+ */
+ private $pivsign;
+
+ /**
+ * Internal storage of pivot vector.
+ * @var array
+ */
+ private $piv = array();
+
+ /**
+ * LU Decomposition constructor.
+ *
+ * @param $A Rectangular matrix
+ * @return Structure to access L, U and piv.
+ */
+ public function __construct($A)
+ {
+ if ($A instanceof PHPExcel_Shared_JAMA_Matrix) {
+ // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+ $this->LU = $A->getArray();
+ $this->m = $A->getRowDimension();
+ $this->n = $A->getColumnDimension();
+ for ($i = 0; $i < $this->m; ++$i) {
+ $this->piv[$i] = $i;
+ }
+ $this->pivsign = 1;
+ $LUrowi = $LUcolj = array();
+
+ // Outer loop.
+ for ($j = 0; $j < $this->n; ++$j) {
+ // Make a copy of the j-th column to localize references.
+ for ($i = 0; $i < $this->m; ++$i) {
+ $LUcolj[$i] = &$this->LU[$i][$j];
+ }
+ // Apply previous transformations.
+ for ($i = 0; $i < $this->m; ++$i) {
+ $LUrowi = $this->LU[$i];
+ // Most of the time is spent in the following dot product.
+ $kmax = min($i, $j);
+ $s = 0.0;
+ for ($k = 0; $k < $kmax; ++$k) {
+ $s += $LUrowi[$k] * $LUcolj[$k];
+ }
+ $LUrowi[$j] = $LUcolj[$i] -= $s;
+ }
+ // Find pivot and exchange if necessary.
+ $p = $j;
+ for ($i = $j+1; $i < $this->m; ++$i) {
+ if (abs($LUcolj[$i]) > abs($LUcolj[$p])) {
+ $p = $i;
+ }
+ }
+ if ($p != $j) {
+ for ($k = 0; $k < $this->n; ++$k) {
+ $t = $this->LU[$p][$k];
+ $this->LU[$p][$k] = $this->LU[$j][$k];
+ $this->LU[$j][$k] = $t;
+ }
+ $k = $this->piv[$p];
+ $this->piv[$p] = $this->piv[$j];
+ $this->piv[$j] = $k;
+ $this->pivsign = $this->pivsign * -1;
+ }
+ // Compute multipliers.
+ if (($j < $this->m) && ($this->LU[$j][$j] != 0.0)) {
+ for ($i = $j+1; $i < $this->m; ++$i) {
+ $this->LU[$i][$j] /= $this->LU[$j][$j];
+ }
+ }
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(PHPExcel_Shared_JAMA_Matrix::ARGUMENT_TYPE_EXCEPTION);
+ }
+ } // function __construct()
+
+ /**
+ * Get lower triangular factor.
+ *
+ * @return array Lower triangular factor
+ */
+ public function getL()
+ {
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ if ($i > $j) {
+ $L[$i][$j] = $this->LU[$i][$j];
+ } elseif ($i == $j) {
+ $L[$i][$j] = 1.0;
+ } else {
+ $L[$i][$j] = 0.0;
+ }
+ }
+ }
+ return new PHPExcel_Shared_JAMA_Matrix($L);
+ } // function getL()
+
+ /**
+ * Get upper triangular factor.
+ *
+ * @return array Upper triangular factor
+ */
+ public function getU()
+ {
+ for ($i = 0; $i < $this->n; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ if ($i <= $j) {
+ $U[$i][$j] = $this->LU[$i][$j];
+ } else {
+ $U[$i][$j] = 0.0;
+ }
+ }
+ }
+ return new PHPExcel_Shared_JAMA_Matrix($U);
+ } // function getU()
+
+ /**
+ * Return pivot permutation vector.
+ *
+ * @return array Pivot vector
+ */
+ public function getPivot()
+ {
+ return $this->piv;
+ } // function getPivot()
+
+ /**
+ * Alias for getPivot
+ *
+ * @see getPivot
+ */
+ public function getDoublePivot()
+ {
+ return $this->getPivot();
+ } // function getDoublePivot()
+
+ /**
+ * Is the matrix nonsingular?
+ *
+ * @return true if U, and hence A, is nonsingular.
+ */
+ public function isNonsingular()
+ {
+ for ($j = 0; $j < $this->n; ++$j) {
+ if ($this->LU[$j][$j] == 0) {
+ return false;
+ }
+ }
+ return true;
+ } // function isNonsingular()
+
+ /**
+ * Count determinants
+ *
+ * @return array d matrix deterninat
+ */
+ public function det()
+ {
+ if ($this->m == $this->n) {
+ $d = $this->pivsign;
+ for ($j = 0; $j < $this->n; ++$j) {
+ $d *= $this->LU[$j][$j];
+ }
+ return $d;
+ } else {
+ throw new PHPExcel_Calculation_Exception(PHPExcel_Shared_JAMA_Matrix::MATRIX_DIMENSION_EXCEPTION);
+ }
+ } // function det()
+
+ /**
+ * Solve A*X = B
+ *
+ * @param $B A Matrix with as many rows as A and any number of columns.
+ * @return X so that L*U*X = B(piv,:)
+ * @PHPExcel_Calculation_Exception IllegalArgumentException Matrix row dimensions must agree.
+ * @PHPExcel_Calculation_Exception RuntimeException Matrix is singular.
+ */
+ public function solve($B)
+ {
+ if ($B->getRowDimension() == $this->m) {
+ if ($this->isNonsingular()) {
+ // Copy right hand side with pivoting
+ $nx = $B->getColumnDimension();
+ $X = $B->getMatrix($this->piv, 0, $nx-1);
+ // Solve L*Y = B(piv,:)
+ for ($k = 0; $k < $this->n; ++$k) {
+ for ($i = $k+1; $i < $this->n; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
+ }
+ }
+ }
+ // Solve U*X = Y;
+ for ($k = $this->n-1; $k >= 0; --$k) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X->A[$k][$j] /= $this->LU[$k][$k];
+ }
+ for ($i = 0; $i < $k; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X->A[$i][$j] -= $X->A[$k][$j] * $this->LU[$i][$k];
+ }
+ }
+ }
+ return $X;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::MATRIX_SINGULAR_EXCEPTION);
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::MATRIX_SQUARE_EXCEPTION);
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php
new file mode 100755
index 0000000..82fb0fb
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/Matrix.php
@@ -0,0 +1,1159 @@
+ 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ //Rectangular matrix - m x n initialized from 2D array
+ case 'array':
+ $this->m = count($args[0]);
+ $this->n = count($args[0][0]);
+ $this->A = $args[0];
+ break;
+ //Square matrix - n x n
+ case 'integer':
+ $this->m = $args[0];
+ $this->n = $args[0];
+ $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0));
+ break;
+ //Rectangular matrix - m x n
+ case 'integer,integer':
+ $this->m = $args[0];
+ $this->n = $args[1];
+ $this->A = array_fill(0, $this->m, array_fill(0, $this->n, 0));
+ break;
+ //Rectangular matrix - m x n initialized from packed array
+ case 'array,integer':
+ $this->m = $args[1];
+ if ($this->m != 0) {
+ $this->n = count($args[0]) / $this->m;
+ } else {
+ $this->n = 0;
+ }
+ if (($this->m * $this->n) == count($args[0])) {
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $this->A[$i][$j] = $args[0][$i + $j * $this->m];
+ }
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARRAY_LENGTH_EXCEPTION);
+ }
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * getArray
+ *
+ * @return array Matrix array
+ */
+ public function getArray()
+ {
+ return $this->A;
+ }
+
+ /**
+ * getRowDimension
+ *
+ * @return int Row dimension
+ */
+ public function getRowDimension()
+ {
+ return $this->m;
+ }
+
+ /**
+ * getColumnDimension
+ *
+ * @return int Column dimension
+ */
+ public function getColumnDimension()
+ {
+ return $this->n;
+ }
+
+ /**
+ * get
+ *
+ * Get the i,j-th element of the matrix.
+ * @param int $i Row position
+ * @param int $j Column position
+ * @return mixed Element (int/float/double)
+ */
+ public function get($i = null, $j = null)
+ {
+ return $this->A[$i][$j];
+ }
+
+ /**
+ * getMatrix
+ *
+ * Get a submatrix
+ * @param int $i0 Initial row index
+ * @param int $iF Final row index
+ * @param int $j0 Initial column index
+ * @param int $jF Final column index
+ * @return Matrix Submatrix
+ */
+ public function getMatrix()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ //A($i0...; $j0...)
+ case 'integer,integer':
+ list($i0, $j0) = $args;
+ if ($i0 >= 0) {
+ $m = $this->m - $i0;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ if ($j0 >= 0) {
+ $n = $this->n - $j0;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
+ for ($i = $i0; $i < $this->m; ++$i) {
+ for ($j = $j0; $j < $this->n; ++$j) {
+ $R->set($i, $j, $this->A[$i][$j]);
+ }
+ }
+ return $R;
+ break;
+ //A($i0...$iF; $j0...$jF)
+ case 'integer,integer,integer,integer':
+ list($i0, $iF, $j0, $jF) = $args;
+ if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
+ $m = $iF - $i0;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ if (($jF > $j0) && ($this->n >= $jF) && ($j0 >= 0)) {
+ $n = $jF - $j0;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ $R = new PHPExcel_Shared_JAMA_Matrix($m+1, $n+1);
+ for ($i = $i0; $i <= $iF; ++$i) {
+ for ($j = $j0; $j <= $jF; ++$j) {
+ $R->set($i - $i0, $j - $j0, $this->A[$i][$j]);
+ }
+ }
+ return $R;
+ break;
+ //$R = array of row indices; $C = array of column indices
+ case 'array,array':
+ list($RL, $CL) = $args;
+ if (count($RL) > 0) {
+ $m = count($RL);
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ if (count($CL) > 0) {
+ $n = count($CL);
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
+ for ($i = 0; $i < $m; ++$i) {
+ for ($j = 0; $j < $n; ++$j) {
+ $R->set($i - $i0, $j - $j0, $this->A[$RL[$i]][$CL[$j]]);
+ }
+ }
+ return $R;
+ break;
+ //$RL = array of row indices; $CL = array of column indices
+ case 'array,array':
+ list($RL, $CL) = $args;
+ if (count($RL) > 0) {
+ $m = count($RL);
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ if (count($CL) > 0) {
+ $n = count($CL);
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
+ for ($i = 0; $i < $m; ++$i) {
+ for ($j = 0; $j < $n; ++$j) {
+ $R->set($i, $j, $this->A[$RL[$i]][$CL[$j]]);
+ }
+ }
+ return $R;
+ break;
+ //A($i0...$iF); $CL = array of column indices
+ case 'integer,integer,array':
+ list($i0, $iF, $CL) = $args;
+ if (($iF > $i0) && ($this->m >= $iF) && ($i0 >= 0)) {
+ $m = $iF - $i0;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ if (count($CL) > 0) {
+ $n = count($CL);
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
+ for ($i = $i0; $i < $iF; ++$i) {
+ for ($j = 0; $j < $n; ++$j) {
+ $R->set($i - $i0, $j, $this->A[$RL[$i]][$j]);
+ }
+ }
+ return $R;
+ break;
+ //$RL = array of row indices
+ case 'array,integer,integer':
+ list($RL, $j0, $jF) = $args;
+ if (count($RL) > 0) {
+ $m = count($RL);
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ if (($jF >= $j0) && ($this->n >= $jF) && ($j0 >= 0)) {
+ $n = $jF - $j0;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_BOUNDS_EXCEPTION);
+ }
+ $R = new PHPExcel_Shared_JAMA_Matrix($m, $n+1);
+ for ($i = 0; $i < $m; ++$i) {
+ for ($j = $j0; $j <= $jF; ++$j) {
+ $R->set($i, $j - $j0, $this->A[$RL[$i]][$j]);
+ }
+ }
+ return $R;
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * checkMatrixDimensions
+ *
+ * Is matrix B the same size?
+ * @param Matrix $B Matrix B
+ * @return boolean
+ */
+ public function checkMatrixDimensions($B = null)
+ {
+ if ($B instanceof PHPExcel_Shared_JAMA_Matrix) {
+ if (($this->m == $B->getRowDimension()) && ($this->n == $B->getColumnDimension())) {
+ return true;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::MATRIX_DIMENSION_EXCEPTION);
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ } // function checkMatrixDimensions()
+
+ /**
+ * set
+ *
+ * Set the i,j-th element of the matrix.
+ * @param int $i Row position
+ * @param int $j Column position
+ * @param mixed $c Int/float/double value
+ * @return mixed Element (int/float/double)
+ */
+ public function set($i = null, $j = null, $c = null)
+ {
+ // Optimized set version just has this
+ $this->A[$i][$j] = $c;
+ } // function set()
+
+ /**
+ * identity
+ *
+ * Generate an identity matrix.
+ * @param int $m Row dimension
+ * @param int $n Column dimension
+ * @return Matrix Identity matrix
+ */
+ public function identity($m = null, $n = null)
+ {
+ return $this->diagonal($m, $n, 1);
+ }
+
+ /**
+ * diagonal
+ *
+ * Generate a diagonal matrix
+ * @param int $m Row dimension
+ * @param int $n Column dimension
+ * @param mixed $c Diagonal value
+ * @return Matrix Diagonal matrix
+ */
+ public function diagonal($m = null, $n = null, $c = 1)
+ {
+ $R = new PHPExcel_Shared_JAMA_Matrix($m, $n);
+ for ($i = 0; $i < $m; ++$i) {
+ $R->set($i, $i, $c);
+ }
+ return $R;
+ }
+
+ /**
+ * getMatrixByRow
+ *
+ * Get a submatrix by row index/range
+ * @param int $i0 Initial row index
+ * @param int $iF Final row index
+ * @return Matrix Submatrix
+ */
+ public function getMatrixByRow($i0 = null, $iF = null)
+ {
+ if (is_int($i0)) {
+ if (is_int($iF)) {
+ return $this->getMatrix($i0, 0, $iF + 1, $this->n);
+ } else {
+ return $this->getMatrix($i0, 0, $i0 + 1, $this->n);
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ }
+
+ /**
+ * getMatrixByCol
+ *
+ * Get a submatrix by column index/range
+ * @param int $i0 Initial column index
+ * @param int $iF Final column index
+ * @return Matrix Submatrix
+ */
+ public function getMatrixByCol($j0 = null, $jF = null)
+ {
+ if (is_int($j0)) {
+ if (is_int($jF)) {
+ return $this->getMatrix(0, $j0, $this->m, $jF + 1);
+ } else {
+ return $this->getMatrix(0, $j0, $this->m, $j0 + 1);
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ }
+
+ /**
+ * transpose
+ *
+ * Tranpose matrix
+ * @return Matrix Transposed matrix
+ */
+ public function transpose()
+ {
+ $R = new PHPExcel_Shared_JAMA_Matrix($this->n, $this->m);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $R->set($j, $i, $this->A[$i][$j]);
+ }
+ }
+ return $R;
+ } // function transpose()
+
+ /**
+ * trace
+ *
+ * Sum of diagonal elements
+ * @return float Sum of diagonal elements
+ */
+ public function trace()
+ {
+ $s = 0;
+ $n = min($this->m, $this->n);
+ for ($i = 0; $i < $n; ++$i) {
+ $s += $this->A[$i][$i];
+ }
+ return $s;
+ }
+
+ /**
+ * uminus
+ *
+ * Unary minus matrix -A
+ * @return Matrix Unary minus matrix
+ */
+ public function uminus()
+ {
+ }
+
+ /**
+ * plus
+ *
+ * A + B
+ * @param mixed $B Matrix/Array
+ * @return Matrix Sum
+ */
+ public function plus()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $M->set($i, $j, $M->get($i, $j) + $this->A[$i][$j]);
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * plusEquals
+ *
+ * A = A + B
+ * @param mixed $B Matrix/Array
+ * @return Matrix Sum
+ */
+ public function plusEquals()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $validValues = true;
+ $value = $M->get($i, $j);
+ if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
+ $this->A[$i][$j] = trim($this->A[$i][$j], '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
+ }
+ if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
+ $value = trim($value, '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
+ }
+ if ($validValues) {
+ $this->A[$i][$j] += $value;
+ } else {
+ $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+ }
+ return $this;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * minus
+ *
+ * A - B
+ * @param mixed $B Matrix/Array
+ * @return Matrix Sum
+ */
+ public function minus()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $M->set($i, $j, $M->get($i, $j) - $this->A[$i][$j]);
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * minusEquals
+ *
+ * A = A - B
+ * @param mixed $B Matrix/Array
+ * @return Matrix Sum
+ */
+ public function minusEquals()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $validValues = true;
+ $value = $M->get($i, $j);
+ if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
+ $this->A[$i][$j] = trim($this->A[$i][$j], '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
+ }
+ if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
+ $value = trim($value, '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
+ }
+ if ($validValues) {
+ $this->A[$i][$j] -= $value;
+ } else {
+ $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+ }
+ return $this;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * arrayTimes
+ *
+ * Element-by-element multiplication
+ * Cij = Aij * Bij
+ * @param mixed $B Matrix/Array
+ * @return Matrix Matrix Cij
+ */
+ public function arrayTimes()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $M->set($i, $j, $M->get($i, $j) * $this->A[$i][$j]);
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * arrayTimesEquals
+ *
+ * Element-by-element multiplication
+ * Aij = Aij * Bij
+ * @param mixed $B Matrix/Array
+ * @return Matrix Matrix Aij
+ */
+ public function arrayTimesEquals()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $validValues = true;
+ $value = $M->get($i, $j);
+ if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
+ $this->A[$i][$j] = trim($this->A[$i][$j], '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
+ }
+ if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
+ $value = trim($value, '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
+ }
+ if ($validValues) {
+ $this->A[$i][$j] *= $value;
+ } else {
+ $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+ }
+ return $this;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * arrayRightDivide
+ *
+ * Element-by-element right division
+ * A / B
+ * @param Matrix $B Matrix B
+ * @return Matrix Division result
+ */
+ public function arrayRightDivide()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $validValues = true;
+ $value = $M->get($i, $j);
+ if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
+ $this->A[$i][$j] = trim($this->A[$i][$j], '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
+ }
+ if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
+ $value = trim($value, '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
+ }
+ if ($validValues) {
+ if ($value == 0) {
+ // Trap for Divide by Zero error
+ $M->set($i, $j, '#DIV/0!');
+ } else {
+ $M->set($i, $j, $this->A[$i][$j] / $value);
+ }
+ } else {
+ $M->set($i, $j, PHPExcel_Calculation_Functions::NaN());
+ }
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+
+ /**
+ * arrayRightDivideEquals
+ *
+ * Element-by-element right division
+ * Aij = Aij / Bij
+ * @param mixed $B Matrix/Array
+ * @return Matrix Matrix Aij
+ */
+ public function arrayRightDivideEquals()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $this->A[$i][$j] = $this->A[$i][$j] / $M->get($i, $j);
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+
+ /**
+ * arrayLeftDivide
+ *
+ * Element-by-element Left division
+ * A / B
+ * @param Matrix $B Matrix B
+ * @return Matrix Division result
+ */
+ public function arrayLeftDivide()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $M->set($i, $j, $M->get($i, $j) / $this->A[$i][$j]);
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+
+ /**
+ * arrayLeftDivideEquals
+ *
+ * Element-by-element Left division
+ * Aij = Aij / Bij
+ * @param mixed $B Matrix/Array
+ * @return Matrix Matrix Aij
+ */
+ public function arrayLeftDivideEquals()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $this->A[$i][$j] = $M->get($i, $j) / $this->A[$i][$j];
+ }
+ }
+ return $M;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+
+ /**
+ * times
+ *
+ * Matrix multiplication
+ * @param mixed $n Matrix/Array/Scalar
+ * @return Matrix Product
+ */
+ public function times()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $B = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ if ($this->n == $B->m) {
+ $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $B->n);
+ for ($j = 0; $j < $B->n; ++$j) {
+ for ($k = 0; $k < $this->n; ++$k) {
+ $Bcolj[$k] = $B->A[$k][$j];
+ }
+ for ($i = 0; $i < $this->m; ++$i) {
+ $Arowi = $this->A[$i];
+ $s = 0;
+ for ($k = 0; $k < $this->n; ++$k) {
+ $s += $Arowi[$k] * $Bcolj[$k];
+ }
+ $C->A[$i][$j] = $s;
+ }
+ }
+ return $C;
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(MatrixDimensionMismatch));
+ }
+ break;
+ case 'array':
+ $B = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ if ($this->n == $B->m) {
+ $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $B->n);
+ for ($i = 0; $i < $C->m; ++$i) {
+ for ($j = 0; $j < $C->n; ++$j) {
+ $s = "0";
+ for ($k = 0; $k < $C->n; ++$k) {
+ $s += $this->A[$i][$k] * $B->A[$k][$j];
+ }
+ $C->A[$i][$j] = $s;
+ }
+ }
+ return $C;
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(MatrixDimensionMismatch));
+ }
+ return $M;
+ break;
+ case 'integer':
+ $C = new PHPExcel_Shared_JAMA_Matrix($this->A);
+ for ($i = 0; $i < $C->m; ++$i) {
+ for ($j = 0; $j < $C->n; ++$j) {
+ $C->A[$i][$j] *= $args[0];
+ }
+ }
+ return $C;
+ break;
+ case 'double':
+ $C = new PHPExcel_Shared_JAMA_Matrix($this->m, $this->n);
+ for ($i = 0; $i < $C->m; ++$i) {
+ for ($j = 0; $j < $C->n; ++$j) {
+ $C->A[$i][$j] = $args[0] * $this->A[$i][$j];
+ }
+ }
+ return $C;
+ break;
+ case 'float':
+ $C = new PHPExcel_Shared_JAMA_Matrix($this->A);
+ for ($i = 0; $i < $C->m; ++$i) {
+ for ($j = 0; $j < $C->n; ++$j) {
+ $C->A[$i][$j] *= $args[0];
+ }
+ }
+ return $C;
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * power
+ *
+ * A = A ^ B
+ * @param mixed $B Matrix/Array
+ * @return Matrix Sum
+ */
+ public function power()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ break;
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $validValues = true;
+ $value = $M->get($i, $j);
+ if ((is_string($this->A[$i][$j])) && (strlen($this->A[$i][$j]) > 0) && (!is_numeric($this->A[$i][$j]))) {
+ $this->A[$i][$j] = trim($this->A[$i][$j], '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($this->A[$i][$j]);
+ }
+ if ((is_string($value)) && (strlen($value) > 0) && (!is_numeric($value))) {
+ $value = trim($value, '"');
+ $validValues &= PHPExcel_Shared_String::convertToNumberIfFraction($value);
+ }
+ if ($validValues) {
+ $this->A[$i][$j] = pow($this->A[$i][$j], $value);
+ } else {
+ $this->A[$i][$j] = PHPExcel_Calculation_Functions::NaN();
+ }
+ }
+ }
+ return $this;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * concat
+ *
+ * A = A & B
+ * @param mixed $B Matrix/Array
+ * @return Matrix Sum
+ */
+ public function concat()
+ {
+ if (func_num_args() > 0) {
+ $args = func_get_args();
+ $match = implode(",", array_map('gettype', $args));
+
+ switch ($match) {
+ case 'object':
+ if ($args[0] instanceof PHPExcel_Shared_JAMA_Matrix) {
+ $M = $args[0];
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::ARGUMENT_TYPE_EXCEPTION);
+ }
+ case 'array':
+ $M = new PHPExcel_Shared_JAMA_Matrix($args[0]);
+ break;
+ default:
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ break;
+ }
+ $this->checkMatrixDimensions($M);
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $this->A[$i][$j] = trim($this->A[$i][$j], '"').trim($M->get($i, $j), '"');
+ }
+ }
+ return $this;
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::POLYMORPHIC_ARGUMENT_EXCEPTION);
+ }
+ }
+
+ /**
+ * Solve A*X = B.
+ *
+ * @param Matrix $B Right hand side
+ * @return Matrix ... Solution if A is square, least squares solution otherwise
+ */
+ public function solve($B)
+ {
+ if ($this->m == $this->n) {
+ $LU = new PHPExcel_Shared_JAMA_LUDecomposition($this);
+ return $LU->solve($B);
+ } else {
+ $QR = new PHPExcel_Shared_JAMA_QRDecomposition($this);
+ return $QR->solve($B);
+ }
+ }
+
+ /**
+ * Matrix inverse or pseudoinverse.
+ *
+ * @return Matrix ... Inverse(A) if A is square, pseudoinverse otherwise.
+ */
+ public function inverse()
+ {
+ return $this->solve($this->identity($this->m, $this->m));
+ }
+
+ /**
+ * det
+ *
+ * Calculate determinant
+ * @return float Determinant
+ */
+ public function det()
+ {
+ $L = new PHPExcel_Shared_JAMA_LUDecomposition($this);
+ return $L->det();
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php
new file mode 100755
index 0000000..1e43c7c
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/QRDecomposition.php
@@ -0,0 +1,235 @@
+= n, the QR decomposition is an m-by-n
+ * orthogonal matrix Q and an n-by-n upper triangular matrix R so that
+ * A = Q*R.
+ *
+ * The QR decompostion always exists, even if the matrix does not have
+ * full rank, so the constructor will never fail. The primary use of the
+ * QR decomposition is in the least squares solution of nonsquare systems
+ * of simultaneous linear equations. This will fail if isFullRank()
+ * returns false.
+ *
+ * @author Paul Meagher
+ * @license PHP v3.0
+ * @version 1.1
+ */
+class PHPExcel_Shared_JAMA_QRDecomposition
+{
+ const MATRIX_RANK_EXCEPTION = "Can only perform operation on full-rank matrix.";
+
+ /**
+ * Array for internal storage of decomposition.
+ * @var array
+ */
+ private $QR = array();
+
+ /**
+ * Row dimension.
+ * @var integer
+ */
+ private $m;
+
+ /**
+ * Column dimension.
+ * @var integer
+ */
+ private $n;
+
+ /**
+ * Array for internal storage of diagonal of R.
+ * @var array
+ */
+ private $Rdiag = array();
+
+
+ /**
+ * QR Decomposition computed by Householder reflections.
+ *
+ * @param matrix $A Rectangular matrix
+ * @return Structure to access R and the Householder vectors and compute Q.
+ */
+ public function __construct($A)
+ {
+ if ($A instanceof PHPExcel_Shared_JAMA_Matrix) {
+ // Initialize.
+ $this->QR = $A->getArrayCopy();
+ $this->m = $A->getRowDimension();
+ $this->n = $A->getColumnDimension();
+ // Main loop.
+ for ($k = 0; $k < $this->n; ++$k) {
+ // Compute 2-norm of k-th column without under/overflow.
+ $nrm = 0.0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $nrm = hypo($nrm, $this->QR[$i][$k]);
+ }
+ if ($nrm != 0.0) {
+ // Form k-th Householder vector.
+ if ($this->QR[$k][$k] < 0) {
+ $nrm = -$nrm;
+ }
+ for ($i = $k; $i < $this->m; ++$i) {
+ $this->QR[$i][$k] /= $nrm;
+ }
+ $this->QR[$k][$k] += 1.0;
+ // Apply transformation to remaining columns.
+ for ($j = $k+1; $j < $this->n; ++$j) {
+ $s = 0.0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $s += $this->QR[$i][$k] * $this->QR[$i][$j];
+ }
+ $s = -$s/$this->QR[$k][$k];
+ for ($i = $k; $i < $this->m; ++$i) {
+ $this->QR[$i][$j] += $s * $this->QR[$i][$k];
+ }
+ }
+ }
+ $this->Rdiag[$k] = -$nrm;
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(PHPExcel_Shared_JAMA_Matrix::ARGUMENT_TYPE_EXCEPTION);
+ }
+ } // function __construct()
+
+
+ /**
+ * Is the matrix full rank?
+ *
+ * @return boolean true if R, and hence A, has full rank, else false.
+ */
+ public function isFullRank()
+ {
+ for ($j = 0; $j < $this->n; ++$j) {
+ if ($this->Rdiag[$j] == 0) {
+ return false;
+ }
+ }
+ return true;
+ } // function isFullRank()
+
+ /**
+ * Return the Householder vectors
+ *
+ * @return Matrix Lower trapezoidal matrix whose columns define the reflections
+ */
+ public function getH()
+ {
+ for ($i = 0; $i < $this->m; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ if ($i >= $j) {
+ $H[$i][$j] = $this->QR[$i][$j];
+ } else {
+ $H[$i][$j] = 0.0;
+ }
+ }
+ }
+ return new PHPExcel_Shared_JAMA_Matrix($H);
+ } // function getH()
+
+ /**
+ * Return the upper triangular factor
+ *
+ * @return Matrix upper triangular factor
+ */
+ public function getR()
+ {
+ for ($i = 0; $i < $this->n; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ if ($i < $j) {
+ $R[$i][$j] = $this->QR[$i][$j];
+ } elseif ($i == $j) {
+ $R[$i][$j] = $this->Rdiag[$i];
+ } else {
+ $R[$i][$j] = 0.0;
+ }
+ }
+ }
+ return new PHPExcel_Shared_JAMA_Matrix($R);
+ } // function getR()
+
+ /**
+ * Generate and return the (economy-sized) orthogonal factor
+ *
+ * @return Matrix orthogonal factor
+ */
+ public function getQ()
+ {
+ for ($k = $this->n-1; $k >= 0; --$k) {
+ for ($i = 0; $i < $this->m; ++$i) {
+ $Q[$i][$k] = 0.0;
+ }
+ $Q[$k][$k] = 1.0;
+ for ($j = $k; $j < $this->n; ++$j) {
+ if ($this->QR[$k][$k] != 0) {
+ $s = 0.0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $s += $this->QR[$i][$k] * $Q[$i][$j];
+ }
+ $s = -$s/$this->QR[$k][$k];
+ for ($i = $k; $i < $this->m; ++$i) {
+ $Q[$i][$j] += $s * $this->QR[$i][$k];
+ }
+ }
+ }
+ }
+ /*
+ for($i = 0; $i < count($Q); ++$i) {
+ for($j = 0; $j < count($Q); ++$j) {
+ if (! isset($Q[$i][$j]) ) {
+ $Q[$i][$j] = 0;
+ }
+ }
+ }
+ */
+ return new PHPExcel_Shared_JAMA_Matrix($Q);
+ } // function getQ()
+
+ /**
+ * Least squares solution of A*X = B
+ *
+ * @param Matrix $B A Matrix with as many rows as A and any number of columns.
+ * @return Matrix Matrix that minimizes the two norm of Q*R*X-B.
+ */
+ public function solve($B)
+ {
+ if ($B->getRowDimension() == $this->m) {
+ if ($this->isFullRank()) {
+ // Copy right hand side
+ $nx = $B->getColumnDimension();
+ $X = $B->getArrayCopy();
+ // Compute Y = transpose(Q)*B
+ for ($k = 0; $k < $this->n; ++$k) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $s = 0.0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $s += $this->QR[$i][$k] * $X[$i][$j];
+ }
+ $s = -$s/$this->QR[$k][$k];
+ for ($i = $k; $i < $this->m; ++$i) {
+ $X[$i][$j] += $s * $this->QR[$i][$k];
+ }
+ }
+ }
+ // Solve R*X = Y;
+ for ($k = $this->n-1; $k >= 0; --$k) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$k][$j] /= $this->Rdiag[$k];
+ }
+ for ($i = 0; $i < $k; ++$i) {
+ for ($j = 0; $j < $nx; ++$j) {
+ $X[$i][$j] -= $X[$k][$j]* $this->QR[$i][$k];
+ }
+ }
+ }
+ $X = new PHPExcel_Shared_JAMA_Matrix($X);
+ return ($X->getMatrix(0, $this->n-1, 0, $nx));
+ } else {
+ throw new PHPExcel_Calculation_Exception(self::MATRIX_RANK_EXCEPTION);
+ }
+ } else {
+ throw new PHPExcel_Calculation_Exception(PHPExcel_Shared_JAMA_Matrix::MATRIX_DIMENSION_EXCEPTION);
+ }
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/SingularValueDecomposition.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/SingularValueDecomposition.php
new file mode 100755
index 0000000..f57d122
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/SingularValueDecomposition.php
@@ -0,0 +1,528 @@
+= n, the singular value decomposition is
+ * an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
+ * an n-by-n orthogonal matrix V so that A = U*S*V'.
+ *
+ * The singular values, sigma[$k] = S[$k][$k], are ordered so that
+ * sigma[0] >= sigma[1] >= ... >= sigma[n-1].
+ *
+ * The singular value decompostion always exists, so the constructor will
+ * never fail. The matrix condition number and the effective numerical
+ * rank can be computed from this decomposition.
+ *
+ * @author Paul Meagher
+ * @license PHP v3.0
+ * @version 1.1
+ */
+class SingularValueDecomposition
+{
+ /**
+ * Internal storage of U.
+ * @var array
+ */
+ private $U = array();
+
+ /**
+ * Internal storage of V.
+ * @var array
+ */
+ private $V = array();
+
+ /**
+ * Internal storage of singular values.
+ * @var array
+ */
+ private $s = array();
+
+ /**
+ * Row dimension.
+ * @var int
+ */
+ private $m;
+
+ /**
+ * Column dimension.
+ * @var int
+ */
+ private $n;
+
+ /**
+ * Construct the singular value decomposition
+ *
+ * Derived from LINPACK code.
+ *
+ * @param $A Rectangular matrix
+ * @return Structure to access U, S and V.
+ */
+ public function __construct($Arg)
+ {
+ // Initialize.
+ $A = $Arg->getArrayCopy();
+ $this->m = $Arg->getRowDimension();
+ $this->n = $Arg->getColumnDimension();
+ $nu = min($this->m, $this->n);
+ $e = array();
+ $work = array();
+ $wantu = true;
+ $wantv = true;
+ $nct = min($this->m - 1, $this->n);
+ $nrt = max(0, min($this->n - 2, $this->m));
+
+ // Reduce A to bidiagonal form, storing the diagonal elements
+ // in s and the super-diagonal elements in e.
+ for ($k = 0; $k < max($nct, $nrt); ++$k) {
+ if ($k < $nct) {
+ // Compute the transformation for the k-th column and
+ // place the k-th diagonal in s[$k].
+ // Compute 2-norm of k-th column without under/overflow.
+ $this->s[$k] = 0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $this->s[$k] = hypo($this->s[$k], $A[$i][$k]);
+ }
+ if ($this->s[$k] != 0.0) {
+ if ($A[$k][$k] < 0.0) {
+ $this->s[$k] = -$this->s[$k];
+ }
+ for ($i = $k; $i < $this->m; ++$i) {
+ $A[$i][$k] /= $this->s[$k];
+ }
+ $A[$k][$k] += 1.0;
+ }
+ $this->s[$k] = -$this->s[$k];
+ }
+
+ for ($j = $k + 1; $j < $this->n; ++$j) {
+ if (($k < $nct) & ($this->s[$k] != 0.0)) {
+ // Apply the transformation.
+ $t = 0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $t += $A[$i][$k] * $A[$i][$j];
+ }
+ $t = -$t / $A[$k][$k];
+ for ($i = $k; $i < $this->m; ++$i) {
+ $A[$i][$j] += $t * $A[$i][$k];
+ }
+ // Place the k-th row of A into e for the
+ // subsequent calculation of the row transformation.
+ $e[$j] = $A[$k][$j];
+ }
+ }
+
+ if ($wantu and ($k < $nct)) {
+ // Place the transformation in U for subsequent back
+ // multiplication.
+ for ($i = $k; $i < $this->m; ++$i) {
+ $this->U[$i][$k] = $A[$i][$k];
+ }
+ }
+
+ if ($k < $nrt) {
+ // Compute the k-th row transformation and place the
+ // k-th super-diagonal in e[$k].
+ // Compute 2-norm without under/overflow.
+ $e[$k] = 0;
+ for ($i = $k + 1; $i < $this->n; ++$i) {
+ $e[$k] = hypo($e[$k], $e[$i]);
+ }
+ if ($e[$k] != 0.0) {
+ if ($e[$k+1] < 0.0) {
+ $e[$k] = -$e[$k];
+ }
+ for ($i = $k + 1; $i < $this->n; ++$i) {
+ $e[$i] /= $e[$k];
+ }
+ $e[$k+1] += 1.0;
+ }
+ $e[$k] = -$e[$k];
+ if (($k+1 < $this->m) and ($e[$k] != 0.0)) {
+ // Apply the transformation.
+ for ($i = $k+1; $i < $this->m; ++$i) {
+ $work[$i] = 0.0;
+ }
+ for ($j = $k+1; $j < $this->n; ++$j) {
+ for ($i = $k+1; $i < $this->m; ++$i) {
+ $work[$i] += $e[$j] * $A[$i][$j];
+ }
+ }
+ for ($j = $k + 1; $j < $this->n; ++$j) {
+ $t = -$e[$j] / $e[$k+1];
+ for ($i = $k + 1; $i < $this->m; ++$i) {
+ $A[$i][$j] += $t * $work[$i];
+ }
+ }
+ }
+ if ($wantv) {
+ // Place the transformation in V for subsequent
+ // back multiplication.
+ for ($i = $k + 1; $i < $this->n; ++$i) {
+ $this->V[$i][$k] = $e[$i];
+ }
+ }
+ }
+ }
+
+ // Set up the final bidiagonal matrix or order p.
+ $p = min($this->n, $this->m + 1);
+ if ($nct < $this->n) {
+ $this->s[$nct] = $A[$nct][$nct];
+ }
+ if ($this->m < $p) {
+ $this->s[$p-1] = 0.0;
+ }
+ if ($nrt + 1 < $p) {
+ $e[$nrt] = $A[$nrt][$p-1];
+ }
+ $e[$p-1] = 0.0;
+ // If required, generate U.
+ if ($wantu) {
+ for ($j = $nct; $j < $nu; ++$j) {
+ for ($i = 0; $i < $this->m; ++$i) {
+ $this->U[$i][$j] = 0.0;
+ }
+ $this->U[$j][$j] = 1.0;
+ }
+ for ($k = $nct - 1; $k >= 0; --$k) {
+ if ($this->s[$k] != 0.0) {
+ for ($j = $k + 1; $j < $nu; ++$j) {
+ $t = 0;
+ for ($i = $k; $i < $this->m; ++$i) {
+ $t += $this->U[$i][$k] * $this->U[$i][$j];
+ }
+ $t = -$t / $this->U[$k][$k];
+ for ($i = $k; $i < $this->m; ++$i) {
+ $this->U[$i][$j] += $t * $this->U[$i][$k];
+ }
+ }
+ for ($i = $k; $i < $this->m; ++$i) {
+ $this->U[$i][$k] = -$this->U[$i][$k];
+ }
+ $this->U[$k][$k] = 1.0 + $this->U[$k][$k];
+ for ($i = 0; $i < $k - 1; ++$i) {
+ $this->U[$i][$k] = 0.0;
+ }
+ } else {
+ for ($i = 0; $i < $this->m; ++$i) {
+ $this->U[$i][$k] = 0.0;
+ }
+ $this->U[$k][$k] = 1.0;
+ }
+ }
+ }
+
+ // If required, generate V.
+ if ($wantv) {
+ for ($k = $this->n - 1; $k >= 0; --$k) {
+ if (($k < $nrt) and ($e[$k] != 0.0)) {
+ for ($j = $k + 1; $j < $nu; ++$j) {
+ $t = 0;
+ for ($i = $k + 1; $i < $this->n; ++$i) {
+ $t += $this->V[$i][$k]* $this->V[$i][$j];
+ }
+ $t = -$t / $this->V[$k+1][$k];
+ for ($i = $k + 1; $i < $this->n; ++$i) {
+ $this->V[$i][$j] += $t * $this->V[$i][$k];
+ }
+ }
+ }
+ for ($i = 0; $i < $this->n; ++$i) {
+ $this->V[$i][$k] = 0.0;
+ }
+ $this->V[$k][$k] = 1.0;
+ }
+ }
+
+ // Main iteration loop for the singular values.
+ $pp = $p - 1;
+ $iter = 0;
+ $eps = pow(2.0, -52.0);
+
+ while ($p > 0) {
+ // Here is where a test for too many iterations would go.
+ // This section of the program inspects for negligible
+ // elements in the s and e arrays. On completion the
+ // variables kase and k are set as follows:
+ // kase = 1 if s(p) and e[k-1] are negligible and k= -1; --$k) {
+ if ($k == -1) {
+ break;
+ }
+ if (abs($e[$k]) <= $eps * (abs($this->s[$k]) + abs($this->s[$k+1]))) {
+ $e[$k] = 0.0;
+ break;
+ }
+ }
+ if ($k == $p - 2) {
+ $kase = 4;
+ } else {
+ for ($ks = $p - 1; $ks >= $k; --$ks) {
+ if ($ks == $k) {
+ break;
+ }
+ $t = ($ks != $p ? abs($e[$ks]) : 0.) + ($ks != $k + 1 ? abs($e[$ks-1]) : 0.);
+ if (abs($this->s[$ks]) <= $eps * $t) {
+ $this->s[$ks] = 0.0;
+ break;
+ }
+ }
+ if ($ks == $k) {
+ $kase = 3;
+ } elseif ($ks == $p-1) {
+ $kase = 1;
+ } else {
+ $kase = 2;
+ $k = $ks;
+ }
+ }
+ ++$k;
+
+ // Perform the task indicated by kase.
+ switch ($kase) {
+ // Deflate negligible s(p).
+ case 1:
+ $f = $e[$p-2];
+ $e[$p-2] = 0.0;
+ for ($j = $p - 2; $j >= $k; --$j) {
+ $t = hypo($this->s[$j], $f);
+ $cs = $this->s[$j] / $t;
+ $sn = $f / $t;
+ $this->s[$j] = $t;
+ if ($j != $k) {
+ $f = -$sn * $e[$j-1];
+ $e[$j-1] = $cs * $e[$j-1];
+ }
+ if ($wantv) {
+ for ($i = 0; $i < $this->n; ++$i) {
+ $t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$p-1];
+ $this->V[$i][$p-1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$p-1];
+ $this->V[$i][$j] = $t;
+ }
+ }
+ }
+ break;
+ // Split at negligible s(k).
+ case 2:
+ $f = $e[$k-1];
+ $e[$k-1] = 0.0;
+ for ($j = $k; $j < $p; ++$j) {
+ $t = hypo($this->s[$j], $f);
+ $cs = $this->s[$j] / $t;
+ $sn = $f / $t;
+ $this->s[$j] = $t;
+ $f = -$sn * $e[$j];
+ $e[$j] = $cs * $e[$j];
+ if ($wantu) {
+ for ($i = 0; $i < $this->m; ++$i) {
+ $t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$k-1];
+ $this->U[$i][$k-1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$k-1];
+ $this->U[$i][$j] = $t;
+ }
+ }
+ }
+ break;
+ // Perform one qr step.
+ case 3:
+ // Calculate the shift.
+ $scale = max(max(max(max(abs($this->s[$p-1]), abs($this->s[$p-2])), abs($e[$p-2])), abs($this->s[$k])), abs($e[$k]));
+ $sp = $this->s[$p-1] / $scale;
+ $spm1 = $this->s[$p-2] / $scale;
+ $epm1 = $e[$p-2] / $scale;
+ $sk = $this->s[$k] / $scale;
+ $ek = $e[$k] / $scale;
+ $b = (($spm1 + $sp) * ($spm1 - $sp) + $epm1 * $epm1) / 2.0;
+ $c = ($sp * $epm1) * ($sp * $epm1);
+ $shift = 0.0;
+ if (($b != 0.0) || ($c != 0.0)) {
+ $shift = sqrt($b * $b + $c);
+ if ($b < 0.0) {
+ $shift = -$shift;
+ }
+ $shift = $c / ($b + $shift);
+ }
+ $f = ($sk + $sp) * ($sk - $sp) + $shift;
+ $g = $sk * $ek;
+ // Chase zeros.
+ for ($j = $k; $j < $p-1; ++$j) {
+ $t = hypo($f, $g);
+ $cs = $f/$t;
+ $sn = $g/$t;
+ if ($j != $k) {
+ $e[$j-1] = $t;
+ }
+ $f = $cs * $this->s[$j] + $sn * $e[$j];
+ $e[$j] = $cs * $e[$j] - $sn * $this->s[$j];
+ $g = $sn * $this->s[$j+1];
+ $this->s[$j+1] = $cs * $this->s[$j+1];
+ if ($wantv) {
+ for ($i = 0; $i < $this->n; ++$i) {
+ $t = $cs * $this->V[$i][$j] + $sn * $this->V[$i][$j+1];
+ $this->V[$i][$j+1] = -$sn * $this->V[$i][$j] + $cs * $this->V[$i][$j+1];
+ $this->V[$i][$j] = $t;
+ }
+ }
+ $t = hypo($f, $g);
+ $cs = $f/$t;
+ $sn = $g/$t;
+ $this->s[$j] = $t;
+ $f = $cs * $e[$j] + $sn * $this->s[$j+1];
+ $this->s[$j+1] = -$sn * $e[$j] + $cs * $this->s[$j+1];
+ $g = $sn * $e[$j+1];
+ $e[$j+1] = $cs * $e[$j+1];
+ if ($wantu && ($j < $this->m - 1)) {
+ for ($i = 0; $i < $this->m; ++$i) {
+ $t = $cs * $this->U[$i][$j] + $sn * $this->U[$i][$j+1];
+ $this->U[$i][$j+1] = -$sn * $this->U[$i][$j] + $cs * $this->U[$i][$j+1];
+ $this->U[$i][$j] = $t;
+ }
+ }
+ }
+ $e[$p-2] = $f;
+ $iter = $iter + 1;
+ break;
+ // Convergence.
+ case 4:
+ // Make the singular values positive.
+ if ($this->s[$k] <= 0.0) {
+ $this->s[$k] = ($this->s[$k] < 0.0 ? -$this->s[$k] : 0.0);
+ if ($wantv) {
+ for ($i = 0; $i <= $pp; ++$i) {
+ $this->V[$i][$k] = -$this->V[$i][$k];
+ }
+ }
+ }
+ // Order the singular values.
+ while ($k < $pp) {
+ if ($this->s[$k] >= $this->s[$k+1]) {
+ break;
+ }
+ $t = $this->s[$k];
+ $this->s[$k] = $this->s[$k+1];
+ $this->s[$k+1] = $t;
+ if ($wantv and ($k < $this->n - 1)) {
+ for ($i = 0; $i < $this->n; ++$i) {
+ $t = $this->V[$i][$k+1];
+ $this->V[$i][$k+1] = $this->V[$i][$k];
+ $this->V[$i][$k] = $t;
+ }
+ }
+ if ($wantu and ($k < $this->m-1)) {
+ for ($i = 0; $i < $this->m; ++$i) {
+ $t = $this->U[$i][$k+1];
+ $this->U[$i][$k+1] = $this->U[$i][$k];
+ $this->U[$i][$k] = $t;
+ }
+ }
+ ++$k;
+ }
+ $iter = 0;
+ --$p;
+ break;
+ } // end switch
+ } // end while
+
+ } // end constructor
+
+
+ /**
+ * Return the left singular vectors
+ *
+ * @access public
+ * @return U
+ */
+ public function getU()
+ {
+ return new Matrix($this->U, $this->m, min($this->m + 1, $this->n));
+ }
+
+
+ /**
+ * Return the right singular vectors
+ *
+ * @access public
+ * @return V
+ */
+ public function getV()
+ {
+ return new Matrix($this->V);
+ }
+
+
+ /**
+ * Return the one-dimensional array of singular values
+ *
+ * @access public
+ * @return diagonal of S.
+ */
+ public function getSingularValues()
+ {
+ return $this->s;
+ }
+
+
+ /**
+ * Return the diagonal matrix of singular values
+ *
+ * @access public
+ * @return S
+ */
+ public function getS()
+ {
+ for ($i = 0; $i < $this->n; ++$i) {
+ for ($j = 0; $j < $this->n; ++$j) {
+ $S[$i][$j] = 0.0;
+ }
+ $S[$i][$i] = $this->s[$i];
+ }
+ return new Matrix($S);
+ }
+
+
+ /**
+ * Two norm
+ *
+ * @access public
+ * @return max(S)
+ */
+ public function norm2()
+ {
+ return $this->s[0];
+ }
+
+
+ /**
+ * Two norm condition number
+ *
+ * @access public
+ * @return max(S)/min(S)
+ */
+ public function cond()
+ {
+ return $this->s[0] / $this->s[min($this->m, $this->n) - 1];
+ }
+
+
+ /**
+ * Effective numerical matrix rank
+ *
+ * @access public
+ * @return Number of nonnegligible singular values.
+ */
+ public function rank()
+ {
+ $eps = pow(2.0, -52.0);
+ $tol = max($this->m, $this->n) * $this->s[0] * $eps;
+ $r = 0;
+ for ($i = 0; $i < count($this->s); ++$i) {
+ if ($this->s[$i] > $tol) {
+ ++$r;
+ }
+ }
+ return $r;
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/JAMA/utils/Error.php b/extend/PHPExcel/PHPExcel/Shared/JAMA/utils/Error.php
new file mode 100755
index 0000000..71b8c99
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/JAMA/utils/Error.php
@@ -0,0 +1,83 @@
+ abs($b)) {
+ $r = $b / $a;
+ $r = abs($a) * sqrt(1 + $r * $r);
+ } elseif ($b != 0) {
+ $r = $a / $b;
+ $r = abs($b) * sqrt(1 + $r * $r);
+ } else {
+ $r = 0.0;
+ }
+ return $r;
+} // function hypo()
+
+
+/**
+ * Mike Bommarito's version.
+ * Compute n-dimensional hyotheneuse.
+ *
+function hypot() {
+ $s = 0;
+ foreach (func_get_args() as $d) {
+ if (is_numeric($d)) {
+ $s += pow($d, 2);
+ } else {
+ throw new PHPExcel_Calculation_Exception(JAMAError(ARGUMENT_TYPE_EXCEPTION));
+ }
+ }
+ return sqrt($s);
+}
+*/
diff --git a/extend/PHPExcel/PHPExcel/Shared/OLE.php b/extend/PHPExcel/PHPExcel/Shared/OLE.php
new file mode 100755
index 0000000..42a3c52
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/OLE.php
@@ -0,0 +1,526 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: OLE.php,v 1.13 2007/03/07 14:38:25 schmidt Exp $
+
+
+/**
+* Array for storing OLE instances that are accessed from
+* OLE_ChainedBlockStream::stream_open().
+* @var array
+*/
+$GLOBALS['_OLE_INSTANCES'] = array();
+
+/**
+* OLE package base class.
+*
+* @author Xavier Noguer
+* @author Christian Schmidt
+* @category PHPExcel
+* @package PHPExcel_Shared_OLE
+*/
+class PHPExcel_Shared_OLE
+{
+ const OLE_PPS_TYPE_ROOT = 5;
+ const OLE_PPS_TYPE_DIR = 1;
+ const OLE_PPS_TYPE_FILE = 2;
+ const OLE_DATA_SIZE_SMALL = 0x1000;
+ const OLE_LONG_INT_SIZE = 4;
+ const OLE_PPS_SIZE = 0x80;
+
+ /**
+ * The file handle for reading an OLE container
+ * @var resource
+ */
+ public $_file_handle;
+
+ /**
+ * Array of PPS's found on the OLE container
+ * @var array
+ */
+ public $_list = array();
+
+ /**
+ * Root directory of OLE container
+ * @var OLE_PPS_Root
+ */
+ public $root;
+
+ /**
+ * Big Block Allocation Table
+ * @var array (blockId => nextBlockId)
+ */
+ public $bbat;
+
+ /**
+ * Short Block Allocation Table
+ * @var array (blockId => nextBlockId)
+ */
+ public $sbat;
+
+ /**
+ * Size of big blocks. This is usually 512.
+ * @var int number of octets per block.
+ */
+ public $bigBlockSize;
+
+ /**
+ * Size of small blocks. This is usually 64.
+ * @var int number of octets per block
+ */
+ public $smallBlockSize;
+
+ /**
+ * Reads an OLE container from the contents of the file given.
+ *
+ * @acces public
+ * @param string $file
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ public function read($file)
+ {
+ $fh = fopen($file, "r");
+ if (!$fh) {
+ throw new PHPExcel_Reader_Exception("Can't open file $file");
+ }
+ $this->_file_handle = $fh;
+
+ $signature = fread($fh, 8);
+ if ("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1" != $signature) {
+ throw new PHPExcel_Reader_Exception("File doesn't seem to be an OLE container.");
+ }
+ fseek($fh, 28);
+ if (fread($fh, 2) != "\xFE\xFF") {
+ // This shouldn't be a problem in practice
+ throw new PHPExcel_Reader_Exception("Only Little-Endian encoding is supported.");
+ }
+ // Size of blocks and short blocks in bytes
+ $this->bigBlockSize = pow(2, self::_readInt2($fh));
+ $this->smallBlockSize = pow(2, self::_readInt2($fh));
+
+ // Skip UID, revision number and version number
+ fseek($fh, 44);
+ // Number of blocks in Big Block Allocation Table
+ $bbatBlockCount = self::_readInt4($fh);
+
+ // Root chain 1st block
+ $directoryFirstBlockId = self::_readInt4($fh);
+
+ // Skip unused bytes
+ fseek($fh, 56);
+ // Streams shorter than this are stored using small blocks
+ $this->bigBlockThreshold = self::_readInt4($fh);
+ // Block id of first sector in Short Block Allocation Table
+ $sbatFirstBlockId = self::_readInt4($fh);
+ // Number of blocks in Short Block Allocation Table
+ $sbbatBlockCount = self::_readInt4($fh);
+ // Block id of first sector in Master Block Allocation Table
+ $mbatFirstBlockId = self::_readInt4($fh);
+ // Number of blocks in Master Block Allocation Table
+ $mbbatBlockCount = self::_readInt4($fh);
+ $this->bbat = array();
+
+ // Remaining 4 * 109 bytes of current block is beginning of Master
+ // Block Allocation Table
+ $mbatBlocks = array();
+ for ($i = 0; $i < 109; ++$i) {
+ $mbatBlocks[] = self::_readInt4($fh);
+ }
+
+ // Read rest of Master Block Allocation Table (if any is left)
+ $pos = $this->_getBlockOffset($mbatFirstBlockId);
+ for ($i = 0; $i < $mbbatBlockCount; ++$i) {
+ fseek($fh, $pos);
+ for ($j = 0; $j < $this->bigBlockSize / 4 - 1; ++$j) {
+ $mbatBlocks[] = self::_readInt4($fh);
+ }
+ // Last block id in each block points to next block
+ $pos = $this->_getBlockOffset(self::_readInt4($fh));
+ }
+
+ // Read Big Block Allocation Table according to chain specified by
+ // $mbatBlocks
+ for ($i = 0; $i < $bbatBlockCount; ++$i) {
+ $pos = $this->_getBlockOffset($mbatBlocks[$i]);
+ fseek($fh, $pos);
+ for ($j = 0; $j < $this->bigBlockSize / 4; ++$j) {
+ $this->bbat[] = self::_readInt4($fh);
+ }
+ }
+
+ // Read short block allocation table (SBAT)
+ $this->sbat = array();
+ $shortBlockCount = $sbbatBlockCount * $this->bigBlockSize / 4;
+ $sbatFh = $this->getStream($sbatFirstBlockId);
+ for ($blockId = 0; $blockId < $shortBlockCount; ++$blockId) {
+ $this->sbat[$blockId] = self::_readInt4($sbatFh);
+ }
+ fclose($sbatFh);
+
+ $this->_readPpsWks($directoryFirstBlockId);
+
+ return true;
+ }
+
+ /**
+ * @param int block id
+ * @param int byte offset from beginning of file
+ * @access public
+ */
+ public function _getBlockOffset($blockId)
+ {
+ return 512 + $blockId * $this->bigBlockSize;
+ }
+
+ /**
+ * Returns a stream for use with fread() etc. External callers should
+ * use PHPExcel_Shared_OLE_PPS_File::getStream().
+ * @param int|PPS block id or PPS
+ * @return resource read-only stream
+ */
+ public function getStream($blockIdOrPps)
+ {
+ static $isRegistered = false;
+ if (!$isRegistered) {
+ stream_wrapper_register('ole-chainedblockstream', 'PHPExcel_Shared_OLE_ChainedBlockStream');
+ $isRegistered = true;
+ }
+
+ // Store current instance in global array, so that it can be accessed
+ // in OLE_ChainedBlockStream::stream_open().
+ // Object is removed from self::$instances in OLE_Stream::close().
+ $GLOBALS['_OLE_INSTANCES'][] = $this;
+ $instanceId = end(array_keys($GLOBALS['_OLE_INSTANCES']));
+
+ $path = 'ole-chainedblockstream://oleInstanceId=' . $instanceId;
+ if ($blockIdOrPps instanceof PHPExcel_Shared_OLE_PPS) {
+ $path .= '&blockId=' . $blockIdOrPps->_StartBlock;
+ $path .= '&size=' . $blockIdOrPps->Size;
+ } else {
+ $path .= '&blockId=' . $blockIdOrPps;
+ }
+ return fopen($path, 'r');
+ }
+
+ /**
+ * Reads a signed char.
+ * @param resource file handle
+ * @return int
+ * @access public
+ */
+ private static function _readInt1($fh)
+ {
+ list(, $tmp) = unpack("c", fread($fh, 1));
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned short (2 octets).
+ * @param resource file handle
+ * @return int
+ * @access public
+ */
+ private static function _readInt2($fh)
+ {
+ list(, $tmp) = unpack("v", fread($fh, 2));
+ return $tmp;
+ }
+
+ /**
+ * Reads an unsigned long (4 octets).
+ * @param resource file handle
+ * @return int
+ * @access public
+ */
+ private static function _readInt4($fh)
+ {
+ list(, $tmp) = unpack("V", fread($fh, 4));
+ return $tmp;
+ }
+
+ /**
+ * Gets information about all PPS's on the OLE container from the PPS WK's
+ * creates an OLE_PPS object for each one.
+ *
+ * @access public
+ * @param integer the block id of the first block
+ * @return mixed true on success, PEAR_Error on failure
+ */
+ public function _readPpsWks($blockId)
+ {
+ $fh = $this->getStream($blockId);
+ for ($pos = 0;; $pos += 128) {
+ fseek($fh, $pos, SEEK_SET);
+ $nameUtf16 = fread($fh, 64);
+ $nameLength = self::_readInt2($fh);
+ $nameUtf16 = substr($nameUtf16, 0, $nameLength - 2);
+ // Simple conversion from UTF-16LE to ISO-8859-1
+ $name = str_replace("\x00", "", $nameUtf16);
+ $type = self::_readInt1($fh);
+ switch ($type) {
+ case self::OLE_PPS_TYPE_ROOT:
+ $pps = new PHPExcel_Shared_OLE_PPS_Root(null, null, array());
+ $this->root = $pps;
+ break;
+ case self::OLE_PPS_TYPE_DIR:
+ $pps = new PHPExcel_Shared_OLE_PPS(null, null, null, null, null, null, null, null, null, array());
+ break;
+ case self::OLE_PPS_TYPE_FILE:
+ $pps = new PHPExcel_Shared_OLE_PPS_File($name);
+ break;
+ default:
+ continue;
+ }
+ fseek($fh, 1, SEEK_CUR);
+ $pps->Type = $type;
+ $pps->Name = $name;
+ $pps->PrevPps = self::_readInt4($fh);
+ $pps->NextPps = self::_readInt4($fh);
+ $pps->DirPps = self::_readInt4($fh);
+ fseek($fh, 20, SEEK_CUR);
+ $pps->Time1st = self::OLE2LocalDate(fread($fh, 8));
+ $pps->Time2nd = self::OLE2LocalDate(fread($fh, 8));
+ $pps->_StartBlock = self::_readInt4($fh);
+ $pps->Size = self::_readInt4($fh);
+ $pps->No = count($this->_list);
+ $this->_list[] = $pps;
+
+ // check if the PPS tree (starting from root) is complete
+ if (isset($this->root) && $this->_ppsTreeComplete($this->root->No)) {
+ break;
+ }
+ }
+ fclose($fh);
+
+ // Initialize $pps->children on directories
+ foreach ($this->_list as $pps) {
+ if ($pps->Type == self::OLE_PPS_TYPE_DIR || $pps->Type == self::OLE_PPS_TYPE_ROOT) {
+ $nos = array($pps->DirPps);
+ $pps->children = array();
+ while ($nos) {
+ $no = array_pop($nos);
+ if ($no != -1) {
+ $childPps = $this->_list[$no];
+ $nos[] = $childPps->PrevPps;
+ $nos[] = $childPps->NextPps;
+ $pps->children[] = $childPps;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * It checks whether the PPS tree is complete (all PPS's read)
+ * starting with the given PPS (not necessarily root)
+ *
+ * @access public
+ * @param integer $index The index of the PPS from which we are checking
+ * @return boolean Whether the PPS tree for the given PPS is complete
+ */
+ public function _ppsTreeComplete($index)
+ {
+ return isset($this->_list[$index]) &&
+ ($pps = $this->_list[$index]) &&
+ ($pps->PrevPps == -1 ||
+ $this->_ppsTreeComplete($pps->PrevPps)) &&
+ ($pps->NextPps == -1 ||
+ $this->_ppsTreeComplete($pps->NextPps)) &&
+ ($pps->DirPps == -1 ||
+ $this->_ppsTreeComplete($pps->DirPps));
+ }
+
+ /**
+ * Checks whether a PPS is a File PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ *
+ * @access public
+ * @param integer $index The index for the PPS
+ * @return bool true if it's a File PPS, false otherwise
+ */
+ public function isFile($index)
+ {
+ if (isset($this->_list[$index])) {
+ return ($this->_list[$index]->Type == self::OLE_PPS_TYPE_FILE);
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a PPS is a Root PPS or not.
+ * If there is no PPS for the index given, it will return false.
+ *
+ * @access public
+ * @param integer $index The index for the PPS.
+ * @return bool true if it's a Root PPS, false otherwise
+ */
+ public function isRoot($index)
+ {
+ if (isset($this->_list[$index])) {
+ return ($this->_list[$index]->Type == self::OLE_PPS_TYPE_ROOT);
+ }
+ return false;
+ }
+
+ /**
+ * Gives the total number of PPS's found in the OLE container.
+ *
+ * @access public
+ * @return integer The total number of PPS's found in the OLE container
+ */
+ public function ppsTotal()
+ {
+ return count($this->_list);
+ }
+
+ /**
+ * Gets data from a PPS
+ * If there is no PPS for the index given, it will return an empty string.
+ *
+ * @access public
+ * @param integer $index The index for the PPS
+ * @param integer $position The position from which to start reading
+ * (relative to the PPS)
+ * @param integer $length The amount of bytes to read (at most)
+ * @return string The binary string containing the data requested
+ * @see OLE_PPS_File::getStream()
+ */
+ public function getData($index, $position, $length)
+ {
+ // if position is not valid return empty string
+ if (!isset($this->_list[$index]) || ($position >= $this->_list[$index]->Size) || ($position < 0)) {
+ return '';
+ }
+ $fh = $this->getStream($this->_list[$index]);
+ $data = stream_get_contents($fh, $length, $position);
+ fclose($fh);
+ return $data;
+ }
+
+ /**
+ * Gets the data length from a PPS
+ * If there is no PPS for the index given, it will return 0.
+ *
+ * @access public
+ * @param integer $index The index for the PPS
+ * @return integer The amount of bytes in data the PPS has
+ */
+ public function getDataLength($index)
+ {
+ if (isset($this->_list[$index])) {
+ return $this->_list[$index]->Size;
+ }
+ return 0;
+ }
+
+ /**
+ * Utility function to transform ASCII text to Unicode
+ *
+ * @access public
+ * @static
+ * @param string $ascii The ASCII string to transform
+ * @return string The string in Unicode
+ */
+ public static function Asc2Ucs($ascii)
+ {
+ $rawname = '';
+ for ($i = 0; $i < strlen($ascii); ++$i) {
+ $rawname .= $ascii{$i} . "\x00";
+ }
+ return $rawname;
+ }
+
+ /**
+ * Utility function
+ * Returns a string for the OLE container with the date given
+ *
+ * @access public
+ * @static
+ * @param integer $date A timestamp
+ * @return string The string for the OLE container
+ */
+ public static function LocalDate2OLE($date = null)
+ {
+ if (!isset($date)) {
+ return "\x00\x00\x00\x00\x00\x00\x00\x00";
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = pow(2, 32);
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+ // calculate seconds
+ $big_date = $days*24*3600 + gmmktime(date("H", $date), date("i", $date), date("s", $date), date("m", $date), date("d", $date), date("Y", $date));
+ // multiply just to make MS happy
+ $big_date *= 10000000;
+
+ $high_part = floor($big_date / $factor);
+ // lower 4 bytes
+ $low_part = floor((($big_date / $factor) - $high_part) * $factor);
+
+ // Make HEX string
+ $res = '';
+
+ for ($i = 0; $i < 4; ++$i) {
+ $hex = $low_part % 0x100;
+ $res .= pack('c', $hex);
+ $low_part /= 0x100;
+ }
+ for ($i = 0; $i < 4; ++$i) {
+ $hex = $high_part % 0x100;
+ $res .= pack('c', $hex);
+ $high_part /= 0x100;
+ }
+ return $res;
+ }
+
+ /**
+ * Returns a timestamp from an OLE container's date
+ *
+ * @access public
+ * @static
+ * @param integer $string A binary string with the encoded date
+ * @return string The timestamp corresponding to the string
+ */
+ public static function OLE2LocalDate($string)
+ {
+ if (strlen($string) != 8) {
+ return new PEAR_Error("Expecting 8 byte string");
+ }
+
+ // factor used for separating numbers into 4 bytes parts
+ $factor = pow(2, 32);
+ list(, $high_part) = unpack('V', substr($string, 4, 4));
+ list(, $low_part) = unpack('V', substr($string, 0, 4));
+
+ $big_date = ($high_part * $factor) + $low_part;
+ // translate to seconds
+ $big_date /= 10000000;
+
+ // days from 1-1-1601 until the beggining of UNIX era
+ $days = 134774;
+
+ // translate to seconds from beggining of UNIX era
+ $big_date -= $days * 24 * 3600;
+ return floor($big_date);
+ }
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php b/extend/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php
new file mode 100755
index 0000000..84d2cc5
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/OLE/ChainedBlockStream.php
@@ -0,0 +1,206 @@
+params);
+ if (!isset($this->params['oleInstanceId'], $this->params['blockId'], $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']])) {
+ if ($options & STREAM_REPORT_ERRORS) {
+ trigger_error('OLE stream not found', E_USER_WARNING);
+ }
+ return false;
+ }
+ $this->ole = $GLOBALS['_OLE_INSTANCES'][$this->params['oleInstanceId']];
+
+ $blockId = $this->params['blockId'];
+ $this->data = '';
+ if (isset($this->params['size']) && $this->params['size'] < $this->ole->bigBlockThreshold && $blockId != $this->ole->root->_StartBlock) {
+ // Block id refers to small blocks
+ $rootPos = $this->ole->_getBlockOffset($this->ole->root->_StartBlock);
+ while ($blockId != -2) {
+ $pos = $rootPos + $blockId * $this->ole->bigBlockSize;
+ $blockId = $this->ole->sbat[$blockId];
+ fseek($this->ole->_file_handle, $pos);
+ $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize);
+ }
+ } else {
+ // Block id refers to big blocks
+ while ($blockId != -2) {
+ $pos = $this->ole->_getBlockOffset($blockId);
+ fseek($this->ole->_file_handle, $pos);
+ $this->data .= fread($this->ole->_file_handle, $this->ole->bigBlockSize);
+ $blockId = $this->ole->bbat[$blockId];
+ }
+ }
+ if (isset($this->params['size'])) {
+ $this->data = substr($this->data, 0, $this->params['size']);
+ }
+
+ if ($options & STREAM_USE_PATH) {
+ $openedPath = $path;
+ }
+
+ return true;
+ }
+
+ /**
+ * Implements support for fclose().
+ *
+ */
+ public function stream_close()
+ {
+ $this->ole = null;
+ unset($GLOBALS['_OLE_INSTANCES']);
+ }
+
+ /**
+ * Implements support for fread(), fgets() etc.
+ *
+ * @param int $count maximum number of bytes to read
+ * @return string
+ */
+ public function stream_read($count)
+ {
+ if ($this->stream_eof()) {
+ return false;
+ }
+ $s = substr($this->data, $this->pos, $count);
+ $this->pos += $count;
+ return $s;
+ }
+
+ /**
+ * Implements support for feof().
+ *
+ * @return bool TRUE if the file pointer is at EOF; otherwise FALSE
+ */
+ public function stream_eof()
+ {
+ return $this->pos >= strlen($this->data);
+ }
+
+ /**
+ * Returns the position of the file pointer, i.e. its offset into the file
+ * stream. Implements support for ftell().
+ *
+ * @return int
+ */
+ public function stream_tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Implements support for fseek().
+ *
+ * @param int $offset byte offset
+ * @param int $whence SEEK_SET, SEEK_CUR or SEEK_END
+ * @return bool
+ */
+ public function stream_seek($offset, $whence)
+ {
+ if ($whence == SEEK_SET && $offset >= 0) {
+ $this->pos = $offset;
+ } elseif ($whence == SEEK_CUR && -$offset <= $this->pos) {
+ $this->pos += $offset;
+ } elseif ($whence == SEEK_END && -$offset <= sizeof($this->data)) {
+ $this->pos = strlen($this->data) + $offset;
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Implements support for fstat(). Currently the only supported field is
+ * "size".
+ * @return array
+ */
+ public function stream_stat()
+ {
+ return array(
+ 'size' => strlen($this->data),
+ );
+ }
+
+ // Methods used by stream_wrapper_register() that are not implemented:
+ // bool stream_flush ( void )
+ // int stream_write ( string data )
+ // bool rename ( string path_from, string path_to )
+ // bool mkdir ( string path, int mode, int options )
+ // bool rmdir ( string path, int options )
+ // bool dir_opendir ( string path, int options )
+ // array url_stat ( string path, int flags )
+ // string dir_readdir ( void )
+ // bool dir_rewinddir ( void )
+ // bool dir_closedir ( void )
+}
diff --git a/extend/PHPExcel/PHPExcel/Shared/OLE/PPS.php b/extend/PHPExcel/PHPExcel/Shared/OLE/PPS.php
new file mode 100755
index 0000000..608a892
--- /dev/null
+++ b/extend/PHPExcel/PHPExcel/Shared/OLE/PPS.php
@@ -0,0 +1,230 @@
+ |
+// | Based on OLE::Storage_Lite by Kawai, Takanori |
+// +----------------------------------------------------------------------+
+//
+// $Id: PPS.php,v 1.7 2007/02/13 21:00:42 schmidt Exp $
+
+
+/**
+* Class for creating PPS's for OLE containers
+*
+* @author Xavier Noguer