diff --git a/Install/Sms.sql b/Install/Sms.sql
index 007ba35..ef7baa3 100644
--- a/Install/Sms.sql
+++ b/Install/Sms.sql
@@ -24,6 +24,8 @@ CREATE TABLE `cms_sms_operator` (
INSERT INTO `cms_sms_operator` (`id`, `name`, `tablename`, `remark`, `enable`) VALUES ('1', '阿里大于', 'alidayu', '阿里大于短信平台', '1');
INSERT INTO `cms_sms_operator` (`id`, `name`, `tablename`, `remark`, `enable`) VALUES ('2', '云之讯', 'ucpaas', '云之讯短信平台', '0');
+INSERT INTO `cms_sms_operator` (`id`, `name`, `tablename`, `remark`, `enable`) VALUES ('3', '阿里短信', 'alisms', '阿里短信服务', '0');
+
DROP TABLE IF EXISTS `cms_sms_alidayu`;
@@ -47,4 +49,18 @@ CREATE TABLE `cms_sms_ucpaas` (
`appid` VARCHAR(255) COMMENT '应用ID',
`templateid` VARCHAR(255) COMMENT '短信模板ID',
PRIMARY KEY (`id`)
-) ENGINE = INNODB DEFAULT CHARSET = utf8;
\ No newline at end of file
+) ENGINE = INNODB DEFAULT CHARSET = utf8;
+
+DROP TABLE IF EXISTS `cms_sms_alisms`;
+
+CREATE TABLE `cms_sms_alisms` (
+ `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `end_point` varchar(255) DEFAULT '' COMMENT '分公网跟私网(请根据业务自行选择)',
+ `access_id` varchar(255) DEFAULT '' COMMENT 'Access Key ID(阿里云API密钥)',
+ `access_key` varchar(255) DEFAULT '' COMMENT 'Access Key Secret(阿里云API密钥)',
+ `topic_name` varchar(255) DEFAULT '' COMMENT '短信主题名称',
+ `sign` varchar(255) DEFAULT '' COMMENT '短信签名',
+ `template` varchar(255) DEFAULT '' COMMENT '短信模版 Code',
+ `message_body` varchar(255) DEFAULT '' COMMENT 'SMS消息体(阿里没有说明作用,不为空即可)',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/Lib/Alisms/AliyunMNS/AsyncCallback.php b/Lib/Alisms/AliyunMNS/AsyncCallback.php
new file mode 100644
index 0000000..47e43be
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/AsyncCallback.php
@@ -0,0 +1,29 @@
+succeedCallback = $succeedCallback;
+ $this->failedCallback = $failedCallback;
+ }
+
+ public function onSucceed(BaseResponse $result)
+ {
+ return call_user_func($this->succeedCallback, $result);
+ }
+
+ public function onFailed(MnsException $e)
+ {
+ return call_user_func($this->failedCallback, $e);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Client.php b/Lib/Alisms/AliyunMNS/Client.php
new file mode 100644
index 0000000..da2f4b8
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Client.php
@@ -0,0 +1,249 @@
+client = new HttpClient($endPoint, $accessId,
+ $accessKey, $securityToken, $config);
+ }
+
+ /**
+ * Returns a queue reference for operating on the queue
+ * this function does not create the queue automatically.
+ *
+ * @param string $queueName: the queue name
+ * @param bool $base64: whether the message in queue will be base64 encoded
+ *
+ * @return Queue $queue: the Queue instance
+ */
+ public function getQueueRef($queueName, $base64 = TRUE)
+ {
+ return new Queue($this->client, $queueName, $base64);
+ }
+
+ /**
+ * Create Queue and Returns the Queue reference
+ *
+ * @param CreateQueueRequest $request: the QueueName and QueueAttributes
+ *
+ * @return CreateQueueResponse $response: the CreateQueueResponse
+ *
+ * @throws QueueAlreadyExistException if queue already exists
+ * @throws InvalidArgumentException if any argument value is invalid
+ * @throws MnsException if any other exception happends
+ */
+ public function createQueue(CreateQueueRequest $request)
+ {
+ $response = new CreateQueueResponse($request->getQueueName());
+ return $this->client->sendRequest($request, $response);
+ }
+
+ /**
+ * Create Queue and Returns the Queue reference
+ * The request will not be sent until calling MnsPromise->wait();
+ *
+ * @param CreateQueueRequest $request: the QueueName and QueueAttributes
+ * @param AsyncCallback $callback: the Callback when the request finishes
+ *
+ * @return MnsPromise $promise: the MnsPromise instance
+ *
+ * @throws MnsException if any exception happends
+ */
+ public function createQueueAsync(CreateQueueRequest $request,
+ AsyncCallback $callback = NULL)
+ {
+ $response = new CreateQueueResponse($request->getQueueName());
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * Query the queues created by current account
+ *
+ * @param ListQueueRequest $request: define filters for quering queues
+ *
+ * @return ListQueueResponse: the response containing queueNames
+ */
+ public function listQueue(ListQueueRequest $request)
+ {
+ $response = new ListQueueResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function listQueueAsync(ListQueueRequest $request,
+ AsyncCallback $callback = NULL)
+ {
+ $response = new ListQueueResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * Delete the specified queue
+ * the request will succeed even when the queue does not exist
+ *
+ * @param $queueName: the queueName
+ *
+ * @return DeleteQueueResponse
+ */
+ public function deleteQueue($queueName)
+ {
+ $request = new DeleteQueueRequest($queueName);
+ $response = new DeleteQueueResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function deleteQueueAsync($queueName,
+ AsyncCallback $callback = NULL)
+ {
+ $request = new DeleteQueueRequest($queueName);
+ $response = new DeleteQueueResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ // API for Topic
+ /**
+ * Returns a topic reference for operating on the topic
+ * this function does not create the topic automatically.
+ *
+ * @param string $topicName: the topic name
+ *
+ * @return Topic $topic: the Topic instance
+ */
+ public function getTopicRef($topicName)
+ {
+ return new Topic($this->client, $topicName);
+ }
+
+ /**
+ * Create Topic and Returns the Topic reference
+ *
+ * @param CreateTopicRequest $request: the TopicName and TopicAttributes
+ *
+ * @return CreateTopicResponse $response: the CreateTopicResponse
+ *
+ * @throws TopicAlreadyExistException if topic already exists
+ * @throws InvalidArgumentException if any argument value is invalid
+ * @throws MnsException if any other exception happends
+ */
+ public function createTopic(CreateTopicRequest $request)
+ {
+ $response = new CreateTopicResponse($request->getTopicName());
+ return $this->client->sendRequest($request, $response);
+ }
+
+ /**
+ * Delete the specified topic
+ * the request will succeed even when the topic does not exist
+ *
+ * @param $topicName: the topicName
+ *
+ * @return DeleteTopicResponse
+ */
+ public function deleteTopic($topicName)
+ {
+ $request = new DeleteTopicRequest($topicName);
+ $response = new DeleteTopicResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ /**
+ * Query the topics created by current account
+ *
+ * @param ListTopicRequest $request: define filters for quering topics
+ *
+ * @return ListTopicResponse: the response containing topicNames
+ */
+ public function listTopic(ListTopicRequest $request)
+ {
+ $response = new ListTopicResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ /**
+ * Query the AccountAttributes
+ *
+ * @return GetAccountAttributesResponse: the response containing topicNames
+ * @throws MnsException if any exception happends
+ */
+ public function getAccountAttributes()
+ {
+ $request = new GetAccountAttributesRequest();
+ $response = new GetAccountAttributesResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function getAccountAttributesAsync(AsyncCallback $callback = NULL)
+ {
+ $request = new GetAccountAttributesRequest();
+ $response = new GetAccountAttributesResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * Set the AccountAttributes
+ *
+ * @param AccountAttributes $attributes: the AccountAttributes to set
+ *
+ * @return SetAccountAttributesResponse: the response
+ *
+ * @throws MnsException if any exception happends
+ */
+ public function setAccountAttributes(AccountAttributes $attributes)
+ {
+ $request = new SetAccountAttributesRequest($attributes);
+ $response = new SetAccountAttributesResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function setAccountAttributesAsync(AccountAttributes $attributes,
+ AsyncCallback $callback = NULL)
+ {
+ $request = new SetAccountAttributesRequest($attributes);
+ $response = new SetAccountAttributesResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Common/XMLParser.php b/Lib/Alisms/AliyunMNS/Common/XMLParser.php
new file mode 100644
index 0000000..9925995
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Common/XMLParser.php
@@ -0,0 +1,51 @@
+ NULL, 'Message' => NULL, 'RequestId' => NULL, 'HostId' => NULL);
+ while ($xmlReader->Read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'Code':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $result['Code'] = $xmlReader->value;
+ }
+ break;
+ case 'Message':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $result['Message'] = $xmlReader->value;
+ }
+ break;
+ case 'RequestId':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $result['RequestId'] = $xmlReader->value;
+ }
+ break;
+ case 'HostId':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $result['HostId'] = $xmlReader->value;
+ }
+ break;
+ }
+ }
+ }
+ return $result;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Config.php b/Lib/Alisms/AliyunMNS/Config.php
new file mode 100644
index 0000000..4898fcd
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Config.php
@@ -0,0 +1,74 @@
+maxAttempts = 3;
+ $this->proxy = NULL;
+ $this->requestTimeout = 35; // 35 seconds
+ $this->connectTimeout = 3; // 3 seconds
+ $this->expectContinue = false;
+ }
+
+ /*
+ public function getMaxAttempts()
+ {
+ return $this->maxAttempts;
+ }
+
+ public function setMaxAttempts($maxAttempts)
+ {
+ $this->maxAttempts = $maxAttempts;
+ }
+ */
+
+ public function getProxy()
+ {
+ return $this->proxy;
+ }
+
+ public function setProxy($proxy)
+ {
+ $this->proxy = $proxy;
+ }
+
+ public function getRequestTimeout()
+ {
+ return $this->requestTimeout;
+ }
+
+ public function setRequestTimeout($requestTimeout)
+ {
+ $this->requestTimeout = $requestTimeout;
+ }
+
+ public function setConnectTimeout($connectTimeout)
+ {
+ $this->connectTimeout = $connectTimeout;
+ }
+
+ public function getConnectTimeout()
+ {
+ return $this->connectTimeout;
+ }
+
+ public function getExpectContinue()
+ {
+ return $this->expectContinue;
+ }
+
+ public function setExpectContinue($expectContinue)
+ {
+ $this->expectContinue = $expectContinue;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Constants.php b/Lib/Alisms/AliyunMNS/Constants.php
new file mode 100644
index 0000000..3cd8afa
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Constants.php
@@ -0,0 +1,76 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/BatchDeleteFailException.php b/Lib/Alisms/AliyunMNS/Exception/BatchDeleteFailException.php
new file mode 100644
index 0000000..8bc987c
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/BatchDeleteFailException.php
@@ -0,0 +1,35 @@
+deleteMessageErrorItems = array();
+ }
+
+ public function addDeleteMessageErrorItem(DeleteMessageErrorItem $item)
+ {
+ $this->deleteMessageErrorItems[] = $item;
+ }
+
+ public function getDeleteMessageErrorItems()
+ {
+ return $this->deleteMessageErrorItems;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Exception/BatchSendFailException.php b/Lib/Alisms/AliyunMNS/Exception/BatchSendFailException.php
new file mode 100644
index 0000000..da460f9
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/BatchSendFailException.php
@@ -0,0 +1,35 @@
+sendMessageResponseItems = array();
+ }
+
+ public function addSendMessageResponseItem(SendMessageResponseItem $item)
+ {
+ $this->sendMessageResponseItems[] = $item;
+ }
+
+ public function getSendMessageResponseItems()
+ {
+ return $this->sendMessageResponseItems;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Exception/InvalidArgumentException.php b/Lib/Alisms/AliyunMNS/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..b4b8caf
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/InvalidArgumentException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/MalformedXMLException.php b/Lib/Alisms/AliyunMNS/Exception/MalformedXMLException.php
new file mode 100644
index 0000000..21ebc34
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/MalformedXMLException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/MessageNotExistException.php b/Lib/Alisms/AliyunMNS/Exception/MessageNotExistException.php
new file mode 100644
index 0000000..f57e404
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/MessageNotExistException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/MnsException.php b/Lib/Alisms/AliyunMNS/Exception/MnsException.php
new file mode 100644
index 0000000..17f02e6
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/MnsException.php
@@ -0,0 +1,65 @@
+= 500)
+ {
+ $mnsErrorCode = "ServerError";
+ }
+ else
+ {
+ $mnsErrorCode = "ClientError";
+ }
+ }
+ $this->mnsErrorCode = $mnsErrorCode;
+
+ $this->requestId = $requestId;
+ $this->hostId = $hostId;
+ }
+
+ public function __toString()
+ {
+ $str = "Code: " . $this->getCode() . " Message: " . $this->getMessage();
+ if ($this->mnsErrorCode != NULL)
+ {
+ $str .= " MnsErrorCode: " . $this->mnsErrorCode;
+ }
+ if ($this->requestId != NULL)
+ {
+ $str .= " RequestId: " . $this->requestId;
+ }
+ if ($this->hostId != NULL)
+ {
+ $str .= " HostId: " . $this->hostId;
+ }
+ return $str;
+ }
+
+ public function getMnsErrorCode()
+ {
+ return $this->mnsErrorCode;
+ }
+
+ public function getRequestId()
+ {
+ return $this->requestId;
+ }
+
+ public function getHostId()
+ {
+ return $this->hostId;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Exception/QueueAlreadyExistException.php b/Lib/Alisms/AliyunMNS/Exception/QueueAlreadyExistException.php
new file mode 100644
index 0000000..4fbf87c
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/QueueAlreadyExistException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/QueueNotExistException.php b/Lib/Alisms/AliyunMNS/Exception/QueueNotExistException.php
new file mode 100644
index 0000000..ac176de
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/QueueNotExistException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/ReceiptHandleErrorException.php b/Lib/Alisms/AliyunMNS/Exception/ReceiptHandleErrorException.php
new file mode 100644
index 0000000..352377e
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/ReceiptHandleErrorException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/SubscriptionAlreadyExistException.php b/Lib/Alisms/AliyunMNS/Exception/SubscriptionAlreadyExistException.php
new file mode 100644
index 0000000..828ba40
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/SubscriptionAlreadyExistException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/SubscriptionNotExistException.php b/Lib/Alisms/AliyunMNS/Exception/SubscriptionNotExistException.php
new file mode 100644
index 0000000..f3397ff
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/SubscriptionNotExistException.php
@@ -0,0 +1,9 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/TopicAlreadyExistException.php b/Lib/Alisms/AliyunMNS/Exception/TopicAlreadyExistException.php
new file mode 100644
index 0000000..5adc8ed
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/TopicAlreadyExistException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Exception/TopicNotExistException.php b/Lib/Alisms/AliyunMNS/Exception/TopicNotExistException.php
new file mode 100644
index 0000000..f92a5d3
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Exception/TopicNotExistException.php
@@ -0,0 +1,10 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Http/HttpClient.php b/Lib/Alisms/AliyunMNS/Http/HttpClient.php
new file mode 100644
index 0000000..4d48858
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Http/HttpClient.php
@@ -0,0 +1,167 @@
+accessId = $accessId;
+ $this->accessKey = $accessKey;
+ $this->client = new \GuzzleHttp\Client([
+ 'base_uri' => $endPoint,
+ 'defaults' => [
+ 'headers' => [
+ 'Host' => $endPoint
+ ],
+ 'proxy' => $config->getProxy(),
+ 'expect' => $config->getExpectContinue()
+ ]
+ ]);
+ $this->requestTimeout = $config->getRequestTimeout();
+ $this->connectTimeout = $config->getConnectTimeout();
+ $this->securityToken = $securityToken;
+ $this->endpoint = $endPoint;
+ $this->parseEndpoint();
+ }
+
+ public function getRegion()
+ {
+ return $this->region;
+ }
+
+ public function getAccountId()
+ {
+ return $this->accountId;
+ }
+
+ // This function is for SDK internal use
+ private function parseEndpoint()
+ {
+ $pieces = explode("//", $this->endpoint);
+ $host = end($pieces);
+
+ $host_pieces = explode(".", $host);
+ $this->accountId = $host_pieces[0];
+ $region_pieces = explode("-internal", $host_pieces[2]);
+ $this->region = $region_pieces[0];
+ }
+
+ private function addRequiredHeaders(BaseRequest &$request)
+ {
+ $body = $request->generateBody();
+ $queryString = $request->generateQueryString();
+
+ $request->setBody($body);
+ $request->setQueryString($queryString);
+
+ if ($body != NULL)
+ {
+ $request->setHeader(Constants::CONTENT_LENGTH, strlen($body));
+ }
+ $request->setHeader('Date', gmdate(Constants::GMT_DATE_FORMAT));
+ if (!$request->isHeaderSet(Constants::CONTENT_TYPE))
+ {
+ $request->setHeader(Constants::CONTENT_TYPE, 'text/xml');
+ }
+ $request->setHeader(Constants::MNS_VERSION_HEADER, Constants::MNS_VERSION);
+
+ if ($this->securityToken != NULL)
+ {
+ $request->setHeader(Constants::SECURITY_TOKEN, $this->securityToken);
+ }
+
+ $sign = Signature::SignRequest($this->accessKey, $request);
+ $request->setHeader(Constants::AUTHORIZATION,
+ Constants::MNS . " " . $this->accessId . ":" . $sign);
+ }
+
+ public function sendRequestAsync(BaseRequest $request,
+ BaseResponse &$response, AsyncCallback $callback = NULL)
+ {
+ $promise = $this->sendRequestAsyncInternal($request, $response, $callback);
+ return new MnsPromise($promise, $response);
+ }
+
+ public function sendRequest(BaseRequest $request, BaseResponse &$response)
+ {
+ $promise = $this->sendRequestAsync($request, $response);
+ return $promise->wait();
+ }
+
+ private function sendRequestAsyncInternal(BaseRequest &$request, BaseResponse &$response, AsyncCallback $callback = NULL)
+ {
+ $this->addRequiredHeaders($request);
+
+ $parameters = array('exceptions' => false, 'http_errors' => false);
+ $queryString = $request->getQueryString();
+ $body = $request->getBody();
+ if ($queryString != NULL) {
+ $parameters['query'] = $queryString;
+ }
+ if ($body != NULL) {
+ $parameters['body'] = $body;
+ }
+
+ $parameters['timeout'] = $this->requestTimeout;
+ $parameters['connect_timeout'] = $this->connectTimeout;
+
+ $request = new Request(strtoupper($request->getMethod()),
+ $request->getResourcePath(), $request->getHeaders());
+ try
+ {
+ if ($callback != NULL)
+ {
+ return $this->client->sendAsync($request, $parameters)->then(
+ function ($res) use (&$response, $callback) {
+ try {
+ $response->parseResponse($res->getStatusCode(), $res->getBody());
+ $callback->onSucceed($response);
+ } catch (MnsException $e) {
+ $callback->onFailed($e);
+ }
+ }
+ );
+ }
+ else
+ {
+ return $this->client->sendAsync($request, $parameters);
+ }
+ }
+ catch (TransferException $e)
+ {
+ $message = $e->getMessage();
+ if ($e->hasResponse()) {
+ $message = $e->getResponse()->getBody();
+ }
+ throw new MnsException($e->getCode(), $message, $e);
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/AccountAttributes.php b/Lib/Alisms/AliyunMNS/Model/AccountAttributes.php
new file mode 100644
index 0000000..8127b83
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/AccountAttributes.php
@@ -0,0 +1,64 @@
+loggingBucket = $loggingBucket;
+ }
+
+ public function setLoggingBucket($loggingBucket)
+ {
+ $this->loggingBucket = $loggingBucket;
+ }
+
+ public function getLoggingBucket()
+ {
+ return $this->loggingBucket;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ if ($this->loggingBucket !== NULL)
+ {
+ $xmlWriter->writeElement(Constants::LOGGING_BUCKET, $this->loggingBucket);
+ }
+ }
+
+ static public function fromXML(\XMLReader $xmlReader)
+ {
+ $loggingBucket = NULL;
+
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'LoggingBucket':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $loggingBucket = $xmlReader->value;
+ }
+ break;
+ }
+ }
+ }
+
+ $attributes = new AccountAttributes($loggingBucket);
+ return $attributes;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/BatchSmsAttributes.php b/Lib/Alisms/AliyunMNS/Model/BatchSmsAttributes.php
new file mode 100644
index 0000000..38b9da7
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/BatchSmsAttributes.php
@@ -0,0 +1,97 @@
+freeSignName = $freeSignName;
+ $this->templateCode = $templateCode;
+ $this->smsParams = $smsParams;
+ }
+
+ public function setFreeSignName($freeSignName)
+ {
+ $this->freeSignName = $freeSignName;
+ }
+
+ public function getFreeSignName()
+ {
+ return $this->freeSignName;
+ }
+
+ public function setTemplateCode($templateCode)
+ {
+ $this->templateCode = $templateCode;
+ }
+
+ public function getTemplateCode()
+ {
+ return $this->templateCode;
+ }
+
+ public function addReceiver($phone, $params)
+ {
+ if (!is_array($params))
+ {
+ throw new MnsException(400, "Params Should be Array!");
+ }
+
+ if ($this->smsParams == null)
+ {
+ $this->smsParams = array();
+ }
+
+ $this->smsParams[$phone] = $params;
+ }
+
+ public function getSmsParams()
+ {
+ return $this->smsParams;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ $jsonArray = array("Type" => "multiContent");
+ if ($this->freeSignName !== NULL)
+ {
+ $jsonArray[Constants::FREE_SIGN_NAME] = $this->freeSignName;
+ }
+ if ($this->templateCode !== NULL)
+ {
+ $jsonArray[Constants::TEMPLATE_CODE] = $this->templateCode;
+ }
+
+ if ($this->smsParams != null)
+ {
+ if (!is_array($this->smsParams))
+ {
+ throw new MnsException(400, "SmsParams should be an array!");
+ }
+ if (!empty($this->smsParams))
+ {
+ $jsonArray[Constants::SMS_PARAMS] = json_encode($this->smsParams, JSON_FORCE_OBJECT);
+ }
+ }
+
+ if (!empty($jsonArray))
+ {
+ $xmlWriter->writeElement(Constants::DIRECT_SMS, json_encode($jsonArray));
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/DeleteMessageErrorItem.php b/Lib/Alisms/AliyunMNS/Model/DeleteMessageErrorItem.php
new file mode 100644
index 0000000..137a262
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/DeleteMessageErrorItem.php
@@ -0,0 +1,83 @@
+errorCode = $errorCode;
+ $this->errorMessage = $errorMessage;
+ $this->receiptHandle = $receiptHandle;
+ }
+
+ public function getErrorCode()
+ {
+ return $this->errorCode;
+ }
+
+ public function getErrorMessage()
+ {
+ return $this->errorMessage;
+ }
+
+ public function getReceiptHandle()
+ {
+ return $this->receiptHandle;
+ }
+
+ static public function fromXML($xmlReader)
+ {
+ $errorCode = NULL;
+ $errorMessage = NULL;
+ $receiptHandle = NULL;
+
+ while ($xmlReader->read())
+ {
+ switch ($xmlReader->nodeType)
+ {
+ case \XMLReader::ELEMENT:
+ switch ($xmlReader->name)
+ {
+ case Constants::ERROR_CODE:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $errorCode = $xmlReader->value;
+ }
+ break;
+ case Constants::ERROR_MESSAGE:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $errorMessage = $xmlReader->value;
+ }
+ break;
+ case Constants::RECEIPT_HANDLE:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $receiptHandle = $xmlReader->value;
+ }
+ break;
+ }
+ break;
+ case \XMLReader::END_ELEMENT:
+ if ($xmlReader->name == Constants::ERROR)
+ {
+ return new DeleteMessageErrorItem($errorCode, $errorMessage, $receiptHandle);
+ }
+ break;
+ }
+ }
+
+ return new DeleteMessageErrorItem($errorCode, $errorMessage, $receiptHandle);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/MailAttributes.php b/Lib/Alisms/AliyunMNS/Model/MailAttributes.php
new file mode 100644
index 0000000..bb74170
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/MailAttributes.php
@@ -0,0 +1,128 @@
+subject = $subject;
+ $this->accountName = $accountName;
+ $this->addressType = $addressType;
+ $this->replyToAddress = $replyToAddress;
+ $this->isHtml = $isHtml;
+ }
+
+ public function setSubject($subject)
+ {
+ $this->subject = $subject;
+ }
+
+ public function getSubject()
+ {
+ return $this->subject;
+ }
+
+ public function setAccountName($accountName)
+ {
+ $this->accountName = $accountName;
+ }
+
+ public function getAccountName()
+ {
+ return $this->accountName;
+ }
+
+ public function setAddressType($addressType)
+ {
+ $this->addressType = $addressType;
+ }
+
+ public function getAddressType()
+ {
+ return $this->addressType;
+ }
+
+ public function setReplyToAddress($replyToAddress)
+ {
+ $this->replyToAddress = $replyToAddress;
+ }
+
+ public function getReplyToAddress()
+ {
+ return $this->replyToAddress;
+ }
+
+ public function setIsHtml($isHtml)
+ {
+ $this->isHtml = $isHtml;
+ }
+
+ public function getIsHtml()
+ {
+ return $this->isHtml;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ $jsonArray = array();
+ if ($this->subject !== NULL)
+ {
+ $jsonArray[Constants::SUBJECT] = $this->subject;
+ }
+ if ($this->accountName !== NULL)
+ {
+ $jsonArray[Constants::ACCOUNT_NAME] = $this->accountName;
+ }
+ if ($this->addressType !== NULL)
+ {
+ $jsonArray[Constants::ADDRESS_TYPE] = $this->addressType;
+ }
+ else
+ {
+ $jsonArray[Constants::ADDRESS_TYPE] = 0;
+ }
+ if ($this->replyToAddress !== NULL)
+ {
+ if ($this->replyToAddress === TRUE)
+ {
+ $jsonArray[Constants::REPLY_TO_ADDRESS] = "1";
+ }
+ else
+ {
+ $jsonArray[Constants::REPLY_TO_ADDRESS] = "0";
+ }
+ }
+ if ($this->isHtml !== NULL)
+ {
+ if ($this->isHtml === TRUE)
+ {
+ $jsonArray[Constants::IS_HTML] = "1";
+ }
+ else
+ {
+ $jsonArray[Constants::IS_HTML] = "0";
+ }
+ }
+
+ if (!empty($jsonArray))
+ {
+ $xmlWriter->writeElement(Constants::DIRECT_MAIL, json_encode($jsonArray));
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/Message.php b/Lib/Alisms/AliyunMNS/Model/Message.php
new file mode 100644
index 0000000..5dc67ac
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/Message.php
@@ -0,0 +1,145 @@
+messageId = $messageId;
+ $this->messageBodyMD5 = $messageBodyMD5;
+ $this->messageBody = $messageBody;
+ $this->enqueueTime = $enqueueTime;
+ $this->nextVisibleTime = $nextVisibleTime;
+ $this->firstDequeueTime = $firstDequeueTime;
+ $this->dequeueCount = $dequeueCount;
+ $this->priority = $priority;
+ $this->receiptHandle = $receiptHandle;
+ }
+
+ static public function fromXML(\XMLReader $xmlReader, $base64)
+ {
+ $messageId = NULL;
+ $messageBodyMD5 = NULL;
+ $messageBody = NULL;
+ $enqueueTime = NULL;
+ $nextVisibleTime = NULL;
+ $firstDequeueTime = NULL;
+ $dequeueCount = NULL;
+ $priority = NULL;
+ $receiptHandle = NULL;
+
+ while ($xmlReader->read())
+ {
+ switch ($xmlReader->nodeType)
+ {
+ case \XMLReader::ELEMENT:
+ switch ($xmlReader->name) {
+ case Constants::MESSAGE_ID:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $messageId = $xmlReader->value;
+ }
+ break;
+ case Constants::MESSAGE_BODY_MD5:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $messageBodyMD5 = $xmlReader->value;
+ }
+ break;
+ case Constants::MESSAGE_BODY:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ if ($base64 == TRUE) {
+ $messageBody = base64_decode($xmlReader->value);
+ } else {
+ $messageBody = $xmlReader->value;
+ }
+ }
+ break;
+ case Constants::ENQUEUE_TIME:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $enqueueTime = $xmlReader->value;
+ }
+ break;
+ case Constants::NEXT_VISIBLE_TIME:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $nextVisibleTime = $xmlReader->value;
+ }
+ break;
+ case Constants::FIRST_DEQUEUE_TIME:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $firstDequeueTime = $xmlReader->value;
+ }
+ break;
+ case Constants::DEQUEUE_COUNT:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $dequeueCount = $xmlReader->value;
+ }
+ break;
+ case Constants::PRIORITY:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $priority = $xmlReader->value;
+ }
+ break;
+ case Constants::RECEIPT_HANDLE:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $receiptHandle = $xmlReader->value;
+ }
+ break;
+ }
+ break;
+ case \XMLReader::END_ELEMENT:
+ if ($xmlReader->name == 'Message')
+ {
+ $message = new Message(
+ $messageId,
+ $messageBodyMD5,
+ $messageBody,
+ $enqueueTime,
+ $nextVisibleTime,
+ $firstDequeueTime,
+ $dequeueCount,
+ $priority,
+ $receiptHandle);
+ return $message;
+ }
+ break;
+ }
+ }
+
+ $message = new Message(
+ $messageId,
+ $messageBodyMD5,
+ $messageBody,
+ $enqueueTime,
+ $nextVisibleTime,
+ $firstDequeueTime,
+ $dequeueCount,
+ $priority,
+ $receiptHandle);
+
+ return $message;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/MessageAttributes.php b/Lib/Alisms/AliyunMNS/Model/MessageAttributes.php
new file mode 100644
index 0000000..d676c7e
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/MessageAttributes.php
@@ -0,0 +1,53 @@
+attributes = $attributes;
+ }
+
+ public function setAttributes($attributes)
+ {
+ $this->attributes = $attributes;
+ }
+
+ public function getAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ $xmlWriter->startELement(Constants::MESSAGE_ATTRIBUTES);
+ if ($this->attributes != NULL)
+ {
+ if (is_array($this->attributes))
+ {
+ foreach ($this->attributes as $subAttributes)
+ {
+ $subAttributes->writeXML($xmlWriter);
+ }
+ }
+ else
+ {
+ $this->attributes->writeXML($xmlWriter);
+ }
+ }
+ $xmlWriter->endElement();
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/QueueAttributes.php b/Lib/Alisms/AliyunMNS/Model/QueueAttributes.php
new file mode 100644
index 0000000..ae9b7ec
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/QueueAttributes.php
@@ -0,0 +1,308 @@
+delaySeconds = $delaySeconds;
+ $this->maximumMessageSize = $maximumMessageSize;
+ $this->messageRetentionPeriod = $messageRetentionPeriod;
+ $this->visibilityTimeout = $visibilityTimeout;
+ $this->pollingWaitSeconds = $pollingWaitSeconds;
+ $this->loggingEnabled = $LoggingEnabled;
+
+ $this->queueName = $queueName;
+ $this->createTime = $createTime;
+ $this->lastModifyTime = $lastModifyTime;
+ $this->activeMessages = $activeMessages;
+ $this->inactiveMessages = $inactiveMessages;
+ $this->delayMessages = $delayMessages;
+ }
+
+ public function setDelaySeconds($delaySeconds)
+ {
+ $this->delaySeconds = $delaySeconds;
+ }
+
+ public function getDelaySeconds()
+ {
+ return $this->delaySeconds;
+ }
+
+ public function setLoggingEnabled($loggingEnabled)
+ {
+ $this->loggingEnabled = $loggingEnabled;
+ }
+
+ public function getLoggingEnabled()
+ {
+ return $this->loggingEnabled;
+ }
+
+ public function setMaximumMessageSize($maximumMessageSize)
+ {
+ $this->maximumMessageSize = $maximumMessageSize;
+ }
+
+ public function getMaximumMessageSize()
+ {
+ return $this->maximumMessageSize;
+ }
+
+ public function setMessageRetentionPeriod($messageRetentionPeriod)
+ {
+ $this->messageRetentionPeriod = $messageRetentionPeriod;
+ }
+
+ public function getMessageRetentionPeriod()
+ {
+ return $this->messageRetentionPeriod;
+ }
+
+ public function setVisibilityTimeout($visibilityTimeout)
+ {
+ $this->visibilityTimeout = $visibilityTimeout;
+ }
+
+ public function getVisibilityTimeout()
+ {
+ return $this->visibilityTimeout;
+ }
+
+ public function setPollingWaitSeconds($pollingWaitSeconds)
+ {
+ $this->pollingWaitSeconds = $pollingWaitSeconds;
+ }
+
+ public function getPollingWaitSeconds()
+ {
+ return $this->pollingWaitSeconds;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getCreateTime()
+ {
+ return $this->createTime;
+ }
+
+ public function getLastModifyTime()
+ {
+ return $this->lastModifyTime;
+ }
+
+ public function getActiveMessages()
+ {
+ return $this->activeMessages;
+ }
+
+ public function getInactiveMessages()
+ {
+ return $this->inactiveMessages;
+ }
+
+ public function getDelayMessages()
+ {
+ return $this->delayMessages;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ if ($this->delaySeconds != NULL)
+ {
+ $xmlWriter->writeElement(Constants::DELAY_SECONDS, $this->delaySeconds);
+ }
+ if ($this->maximumMessageSize != NULL)
+ {
+ $xmlWriter->writeElement(Constants::MAXIMUM_MESSAGE_SIZE, $this->maximumMessageSize);
+ }
+ if ($this->messageRetentionPeriod != NULL)
+ {
+ $xmlWriter->writeElement(Constants::MESSAGE_RETENTION_PERIOD, $this->messageRetentionPeriod);
+ }
+ if ($this->visibilityTimeout != NULL)
+ {
+ $xmlWriter->writeElement(Constants::VISIBILITY_TIMEOUT, $this->visibilityTimeout);
+ }
+ if ($this->pollingWaitSeconds != NULL)
+ {
+ $xmlWriter->writeElement(Constants::POLLING_WAIT_SECONDS, $this->pollingWaitSeconds);
+ }
+ if ($this->loggingEnabled !== NULL)
+ {
+ $xmlWriter->writeElement(Constants::LOGGING_ENABLED, $this->loggingEnabled ? "True" : "False");
+ }
+ }
+
+ static public function fromXML(\XMLReader $xmlReader)
+ {
+ $delaySeconds = NULL;
+ $maximumMessageSize = NULL;
+ $messageRetentionPeriod = NULL;
+ $visibilityTimeout = NULL;
+ $pollingWaitSeconds = NULL;
+ $queueName = NULL;
+ $createTime = NULL;
+ $lastModifyTime = NULL;
+ $activeMessages = NULL;
+ $inactiveMessages = NULL;
+ $delayMessages = NULL;
+ $loggingEnabled = NULL;
+
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'DelaySeconds':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $delaySeconds = $xmlReader->value;
+ }
+ break;
+ case 'MaximumMessageSize':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $maximumMessageSize = $xmlReader->value;
+ }
+ break;
+ case 'MessageRetentionPeriod':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $messageRetentionPeriod = $xmlReader->value;
+ }
+ break;
+ case 'VisibilityTimeout':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $visibilityTimeout = $xmlReader->value;
+ }
+ break;
+ case 'PollingWaitSeconds':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $pollingWaitSeconds = $xmlReader->value;
+ }
+ break;
+ case 'QueueName':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $queueName = $xmlReader->value;
+ }
+ break;
+ case 'CreateTime':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $createTime = $xmlReader->value;
+ }
+ break;
+ case 'LastModifyTime':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $lastModifyTime = $xmlReader->value;
+ }
+ break;
+ case 'ActiveMessages':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $activeMessages = $xmlReader->value;
+ }
+ break;
+ case 'InactiveMessages':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $inactiveMessages = $xmlReader->value;
+ }
+ break;
+ case 'DelayMessages':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $delayMessages = $xmlReader->value;
+ }
+ break;
+ case 'LoggingEnabled':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $loggingEnabled = $xmlReader->value;
+ if ($loggingEnabled == "True")
+ {
+ $loggingEnabled = True;
+ }
+ else
+ {
+ $loggingEnabled = False;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ $attributes = new QueueAttributes(
+ $delaySeconds,
+ $maximumMessageSize,
+ $messageRetentionPeriod,
+ $visibilityTimeout,
+ $pollingWaitSeconds,
+ $queueName,
+ $createTime,
+ $lastModifyTime,
+ $activeMessages,
+ $inactiveMessages,
+ $delayMessages,
+ $loggingEnabled);
+ return $attributes;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/SendMessageRequestItem.php b/Lib/Alisms/AliyunMNS/Model/SendMessageRequestItem.php
new file mode 100644
index 0000000..66deb16
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/SendMessageRequestItem.php
@@ -0,0 +1,27 @@
+messageBody = $messageBody;
+ $this->delaySeconds = $delaySeconds;
+ $this->priority = $priority;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter, $base64)
+ {
+ $xmlWriter->startELement('Message');
+ $this->writeMessagePropertiesForSendXML($xmlWriter, $base64);
+ $xmlWriter->endElement();
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/SendMessageResponseItem.php b/Lib/Alisms/AliyunMNS/Model/SendMessageResponseItem.php
new file mode 100644
index 0000000..20e4cbb
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/SendMessageResponseItem.php
@@ -0,0 +1,119 @@
+isSucceed = $isSucceed;
+ if ($isSucceed == TRUE)
+ {
+ $this->messageId = $param1;
+ $this->messageBodyMD5 = $param2;
+ }
+ else
+ {
+ $this->errorCode = $param1;
+ $this->errorMessage = $param2;
+ }
+ }
+
+ public function isSucceed()
+ {
+ return $this->isSucceed;
+ }
+
+ public function getErrorCode()
+ {
+ return $this->errorCode;
+ }
+
+ public function getErrorMessage()
+ {
+ return $this->errorMessage;
+ }
+
+ static public function fromXML($xmlReader)
+ {
+ $messageId = NULL;
+ $messageBodyMD5 = NULL;
+ $errorCode = NULL;
+ $errorMessage = NULL;
+
+ while ($xmlReader->read())
+ {
+ switch ($xmlReader->nodeType)
+ {
+ case \XMLReader::ELEMENT:
+ switch ($xmlReader->name) {
+ case Constants::MESSAGE_ID:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $messageId = $xmlReader->value;
+ }
+ break;
+ case Constants::MESSAGE_BODY_MD5:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $messageBodyMD5 = $xmlReader->value;
+ }
+ break;
+ case Constants::ERROR_CODE:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $errorCode = $xmlReader->value;
+ }
+ break;
+ case Constants::ERROR_MESSAGE:
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $errorMessage = $xmlReader->value;
+ }
+ break;
+ }
+ break;
+ case \XMLReader::END_ELEMENT:
+ if ($xmlReader->name == 'Message')
+ {
+ if ($messageId != NULL)
+ {
+ return new SendMessageResponseItem(TRUE, $messageId, $messageBodyMD5);
+ }
+ else
+ {
+ return new SendMessageResponseItem(FALSE, $errorCode, $errorMessage);
+ }
+ }
+ break;
+ }
+ }
+
+ if ($messageId != NULL)
+ {
+ return new SendMessageResponseItem(TRUE, $messageId, $messageBodyMD5);
+ }
+ else
+ {
+ return new SendMessageResponseItem(FALSE, $errorCode, $errorMessage);
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/SmsAttributes.php b/Lib/Alisms/AliyunMNS/Model/SmsAttributes.php
new file mode 100644
index 0000000..025b084
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/SmsAttributes.php
@@ -0,0 +1,100 @@
+freeSignName = $freeSignName;
+ $this->templateCode = $templateCode;
+ $this->smsParams = $smsParams;
+ $this->receiver = $receiver;
+ }
+
+ public function setFreeSignName($freeSignName)
+ {
+ $this->freeSignName = $freeSignName;
+ }
+
+ public function getFreeSignName()
+ {
+ return $this->freeSignName;
+ }
+
+ public function setTemplateCode($templateCode)
+ {
+ $this->templateCode = $templateCode;
+ }
+
+ public function getTemplateCode()
+ {
+ return $this->templateCode;
+ }
+
+ public function setSmsParams($smsParams)
+ {
+ $this->smsParams = $smsParams;
+ }
+
+ public function getSmsParams()
+ {
+ return $this->smsParams;
+ }
+
+ public function setReceiver($receiver)
+ {
+ $this->receiver = $receiver;
+ }
+
+ public function getReceiver()
+ {
+ return $this->receiver;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ $jsonArray = array();
+ if ($this->freeSignName !== NULL)
+ {
+ $jsonArray[Constants::FREE_SIGN_NAME] = $this->freeSignName;
+ }
+ if ($this->templateCode !== NULL)
+ {
+ $jsonArray[Constants::TEMPLATE_CODE] = $this->templateCode;
+ }
+ if ($this->receiver !== NULL)
+ {
+ $jsonArray[Constants::RECEIVER] = $this->receiver;
+ }
+
+ if ($this->smsParams !== null)
+ {
+ if (!is_array($this->smsParams))
+ {
+ throw new MnsException(400, "SmsParams should be an array!");
+ }
+ $jsonArray[Constants::SMS_PARAMS] = json_encode($this->smsParams, JSON_FORCE_OBJECT);
+ }
+
+ if (!empty($jsonArray))
+ {
+ $xmlWriter->writeElement(Constants::DIRECT_SMS, json_encode($jsonArray));
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/SubscriptionAttributes.php b/Lib/Alisms/AliyunMNS/Model/SubscriptionAttributes.php
new file mode 100644
index 0000000..e8eb534
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/SubscriptionAttributes.php
@@ -0,0 +1,207 @@
+endpoint = $endpoint;
+ $this->strategy = $strategy;
+ $this->contentFormat = $contentFormat;
+ $this->subscriptionName = $subscriptionName;
+
+ //cloud change in AliyunMNS\Topic
+ $this->topicName = $topicName;
+
+ $this->topicOwner = $topicOwner;
+ $this->createTime = $createTime;
+ $this->lastModifyTime = $lastModifyTime;
+ }
+
+ public function getEndpoint()
+ {
+ return $this->endpoint;
+ }
+
+ public function setEndpoint($endpoint)
+ {
+ $this->endpoint = $endpoint;
+ }
+
+ public function getStrategy()
+ {
+ return $this->strategy;
+ }
+
+ public function setStrategy($strategy)
+ {
+ $this->strategy = $strategy;
+ }
+
+ public function getContentFormat()
+ {
+ return $this->contentFormat;
+ }
+
+ public function setContentFormat($contentFormat)
+ {
+ $this->contentFormat = $contentFormat;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function setTopicName($topicName)
+ {
+ $this->topicName = $topicName;
+ }
+
+ public function getTopicOwner()
+ {
+ return $this->topicOwner;
+ }
+
+ public function getSubscriptionName()
+ {
+ return $this->subscriptionName;
+ }
+
+ public function getCreateTime()
+ {
+ return $this->createTime;
+ }
+
+ public function getLastModifyTime()
+ {
+ return $this->lastModifyTime;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ if ($this->endpoint != NULL)
+ {
+ $xmlWriter->writeElement(Constants::ENDPOINT, $this->endpoint);
+ }
+ if ($this->strategy != NULL)
+ {
+ $xmlWriter->writeElement(Constants::STRATEGY, $this->strategy);
+ }
+ if ($this->contentFormat != NULL)
+ {
+ $xmlWriter->writeElement(Constants::CONTENT_FORMAT, $this->contentFormat);
+ }
+ }
+
+ static public function fromXML(\XMLReader $xmlReader)
+ {
+ $endpoint = NULL;
+ $strategy = NULL;
+ $contentFormat = NULL;
+ $topicOwner = NULL;
+ $topicName = NULL;
+ $createTime = NULL;
+ $lastModifyTime = NULL;
+
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'TopicOwner':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $topicOwner = $xmlReader->value;
+ }
+ break;
+ case 'TopicName':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $topicName = $xmlReader->value;
+ }
+ break;
+ case 'SubscriptionName':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $subscriptionName = $xmlReader->value;
+ }
+ case 'Endpoint':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $endpoint = $xmlReader->value;
+ }
+ break;
+ case 'NotifyStrategy':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $strategy = $xmlReader->value;
+ }
+ break;
+ case 'NotifyContentFormat':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $contentFormat = $xmlReader->value;
+ }
+ break;
+ case 'CreateTime':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $createTime = $xmlReader->value;
+ }
+ break;
+ case 'LastModifyTime':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $lastModifyTime = $xmlReader->value;
+ }
+ break;
+ }
+ }
+ }
+
+ $attributes = new SubscriptionAttributes(
+ $subscriptionName,
+ $endpoint,
+ $strategy,
+ $contentFormat,
+ $topicName,
+ $topicOwner,
+ $createTime,
+ $lastModifyTime);
+ return $attributes;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/TopicAttributes.php b/Lib/Alisms/AliyunMNS/Model/TopicAttributes.php
new file mode 100644
index 0000000..e7d5c11
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/TopicAttributes.php
@@ -0,0 +1,179 @@
+maximumMessageSize = $maximumMessageSize;
+ $this->messageRetentionPeriod = $messageRetentionPeriod;
+ $this->loggingEnabled = $LoggingEnabled;
+
+ $this->topicName = $topicName;
+ $this->createTime = $createTime;
+ $this->lastModifyTime = $lastModifyTime;
+ }
+
+ public function setMaximumMessageSize($maximumMessageSize)
+ {
+ $this->maximumMessageSize = $maximumMessageSize;
+ }
+
+ public function getMaximumMessageSize()
+ {
+ return $this->maximumMessageSize;
+ }
+
+ public function setLoggingEnabled($loggingEnabled)
+ {
+ $this->loggingEnabled = $loggingEnabled;
+ }
+
+ public function getLoggingEnabled()
+ {
+ return $this->loggingEnabled;
+ }
+
+ public function setMessageRetentionPeriod($messageRetentionPeriod)
+ {
+ $this->messageRetentionPeriod = $messageRetentionPeriod;
+ }
+
+ public function getMessageRetentionPeriod()
+ {
+ return $this->messageRetentionPeriod;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function getCreateTime()
+ {
+ return $this->createTime;
+ }
+
+ public function getLastModifyTime()
+ {
+ return $this->lastModifyTime;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ if ($this->maximumMessageSize != NULL)
+ {
+ $xmlWriter->writeElement(Constants::MAXIMUM_MESSAGE_SIZE, $this->maximumMessageSize);
+ }
+ if ($this->messageRetentionPeriod != NULL)
+ {
+ $xmlWriter->writeElement(Constants::MESSAGE_RETENTION_PERIOD, $this->messageRetentionPeriod);
+ }
+ if ($this->loggingEnabled !== NULL)
+ {
+ $xmlWriter->writeElement(Constants::LOGGING_ENABLED, $this->loggingEnabled ? "True" : "False");
+ }
+ }
+
+ static public function fromXML(\XMLReader $xmlReader)
+ {
+ $maximumMessageSize = NULL;
+ $messageRetentionPeriod = NULL;
+ $topicName = NULL;
+ $createTime = NULL;
+ $lastModifyTime = NULL;
+ $loggingEnabled = NULL;
+
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'MaximumMessageSize':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $maximumMessageSize = $xmlReader->value;
+ }
+ break;
+ case 'MessageRetentionPeriod':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $messageRetentionPeriod = $xmlReader->value;
+ }
+ break;
+ case 'TopicName':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $topicName = $xmlReader->value;
+ }
+ break;
+ case 'CreateTime':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $createTime = $xmlReader->value;
+ }
+ break;
+ case 'LastModifyTime':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $lastModifyTime = $xmlReader->value;
+ }
+ break;
+ case 'LoggingEnabled':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $loggingEnabled = $xmlReader->value;
+ if ($loggingEnabled == "True")
+ {
+ $loggingEnabled = True;
+ }
+ else
+ {
+ $loggingEnabled = False;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ $attributes = new TopicAttributes(
+ $maximumMessageSize,
+ $messageRetentionPeriod,
+ $topicName,
+ $createTime,
+ $lastModifyTime,
+ $loggingEnabled);
+ return $attributes;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/UpdateSubscriptionAttributes.php b/Lib/Alisms/AliyunMNS/Model/UpdateSubscriptionAttributes.php
new file mode 100644
index 0000000..f1b2079
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/UpdateSubscriptionAttributes.php
@@ -0,0 +1,58 @@
+subscriptionName = $subscriptionName;
+
+ $this->strategy = $strategy;
+ }
+
+ public function getStrategy()
+ {
+ return $this->strategy;
+ }
+
+ public function setStrategy($strategy)
+ {
+ $this->strategy = $strategy;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function setTopicName($topicName)
+ {
+ $this->topicName = $topicName;
+ }
+
+ public function getSubscriptionName()
+ {
+ return $this->subscriptionName;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ if ($this->strategy != NULL)
+ {
+ $xmlWriter->writeElement(Constants::STRATEGY, $this->strategy);
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Model/WebSocketAttributes.php b/Lib/Alisms/AliyunMNS/Model/WebSocketAttributes.php
new file mode 100644
index 0000000..c38785b
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Model/WebSocketAttributes.php
@@ -0,0 +1,33 @@
+importanceLevel = $importanceLevel;
+ }
+
+ public function setImportanceLevel($importanceLevel)
+ {
+ $this->importanceLevel = $importanceLevel;
+ }
+
+ public function getImportanceLevel()
+ {
+ return $this->importanceLevel;
+ }
+
+ public function writeXML(\XMLWriter $xmlWriter)
+ {
+ $jsonArray = array(Constants::IMPORTANCE_LEVEL => $this->importanceLevel);
+ $xmlWriter->writeElement(Constants::WEBSOCKET, json_encode($jsonArray));
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Queue.php b/Lib/Alisms/AliyunMNS/Queue.php
new file mode 100644
index 0000000..8d63d51
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Queue.php
@@ -0,0 +1,377 @@
+queueName = $queueName;
+ $this->client = $client;
+ $this->base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ /**
+ * Set the QueueAttributes, detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&queue_operation
+ *
+ * @param QueueAttributes $attributes: the QueueAttributes to set
+ *
+ * @return SetQueueAttributeResponse: the response
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws InvalidArgumentException if any argument value is invalid
+ * @throws MnsException if any other exception happends
+ */
+ public function setAttribute(QueueAttributes $attributes)
+ {
+ $request = new SetQueueAttributeRequest($this->queueName, $attributes);
+ $response = new SetQueueAttributeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function setAttributeAsync(QueueAttributes $attributes,
+ AsyncCallback $callback = NULL)
+ {
+ $request = new SetQueueAttributeRequest($this->queueName, $attributes);
+ $response = new SetQueueAttributeResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * Get the QueueAttributes, detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&queue_operation
+ *
+ * @return GetQueueAttributeResponse: containing the attributes
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MnsException if any other exception happends
+ */
+ public function getAttribute()
+ {
+ $request = new GetQueueAttributeRequest($this->queueName);
+ $response = new GetQueueAttributeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function getAttributeAsync(AsyncCallback $callback = NULL)
+ {
+ $request = new GetQueueAttributeRequest($this->queueName);
+ $response = new GetQueueAttributeResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * SendMessage, the messageBody will be automatically encoded in base64
+ * If you do not need the message body to be encoded in Base64,
+ * please specify the $base64 = FALSE in Queue
+ *
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param SendMessageRequest: containing the message body and properties
+ *
+ * @return SendMessageResponse: containing the messageId and bodyMD5
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws InvalidArgumentException if any argument value is invalid
+ * @throws MalformedXMLException if any error in xml
+ * @throws MnsException if any other exception happends
+ */
+ public function sendMessage(SendMessageRequest $request)
+ {
+ $request->setQueueName($this->queueName);
+ $request->setBase64($this->base64);
+ $response = new SendMessageResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function sendMessageAsync(SendMessageRequest $request,
+ AsyncCallback $callback = NULL)
+ {
+ $request->setQueueName($this->queueName);
+ $request->setBase64($this->base64);
+ $response = new SendMessageResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * PeekMessage, the messageBody will be automatically decoded as base64 if the $base64 in Queue is TRUE
+ *
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @return PeekMessageResponse: containing the messageBody and properties
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MessageNotExistException if no message exists in the queue
+ * @throws MnsException if any other exception happends
+ */
+ public function peekMessage()
+ {
+ $request = new PeekMessageRequest($this->queueName);
+ $response = new PeekMessageResponse($this->base64);
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function peekMessageAsync(AsyncCallback $callback = NULL)
+ {
+ $request = new PeekMessageRequest($this->queueName);
+ $response = new PeekMessageResponse($this->base64);
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * ReceiveMessage, the messageBody will be automatically decoded as base64 if $base64 = TRUE in Queue
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param waitSeconds: the long polling waitseconds
+ *
+ * @return ReceiveMessageResponse: containing the messageBody and properties
+ * the response is same as PeekMessageResponse,
+ * except that the receiptHandle is also returned in receiveMessage
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MessageNotExistException if no message exists in the queue
+ * @throws MnsException if any other exception happends
+ */
+ public function receiveMessage($waitSeconds = NULL)
+ {
+ $request = new ReceiveMessageRequest($this->queueName, $waitSeconds);
+ $response = new ReceiveMessageResponse($this->base64);
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function receiveMessageAsync(AsyncCallback $callback = NULL)
+ {
+ $request = new ReceiveMessageRequest($this->queueName);
+ $response = new ReceiveMessageResponse($this->base64);
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * DeleteMessage
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param $receiptHandle: the receiptHandle returned from receiveMessage
+ *
+ * @return ReceiveMessageResponse
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws InvalidArgumentException if the argument is invalid
+ * @throws ReceiptHandleErrorException if the $receiptHandle is invalid
+ * @throws MnsException if any other exception happends
+ */
+ public function deleteMessage($receiptHandle)
+ {
+ $request = new DeleteMessageRequest($this->queueName, $receiptHandle);
+ $response = new DeleteMessageResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function deleteMessageAsync($receiptHandle,
+ AsyncCallback $callback = NULL)
+ {
+ $request = new DeleteMessageRequest($this->queueName, $receiptHandle);
+ $response = new DeleteMessageResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * ChangeMessageVisibility, set the nextVisibleTime for the message
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param $receiptHandle: the receiptHandle returned from receiveMessage
+ *
+ * @return ChangeMessageVisibilityResponse
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MessageNotExistException if the message does not exist
+ * @throws InvalidArgumentException if the argument is invalid
+ * @throws ReceiptHandleErrorException if the $receiptHandle is invalid
+ * @throws MnsException if any other exception happends
+ */
+ public function changeMessageVisibility($receiptHandle, $visibilityTimeout)
+ {
+ $request = new ChangeMessageVisibilityRequest($this->queueName, $receiptHandle, $visibilityTimeout);
+ $response = new ChangeMessageVisibilityResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ /**
+ * BatchSendMessage, message body will be automatically encoded in base64
+ * If you do not need the message body to be encoded in Base64,
+ * please specify the $base64 = FALSE in Queue
+ *
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param BatchSendMessageRequest:
+ * the requests containing an array of SendMessageRequestItems
+ *
+ * @return BatchSendMessageResponse
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MalformedXMLException if any error in the xml
+ * @throws InvalidArgumentException if the argument is invalid
+ * @throws BatchSendFailException if some messages are not sent
+ * @throws MnsException if any other exception happends
+ */
+ public function batchSendMessage(BatchSendMessageRequest $request)
+ {
+ $request->setQueueName($this->queueName);
+ $request->setBase64($this->base64);
+ $response = new BatchSendMessageResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function batchSendMessageAsync(BatchSendMessageRequest $request,
+ AsyncCallback $callback = NULL)
+ {
+ $request->setQueueName($this->queueName);
+ $request->setBase64($this->base64);
+ $response = new BatchSendMessageResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * BatchReceiveMessage, message body will be automatically decoded as base64 if $base64 = TRUE in Queue
+ *
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param BatchReceiveMessageRequest:
+ * containing numOfMessages and waitSeconds
+ *
+ * @return BatchReceiveMessageResponse:
+ * the received messages
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MessageNotExistException if no message exists
+ * @throws MnsException if any other exception happends
+ */
+ public function batchReceiveMessage(BatchReceiveMessageRequest $request)
+ {
+ $request->setQueueName($this->queueName);
+ $response = new BatchReceiveMessageResponse($this->base64);
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function batchReceiveMessageAsync(BatchReceiveMessageRequest $request, AsyncCallback $callback = NULL)
+ {
+ $request->setQueueName($this->queueName);
+ $response = new BatchReceiveMessageResponse($this->base64);
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * BatchPeekMessage, message body will be automatically decoded as base64 is $base64 = TRUE in Queue
+ *
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param BatchPeekMessageRequest:
+ * containing numOfMessages and waitSeconds
+ *
+ * @return BatchPeekMessageResponse:
+ * the received messages
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws MessageNotExistException if no message exists
+ * @throws MnsException if any other exception happends
+ */
+ public function batchPeekMessage($numOfMessages)
+ {
+ $request = new BatchPeekMessageRequest($this->queueName, $numOfMessages);
+ $response = new BatchPeekMessageResponse($this->base64);
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function batchPeekMessageAsync($numOfMessages, AsyncCallback $callback = NULL)
+ {
+ $request = new BatchPeekMessageRequest($this->queueName, $numOfMessages);
+ $response = new BatchPeekMessageResponse($this->base64);
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+
+ /**
+ * BatchDeleteMessage
+ * detail API sepcs:
+ * https://docs.aliyun.com/?spm=#/pub/mns/api_reference/api_spec&message_operation
+ *
+ * @param $receiptHandles:
+ * array of $receiptHandle, which is got from receiveMessage
+ *
+ * @return BatchDeleteMessageResponse
+ *
+ * @throws QueueNotExistException if queue does not exist
+ * @throws ReceiptHandleErrorException if the receiptHandle is invalid
+ * @throws InvalidArgumentException if the argument is invalid
+ * @throws BatchDeleteFailException if any message not deleted
+ * @throws MnsException if any other exception happends
+ */
+ public function batchDeleteMessage($receiptHandles)
+ {
+ $request = new BatchDeleteMessageRequest($this->queueName, $receiptHandles);
+ $response = new BatchDeleteMessageResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function batchDeleteMessageAsync($receiptHandles, AsyncCallback $callback = NULL)
+ {
+ $request = new BatchDeleteMessageRequest($this->queueName, $receiptHandles);
+ $response = new BatchDeleteMessageResponse();
+ return $this->client->sendRequestAsync($request, $response, $callback);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/BaseRequest.php b/Lib/Alisms/AliyunMNS/Requests/BaseRequest.php
new file mode 100644
index 0000000..78e98b2
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/BaseRequest.php
@@ -0,0 +1,75 @@
+method = $method;
+ $this->resourcePath = $resourcePath;
+ }
+
+ abstract public function generateBody();
+ abstract public function generateQueryString();
+
+ public function setBody($body)
+ {
+ $this->body = $body;
+ }
+
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+ public function setQueryString($queryString)
+ {
+ $this->queryString = $queryString;
+ }
+
+ public function getQueryString()
+ {
+ return $this->queryString;
+ }
+
+ public function isHeaderSet($header)
+ {
+ return isset($this->headers[$header]);
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ public function removeHeader($header)
+ {
+ if (isset($this->headers[$header]))
+ {
+ unset($this->headers[$header]);
+ }
+ }
+
+ public function setHeader($header, $value)
+ {
+ $this->headers[$header] = $value;
+ }
+
+ public function getResourcePath()
+ {
+ return $this->resourcePath;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/BatchDeleteMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/BatchDeleteMessageRequest.php
new file mode 100644
index 0000000..c79cfa4
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/BatchDeleteMessageRequest.php
@@ -0,0 +1,50 @@
+queueName = $queueName;
+ $this->receiptHandles = $receiptHandles;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getReceiptHandles()
+ {
+ return $this->receiptHandles;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, Constants::RECEIPT_HANDLES, Constants::MNS_XML_NAMESPACE);
+ foreach ($this->receiptHandles as $receiptHandle)
+ {
+ $xmlWriter->writeElement(Constants::RECEIPT_HANDLE, $receiptHandle);
+ }
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/BatchPeekMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/BatchPeekMessageRequest.php
new file mode 100644
index 0000000..469eb2a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/BatchPeekMessageRequest.php
@@ -0,0 +1,41 @@
+queueName = $queueName;
+ $this->numOfMessages = $numOfMessages;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getNumOfMessages()
+ {
+ return $this->numOfMessages;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return http_build_query(array("numOfMessages" => $this->numOfMessages, "peekonly" => "true"));
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/BatchReceiveMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/BatchReceiveMessageRequest.php
new file mode 100644
index 0000000..89090b4
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/BatchReceiveMessageRequest.php
@@ -0,0 +1,58 @@
+queueName = NULL;
+ $this->numOfMessages = $numOfMessages;
+ $this->waitSeconds = $waitSeconds;
+ }
+
+ public function setQueueName($queueName)
+ {
+ $this->queueName = $queueName;
+ $this->resourcePath = 'queues/' . $queueName . '/messages';
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getWaitSeconds()
+ {
+ return $this->waitSeconds;
+ }
+
+ public function getNumOfMessages()
+ {
+ return $this->numOfMessages;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ $params = array("numOfMessages" => $this->numOfMessages);
+ if ($this->waitSeconds != NULL)
+ {
+ $params["waitseconds"] = $this->waitSeconds;
+ }
+ return http_build_query($params);
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/BatchSendMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/BatchSendMessageRequest.php
new file mode 100644
index 0000000..9074a36
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/BatchSendMessageRequest.php
@@ -0,0 +1,76 @@
+queueName = NULL;
+ $this->sendMessageRequestItems = $sendMessageRequestItems;
+ $this->base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function setQueueName($queueName)
+ {
+ $this->queueName = $queueName;
+ $this->resourcePath = 'queues/' . $queueName . '/messages';
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getSendMessageRequestItems()
+ {
+ return $this->sendMessageRequestItems;
+ }
+
+ public function addSendMessageRequestItem(SendMessageRequestItem $item)
+ {
+ $this->sendMessageRequestItems[] = $item;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Messages", Constants::MNS_XML_NAMESPACE);
+ foreach ($this->sendMessageRequestItems as $item)
+ {
+ $item->writeXML($xmlWriter, $this->base64);
+ }
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/ChangeMessageVisibilityRequest.php b/Lib/Alisms/AliyunMNS/Requests/ChangeMessageVisibilityRequest.php
new file mode 100644
index 0000000..2c9be59
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/ChangeMessageVisibilityRequest.php
@@ -0,0 +1,47 @@
+queueName = $queueName;
+ $this->receiptHandle = $receiptHandle;
+ $this->visibilityTimeout = $visibilityTimeout;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getReceiptHandle()
+ {
+ return $this->receiptHandle;
+ }
+
+ public function getVisibilityTimeout()
+ {
+ return $this->visibilityTimeout;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return http_build_query(array("receiptHandle" => $this->receiptHandle, "visibilityTimeout" => $this->visibilityTimeout));
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/CreateQueueRequest.php b/Lib/Alisms/AliyunMNS/Requests/CreateQueueRequest.php
new file mode 100644
index 0000000..4b16f38
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/CreateQueueRequest.php
@@ -0,0 +1,53 @@
+queueName = $queueName;
+ $this->attributes = $attributes;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getQueueAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Queue", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/CreateTopicRequest.php b/Lib/Alisms/AliyunMNS/Requests/CreateTopicRequest.php
new file mode 100644
index 0000000..65fc94a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/CreateTopicRequest.php
@@ -0,0 +1,53 @@
+topicName = $topicName;
+ $this->attributes = $attributes;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function getTopicAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Topic", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/DeleteMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/DeleteMessageRequest.php
new file mode 100644
index 0000000..ad52aad
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/DeleteMessageRequest.php
@@ -0,0 +1,40 @@
+queueName = $queueName;
+ $this->receiptHandle = $receiptHandle;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getReceiptHandle()
+ {
+ return $this->receiptHandle;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return http_build_query(array("ReceiptHandle" => $this->receiptHandle));
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/DeleteQueueRequest.php b/Lib/Alisms/AliyunMNS/Requests/DeleteQueueRequest.php
new file mode 100644
index 0000000..776ba97
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/DeleteQueueRequest.php
@@ -0,0 +1,33 @@
+queueName = $queueName;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/DeleteTopicRequest.php b/Lib/Alisms/AliyunMNS/Requests/DeleteTopicRequest.php
new file mode 100644
index 0000000..2a08a35
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/DeleteTopicRequest.php
@@ -0,0 +1,33 @@
+topicName = $topicName;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/GetAccountAttributesRequest.php b/Lib/Alisms/AliyunMNS/Requests/GetAccountAttributesRequest.php
new file mode 100644
index 0000000..3b15aa7
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/GetAccountAttributesRequest.php
@@ -0,0 +1,23 @@
+
diff --git a/Lib/Alisms/AliyunMNS/Requests/GetQueueAttributeRequest.php b/Lib/Alisms/AliyunMNS/Requests/GetQueueAttributeRequest.php
new file mode 100644
index 0000000..e10231a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/GetQueueAttributeRequest.php
@@ -0,0 +1,32 @@
+queueName = $queueName;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/GetSubscriptionAttributeRequest.php b/Lib/Alisms/AliyunMNS/Requests/GetSubscriptionAttributeRequest.php
new file mode 100644
index 0000000..a417b12
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/GetSubscriptionAttributeRequest.php
@@ -0,0 +1,39 @@
+topicName = $topicName;
+ $this->subscriptionName = $subscriptionName;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function getSubscriptionName()
+ {
+ return $this->subscriptionName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/GetTopicAttributeRequest.php b/Lib/Alisms/AliyunMNS/Requests/GetTopicAttributeRequest.php
new file mode 100644
index 0000000..5880a98
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/GetTopicAttributeRequest.php
@@ -0,0 +1,32 @@
+topicName = $topicName;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/ListQueueRequest.php b/Lib/Alisms/AliyunMNS/Requests/ListQueueRequest.php
new file mode 100644
index 0000000..8b58774
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/ListQueueRequest.php
@@ -0,0 +1,86 @@
+setRetNum($retNum);
+ $this->setPrefix($prefix);
+ $this->setMarker($marker);
+ }
+
+ public function getRetNum()
+ {
+ return $this->retNum;
+ }
+
+ public function setRetNum($retNum)
+ {
+ $this->retNum = $retNum;
+ if ($retNum != NULL)
+ {
+ $this->setHeader("x-mns-ret-number", $retNum);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-ret-number");
+ }
+ }
+
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ public function setPrefix($prefix)
+ {
+ $this->prefis = $prefix;
+ if ($prefix != NULL)
+ {
+ $this->setHeader("x-mns-prefix", $prefix);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-prefix");
+ }
+ }
+
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ public function setMarker($marker)
+ {
+ $this->marker = $marker;
+ if ($marker != NULL)
+ {
+ $this->setHeader("x-mns-marker", $marker);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-marker");
+ }
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/ListSubscriptionRequest.php b/Lib/Alisms/AliyunMNS/Requests/ListSubscriptionRequest.php
new file mode 100644
index 0000000..bb4b331
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/ListSubscriptionRequest.php
@@ -0,0 +1,97 @@
+topicName = $topicName;
+ $this->setRetNum($retNum);
+ $this->setPrefix($prefix);
+ $this->setMarker($marker);
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function getRetNum()
+ {
+ return $this->retNum;
+ }
+
+ public function setRetNum($retNum)
+ {
+ $this->retNum = $retNum;
+ if ($retNum != NULL)
+ {
+ $this->setHeader("x-mns-ret-number", $retNum);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-ret-number");
+ }
+ }
+
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ public function setPrefix($prefix)
+ {
+ $this->prefis = $prefix;
+ if ($prefix != NULL)
+ {
+ $this->setHeader("x-mns-prefix", $prefix);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-prefix");
+ }
+ }
+
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ public function setMarker($marker)
+ {
+ $this->marker = $marker;
+ if ($marker != NULL)
+ {
+ $this->setHeader("x-mns-marker", $marker);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-marker");
+ }
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/ListTopicRequest.php b/Lib/Alisms/AliyunMNS/Requests/ListTopicRequest.php
new file mode 100644
index 0000000..1d8f97b
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/ListTopicRequest.php
@@ -0,0 +1,86 @@
+setRetNum($retNum);
+ $this->setPrefix($prefix);
+ $this->setMarker($marker);
+ }
+
+ public function getRetNum()
+ {
+ return $this->retNum;
+ }
+
+ public function setRetNum($retNum)
+ {
+ $this->retNum = $retNum;
+ if ($retNum != NULL)
+ {
+ $this->setHeader("x-mns-ret-number", $retNum);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-ret-number");
+ }
+ }
+
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ public function setPrefix($prefix)
+ {
+ $this->prefis = $prefix;
+ if ($prefix != NULL)
+ {
+ $this->setHeader("x-mns-prefix", $prefix);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-prefix");
+ }
+ }
+
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ public function setMarker($marker)
+ {
+ $this->marker = $marker;
+ if ($marker != NULL)
+ {
+ $this->setHeader("x-mns-marker", $marker);
+ }
+ else
+ {
+ $this->removeHeader("x-mns-marker");
+ }
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/PeekMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/PeekMessageRequest.php
new file mode 100644
index 0000000..fbe02f0
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/PeekMessageRequest.php
@@ -0,0 +1,33 @@
+queueName = $queueName;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/PublishMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/PublishMessageRequest.php
new file mode 100644
index 0000000..f66bfa0
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/PublishMessageRequest.php
@@ -0,0 +1,51 @@
+topicName = NULL;
+ $this->messageBody = $messageBody;
+ $this->messageAttributes = $messageAttributes;
+ }
+
+ public function setTopicName($topicName)
+ {
+ $this->topicName = $topicName;
+ $this->resourcePath = 'topics/' . $topicName . '/messages';
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Message", Constants::MNS_XML_NAMESPACE);
+ $this->writeMessagePropertiesForPublishXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/ReceiveMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/ReceiveMessageRequest.php
new file mode 100644
index 0000000..dd853d5
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/ReceiveMessageRequest.php
@@ -0,0 +1,43 @@
+queueName = $queueName;
+ $this->waitSeconds = $waitSeconds;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getWaitSeconds()
+ {
+ return $this->waitSeconds;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ if ($this->waitSeconds != NULL)
+ {
+ return http_build_query(array("waitseconds" => $this->waitSeconds));
+ }
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/SendMessageRequest.php b/Lib/Alisms/AliyunMNS/Requests/SendMessageRequest.php
new file mode 100644
index 0000000..113fba0
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/SendMessageRequest.php
@@ -0,0 +1,67 @@
+queueName = NULL;
+ $this->messageBody = $messageBody;
+ $this->delaySeconds = $delaySeconds;
+ $this->priority = $priority;
+ $this->base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function setQueueName($queueName)
+ {
+ $this->queueName = $queueName;
+ $this->resourcePath = 'queues/' . $queueName . '/messages';
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Message", Constants::MNS_XML_NAMESPACE);
+ $this->writeMessagePropertiesForSendXML($xmlWriter, $this->base64);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/SetAccountAttributesRequest.php b/Lib/Alisms/AliyunMNS/Requests/SetAccountAttributesRequest.php
new file mode 100644
index 0000000..89ca743
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/SetAccountAttributesRequest.php
@@ -0,0 +1,46 @@
+attributes = $attributes;
+ }
+
+ public function getAccountAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Account", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/SetQueueAttributeRequest.php b/Lib/Alisms/AliyunMNS/Requests/SetQueueAttributeRequest.php
new file mode 100644
index 0000000..f6b4ff0
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/SetQueueAttributeRequest.php
@@ -0,0 +1,53 @@
+queueName = $queueName;
+ $this->attributes = $attributes;
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+
+ public function getQueueAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Queue", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/SetSubscriptionAttributeRequest.php b/Lib/Alisms/AliyunMNS/Requests/SetSubscriptionAttributeRequest.php
new file mode 100644
index 0000000..c9489c1
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/SetSubscriptionAttributeRequest.php
@@ -0,0 +1,46 @@
+getTopicName() . '/subscriptions/' . $attributes->getSubscriptionName() . '?metaoverride=true');
+
+ if ($attributes == NULL)
+ {
+ $attributes = new UpdateSubscriptionAttributes();
+ }
+
+ $this->attributes = $attributes;
+ }
+
+ public function getSubscriptionAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Subscription", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/SetTopicAttributeRequest.php b/Lib/Alisms/AliyunMNS/Requests/SetTopicAttributeRequest.php
new file mode 100644
index 0000000..7161a4a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/SetTopicAttributeRequest.php
@@ -0,0 +1,53 @@
+topicName = $topicName;
+ $this->attributes = $attributes;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function getTopicAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Topic", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/SubscribeRequest.php b/Lib/Alisms/AliyunMNS/Requests/SubscribeRequest.php
new file mode 100644
index 0000000..8dcd2f9
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/SubscribeRequest.php
@@ -0,0 +1,42 @@
+getTopicName() . '/subscriptions/' . $attributes->getSubscriptionName());
+
+ $this->attributes = $attributes;
+ }
+
+ public function getSubscriptionAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function generateBody()
+ {
+ $xmlWriter = new \XMLWriter;
+ $xmlWriter->openMemory();
+ $xmlWriter->startDocument("1.0", "UTF-8");
+ $xmlWriter->startElementNS(NULL, "Subscription", Constants::MNS_XML_NAMESPACE);
+ $this->attributes->writeXML($xmlWriter);
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ return $xmlWriter->outputMemory();
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Requests/UnsubscribeRequest.php b/Lib/Alisms/AliyunMNS/Requests/UnsubscribeRequest.php
new file mode 100644
index 0000000..94a10e4
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Requests/UnsubscribeRequest.php
@@ -0,0 +1,39 @@
+topicName = $topicName;
+ $this->subscriptionName = $subscriptionName;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function getSubscriptionName()
+ {
+ return $this->subscriptionName;
+ }
+
+ public function generateBody()
+ {
+ return NULL;
+ }
+
+ public function generateQueryString()
+ {
+ return NULL;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/BaseResponse.php b/Lib/Alisms/AliyunMNS/Responses/BaseResponse.php
new file mode 100644
index 0000000..b342f0a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/BaseResponse.php
@@ -0,0 +1,39 @@
+succeed;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ protected function loadXmlContent($content)
+ {
+ $xmlReader = new \XMLReader();
+ $isXml = $xmlReader->XML($content);
+ if ($isXml === FALSE) {
+ throw new MnsException($this->statusCode, $content);
+ }
+ try {
+ while ($xmlReader->read()) {}
+ } catch (\Exception $e) {
+ throw new MnsException($this->statusCode, $content);
+ }
+ $xmlReader->XML($content);
+ return $xmlReader;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/BatchDeleteMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/BatchDeleteMessageResponse.php
new file mode 100644
index 0000000..90266a0
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/BatchDeleteMessageResponse.php
@@ -0,0 +1,95 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT) {
+ switch ($xmlReader->name) {
+ case Constants::ERROR:
+ $this->parseNormalErrorResponse($xmlReader);
+ break;
+ default: // case Constants::Messages
+ $this->parseBatchDeleteErrorResponse($xmlReader);
+ break;
+ }
+ }
+ }
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ private function parseBatchDeleteErrorResponse($xmlReader)
+ {
+ $ex = new BatchDeleteFailException($this->statusCode, "BatchDeleteMessage Failed For Some ReceiptHandles");
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT && $xmlReader->name == Constants::ERROR) {
+ $ex->addDeleteMessageErrorItem( DeleteMessageErrorItem::fromXML($xmlReader));
+ }
+ }
+ throw $ex;
+ }
+
+ private function parseNormalErrorResponse($xmlReader)
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::RECEIPT_HANDLE_ERROR)
+ {
+ throw new ReceiptHandleErrorException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/BatchPeekMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/BatchPeekMessageResponse.php
new file mode 100644
index 0000000..46108f2
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/BatchPeekMessageResponse.php
@@ -0,0 +1,97 @@
+messages = array();
+ $this->base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function getMessages()
+ {
+ return $this->messages;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT
+ && $xmlReader->name == 'Message')
+ {
+ $this->messages[] = Message::fromXML($xmlReader, $this->base64);
+ }
+ }
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MESSAGE_NOT_EXIST)
+ {
+ throw new MessageNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/BatchReceiveMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/BatchReceiveMessageResponse.php
new file mode 100644
index 0000000..6978311
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/BatchReceiveMessageResponse.php
@@ -0,0 +1,98 @@
+messages = array();
+ $this->base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function getMessages()
+ {
+ return $this->messages;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT
+ && $xmlReader->name == 'Message')
+ {
+ $this->messages[] = Message::fromXML($xmlReader, $this->base64);
+ }
+ }
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MESSAGE_NOT_EXIST)
+ {
+ throw new MessageNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/BatchSendMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/BatchSendMessageResponse.php
new file mode 100644
index 0000000..30ed7a7
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/BatchSendMessageResponse.php
@@ -0,0 +1,117 @@
+sendMessageResponseItems = array();
+ }
+
+ public function getSendMessageResponseItems()
+ {
+ return $this->sendMessageResponseItems;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 201) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT && $xmlReader->name == 'Message') {
+ $this->sendMessageResponseItems[] = SendMessageResponseItem::fromXML($xmlReader);
+ }
+ }
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT) {
+ switch ($xmlReader->name) {
+ case Constants::ERROR:
+ $this->parseNormalErrorResponse($xmlReader);
+ break;
+ default: // case Constants::Messages
+ $this->parseBatchSendErrorResponse($xmlReader);
+ break;
+ }
+ }
+ }
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ private function parseBatchSendErrorResponse($xmlReader)
+ {
+ $ex = new BatchSendFailException($this->statusCode, "BatchSendMessage Failed For Some Messages");
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT && $xmlReader->name == 'Message') {
+ $ex->addSendMessageResponseItem( SendMessageResponseItem::fromXML($xmlReader));
+ }
+ }
+ throw $ex;
+ }
+
+ private function parseNormalErrorResponse($xmlReader)
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MALFORMED_XML)
+ {
+ throw new MalformedXMLException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/ChangeMessageVisibilityResponse.php b/Lib/Alisms/AliyunMNS/Responses/ChangeMessageVisibilityResponse.php
new file mode 100644
index 0000000..5301c21
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/ChangeMessageVisibilityResponse.php
@@ -0,0 +1,96 @@
+receiptHandle;
+ }
+
+ public function getNextVisibleTime()
+ {
+ return $this->nextVisibleTime;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $message = Message::fromXML($xmlReader, TRUE);
+ $this->receiptHandle = $message->getReceiptHandle();
+ $this->nextVisibleTime = $message->getNextVisibleTime();
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MESSAGE_NOT_EXIST)
+ {
+ throw new MessageNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::RECEIPT_HANDLE_ERROR)
+ {
+ throw new ReceiptHandleErrorException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/CreateQueueResponse.php b/Lib/Alisms/AliyunMNS/Responses/CreateQueueResponse.php
new file mode 100644
index 0000000..2a7c1f1
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/CreateQueueResponse.php
@@ -0,0 +1,66 @@
+queueName = $queueName;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 201 || $statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::QUEUE_ALREADY_EXIST)
+ {
+ throw new QueueAlreadyExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function getQueueName()
+ {
+ return $this->queueName;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/CreateTopicResponse.php b/Lib/Alisms/AliyunMNS/Responses/CreateTopicResponse.php
new file mode 100644
index 0000000..aa75b47
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/CreateTopicResponse.php
@@ -0,0 +1,66 @@
+topicName = $topicName;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 201 || $statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::TOPIC_ALREADY_EXIST)
+ {
+ throw new TopicAlreadyExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/DeleteMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/DeleteMessageResponse.php
new file mode 100644
index 0000000..ac3c10b
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/DeleteMessageResponse.php
@@ -0,0 +1,64 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::RECEIPT_HANDLE_ERROR)
+ {
+ throw new ReceiptHandleErrorException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/DeleteQueueResponse.php b/Lib/Alisms/AliyunMNS/Responses/DeleteQueueResponse.php
new file mode 100644
index 0000000..751b2b5
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/DeleteQueueResponse.php
@@ -0,0 +1,46 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/DeleteTopicResponse.php b/Lib/Alisms/AliyunMNS/Responses/DeleteTopicResponse.php
new file mode 100644
index 0000000..dcb4368
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/DeleteTopicResponse.php
@@ -0,0 +1,46 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/GetAccountAttributesResponse.php b/Lib/Alisms/AliyunMNS/Responses/GetAccountAttributesResponse.php
new file mode 100644
index 0000000..0aba419
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/GetAccountAttributesResponse.php
@@ -0,0 +1,68 @@
+attributes = NULL;
+ }
+
+ public function getAccountAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $this->attributes = AccountAttributes::fromXML($xmlReader);
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/GetQueueAttributeResponse.php b/Lib/Alisms/AliyunMNS/Responses/GetQueueAttributeResponse.php
new file mode 100644
index 0000000..82de2bd
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/GetQueueAttributeResponse.php
@@ -0,0 +1,73 @@
+attributes = NULL;
+ }
+
+ public function getQueueAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $this->attributes = QueueAttributes::fromXML($xmlReader);
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/GetSubscriptionAttributeResponse.php b/Lib/Alisms/AliyunMNS/Responses/GetSubscriptionAttributeResponse.php
new file mode 100644
index 0000000..e0eea96
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/GetSubscriptionAttributeResponse.php
@@ -0,0 +1,88 @@
+attributes = NULL;
+ }
+
+ public function getSubscriptionAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200)
+ {
+ $this->succeed = TRUE;
+ }
+ else
+ {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try
+ {
+ $this->attributes = SubscriptionAttributes::fromXML($xmlReader);
+ }
+ catch (\Exception $e)
+ {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::SUBSCRIPTION_NOT_EXIST)
+ {
+ throw new SubscriptionNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL)
+ {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/GetTopicAttributeResponse.php b/Lib/Alisms/AliyunMNS/Responses/GetTopicAttributeResponse.php
new file mode 100644
index 0000000..38b1aee
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/GetTopicAttributeResponse.php
@@ -0,0 +1,88 @@
+attributes = NULL;
+ }
+
+ public function getTopicAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200)
+ {
+ $this->succeed = TRUE;
+ }
+ else
+ {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $this->attributes = TopicAttributes::fromXML($xmlReader);
+ }
+ catch (\Exception $e)
+ {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::TOPIC_NOT_EXIST)
+ {
+ throw new TopicNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL)
+ {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/ListQueueResponse.php b/Lib/Alisms/AliyunMNS/Responses/ListQueueResponse.php
new file mode 100644
index 0000000..79f3cfd
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/ListQueueResponse.php
@@ -0,0 +1,109 @@
+queueNames = array();
+ $this->nextMarker = NULL;
+ }
+
+ public function isFinished()
+ {
+ return $this->nextMarker == NULL;
+ }
+
+ public function getQueueNames()
+ {
+ return $this->queueNames;
+ }
+
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode != 200) {
+ $this->parseErrorResponse($statusCode, $content);
+ return;
+ }
+
+ $this->succeed = TRUE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'QueueURL':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $queueName = $this->getQueueNameFromQueueURL($xmlReader->value);
+ $this->queueNames[] = $queueName;
+ }
+ break;
+ case 'NextMarker':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $this->nextMarker = $xmlReader->value;
+ }
+ break;
+ }
+ }
+ }
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ private function getQueueNameFromQueueURL($queueURL)
+ {
+ $pieces = explode("/", $queueURL);
+ if (count($pieces) == 5)
+ {
+ return $pieces[4];
+ }
+ return "";
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/ListSubscriptionResponse.php b/Lib/Alisms/AliyunMNS/Responses/ListSubscriptionResponse.php
new file mode 100644
index 0000000..a6e0fb2
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/ListSubscriptionResponse.php
@@ -0,0 +1,121 @@
+SubscriptionNames = array();
+ $this->nextMarker = NULL;
+ }
+
+ public function isFinished()
+ {
+ return $this->nextMarker == NULL;
+ }
+
+ public function getSubscriptionNames()
+ {
+ return $this->SubscriptionNames;
+ }
+
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode != 200) {
+ $this->parseErrorResponse($statusCode, $content);
+ return;
+ }
+
+ $this->succeed = TRUE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'SubscriptionURL':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $subscriptionName = $this->getSubscriptionNameFromSubscriptionURL($xmlReader->value);
+ $this->SubscriptionNames[] = $subscriptionName;
+ }
+ break;
+ case 'NextMarker':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $this->nextMarker = $xmlReader->value;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (\Exception $e)
+ {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ private function getSubscriptionNameFromSubscriptionURL($subscriptionURL)
+ {
+ $pieces = explode("/", $subscriptionURL);
+ if (count($pieces) == 7)
+ {
+ return $pieces[6];
+ }
+ return "";
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL)
+ {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
diff --git a/Lib/Alisms/AliyunMNS/Responses/ListTopicResponse.php b/Lib/Alisms/AliyunMNS/Responses/ListTopicResponse.php
new file mode 100644
index 0000000..8013c78
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/ListTopicResponse.php
@@ -0,0 +1,124 @@
+topicNames = array();
+ $this->nextMarker = NULL;
+ }
+
+ public function isFinished()
+ {
+ return $this->nextMarker == NULL;
+ }
+
+ public function getTopicNames()
+ {
+ return $this->topicNames;
+ }
+
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode != 200) {
+ $this->parseErrorResponse($statusCode, $content);
+ return;
+ }
+
+ $this->succeed = TRUE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try
+ {
+ while ($xmlReader->read())
+ {
+ if ($xmlReader->nodeType == \XMLReader::ELEMENT)
+ {
+ switch ($xmlReader->name) {
+ case 'TopicURL':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $topicName = $this->getTopicNameFromTopicURL($xmlReader->value);
+ $this->topicNames[] = $topicName;
+ }
+ break;
+ case 'NextMarker':
+ $xmlReader->read();
+ if ($xmlReader->nodeType == \XMLReader::TEXT)
+ {
+ $this->nextMarker = $xmlReader->value;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (\Exception $e)
+ {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+
+ private function getTopicNameFromTopicURL($topicURL)
+ {
+ $pieces = explode("/", $topicURL);
+ if (count($pieces) == 5)
+ {
+ return $pieces[4];
+ }
+ return "";
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL)
+ {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/MnsPromise.php b/Lib/Alisms/AliyunMNS/Responses/MnsPromise.php
new file mode 100644
index 0000000..f40c024
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/MnsPromise.php
@@ -0,0 +1,50 @@
+promise = $promise;
+ $this->response = $response;
+ }
+
+ public function isCompleted()
+ {
+ return $this->promise->getState() != 'pending';
+ }
+
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ public function wait()
+ {
+ try {
+ $res = $this->promise->wait();
+ if ($res instanceof ResponseInterface)
+ {
+ $this->response->parseResponse($res->getStatusCode(), $res->getBody());
+ }
+ } catch (TransferException $e) {
+ $message = $e->getMessage();
+ if ($e->hasResponse()) {
+ $message = $e->getResponse()->getBody();
+ }
+ $this->response->parseErrorResponse($e->getCode(), $message);
+ }
+ return $this->response;
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/PeekMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/PeekMessageResponse.php
new file mode 100644
index 0000000..deb3c83
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/PeekMessageResponse.php
@@ -0,0 +1,85 @@
+base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $this->readMessagePropertiesForPeekXML($xmlReader, $this->base64);
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MESSAGE_NOT_EXIST)
+ {
+ throw new MessageNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/PublishMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/PublishMessageResponse.php
new file mode 100644
index 0000000..0ee38da
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/PublishMessageResponse.php
@@ -0,0 +1,74 @@
+statusCode = $statusCode;
+ if ($statusCode == 201) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $this->readMessageIdAndMD5XML($xmlReader);
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::TOPIC_NOT_EXIST)
+ {
+ throw new TopicNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MALFORMED_XML)
+ {
+ throw new MalformedXMLException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/ReceiveMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/ReceiveMessageResponse.php
new file mode 100644
index 0000000..44aa72c
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/ReceiveMessageResponse.php
@@ -0,0 +1,83 @@
+base64 = $base64;
+ }
+
+ public function setBase64($base64)
+ {
+ $this->base64 = $base64;
+ }
+
+ public function isBase64()
+ {
+ return ($this->base64 == TRUE);
+ }
+
+ public function parseResponse($statusCode, $content)
+ {
+ $this->statusCode = $statusCode;
+ if ($statusCode == 200) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $this->readMessagePropertiesForReceiveXML($xmlReader, $this->base64);
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MESSAGE_NOT_EXIST)
+ {
+ throw new MessageNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/SendMessageResponse.php b/Lib/Alisms/AliyunMNS/Responses/SendMessageResponse.php
new file mode 100644
index 0000000..77f1681
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/SendMessageResponse.php
@@ -0,0 +1,74 @@
+statusCode = $statusCode;
+ if ($statusCode == 201) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $this->readMessageIdAndMD5XML($xmlReader);
+ } catch (\Exception $e) {
+ throw new MnsException($statusCode, $e->getMessage(), $e);
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::MALFORMED_XML)
+ {
+ throw new MalformedXMLException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/SetAccountAttributesResponse.php b/Lib/Alisms/AliyunMNS/Responses/SetAccountAttributesResponse.php
new file mode 100644
index 0000000..4d08334
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/SetAccountAttributesResponse.php
@@ -0,0 +1,47 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/SetQueueAttributeResponse.php b/Lib/Alisms/AliyunMNS/Responses/SetQueueAttributeResponse.php
new file mode 100644
index 0000000..5540cd2
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/SetQueueAttributeResponse.php
@@ -0,0 +1,57 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::QUEUE_NOT_EXIST)
+ {
+ throw new QueueNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/SetSubscriptionAttributeResponse.php b/Lib/Alisms/AliyunMNS/Responses/SetSubscriptionAttributeResponse.php
new file mode 100644
index 0000000..1d79849
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/SetSubscriptionAttributeResponse.php
@@ -0,0 +1,63 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::SUBSCRIPTION_NOT_EXIST)
+ {
+ throw new SubscriptionNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL) {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/SetTopicAttributeResponse.php b/Lib/Alisms/AliyunMNS/Responses/SetTopicAttributeResponse.php
new file mode 100644
index 0000000..642c823
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/SetTopicAttributeResponse.php
@@ -0,0 +1,66 @@
+statusCode = $statusCode;
+ if ($statusCode == 204) {
+ $this->succeed = TRUE;
+ } else {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::TOPIC_NOT_EXIST)
+ {
+ throw new TopicNotExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL)
+ {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/SubscribeResponse.php b/Lib/Alisms/AliyunMNS/Responses/SubscribeResponse.php
new file mode 100644
index 0000000..8a1fff6
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/SubscribeResponse.php
@@ -0,0 +1,66 @@
+statusCode = $statusCode;
+ if ($statusCode == 201 || $statusCode == 204)
+ {
+ $this->succeed = TRUE;
+ }
+ else
+ {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try
+ {
+ $result = XMLParser::parseNormalError($xmlReader);
+
+ if ($result['Code'] == Constants::INVALID_ARGUMENT)
+ {
+ throw new InvalidArgumentException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ if ($result['Code'] == Constants::SUBSCRIPTION_ALREADY_EXIST)
+ {
+ throw new SubscriptionAlreadyExistException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ }
+ catch (\Exception $e)
+ {
+ if ($exception != NULL)
+ {
+ throw $exception;
+ }
+ elseif ($e instanceof MnsException)
+ {
+ throw $e;
+ }
+ else
+ {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ }
+ catch (\Throwable $t)
+ {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Responses/UnsubscribeResponse.php b/Lib/Alisms/AliyunMNS/Responses/UnsubscribeResponse.php
new file mode 100644
index 0000000..cfd902e
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Responses/UnsubscribeResponse.php
@@ -0,0 +1,48 @@
+statusCode = $statusCode;
+ if ($statusCode == 204)
+ {
+ $this->succeed = TRUE;
+ }
+ else
+ {
+ $this->parseErrorResponse($statusCode, $content);
+ }
+ }
+
+ public function parseErrorResponse($statusCode, $content, MnsException $exception = NULL)
+ {
+ $this->succeed = FALSE;
+ $xmlReader = $this->loadXmlContent($content);
+ try {
+ $result = XMLParser::parseNormalError($xmlReader);
+ throw new MnsException($statusCode, $result['Message'], $exception, $result['Code'], $result['RequestId'], $result['HostId']);
+ } catch (\Exception $e) {
+ if ($exception != NULL) {
+ throw $exception;
+ } elseif($e instanceof MnsException) {
+ throw $e;
+ } else {
+ throw new MnsException($statusCode, $e->getMessage());
+ }
+ } catch (\Throwable $t) {
+ throw new MnsException($statusCode, $t->getMessage());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Signature/Signature.php b/Lib/Alisms/AliyunMNS/Signature/Signature.php
new file mode 100644
index 0000000..2ed987e
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Signature/Signature.php
@@ -0,0 +1,53 @@
+getHeaders();
+ $contentMd5 = "";
+ if (isset($headers['Content-MD5']))
+ {
+ $contentMd5 = $headers['Content-MD5'];
+ }
+ $contentType = "";
+ if (isset($headers['Content-Type']))
+ {
+ $contentType = $headers['Content-Type'];
+ }
+ $date = $headers['Date'];
+ $queryString = $request->getQueryString();
+ $canonicalizedResource = $request->getResourcePath();
+ if ($queryString != NULL)
+ {
+ $canonicalizedResource .= "?" . $request->getQueryString();
+ }
+ if (0 !== strpos($canonicalizedResource, "/"))
+ {
+ $canonicalizedResource = "/" . $canonicalizedResource;
+ }
+
+ $tmpHeaders = array();
+ foreach ($headers as $key => $value)
+ {
+ if (0 === strpos($key, Constants::MNS_HEADER_PREFIX))
+ {
+ $tmpHeaders[$key] = $value;
+ }
+ }
+ ksort($tmpHeaders);
+
+ $canonicalizedMNSHeaders = implode("\n", array_map(function ($v, $k) { return $k . ":" . $v; }, $tmpHeaders, array_keys($tmpHeaders)));
+
+ $stringToSign = strtoupper($request->getMethod()) . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n" . $canonicalizedMNSHeaders . "\n" . $canonicalizedResource;
+
+ return base64_encode(hash_hmac("sha1", $stringToSign, $accessKey, $raw_output = TRUE));
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Topic.php b/Lib/Alisms/AliyunMNS/Topic.php
new file mode 100644
index 0000000..6682b2f
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Topic.php
@@ -0,0 +1,128 @@
+client = $client;
+ $this->topicName = $topicName;
+ }
+
+ public function getTopicName()
+ {
+ return $this->topicName;
+ }
+
+ public function setAttribute(TopicAttributes $attributes)
+ {
+ $request = new SetTopicAttributeRequest($this->topicName, $attributes);
+ $response = new SetTopicAttributeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function getAttribute()
+ {
+ $request = new GetTopicAttributeRequest($this->topicName);
+ $response = new GetTopicAttributeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function generateQueueEndpoint($queueName)
+ {
+ return "acs:mns:" . $this->client->getRegion() . ":" . $this->client->getAccountId() . ":queues/" . $queueName;
+ }
+
+ public function generateMailEndpoint($mailAddress)
+ {
+ return "mail:directmail:" . $mailAddress;
+ }
+
+ public function generateSmsEndpoint($phone = null)
+ {
+ if ($phone)
+ {
+ return "sms:directsms:" . $phone;
+ }
+ else
+ {
+ return "sms:directsms:anonymous";
+ }
+ }
+
+ public function generateBatchSmsEndpoint()
+ {
+ return "sms:directsms:anonymous";
+ }
+
+ public function publishMessage(PublishMessageRequest $request)
+ {
+ $request->setTopicName($this->topicName);
+ $response = new PublishMessageResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function subscribe(SubscriptionAttributes $attributes)
+ {
+ $attributes->setTopicName($this->topicName);
+ $request = new SubscribeRequest($attributes);
+ $response = new SubscribeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function unsubscribe($subscriptionName)
+ {
+ $request = new UnsubscribeRequest($this->topicName, $subscriptionName);
+ $response = new UnsubscribeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function getSubscriptionAttribute($subscriptionName)
+ {
+ $request = new GetSubscriptionAttributeRequest($this->topicName, $subscriptionName);
+ $response = new GetSubscriptionAttributeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function setSubscriptionAttribute(UpdateSubscriptionAttributes $attributes)
+ {
+ $attributes->setTopicName($this->topicName);
+ $request = new SetSubscriptionAttributeRequest($attributes);
+ $response = new SetSubscriptionAttributeResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+
+ public function listSubscription($retNum = NULL, $prefix = NULL, $marker = NULL)
+ {
+ $request = new ListSubscriptionRequest($this->topicName, $retNum, $prefix, $marker);
+ $response = new ListSubscriptionResponse();
+ return $this->client->sendRequest($request, $response);
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Traits/MessageIdAndMD5.php b/Lib/Alisms/AliyunMNS/Traits/MessageIdAndMD5.php
new file mode 100644
index 0000000..19df2bf
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Traits/MessageIdAndMD5.php
@@ -0,0 +1,30 @@
+messageId;
+ }
+
+ public function getMessageBodyMD5()
+ {
+ return $this->messageBodyMD5;
+ }
+
+ public function readMessageIdAndMD5XML(\XMLReader $xmlReader)
+ {
+ $message = Message::fromXML($xmlReader, TRUE);
+ $this->messageId = $message->getMessageId();
+ $this->messageBodyMD5 = $message->getMessageBodyMD5();
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForPeek.php b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForPeek.php
new file mode 100644
index 0000000..cb1a48a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForPeek.php
@@ -0,0 +1,63 @@
+messageBody;
+ }
+
+ public function getEnqueueTime()
+ {
+ return $this->enqueueTime;
+ }
+
+ public function getNextVisibleTime()
+ {
+ return $this->nextVisibleTime;
+ }
+
+ public function getFirstDequeueTime()
+ {
+ return $this->firstDequeueTime;
+ }
+
+ public function getDequeueCount()
+ {
+ return $this->dequeueCount;
+ }
+
+ public function getPriority()
+ {
+ return $this->priority;
+ }
+
+ public function readMessagePropertiesForPeekXML(\XMLReader $xmlReader, $base64)
+ {
+ $message = Message::fromXML($xmlReader, $base64);
+ $this->messageId = $message->getMessageId();
+ $this->messageBodyMD5 = $message->getMessageBodyMD5();
+ $this->messageBody = $message->getMessageBody();
+ $this->enqueueTime = $message->getEnqueueTime();
+ $this->nextVisibleTime = $message->getNextVisibleTime();
+ $this->firstDequeueTime = $message->getFirstDequeueTime();
+ $this->dequeueCount = $message->getDequeueCount();
+ $this->priority = $message->getPriority();
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForPublish.php b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForPublish.php
new file mode 100644
index 0000000..be6e5af
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForPublish.php
@@ -0,0 +1,45 @@
+messageBody;
+ }
+
+ public function setMessageBody($messageBody)
+ {
+ $this->messageBody = $messageBody;
+ }
+
+ public function getMessageAttributes()
+ {
+ return $this->messageAttributes;
+ }
+
+ public function setMessageAttributes($messageAttributes)
+ {
+ $this->messageAttributes = $messageAttributes;
+ }
+
+ public function writeMessagePropertiesForPublishXML(\XMLWriter $xmlWriter)
+ {
+ if ($this->messageBody != NULL)
+ {
+ $xmlWriter->writeElement(Constants::MESSAGE_BODY, $this->messageBody);
+ }
+ if ($this->messageAttributes !== NULL)
+ {
+ $this->messageAttributes->writeXML($xmlWriter);
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForReceive.php b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForReceive.php
new file mode 100644
index 0000000..581c97e
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForReceive.php
@@ -0,0 +1,33 @@
+receiptHandle;
+ }
+
+ public function readMessagePropertiesForReceiveXML(\XMLReader $xmlReader, $base64)
+ {
+ $message = Message::fromXML($xmlReader, $base64);
+ $this->messageId = $message->getMessageId();
+ $this->messageBodyMD5 = $message->getMessageBodyMD5();
+ $this->messageBody = $message->getMessageBody();
+ $this->enqueueTime = $message->getEnqueueTime();
+ $this->nextVisibleTime = $message->getNextVisibleTime();
+ $this->firstDequeueTime = $message->getFirstDequeueTime();
+ $this->dequeueCount = $message->getDequeueCount();
+ $this->priority = $message->getPriority();
+ $this->receiptHandle = $message->getReceiptHandle();
+ }
+}
+
+?>
diff --git a/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForSend.php b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForSend.php
new file mode 100644
index 0000000..c92d07a
--- /dev/null
+++ b/Lib/Alisms/AliyunMNS/Traits/MessagePropertiesForSend.php
@@ -0,0 +1,63 @@
+messageBody;
+ }
+
+ public function setMessageBody($messageBody)
+ {
+ $this->messageBody = $messageBody;
+ }
+
+ public function getDelaySeconds()
+ {
+ return $this->delaySeconds;
+ }
+
+ public function setDelaySeconds($delaySeconds)
+ {
+ $this->delaySeconds = $delaySeconds;
+ }
+
+ public function getPriority()
+ {
+ return $this->priority;
+ }
+
+ public function setPriority($priority)
+ {
+ $this->priority = $priority;
+ }
+
+ public function writeMessagePropertiesForSendXML(\XMLWriter $xmlWriter, $base64)
+ {
+ if ($this->messageBody != NULL)
+ {
+ if ($base64 == TRUE) {
+ $xmlWriter->writeElement(Constants::MESSAGE_BODY, base64_encode($this->messageBody));
+ } else {
+ $xmlWriter->writeElement(Constants::MESSAGE_BODY, $this->messageBody);
+ }
+ }
+ if ($this->delaySeconds != NULL)
+ {
+ $xmlWriter->writeElement(Constants::DELAY_SECONDS, $this->delaySeconds);
+ }
+ if ($this->priority !== NULL)
+ {
+ $xmlWriter->writeElement(Constants::PRIORITY, $this->priority);
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/GuzzleHttp/Client.php b/Lib/Alisms/GuzzleHttp/Client.php
new file mode 100644
index 0000000..2e86ece
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Client.php
@@ -0,0 +1,397 @@
+ 'http://www.foo.com/1.0/',
+ * 'timeout' => 0,
+ * 'allow_redirects' => false,
+ * 'proxy' => '192.168.16.1:10'
+ * ]);
+ *
+ * Client configuration settings include the following options:
+ *
+ * - handler: (callable) Function that transfers HTTP requests over the
+ * wire. The function is called with a Psr7\Http\Message\RequestInterface
+ * and array of transfer options, and must return a
+ * GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
+ * Psr7\Http\Message\ResponseInterface on success. "handler" is a
+ * constructor only option that cannot be overridden in per/request
+ * options. If no handler is provided, a default handler will be created
+ * that enables all of the request options below by attaching all of the
+ * default middleware to the handler.
+ * - base_uri: (string|UriInterface) Base URI of the client that is merged
+ * into relative URIs. Can be a string or instance of UriInterface.
+ * - **: any request option
+ *
+ * @param array $config Client configuration settings.
+ *
+ * @see \GuzzleHttp\RequestOptions for a list of available request options.
+ */
+ public function __construct(array $config = [])
+ {
+ if (!isset($config['handler'])) {
+ $config['handler'] = HandlerStack::create();
+ }
+
+ // Convert the base_uri to a UriInterface
+ if (isset($config['base_uri'])) {
+ $config['base_uri'] = Psr7\uri_for($config['base_uri']);
+ }
+
+ $this->configureDefaults($config);
+ }
+
+ public function __call($method, $args)
+ {
+ if (count($args) < 1) {
+ throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
+ }
+
+ $uri = $args[0];
+ $opts = isset($args[1]) ? $args[1] : [];
+
+ return substr($method, -5) === 'Async'
+ ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
+ : $this->request($method, $uri, $opts);
+ }
+
+ public function sendAsync(RequestInterface $request, array $options = [])
+ {
+ // Merge the base URI into the request URI if needed.
+ $options = $this->prepareDefaults($options);
+
+ return $this->transfer(
+ $request->withUri($this->buildUri($request->getUri(), $options)),
+ $options
+ );
+ }
+
+ public function send(RequestInterface $request, array $options = [])
+ {
+ $options[RequestOptions::SYNCHRONOUS] = true;
+ return $this->sendAsync($request, $options)->wait();
+ }
+
+ public function requestAsync($method, $uri = null, array $options = [])
+ {
+ $options = $this->prepareDefaults($options);
+ // Remove request modifying parameter because it can be done up-front.
+ $headers = isset($options['headers']) ? $options['headers'] : [];
+ $body = isset($options['body']) ? $options['body'] : null;
+ $version = isset($options['version']) ? $options['version'] : '1.1';
+ // Merge the URI into the base URI.
+ $uri = $this->buildUri($uri, $options);
+ if (is_array($body)) {
+ $this->invalidBody();
+ }
+ $request = new Psr7\Request($method, $uri, $headers, $body, $version);
+ // Remove the option so that they are not doubly-applied.
+ unset($options['headers'], $options['body'], $options['version']);
+
+ return $this->transfer($request, $options);
+ }
+
+ public function request($method, $uri = null, array $options = [])
+ {
+ $options[RequestOptions::SYNCHRONOUS] = true;
+ return $this->requestAsync($method, $uri, $options)->wait();
+ }
+
+ public function getConfig($option = null)
+ {
+ return $option === null
+ ? $this->config
+ : (isset($this->config[$option]) ? $this->config[$option] : null);
+ }
+
+ private function buildUri($uri, array $config)
+ {
+ if (!isset($config['base_uri'])) {
+ return $uri instanceof UriInterface ? $uri : new Psr7\Uri($uri);
+ }
+
+ return Psr7\Uri::resolve(Psr7\uri_for($config['base_uri']), $uri);
+ }
+
+ /**
+ * Configures the default options for a client.
+ *
+ * @param array $config
+ */
+ private function configureDefaults(array $config)
+ {
+ $defaults = [
+ 'allow_redirects' => RedirectMiddleware::$defaultSettings,
+ 'http_errors' => true,
+ 'decode_content' => true,
+ 'verify' => true,
+ 'cookies' => false
+ ];
+
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
+ if ($proxy = getenv('HTTP_PROXY')) {
+ $defaults['proxy']['http'] = $proxy;
+ }
+
+ if ($proxy = getenv('HTTPS_PROXY')) {
+ $defaults['proxy']['https'] = $proxy;
+ }
+
+ if ($noProxy = getenv('NO_PROXY')) {
+ $cleanedNoProxy = str_replace(' ', '', $noProxy);
+ $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
+ }
+
+ $this->config = $config + $defaults;
+
+ if (!empty($config['cookies']) && $config['cookies'] === true) {
+ $this->config['cookies'] = new CookieJar();
+ }
+
+ // Add the default user-agent header.
+ if (!isset($this->config['headers'])) {
+ $this->config['headers'] = ['User-Agent' => default_user_agent()];
+ } else {
+ // Add the User-Agent header if one was not already set.
+ foreach (array_keys($this->config['headers']) as $name) {
+ if (strtolower($name) === 'user-agent') {
+ return;
+ }
+ }
+ $this->config['headers']['User-Agent'] = default_user_agent();
+ }
+ }
+
+ /**
+ * Merges default options into the array.
+ *
+ * @param array $options Options to modify by reference
+ *
+ * @return array
+ */
+ private function prepareDefaults($options)
+ {
+ $defaults = $this->config;
+
+ if (!empty($defaults['headers'])) {
+ // Default headers are only added if they are not present.
+ $defaults['_conditional'] = $defaults['headers'];
+ unset($defaults['headers']);
+ }
+
+ // Special handling for headers is required as they are added as
+ // conditional headers and as headers passed to a request ctor.
+ if (array_key_exists('headers', $options)) {
+ // Allows default headers to be unset.
+ if ($options['headers'] === null) {
+ $defaults['_conditional'] = null;
+ unset($options['headers']);
+ } elseif (!is_array($options['headers'])) {
+ throw new \InvalidArgumentException('headers must be an array');
+ }
+ }
+
+ // Shallow merge defaults underneath options.
+ $result = $options + $defaults;
+
+ // Remove null values.
+ foreach ($result as $k => $v) {
+ if ($v === null) {
+ unset($result[$k]);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Transfers the given request and applies request options.
+ *
+ * The URI of the request is not modified and the request options are used
+ * as-is without merging in default options.
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return Promise\PromiseInterface
+ */
+ private function transfer(RequestInterface $request, array $options)
+ {
+ // save_to -> sink
+ if (isset($options['save_to'])) {
+ $options['sink'] = $options['save_to'];
+ unset($options['save_to']);
+ }
+
+ // exceptions -> http_error
+ if (isset($options['exceptions'])) {
+ $options['http_errors'] = $options['exceptions'];
+ unset($options['exceptions']);
+ }
+
+ $request = $this->applyOptions($request, $options);
+ $handler = $options['handler'];
+
+ try {
+ return Promise\promise_for($handler($request, $options));
+ } catch (\Exception $e) {
+ return Promise\rejection_for($e);
+ }
+ }
+
+ /**
+ * Applies the array of request options to a request.
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return RequestInterface
+ */
+ private function applyOptions(RequestInterface $request, array &$options)
+ {
+ $modify = [];
+
+ if (isset($options['form_params'])) {
+ if (isset($options['multipart'])) {
+ throw new \InvalidArgumentException('You cannot use '
+ . 'form_params and multipart at the same time. Use the '
+ . 'form_params option if you want to send application/'
+ . 'x-www-form-urlencoded requests, and the multipart '
+ . 'option to send multipart/form-data requests.');
+ }
+ $options['body'] = http_build_query($options['form_params'], null, '&');
+ unset($options['form_params']);
+ $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+
+ if (isset($options['multipart'])) {
+ $elements = $options['multipart'];
+ unset($options['multipart']);
+ $options['body'] = new Psr7\MultipartStream($elements);
+ }
+
+ if (!empty($options['decode_content'])
+ && $options['decode_content'] !== true
+ ) {
+ $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
+ }
+
+ if (isset($options['headers'])) {
+ if (isset($modify['set_headers'])) {
+ $modify['set_headers'] = $options['headers'] + $modify['set_headers'];
+ } else {
+ $modify['set_headers'] = $options['headers'];
+ }
+ unset($options['headers']);
+ }
+
+ if (isset($options['body'])) {
+ if (is_array($options['body'])) {
+ $this->invalidBody();
+ }
+ $modify['body'] = Psr7\stream_for($options['body']);
+ unset($options['body']);
+ }
+
+ if (!empty($options['auth'])) {
+ $value = $options['auth'];
+ $type = is_array($value)
+ ? (isset($value[2]) ? strtolower($value[2]) : 'basic')
+ : $value;
+ $config['auth'] = $value;
+ switch (strtolower($type)) {
+ case 'basic':
+ $modify['set_headers']['Authorization'] = 'Basic '
+ . base64_encode("$value[0]:$value[1]");
+ break;
+ case 'digest':
+ // @todo: Do not rely on curl
+ $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
+ $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
+ break;
+ }
+ }
+
+ if (isset($options['query'])) {
+ $value = $options['query'];
+ if (is_array($value)) {
+ $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
+ }
+ if (!is_string($value)) {
+ throw new \InvalidArgumentException('query must be a string or array');
+ }
+ $modify['query'] = $value;
+ unset($options['query']);
+ }
+
+ if (isset($options['json'])) {
+ $modify['body'] = Psr7\stream_for(json_encode($options['json']));
+ $options['_conditional']['Content-Type'] = 'application/json';
+ unset($options['json']);
+ }
+
+ $request = Psr7\modify_request($request, $modify);
+ if ($request->getBody() instanceof Psr7\MultipartStream) {
+ // Use a multipart/form-data POST if a Content-Type is not set.
+ $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
+ . $request->getBody()->getBoundary();
+ }
+
+ // Merge in conditional headers if they are not present.
+ if (isset($options['_conditional'])) {
+ // Build up the changes so it's in a single clone of the message.
+ $modify = [];
+ foreach ($options['_conditional'] as $k => $v) {
+ if (!$request->hasHeader($k)) {
+ $modify['set_headers'][$k] = $v;
+ }
+ }
+ $request = Psr7\modify_request($request, $modify);
+ // Don't pass this internal value along to middleware/handlers.
+ unset($options['_conditional']);
+ }
+
+ return $request;
+ }
+
+ private function invalidBody()
+ {
+ throw new \InvalidArgumentException('Passing in the "body" request '
+ . 'option as an array to send a POST request has been deprecated. '
+ . 'Please use the "form_params" request option to send a '
+ . 'application/x-www-form-urlencoded request, or a the "multipart" '
+ . 'request option to send a multipart/form-data request.');
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/ClientInterface.php b/Lib/Alisms/GuzzleHttp/ClientInterface.php
new file mode 100644
index 0000000..b5b2306
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/ClientInterface.php
@@ -0,0 +1,84 @@
+strictMode = $strictMode;
+
+ foreach ($cookieArray as $cookie) {
+ if (!($cookie instanceof SetCookie)) {
+ $cookie = new SetCookie($cookie);
+ }
+ $this->setCookie($cookie);
+ }
+ }
+
+ /**
+ * Create a new Cookie jar from an associative array and domain.
+ *
+ * @param array $cookies Cookies to create the jar from
+ * @param string $domain Domain to set the cookies to
+ *
+ * @return self
+ */
+ public static function fromArray(array $cookies, $domain)
+ {
+ $cookieJar = new self();
+ foreach ($cookies as $name => $value) {
+ $cookieJar->setCookie(new SetCookie([
+ 'Domain' => $domain,
+ 'Name' => $name,
+ 'Value' => $value,
+ 'Discard' => true
+ ]));
+ }
+
+ return $cookieJar;
+ }
+
+ /**
+ * Quote the cookie value if it is not already quoted and it contains
+ * problematic characters.
+ *
+ * @param string $value Value that may or may not need to be quoted
+ *
+ * @return string
+ */
+ public static function getCookieValue($value)
+ {
+ if (substr($value, 0, 1) !== '"' &&
+ substr($value, -1, 1) !== '"' &&
+ strpbrk($value, ';,=')
+ ) {
+ $value = '"' . $value . '"';
+ }
+
+ return $value;
+ }
+
+ /**
+ * Evaluate if this cookie should be persisted to storage
+ * that survives between requests.
+ *
+ * @param SetCookie $cookie Being evaluated.
+ * @param bool $allowSessionCookies If we should presist session cookies
+ * @return bool
+ */
+ public static function shouldPersist(
+ SetCookie $cookie,
+ $allowSessionCookies = false
+ ) {
+ if ($cookie->getExpires() || $allowSessionCookies) {
+ if (!$cookie->getDiscard()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function toArray()
+ {
+ return array_map(function (SetCookie $cookie) {
+ return $cookie->toArray();
+ }, $this->getIterator()->getArrayCopy());
+ }
+
+ public function clear($domain = null, $path = null, $name = null)
+ {
+ if (!$domain) {
+ $this->cookies = [];
+ return;
+ } elseif (!$path) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain) {
+ return !$cookie->matchesDomain($domain);
+ }
+ );
+ } elseif (!$name) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain) {
+ return !($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ } else {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain, $name) {
+ return !($cookie->getName() == $name &&
+ $cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ }
+ }
+
+ public function clearSessionCookies()
+ {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) {
+ return !$cookie->getDiscard() && $cookie->getExpires();
+ }
+ );
+ }
+
+ public function setCookie(SetCookie $cookie)
+ {
+ // If the name string is empty (but not 0), ignore the set-cookie
+ // string entirely.
+ $name = $cookie->getName();
+ if (!$name && $name !== '0') {
+ return false;
+ }
+
+ // Only allow cookies with set and valid domain, name, value
+ $result = $cookie->validate();
+ if ($result !== true) {
+ if ($this->strictMode) {
+ throw new \RuntimeException('Invalid cookie: ' . $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, and domain are
+ // identical.
+ if ($c->getPath() != $cookie->getPath() ||
+ $c->getDomain() != $cookie->getDomain() ||
+ $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;
+ }
+
+ public function count()
+ {
+ return count($this->cookies);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator(array_values($this->cookies));
+ }
+
+ public function extractCookies(
+ RequestInterface $request,
+ ResponseInterface $response
+ ) {
+ if ($cookieHeader = $response->getHeader('Set-Cookie')) {
+ foreach ($cookieHeader as $cookie) {
+ $sc = SetCookie::fromString($cookie);
+ if (!$sc->getDomain()) {
+ $sc->setDomain($request->getUri()->getHost());
+ }
+ $this->setCookie($sc);
+ }
+ }
+ }
+
+ public function withCookieHeader(RequestInterface $request)
+ {
+ $values = [];
+ $uri = $request->getUri();
+ $scheme = $uri->getScheme();
+ $host = $uri->getHost();
+ $path = $uri->getPath() ?: '/';
+
+ foreach ($this->cookies as $cookie) {
+ if ($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($host) &&
+ !$cookie->isExpired() &&
+ (!$cookie->getSecure() || $scheme == 'https')
+ ) {
+ $values[] = $cookie->getName() . '='
+ . self::getCookieValue($cookie->getValue());
+ }
+ }
+
+ return $values
+ ? $request->withHeader('Cookie', implode('; ', $values))
+ : $request;
+ }
+
+ /**
+ * If a cookie already exists and the server asks to set it again with a
+ * null value, the cookie must be deleted.
+ *
+ * @param SetCookie $cookie
+ */
+ private function removeCookieIfEmpty(SetCookie $cookie)
+ {
+ $cookieValue = $cookie->getValue();
+ if ($cookieValue === null || $cookieValue === '') {
+ $this->clear(
+ $cookie->getDomain(),
+ $cookie->getPath(),
+ $cookie->getName()
+ );
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Cookie/CookieJarInterface.php b/Lib/Alisms/GuzzleHttp/Cookie/CookieJarInterface.php
new file mode 100644
index 0000000..2cf298a
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Cookie/CookieJarInterface.php
@@ -0,0 +1,84 @@
+filename = $cookieFile;
+ $this->storeSessionCookies = $storeSessionCookies;
+
+ if (file_exists($cookieFile)) {
+ $this->load($cookieFile);
+ }
+ }
+
+ /**
+ * Saves the file when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save($this->filename);
+ }
+
+ /**
+ * Saves the cookies to a file.
+ *
+ * @param string $filename File to save
+ * @throws \RuntimeException if the file cannot be found or created
+ */
+ public function save($filename)
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ /** @var SetCookie $cookie */
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ if (false === file_put_contents($filename, json_encode($json))) {
+ throw new \RuntimeException("Unable to save file {$filename}");
+ }
+ }
+
+ /**
+ * Load cookies from a JSON formatted file.
+ *
+ * Old cookies are kept unless overwritten by newly loaded ones.
+ *
+ * @param string $filename Cookie file to load.
+ * @throws \RuntimeException if the file cannot be loaded.
+ */
+ public function load($filename)
+ {
+ $json = file_get_contents($filename);
+ if (false === $json) {
+ throw new \RuntimeException("Unable to load file {$filename}");
+ }
+
+ $data = json_decode($json, true);
+ if (is_array($data)) {
+ foreach (json_decode($json, true) as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Cookie/SessionCookieJar.php b/Lib/Alisms/GuzzleHttp/Cookie/SessionCookieJar.php
new file mode 100644
index 0000000..d80c480
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Cookie/SessionCookieJar.php
@@ -0,0 +1,72 @@
+sessionKey = $sessionKey;
+ $this->storeSessionCookies = $storeSessionCookies;
+ $this->load();
+ }
+
+ /**
+ * Saves cookies to session when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save();
+ }
+
+ /**
+ * Save cookies to the client session
+ */
+ public function save()
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ /** @var SetCookie $cookie */
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ $_SESSION[$this->sessionKey] = json_encode($json);
+ }
+
+ /**
+ * Load the contents of the client session into the data array
+ */
+ protected function load()
+ {
+ $cookieJar = isset($_SESSION[$this->sessionKey])
+ ? $_SESSION[$this->sessionKey]
+ : null;
+
+ $data = json_decode($cookieJar, true);
+ if (is_array($data)) {
+ foreach ($data as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie data");
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Cookie/SetCookie.php b/Lib/Alisms/GuzzleHttp/Cookie/SetCookie.php
new file mode 100644
index 0000000..acd654d
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Cookie/SetCookie.php
@@ -0,0 +1,404 @@
+ null,
+ 'Value' => null,
+ 'Domain' => null,
+ 'Path' => '/',
+ 'Max-Age' => null,
+ 'Expires' => null,
+ 'Secure' => false,
+ 'Discard' => false,
+ 'HttpOnly' => false
+ ];
+
+ /** @var array Cookie data */
+ private $data;
+
+ /**
+ * Create a new SetCookie object from a string
+ *
+ * @param string $cookie Set-Cookie header string
+ *
+ * @return self
+ */
+ public static function fromString($cookie)
+ {
+ // Create the default return array
+ $data = self::$defaults;
+ // 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 new self($data);
+ }
+
+ // Add the cookie pieces into the parsed data array
+ foreach ($pieces as $part) {
+
+ $cookieParts = explode('=', $part, 2);
+ $key = trim($cookieParts[0]);
+ $value = isset($cookieParts[1])
+ ? trim($cookieParts[1], " \n\r\t\0\x0B")
+ : true;
+
+ // Only check for non-cookies when cookies have been found
+ if (empty($data['Name'])) {
+ $data['Name'] = $key;
+ $data['Value'] = $value;
+ } else {
+ foreach (array_keys(self::$defaults) as $search) {
+ if (!strcasecmp($search, $key)) {
+ $data[$search] = $value;
+ continue 2;
+ }
+ }
+ $data[$key] = $value;
+ }
+ }
+
+ return new self($data);
+ }
+
+ /**
+ * @param array $data Array of cookie data provided by a Cookie parser
+ */
+ public function __construct(array $data = [])
+ {
+ $this->data = array_replace(self::$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() + $this->getMaxAge());
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
+ $this->setExpires($this->getExpires());
+ }
+ }
+
+ public function __toString()
+ {
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
+ foreach ($this->data as $k => $v) {
+ if ($k != 'Name' && $k != 'Value' && $v !== null && $v !== false) {
+ if ($k == 'Expires') {
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
+ } else {
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
+ }
+ }
+ }
+
+ return rtrim($str, '; ');
+ }
+
+ 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
+ */
+ public function setName($name)
+ {
+ $this->data['Name'] = $name;
+ }
+
+ /**
+ * Get the cookie value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->data['Value'];
+ }
+
+ /**
+ * Set the cookie value
+ *
+ * @param string $value Cookie value
+ */
+ public function setValue($value)
+ {
+ $this->data['Value'] = $value;
+ }
+
+ /**
+ * Get the domain
+ *
+ * @return string|null
+ */
+ public function getDomain()
+ {
+ return $this->data['Domain'];
+ }
+
+ /**
+ * Set the domain of the cookie
+ *
+ * @param string $domain
+ */
+ public function setDomain($domain)
+ {
+ $this->data['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
+ */
+ public function setPath($path)
+ {
+ $this->data['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
+ */
+ public function setMaxAge($maxAge)
+ {
+ $this->data['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
+ */
+ public function setExpires($timestamp)
+ {
+ $this->data['Expires'] = is_numeric($timestamp)
+ ? (int) $timestamp
+ : strtotime($timestamp);
+ }
+
+ /**
+ * 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
+ */
+ public function setSecure($secure)
+ {
+ $this->data['Secure'] = $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
+ */
+ public function setDiscard($discard)
+ {
+ $this->data['Discard'] = $discard;
+ }
+
+ /**
+ * Get whether or not this is an HTTP only cookie
+ *
+ * @return bool
+ */
+ public function getHttpOnly()
+ {
+ return $this->data['HttpOnly'];
+ }
+
+ /**
+ * Set whether or not this is an HTTP only cookie
+ *
+ * @param bool $httpOnly Set to true or false if this is HTTP only
+ */
+ public function setHttpOnly($httpOnly)
+ {
+ $this->data['HttpOnly'] = $httpOnly;
+ }
+
+ /**
+ * Check if the cookie matches a path value.
+ *
+ * A request-path path-matches a given cookie-path if at least one of
+ * the following conditions holds:
+ *
+ * - The cookie-path and the request-path are identical.
+ * - The cookie-path is a prefix of the request-path, and the last
+ * character of the cookie-path is %x2F ("/").
+ * - 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.
+ *
+ * @param string $requestPath Path to check against
+ *
+ * @return bool
+ */
+ public function matchesPath($requestPath)
+ {
+ $cookiePath = $this->getPath();
+
+ // Match on exact matches or when path is the default empty "/"
+ if ($cookiePath == '/' || $cookiePath == $requestPath) {
+ return true;
+ }
+
+ // Ensure that the cookie-path is a prefix of the request path.
+ if (0 !== strpos($requestPath, $cookiePath)) {
+ return false;
+ }
+
+ // Match if the last character of the cookie-path is "/"
+ if (substr($cookiePath, -1, 1) == '/') {
+ return true;
+ }
+
+ // Match if the first character not included in cookie path is "/"
+ return substr($requestPath, strlen($cookiePath), 1) == '/';
+ }
+
+ /**
+ * 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) . '$/', $domain);
+ }
+
+ /**
+ * 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 (preg_match(
+ '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
+ $name)
+ ) {
+ return 'Cookie name must not contain invalid characters: ASCII '
+ . 'Control characters (0-31;127), space, tab and the '
+ . 'following characters: ()<>@,;:\"/?={}';
+ }
+
+ // 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;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Exception/BadResponseException.php b/Lib/Alisms/GuzzleHttp/Exception/BadResponseException.php
new file mode 100644
index 0000000..fd78431
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Exception/BadResponseException.php
@@ -0,0 +1,7 @@
+getStatusCode()
+ : 0;
+ parent::__construct($message, $code, $previous);
+ $this->request = $request;
+ $this->response = $response;
+ $this->handlerContext = $handlerContext;
+ }
+
+ /**
+ * Wrap non-RequestExceptions with a RequestException
+ *
+ * @param RequestInterface $request
+ * @param \Exception $e
+ *
+ * @return RequestException
+ */
+ public static function wrapException(RequestInterface $request, \Exception $e)
+ {
+ return $e instanceof RequestException
+ ? $e
+ : new RequestException($e->getMessage(), $request, null, $e);
+ }
+
+ /**
+ * Factory method to create a new exception with a normalized error message
+ *
+ * @param RequestInterface $request Request
+ * @param ResponseInterface $response Response received
+ * @param \Exception $previous Previous exception
+ * @param array $ctx Optional handler context.
+ *
+ * @return self
+ */
+ public static function create(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $previous = null,
+ array $ctx = []
+ ) {
+ if (!$response) {
+ return new self(
+ 'Error completing request',
+ $request,
+ null,
+ $previous,
+ $ctx
+ );
+ }
+
+ $level = floor($response->getStatusCode() / 100);
+ if ($level == '4') {
+ $label = 'Client error response';
+ $className = __NAMESPACE__ . '\\ClientException';
+ } elseif ($level == '5') {
+ $label = 'Server error response';
+ $className = __NAMESPACE__ . '\\ServerException';
+ } else {
+ $label = 'Unsuccessful response';
+ $className = __CLASS__;
+ }
+
+ $message = $label . ' [url] ' . $request->getUri()
+ . ' [http method] ' . $request->getMethod()
+ . ' [status code] ' . $response->getStatusCode()
+ . ' [reason phrase] ' . $response->getReasonPhrase();
+
+ return new $className($message, $request, $response, $previous, $ctx);
+ }
+
+ /**
+ * Get the request that caused the exception
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Get the associated response
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Check if a response was received
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * Get contextual information about the error from the underlying handler.
+ *
+ * The contents of this array will vary depending on which handler you are
+ * using. It may also be just an empty array. Relying on this data will
+ * couple you to a specific handler, but can give more debug information
+ * when needed.
+ *
+ * @return array
+ */
+ public function getHandlerContext()
+ {
+ return $this->handlerContext;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Exception/SeekException.php b/Lib/Alisms/GuzzleHttp/Exception/SeekException.php
new file mode 100644
index 0000000..a77c289
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Exception/SeekException.php
@@ -0,0 +1,27 @@
+stream = $stream;
+ $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
+ parent::__construct($msg);
+ }
+
+ /**
+ * @return StreamInterface
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Exception/ServerException.php b/Lib/Alisms/GuzzleHttp/Exception/ServerException.php
new file mode 100644
index 0000000..7cdd340
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Exception/ServerException.php
@@ -0,0 +1,7 @@
+maxHandles = $maxHandles;
+ }
+
+ public function create(RequestInterface $request, array $options)
+ {
+ if (isset($options['curl']['body_as_string'])) {
+ $options['_body_as_string'] = $options['curl']['body_as_string'];
+ unset($options['curl']['body_as_string']);
+ }
+
+ $easy = new EasyHandle;
+ $easy->request = $request;
+ $easy->options = $options;
+ $conf = $this->getDefaultConf($easy);
+ $this->applyMethod($easy, $conf);
+ $this->applyHandlerOptions($easy, $conf);
+ $this->applyHeaders($easy, $conf);
+ unset($conf['_headers']);
+
+ // Add handler options from the request configuration options
+ if (isset($options['curl'])) {
+ $conf = array_replace($conf, $options['curl']);
+ }
+
+ $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
+ $easy->handle = $this->handles
+ ? array_pop($this->handles)
+ : curl_init();
+ curl_setopt_array($easy->handle, $conf);
+
+ return $easy;
+ }
+
+ public function release(EasyHandle $easy)
+ {
+ $resource = $easy->handle;
+ unset($easy->handle);
+
+ if (count($this->handles) >= $this->maxHandles) {
+ curl_close($resource);
+ } else {
+ // Remove all callback functions as they can hold onto references
+ // and are not cleaned up by curl_reset. Using curl_setopt_array
+ // does not work for some reason, so removing each one
+ // individually.
+ curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
+ curl_setopt($resource, CURLOPT_READFUNCTION, null);
+ curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
+ curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
+ curl_reset($resource);
+ $this->handles[] = $resource;
+ }
+ }
+
+ /**
+ * Completes a cURL transaction, either returning a response promise or a
+ * rejected promise.
+ *
+ * @param callable $handler
+ * @param EasyHandle $easy
+ * @param CurlFactoryInterface $factory Dictates how the handle is released
+ *
+ * @return \GuzzleHttp\Promise\PromiseInterface
+ */
+ public static function finish(
+ callable $handler,
+ EasyHandle $easy,
+ CurlFactoryInterface $factory
+ ) {
+ if (isset($easy->options['on_stats'])) {
+ self::invokeStats($easy);
+ }
+
+ if (!$easy->response || $easy->errno) {
+ return self::finishError($handler, $easy, $factory);
+ }
+
+ // Return the response if it is present and there is no error.
+ $factory->release($easy);
+
+ // Rewind the body of the response if possible.
+ $body = $easy->response->getBody();
+ if ($body->isSeekable()) {
+ $body->rewind();
+ }
+
+ return new FulfilledPromise($easy->response);
+ }
+
+ private static function invokeStats(EasyHandle $easy)
+ {
+ $curlStats = curl_getinfo($easy->handle);
+ $stats = new TransferStats(
+ $easy->request,
+ $easy->response,
+ $curlStats['total_time'],
+ $easy->errno,
+ $curlStats
+ );
+ call_user_func($easy->options['on_stats'], $stats);
+ }
+
+ private static function finishError(
+ callable $handler,
+ EasyHandle $easy,
+ CurlFactoryInterface $factory
+ ) {
+ // Get error information and release the handle to the factory.
+ $ctx = [
+ 'errno' => $easy->errno,
+ 'error' => curl_error($easy->handle),
+ ] + curl_getinfo($easy->handle);
+ $factory->release($easy);
+
+ // Retry when nothing is present or when curl failed to rewind.
+ if (empty($easy->options['_err_message'])
+ && (!$easy->errno || $easy->errno == 65)
+ ) {
+ return self::retryFailedRewind($handler, $easy, $ctx);
+ }
+
+ return self::createRejection($easy, $ctx);
+ }
+
+ private static function createRejection(EasyHandle $easy, array $ctx)
+ {
+ static $connectionErrors = [
+ CURLE_OPERATION_TIMEOUTED => true,
+ CURLE_COULDNT_RESOLVE_HOST => true,
+ CURLE_COULDNT_CONNECT => true,
+ CURLE_SSL_CONNECT_ERROR => true,
+ CURLE_GOT_NOTHING => true,
+ ];
+
+ // If an exception was encountered during the onHeaders event, then
+ // return a rejected promise that wraps that exception.
+ if ($easy->onHeadersException) {
+ return new RejectedPromise(
+ new RequestException(
+ 'An error was encountered during the on_headers event',
+ $easy->request,
+ $easy->response,
+ $easy->onHeadersException,
+ $ctx
+ )
+ );
+ }
+
+ $message = sprintf(
+ 'cURL error %s: %s (%s)',
+ $ctx['errno'],
+ $ctx['error'],
+ 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
+ );
+
+ // Create a connection exception if it was a specific error code.
+ $error = isset($connectionErrors[$easy->errno])
+ ? new ConnectException($message, $easy->request, null, $ctx)
+ : new RequestException($message, $easy->request, $easy->response, null, $ctx);
+
+ return new RejectedPromise($error);
+ }
+
+ private function getDefaultConf(EasyHandle $easy)
+ {
+ $conf = [
+ '_headers' => $easy->request->getHeaders(),
+ CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
+ CURLOPT_URL => (string) $easy->request->getUri(),
+ CURLOPT_RETURNTRANSFER => false,
+ CURLOPT_HEADER => false,
+ CURLOPT_CONNECTTIMEOUT => 150,
+ CURLOPT_NOSIGNAL => true,
+ ];
+
+ if (defined('CURLOPT_PROTOCOLS')) {
+ $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
+ }
+
+ $version = $easy->request->getProtocolVersion();
+ if ($version == 1.1) {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
+ } elseif ($version == 2.0) {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
+ } else {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
+ }
+
+ return $conf;
+ }
+
+ private function applyMethod(EasyHandle $easy, array &$conf)
+ {
+ $body = $easy->request->getBody();
+ $size = $body->getSize();
+
+ if ($size === null || $size > 0) {
+ $this->applyBody($easy->request, $easy->options, $conf);
+ return;
+ }
+
+ $method = $easy->request->getMethod();
+ if ($method === 'PUT' || $method === 'POST') {
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
+ if (!$easy->request->hasHeader('Content-Length')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
+ }
+ } elseif ($method === 'HEAD') {
+ $conf[CURLOPT_NOBODY] = true;
+ unset(
+ $conf[CURLOPT_WRITEFUNCTION],
+ $conf[CURLOPT_READFUNCTION],
+ $conf[CURLOPT_FILE],
+ $conf[CURLOPT_INFILE]
+ );
+ }
+ }
+
+ private function applyBody(RequestInterface $request, array $options, array &$conf)
+ {
+ $size = $request->hasHeader('Content-Length')
+ ? (int) $request->getHeaderLine('Content-Length')
+ : null;
+
+ // Send the body as a string if the size is less than 1MB OR if the
+ // [curl][body_as_string] request value is set.
+ if (($size !== null && $size < 1000000) ||
+ !empty($options['_body_as_string'])
+ ) {
+ $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
+ // Don't duplicate the Content-Length header
+ $this->removeHeader('Content-Length', $conf);
+ $this->removeHeader('Transfer-Encoding', $conf);
+ } else {
+ $conf[CURLOPT_UPLOAD] = true;
+ if ($size !== null) {
+ $conf[CURLOPT_INFILESIZE] = $size;
+ $this->removeHeader('Content-Length', $conf);
+ }
+ $body = $request->getBody();
+ $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
+ return $body->read($length);
+ };
+ }
+
+ // If the Expect header is not present, prevent curl from adding it
+ if (!$request->hasHeader('Expect')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
+ }
+
+ // cURL sometimes adds a content-type by default. Prevent this.
+ if (!$request->hasHeader('Content-Type')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
+ }
+ }
+
+ private function applyHeaders(EasyHandle $easy, array &$conf)
+ {
+ foreach ($conf['_headers'] as $name => $values) {
+ foreach ($values as $value) {
+ $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
+ }
+ }
+
+ // Remove the Accept header if one was not set
+ if (!$easy->request->hasHeader('Accept')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
+ }
+ }
+
+ /**
+ * Remove a header from the options array.
+ *
+ * @param string $name Case-insensitive header to remove
+ * @param array $options Array of options to modify
+ */
+ private function removeHeader($name, array &$options)
+ {
+ foreach (array_keys($options['_headers']) as $key) {
+ if (!strcasecmp($key, $name)) {
+ unset($options['_headers'][$key]);
+ return;
+ }
+ }
+ }
+
+ private function applyHandlerOptions(EasyHandle $easy, array &$conf)
+ {
+ $options = $easy->options;
+ if (isset($options['verify'])) {
+ if ($options['verify'] === false) {
+ unset($conf[CURLOPT_CAINFO]);
+ $conf[CURLOPT_SSL_VERIFYHOST] = 0;
+ $conf[CURLOPT_SSL_VERIFYPEER] = false;
+ } else {
+ $conf[CURLOPT_SSL_VERIFYHOST] = 2;
+ $conf[CURLOPT_SSL_VERIFYPEER] = true;
+ if (is_string($options['verify'])) {
+ $conf[CURLOPT_CAINFO] = $options['verify'];
+ if (!file_exists($options['verify'])) {
+ throw new \InvalidArgumentException(
+ "SSL CA bundle not found: {$options['verify']}"
+ );
+ }
+ }
+ }
+ }
+
+ if (!empty($options['decode_content'])) {
+ $accept = $easy->request->getHeaderLine('Accept-Encoding');
+ if ($accept) {
+ $conf[CURLOPT_ENCODING] = $accept;
+ } else {
+ $conf[CURLOPT_ENCODING] = '';
+ // Don't let curl send the header over the wire
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
+ }
+ }
+
+ if (isset($options['sink'])) {
+ $sink = $options['sink'];
+ if (!is_string($sink)) {
+ $sink = \GuzzleHttp\Psr7\stream_for($sink);
+ } elseif (!is_dir(dirname($sink))) {
+ // Ensure that the directory exists before failing in curl.
+ throw new \RuntimeException(sprintf(
+ 'Directory %s does not exist for sink value of %s',
+ dirname($sink),
+ $sink
+ ));
+ } else {
+ $sink = new LazyOpenStream($sink, 'w+');
+ }
+ $easy->sink = $sink;
+ $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
+ return $sink->write($write);
+ };
+ } else {
+ // Use a default temp stream if no sink was set.
+ $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
+ $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
+ }
+
+ if (isset($options['timeout'])) {
+ $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
+ }
+
+ if (isset($options['connect_timeout'])) {
+ $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
+ }
+
+ if (isset($options['proxy'])) {
+ if (!is_array($options['proxy'])) {
+ $conf[CURLOPT_PROXY] = $options['proxy'];
+ } else {
+ $scheme = $easy->request->getUri()->getScheme();
+ if (isset($options['proxy'][$scheme])) {
+ $host = $easy->request->getUri()->getHost();
+ if (!isset($options['proxy']['no']) ||
+ !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
+ ) {
+ $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
+ }
+ }
+ }
+ }
+
+ if (isset($options['cert'])) {
+ $cert = $options['cert'];
+ if (is_array($cert)) {
+ $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
+ $cert = $cert[0];
+ }
+ if (!file_exists($cert)) {
+ throw new \InvalidArgumentException(
+ "SSL certificate not found: {$cert}"
+ );
+ }
+ $conf[CURLOPT_SSLCERT] = $cert;
+ }
+
+ if (isset($options['ssl_key'])) {
+ $sslKey = $options['ssl_key'];
+ if (is_array($sslKey)) {
+ $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
+ $sslKey = $sslKey[0];
+ }
+ if (!file_exists($sslKey)) {
+ throw new \InvalidArgumentException(
+ "SSL private key not found: {$sslKey}"
+ );
+ }
+ $conf[CURLOPT_SSLKEY] = $sslKey;
+ }
+
+ if (isset($options['progress'])) {
+ $progress = $options['progress'];
+ if (!is_callable($progress)) {
+ throw new \InvalidArgumentException(
+ 'progress client option must be callable'
+ );
+ }
+ $conf[CURLOPT_NOPROGRESS] = false;
+ $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
+ $args = func_get_args();
+ // PHP 5.5 pushed the handle onto the start of the args
+ if (is_resource($args[0])) {
+ array_shift($args);
+ }
+ call_user_func_array($progress, $args);
+ };
+ }
+
+ if (!empty($options['debug'])) {
+ $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
+ $conf[CURLOPT_VERBOSE] = true;
+ }
+ }
+
+ /**
+ * This function ensures that a response was set on a transaction. If one
+ * was not set, then the request is retried if possible. This error
+ * typically means you are sending a payload, curl encountered a
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
+ * stream, and then encountered a "necessary data rewind wasn't possible"
+ * error, causing the request to be sent through curl_multi_info_read()
+ * without an error status.
+ */
+ private static function retryFailedRewind(
+ callable $handler,
+ EasyHandle $easy,
+ array $ctx
+ ) {
+ try {
+ // Only rewind if the body has been read from.
+ $body = $easy->request->getBody();
+ if ($body->tell() > 0) {
+ $body->rewind();
+ }
+ } catch (\RuntimeException $e) {
+ $ctx['error'] = 'The connection unexpectedly failed without '
+ . 'providing an error. The request would have been retried, '
+ . 'but attempting to rewind the request body failed. '
+ . 'Exception: ' . $e;
+ return self::createRejection($easy, $ctx);
+ }
+
+ // Retry no more than 3 times before giving up.
+ if (!isset($easy->options['_curl_retries'])) {
+ $easy->options['_curl_retries'] = 1;
+ } elseif ($easy->options['_curl_retries'] == 2) {
+ $ctx['error'] = 'The cURL request was retried 3 times '
+ . 'and did not succeed. The most likely reason for the failure '
+ . 'is that cURL was unable to rewind the body of the request '
+ . 'and subsequent retries resulted in the same error. Turn on '
+ . 'the debug option to see what went wrong. See '
+ . 'https://bugs.php.net/bug.php?id=47204 for more information.';
+ return self::createRejection($easy, $ctx);
+ } else {
+ $easy->options['_curl_retries']++;
+ }
+
+ return $handler($easy->request, $easy->options);
+ }
+
+ private function createHeaderFn(EasyHandle $easy)
+ {
+ if (!isset($easy->options['on_headers'])) {
+ $onHeaders = null;
+ } elseif (!is_callable($easy->options['on_headers'])) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ } else {
+ $onHeaders = $easy->options['on_headers'];
+ }
+
+ return function ($ch, $h) use (
+ $onHeaders,
+ $easy,
+ &$startingResponse
+ ) {
+ $value = trim($h);
+ if ($value === '') {
+ $startingResponse = true;
+ $easy->createResponse();
+ if ($onHeaders) {
+ try {
+ $onHeaders($easy->response);
+ } catch (\Exception $e) {
+ // Associate the exception with the handle and trigger
+ // a curl header write error by returning 0.
+ $easy->onHeadersException = $e;
+ return -1;
+ }
+ }
+ } elseif ($startingResponse) {
+ $startingResponse = false;
+ $easy->headers = [$value];
+ } else {
+ $easy->headers[] = $value;
+ }
+ return strlen($h);
+ };
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Handler/CurlFactoryInterface.php b/Lib/Alisms/GuzzleHttp/Handler/CurlFactoryInterface.php
new file mode 100644
index 0000000..b0fc236
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Handler/CurlFactoryInterface.php
@@ -0,0 +1,27 @@
+factory = isset($options['handle_factory'])
+ ? $options['handle_factory']
+ : new CurlFactory(3);
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (isset($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $easy = $this->factory->create($request, $options);
+ curl_exec($easy->handle);
+ $easy->errno = curl_errno($easy->handle);
+
+ return CurlFactory::finish($this, $easy, $this->factory);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Handler/CurlMultiHandler.php b/Lib/Alisms/GuzzleHttp/Handler/CurlMultiHandler.php
new file mode 100644
index 0000000..417850b
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Handler/CurlMultiHandler.php
@@ -0,0 +1,197 @@
+factory = isset($options['handle_factory'])
+ ? $options['handle_factory'] : new CurlFactory(50);
+ $this->selectTimeout = isset($options['select_timeout'])
+ ? $options['select_timeout'] : 1;
+ }
+
+ public function __get($name)
+ {
+ if ($name === '_mh') {
+ return $this->_mh = curl_multi_init();
+ }
+
+ throw new \BadMethodCallException();
+ }
+
+ public function __destruct()
+ {
+ if (isset($this->_mh)) {
+ curl_multi_close($this->_mh);
+ unset($this->_mh);
+ }
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $easy = $this->factory->create($request, $options);
+ $id = (int) $easy->handle;
+
+ $promise = new Promise(
+ [$this, 'execute'],
+ function () use ($id) { return $this->cancel($id); }
+ );
+
+ $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
+
+ return $promise;
+ }
+
+ /**
+ * Ticks the curl event loop.
+ */
+ public function tick()
+ {
+ // Add any delayed handles if needed.
+ if ($this->delays) {
+ $currentTime = microtime(true);
+ foreach ($this->delays as $id => $delay) {
+ if ($currentTime >= $delay) {
+ unset($this->delays[$id]);
+ curl_multi_add_handle(
+ $this->_mh,
+ $this->handles[$id]['easy']->handle
+ );
+ }
+ }
+ }
+
+ // Step through the task queue which may add additional requests.
+ P\queue()->run();
+
+ if ($this->active &&
+ curl_multi_select($this->_mh, $this->selectTimeout) === -1
+ ) {
+ // Perform a usleep if a select returns -1.
+ // See: https://bugs.php.net/bug.php?id=61141
+ usleep(250);
+ }
+
+ while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
+
+ $this->processMessages();
+ }
+
+ /**
+ * Runs until all outstanding connections have completed.
+ */
+ public function execute()
+ {
+ $queue = P\queue();
+
+ while ($this->handles || !$queue->isEmpty()) {
+ // If there are no transfers, then sleep for the next delay
+ if (!$this->active && $this->delays) {
+ usleep($this->timeToNext());
+ }
+ $this->tick();
+ }
+ }
+
+ private function addRequest(array $entry)
+ {
+ $easy = $entry['easy'];
+ $id = (int) $easy->handle;
+ $this->handles[$id] = $entry;
+ if (empty($easy->options['delay'])) {
+ curl_multi_add_handle($this->_mh, $easy->handle);
+ } else {
+ $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
+ }
+ }
+
+ /**
+ * Cancels a handle from sending and removes references to it.
+ *
+ * @param int $id Handle ID to cancel and remove.
+ *
+ * @return bool True on success, false on failure.
+ */
+ private function cancel($id)
+ {
+ // Cannot cancel if it has been processed.
+ if (!isset($this->handles[$id])) {
+ return false;
+ }
+
+ $handle = $this->handles[$id]['easy']->handle;
+ unset($this->delays[$id], $this->handles[$id]);
+ curl_multi_remove_handle($this->_mh, $handle);
+ curl_close($handle);
+
+ return true;
+ }
+
+ private function processMessages()
+ {
+ while ($done = curl_multi_info_read($this->_mh)) {
+ $id = (int) $done['handle'];
+ curl_multi_remove_handle($this->_mh, $done['handle']);
+
+ if (!isset($this->handles[$id])) {
+ // Probably was cancelled.
+ continue;
+ }
+
+ $entry = $this->handles[$id];
+ unset($this->handles[$id], $this->delays[$id]);
+ $entry['easy']->errno = $done['result'];
+ $entry['deferred']->resolve(
+ CurlFactory::finish(
+ $this,
+ $entry['easy'],
+ $this->factory
+ )
+ );
+ }
+ }
+
+ private function timeToNext()
+ {
+ $currentTime = microtime(true);
+ $nextTime = PHP_INT_MAX;
+ foreach ($this->delays as $time) {
+ if ($time < $nextTime) {
+ $nextTime = $time;
+ }
+ }
+
+ return max(0, $currentTime - $nextTime);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Handler/EasyHandle.php b/Lib/Alisms/GuzzleHttp/Handler/EasyHandle.php
new file mode 100644
index 0000000..c4b927e
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Handler/EasyHandle.php
@@ -0,0 +1,87 @@
+headers)) {
+ throw new \RuntimeException('No headers have been received');
+ }
+
+ // HTTP-version SP status-code SP reason-phrase
+ $startLine = explode(' ', array_shift($this->headers), 3);
+ $headers = \GuzzleHttp\headers_from_lines($this->headers);
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+
+ if (!empty($this->options['decode_content'])
+ && isset($normalizedKeys['content-encoding'])
+ ) {
+ unset($headers[$normalizedKeys['content-encoding']]);
+ if (isset($normalizedKeys['content-length'])) {
+ $bodyLength = (int) $this->sink->getSize();
+ if ($bodyLength) {
+ $headers[$normalizedKeys['content-length']] = $bodyLength;
+ } else {
+ unset($headers[$normalizedKeys['content-length']]);
+ }
+ }
+ }
+
+ // Attach a response to the easy handle with the parsed headers.
+ $this->response = new Response(
+ $startLine[1],
+ $headers,
+ $this->sink,
+ substr($startLine[0], 5),
+ isset($startLine[2]) ? (string) $startLine[2] : null
+ );
+ }
+
+ public function __get($name)
+ {
+ $msg = $name === 'handle'
+ ? 'The EasyHandle has been released'
+ : 'Invalid property: ' . $name;
+ throw new \BadMethodCallException($msg);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Handler/MockHandler.php b/Lib/Alisms/GuzzleHttp/Handler/MockHandler.php
new file mode 100644
index 0000000..4b1b0af
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Handler/MockHandler.php
@@ -0,0 +1,163 @@
+onFulfilled = $onFulfilled;
+ $this->onRejected = $onRejected;
+
+ if ($queue) {
+ call_user_func_array([$this, 'append'], $queue);
+ }
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!$this->queue) {
+ throw new \OutOfBoundsException('Mock queue is empty');
+ }
+
+ if (isset($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $this->lastRequest = $request;
+ $this->lastOptions = $options;
+ $response = array_shift($this->queue);
+
+ if (is_callable($response)) {
+ $response = $response($request, $options);
+ }
+
+ $response = $response instanceof \Exception
+ ? new RejectedPromise($response)
+ : \GuzzleHttp\Promise\promise_for($response);
+
+ return $response->then(
+ function ($value) use ($request, $options) {
+ $this->invokeStats($request, $options, $value);
+ if ($this->onFulfilled) {
+ call_user_func($this->onFulfilled, $value);
+ }
+ return $value;
+ },
+ function ($reason) use ($request, $options) {
+ $this->invokeStats($request, $options, null, $reason);
+ if ($this->onRejected) {
+ call_user_func($this->onRejected, $reason);
+ }
+ return new RejectedPromise($reason);
+ }
+ );
+ }
+
+ /**
+ * Adds one or more variadic requests, exceptions, callables, or promises
+ * to the queue.
+ */
+ public function append()
+ {
+ foreach (func_get_args() as $value) {
+ if ($value instanceof ResponseInterface
+ || $value instanceof \Exception
+ || $value instanceof PromiseInterface
+ || is_callable($value)
+ ) {
+ $this->queue[] = $value;
+ } else {
+ throw new \InvalidArgumentException('Expected a response or '
+ . 'exception. Found ' . \GuzzleHttp\describe_type($value));
+ }
+ }
+ }
+
+ /**
+ * Get the last received request.
+ *
+ * @return RequestInterface
+ */
+ public function getLastRequest()
+ {
+ return $this->lastRequest;
+ }
+
+ /**
+ * Get the last received request options.
+ *
+ * @return RequestInterface
+ */
+ public function getLastOptions()
+ {
+ return $this->lastOptions;
+ }
+
+ /**
+ * Returns the number of remaining items in the queue.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->queue);
+ }
+
+ private function invokeStats(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response = null,
+ $reason = null
+ ) {
+ if (isset($options['on_stats'])) {
+ $stats = new TransferStats($request, $response, 0, $reason);
+ call_user_func($options['on_stats'], $stats);
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Handler/Proxy.php b/Lib/Alisms/GuzzleHttp/Handler/Proxy.php
new file mode 100644
index 0000000..9bd76d2
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Handler/Proxy.php
@@ -0,0 +1,54 @@
+withoutHeader('Expect');
+
+ // Append a content-length header if body size is zero to match
+ // cURL's behavior.
+ if (0 === $request->getBody()->getSize()) {
+ $request = $request->withHeader('Content-Length', 0);
+ }
+
+ return $this->createResponse(
+ $request,
+ $options,
+ $this->createStream($request, $options),
+ $startTime
+ );
+ } catch (\InvalidArgumentException $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ // Determine if the error was a networking error.
+ $message = $e->getMessage();
+ // This list can probably get more comprehensive.
+ if (strpos($message, 'getaddrinfo') // DNS lookup failed
+ || strpos($message, 'Connection refused')
+ || strpos($message, "couldn't connect to host") // error on HHVM
+ ) {
+ $e = new ConnectException($e->getMessage(), $request, $e);
+ }
+ $e = RequestException::wrapException($request, $e);
+ $this->invokeStats($options, $request, $startTime, null, $e);
+
+ return new RejectedPromise($e);
+ }
+ }
+
+ private function invokeStats(
+ array $options,
+ RequestInterface $request,
+ $startTime,
+ ResponseInterface $response = null,
+ $error = null
+ ) {
+ if (isset($options['on_stats'])) {
+ $stats = new TransferStats(
+ $request,
+ $response,
+ microtime(true) - $startTime,
+ $error,
+ []
+ );
+ call_user_func($options['on_stats'], $stats);
+ }
+ }
+
+ private function createResponse(
+ RequestInterface $request,
+ array $options,
+ $stream,
+ $startTime
+ ) {
+ $hdrs = $this->lastHeaders;
+ $this->lastHeaders = [];
+ $parts = explode(' ', array_shift($hdrs), 3);
+ $ver = explode('/', $parts[0])[1];
+ $status = $parts[1];
+ $reason = isset($parts[2]) ? $parts[2] : null;
+ $headers = \GuzzleHttp\headers_from_lines($hdrs);
+ list ($stream, $headers) = $this->checkDecode($options, $headers, $stream);
+ $stream = Psr7\stream_for($stream);
+ $sink = $this->createSink($stream, $options);
+ $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
+
+ if (isset($options['on_headers'])) {
+ try {
+ $options['on_headers']($response);
+ } catch (\Exception $e) {
+ $msg = 'An error was encountered during the on_headers event';
+ $ex = new RequestException($msg, $request, $response, $e);
+ return new RejectedPromise($ex);
+ }
+ }
+
+ if ($sink !== $stream) {
+ $this->drain($stream, $sink);
+ }
+
+ $this->invokeStats($options, $request, $startTime, $response, null);
+
+ return new FulfilledPromise($response);
+ }
+
+ private function createSink(StreamInterface $stream, array $options)
+ {
+ if (!empty($options['stream'])) {
+ return $stream;
+ }
+
+ $sink = isset($options['sink'])
+ ? $options['sink']
+ : fopen('php://temp', 'r+');
+
+ return is_string($sink)
+ ? new Psr7\Stream(Psr7\try_fopen($sink, 'r+'))
+ : Psr7\stream_for($sink);
+ }
+
+ private function checkDecode(array $options, array $headers, $stream)
+ {
+ // Automatically decode responses when instructed.
+ if (!empty($options['decode_content'])) {
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+ if (isset($normalizedKeys['content-encoding'])) {
+ $encoding = $headers[$normalizedKeys['content-encoding']];
+ if ($encoding[0] == 'gzip' || $encoding[0] == 'deflate') {
+ $stream = new Psr7\InflateStream(
+ Psr7\stream_for($stream)
+ );
+ // Remove content-encoding header
+ unset($headers[$normalizedKeys['content-encoding']]);
+ // Fix content-length header
+ if (isset($normalizedKeys['content-length'])) {
+ $length = (int) $stream->getSize();
+ if ($length == 0) {
+ unset($headers[$normalizedKeys['content-length']]);
+ } else {
+ $headers[$normalizedKeys['content-length']] = [$length];
+ }
+ }
+ }
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ /**
+ * Drains the source stream into the "sink" client option.
+ *
+ * @param StreamInterface $source
+ * @param StreamInterface $sink
+ *
+ * @return StreamInterface
+ * @throws \RuntimeException when the sink option is invalid.
+ */
+ private function drain(StreamInterface $source, StreamInterface $sink)
+ {
+ Psr7\copy_to_stream($source, $sink);
+ $sink->seek(0);
+ $source->close();
+
+ return $sink;
+ }
+
+ /**
+ * Create a resource and check to ensure it was created successfully
+ *
+ * @param callable $callback Callable that returns stream resource
+ *
+ * @return resource
+ * @throws \RuntimeException on error
+ */
+ private function createResource(callable $callback)
+ {
+ $errors = null;
+ set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
+ $errors[] = [
+ 'message' => $msg,
+ 'file' => $file,
+ 'line' => $line
+ ];
+ return true;
+ });
+
+ $resource = $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;
+ }
+
+ private function createStream(RequestInterface $request, array $options)
+ {
+ static $methods;
+ if (!$methods) {
+ $methods = array_flip(get_class_methods(__CLASS__));
+ }
+
+ // HTTP/1.1 streams using the PHP stream wrapper require a
+ // Connection: close header
+ if ($request->getProtocolVersion() == '1.1'
+ && !$request->hasHeader('Connection')
+ ) {
+ $request = $request->withHeader('Connection', 'close');
+ }
+
+ // Ensure SSL is verified by default
+ if (!isset($options['verify'])) {
+ $options['verify'] = true;
+ }
+
+ $params = [];
+ $context = $this->getDefaultContext($request, $options);
+
+ if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+
+ if (!empty($options)) {
+ foreach ($options as $key => $value) {
+ $method = "add_{$key}";
+ if (isset($methods[$method])) {
+ $this->{$method}($request, $context, $value, $params);
+ }
+ }
+ }
+
+ if (isset($options['stream_context'])) {
+ if (!is_array($options['stream_context'])) {
+ throw new \InvalidArgumentException('stream_context must be an array');
+ }
+ $context = array_replace_recursive(
+ $context,
+ $options['stream_context']
+ );
+ }
+
+ $context = $this->createResource(
+ function () use ($context, $params) {
+ return stream_context_create($context, $params);
+ }
+ );
+
+ return $this->createResource(
+ function () use ($request, &$http_response_header, $context) {
+ $resource = fopen($request->getUri(), 'r', null, $context);
+ $this->lastHeaders = $http_response_header;
+ return $resource;
+ }
+ );
+ }
+
+ private function getDefaultContext(RequestInterface $request)
+ {
+ $headers = '';
+ foreach ($request->getHeaders() as $name => $value) {
+ foreach ($value as $val) {
+ $headers .= "$name: $val\r\n";
+ }
+ }
+
+ $context = [
+ 'http' => [
+ 'method' => $request->getMethod(),
+ 'header' => $headers,
+ 'protocol_version' => $request->getProtocolVersion(),
+ 'ignore_errors' => true,
+ 'follow_location' => 0,
+ ],
+ ];
+
+ $body = (string) $request->getBody();
+
+ if (!empty($body)) {
+ $context['http']['content'] = $body;
+ // Prevent the HTTP handler from adding a Content-Type header.
+ if (!$request->hasHeader('Content-Type')) {
+ $context['http']['header'] .= "Content-Type:\r\n";
+ }
+ }
+
+ $context['http']['header'] = rtrim($context['http']['header']);
+
+ return $context;
+ }
+
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (!is_array($value)) {
+ $options['http']['proxy'] = $value;
+ } else {
+ $scheme = $request->getUri()->getScheme();
+ if (isset($value[$scheme])) {
+ if (!isset($value['no'])
+ || !\GuzzleHttp\is_host_in_noproxy(
+ $request->getUri()->getHost(),
+ $value['no']
+ )
+ ) {
+ $options['http']['proxy'] = $value[$scheme];
+ }
+ }
+ }
+ }
+
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
+ {
+ $options['http']['timeout'] = $value;
+ }
+
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value === true) {
+ // PHP 5.6 or greater will find the system cert by default. When
+ // < 5.6, use the Guzzle bundled cacert.
+ if (PHP_VERSION_ID < 50600) {
+ $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
+ }
+ } elseif (is_string($value)) {
+ $options['ssl']['cafile'] = $value;
+ if (!file_exists($value)) {
+ throw new \RuntimeException("SSL CA bundle not found: $value");
+ }
+ } elseif ($value === false) {
+ $options['ssl']['verify_peer'] = false;
+ return;
+ } else {
+ throw new \InvalidArgumentException('Invalid verify request option');
+ }
+
+ $options['ssl']['verify_peer'] = true;
+ $options['ssl']['allow_self_signed'] = false;
+ }
+
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (is_array($value)) {
+ $options['ssl']['passphrase'] = $value[1];
+ $value = $value[0];
+ }
+
+ if (!file_exists($value)) {
+ throw new \RuntimeException("SSL certificate not found: {$value}");
+ }
+
+ $options['ssl']['local_cert'] = $value;
+ }
+
+ private function add_progress(RequestInterface $request, &$options, $value, &$params)
+ {
+ $this->addNotification(
+ $params,
+ function ($code, $a, $b, $c, $transferred, $total) use ($value) {
+ if ($code == STREAM_NOTIFY_PROGRESS) {
+ $value($total, $transferred, null, null);
+ }
+ }
+ );
+ }
+
+ private function add_debug(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value === false) {
+ return;
+ }
+
+ static $map = [
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE',
+ ];
+ static $args = ['severity', 'message', 'message_code',
+ 'bytes_transferred', 'bytes_max'];
+
+ $value = \GuzzleHttp\debug_resource($value);
+ $ident = $request->getMethod() . ' ' . $request->getUri();
+ $this->addNotification(
+ $params,
+ function () use ($ident, $value, $map, $args) {
+ $passed = func_get_args();
+ $code = array_shift($passed);
+ fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
+ foreach (array_filter($passed) as $i => $v) {
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
+ }
+ fwrite($value, "\n");
+ }
+ );
+ }
+
+ private function addNotification(array &$params, callable $notify)
+ {
+ // Wrap the existing function if needed.
+ if (!isset($params['notification'])) {
+ $params['notification'] = $notify;
+ } else {
+ $params['notification'] = $this->callArray([
+ $params['notification'],
+ $notify
+ ]);
+ }
+ }
+
+ private function callArray(array $functions)
+ {
+ return function () use ($functions) {
+ $args = func_get_args();
+ foreach ($functions as $fn) {
+ call_user_func_array($fn, $args);
+ }
+ };
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/HandlerStack.php b/Lib/Alisms/GuzzleHttp/HandlerStack.php
new file mode 100644
index 0000000..f851849
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/HandlerStack.php
@@ -0,0 +1,272 @@
+push(Middleware::httpErrors(), 'http_errors');
+ $stack->push(Middleware::redirect(), 'allow_redirects');
+ $stack->push(Middleware::cookies(), 'cookies');
+ $stack->push(Middleware::prepareBody(), 'prepare_body');
+
+ return $stack;
+ }
+
+ /**
+ * @param callable $handler Underlying HTTP handler.
+ */
+ public function __construct(callable $handler = null)
+ {
+ $this->handler = $handler;
+ }
+
+ /**
+ * Invokes the handler stack as a composed handler
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!$this->cached) {
+ $this->cached = $this->resolve();
+ }
+
+ $handler = $this->cached;
+ return $handler($request, $options);
+ }
+
+ /**
+ * Dumps a string representation of the stack.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $depth = 0;
+ $stack = [];
+ if ($this->handler) {
+ $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
+ }
+
+ $result = '';
+ foreach (array_reverse($this->stack) as $tuple) {
+ $depth++;
+ $str = "{$depth}) Name: '{$tuple[1]}', ";
+ $str .= "Function: " . $this->debugCallable($tuple[0]);
+ $result = "> {$str}\n{$result}";
+ $stack[] = $str;
+ }
+
+ foreach (array_keys($stack) as $k) {
+ $result .= "< {$stack[$k]}\n";
+ }
+
+ return $result;
+ }
+
+ /**
+ * Set the HTTP handler that actually returns a promise.
+ *
+ * @param callable $handler Accepts a request and array of options and
+ * returns a Promise.
+ */
+ public function setHandler(callable $handler)
+ {
+ $this->handler = $handler;
+ $this->cached = null;
+ }
+
+ /**
+ * Returns true if the builder has a handler.
+ *
+ * @return bool
+ */
+ public function hasHandler()
+ {
+ return (bool) $this->handler;
+ }
+
+ /**
+ * Unshift a middleware to the bottom of the stack.
+ *
+ * @param callable $middleware Middleware function
+ * @param string $name Name to register for this middleware.
+ */
+ public function unshift(callable $middleware, $name = null)
+ {
+ array_unshift($this->stack, [$middleware, $name]);
+ $this->cached = null;
+ }
+
+ /**
+ * Push a middleware to the top of the stack.
+ *
+ * @param callable $middleware Middleware function
+ * @param string $name Name to register for this middleware.
+ */
+ public function push(callable $middleware, $name = '')
+ {
+ $this->stack[] = [$middleware, $name];
+ $this->cached = null;
+ }
+
+ /**
+ * Add a middleware before another middleware by name.
+ *
+ * @param string $findName Middleware to find
+ * @param callable $middleware Middleware function
+ * @param string $withName Name to register for this middleware.
+ */
+ public function before($findName, callable $middleware, $withName = '')
+ {
+ $this->splice($findName, $withName, $middleware, true);
+ }
+
+ /**
+ * Add a middleware after another middleware by name.
+ *
+ * @param string $findName Middleware to find
+ * @param callable $middleware Middleware function
+ * @param string $withName Name to register for this middleware.
+ */
+ public function after($findName, callable $middleware, $withName = '')
+ {
+ $this->splice($findName, $withName, $middleware, false);
+ }
+
+ /**
+ * Remove a middleware by instance or name from the stack.
+ *
+ * @param callable|string $remove Middleware to remove by instance or name.
+ */
+ public function remove($remove)
+ {
+ $this->cached = null;
+ $idx = is_callable($remove) ? 0 : 1;
+ $this->stack = array_values(array_filter(
+ $this->stack,
+ function ($tuple) use ($idx, $remove) {
+ return $tuple[$idx] !== $remove;
+ }
+ ));
+ }
+
+ /**
+ * Compose the middleware and handler into a single callable function.
+ *
+ * @return callable
+ */
+ public function resolve()
+ {
+ if (!($prev = $this->handler)) {
+ throw new \LogicException('No handler has been specified');
+ }
+
+ foreach (array_reverse($this->stack) as $fn) {
+ $prev = $fn[0]($prev);
+ }
+
+ return $prev;
+ }
+
+ /**
+ * @param $name
+ * @return int
+ */
+ private function findByName($name)
+ {
+ foreach ($this->stack as $k => $v) {
+ if ($v[1] === $name) {
+ return $k;
+ }
+ }
+
+ throw new \InvalidArgumentException("Middleware not found: $name");
+ }
+
+ /**
+ * Splices a function into the middleware list at a specific position.
+ *
+ * @param $findName
+ * @param $withName
+ * @param callable $middleware
+ * @param $before
+ */
+ private function splice($findName, $withName, callable $middleware, $before)
+ {
+ $this->cached = null;
+ $idx = $this->findByName($findName);
+ $tuple = [$middleware, $withName];
+
+ if ($before) {
+ if ($idx === 0) {
+ array_unshift($this->stack, $tuple);
+ } else {
+ $replacement = [$tuple, $this->stack[$idx]];
+ array_splice($this->stack, $idx, 1, $replacement);
+ }
+ } elseif ($idx === count($this->stack) - 1) {
+ $this->stack[] = $tuple;
+ } else {
+ $replacement = [$this->stack[$idx], $tuple];
+ array_splice($this->stack, $idx, 1, $replacement);
+ }
+ }
+
+ /**
+ * Provides a debug string for a given callable.
+ *
+ * @param array|callable $fn Function to write as a string.
+ *
+ * @return string
+ */
+ private function debugCallable($fn)
+ {
+ if (is_string($fn)) {
+ return "callable({$fn})";
+ }
+
+ if (is_array($fn)) {
+ return is_string($fn[0])
+ ? "callable({$fn[0]}::{$fn[1]})"
+ : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
+ }
+
+ return 'callable(' . spl_object_hash($fn) . ')';
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/MessageFormatter.php b/Lib/Alisms/GuzzleHttp/MessageFormatter.php
new file mode 100644
index 0000000..6b090a9
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/MessageFormatter.php
@@ -0,0 +1,182 @@
+>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
+ const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
+
+ /** @var string Template used to format log messages */
+ private $template;
+
+ /**
+ * @param string $template Log message template
+ */
+ public function __construct($template = self::CLF)
+ {
+ $this->template = $template ?: self::CLF;
+ }
+
+ /**
+ * 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
+ ) {
+ $cache = [];
+
+ return preg_replace_callback(
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
+ function (array $matches) use ($request, $response, $error, &$cache) {
+
+ if (isset($cache[$matches[1]])) {
+ return $cache[$matches[1]];
+ }
+
+ $result = '';
+ switch ($matches[1]) {
+ case 'request':
+ $result = Psr7\str($request);
+ break;
+ case 'response':
+ $result = $response ? Psr7\str($response) : '';
+ break;
+ case 'req_headers':
+ $result = trim($request->getMethod()
+ . ' ' . $request->getRequestTarget())
+ . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
+ . $this->headers($request);
+ break;
+ case 'res_headers':
+ $result = $response ?
+ sprintf(
+ 'HTTP/%s %d %s',
+ $response->getProtocolVersion(),
+ $response->getStatusCode(),
+ $response->getReasonPhrase()
+ ) . "\r\n" . $this->headers($response)
+ : 'NULL';
+ break;
+ case 'req_body':
+ $result = $request->getBody();
+ break;
+ case 'res_body':
+ $result = $response ? $response->getBody() : 'NULL';
+ break;
+ case 'ts':
+ case 'date_iso_8601':
+ $result = gmdate('c');
+ break;
+ case 'date_common_log':
+ $result = date('d/M/Y:H:i:s O');
+ break;
+ case 'method':
+ $result = $request->getMethod();
+ break;
+ case 'version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'uri':
+ case 'url':
+ $result = $request->getUri();
+ break;
+ case 'target':
+ $result = $request->getRequestTarget();
+ break;
+ case 'req_version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'res_version':
+ $result = $response
+ ? $response->getProtocolVersion()
+ : 'NULL';
+ break;
+ case 'host':
+ $result = $request->getHeaderLine('Host');
+ break;
+ case 'hostname':
+ $result = gethostname();
+ break;
+ case 'code':
+ $result = $response ? $response->getStatusCode() : 'NULL';
+ break;
+ case 'phrase':
+ $result = $response ? $response->getReasonPhrase() : 'NULL';
+ break;
+ case 'error':
+ $result = $error ? $error->getMessage() : 'NULL';
+ break;
+ default:
+ // handle prefixed dynamic headers
+ if (strpos($matches[1], 'req_header_') === 0) {
+ $result = $request->getHeaderLine(substr($matches[1], 11));
+ } elseif (strpos($matches[1], 'res_header_') === 0) {
+ $result = $response
+ ? $response->getHeaderLine(substr($matches[1], 11))
+ : 'NULL';
+ }
+ }
+
+ $cache[$matches[1]] = $result;
+ return $result;
+ },
+ $this->template
+ );
+ }
+
+ private function headers(MessageInterface $message)
+ {
+ $result = '';
+ foreach ($message->getHeaders() as $name => $values) {
+ $result .= $name . ': ' . implode(', ', $values) . "\r\n";
+ }
+
+ return trim($result);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Middleware.php b/Lib/Alisms/GuzzleHttp/Middleware.php
new file mode 100644
index 0000000..2f165f3
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Middleware.php
@@ -0,0 +1,253 @@
+withCookieHeader($request);
+ return $handler($request, $options)
+ ->then(function ($response) use ($cookieJar, $request) {
+ $cookieJar->extractCookies($request, $response);
+ return $response;
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that throws exceptions for 4xx or 5xx responses when the
+ * "http_error" request option is set to true.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function httpErrors()
+ {
+ return function (callable $handler) {
+ return function ($request, array $options) use ($handler) {
+ if (empty($options['http_errors'])) {
+ return $handler($request, $options);
+ }
+ return $handler($request, $options)->then(
+ function (ResponseInterface $response) use ($request, $handler) {
+ $code = $response->getStatusCode();
+ if ($code < 400) {
+ return $response;
+ }
+ throw $code > 499
+ ? new ServerException("Server error: $code", $request, $response)
+ : new ClientException("Client error: $code", $request, $response);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that pushes history data to an ArrayAccess container.
+ *
+ * @param array $container Container to hold the history (by reference).
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function history(array &$container)
+ {
+ return function (callable $handler) use (&$container) {
+ return function ($request, array $options) use ($handler, &$container) {
+ return $handler($request, $options)->then(
+ function ($value) use ($request, &$container, $options) {
+ $container[] = [
+ 'request' => $request,
+ 'response' => $value,
+ 'error' => null,
+ 'options' => $options
+ ];
+ return $value;
+ },
+ function ($reason) use ($request, &$container, $options) {
+ $container[] = [
+ 'request' => $request,
+ 'response' => null,
+ 'error' => $reason,
+ 'options' => $options
+ ];
+ return new RejectedPromise($reason);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that invokes a callback before and after sending a request.
+ *
+ * The provided listener cannot modify or alter the response. It simply
+ * "taps" into the chain to be notified before returning the promise. The
+ * before listener accepts a request and options array, and the after
+ * listener accepts a request, options array, and response promise.
+ *
+ * @param callable $before Function to invoke before forwarding the request.
+ * @param callable $after Function invoked after forwarding.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function tap(callable $before = null, callable $after = null)
+ {
+ return function (callable $handler) use ($before, $after) {
+ return function ($request, array $options) use ($handler, $before, $after) {
+ if ($before) {
+ $before($request, $options);
+ }
+ $response = $handler($request, $options);
+ if ($after) {
+ $after($request, $options, $response);
+ }
+ return $response;
+ };
+ };
+ }
+
+ /**
+ * Middleware that handles request redirects.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function redirect()
+ {
+ return function (callable $handler) {
+ return new RedirectMiddleware($handler);
+ };
+ }
+
+ /**
+ * Middleware that retries requests based on the boolean result of
+ * invoking the provided "decider" function.
+ *
+ * If no delay function is provided, a simple implementation of exponential
+ * backoff will be utilized.
+ *
+ * @param callable $decider Function that accepts the number of retries,
+ * a request, [response], and [exception] and
+ * returns true if the request is to be retried.
+ * @param callable $delay Function that accepts the number of retries and
+ * returns the number of milliseconds to delay.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function retry(callable $decider, callable $delay = null)
+ {
+ return function (callable $handler) use ($decider, $delay) {
+ return new RetryMiddleware($decider, $handler, $delay);
+ };
+ }
+
+ /**
+ * Middleware that logs requests, responses, and errors using a message
+ * formatter.
+ *
+ * @param LoggerInterface $logger Logs messages.
+ * @param MessageFormatter $formatter Formatter used to create message strings.
+ * @param string $logLevel Level at which to log requests.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
+ {
+ return function (callable $handler) use ($logger, $formatter, $logLevel) {
+ return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
+ return $handler($request, $options)->then(
+ function ($response) use ($logger, $request, $formatter, $logLevel) {
+ $message = $formatter->format($request, $response);
+ $logger->log($logLevel, $message);
+ return $response;
+ },
+ function ($reason) use ($logger, $request, $formatter) {
+ $response = $reason instanceof RequestException
+ ? $reason->getResponse()
+ : null;
+ $message = $formatter->format($request, $response, $reason);
+ $logger->notice($message);
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * This middleware adds a default content-type if possible, a default
+ * content-length or transfer-encoding header, and the expect header.
+ *
+ * @return callable
+ */
+ public static function prepareBody()
+ {
+ return function (callable $handler) {
+ return new PrepareBodyMiddleware($handler);
+ };
+ }
+
+ /**
+ * Middleware that applies a map function to the request before passing to
+ * the next handler.
+ *
+ * @param callable $fn Function that accepts a RequestInterface and returns
+ * a RequestInterface.
+ * @return callable
+ */
+ public static function mapRequest(callable $fn)
+ {
+ return function (callable $handler) use ($fn) {
+ return function ($request, array $options) use ($handler, $fn) {
+ return $handler($fn($request), $options);
+ };
+ };
+ }
+
+ /**
+ * Middleware that applies a map function to the resolved promise's
+ * response.
+ *
+ * @param callable $fn Function that accepts a ResponseInterface and
+ * returns a ResponseInterface.
+ * @return callable
+ */
+ public static function mapResponse(callable $fn)
+ {
+ return function (callable $handler) use ($fn) {
+ return function ($request, array $options) use ($handler, $fn) {
+ return $handler($request, $options)->then($fn);
+ };
+ };
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Pool.php b/Lib/Alisms/GuzzleHttp/Pool.php
new file mode 100644
index 0000000..bc41d6e
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Pool.php
@@ -0,0 +1,123 @@
+sendAsync($rfn, $opts);
+ } elseif (is_callable($rfn)) {
+ yield $rfn($opts);
+ } else {
+ throw new \InvalidArgumentException('Each value yielded by '
+ . 'the iterator must be a Psr7\Http\Message\RequestInterface '
+ . 'or a callable that returns a promise that fulfills '
+ . 'with a Psr7\Message\Http\ResponseInterface object.');
+ }
+ }
+ };
+
+ $this->each = new EachPromise($requests(), $config);
+ }
+
+ public function promise()
+ {
+ return $this->each->promise();
+ }
+
+ /**
+ * Sends multiple requests concurrently and returns an array of responses
+ * and exceptions that uses the same ordering as the provided requests.
+ *
+ * IMPORTANT: This method keeps every request and response in memory, and
+ * as such, is NOT recommended when sending a large number or an
+ * indeterminate number of requests concurrently.
+ *
+ * @param ClientInterface $client Client used to send the requests
+ * @param array|\Iterator $requests Requests to send concurrently.
+ * @param array $options Passes through the options available in
+ * {@see GuzzleHttp\Pool::__construct}
+ *
+ * @return array Returns an array containing the response or an exception
+ * in the same order that the requests were sent.
+ * @throws \InvalidArgumentException if the event format is incorrect.
+ */
+ public static function batch(
+ ClientInterface $client,
+ $requests,
+ array $options = []
+ ) {
+ $res = [];
+ self::cmpCallback($options, 'fulfilled', $res);
+ self::cmpCallback($options, 'rejected', $res);
+ $pool = new static($client, $requests, $options);
+ $pool->promise()->wait();
+ ksort($res);
+
+ return $res;
+ }
+
+ private static function cmpCallback(array &$options, $name, array &$results)
+ {
+ if (!isset($options[$name])) {
+ $options[$name] = function ($v, $k) use (&$results) {
+ $results[$k] = $v;
+ };
+ } else {
+ $currentFn = $options[$name];
+ $options[$name] = function ($v, $k) use (&$results, $currentFn) {
+ $currentFn($v, $k);
+ $results[$k] = $v;
+ };
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/PrepareBodyMiddleware.php b/Lib/Alisms/GuzzleHttp/PrepareBodyMiddleware.php
new file mode 100644
index 0000000..e6d176b
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/PrepareBodyMiddleware.php
@@ -0,0 +1,112 @@
+ true, 'HEAD' => true];
+
+ /**
+ * @param callable $nextHandler Next handler to invoke.
+ */
+ public function __construct(callable $nextHandler)
+ {
+ $this->nextHandler = $nextHandler;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $fn = $this->nextHandler;
+
+ // Don't do anything if the request has no body.
+ if (isset(self::$skipMethods[$request->getMethod()])
+ || $request->getBody()->getSize() === 0
+ ) {
+ return $fn($request, $options);
+ }
+
+ $modify = [];
+
+ // Add a default content-type if possible.
+ if (!$request->hasHeader('Content-Type')) {
+ if ($uri = $request->getBody()->getMetadata('uri')) {
+ if ($type = Psr7\mimetype_from_filename($uri)) {
+ $modify['set_headers']['Content-Type'] = $type;
+ }
+ }
+ }
+
+ // Add a default content-length or transfer-encoding header.
+ if (!isset(self::$skipMethods[$request->getMethod()])
+ && !$request->hasHeader('Content-Length')
+ && !$request->hasHeader('Transfer-Encoding')
+ ) {
+ $size = $request->getBody()->getSize();
+ if ($size !== null) {
+ $modify['set_headers']['Content-Length'] = $size;
+ } else {
+ $modify['set_headers']['Transfer-Encoding'] = 'chunked';
+ }
+ }
+
+ // Add the expect header if needed.
+ $this->addExpectHeader($request, $options, $modify);
+
+ return $fn(Psr7\modify_request($request, $modify), $options);
+ }
+
+ private function addExpectHeader(
+ RequestInterface $request,
+ array $options,
+ array &$modify
+ ) {
+ // Determine if the Expect header should be used
+ if ($request->hasHeader('Expect')) {
+ return;
+ }
+
+ $expect = isset($options['expect']) ? $options['expect'] : null;
+
+ // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
+ if ($expect === false || $request->getProtocolVersion() < 1.1) {
+ return;
+ }
+
+ // The expect header is unconditionally enabled
+ if ($expect === true) {
+ $modify['set_headers']['Expect'] = '100-Continue';
+ return;
+ }
+
+ // By default, send the expect header when the payload is > 1mb
+ if ($expect === null) {
+ $expect = 1048576;
+ }
+
+ // Always add if the body cannot be rewound, the size cannot be
+ // determined, or the size is greater than the cutoff threshold
+ $body = $request->getBody();
+ $size = $body->getSize();
+
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
+ $modify['set_headers']['Expect'] = '100-Continue';
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/AggregateException.php b/Lib/Alisms/GuzzleHttp/Promise/AggregateException.php
new file mode 100644
index 0000000..6a5690c
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/AggregateException.php
@@ -0,0 +1,16 @@
+iterable = iter_for($iterable);
+
+ if (isset($config['concurrency'])) {
+ $this->concurrency = $config['concurrency'];
+ }
+
+ if (isset($config['fulfilled'])) {
+ $this->onFulfilled = $config['fulfilled'];
+ }
+
+ if (isset($config['rejected'])) {
+ $this->onRejected = $config['rejected'];
+ }
+ }
+
+ public function promise()
+ {
+ if ($this->aggregate) {
+ return $this->aggregate;
+ }
+
+ try {
+ $this->createPromise();
+ $this->iterable->rewind();
+ $this->refillPending();
+ } catch (\Exception $e) {
+ $this->aggregate->reject($e);
+ }
+
+ return $this->aggregate;
+ }
+
+ private function createPromise()
+ {
+ $this->aggregate = new Promise(function () {
+ reset($this->pending);
+ // Consume a potentially fluctuating list of promises while
+ // ensuring that indexes are maintained (precluding array_shift).
+ while ($promise = current($this->pending)) {
+ next($this->pending);
+ $promise->wait();
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
+ return;
+ }
+ }
+ });
+
+ // Clear the references when the promise is resolved.
+ $clearFn = function () {
+ $this->iterable = $this->concurrency = $this->pending = null;
+ $this->onFulfilled = $this->onRejected = null;
+ };
+
+ $this->aggregate->then($clearFn, $clearFn);
+ }
+
+ private function refillPending()
+ {
+ if (!$this->concurrency) {
+ // Add all pending promises.
+ while ($this->addPending() && $this->advanceIterator());
+ return;
+ }
+
+ // Add only up to N pending promises.
+ $concurrency = is_callable($this->concurrency)
+ ? call_user_func($this->concurrency, count($this->pending))
+ : $this->concurrency;
+ $concurrency = max($concurrency - count($this->pending), 0);
+ // Concurrency may be set to 0 to disallow new promises.
+ if (!$concurrency) {
+ return;
+ }
+ // Add the first pending promise.
+ $this->addPending();
+ // Note this is special handling for concurrency=1 so that we do
+ // not advance the iterator after adding the first promise. This
+ // helps work around issues with generators that might not have the
+ // next value to yield until promise callbacks are called.
+ while (--$concurrency
+ && $this->advanceIterator()
+ && $this->addPending());
+ }
+
+ private function addPending()
+ {
+ if (!$this->iterable || !$this->iterable->valid()) {
+ return false;
+ }
+
+ $promise = promise_for($this->iterable->current());
+ $idx = $this->iterable->key();
+
+ $this->pending[$idx] = $promise->then(
+ function ($value) use ($idx) {
+ if ($this->onFulfilled) {
+ call_user_func(
+ $this->onFulfilled, $value, $idx, $this->aggregate
+ );
+ }
+ $this->step($idx);
+ },
+ function ($reason) use ($idx) {
+ if ($this->onRejected) {
+ call_user_func(
+ $this->onRejected, $reason, $idx, $this->aggregate
+ );
+ }
+ $this->step($idx);
+ }
+ );
+
+ return true;
+ }
+
+ private function advanceIterator()
+ {
+ try {
+ $this->iterable->next();
+ return true;
+ } catch (\Exception $e) {
+ $this->aggregate->reject($e);
+ return false;
+ }
+ }
+
+ private function step($idx)
+ {
+ // If the promise was already resolved, then ignore this step.
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
+ return;
+ }
+
+ unset($this->pending[$idx]);
+ $this->advanceIterator();
+
+ if (!$this->checkIfFinished()) {
+ // Add more pending promises if possible.
+ $this->refillPending();
+ }
+ }
+
+ private function checkIfFinished()
+ {
+ if (!$this->pending && !$this->iterable->valid()) {
+ // Resolve the promise if there's nothing left to do.
+ $this->aggregate->resolve(null);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/FulfilledPromise.php b/Lib/Alisms/GuzzleHttp/Promise/FulfilledPromise.php
new file mode 100644
index 0000000..5596296
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/FulfilledPromise.php
@@ -0,0 +1,80 @@
+value = $value;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ // Return itself if there is no onFulfilled function.
+ if (!$onFulfilled) {
+ return $this;
+ }
+
+ $queue = queue();
+ $p = new Promise([$queue, 'run']);
+ $value = $this->value;
+ $queue->add(static function () use ($p, $value, $onFulfilled) {
+ if ($p->getState() === self::PENDING) {
+ try {
+ $p->resolve($onFulfilled($value));
+ } catch (\Exception $e) {
+ $p->reject($e);
+ }
+ }
+ });
+
+ return $p;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true, $defaultDelivery = null)
+ {
+ return $unwrap ? $this->value : null;
+ }
+
+ public function getState()
+ {
+ return self::FULFILLED;
+ }
+
+ public function resolve($value)
+ {
+ if ($value !== $this->value) {
+ throw new \LogicException("Cannot resolve a fulfilled promise");
+ }
+ }
+
+ public function reject($reason)
+ {
+ throw new \LogicException("Cannot reject a fulfilled promise");
+ }
+
+ public function cancel()
+ {
+ // pass
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/Promise.php b/Lib/Alisms/GuzzleHttp/Promise/Promise.php
new file mode 100644
index 0000000..c2cf969
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/Promise.php
@@ -0,0 +1,268 @@
+waitFn = $waitFn;
+ $this->cancelFn = $cancelFn;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ if ($this->state === self::PENDING) {
+ $p = new Promise(null, [$this, 'cancel']);
+ $this->handlers[] = [$p, $onFulfilled, $onRejected];
+ $p->waitList = $this->waitList;
+ $p->waitList[] = $this;
+ return $p;
+ }
+
+ // Return a fulfilled promise and immediately invoke any callbacks.
+ if ($this->state === self::FULFILLED) {
+ return $onFulfilled
+ ? promise_for($this->result)->then($onFulfilled)
+ : promise_for($this->result);
+ }
+
+ // It's either cancelled or rejected, so return a rejected promise
+ // and immediately invoke any callbacks.
+ $rejection = rejection_for($this->result);
+ return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true)
+ {
+ $this->waitIfPending();
+
+ if (!$unwrap) {
+ return null;
+ }
+
+ if ($this->result instanceof PromiseInterface) {
+ return $this->result->wait($unwrap);
+ } elseif ($this->state === self::FULFILLED) {
+ return $this->result;
+ } else {
+ // It's rejected so "unwrap" and throw an exception.
+ throw exception_for($this->result);
+ }
+ }
+
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ public function cancel()
+ {
+ if ($this->state !== self::PENDING) {
+ return;
+ }
+
+ $this->waitFn = $this->waitList = null;
+
+ if ($this->cancelFn) {
+ $fn = $this->cancelFn;
+ $this->cancelFn = null;
+ try {
+ $fn();
+ } catch (\Exception $e) {
+ $this->reject($e);
+ }
+ }
+
+ // Reject the promise only if it wasn't rejected in a then callback.
+ if ($this->state === self::PENDING) {
+ $this->reject(new CancellationException('Promise has been cancelled'));
+ }
+ }
+
+ public function resolve($value)
+ {
+ $this->settle(self::FULFILLED, $value);
+ }
+
+ public function reject($reason)
+ {
+ $this->settle(self::REJECTED, $reason);
+ }
+
+ private function settle($state, $value)
+ {
+ if ($this->state !== self::PENDING) {
+ // Ignore calls with the same resolution.
+ if ($state === $this->state && $value === $this->result) {
+ return;
+ }
+ throw $this->state === $state
+ ? new \LogicException("The promise is already {$state}.")
+ : new \LogicException("Cannot change a {$this->state} promise to {$state}");
+ }
+
+ if ($value === $this) {
+ throw new \LogicException('Cannot fulfill or reject a promise with itself');
+ }
+
+ // Clear out the state of the promise but stash the handlers.
+ $this->state = $state;
+ $this->result = $value;
+ $handlers = $this->handlers;
+ $this->handlers = null;
+ $this->waitList = $this->waitFn = null;
+ $this->cancelFn = null;
+
+ if (!$handlers) {
+ return;
+ }
+
+ // If the value was not a settled promise or a thenable, then resolve
+ // it in the task queue using the correct ID.
+ if (!method_exists($value, 'then')) {
+ $id = $state === self::FULFILLED ? 1 : 2;
+ // It's a success, so resolve the handlers in the queue.
+ queue()->add(static function () use ($id, $value, $handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler($id, $value, $handler);
+ }
+ });
+ } elseif ($value instanceof Promise
+ && $value->getState() === self::PENDING
+ ) {
+ // We can just merge our handlers onto the next promise.
+ $value->handlers = array_merge($value->handlers, $handlers);
+ } else {
+ // Resolve the handlers when the forwarded promise is resolved.
+ $value->then(
+ static function ($value) use ($handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler(1, $value, $handler);
+ }
+ },
+ static function ($reason) use ($handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler(2, $reason, $handler);
+ }
+ }
+ );
+ }
+ }
+
+ /**
+ * Call a stack of handlers using a specific callback index and value.
+ *
+ * @param int $index 1 (resolve) or 2 (reject).
+ * @param mixed $value Value to pass to the callback.
+ * @param array $handler Array of handler data (promise and callbacks).
+ *
+ * @return array Returns the next group to resolve.
+ */
+ private static function callHandler($index, $value, array $handler)
+ {
+ /** @var PromiseInterface $promise */
+ $promise = $handler[0];
+
+ // The promise may have been cancelled or resolved before placing
+ // this thunk in the queue.
+ if ($promise->getState() !== self::PENDING) {
+ return;
+ }
+
+ try {
+ if (isset($handler[$index])) {
+ $promise->resolve($handler[$index]($value));
+ } elseif ($index === 1) {
+ // Forward resolution values as-is.
+ $promise->resolve($value);
+ } else {
+ // Forward rejections down the chain.
+ $promise->reject($value);
+ }
+ } catch (\Exception $reason) {
+ $promise->reject($reason);
+ }
+ }
+
+ private function waitIfPending()
+ {
+ if ($this->state !== self::PENDING) {
+ return;
+ } elseif ($this->waitFn) {
+ $this->invokeWaitFn();
+ } elseif ($this->waitList) {
+ $this->invokeWaitList();
+ } else {
+ // If there's not wait function, then reject the promise.
+ $this->reject('Cannot wait on a promise that has '
+ . 'no internal wait function. You must provide a wait '
+ . 'function when constructing the promise to be able to '
+ . 'wait on a promise.');
+ }
+
+ queue()->run();
+
+ if ($this->state === self::PENDING) {
+ $this->reject('Invoking the wait callback did not resolve the promise');
+ }
+ }
+
+ private function invokeWaitFn()
+ {
+ try {
+ $wfn = $this->waitFn;
+ $this->waitFn = null;
+ $wfn(true);
+ } catch (\Exception $reason) {
+ if ($this->state === self::PENDING) {
+ // The promise has not been resolved yet, so reject the promise
+ // with the exception.
+ $this->reject($reason);
+ } else {
+ // The promise was already resolved, so there's a problem in
+ // the application.
+ throw $reason;
+ }
+ }
+ }
+
+ private function invokeWaitList()
+ {
+ $waitList = $this->waitList;
+ $this->waitList = null;
+
+ foreach ($waitList as $result) {
+ descend:
+ $result->waitIfPending();
+ if ($result->result instanceof Promise) {
+ $result = $result->result;
+ goto descend;
+ }
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/PromiseInterface.php b/Lib/Alisms/GuzzleHttp/Promise/PromiseInterface.php
new file mode 100644
index 0000000..8f5f4b9
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/PromiseInterface.php
@@ -0,0 +1,93 @@
+reason = $reason;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ // If there's no onRejected callback then just return self.
+ if (!$onRejected) {
+ return $this;
+ }
+
+ $queue = queue();
+ $reason = $this->reason;
+ $p = new Promise([$queue, 'run']);
+ $queue->add(static function () use ($p, $reason, $onRejected) {
+ if ($p->getState() === self::PENDING) {
+ try {
+ // Return a resolved promise if onRejected does not throw.
+ $p->resolve($onRejected($reason));
+ } catch (\Exception $e) {
+ // onRejected threw, so return a rejected promise.
+ $p->reject($e);
+ }
+ }
+ });
+
+ return $p;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true, $defaultDelivery = null)
+ {
+ if ($unwrap) {
+ throw exception_for($this->reason);
+ }
+ }
+
+ public function getState()
+ {
+ return self::REJECTED;
+ }
+
+ public function resolve($value)
+ {
+ throw new \LogicException("Cannot resolve a rejected promise");
+ }
+
+ public function reject($reason)
+ {
+ if ($reason !== $this->reason) {
+ throw new \LogicException("Cannot reject a rejected promise");
+ }
+ }
+
+ public function cancel()
+ {
+ // pass
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/RejectionException.php b/Lib/Alisms/GuzzleHttp/Promise/RejectionException.php
new file mode 100644
index 0000000..07c1136
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/RejectionException.php
@@ -0,0 +1,47 @@
+reason = $reason;
+
+ $message = 'The promise was rejected';
+
+ if ($description) {
+ $message .= ' with reason: ' . $description;
+ } elseif (is_string($reason)
+ || (is_object($reason) && method_exists($reason, '__toString'))
+ ) {
+ $message .= ' with reason: ' . $this->reason;
+ } elseif ($reason instanceof \JsonSerializable) {
+ $message .= ' with reason: '
+ . json_encode($this->reason, JSON_PRETTY_PRINT);
+ }
+
+ parent::__construct($message);
+ }
+
+ /**
+ * Returns the rejection reason.
+ *
+ * @return mixed
+ */
+ public function getReason()
+ {
+ return $this->reason;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/TaskQueue.php b/Lib/Alisms/GuzzleHttp/Promise/TaskQueue.php
new file mode 100644
index 0000000..5026363
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/TaskQueue.php
@@ -0,0 +1,79 @@
+run();
+ */
+class TaskQueue
+{
+ private $enableShutdown = true;
+ private $queue = [];
+
+ public function __construct($withShutdown = true)
+ {
+ if ($withShutdown) {
+ register_shutdown_function(function () {
+ if ($this->enableShutdown) {
+ // Only run the tasks if an E_ERROR didn't occur.
+ $err = error_get_last();
+ if (!$err || ($err['type'] ^ E_ERROR)) {
+ $this->run();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns true if the queue is empty.
+ *
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return !$this->queue;
+ }
+
+ /**
+ * Adds a task to the queue that will be executed the next time run is
+ * called.
+ *
+ * @param callable $task
+ */
+ public function add(callable $task)
+ {
+ $this->queue[] = $task;
+ }
+
+ /**
+ * Execute all of the pending task in the queue.
+ */
+ public function run()
+ {
+ while ($task = array_shift($this->queue)) {
+ $task();
+ }
+ }
+
+ /**
+ * The task queue will be run and exhausted by default when the process
+ * exits IFF the exit is not the result of a PHP E_ERROR error.
+ *
+ * You can disable running the automatic shutdown of the queue by calling
+ * this function. If you disable the task queue shutdown process, then you
+ * MUST either run the task queue (as a result of running your event loop
+ * or manually using the run() method) or wait on each outstanding promise.
+ *
+ * Note: This shutdown will occur before any destructors are triggered.
+ */
+ public function disableShutdown()
+ {
+ $this->enableShutdown = false;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/functions.php b/Lib/Alisms/GuzzleHttp/Promise/functions.php
new file mode 100644
index 0000000..89c6569
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/functions.php
@@ -0,0 +1,495 @@
+
+ * while ($eventLoop->isRunning()) {
+ * GuzzleHttp\Promise\queue()->run();
+ * }
+ *
+ *
+ * @return TaskQueue
+ */
+function queue()
+{
+ static $queue;
+
+ if (!$queue) {
+ $queue = new TaskQueue();
+ }
+
+ return $queue;
+}
+
+/**
+ * Adds a function to run in the task queue when it is next `run()` and returns
+ * a promise that is fulfilled or rejected with the result.
+ *
+ * @param callable $task Task function to run.
+ *
+ * @return PromiseInterface
+ */
+function task(callable $task)
+{
+ $queue = queue();
+ $promise = new Promise([$queue, 'run']);
+ $queue->add(function () use ($task, $promise) {
+ try {
+ $promise->resolve($task());
+ } catch (\Exception $e) {
+ $promise->reject($e);
+ }
+ });
+
+ return $promise;
+}
+
+/**
+ * Creates a promise for a value if the value is not a promise.
+ *
+ * @param mixed $value Promise or value.
+ *
+ * @return PromiseInterface
+ */
+function promise_for($value)
+{
+ if ($value instanceof PromiseInterface) {
+ return $value;
+ }
+
+ // Return a Guzzle promise that shadows the given promise.
+ if (method_exists($value, 'then')) {
+ $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
+ $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
+ $promise = new Promise($wfn, $cfn);
+ $value->then([$promise, 'resolve'], [$promise, 'reject']);
+ return $promise;
+ }
+
+ return new FulfilledPromise($value);
+}
+
+/**
+ * Creates a rejected promise for a reason if the reason is not a promise. If
+ * the provided reason is a promise, then it is returned as-is.
+ *
+ * @param mixed $reason Promise or reason.
+ *
+ * @return PromiseInterface
+ */
+function rejection_for($reason)
+{
+ if ($reason instanceof PromiseInterface) {
+ return $reason;
+ }
+
+ return new RejectedPromise($reason);
+}
+
+/**
+ * Create an exception for a rejected promise value.
+ *
+ * @param mixed $reason
+ *
+ * @return \Exception
+ */
+function exception_for($reason)
+{
+ return $reason instanceof \Exception
+ ? $reason
+ : new RejectionException($reason);
+}
+
+/**
+ * Returns an iterator for the given value.
+ *
+ * @param mixed $value
+ *
+ * @return \Iterator
+ */
+function iter_for($value)
+{
+ if ($value instanceof \Iterator) {
+ return $value;
+ } elseif (is_array($value)) {
+ return new \ArrayIterator($value);
+ } else {
+ return new \ArrayIterator([$value]);
+ }
+}
+
+/**
+ * Synchronously waits on a promise to resolve and returns an inspection state
+ * array.
+ *
+ * Returns a state associative array containing a "state" key mapping to a
+ * valid promise state. If the state of the promise is "fulfilled", the array
+ * will contain a "value" key mapping to the fulfilled value of the promise. If
+ * the promise is rejected, the array will contain a "reason" key mapping to
+ * the rejection reason of the promise.
+ *
+ * @param PromiseInterface $promise Promise or value.
+ *
+ * @return array
+ */
+function inspect(PromiseInterface $promise)
+{
+ try {
+ return [
+ 'state' => PromiseInterface::FULFILLED,
+ 'value' => $promise->wait()
+ ];
+ } catch (RejectionException $e) {
+ return ['state' => 'rejected', 'reason' => $e->getReason()];
+ } catch (\Exception $e) {
+ return ['state' => 'rejected', 'reason' => $e];
+ }
+}
+
+/**
+ * Waits on all of the provided promises, but does not unwrap rejected promises
+ * as thrown exception.
+ *
+ * Returns an array of inspection state arrays.
+ *
+ * @param PromiseInterface[] $promises Traversable of promises to wait upon.
+ *
+ * @return array
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
+ */
+function inspect_all($promises)
+{
+ $results = [];
+ foreach ($promises as $key => $promise) {
+ $results[$key] = inspect($promise);
+ }
+
+ return $results;
+}
+
+/**
+ * Waits on all of the provided promises and returns the fulfilled values.
+ *
+ * Returns an array that contains the value of each promise (in the same order
+ * the promises were provided). An exception is thrown if any of the promises
+ * are rejected.
+ *
+ * @param mixed $promises Iterable of PromiseInterface objects to wait on.
+ *
+ * @return array
+ * @throws \Exception on error
+ */
+function unwrap($promises)
+{
+ $results = [];
+ foreach ($promises as $key => $promise) {
+ $results[$key] = $promise->wait();
+ }
+
+ return $results;
+}
+
+/**
+ * Given an array of promises, return a promise that is fulfilled when all the
+ * items in the array are fulfilled.
+ *
+ * The promise's fulfillment value is an array with fulfillment values at
+ * respective positions to the original array. If any promise in the array
+ * rejects, the returned promise is rejected with the rejection reason.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return Promise
+ */
+function all($promises)
+{
+ $results = [];
+ return each(
+ $promises,
+ function ($value, $idx) use (&$results) {
+ $results[$idx] = $value;
+ },
+ function ($reason, $idx, Promise $aggregate) {
+ $aggregate->reject($reason);
+ }
+ )->then(function () use (&$results) {
+ ksort($results);
+ return $results;
+ });
+}
+
+/**
+ * Initiate a competitive race between multiple promises or values (values will
+ * become immediately fulfilled promises).
+ *
+ * When count amount of promises have been fulfilled, the returned promise is
+ * fulfilled with an array that contains the fulfillment values of the winners
+ * in order of resolution.
+ *
+ * This prommise is rejected with a {@see GuzzleHttp\Promise\AggregateException}
+ * if the number of fulfilled promises is less than the desired $count.
+ *
+ * @param int $count Total number of promises.
+ * @param mixed $promises Promises or values.
+ *
+ * @return Promise
+ */
+function some($count, $promises)
+{
+ $results = [];
+ $rejections = [];
+
+ return each(
+ $promises,
+ function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
+ if ($p->getState() !== PromiseInterface::PENDING) {
+ return;
+ }
+ $results[$idx] = $value;
+ if (count($results) >= $count) {
+ $p->resolve(null);
+ }
+ },
+ function ($reason) use (&$rejections) {
+ $rejections[] = $reason;
+ }
+ )->then(
+ function () use (&$results, &$rejections, $count) {
+ if (count($results) !== $count) {
+ throw new AggregateException(
+ 'Not enough promises to fulfill count',
+ $rejections
+ );
+ }
+ ksort($results);
+ return array_values($results);
+ }
+ );
+}
+
+/**
+ * Like some(), with 1 as count. However, if the promise fulfills, the
+ * fulfillment value is not an array of 1 but the value directly.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+function any($promises)
+{
+ return some(1, $promises)->then(function ($values) { return $values[0]; });
+}
+
+/**
+ * Returns a promise that is fulfilled when all of the provided promises have
+ * been fulfilled or rejected.
+ *
+ * The returned promise is fulfilled with an array of inspection state arrays.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return Promise
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
+ */
+function settle($promises)
+{
+ $results = [];
+
+ return each(
+ $promises,
+ function ($value, $idx) use (&$results) {
+ $results[$idx] = ['state' => 'fulfilled', 'value' => $value];
+ },
+ function ($reason, $idx) use (&$results) {
+ $results[$idx] = ['state' => 'rejected', 'reason' => $reason];
+ }
+ )->then(function () use (&$results) {
+ ksort($results);
+ return $results;
+ });
+}
+
+/**
+ * Given an iterator that yields promises or values, returns a promise that is
+ * fulfilled with a null value when the iterator has been consumed or the
+ * aggregate promise has been fulfilled or rejected.
+ *
+ * $onFulfilled is a function that accepts the fulfilled value, iterator
+ * index, and the aggregate promise. The callback can invoke any necessary side
+ * effects and choose to resolve or reject the aggregate promise if needed.
+ *
+ * $onRejected is a function that accepts the rejection reason, iterator
+ * index, and the aggregate promise. The callback can invoke any necessary side
+ * effects and choose to resolve or reject the aggregate promise if needed.
+ *
+ * @param mixed $iterable Iterator or array to iterate over.
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return Promise
+ */
+function each(
+ $iterable,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+) {
+ return (new EachPromise($iterable, [
+ 'fulfilled' => $onFulfilled,
+ 'rejected' => $onRejected
+ ]))->promise();
+}
+
+/**
+ * Like each, but only allows a certain number of outstanding promises at any
+ * given time.
+ *
+ * $concurrency may be an integer or a function that accepts the number of
+ * pending promises and returns a numeric concurrency limit value to allow for
+ * dynamic a concurrency size.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return mixed
+ */
+function each_limit(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+) {
+ return (new EachPromise($iterable, [
+ 'fulfilled' => $onFulfilled,
+ 'rejected' => $onRejected,
+ 'concurrency' => $concurrency
+ ]))->promise();
+}
+
+/**
+ * Like each_limit, but ensures that no promise in the given $iterable argument
+ * is rejected. If any promise is rejected, then the aggregate promise is
+ * rejected with the encountered rejection.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ *
+ * @return mixed
+ */
+function each_limit_all(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null
+) {
+ return each_limit(
+ $iterable,
+ $concurrency,
+ $onFulfilled,
+ function ($reason, $idx, PromiseInterface $aggregate) {
+ $aggregate->reject($reason);
+ }
+ );
+}
+
+/**
+ * Returns true if a promise is fulfilled.
+ *
+ * @param PromiseInterface $promise
+ *
+ * @return bool
+ */
+function is_fulfilled(PromiseInterface $promise)
+{
+ return $promise->getState() === PromiseInterface::FULFILLED;
+}
+
+/**
+ * Returns true if a promise is rejected.
+ *
+ * @param PromiseInterface $promise
+ *
+ * @return bool
+ */
+function is_rejected(PromiseInterface $promise)
+{
+ return $promise->getState() === PromiseInterface::REJECTED;
+}
+
+/**
+ * Returns true if a promise is fulfilled or rejected.
+ *
+ * @param PromiseInterface $promise
+ *
+ * @return bool
+ */
+function is_settled(PromiseInterface $promise)
+{
+ return $promise->getState() !== PromiseInterface::PENDING;
+}
+
+/**
+ * Creates a promise that is resolved using a generator that yields values or
+ * promises (somewhat similar to C#'s async keyword).
+ *
+ * When called, the coroutine function will start an instance of the generator
+ * and returns a promise that is fulfilled with its final yielded value.
+ *
+ * Control is returned back to the generator when the yielded promise settles.
+ * This can lead to less verbose code when doing lots of sequential async calls
+ * with minimal processing in between.
+ *
+ * use GuzzleHttp\Promise;
+ *
+ * function createPromise($value) {
+ * return new Promise\FulfilledPromise($value);
+ * }
+ *
+ * $promise = Promise\coroutine(function () {
+ * $value = (yield createPromise('a'));
+ * try {
+ * $value = (yield createPromise($value . 'b'));
+ * } catch (\Exception $e) {
+ * // The promise was rejected.
+ * }
+ * yield $value . 'c';
+ * });
+ *
+ * // Outputs "abc"
+ * $promise->then(function ($v) { echo $v; });
+ *
+ * @param callable $generatorFn Generator function to wrap into a promise.
+ *
+ * @return Promise
+ * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
+ */
+function coroutine(callable $generatorFn)
+{
+ $generator = $generatorFn();
+ return __next_coroutine($generator->current(), $generator)->then();
+}
+
+/** @internal */
+function __next_coroutine($yielded, \Generator $generator)
+{
+ return promise_for($yielded)->then(
+ function ($value) use ($generator) {
+ $nextYield = $generator->send($value);
+ return $generator->valid()
+ ? __next_coroutine($nextYield, $generator)
+ : $value;
+ },
+ function ($reason) use ($generator) {
+ $nextYield = $generator->throw(exception_for($reason));
+ // The throw was caught, so keep iterating on the coroutine
+ return __next_coroutine($nextYield, $generator);
+ }
+ );
+}
diff --git a/Lib/Alisms/GuzzleHttp/Promise/functions_include.php b/Lib/Alisms/GuzzleHttp/Promise/functions_include.php
new file mode 100644
index 0000000..34cd171
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Promise/functions_include.php
@@ -0,0 +1,6 @@
+addStream($stream);
+ }
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->rewind();
+ return $this->getContents();
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ /**
+ * Add a stream to the AppendStream
+ *
+ * @param StreamInterface $stream Stream to append. Must be readable.
+ *
+ * @throws \InvalidArgumentException if the stream is not readable
+ */
+ public function addStream(StreamInterface $stream)
+ {
+ if (!$stream->isReadable()) {
+ throw new \InvalidArgumentException('Each stream must be readable');
+ }
+
+ // The stream is only seekable if all streams are seekable
+ if (!$stream->isSeekable()) {
+ $this->seekable = false;
+ }
+
+ $this->streams[] = $stream;
+ }
+
+ public function getContents()
+ {
+ return copy_to_string($this);
+ }
+
+ /**
+ * Closes each attached stream.
+ *
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->pos = $this->current = 0;
+
+ foreach ($this->streams as $stream) {
+ $stream->close();
+ }
+
+ $this->streams = [];
+ }
+
+ /**
+ * Detaches each attached stream
+ *
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ $this->close();
+ $this->detached = true;
+ }
+
+ public function tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Tries to calculate the size by adding the size of each stream.
+ *
+ * If any of the streams do not return a valid number, then the size of the
+ * append stream cannot be determined and null is returned.
+ *
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ $size = 0;
+
+ foreach ($this->streams as $stream) {
+ $s = $stream->getSize();
+ if ($s === null) {
+ return null;
+ }
+ $size += $s;
+ }
+
+ return $size;
+ }
+
+ public function eof()
+ {
+ return !$this->streams ||
+ ($this->current >= count($this->streams) - 1 &&
+ $this->streams[$this->current]->eof());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ /**
+ * Attempts to seek to the given position. Only supports SEEK_SET.
+ *
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('This AppendStream is not seekable');
+ } elseif ($whence !== SEEK_SET) {
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
+ }
+
+ $this->pos = $this->current = 0;
+
+ // Rewind each stream
+ foreach ($this->streams as $i => $stream) {
+ try {
+ $stream->rewind();
+ } catch (\Exception $e) {
+ throw new \RuntimeException('Unable to seek stream '
+ . $i . ' of the AppendStream', 0, $e);
+ }
+ }
+
+ // Seek to the actual position by reading from each stream
+ while ($this->pos < $offset && !$this->eof()) {
+ $result = $this->read(min(8096, $offset - $this->pos));
+ if ($result === '') {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads from all of the appended streams until the length is met or EOF.
+ *
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ $buffer = '';
+ $total = count($this->streams) - 1;
+ $remaining = $length;
+ $progressToNext = false;
+
+ while ($remaining > 0) {
+
+ // Progress to the next stream if needed.
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
+ $progressToNext = false;
+ if ($this->current === $total) {
+ break;
+ }
+ $this->current++;
+ }
+
+ $result = $this->streams[$this->current]->read($remaining);
+
+ // Using a loose comparison here to match on '', false, and null
+ if ($result == null) {
+ $progressToNext = true;
+ continue;
+ }
+
+ $buffer .= $result;
+ $remaining = $length - strlen($buffer);
+ }
+
+ $this->pos += strlen($buffer);
+
+ return $buffer;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to an AppendStream');
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $key ? null : [];
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/BufferStream.php b/Lib/Alisms/GuzzleHttp/Psr7/BufferStream.php
new file mode 100644
index 0000000..af4d4c2
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/BufferStream.php
@@ -0,0 +1,137 @@
+hwm = $hwm;
+ }
+
+ public function __toString()
+ {
+ return $this->getContents();
+ }
+
+ public function getContents()
+ {
+ $buffer = $this->buffer;
+ $this->buffer = '';
+
+ return $buffer;
+ }
+
+ public function close()
+ {
+ $this->buffer = '';
+ }
+
+ public function detach()
+ {
+ $this->close();
+ }
+
+ public function getSize()
+ {
+ return strlen($this->buffer);
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return true;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a BufferStream');
+ }
+
+ public function eof()
+ {
+ return strlen($this->buffer) === 0;
+ }
+
+ public function tell()
+ {
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
+ }
+
+ /**
+ * Reads data from the buffer.
+ */
+ public function read($length)
+ {
+ $currentLength = strlen($this->buffer);
+
+ if ($length >= $currentLength) {
+ // No need to slice the buffer because we don't have enough data.
+ $result = $this->buffer;
+ $this->buffer = '';
+ } else {
+ // Slice up the result to provide a subset of the buffer.
+ $result = substr($this->buffer, 0, $length);
+ $this->buffer = substr($this->buffer, $length);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Writes data to the buffer.
+ */
+ public function write($string)
+ {
+ $this->buffer .= $string;
+
+ // TODO: What should happen here?
+ if (strlen($this->buffer) >= $this->hwm) {
+ return false;
+ }
+
+ return strlen($string);
+ }
+
+ public function getMetadata($key = null)
+ {
+ if ($key == 'hwm') {
+ return $this->hwm;
+ }
+
+ return $key ? null : [];
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/CachingStream.php b/Lib/Alisms/GuzzleHttp/Psr7/CachingStream.php
new file mode 100644
index 0000000..796d581
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/CachingStream.php
@@ -0,0 +1,136 @@
+remoteStream = $stream;
+ $this->stream = $target ?: new Stream(fopen('php://temp', 'r+'));
+ }
+
+ public function getSize()
+ {
+ return max($this->stream->getSize(), $this->remoteStream->getSize());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence == SEEK_SET) {
+ $byte = $offset;
+ } elseif ($whence == SEEK_CUR) {
+ $byte = $offset + $this->tell();
+ } elseif ($whence == SEEK_END) {
+ $size = $this->remoteStream->getSize();
+ if ($size === null) {
+ $size = $this->cacheEntireStream();
+ }
+ // Because 0 is the first byte, we seek to size - 1.
+ $byte = $size - 1 - $offset;
+ } else {
+ throw new \InvalidArgumentException('Invalid whence');
+ }
+
+ $diff = $byte - $this->stream->getSize();
+
+ if ($diff > 0) {
+ // If the seek byte is greater the number of read bytes, then read
+ // the difference of bytes to cache the bytes and inherently seek.
+ $this->read($diff);
+ } else {
+ // We can just do a normal seek since we've already seen this byte.
+ $this->stream->seek($byte);
+ }
+ }
+
+ public function read($length)
+ {
+ // Perform a regular read on any previously read data from the buffer
+ $data = $this->stream->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->stream->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->tell()) - $this->remoteStream->tell();
+ if ($overflow > 0) {
+ $this->skipReadBytes += $overflow;
+ }
+
+ return $this->stream->write($string);
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof() && $this->remoteStream->eof();
+ }
+
+ /**
+ * Close both the remote stream and buffer stream
+ */
+ public function close()
+ {
+ $this->remoteStream->close() && $this->stream->close();
+ }
+
+ private function cacheEntireStream()
+ {
+ $target = new FnStream(['write' => 'strlen']);
+ copy_to_stream($this, $target);
+
+ return $this->tell();
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/DroppingStream.php b/Lib/Alisms/GuzzleHttp/Psr7/DroppingStream.php
new file mode 100644
index 0000000..8935c80
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/DroppingStream.php
@@ -0,0 +1,42 @@
+stream = $stream;
+ $this->maxLength = $maxLength;
+ }
+
+ public function write($string)
+ {
+ $diff = $this->maxLength - $this->stream->getSize();
+
+ // Begin returning 0 when the underlying stream is too large.
+ if ($diff <= 0) {
+ return 0;
+ }
+
+ // Write the stream or a subset of the stream if needed.
+ if (strlen($string) < $diff) {
+ return $this->stream->write($string);
+ }
+
+ return $this->stream->write(substr($string, 0, $diff));
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/FnStream.php b/Lib/Alisms/GuzzleHttp/Psr7/FnStream.php
new file mode 100644
index 0000000..cc9b445
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/FnStream.php
@@ -0,0 +1,149 @@
+methods = $methods;
+
+ // Create the functions on the class
+ foreach ($methods as $name => $fn) {
+ $this->{'_fn_' . $name} = $fn;
+ }
+ }
+
+ /**
+ * Lazily determine which methods are not implemented.
+ * @throws \BadMethodCallException
+ */
+ public function __get($name)
+ {
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
+ . '() is not implemented in the FnStream');
+ }
+
+ /**
+ * The close method is called on the underlying stream only if possible.
+ */
+ public function __destruct()
+ {
+ if (isset($this->_fn_close)) {
+ call_user_func($this->_fn_close);
+ }
+ }
+
+ /**
+ * Adds custom functionality to an underlying stream by intercepting
+ * specific method calls.
+ *
+ * @param StreamInterface $stream Stream to decorate
+ * @param array $methods Hash of method name to a closure
+ *
+ * @return FnStream
+ */
+ public static function decorate(StreamInterface $stream, array $methods)
+ {
+ // If any of the required methods were not provided, then simply
+ // proxy to the decorated stream.
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
+ $methods[$diff] = [$stream, $diff];
+ }
+
+ return new self($methods);
+ }
+
+ public function __toString()
+ {
+ return call_user_func($this->_fn___toString);
+ }
+
+ public function close()
+ {
+ return call_user_func($this->_fn_close);
+ }
+
+ public function detach()
+ {
+ return call_user_func($this->_fn_detach);
+ }
+
+ public function getSize()
+ {
+ return call_user_func($this->_fn_getSize);
+ }
+
+ public function tell()
+ {
+ return call_user_func($this->_fn_tell);
+ }
+
+ public function eof()
+ {
+ return call_user_func($this->_fn_eof);
+ }
+
+ public function isSeekable()
+ {
+ return call_user_func($this->_fn_isSeekable);
+ }
+
+ public function rewind()
+ {
+ call_user_func($this->_fn_rewind);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ call_user_func($this->_fn_seek, $offset, $whence);
+ }
+
+ public function isWritable()
+ {
+ return call_user_func($this->_fn_isWritable);
+ }
+
+ public function write($string)
+ {
+ return call_user_func($this->_fn_write, $string);
+ }
+
+ public function isReadable()
+ {
+ return call_user_func($this->_fn_isReadable);
+ }
+
+ public function read($length)
+ {
+ return call_user_func($this->_fn_read, $length);
+ }
+
+ public function getContents()
+ {
+ return call_user_func($this->_fn_getContents);
+ }
+
+ public function getMetadata($key = null)
+ {
+ return call_user_func($this->_fn_getMetadata, $key);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/InflateStream.php b/Lib/Alisms/GuzzleHttp/Psr7/InflateStream.php
new file mode 100644
index 0000000..2c8628b
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/InflateStream.php
@@ -0,0 +1,29 @@
+stream = new Stream($resource);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/LazyOpenStream.php b/Lib/Alisms/GuzzleHttp/Psr7/LazyOpenStream.php
new file mode 100644
index 0000000..02cec3a
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/LazyOpenStream.php
@@ -0,0 +1,39 @@
+filename = $filename;
+ $this->mode = $mode;
+ }
+
+ /**
+ * Creates the underlying stream lazily when required.
+ *
+ * @return StreamInterface
+ */
+ protected function createStream()
+ {
+ return stream_for(try_fopen($this->filename, $this->mode));
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/LimitStream.php b/Lib/Alisms/GuzzleHttp/Psr7/LimitStream.php
new file mode 100644
index 0000000..7f2298b
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/LimitStream.php
@@ -0,0 +1,155 @@
+stream = $stream;
+ $this->setLimit($limit);
+ $this->setOffset($offset);
+ }
+
+ public function eof()
+ {
+ // Always return true if the underlying stream is EOF
+ if ($this->stream->eof()) {
+ return true;
+ }
+
+ // No limit and the underlying stream is not at EOF
+ if ($this->limit == -1) {
+ return false;
+ }
+
+ return $this->stream->tell() >= $this->offset + $this->limit;
+ }
+
+ /**
+ * Returns the size of the limited subset of data
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ if (null === ($length = $this->stream->getSize())) {
+ return null;
+ } elseif ($this->limit == -1) {
+ return $length - $this->offset;
+ } else {
+ return min($this->limit, $length - $this->offset);
+ }
+ }
+
+ /**
+ * Allow for a bounded seek on the read limited stream
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence !== SEEK_SET || $offset < 0) {
+ throw new \RuntimeException(sprintf(
+ 'Cannot seek to offset % with whence %s',
+ $offset,
+ $whence
+ ));
+ }
+
+ $offset += $this->offset;
+
+ if ($this->limit !== -1) {
+ if ($offset > $this->offset + $this->limit) {
+ $offset = $this->offset + $this->limit;
+ }
+ }
+
+ $this->stream->seek($offset);
+ }
+
+ /**
+ * Give a relative tell()
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ return $this->stream->tell() - $this->offset;
+ }
+
+ /**
+ * Set the offset to start limiting from
+ *
+ * @param int $offset Offset to seek to and begin byte limiting from
+ *
+ * @throws \RuntimeException if the stream cannot be seeked.
+ */
+ public function setOffset($offset)
+ {
+ $current = $this->stream->tell();
+
+ if ($current !== $offset) {
+ // If the stream cannot seek to the offset position, then read to it
+ if ($this->stream->isSeekable()) {
+ $this->stream->seek($offset);
+ } elseif ($current > $offset) {
+ throw new \RuntimeException("Could not seek to stream offset $offset");
+ } else {
+ $this->stream->read($offset - $current);
+ }
+ }
+
+ $this->offset = $offset;
+ }
+
+ /**
+ * Set the limit of bytes that the decorator allows to be read from the
+ * stream.
+ *
+ * @param int $limit Number of bytes to allow to be read from the stream.
+ * Use -1 for no limit.
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ public function read($length)
+ {
+ if ($this->limit == -1) {
+ return $this->stream->read($length);
+ }
+
+ // Check if the current position is less than the total allowed
+ // bytes + original offset
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
+ if ($remaining > 0) {
+ // Only return the amount of requested data, ensuring that the byte
+ // limit is not exceeded
+ return $this->stream->read(min($remaining, $length));
+ }
+
+ return '';
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/MessageTrait.php b/Lib/Alisms/GuzzleHttp/Psr7/MessageTrait.php
new file mode 100644
index 0000000..123205c
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/MessageTrait.php
@@ -0,0 +1,158 @@
+protocol;
+ }
+
+ public function withProtocolVersion($version)
+ {
+ if ($this->protocol === $version) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->protocol = $version;
+ return $new;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headerLines;
+ }
+
+ public function hasHeader($header)
+ {
+ return isset($this->headers[strtolower($header)]);
+ }
+
+ public function getHeader($header)
+ {
+ $name = strtolower($header);
+ return isset($this->headers[$name]) ? $this->headers[$name] : [];
+ }
+
+ public function getHeaderLine($header)
+ {
+ return implode(', ', $this->getHeader($header));
+ }
+
+ public function withHeader($header, $value)
+ {
+ $new = clone $this;
+ $header = trim($header);
+ $name = strtolower($header);
+
+ if (!is_array($value)) {
+ $new->headers[$name] = [trim($value)];
+ } else {
+ $new->headers[$name] = $value;
+ foreach ($new->headers[$name] as &$v) {
+ $v = trim($v);
+ }
+ }
+
+ // Remove the header lines.
+ foreach (array_keys($new->headerLines) as $key) {
+ if (strtolower($key) === $name) {
+ unset($new->headerLines[$key]);
+ }
+ }
+
+ // Add the header line.
+ $new->headerLines[$header] = $new->headers[$name];
+
+ return $new;
+ }
+
+ public function withAddedHeader($header, $value)
+ {
+ if (!$this->hasHeader($header)) {
+ return $this->withHeader($header, $value);
+ }
+
+ $new = clone $this;
+ $new->headers[strtolower($header)][] = $value;
+ $new->headerLines[$header][] = $value;
+ return $new;
+ }
+
+ public function withoutHeader($header)
+ {
+ if (!$this->hasHeader($header)) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $name = strtolower($header);
+ unset($new->headers[$name]);
+
+ foreach (array_keys($new->headerLines) as $key) {
+ if (strtolower($key) === $name) {
+ unset($new->headerLines[$key]);
+ }
+ }
+
+ return $new;
+ }
+
+ public function getBody()
+ {
+ if (!$this->stream) {
+ $this->stream = stream_for('');
+ }
+
+ return $this->stream;
+ }
+
+ public function withBody(StreamInterface $body)
+ {
+ if ($body === $this->stream) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->stream = $body;
+ return $new;
+ }
+
+ private function setHeaders(array $headers)
+ {
+ $this->headerLines = $this->headers = [];
+ foreach ($headers as $header => $value) {
+ $header = trim($header);
+ $name = strtolower($header);
+ if (!is_array($value)) {
+ $value = trim($value);
+ $this->headers[$name][] = $value;
+ $this->headerLines[$header][] = $value;
+ } else {
+ foreach ($value as $v) {
+ $v = trim($v);
+ $this->headers[$name][] = $v;
+ $this->headerLines[$header][] = $v;
+ }
+ }
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/MultipartStream.php b/Lib/Alisms/GuzzleHttp/Psr7/MultipartStream.php
new file mode 100644
index 0000000..fd006ec
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/MultipartStream.php
@@ -0,0 +1,153 @@
+boundary = $boundary ?: uniqid();
+ $this->stream = $this->createStream($elements);
+ }
+
+ /**
+ * Get the boundary
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ return $this->boundary;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * Get the headers needed before transferring the content of a POST file
+ */
+ private function getHeaders(array $headers)
+ {
+ $str = '';
+ foreach ($headers as $key => $value) {
+ $str .= "{$key}: {$value}\r\n";
+ }
+
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
+ }
+
+ /**
+ * Create the aggregate stream that will be used to upload the POST data
+ */
+ protected function createStream(array $elements)
+ {
+ $stream = new AppendStream();
+
+ foreach ($elements as $element) {
+ $this->addElement($stream, $element);
+ }
+
+ // Add the trailing boundary with CRLF
+ $stream->addStream(stream_for("--{$this->boundary}--\r\n"));
+
+ return $stream;
+ }
+
+ private function addElement(AppendStream $stream, array $element)
+ {
+ foreach (['contents', 'name'] as $key) {
+ if (!array_key_exists($key, $element)) {
+ throw new \InvalidArgumentException("A '{$key}' key is required");
+ }
+ }
+
+ $element['contents'] = stream_for($element['contents']);
+
+ if (empty($element['filename'])) {
+ $uri = $element['contents']->getMetadata('uri');
+ if (substr($uri, 0, 6) !== 'php://') {
+ $element['filename'] = $uri;
+ }
+ }
+
+ list($body, $headers) = $this->createElement(
+ $element['name'],
+ $element['contents'],
+ isset($element['filename']) ? $element['filename'] : null,
+ isset($element['headers']) ? $element['headers'] : []
+ );
+
+ $stream->addStream(stream_for($this->getHeaders($headers)));
+ $stream->addStream($body);
+ $stream->addStream(stream_for("\r\n"));
+ }
+
+ /**
+ * @return array
+ */
+ private function createElement($name, $stream, $filename, array $headers)
+ {
+ // Set a default content-disposition header if one was no provided
+ $disposition = $this->getHeader($headers, 'content-disposition');
+ if (!$disposition) {
+ $headers['Content-Disposition'] = $filename
+ ? sprintf('form-data; name="%s"; filename="%s"',
+ $name,
+ basename($filename))
+ : "form-data; name=\"{$name}\"";
+ }
+
+ // Set a default content-length header if one was no provided
+ $length = $this->getHeader($headers, 'content-length');
+ if (!$length) {
+ if ($length = $stream->getSize()) {
+ $headers['Content-Length'] = (string) $length;
+ }
+ }
+
+ // Set a default Content-Type if one was not supplied
+ $type = $this->getHeader($headers, 'content-type');
+ if (!$type && $filename) {
+ if ($type = mimetype_from_filename($filename)) {
+ $headers['Content-Type'] = $type;
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ private function getHeader(array $headers, $key)
+ {
+ $lowercaseHeader = strtolower($key);
+ foreach ($headers as $k => $v) {
+ if (strtolower($k) === $lowercaseHeader) {
+ return $v;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/NoSeekStream.php b/Lib/Alisms/GuzzleHttp/Psr7/NoSeekStream.php
new file mode 100644
index 0000000..2332218
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/NoSeekStream.php
@@ -0,0 +1,22 @@
+source = $source;
+ $this->size = isset($options['size']) ? $options['size'] : null;
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
+ $this->buffer = new BufferStream();
+ }
+
+ public function __toString()
+ {
+ try {
+ return copy_to_string($this);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function close()
+ {
+ $this->detach();
+ }
+
+ public function detach()
+ {
+ $this->tellPos = false;
+ $this->source = null;
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ return $this->tellPos;
+ }
+
+ public function eof()
+ {
+ return !$this->source;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a PumpStream');
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to a PumpStream');
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function read($length)
+ {
+ $data = $this->buffer->read($length);
+ $readLen = strlen($data);
+ $this->tellPos += $readLen;
+ $remaining = $length - $readLen;
+
+ if ($remaining) {
+ $this->pump($remaining);
+ $data .= $this->buffer->read($remaining);
+ $this->tellPos += strlen($data) - $readLen;
+ }
+
+ return $data;
+ }
+
+ public function getContents()
+ {
+ $result = '';
+ while (!$this->eof()) {
+ $result .= $this->read(1000000);
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!$key) {
+ return $this->metadata;
+ }
+
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
+ }
+
+ private function pump($length)
+ {
+ if ($this->source) {
+ do {
+ $data = call_user_func($this->source, $length);
+ if ($data === false || $data === null) {
+ $this->source = null;
+ return;
+ }
+ $this->buffer->write($data);
+ $length -= strlen($data);
+ } while ($length > 0);
+ }
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/Request.php b/Lib/Alisms/GuzzleHttp/Psr7/Request.php
new file mode 100644
index 0000000..0189b14
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/Request.php
@@ -0,0 +1,149 @@
+method = strtoupper($method);
+ $this->uri = $uri;
+ $this->setHeaders($headers);
+ $this->protocol = $protocolVersion;
+
+ $host = $uri->getHost();
+ if ($host && !$this->hasHeader('Host')) {
+ $this->updateHostFromUri($host);
+ }
+
+ if ($body) {
+ $this->stream = stream_for($body);
+ }
+ }
+
+ public function getRequestTarget()
+ {
+ if ($this->requestTarget !== null) {
+ return $this->requestTarget;
+ }
+
+ $target = $this->uri->getPath();
+ if ($target == null) {
+ $target = '/';
+ }
+ if ($this->uri->getQuery()) {
+ $target .= '?' . $this->uri->getQuery();
+ }
+
+ return $target;
+ }
+
+ public function withRequestTarget($requestTarget)
+ {
+ if (preg_match('#\s#', $requestTarget)) {
+ throw new InvalidArgumentException(
+ 'Invalid request target provided; cannot contain whitespace'
+ );
+ }
+
+ $new = clone $this;
+ $new->requestTarget = $requestTarget;
+ return $new;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function withMethod($method)
+ {
+ $new = clone $this;
+ $new->method = strtoupper($method);
+ return $new;
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ if ($uri === $this->uri) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->uri = $uri;
+
+ if (!$preserveHost) {
+ if ($host = $uri->getHost()) {
+ $new->updateHostFromUri($host);
+ }
+ }
+
+ return $new;
+ }
+
+ public function withHeader($header, $value)
+ {
+ /** @var Request $newInstance */
+ $newInstance = $this->withParentHeader($header, $value);
+ return $newInstance;
+ }
+
+ private function updateHostFromUri($host)
+ {
+ // Ensure Host is the first header.
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
+ if ($port = $this->uri->getPort()) {
+ $host .= ':' . $port;
+ }
+
+ $this->headerLines = ['Host' => [$host]] + $this->headerLines;
+ $this->headers = ['host' => [$host]] + $this->headers;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/Response.php b/Lib/Alisms/GuzzleHttp/Psr7/Response.php
new file mode 100644
index 0000000..c94bf8f
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/Response.php
@@ -0,0 +1,130 @@
+ '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',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Switch Proxy',
+ 307 => 'Temporary 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 Time-out',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested range not satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Unordered Collection',
+ 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 Time-out',
+ 505 => 'HTTP Version not supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 511 => 'Network Authentication Required',
+ ];
+
+ /** @var null|string */
+ private $reasonPhrase = '';
+
+ /** @var int */
+ private $statusCode = 200;
+
+ /**
+ * @param int $status Status code for the response, if any.
+ * @param array $headers Headers for the response, if any.
+ * @param mixed $body Stream body.
+ * @param string $version Protocol version.
+ * @param string $reason Reason phrase (a default will be used if possible).
+ */
+ public function __construct(
+ $status = 200,
+ array $headers = [],
+ $body = null,
+ $version = '1.1',
+ $reason = null
+ ) {
+ $this->statusCode = (int) $status;
+
+ if ($body !== null) {
+ $this->stream = stream_for($body);
+ }
+
+ $this->setHeaders($headers);
+ if (!$reason && isset(self::$phrases[$this->statusCode])) {
+ $this->reasonPhrase = self::$phrases[$status];
+ } else {
+ $this->reasonPhrase = (string) $reason;
+ }
+
+ $this->protocol = $version;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function withStatus($code, $reasonPhrase = '')
+ {
+ $new = clone $this;
+ $new->statusCode = (int) $code;
+ if (!$reasonPhrase && isset(self::$phrases[$new->statusCode])) {
+ $reasonPhrase = self::$phrases[$new->statusCode];
+ }
+ $new->reasonPhrase = $reasonPhrase;
+ return $new;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/Stream.php b/Lib/Alisms/GuzzleHttp/Psr7/Stream.php
new file mode 100644
index 0000000..0b0db01
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/Stream.php
@@ -0,0 +1,245 @@
+ [
+ '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' => [
+ '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
+ ]
+ ];
+
+ /**
+ * This constructor accepts an associative array of options.
+ *
+ * - size: (int) If a read stream would otherwise have an indeterminate
+ * size, but the size is known due to foreknownledge, then you can
+ * provide that size, in bytes.
+ * - metadata: (array) Any additional metadata to return when the metadata
+ * of the stream is accessed.
+ *
+ * @param resource $stream Stream resource to wrap.
+ * @param array $options Associative array of options.
+ *
+ * @throws \InvalidArgumentException if the stream is not a stream resource
+ */
+ public function __construct($stream, $options = [])
+ {
+ if (!is_resource($stream)) {
+ throw new \InvalidArgumentException('Stream must be a resource');
+ }
+
+ if (isset($options['size'])) {
+ $this->size = $options['size'];
+ }
+
+ $this->customMetadata = isset($options['metadata'])
+ ? $options['metadata']
+ : [];
+
+ $this->stream = $stream;
+ $meta = stream_get_meta_data($this->stream);
+ $this->seekable = $meta['seekable'];
+ $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
+ $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
+ $this->uri = $this->getMetadata('uri');
+ }
+
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ throw new \RuntimeException('The stream is detached');
+ }
+
+ throw new \BadMethodCallException('No value for ' . $name);
+ }
+
+ /**
+ * Closes the stream when the destructed
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->seek(0);
+ return (string) stream_get_contents($this->stream);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ $contents = stream_get_contents($this->stream);
+
+ if ($contents === false) {
+ throw new \RuntimeException('Unable to read stream contents');
+ }
+
+ return $contents;
+ }
+
+ public function close()
+ {
+ if (isset($this->stream)) {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->detach();
+ }
+ }
+
+ public function detach()
+ {
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ $result = $this->stream;
+ unset($this->stream);
+ $this->size = $this->uri = null;
+ $this->readable = $this->writable = $this->seekable = false;
+
+ return $result;
+ }
+
+ public function getSize()
+ {
+ if ($this->size !== null) {
+ return $this->size;
+ }
+
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ // Clear the stat cache if the stream has a URI
+ if ($this->uri) {
+ clearstatcache(true, $this->uri);
+ }
+
+ $stats = fstat($this->stream);
+ if (isset($stats['size'])) {
+ $this->size = $stats['size'];
+ return $this->size;
+ }
+
+ return null;
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function eof()
+ {
+ return !$this->stream || feof($this->stream);
+ }
+
+ public function tell()
+ {
+ $result = ftell($this->stream);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to determine stream position');
+ }
+
+ return $result;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('Stream is not seekable');
+ } elseif (fseek($this->stream, $offset, $whence) === -1) {
+ throw new \RuntimeException('Unable to seek to stream position '
+ . $offset . ' with whence ' . var_export($whence, true));
+ }
+ }
+
+ public function read($length)
+ {
+ if (!$this->readable) {
+ throw new \RuntimeException('Cannot read from non-readable stream');
+ }
+
+ return fread($this->stream, $length);
+ }
+
+ public function write($string)
+ {
+ if (!$this->writable) {
+ throw new \RuntimeException('Cannot write to a non-writable stream');
+ }
+
+ // We can't know the size after writing anything
+ $this->size = null;
+ $result = fwrite($this->stream, $string);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to write to stream');
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!isset($this->stream)) {
+ return $key ? null : [];
+ } elseif (!$key) {
+ return $this->customMetadata + stream_get_meta_data($this->stream);
+ } elseif (isset($this->customMetadata[$key])) {
+ return $this->customMetadata[$key];
+ }
+
+ $meta = stream_get_meta_data($this->stream);
+
+ return isset($meta[$key]) ? $meta[$key] : null;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/StreamDecoratorTrait.php b/Lib/Alisms/GuzzleHttp/Psr7/StreamDecoratorTrait.php
new file mode 100644
index 0000000..daec6f5
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/StreamDecoratorTrait.php
@@ -0,0 +1,149 @@
+stream = $stream;
+ }
+
+ /**
+ * Magic method used to create a new stream if streams are not added in
+ * the constructor of a decorator (e.g., LazyOpenStream).
+ *
+ * @param string $name Name of the property (allows "stream" only).
+ *
+ * @return StreamInterface
+ */
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ $this->stream = $this->createStream();
+ return $this->stream;
+ }
+
+ throw new \UnexpectedValueException("$name not found on class");
+ }
+
+ public function __toString()
+ {
+ try {
+ if ($this->isSeekable()) {
+ $this->seek(0);
+ }
+ return $this->getContents();
+ } catch (\Exception $e) {
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
+ trigger_error('StreamDecorator::__toString exception: '
+ . (string) $e, E_USER_ERROR);
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ return copy_to_string($this);
+ }
+
+ /**
+ * 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)
+ {
+ $result = call_user_func_array([$this->stream, $method], $args);
+
+ // Always return the wrapped object if the result is a return $this
+ return $result === $this->stream ? $this : $result;
+ }
+
+ public function close()
+ {
+ $this->stream->close();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $this->stream->getMetadata($key);
+ }
+
+ public function detach()
+ {
+ return $this->stream->detach();
+ }
+
+ public function getSize()
+ {
+ return $this->stream->getSize();
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->stream->isWritable();
+ }
+
+ public function isSeekable()
+ {
+ return $this->stream->isSeekable();
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->stream->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->stream->read($length);
+ }
+
+ public function write($string)
+ {
+ return $this->stream->write($string);
+ }
+
+ /**
+ * Implement in subclasses to dynamically create streams when requested.
+ *
+ * @return StreamInterface
+ * @throws \BadMethodCallException
+ */
+ protected function createStream()
+ {
+ throw new \BadMethodCallException('Not implemented');
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/StreamWrapper.php b/Lib/Alisms/GuzzleHttp/Psr7/StreamWrapper.php
new file mode 100644
index 0000000..cf7b223
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/StreamWrapper.php
@@ -0,0 +1,121 @@
+isReadable()) {
+ $mode = $stream->isWritable() ? 'r+' : 'r';
+ } elseif ($stream->isWritable()) {
+ $mode = 'w';
+ } else {
+ throw new \InvalidArgumentException('The stream must be readable, '
+ . 'writable, or both.');
+ }
+
+ return fopen('guzzle://stream', $mode, null, stream_context_create([
+ 'guzzle' => ['stream' => $stream]
+ ]));
+ }
+
+ /**
+ * Registers the stream wrapper if needed
+ */
+ public static function register()
+ {
+ if (!in_array('guzzle', stream_get_wrappers())) {
+ stream_wrapper_register('guzzle', __CLASS__);
+ }
+ }
+
+ public function stream_open($path, $mode, $options, &$opened_path)
+ {
+ $options = stream_context_get_options($this->context);
+
+ if (!isset($options['guzzle']['stream'])) {
+ return false;
+ }
+
+ $this->mode = $mode;
+ $this->stream = $options['guzzle']['stream'];
+
+ return true;
+ }
+
+ public function stream_read($count)
+ {
+ return $this->stream->read($count);
+ }
+
+ public function stream_write($data)
+ {
+ return (int) $this->stream->write($data);
+ }
+
+ public function stream_tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function stream_eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ $this->stream->seek($offset, $whence);
+
+ return true;
+ }
+
+ public function stream_stat()
+ {
+ static $modeMap = [
+ 'r' => 33060,
+ 'r+' => 33206,
+ 'w' => 33188
+ ];
+
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => $modeMap[$this->mode],
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => $this->stream->getSize() ?: 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/Uri.php b/Lib/Alisms/GuzzleHttp/Psr7/Uri.php
new file mode 100644
index 0000000..d428f2e
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/Uri.php
@@ -0,0 +1,599 @@
+ 80,
+ 'https' => 443,
+ ];
+
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
+ private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
+
+ /** @var string Uri scheme. */
+ private $scheme = '';
+
+ /** @var string Uri user info. */
+ private $userInfo = '';
+
+ /** @var string Uri host. */
+ private $host = '';
+
+ /** @var int|null Uri port. */
+ private $port;
+
+ /** @var string Uri path. */
+ private $path = '';
+
+ /** @var string Uri query string. */
+ private $query = '';
+
+ /** @var string Uri fragment. */
+ private $fragment = '';
+
+ /**
+ * @param string $uri URI to parse and wrap.
+ */
+ public function __construct($uri = '')
+ {
+ if ($uri != null) {
+ $parts = parse_url($uri);
+ if ($parts === false) {
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
+ }
+ $this->applyParts($parts);
+ }
+ }
+
+ public function __toString()
+ {
+ return self::createUriString(
+ $this->scheme,
+ $this->getAuthority(),
+ $this->getPath(),
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
+ */
+ public static function removeDotSegments($path)
+ {
+ static $noopPaths = ['' => true, '/' => true, '*' => true];
+ static $ignoreSegments = ['.' => true, '..' => true];
+
+ if (isset($noopPaths[$path])) {
+ return $path;
+ }
+
+ $results = [];
+ $segments = explode('/', $path);
+ foreach ($segments as $segment) {
+ if ($segment == '..') {
+ array_pop($results);
+ } elseif (!isset($ignoreSegments[$segment])) {
+ $results[] = $segment;
+ }
+ }
+
+ $newPath = implode('/', $results);
+ // Add the leading slash if necessary
+ if (substr($path, 0, 1) === '/' &&
+ substr($newPath, 0, 1) !== '/'
+ ) {
+ $newPath = '/' . $newPath;
+ }
+
+ // Add the trailing slash if necessary
+ if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
+ $newPath .= '/';
+ }
+
+ return $newPath;
+ }
+
+ /**
+ * Resolve a base URI with a relative URI and return a new URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param string $rel Relative URI
+ *
+ * @return UriInterface
+ */
+ public static function resolve(UriInterface $base, $rel)
+ {
+ if ($rel === null || $rel === '') {
+ return $base;
+ }
+
+ if (!($rel instanceof UriInterface)) {
+ $rel = new self($rel);
+ }
+
+ // Return the relative uri as-is if it has a scheme.
+ if ($rel->getScheme()) {
+ return $rel->withPath(static::removeDotSegments($rel->getPath()));
+ }
+
+ $relParts = [
+ 'scheme' => $rel->getScheme(),
+ 'authority' => $rel->getAuthority(),
+ 'path' => $rel->getPath(),
+ 'query' => $rel->getQuery(),
+ 'fragment' => $rel->getFragment()
+ ];
+
+ $parts = [
+ 'scheme' => $base->getScheme(),
+ 'authority' => $base->getAuthority(),
+ 'path' => $base->getPath(),
+ 'query' => $base->getQuery(),
+ 'fragment' => $base->getFragment()
+ ];
+
+ if (!empty($relParts['authority'])) {
+ $parts['authority'] = $relParts['authority'];
+ $parts['path'] = self::removeDotSegments($relParts['path']);
+ $parts['query'] = $relParts['query'];
+ $parts['fragment'] = $relParts['fragment'];
+ } elseif (!empty($relParts['path'])) {
+ if (substr($relParts['path'], 0, 1) == '/') {
+ $parts['path'] = self::removeDotSegments($relParts['path']);
+ $parts['query'] = $relParts['query'];
+ $parts['fragment'] = $relParts['fragment'];
+ } else {
+ if (!empty($parts['authority']) && empty($parts['path'])) {
+ $mergedPath = '/';
+ } else {
+ $mergedPath = substr($parts['path'], 0, strrpos($parts['path'], '/') + 1);
+ }
+ $parts['path'] = self::removeDotSegments($mergedPath . $relParts['path']);
+ $parts['query'] = $relParts['query'];
+ $parts['fragment'] = $relParts['fragment'];
+ }
+ } elseif (!empty($relParts['query'])) {
+ $parts['query'] = $relParts['query'];
+ } elseif ($relParts['fragment'] != null) {
+ $parts['fragment'] = $relParts['fragment'];
+ }
+
+ return new self(static::createUriString(
+ $parts['scheme'],
+ $parts['authority'],
+ $parts['path'],
+ $parts['query'],
+ $parts['fragment']
+ ));
+ }
+
+ /**
+ * Create a new URI with a specific query string value removed.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed.
+ *
+ * Note: this function will convert "=" to "%3D" and "&" to "%26".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Query string key value pair to remove.
+ *
+ * @return UriInterface
+ */
+ public static function withoutQueryValue(UriInterface $uri, $key)
+ {
+ $current = $uri->getQuery();
+ if (!$current) {
+ return $uri;
+ }
+
+ $result = [];
+ foreach (explode('&', $current) as $part) {
+ if (explode('=', $part)[0] !== $key) {
+ $result[] = $part;
+ };
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Create a new URI with a specific query string value.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed and replaced with the given key value pair.
+ *
+ * Note: this function will convert "=" to "%3D" and "&" to "%26".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Key to set.
+ * @param string $value Value to set.
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValue(UriInterface $uri, $key, $value)
+ {
+ $current = $uri->getQuery();
+ $key = strtr($key, self::$replaceQuery);
+
+ if (!$current) {
+ $result = [];
+ } else {
+ $result = [];
+ foreach (explode('&', $current) as $part) {
+ if (explode('=', $part)[0] !== $key) {
+ $result[] = $part;
+ };
+ }
+ }
+
+ if ($value !== null) {
+ $result[] = $key . '=' . strtr($value, self::$replaceQuery);
+ } else {
+ $result[] = $key;
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Create a URI from a hash of parse_url parts.
+ *
+ * @param array $parts
+ *
+ * @return self
+ */
+ public static function fromParts(array $parts)
+ {
+ $uri = new self();
+ $uri->applyParts($parts);
+ return $uri;
+ }
+
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ public function getAuthority()
+ {
+ if (empty($this->host)) {
+ return '';
+ }
+
+ $authority = $this->host;
+ if (!empty($this->userInfo)) {
+ $authority = $this->userInfo . '@' . $authority;
+ }
+
+ if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
+ $authority .= ':' . $this->port;
+ }
+
+ return $authority;
+ }
+
+ public function getUserInfo()
+ {
+ return $this->userInfo;
+ }
+
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ public function getPath()
+ {
+ return $this->path == null ? '' : $this->path;
+ }
+
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ public function withScheme($scheme)
+ {
+ $scheme = $this->filterScheme($scheme);
+
+ if ($this->scheme === $scheme) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->scheme = $scheme;
+ $new->port = $new->filterPort($new->scheme, $new->host, $new->port);
+ return $new;
+ }
+
+ public function withUserInfo($user, $password = null)
+ {
+ $info = $user;
+ if ($password) {
+ $info .= ':' . $password;
+ }
+
+ if ($this->userInfo === $info) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->userInfo = $info;
+ return $new;
+ }
+
+ public function withHost($host)
+ {
+ if ($this->host === $host) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->host = $host;
+ return $new;
+ }
+
+ public function withPort($port)
+ {
+ $port = $this->filterPort($this->scheme, $this->host, $port);
+
+ if ($this->port === $port) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->port = $port;
+ return $new;
+ }
+
+ public function withPath($path)
+ {
+ if (!is_string($path)) {
+ throw new \InvalidArgumentException(
+ 'Invalid path provided; must be a string'
+ );
+ }
+
+ $path = $this->filterPath($path);
+
+ if ($this->path === $path) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->path = $path;
+ return $new;
+ }
+
+ public function withQuery($query)
+ {
+ if (!is_string($query) && !method_exists($query, '__toString')) {
+ throw new \InvalidArgumentException(
+ 'Query string must be a string'
+ );
+ }
+
+ $query = (string) $query;
+ if (substr($query, 0, 1) === '?') {
+ $query = substr($query, 1);
+ }
+
+ $query = $this->filterQueryAndFragment($query);
+
+ if ($this->query === $query) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->query = $query;
+ return $new;
+ }
+
+ public function withFragment($fragment)
+ {
+ if (substr($fragment, 0, 1) === '#') {
+ $fragment = substr($fragment, 1);
+ }
+
+ $fragment = $this->filterQueryAndFragment($fragment);
+
+ if ($this->fragment === $fragment) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->fragment = $fragment;
+ return $new;
+ }
+
+ /**
+ * Apply parse_url parts to a URI.
+ *
+ * @param $parts Array of parse_url parts to apply.
+ */
+ private function applyParts(array $parts)
+ {
+ $this->scheme = isset($parts['scheme'])
+ ? $this->filterScheme($parts['scheme'])
+ : '';
+ $this->userInfo = isset($parts['user']) ? $parts['user'] : '';
+ $this->host = isset($parts['host']) ? $parts['host'] : '';
+ $this->port = !empty($parts['port'])
+ ? $this->filterPort($this->scheme, $this->host, $parts['port'])
+ : null;
+ $this->path = isset($parts['path'])
+ ? $this->filterPath($parts['path'])
+ : '';
+ $this->query = isset($parts['query'])
+ ? $this->filterQueryAndFragment($parts['query'])
+ : '';
+ $this->fragment = isset($parts['fragment'])
+ ? $this->filterQueryAndFragment($parts['fragment'])
+ : '';
+ if (isset($parts['pass'])) {
+ $this->userInfo .= ':' . $parts['pass'];
+ }
+ }
+
+ /**
+ * Create a URI string from its various parts
+ *
+ * @param string $scheme
+ * @param string $authority
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
+ * @return string
+ */
+ private static function createUriString($scheme, $authority, $path, $query, $fragment)
+ {
+ $uri = '';
+
+ if (!empty($scheme)) {
+ $uri .= $scheme . '://';
+ }
+
+ if (!empty($authority)) {
+ $uri .= $authority;
+ }
+
+ if ($path != null) {
+ // Add a leading slash if necessary.
+ if ($uri && substr($path, 0, 1) !== '/') {
+ $uri .= '/';
+ }
+ $uri .= $path;
+ }
+
+ if ($query != null) {
+ $uri .= '?' . $query;
+ }
+
+ if ($fragment != null) {
+ $uri .= '#' . $fragment;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Is a given port non-standard for the current scheme?
+ *
+ * @param string $scheme
+ * @param string $host
+ * @param int $port
+ * @return bool
+ */
+ private static function isNonStandardPort($scheme, $host, $port)
+ {
+ if (!$scheme && $port) {
+ return true;
+ }
+
+ if (!$host || !$port) {
+ return false;
+ }
+
+ return !isset(static::$schemes[$scheme]) || $port !== static::$schemes[$scheme];
+ }
+
+ /**
+ * @param string $scheme
+ *
+ * @return string
+ */
+ private function filterScheme($scheme)
+ {
+ $scheme = strtolower($scheme);
+ $scheme = rtrim($scheme, ':/');
+
+ return $scheme;
+ }
+
+ /**
+ * @param string $scheme
+ * @param string $host
+ * @param int $port
+ *
+ * @return int|null
+ *
+ * @throws \InvalidArgumentException If the port is invalid.
+ */
+ private function filterPort($scheme, $host, $port)
+ {
+ if (null !== $port) {
+ $port = (int) $port;
+ if (1 > $port || 0xffff < $port) {
+ throw new \InvalidArgumentException(
+ sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
+ );
+ }
+ }
+
+ return $this->isNonStandardPort($scheme, $host, $port) ? $port : null;
+ }
+
+ /**
+ * Filters the path of a URI
+ *
+ * @param $path
+ *
+ * @return string
+ */
+ private function filterPath($path)
+ {
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . ':@\/%]+|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $path
+ );
+ }
+
+ /**
+ * Filters the query string or fragment of a URI.
+ *
+ * @param $str
+ *
+ * @return string
+ */
+ private function filterQueryAndFragment($str)
+ {
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $str
+ );
+ }
+
+ private function rawurlencodeMatchZero(array $match)
+ {
+ return rawurlencode($match[0]);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/functions.php b/Lib/Alisms/GuzzleHttp/Psr7/functions.php
new file mode 100644
index 0000000..fd3e7f5
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/functions.php
@@ -0,0 +1,802 @@
+getMethod() . ' '
+ . $message->getRequestTarget())
+ . ' HTTP/' . $message->getProtocolVersion();
+ if (!$message->hasHeader('host')) {
+ $msg .= "\r\nHost: " . $message->getUri()->getHost();
+ }
+ } elseif ($message instanceof ResponseInterface) {
+ $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
+ . $message->getStatusCode() . ' '
+ . $message->getReasonPhrase();
+ } else {
+ throw new \InvalidArgumentException('Unknown message type');
+ }
+
+ foreach ($message->getHeaders() as $name => $values) {
+ $msg .= "\r\n{$name}: " . implode(', ', $values);
+ }
+
+ return "{$msg}\r\n\r\n" . $message->getBody();
+}
+
+/**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or {@see Psr\Http\Message\UriInterface} and
+ * returns a UriInterface for the given value. If the value is already a
+ * `UriInterface`, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ * @throws \InvalidArgumentException
+ */
+function uri_for($uri)
+{
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ } elseif (is_string($uri)) {
+ return new Uri($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+}
+
+/**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * @param resource|string|StreamInterface $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return Stream
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ */
+function stream_for($resource = '', array $options = [])
+{
+ switch (gettype($resource)) {
+ case 'string':
+ $stream = fopen('php://temp', 'r+');
+ if ($resource !== '') {
+ fwrite($stream, $resource);
+ fseek($stream, 0);
+ }
+ return new Stream($stream, $options);
+ case 'resource':
+ return new Stream($resource, $options);
+ case 'object':
+ if ($resource instanceof StreamInterface) {
+ return $resource;
+ } elseif ($resource instanceof \Iterator) {
+ return new PumpStream(function () use ($resource) {
+ if (!$resource->valid()) {
+ return false;
+ }
+ $result = $resource->current();
+ $resource->next();
+ return $result;
+ }, $options);
+ } elseif (method_exists($resource, '__toString')) {
+ return stream_for((string) $resource, $options);
+ }
+ break;
+ case 'NULL':
+ return new Stream(fopen('php://temp', 'r+'), $options);
+ }
+
+ if (is_callable($resource)) {
+ return new PumpStream($resource, $options);
+ }
+
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
+}
+
+/**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair
+ * data of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param string|array $header Header to parse into components.
+ *
+ * @return array Returns the parsed header values.
+ */
+function parse_header($header)
+{
+ static $trimmed = "\"' \n\t\r";
+ $params = $matches = [];
+
+ foreach (normalize_header($header) as $val) {
+ $part = [];
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
+ $m = $matches[0];
+ if (isset($m[1])) {
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
+ } else {
+ $part[] = trim($m[0], $trimmed);
+ }
+ }
+ }
+ if ($part) {
+ $params[] = $part;
+ }
+ }
+
+ return $params;
+}
+
+/**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param string|array $header Header to normalize.
+ *
+ * @return array Returns the normalized header field values.
+ */
+function normalize_header($header)
+{
+ if (!is_array($header)) {
+ return array_map('trim', explode(',', $header));
+ }
+
+ $result = [];
+ foreach ($header as $value) {
+ foreach ((array) $value as $v) {
+ if (strpos($v, ',') === false) {
+ $result[] = $v;
+ continue;
+ }
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
+ $result[] = trim($vv);
+ }
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Clone and modify a request with the given changes.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ */
+function modify_request(RequestInterface $request, array $changes)
+{
+ if (!$changes) {
+ return $request;
+ }
+
+ $headers = $request->getHeaders();
+
+ if (!isset($changes['uri'])) {
+ $uri = $request->getUri();
+ } else {
+ // Remove the host header if one is on the URI
+ if ($host = $changes['uri']->getHost()) {
+ $changes['set_headers']['Host'] = $host;
+ }
+ $uri = $changes['uri'];
+ }
+
+ if (!empty($changes['remove_headers'])) {
+ $headers = _caseless_remove($changes['remove_headers'], $headers);
+ }
+
+ if (!empty($changes['set_headers'])) {
+ $headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
+ $headers = $changes['set_headers'] + $headers;
+ }
+
+ if (isset($changes['query'])) {
+ $uri = $uri->withQuery($changes['query']);
+ }
+
+ return new Request(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion()
+ );
+}
+
+/**
+ * Attempts to rewind a message body and throws an exception on failure.
+ *
+ * The body of the message will only be rewound if a call to `tell()` returns a
+ * value other than `0`.
+ *
+ * @param MessageInterface $message Message to rewind
+ *
+ * @throws \RuntimeException
+ */
+function rewind_body(MessageInterface $message)
+{
+ $body = $message->getBody();
+
+ if ($body->tell()) {
+ $body->rewind();
+ }
+}
+
+/**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ * @throws \RuntimeException if the file cannot be opened
+ */
+function try_fopen($filename, $mode)
+{
+ $ex = null;
+ set_error_handler(function () use ($filename, $mode, &$ex) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open %s using mode %s: %s',
+ $filename,
+ $mode,
+ func_get_args()[1]
+ ));
+ });
+
+ $handle = fopen($filename, $mode);
+ restore_error_handler();
+
+ if ($ex) {
+ /** @var $ex \RuntimeException */
+ throw $ex;
+ }
+
+ return $handle;
+}
+
+/**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ * @return string
+ * @throws \RuntimeException on error.
+ */
+function copy_to_string(StreamInterface $stream, $maxLen = -1)
+{
+ $buffer = '';
+
+ if ($maxLen === -1) {
+ while (!$stream->eof()) {
+ $buf = $stream->read(1048576);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ }
+ return $buffer;
+ }
+
+ $len = 0;
+ while (!$stream->eof() && $len < $maxLen) {
+ $buf = $stream->read($maxLen - $len);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ $len = strlen($buffer);
+ }
+
+ return $buffer;
+}
+
+/**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ */
+function copy_to_stream(
+ StreamInterface $source,
+ StreamInterface $dest,
+ $maxLen = -1
+) {
+ if ($maxLen === -1) {
+ while (!$source->eof()) {
+ if (!$dest->write($source->read(1048576))) {
+ break;
+ }
+ }
+ return;
+ }
+
+ $bytes = 0;
+ while (!$source->eof()) {
+ $buf = $source->read($maxLen - $bytes);
+ if (!($len = strlen($buf))) {
+ break;
+ }
+ $bytes += $len;
+ $dest->write($buf);
+ if ($bytes == $maxLen) {
+ break;
+ }
+ }
+}
+
+/**
+ * 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 string Returns the hash of the stream
+ * @throws \RuntimeException on error.
+ */
+function hash(
+ StreamInterface $stream,
+ $algo,
+ $rawOutput = false
+) {
+ $pos = $stream->tell();
+
+ if ($pos > 0) {
+ $stream->rewind();
+ }
+
+ $ctx = hash_init($algo);
+ while (!$stream->eof()) {
+ hash_update($ctx, $stream->read(1048576));
+ }
+
+ $out = hash_final($ctx, (bool) $rawOutput);
+ $stream->seek($pos);
+
+ return $out;
+}
+
+/**
+ * Read a line from the stream up to the maximum allowed buffer length
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int $maxLength Maximum buffer length
+ *
+ * @return string|bool
+ */
+function readline(StreamInterface $stream, $maxLength = null)
+{
+ $buffer = '';
+ $size = 0;
+
+ while (!$stream->eof()) {
+ // Using a loose equality here to match on '' and false.
+ if (null == ($byte = $stream->read(1))) {
+ return $buffer;
+ }
+ $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;
+}
+
+/**
+ * Parses a request message string into a request object.
+ *
+ * @param string $message Request message string.
+ *
+ * @return Request
+ */
+function parse_request($message)
+{
+ $data = _parse_message($message);
+ $matches = [];
+ if (!preg_match('/^[a-zA-Z]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
+ throw new \InvalidArgumentException('Invalid request string');
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+ $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
+
+ $request = new Request(
+ $parts[0],
+ $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
+ $data['headers'],
+ $data['body'],
+ $version
+ );
+
+ return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
+}
+
+/**
+ * Parses a response message string into a response object.
+ *
+ * @param string $message Response message string.
+ *
+ * @return Response
+ */
+function parse_response($message)
+{
+ $data = _parse_message($message);
+ if (!preg_match('/^HTTP\/.* [0-9]{3} .*/', $data['start-line'])) {
+ throw new \InvalidArgumentException('Invalid response string');
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+
+ return new Response(
+ $parts[1],
+ $data['headers'],
+ $data['body'],
+ explode('/', $parts[0])[1],
+ isset($parts[2]) ? $parts[2] : null
+ );
+}
+
+/**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key
+ * value pair will become an array. This function does not parse nested
+ * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
+ * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
+ *
+ * @param string $str Query string to parse
+ * @param bool|string $urlEncoding How the query string is encoded
+ *
+ * @return array
+ */
+function parse_query($str, $urlEncoding = true)
+{
+ $result = [];
+
+ if ($str === '') {
+ return $result;
+ }
+
+ if ($urlEncoding === true) {
+ $decoder = function ($value) {
+ return rawurldecode(str_replace('+', ' ', $value));
+ };
+ } elseif ($urlEncoding == PHP_QUERY_RFC3986) {
+ $decoder = 'rawurldecode';
+ } elseif ($urlEncoding == PHP_QUERY_RFC1738) {
+ $decoder = 'urldecode';
+ } else {
+ $decoder = function ($str) { return $str; };
+ }
+
+ foreach (explode('&', $str) as $kvp) {
+ $parts = explode('=', $kvp, 2);
+ $key = $decoder($parts[0]);
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
+ if (!isset($result[$key])) {
+ $result[$key] = $value;
+ } else {
+ if (!is_array($result[$key])) {
+ $result[$key] = [$result[$key]];
+ }
+ $result[$key][] = $value;
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of parseQuery() to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like http_build_query would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ * @return string
+ */
+function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
+{
+ if (!$params) {
+ return '';
+ }
+
+ if ($encoding === false) {
+ $encoder = function ($str) { return $str; };
+ } elseif ($encoding == PHP_QUERY_RFC3986) {
+ $encoder = 'rawurlencode';
+ } elseif ($encoding == PHP_QUERY_RFC1738) {
+ $encoder = 'urlencode';
+ } else {
+ throw new \InvalidArgumentException('Invalid type');
+ }
+
+ $qs = '';
+ foreach ($params as $k => $v) {
+ $k = $encoder($k);
+ if (!is_array($v)) {
+ $qs .= $k;
+ if ($v !== null) {
+ $qs .= '=' . $encoder($v);
+ }
+ $qs .= '&';
+ } else {
+ foreach ($v as $vv) {
+ $qs .= $k;
+ if ($vv !== null) {
+ $qs .= '=' . $encoder($vv);
+ }
+ $qs .= '&';
+ }
+ }
+ }
+
+ return $qs ? (string) substr($qs, 0, -1) : '';
+}
+
+/**
+ * Determines the mimetype of a file by looking at its extension.
+ *
+ * @param $filename
+ *
+ * @return null|string
+ */
+function mimetype_from_filename($filename)
+{
+ return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
+}
+
+/**
+ * Maps a file extensions to a mimetype.
+ *
+ * @param $extension string The file extension.
+ *
+ * @return string|null
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
+ */
+function mimetype_from_extension($extension)
+{
+ static $mimetypes = [
+ '7z' => 'application/x-7z-compressed',
+ 'aac' => 'audio/x-aac',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'asc' => 'text/plain',
+ 'asf' => 'video/x-ms-asf',
+ 'atom' => 'application/atom+xml',
+ 'avi' => 'video/x-msvideo',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bzip2',
+ 'cer' => 'application/pkix-cert',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'css' => 'text/css',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'deb' => 'application/x-debian-package',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dvi' => 'application/x-dvi',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'etx' => 'text/x-setext',
+ 'flac' => 'audio/flac',
+ 'flv' => 'video/x-flv',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ini' => 'text/plain',
+ 'iso' => 'application/x-iso9660-image',
+ 'jar' => 'application/java-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'latex' => 'application/x-latex',
+ 'log' => 'text/plain',
+ 'm4a' => 'audio/mp4',
+ 'm4v' => 'video/mp4',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pdf' => 'application/pdf',
+ 'pgm' => 'image/x-portable-graymap',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'ps' => 'application/postscript',
+ 'qt' => 'video/quicktime',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'svg' => 'image/svg+xml',
+ 'swf' => 'application/x-shockwave-flash',
+ 'tar' => 'application/x-tar',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'torrent' => 'application/x-bittorrent',
+ 'ttf' => 'application/x-font-ttf',
+ 'txt' => 'text/plain',
+ 'wav' => 'audio/x-wav',
+ 'webm' => 'video/webm',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmv' => 'video/x-ms-wmv',
+ 'woff' => 'application/x-font-woff',
+ 'wsdl' => 'application/wsdl+xml',
+ 'xbm' => 'image/x-xbitmap',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ 'xpm' => 'image/x-xpixmap',
+ 'xwd' => 'image/x-xwindowdump',
+ 'yaml' => 'text/yaml',
+ 'yml' => 'text/yaml',
+ 'zip' => 'application/zip',
+ ];
+
+ $extension = strtolower($extension);
+
+ return isset($mimetypes[$extension])
+ ? $mimetypes[$extension]
+ : null;
+}
+
+/**
+ * Parses an HTTP message into an associative array.
+ *
+ * The array contains the "start-line" key containing the start line of
+ * the message, "headers" key containing an associative array of header
+ * array values, and a "body" key containing the body of the message.
+ *
+ * @param string $message HTTP request or response to parse.
+ *
+ * @return array
+ * @internal
+ */
+function _parse_message($message)
+{
+ if (!$message) {
+ throw new \InvalidArgumentException('Invalid message');
+ }
+
+ // Iterate over each line in the message, accounting for line endings
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => ''];
+ array_shift($lines);
+
+ 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) {
+ $result['body'] = implode('', array_slice($lines, $i + 2));
+ }
+ break;
+ }
+ if (strpos($line, ':')) {
+ $parts = explode(':', $line, 2);
+ $key = trim($parts[0]);
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
+ $result['headers'][$key][] = $value;
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Constructs a URI for an HTTP request message.
+ *
+ * @param string $path Path from the start-line
+ * @param array $headers Array of headers (each value an array).
+ *
+ * @return string
+ * @internal
+ */
+function _parse_request_uri($path, array $headers)
+{
+ $hostKey = array_filter(array_keys($headers), function ($k) {
+ return strtolower($k) === 'host';
+ });
+
+ // If no host is found, then a full URI cannot be constructed.
+ if (!$hostKey) {
+ return $path;
+ }
+
+ $host = $headers[reset($hostKey)][0];
+ $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
+
+ return $scheme . '://' . $host . '/' . ltrim($path, '/');
+}
+
+/** @internal */
+function _caseless_remove($keys, array $data)
+{
+ $result = [];
+
+ foreach ($keys as &$key) {
+ $key = strtolower($key);
+ }
+
+ foreach ($data as $k => $v) {
+ if (!in_array(strtolower($k), $keys)) {
+ $result[$k] = $v;
+ }
+ }
+
+ return $result;
+}
diff --git a/Lib/Alisms/GuzzleHttp/Psr7/functions_include.php b/Lib/Alisms/GuzzleHttp/Psr7/functions_include.php
new file mode 100644
index 0000000..96a4a83
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/Psr7/functions_include.php
@@ -0,0 +1,6 @@
+ 5,
+ 'protocols' => ['http', 'https'],
+ 'strict' => false,
+ 'referer' => false,
+ 'track_redirects' => false,
+ ];
+
+ /** @var callable */
+ private $nextHandler;
+
+ /**
+ * @param callable $nextHandler Next handler to invoke.
+ */
+ public function __construct(callable $nextHandler)
+ {
+ $this->nextHandler = $nextHandler;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $fn = $this->nextHandler;
+
+ if (empty($options['allow_redirects'])) {
+ return $fn($request, $options);
+ }
+
+ if ($options['allow_redirects'] === true) {
+ $options['allow_redirects'] = self::$defaultSettings;
+ } elseif (!is_array($options['allow_redirects'])) {
+ throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
+ } else {
+ // Merge the default settings with the provided settings
+ $options['allow_redirects'] += self::$defaultSettings;
+ }
+
+ if (empty($options['allow_redirects']['max'])) {
+ return $fn($request, $options);
+ }
+
+ return $fn($request, $options)
+ ->then(function (ResponseInterface $response) use ($request, $options) {
+ return $this->checkRedirect($request, $options, $response);
+ });
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ * @param ResponseInterface|PromiseInterface $response
+ *
+ * @return ResponseInterface|PromiseInterface
+ */
+ public function checkRedirect(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response
+ ) {
+ if (substr($response->getStatusCode(), 0, 1) != '3'
+ || !$response->hasHeader('Location')
+ ) {
+ return $response;
+ }
+
+ $this->guardMax($request, $options);
+ $nextRequest = $this->modifyRequest($request, $options, $response);
+
+ if (isset($options['allow_redirects']['on_redirect'])) {
+ call_user_func(
+ $options['allow_redirects']['on_redirect'],
+ $request,
+ $response,
+ $nextRequest->getUri()
+ );
+ }
+
+ /** @var PromiseInterface|ResponseInterface $promise */
+ $promise = $this($nextRequest, $options);
+
+ // Add headers to be able to track history of redirects.
+ if (!empty($options['allow_redirects']['track_redirects'])) {
+ return $this->withTracking(
+ $promise,
+ (string) $nextRequest->getUri()
+ );
+ }
+
+ return $promise;
+ }
+
+ private function withTracking(PromiseInterface $promise, $uri)
+ {
+ return $promise->then(
+ function (ResponseInterface $response) use ($uri) {
+ // Note that we are pushing to the front of the list as this
+ // would be an earlier response than what is currently present
+ // in the history header.
+ $header = $response->getHeader(self::HISTORY_HEADER);
+ array_unshift($header, $uri);
+ return $response->withHeader(self::HISTORY_HEADER, $header);
+ }
+ );
+ }
+
+ private function guardMax(RequestInterface $request, array &$options)
+ {
+ $current = isset($options['__redirect_count'])
+ ? $options['__redirect_count']
+ : 0;
+ $options['__redirect_count'] = $current + 1;
+ $max = $options['allow_redirects']['max'];
+
+ if ($options['__redirect_count'] > $max) {
+ throw new TooManyRedirectsException(
+ "Will not follow more than {$max} redirects",
+ $request
+ );
+ }
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ * @param ResponseInterface $response
+ *
+ * @return RequestInterface
+ */
+ public function modifyRequest(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response
+ ) {
+ // Request modifications to apply.
+ $modify = [];
+ $protocols = $options['allow_redirects']['protocols'];
+
+ // Use a GET request if this is an entity enclosing request and we are
+ // not forcing RFC compliance, but rather emulating what all browsers
+ // would do.
+ $statusCode = $response->getStatusCode();
+ if ($statusCode == 303 ||
+ ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
+ ) {
+ $modify['method'] = 'GET';
+ $modify['body'] = '';
+ }
+
+ $modify['uri'] = $this->redirectUri($request, $response, $protocols);
+ Psr7\rewind_body($request);
+
+ // Add the Referer header if it is told to do so and only
+ // add the header if we are not redirecting from https to http.
+ if ($options['allow_redirects']['referer']
+ && $modify['uri']->getScheme() === $request->getUri()->getScheme()
+ ) {
+ $uri = $request->getUri()->withUserInfo('', '');
+ $modify['set_headers']['Referer'] = (string) $uri;
+ } else {
+ $modify['remove_headers'][] = 'Referer';
+ }
+
+ // Remove Authorization header if host is different.
+ if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
+ $modify['remove_headers'][] = 'Authorization';
+ }
+
+ return Psr7\modify_request($request, $modify);
+ }
+
+ /**
+ * Set the appropriate URL on the request based on the location header
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ * @param array $protocols
+ *
+ * @return UriInterface
+ */
+ private function redirectUri(
+ RequestInterface $request,
+ ResponseInterface $response,
+ array $protocols
+ ) {
+ $location = Psr7\Uri::resolve(
+ $request->getUri(),
+ $response->getHeaderLine('Location')
+ );
+
+ // Ensure that the redirect URI is allowed based on the protocols.
+ if (!in_array($location->getScheme(), $protocols)) {
+ throw new BadResponseException(
+ sprintf(
+ 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
+ $location,
+ implode(', ', $protocols)
+ ),
+ $request,
+ $response
+ );
+ }
+
+ return $location;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/RequestOptions.php b/Lib/Alisms/GuzzleHttp/RequestOptions.php
new file mode 100644
index 0000000..3af2f36
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/RequestOptions.php
@@ -0,0 +1,244 @@
+decider = $decider;
+ $this->nextHandler = $nextHandler;
+ $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
+ }
+
+ /**
+ * Default exponential backoff delay function.
+ *
+ * @param $retries
+ *
+ * @return int
+ */
+ public static function exponentialDelay($retries)
+ {
+ return (int) pow(2, $retries - 1);
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!isset($options['retries'])) {
+ $options['retries'] = 0;
+ }
+
+ $fn = $this->nextHandler;
+ return $fn($request, $options)
+ ->then(
+ $this->onFulfilled($request, $options),
+ $this->onRejected($request, $options)
+ );
+ }
+
+ private function onFulfilled(RequestInterface $req, array $options)
+ {
+ return function ($value) use ($req, $options) {
+ if (!call_user_func(
+ $this->decider,
+ $options['retries'],
+ $req,
+ $value,
+ null
+ )) {
+ return $value;
+ }
+ return $this->doRetry($req, $options);
+ };
+ }
+
+ private function onRejected(RequestInterface $req, array $options)
+ {
+ return function ($reason) use ($req, $options) {
+ if (!call_user_func(
+ $this->decider,
+ $options['retries'],
+ $req,
+ null,
+ $reason
+ )) {
+ return new RejectedPromise($reason);
+ }
+ return $this->doRetry($req, $options);
+ };
+ }
+
+ private function doRetry(RequestInterface $request, array $options)
+ {
+ $options['delay'] = call_user_func($this->delay, ++$options['retries']);
+
+ return $this($request, $options);
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/TransferStats.php b/Lib/Alisms/GuzzleHttp/TransferStats.php
new file mode 100644
index 0000000..15f717e
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/TransferStats.php
@@ -0,0 +1,126 @@
+request = $request;
+ $this->response = $response;
+ $this->transferTime = $transferTime;
+ $this->handlerErrorData = $handlerErrorData;
+ $this->handlerStats = $handlerStats;
+ }
+
+ /**
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Returns the response that was received (if any).
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Returns true if a response was received.
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * Gets handler specific error data.
+ *
+ * This might be an exception, a integer representing an error code, or
+ * anything else. Relying on this value assumes that you know what handler
+ * you are using.
+ *
+ * @return mixed
+ */
+ public function getHandlerErrorData()
+ {
+ return $this->handlerErrorData;
+ }
+
+ /**
+ * Get the effective URI the request was sent to.
+ *
+ * @return UriInterface
+ */
+ public function getEffectiveUri()
+ {
+ return $this->request->getUri();
+ }
+
+ /**
+ * Get the estimated time the request was being transferred by the handler.
+ *
+ * @return float Time in seconds.
+ */
+ public function getTransferTime()
+ {
+ return $this->transferTime;
+ }
+
+ /**
+ * Gets an array of all of the handler specific transfer data.
+ *
+ * @return array
+ */
+ public function getHandlerStats()
+ {
+ return $this->handlerStats;
+ }
+
+ /**
+ * Get a specific handler statistic from the handler by name.
+ *
+ * @param string $stat Handler specific transfer stat to retrieve.
+ *
+ * @return mixed|null
+ */
+ public function getHandlerStat($stat)
+ {
+ return isset($this->handlerStats[$stat])
+ ? $this->handlerStats[$stat]
+ : null;
+ }
+}
diff --git a/Lib/Alisms/GuzzleHttp/UriTemplate.php b/Lib/Alisms/GuzzleHttp/UriTemplate.php
new file mode 100644
index 0000000..55dfeb5
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/UriTemplate.php
@@ -0,0 +1,241 @@
+ array('prefix' => '', 'joiner' => ',', 'query' => false),
+ '+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
+ '#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
+ '.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
+ '/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
+ ';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
+ '?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
+ '&' => array('prefix' => '&', 'joiner' => '&', 'query' => 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 (false === strpos($template, '{')) {
+ return $template;
+ }
+
+ $this->template = $template;
+ $this->variables = $variables;
+
+ return preg_replace_callback(
+ '/\{([^\}]+)\}/',
+ [$this, 'expandMatch'],
+ $this->template
+ );
+ }
+
+ /**
+ * Parse an expression into parts
+ *
+ * @param string $expression Expression to parse
+ *
+ * @return array Returns an associative array of parts
+ */
+ private function parseExpression($expression)
+ {
+ $result = array();
+
+ if (isset(self::$operatorHash[$expression[0]])) {
+ $result['operator'] = $expression[0];
+ $expression = substr($expression, 1);
+ } else {
+ $result['operator'] = '';
+ }
+
+ foreach (explode(',', $expression) as $value) {
+ $value = trim($value);
+ $varspec = array();
+ if ($colonPos = strpos($value, ':')) {
+ $varspec['value'] = substr($value, 0, $colonPos);
+ $varspec['modifier'] = ':';
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
+ } elseif (substr($value, -1) == '*') {
+ $varspec['modifier'] = '*';
+ $varspec['value'] = substr($value, 0, -1);
+ } else {
+ $varspec['value'] = (string) $value;
+ $varspec['modifier'] = '';
+ }
+ $result['values'][] = $varspec;
+ }
+
+ return $result;
+ }
+
+ /**
+ * 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' => '~');
+
+ $replacements = array();
+ $parsed = self::parseExpression($matches[1]);
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
+
+ foreach ($parsed['values'] as $value) {
+
+ if (!isset($this->variables[$value['value']])) {
+ continue;
+ }
+
+ $variable = $this->variables[$value['value']];
+ $actuallyUseQuery = $useQuery;
+ $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([$key => $var]),
+ $rfc1738to3986
+ );
+ } else {
+ $var = $key . '=' . $var;
+ }
+ } elseif ($key > 0 && $actuallyUseQuery) {
+ $var = $value['value'] . '=' . $var;
+ }
+ }
+
+ $kvp[$key] = $var;
+ }
+
+ if (empty($variable)) {
+ $actuallyUseQuery = 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.
+ $actuallyUseQuery = 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 ($actuallyUseQuery) {
+ 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.
+ *
+ * This makes the assumption that input arrays are sequences or hashes.
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
+ * should work in almost every case where input is supplied for a URI
+ * template.
+ *
+ * @param array $array Array to check
+ *
+ * @return bool
+ */
+ private function isAssoc(array $array)
+ {
+ return $array && array_keys($array)[0] !== 0;
+ }
+
+ /**
+ * 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/Lib/Alisms/GuzzleHttp/functions.php b/Lib/Alisms/GuzzleHttp/functions.php
new file mode 100644
index 0000000..d0a2ca8
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/functions.php
@@ -0,0 +1,280 @@
+expand($template, $variables);
+}
+
+/**
+ * Debug function used to describe the provided value type and class.
+ *
+ * @param mixed $input
+ *
+ * @return string Returns a string containing the type of the variable and
+ * if a class is provided, the class name.
+ */
+function describe_type($input)
+{
+ switch (gettype($input)) {
+ case 'object':
+ return 'object(' . get_class($input) . ')';
+ case 'array':
+ return 'array(' . count($input) . ')';
+ default:
+ ob_start();
+ var_dump($input);
+ // normalize float vs double
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
+ }
+}
+
+/**
+ * Parses an array of header lines into an associative array of headers.
+ *
+ * @param array $lines Header lines array of strings in the following
+ * format: "Name: Value"
+ * @return array
+ */
+function headers_from_lines($lines)
+{
+ $headers = [];
+
+ foreach ($lines as $line) {
+ $parts = explode(':', $line, 2);
+ $headers[trim($parts[0])][] = isset($parts[1])
+ ? trim($parts[1])
+ : null;
+ }
+
+ return $headers;
+}
+
+/**
+ * Returns a debug stream based on the provided variable.
+ *
+ * @param mixed $value Optional value
+ *
+ * @return resource
+ */
+function debug_resource($value = null)
+{
+ if (is_resource($value)) {
+ return $value;
+ } elseif (defined('STDOUT')) {
+ return STDOUT;
+ }
+
+ return fopen('php://output', 'w');
+}
+
+/**
+ * Chooses and creates a default handler to use based on the environment.
+ *
+ * The returned handler is not wrapped by any default middlewares.
+ *
+ * @throws \RuntimeException if no viable Handler is available.
+ * @return callable Returns the best handler for the given system.
+ */
+function choose_handler()
+{
+ $handler = null;
+ if (extension_loaded('curl')) {
+ $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
+ }
+
+ if (ini_get('allow_url_fopen')) {
+ $handler = $handler
+ ? Proxy::wrapStreaming($handler, new StreamHandler())
+ : new StreamHandler();
+ } elseif (!$handler) {
+ throw new \RuntimeException('GuzzleHttp requires cURL, the '
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
+ }
+
+ return $handler;
+}
+
+/**
+ * Get the default User-Agent string to use with Guzzle
+ *
+ * @return string
+ */
+function default_user_agent()
+{
+ static $defaultAgent = '';
+
+ if (!$defaultAgent) {
+ $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
+ if (extension_loaded('curl') && function_exists('curl_version')) {
+ $defaultAgent .= ' curl/' . \curl_version()['version'];
+ }
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
+ }
+
+ return $defaultAgent;
+}
+
+/**
+ * Returns the default cacert bundle for the current system.
+ *
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
+ * If those settings are not configured, then the common locations for
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
+ * and Windows are checked. If any of these file locations are found on
+ * disk, they will be utilized.
+ *
+ * Note: the result of this function is cached for subsequent calls.
+ *
+ * @return string
+ * @throws \RuntimeException if no bundle can be found.
+ */
+function default_ca_bundle()
+{
+ static $cached = null;
+ static $cafiles = [
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
+ '/etc/pki/tls/certs/ca-bundle.crt',
+ // Ubuntu, Debian (provided by the ca-certificates package)
+ '/etc/ssl/certs/ca-certificates.crt',
+ // FreeBSD (provided by the ca_root_nss package)
+ '/usr/local/share/certs/ca-root-nss.crt',
+ // OS X provided by homebrew (using the default path)
+ '/usr/local/etc/openssl/cert.pem',
+ // Google app engine
+ '/etc/ca-certificates.crt',
+ // Windows?
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
+ 'C:\\windows\\curl-ca-bundle.crt',
+ ];
+
+ if ($cached) {
+ return $cached;
+ }
+
+ if ($ca = ini_get('openssl.cafile')) {
+ return $cached = $ca;
+ }
+
+ if ($ca = ini_get('curl.cainfo')) {
+ return $cached = $ca;
+ }
+
+ foreach ($cafiles as $filename) {
+ if (file_exists($filename)) {
+ return $cached = $filename;
+ }
+ }
+
+ throw new \RuntimeException(<<< EOT
+No system CA bundle could be found in any of the the common system locations.
+PHP versions earlier than 5.6 are not properly configured to use the system's
+CA bundle by default. In order to verify peer certificates, you will need to
+supply the path on disk to a certificate bundle to the 'verify' request
+option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
+need a specific certificate bundle, then Mozilla provides a commonly used CA
+bundle which can be downloaded here (provided by the maintainer of cURL):
+https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
+you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
+ini setting to point to the path to the file, allowing you to omit the 'verify'
+request option. See http://curl.haxx.se/docs/sslcerts.html for more
+information.
+EOT
+ );
+}
+
+/**
+ * Creates an associative array of lowercase header names to the actual
+ * header casing.
+ *
+ * @param array $headers
+ *
+ * @return array
+ */
+function normalize_header_keys(array $headers)
+{
+ $result = [];
+ foreach (array_keys($headers) as $key) {
+ $result[strtolower($key)] = $key;
+ }
+
+ return $result;
+}
+
+/**
+ * Returns true if the provided host matches any of the no proxy areas.
+ *
+ * This method will strip a port from the host if it is present. Each pattern
+ * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
+ * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
+ * "baz.foo.com", but ".foo.com" != "foo.com").
+ *
+ * Areas are matched in the following cases:
+ * 1. "*" (without quotes) always matches any hosts.
+ * 2. An exact match.
+ * 3. The area starts with "." and the area is the last part of the host. e.g.
+ * '.mit.edu' will match any host that ends with '.mit.edu'.
+ *
+ * @param string $host Host to check against the patterns.
+ * @param array $noProxyArray An array of host patterns.
+ *
+ * @return bool
+ */
+function is_host_in_noproxy($host, array $noProxyArray)
+{
+ if (strlen($host) === 0) {
+ throw new \InvalidArgumentException('Empty host provided');
+ }
+
+ // Strip port if present.
+ if (strpos($host, ':')) {
+ $host = explode($host, ':', 2)[0];
+ }
+
+ foreach ($noProxyArray as $area) {
+ // Always match on wildcards.
+ if ($area === '*') {
+ return true;
+ } elseif (empty($area)) {
+ // Don't match on empty values.
+ continue;
+ } elseif ($area === $host) {
+ // Exact matches.
+ return true;
+ } else {
+ // Special match if the area when prefixed with ".". Remove any
+ // existing leading "." and add a new leading ".".
+ $area = '.' . ltrim($area, '.');
+ if (substr($host, -(strlen($area))) === $area) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/Lib/Alisms/GuzzleHttp/functions_include.php b/Lib/Alisms/GuzzleHttp/functions_include.php
new file mode 100644
index 0000000..a93393a
--- /dev/null
+++ b/Lib/Alisms/GuzzleHttp/functions_include.php
@@ -0,0 +1,6 @@
+client = new Client($conf['end_point'], $conf['access_id'], $conf['access_key']);
+ /**
+ * Step 2. 获取主题引用
+ */
+ $topic = $this->client->getTopicRef($conf['topic_name']);
+ /**
+ * Step 3. 生成SMS消息属性
+ */
+ // 3.1 设置发送短信的签名(SMSSignName)和模板(SMSTemplateCode)
+ $batchSmsAttributes = new BatchSmsAttributes($conf['sign'], $conf['template']);
+ // 3.2 (如果在短信模板中定义了参数)指定短信模板中对应参数的值
+ $to = explode(',', $to);
+ foreach ($to as $phone) {
+ var_dump($phone);
+ $batchSmsAttributes->addReceiver($phone, $param);
+ }
+ $messageAttributes = new MessageAttributes(array($batchSmsAttributes));
+ /**
+ * Step 4. 设置SMS消息体(必须)
+ *
+ * 注:目前暂时不支持消息内容为空,需要指定消息内容,不为空即可。
+ */
+ $messageBody = $conf['message_body'];
+ /**
+ * Step 5. 发布SMS消息
+ */
+ $request = new PublishMessageRequest($messageBody, $messageAttributes);
+
+ try {
+ return $topic->publishMessage($request);
+ } catch (MnsException $e) {
+ return $e;
+ }
+
+ }
+
+ /**
+ * 创建短信主题
+ * @param $topicName
+ * @return bool
+ */
+ protected function createTopic($topicName) {
+ $request = new CreateTopicRequest($topicName);
+ try {
+
+ $res = $this->client->createTopic($request);
+ echo "TopicCreated! \n";
+ return true;
+ } catch (MnsException $e) {
+ // 2. 可能因为网络错误,或者Topic已经存在等原因导致CreateTopic失败,这里CatchException并做对应的处理
+ echo "CreateTopicFailed: " . $e . "\n";
+ echo "MNSErrorCode: " . $e->getMnsErrorCode() . "\n";
+ return false;
+ }
+ }
+
+ /**
+ * 删除短信主题
+ * @param $topicName
+ * @return bool
+ */
+ protected function deleteTopic($topicName) {
+ try {
+ $this->client->deleteTopic($topicName);
+ echo "DeleteTopic Succeed! \n";
+ return true;
+ } catch (MnsException $e) {
+ echo "DeleteTopic Failed: " . $e;
+ return false;
+ }
+ }
+
+ /**
+ * 创建订阅
+ * @param $subscriptionName
+ * @return bool
+ */
+ protected function subscript($subscriptionName) {
+ // 1. 生成SubscriptionAttributes,这里第二个参数是Subscription的Endpoint。
+ // 1.1 这里设置的是刚才启动的http server的地址
+ // 1.2 更多支持的Endpoint类型可以参考:help.aliyun.com/document_detail/27479.html
+ $attributes = new SubscriptionAttributes($subscriptionName, 'http://' . $this->ip . ':' . $this->port);
+ try {
+ $this->topic->subscribe($attributes);
+ // 2. 订阅成功
+ echo "Subscribed! \n";
+ return true;
+ } catch (MnsException $e) {
+ // 3. 可能因为网络错误,或者同名的Subscription已存在等原因导致订阅出错,这里CatchException并做对应的处理
+ echo "SubscribeFailed: " . $e . "\n";
+ echo "MNSErrorCode: " . $e->getMnsErrorCode() . "\n";
+ return false;
+ }
+ }
+
+ /**
+ * 删除订阅
+ * @param $subscriptionName
+ * @return bool
+ */
+ protected function deleteSubscript($subscriptionName) {
+ try {
+ $this->topic->unsubscribe($subscriptionName);
+ echo "Unsubscribe Succeed! \n";
+ return true;
+ } catch (MnsException $e) {
+ echo "Unsubscribe Failed: " . $e;
+ return false;
+ }
+ }
+
+ /**
+ * 推送消息
+ * @return bool
+ */
+ protected function pushMessage() {
+ $messageBody = "test";
+ // 1. 生成PublishMessageRequest
+ // 1.1 如果是推送到邮箱,还需要设置MessageAttributes,可以参照Tests/TopicTest.php里面的testPublishMailMessage
+ $request = new PublishMessageRequest($messageBody);
+ try {
+ $res = $this->topic->publishMessage($request);
+ // 2. PublishMessage成功
+ echo "MessagePublished! \n";
+ return true;
+ } catch (MnsException $e) {
+ // 3. 可能因为网络错误等原因导致PublishMessage失败,这里CatchException并做对应处理
+ echo "PublishMessage Failed: " . $e . "\n";
+ echo "MNSErrorCode: " . $e->getMnsErrorCode() . "\n";
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Lib/Alisms/Psr/Http/Message/MessageInterface.php b/Lib/Alisms/Psr/Http/Message/MessageInterface.php
new file mode 100644
index 0000000..8f67a05
--- /dev/null
+++ b/Lib/Alisms/Psr/Http/Message/MessageInterface.php
@@ -0,0 +1,187 @@
+getHeaders() as $name => $values) {
+ * echo $name . ": " . implode(", ", $values);
+ * }
+ *
+ * // Emit headers iteratively:
+ * foreach ($message->getHeaders() as $name => $values) {
+ * foreach ($values as $value) {
+ * header(sprintf('%s: %s', $name, $value), false);
+ * }
+ * }
+ *
+ * While header names are not case-sensitive, getHeaders() will preserve the
+ * exact case in which headers were originally specified.
+ *
+ * @return array Returns an associative array of the message's headers. Each
+ * key MUST be a header name, and each value MUST be an array of strings
+ * for that header.
+ */
+ public function getHeaders();
+
+ /**
+ * Checks if a header exists by the given case-insensitive name.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return bool Returns true if any header names match the given header
+ * name using a case-insensitive string comparison. Returns false if
+ * no matching header name is found in the message.
+ */
+ public function hasHeader($name);
+
+ /**
+ * Retrieves a message header value by the given case-insensitive name.
+ *
+ * This method returns an array of all the header values of the given
+ * case-insensitive header name.
+ *
+ * If the header does not appear in the message, this method MUST return an
+ * empty array.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string[] An array of string values as provided for the given
+ * header. If the header does not appear in the message, this method MUST
+ * return an empty array.
+ */
+ public function getHeader($name);
+
+ /**
+ * Retrieves a comma-separated string of the values for a single header.
+ *
+ * This method returns all of the header values of the given
+ * case-insensitive header name as a string concatenated together using
+ * a comma.
+ *
+ * NOTE: Not all header values may be appropriately represented using
+ * comma concatenation. For such headers, use getHeader() instead
+ * and supply your own delimiter when concatenating.
+ *
+ * If the header does not appear in the message, this method MUST return
+ * an empty string.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string A string of values as provided for the given header
+ * concatenated together using a comma. If the header does not appear in
+ * the message, this method MUST return an empty string.
+ */
+ public function getHeaderLine($name);
+
+ /**
+ * Return an instance with the provided value replacing the specified header.
+ *
+ * While header names are case-insensitive, the casing of the header will
+ * be preserved by this function, and returned from getHeaders().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new and/or updated header and value.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @param string|string[] $value Header value(s).
+ * @return self
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withHeader($name, $value);
+
+ /**
+ * Return an instance with the specified header appended with the given value.
+ *
+ * Existing values for the specified header will be maintained. The new
+ * value(s) will be appended to the existing list. If the header did not
+ * exist previously, it will be added.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new header and/or value.
+ *
+ * @param string $name Case-insensitive header field name to add.
+ * @param string|string[] $value Header value(s).
+ * @return self
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withAddedHeader($name, $value);
+
+ /**
+ * Return an instance without the specified header.
+ *
+ * Header resolution MUST be done without case-sensitivity.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the named header.
+ *
+ * @param string $name Case-insensitive header field name to remove.
+ * @return self
+ */
+ public function withoutHeader($name);
+
+ /**
+ * Gets the body of the message.
+ *
+ * @return StreamInterface Returns the body as a stream.
+ */
+ public function getBody();
+
+ /**
+ * Return an instance with the specified message body.
+ *
+ * The body MUST be a StreamInterface object.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return a new instance that has the
+ * new body stream.
+ *
+ * @param StreamInterface $body Body.
+ * @return self
+ * @throws \InvalidArgumentException When the body is not valid.
+ */
+ public function withBody(StreamInterface $body);
+}
diff --git a/Lib/Alisms/Psr/Http/Message/RequestInterface.php b/Lib/Alisms/Psr/Http/Message/RequestInterface.php
new file mode 100644
index 0000000..75c802e
--- /dev/null
+++ b/Lib/Alisms/Psr/Http/Message/RequestInterface.php
@@ -0,0 +1,129 @@
+getQuery()`
+ * or from the `QUERY_STRING` server param.
+ *
+ * @return array
+ */
+ public function getQueryParams();
+
+ /**
+ * Return an instance with the specified query string arguments.
+ *
+ * These values SHOULD remain immutable over the course of the incoming
+ * request. They MAY be injected during instantiation, such as from PHP's
+ * $_GET superglobal, or MAY be derived from some other value such as the
+ * URI. In cases where the arguments are parsed from the URI, the data
+ * MUST be compatible with what PHP's parse_str() would return for
+ * purposes of how duplicate query parameters are handled, and how nested
+ * sets are handled.
+ *
+ * Setting query string arguments MUST NOT change the URI stored by the
+ * request, nor the values in the server params.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated query string arguments.
+ *
+ * @param array $query Array of query string arguments, typically from
+ * $_GET.
+ * @return self
+ */
+ public function withQueryParams(array $query);
+
+ /**
+ * Retrieve normalized file upload data.
+ *
+ * This method returns upload metadata in a normalized tree, with each leaf
+ * an instance of Psr\Http\Message\UploadedFileInterface.
+ *
+ * These values MAY be prepared from $_FILES or the message body during
+ * instantiation, or MAY be injected via withUploadedFiles().
+ *
+ * @return array An array tree of UploadedFileInterface instances; an empty
+ * array MUST be returned if no data is present.
+ */
+ public function getUploadedFiles();
+
+ /**
+ * Create a new instance with the specified uploaded files.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param array An array tree of UploadedFileInterface instances.
+ * @return self
+ * @throws \InvalidArgumentException if an invalid structure is provided.
+ */
+ public function withUploadedFiles(array $uploadedFiles);
+
+ /**
+ * Retrieve any parameters provided in the request body.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, this method MUST
+ * return the contents of $_POST.
+ *
+ * Otherwise, this method may return any results of deserializing
+ * the request body content; as parsing returns structured content, the
+ * potential types MUST be arrays or objects only. A null value indicates
+ * the absence of body content.
+ *
+ * @return null|array|object The deserialized body parameters, if any.
+ * These will typically be an array or object.
+ */
+ public function getParsedBody();
+
+ /**
+ * Return an instance with the specified body parameters.
+ *
+ * These MAY be injected during instantiation.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, use this method
+ * ONLY to inject the contents of $_POST.
+ *
+ * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
+ * deserializing the request body content. Deserialization/parsing returns
+ * structured data, and, as such, this method ONLY accepts arrays or objects,
+ * or a null value if nothing was available to parse.
+ *
+ * As an example, if content negotiation determines that the request data
+ * is a JSON payload, this method could be used to create a request
+ * instance with the deserialized parameters.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param null|array|object $data The deserialized body data. This will
+ * typically be in an array or object.
+ * @return self
+ * @throws \InvalidArgumentException if an unsupported argument type is
+ * provided.
+ */
+ public function withParsedBody($data);
+
+ /**
+ * Retrieve attributes derived from the request.
+ *
+ * The request "attributes" may be used to allow injection of any
+ * parameters derived from the request: e.g., the results of path
+ * match operations; the results of decrypting cookies; the results of
+ * deserializing non-form-encoded message bodies; etc. Attributes
+ * will be application and request specific, and CAN be mutable.
+ *
+ * @return array Attributes derived from the request.
+ */
+ public function getAttributes();
+
+ /**
+ * Retrieve a single derived request attribute.
+ *
+ * Retrieves a single derived request attribute as described in
+ * getAttributes(). If the attribute has not been previously set, returns
+ * the default value as provided.
+ *
+ * This method obviates the need for a hasAttribute() method, as it allows
+ * specifying a default value to return if the attribute is not found.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $default Default value to return if the attribute does not exist.
+ * @return mixed
+ */
+ public function getAttribute($name, $default = null);
+
+ /**
+ * Return an instance with the specified derived request attribute.
+ *
+ * This method allows setting a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $value The value of the attribute.
+ * @return self
+ */
+ public function withAttribute($name, $value);
+
+ /**
+ * Return an instance that removes the specified derived request attribute.
+ *
+ * This method allows removing a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @return self
+ */
+ public function withoutAttribute($name);
+}
diff --git a/Lib/Alisms/Psr/Http/Message/StreamInterface.php b/Lib/Alisms/Psr/Http/Message/StreamInterface.php
new file mode 100644
index 0000000..f68f391
--- /dev/null
+++ b/Lib/Alisms/Psr/Http/Message/StreamInterface.php
@@ -0,0 +1,158 @@
+
+ * [user-info@]host[:port]
+ *
+ *
+ * If the port component is not set or is the standard port for the current
+ * scheme, it SHOULD NOT be included.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2
+ * @return string The URI authority, in "[user-info@]host[:port]" format.
+ */
+ public function getAuthority();
+
+ /**
+ * Retrieve the user information component of the URI.
+ *
+ * If no user information is present, this method MUST return an empty
+ * string.
+ *
+ * If a user is present in the URI, this will return that value;
+ * additionally, if the password is also present, it will be appended to the
+ * user value, with a colon (":") separating the values.
+ *
+ * The trailing "@" character is not part of the user information and MUST
+ * NOT be added.
+ *
+ * @return string The URI user information, in "username[:password]" format.
+ */
+ public function getUserInfo();
+
+ /**
+ * Retrieve the host component of the URI.
+ *
+ * If no host is present, this method MUST return an empty string.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.2.2.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
+ * @return string The URI host.
+ */
+ public function getHost();
+
+ /**
+ * Retrieve the port component of the URI.
+ *
+ * If a port is present, and it is non-standard for the current scheme,
+ * this method MUST return it as an integer. If the port is the standard port
+ * used with the current scheme, this method SHOULD return null.
+ *
+ * If no port is present, and no scheme is present, this method MUST return
+ * a null value.
+ *
+ * If no port is present, but a scheme is present, this method MAY return
+ * the standard port for that scheme, but SHOULD return null.
+ *
+ * @return null|int The URI port.
+ */
+ public function getPort();
+
+ /**
+ * Retrieve the path component of the URI.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * Normally, the empty path "" and absolute path "/" are considered equal as
+ * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
+ * do this normalization because in contexts with a trimmed base path, e.g.
+ * the front controller, this difference becomes significant. It's the task
+ * of the user to handle both "" and "/".
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.3.
+ *
+ * As an example, if the value should include a slash ("/") not intended as
+ * delimiter between path segments, that value MUST be passed in encoded
+ * form (e.g., "%2F") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.3
+ * @return string The URI path.
+ */
+ public function getPath();
+
+ /**
+ * Retrieve the query string of the URI.
+ *
+ * If no query string is present, this method MUST return an empty string.
+ *
+ * The leading "?" character is not part of the query and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.4.
+ *
+ * As an example, if a value in a key/value pair of the query string should
+ * include an ampersand ("&") not intended as a delimiter between values,
+ * that value MUST be passed in encoded form (e.g., "%26") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.4
+ * @return string The URI query string.
+ */
+ public function getQuery();
+
+ /**
+ * Retrieve the fragment component of the URI.
+ *
+ * If no fragment is present, this method MUST return an empty string.
+ *
+ * The leading "#" character is not part of the fragment and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.5.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.5
+ * @return string The URI fragment.
+ */
+ public function getFragment();
+
+ /**
+ * Return an instance with the specified scheme.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified scheme.
+ *
+ * Implementations MUST support the schemes "http" and "https" case
+ * insensitively, and MAY accommodate other schemes if required.
+ *
+ * An empty scheme is equivalent to removing the scheme.
+ *
+ * @param string $scheme The scheme to use with the new instance.
+ * @return self A new instance with the specified scheme.
+ * @throws \InvalidArgumentException for invalid or unsupported schemes.
+ */
+ public function withScheme($scheme);
+
+ /**
+ * Return an instance with the specified user information.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user information.
+ *
+ * Password is optional, but the user information MUST include the
+ * user; an empty string for the user is equivalent to removing user
+ * information.
+ *
+ * @param string $user The user name to use for authority.
+ * @param null|string $password The password associated with $user.
+ * @return self A new instance with the specified user information.
+ */
+ public function withUserInfo($user, $password = null);
+
+ /**
+ * Return an instance with the specified host.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified host.
+ *
+ * An empty host value is equivalent to removing the host.
+ *
+ * @param string $host The hostname to use with the new instance.
+ * @return self A new instance with the specified host.
+ * @throws \InvalidArgumentException for invalid hostnames.
+ */
+ public function withHost($host);
+
+ /**
+ * Return an instance with the specified port.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified port.
+ *
+ * Implementations MUST raise an exception for ports outside the
+ * established TCP and UDP port ranges.
+ *
+ * A null value provided for the port is equivalent to removing the port
+ * information.
+ *
+ * @param null|int $port The port to use with the new instance; a null value
+ * removes the port information.
+ * @return self A new instance with the specified port.
+ * @throws \InvalidArgumentException for invalid ports.
+ */
+ public function withPort($port);
+
+ /**
+ * Return an instance with the specified path.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified path.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * If the path is intended to be domain-relative rather than path relative then
+ * it must begin with a slash ("/"). Paths not starting with a slash ("/")
+ * are assumed to be relative to some base path known to the application or
+ * consumer.
+ *
+ * Users can provide both encoded and decoded path characters.
+ * Implementations ensure the correct encoding as outlined in getPath().
+ *
+ * @param string $path The path to use with the new instance.
+ * @return self A new instance with the specified path.
+ * @throws \InvalidArgumentException for invalid paths.
+ */
+ public function withPath($path);
+
+ /**
+ * Return an instance with the specified query string.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified query string.
+ *
+ * Users can provide both encoded and decoded query characters.
+ * Implementations ensure the correct encoding as outlined in getQuery().
+ *
+ * An empty query string value is equivalent to removing the query string.
+ *
+ * @param string $query The query string to use with the new instance.
+ * @return self A new instance with the specified query string.
+ * @throws \InvalidArgumentException for invalid query strings.
+ */
+ public function withQuery($query);
+
+ /**
+ * Return an instance with the specified URI fragment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified URI fragment.
+ *
+ * Users can provide both encoded and decoded fragment characters.
+ * Implementations ensure the correct encoding as outlined in getFragment().
+ *
+ * An empty fragment value is equivalent to removing the fragment.
+ *
+ * @param string $fragment The fragment to use with the new instance.
+ * @return self A new instance with the specified fragment.
+ */
+ public function withFragment($fragment);
+
+ /**
+ * Return the string representation as a URI reference.
+ *
+ * Depending on which components of the URI are present, the resulting
+ * string is either a full URI or relative reference according to RFC 3986,
+ * Section 4.1. The method concatenates the various components of the URI,
+ * using the appropriate delimiters:
+ *
+ * - If a scheme is present, it MUST be suffixed by ":".
+ * - If an authority is present, it MUST be prefixed by "//".
+ * - The path can be concatenated without delimiters. But there are two
+ * cases where the path has to be adjusted to make the URI reference
+ * valid as PHP does not allow to throw an exception in __toString():
+ * - If the path is rootless and an authority is present, the path MUST
+ * be prefixed by "/".
+ * - If the path is starting with more than one "/" and no authority is
+ * present, the starting slashes MUST be reduced to one.
+ * - If a query is present, it MUST be prefixed by "?".
+ * - If a fragment is present, it MUST be prefixed by "#".
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
+ * @return string
+ */
+ public function __toString();
+}
diff --git a/Lib/Alisms/README.md b/Lib/Alisms/README.md
new file mode 100644
index 0000000..3d97187
--- /dev/null
+++ b/Lib/Alisms/README.md
@@ -0,0 +1,5 @@
+# MNS SDK for PHP
+Please refer to http://www.aliyun.com/product/mns and https://docs.aliyun.com/?spm=5176.7393424.9.6.5ki1hv#/pub/mns/api_reference/intro&intro for more API details.
+
+## Samples
+You must fulfill the AccessId/AccessKey/AccountID in the example before running.
diff --git a/Lib/Alisms/Samples/Queue/CreateQueueAndSendMessage.php b/Lib/Alisms/Samples/Queue/CreateQueueAndSendMessage.php
new file mode 100644
index 0000000..432a08a
--- /dev/null
+++ b/Lib/Alisms/Samples/Queue/CreateQueueAndSendMessage.php
@@ -0,0 +1,116 @@
+accessId = $accessId;
+ $this->accessKey = $accessKey;
+ $this->endPoint = $endPoint;
+ }
+
+ public function run()
+ {
+ $queueName = "CreateQueueAndSendMessageExample";
+
+ $this->client = new Client($this->endPoint, $this->accessId, $this->accessKey);
+
+ // 1. create queue
+ $request = new CreateQueueRequest($queueName);
+ try
+ {
+ $res = $this->client->createQueue($request);
+ echo "QueueCreated! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "CreateQueueFailed: " . $e;
+ return;
+ }
+ $queue = $this->client->getQueueRef($queueName);
+
+ // 2. send message
+ $messageBody = "test";
+ // as the messageBody will be automatically encoded
+ // the MD5 is calculated for the encoded body
+ $bodyMD5 = md5(base64_encode($messageBody));
+ $request = new SendMessageRequest($messageBody);
+ try
+ {
+ $res = $queue->sendMessage($request);
+ echo "MessageSent! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "SendMessage Failed: " . $e;
+ return;
+ }
+
+ // 3. receive message
+ $receiptHandle = NULL;
+ try
+ {
+ // when receiving messages, it's always a good practice to set the waitSeconds to be 30.
+ // it means to send one http-long-polling request which lasts 30 seconds at most.
+ $res = $queue->receiveMessage(30);
+ echo "ReceiveMessage Succeed! \n";
+ if (strtoupper($bodyMD5) == $res->getMessageBodyMD5())
+ {
+ echo "You got the message sent by yourself! \n";
+ }
+ $receiptHandle = $res->getReceiptHandle();
+ }
+ catch (MnsException $e)
+ {
+ echo "ReceiveMessage Failed: " . $e;
+ return;
+ }
+
+ // 4. delete message
+ try
+ {
+ $res = $queue->deleteMessage($receiptHandle);
+ echo "DeleteMessage Succeed! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "DeleteMessage Failed: " . $e;
+ return;
+ }
+
+ // 5. delete queue
+ try {
+ $this->client->deleteQueue($queueName);
+ echo "DeleteQueue Succeed! \n";
+ } catch (MnsException $e) {
+ echo "DeleteQueue Failed: " . $e;
+ return;
+ }
+ }
+}
+
+$accessId = "";
+$accessKey = "";
+$endPoint = "";
+
+if (empty($accessId) || empty($accessKey) || empty($endPoint))
+{
+ echo "Must Provide AccessId/AccessKey/EndPoint to Run the Example. \n";
+ return;
+}
+
+$instance = new CreateQueueAndSendMessage($accessId, $accessKey, $endPoint);
+$instance->run();
+
+?>
diff --git a/Lib/Alisms/Samples/Topic/CreateTopicAndPublishMessage.php b/Lib/Alisms/Samples/Topic/CreateTopicAndPublishMessage.php
new file mode 100644
index 0000000..f5a0246
--- /dev/null
+++ b/Lib/Alisms/Samples/Topic/CreateTopicAndPublishMessage.php
@@ -0,0 +1,125 @@
+ip = $ip;
+ $this->port = strval($port);
+ $this->accessId = $accessId;
+ $this->accessKey = $accessKey;
+ $this->endPoint = $endPoint;
+ }
+
+ public function run()
+ {
+ $topicName = "CreateTopicAndPublishMessageExample";
+
+ $this->client = new Client($this->endPoint, $this->accessId, $this->accessKey);
+
+ // 1. create topic
+ $request = new CreateTopicRequest($topicName);
+ try
+ {
+ $res = $this->client->createTopic($request);
+ echo "TopicCreated! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "CreateTopicFailed: " . $e;
+ return;
+ }
+ $topic = $this->client->getTopicRef($topicName);
+
+ // 2. subscribe
+ $subscriptionName = "SubscriptionExample";
+ $attributes = new SubscriptionAttributes($subscriptionName, 'http://' . $this->ip . ':' . $this->port);
+
+ try
+ {
+ $topic->subscribe($attributes);
+ echo "Subscribed! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "SubscribeFailed: " . $e;
+ return;
+ }
+
+ // 3. send message
+ $messageBody = "test";
+ // as the messageBody will be automatically encoded
+ // the MD5 is calculated for the encoded body
+ $bodyMD5 = md5(base64_encode($messageBody));
+ $request = new PublishMessageRequest($messageBody);
+ try
+ {
+ $res = $topic->publishMessage($request);
+ echo "MessagePublished! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "PublishMessage Failed: " . $e;
+ return;
+ }
+
+ // 4. sleep for receiving notification
+ sleep(20);
+
+ // 5. unsubscribe
+ try
+ {
+ $topic->unsubscribe($subscriptionName);
+ echo "Unsubscribe Succeed! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "Unsubscribe Failed: " . $e;
+ return;
+ }
+
+ // 6. delete topic
+ try
+ {
+ $this->client->deleteTopic($topicName);
+ echo "DeleteTopic Succeed! \n";
+ }
+ catch (MnsException $e)
+ {
+ echo "DeleteTopic Failed: " . $e;
+ return;
+ }
+ }
+}
+
+$accessId = "";
+$accessKey = "";
+$endPoint = "";
+$ip = ""; //公网IP
+$port = "8000";
+
+if (empty($accessId) || empty($accessKey) || empty($endPoint))
+{
+ echo "Must Provide AccessId/AccessKey/EndPoint to Run the Example. \n";
+ return;
+}
+
+
+$instance = new CreateTopicAndPublishMessage($ip, $port, $accessId, $accessKey, $endPoint);
+$instance->run();
+
+?>
diff --git a/Lib/Alisms/Samples/Topic/http_server_sample.php b/Lib/Alisms/Samples/Topic/http_server_sample.php
new file mode 100644
index 0000000..a5cca27
--- /dev/null
+++ b/Lib/Alisms/Samples/Topic/http_server_sample.php
@@ -0,0 +1,113 @@
+ $value)
+ {
+ if (substr($name, 0, 5) == 'HTTP_')
+ {
+ $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
+ }
+ }
+ return $headers;
+ }
+}
+
+// 1. get the headers and check the signature
+$tmpHeaders = array();
+$headers = getallheaders();
+foreach ($headers as $key => $value)
+{
+ if (0 === strpos($key, 'x-mns-'))
+ {
+ $tmpHeaders[$key] = $value;
+ }
+}
+ksort($tmpHeaders);
+$canonicalizedMNSHeaders = implode("\n", array_map(function ($v, $k) { return $k . ":" . $v; }, $tmpHeaders, array_keys($tmpHeaders)));
+
+$method = $_SERVER['REQUEST_METHOD'];
+$canonicalizedResource = $_SERVER['REQUEST_URI'];
+error_log($canonicalizedResource);
+
+$contentMd5 = '';
+if (array_key_exists('Content-MD5', $headers))
+{
+ $contentMd5 = $headers['Content-MD5'];
+}
+else if (array_key_exists('Content-md5', $headers))
+{
+ $contentMd5 = $headers['Content-md5'];
+}
+
+$contentType = '';
+if (array_key_exists('Content-Type', $headers))
+{
+ $contentType = $headers['Content-Type'];
+}
+$date = $headers['Date'];
+
+$stringToSign = strtoupper($method) . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n" . $canonicalizedMNSHeaders . "\n" . $canonicalizedResource;
+error_log($stringToSign);
+
+$publicKeyURL = base64_decode($headers['x-mns-signing-cert-url']);
+$publicKey = get_by_url($publicKeyURL);
+$signature = $headers['Authorization'];
+
+$pass = verify($stringToSign, $signature, $publicKey);
+if (!$pass)
+{
+ error_log("verify signature fail");
+ http_response_code(400);
+ return;
+}
+
+// 2. now parse the content
+$content = file_get_contents("php://input");
+error_log($content);
+
+if (!empty($contentMd5) && $contentMd5 != base64_encode(md5($content)))
+{
+ error_log("md5 mismatch");
+ http_response_code(401);
+ return;
+}
+
+$msg = new SimpleXMLElement($content);
+echo "\n______________________________________________________\n";
+echo "TopicName: " . $msg->TopicName . "\n";
+echo "SubscriptionName: " . $msg->SubscriptionName . "\n";
+echo "MessageId: " . $msg->MessageId . "\n";
+echo "MessageMD5: " . $msg->MessageMD5 . "\n";
+echo "Message: " . $msg->Message . "\n";
+echo "______________________________________________________\n";
+http_response_code(200);
+
+
+?>
diff --git a/Lib/Alisms/Tests/ClientTest.php b/Lib/Alisms/Tests/ClientTest.php
new file mode 100644
index 0000000..09b6dfe
--- /dev/null
+++ b/Lib/Alisms/Tests/ClientTest.php
@@ -0,0 +1,539 @@
+endPoint = $ini_array["endpoint"];
+ $this->accessId = $ini_array["accessid"];
+ $this->accessKey = $ini_array["accesskey"];
+
+ $this->queueToDelete = array();
+ $this->topicToDelete = array();
+
+ $this->client = new Client($this->endPoint, $this->accessId, $this->accessKey);
+ }
+
+ public function tearDown()
+ {
+ foreach ($this->queueToDelete as $queueName)
+ {
+ try {
+ $this->client->deleteQueue($queueName);
+ } catch (\Exception $e) {
+ }
+ }
+ foreach ($this->topicToDelete as $topicName)
+ {
+ try {
+ $this->client->deleteTopic($topicName);
+ } catch (\Exception $e) {
+ }
+ }
+ }
+
+ public function testAccountAttributes()
+ {
+ try
+ {
+ $attributes = new AccountAttributes;
+ $attributes->setLoggingBucket("Test");
+ $this->client->setAccountAttributes($attributes);
+ $res = $this->client->getAccountAttributes();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals("Test", $res->getAccountAttributes()->getLoggingBucket());
+
+ $attributes = new AccountAttributes;
+ $this->client->setAccountAttributes($attributes);
+ $res = $this->client->getAccountAttributes();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals("Test", $res->getAccountAttributes()->getLoggingBucket());
+
+ $attributes = new AccountAttributes;
+ $attributes->setLoggingBucket("");
+ $this->client->setAccountAttributes($attributes);
+ $res = $this->client->getAccountAttributes();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals("", $res->getAccountAttributes()->getLoggingBucket());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::INVALID_ARGUMENT);
+ }
+ }
+
+ public function testCreateQueueAsync()
+ {
+ $queueName = "testCreateQueueAsync";
+ $request = new CreateQueueRequest($queueName);
+ $this->queueToDelete[] = $queueName;
+
+ // Async Call with callback
+ try
+ {
+ $res = $this->client->createQueueAsync($request,
+ new AsyncCallback(
+ function($response) {
+ $this->assertTrue($response->isSucceed());
+ },
+ function($e) {
+ $this->assertTrue(FALSE, $e);
+ }
+ )
+ );
+ $res = $res->wait();
+
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // Async call without callback
+ try
+ {
+ $res = $this->client->createQueueAsync($request);
+ $res = $res->wait();
+
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testCreateQueueSync()
+ {
+ $queueName = "testCreateQueueSync";
+
+ // 1. create queue with InvalidArgument
+ $attributes = new QueueAttributes;
+ $attributes->setPollingWaitSeconds(60);
+
+ $request = new CreateQueueRequest($queueName, $attributes);
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue(FALSE, "Should throw InvalidArgumentException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::INVALID_ARGUMENT);
+ }
+
+ // 2. create queue
+ $request = new CreateQueueRequest($queueName);
+ $this->queueToDelete[] = $queueName;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 3. create queue with same attributes
+ $request = new CreateQueueRequest($queueName);
+ $this->queueToDelete[] = $queueName;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 4. create same queue with different attributes
+ $attributes = new QueueAttributes;
+ $attributes->setPollingWaitSeconds(20);
+
+ $request = new CreateQueueRequest($queueName, $attributes);
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue(FALSE, "Should throw QueueAlreadyExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::QUEUE_ALREADY_EXIST);
+ }
+ }
+
+ public function testListQueue()
+ {
+ $queueNamePrefix = uniqid();
+ $queueName1 = $queueNamePrefix . "testListQueue1";
+ $queueName2 = $queueNamePrefix . "testListQueue2";
+
+ // 1. create queue
+ $request = new CreateQueueRequest($queueName1);
+ $this->queueToDelete[] = $queueName1;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $request = new CreateQueueRequest($queueName2);
+ $this->queueToDelete[] = $queueName2;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 2. list queue
+ $queueName1Found = FALSE;
+ $queueName2Found = FALSE;
+
+ $count = 0;
+ $request = new ListQueueRequest(1, $queueNamePrefix);
+
+ while ($count < 2) {
+ try
+ {
+ $res = $this->client->listQueue($request);
+ $this->assertTrue($res->isSucceed());
+
+ $queueNames = $res->getQueueNames();
+ foreach ($queueNames as $queueName) {
+ if ($queueName == $queueName1) {
+ $queueName1Found = TRUE;
+ } elseif ($queueName == $queueName2) {
+ $queueName2Found = TRUE;
+ } else {
+ $this->assertTrue(FALSE, $queueName . " Should not be here.");
+ }
+ }
+
+ if ($count > 0) {
+ $this->assertTrue($res->isFinished(), implode(", ", $queueNames));
+ }
+ $request->setMarker($res->getNextMarker());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ $count += 1;
+ }
+
+ $this->assertTrue($queueName1Found, $queueName1 . " Not Found!");
+ $this->assertTrue($queueName2Found, $queueName2 . " Not Found!");
+ }
+
+ public function testListQueueAsync()
+ {
+ $queueNamePrefix = uniqid();
+ $queueName1 = $queueNamePrefix . "testListQueue1";
+ $queueName2 = $queueNamePrefix . "testListQueue2";
+
+ // 1. create queue
+ $request = new CreateQueueRequest($queueName1);
+ $this->queueToDelete[] = $queueName1;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $request = new CreateQueueRequest($queueName2);
+ $this->queueToDelete[] = $queueName2;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 2. list queue
+ $queueName1Found = FALSE;
+ $queueName2Found = FALSE;
+
+ $count = 0;
+ $request = new ListQueueRequest(1, $queueNamePrefix);
+
+ while ($count < 2) {
+ try
+ {
+ $res = $this->client->listQueueAsync($request,
+ new AsyncCallback(
+ function($response) use ($count, &$request, $queueName1, $queueName2, &$queueName1Found, &$queueName2Found) {
+ $this->assertTrue($response->isSucceed());
+
+ $queueNames = $response->getQueueNames();
+ foreach ($queueNames as $queueName) {
+ if ($queueName == $queueName1) {
+ $queueName1Found = TRUE;
+ } elseif ($queueName == $queueName2) {
+ $queueName2Found = TRUE;
+ } else {
+ $this->assertTrue(FALSE, $queueName . " Should not be here.");
+ }
+ }
+
+ if ($count > 0) {
+ $this->assertTrue($response->isFinished(), implode(", ", $queueNames));
+ }
+ $request->setMarker($response->getNextMarker());
+ },
+ function($e) {
+ $this->assertTrue(FALSE, $e);
+ }
+ )
+ );
+ $res = $res->wait();
+
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ $count += 1;
+ }
+
+ $this->assertTrue($queueName1Found, $queueName1 . " Not Found!");
+ $this->assertTrue($queueName2Found, $queueName2 . " Not Found!");
+ }
+
+ public function testDeleteQueue()
+ {
+ $queueName = "testDeleteQueue";
+
+ // 1. create queue
+ $request = new CreateQueueRequest($queueName);
+ $this->queueToDelete[] = $queueName;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 2. delete queue
+ try
+ {
+ $res = $this->client->deleteQueue($queueName);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testDeleteQueueAsync()
+ {
+ $queueName = "testDeleteQueueAsync";
+
+ // 1. create queue
+ $request = new CreateQueueRequest($queueName);
+ $this->queueToDelete[] = $queueName;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 2. delete Queue
+ try
+ {
+ $res = $this->client->deleteQueueAsync($queueName);
+ $res = $res->wait();
+
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testCreateTopicSync()
+ {
+ $topicName = "testCreateTopicSync";
+
+ // 1. create topic with InvalidArgument
+ $attributes = new TopicAttributes;
+ $attributes->setMaximumMessageSize(65 * 1024);
+
+ $request = new CreateTopicRequest($topicName, $attributes);
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue(FALSE, "Should throw InvalidArgumentException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::INVALID_ARGUMENT);
+ }
+
+ // 2. create topic
+ $request = new CreateTopicRequest($topicName);
+ $this->topicToDelete[] = $topicName;
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 3. create topic with same attributes
+ $request = new CreateTopicRequest($topicName);
+ $this->topicToDelete[] = $topicName;
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 4. create same topic with different attributes
+ $attributes = new TopicAttributes;
+ $attributes->setMaximumMessageSize(10 * 1024);
+
+ $request = new CreateTopicRequest($topicName, $attributes);
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue(FALSE, "Should throw TopicAlreadyExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::TOPIC_ALREADY_EXIST);
+ }
+ }
+
+ public function testListTopic()
+ {
+ $topicNamePrefix = uniqid();
+ $topicName1 = $topicNamePrefix . "testListTopic1";
+ $topicName2 = $topicNamePrefix . "testListTopic2";
+
+ // 1. create Topic
+ $request = new CreateTopicRequest($topicName1);
+ $this->topicToDelete[] = $topicName1;
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $request = new CreateTopicRequest($topicName2);
+ $this->topicToDelete[] = $topicName2;
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ // 2. list Topic
+ $topicName1Found = FALSE;
+ $topicName2Found = FALSE;
+
+ $count = 0;
+ $request = new ListTopicRequest(1, $topicNamePrefix);
+
+ while ($count < 2) {
+ try
+ {
+ $res = $this->client->listTopic($request);
+ $this->assertTrue($res->isSucceed());
+
+ $topicNames = $res->getTopicNames();
+ foreach ($topicNames as $topicName) {
+ if ($topicName == $topicName1) {
+ $topicName1Found = TRUE;
+ } elseif ($topicName == $topicName2) {
+ $topicName2Found = TRUE;
+ } else {
+ $this->assertTrue(FALSE, $topicName . " Should not be here.");
+ }
+ }
+
+ if ($count > 0) {
+ $this->assertTrue($res->isFinished(), implode(", ", $topicNames));
+ }
+ $request->setMarker($res->getNextMarker());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ $count += 1;
+ }
+
+ $this->assertTrue($topicName1Found, $topicName1 . " Not Found!");
+ $this->assertTrue($topicName2Found, $topicName2 . " Not Found!");
+ }
+}
+
+?>
diff --git a/Lib/Alisms/Tests/QueueTest.php b/Lib/Alisms/Tests/QueueTest.php
new file mode 100644
index 0000000..f2a0050
--- /dev/null
+++ b/Lib/Alisms/Tests/QueueTest.php
@@ -0,0 +1,494 @@
+endPoint = $ini_array["endpoint"];
+ $this->accessId = $ini_array["accessid"];
+ $this->accessKey = $ini_array["accesskey"];
+
+ $this->queueToDelete = array();
+
+ $this->client = new Client($this->endPoint, $this->accessId, $this->accessKey);
+ }
+
+ public function tearDown()
+ {
+ foreach ($this->queueToDelete as $queueName)
+ {
+ try {
+ $this->client->deleteQueue($queueName);
+ } catch (\Exception $e) {
+ }
+ }
+ }
+
+ private function prepareQueue($queueName, $attributes = NULL, $base64=TRUE)
+ {
+ $request = new CreateQueueRequest($queueName, $attributes);
+ $this->queueToDelete[] = $queueName;
+ try
+ {
+ $res = $this->client->createQueue($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ return $this->client->getQueueRef($queueName, $base64);
+ }
+
+ public function testLoggingEnabled()
+ {
+ $queueName = "testLoggingEnabled";
+ $queue = $this->prepareQueue($queueName);
+
+ try
+ {
+ $attributes = new QueueAttributes;
+ $attributes->setLoggingEnabled(false);
+ $queue->setAttribute($attributes);
+ $res = $queue->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(false, $res->getQueueAttributes()->getLoggingEnabled());
+
+ $attributes = new QueueAttributes;
+ $attributes->setLoggingEnabled(true);
+ $queue->setAttribute($attributes);
+ $res = $queue->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(true, $res->getQueueAttributes()->getLoggingEnabled());
+
+ $attributes = new QueueAttributes;
+ $queue->setAttribute($attributes);
+ $res = $queue->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(true, $res->getQueueAttributes()->getLoggingEnabled());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testQueueAttributes()
+ {
+ $queueName = "testQueueAttributes";
+ $queue = $this->prepareQueue($queueName);
+
+ try
+ {
+ $res = $queue->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals($queueName, $res->getQueueAttributes()->getQueueName());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $delaySeconds = 3;
+ $attributes = new QueueAttributes;
+ $attributes->setDelaySeconds($delaySeconds);
+ try
+ {
+ $res = $queue->setAttribute($attributes);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $queue->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals($res->getQueueAttributes()->getDelaySeconds(), $delaySeconds);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testMessageDelaySeconds()
+ {
+ $queueName = "testMessageDelaySeconds" . uniqid();
+ $queue = $this->prepareQueue($queueName, NULL, FALSE);
+
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+ $delaySeconds = 1;
+ $request = new SendMessageRequest($messageBody, $delaySeconds);
+ $receiptHandle = NULL;
+ try
+ {
+ $res = $queue->sendMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testMessageNoBase64()
+ {
+ $queueName = "testQueueAttributes" . uniqid();
+ $queue = $this->prepareQueue($queueName, NULL, FALSE);
+
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+ $request = new SendMessageRequest($messageBody);
+ try
+ {
+ $res = $queue->sendMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $queue->peekMessage();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $receiptHandle = NULL;
+ try
+ {
+ $res = $queue->receiveMessage();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+
+ $receiptHandle = $res->getReceiptHandle();
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $newReceiptHandle = NULL;
+ try
+ {
+ $res = $queue->changeMessageVisibility($receiptHandle, 18);
+ $this->assertTrue($res->isSucceed());
+ $newReceiptHandle = $res->getReceiptHandle();
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $queue->deleteMessage($receiptHandle);
+ $this->assertTrue(FALSE, "Should NOT reach here!");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals(Constants::MESSAGE_NOT_EXIST, $e->getMnsErrorCode());
+ }
+
+ try
+ {
+ $res = $queue->deleteMessage($newReceiptHandle);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testMessage()
+ {
+ $queueName = "testQueueAttributes" . uniqid();
+ $queue = $this->prepareQueue($queueName);
+
+ $messageBody = "test";
+ $bodyMD5 = md5(base64_encode($messageBody));
+ $request = new SendMessageRequest($messageBody);
+ try
+ {
+ $res = $queue->sendMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $queue->peekMessage();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $receiptHandle = NULL;
+ try
+ {
+ $res = $queue->receiveMessage();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+
+ $receiptHandle = $res->getReceiptHandle();
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $newReceiptHandle = NULL;
+ try
+ {
+ $res = $queue->changeMessageVisibility($receiptHandle, 18);
+ $this->assertTrue($res->isSucceed());
+ $newReceiptHandle = $res->getReceiptHandle();
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $queue->deleteMessage($receiptHandle);
+ $this->assertTrue(FALSE, "Should NOT reach here!");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals(Constants::MESSAGE_NOT_EXIST, $e->getMnsErrorCode());
+ }
+
+ try
+ {
+ $res = $queue->deleteMessage($newReceiptHandle);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testBatchNoBase64()
+ {
+ $queueName = "testBatch" . uniqid();
+ $queue = $this->prepareQueue($queueName, NULL, FALSE);
+
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+
+ $numOfMessages = 3;
+
+ $item = new SendMessageRequestItem($messageBody);
+ $items = array($item, $item, $item);
+ $request = new BatchSendMessageRequest($items);
+ try
+ {
+ $res = $queue->batchSendMessage($request);
+ $this->assertTrue($res->isSucceed());
+
+ $responseItems = $res->getSendMessageResponseItems();
+ $this->assertTrue(count($responseItems) == 3);
+ foreach ($responseItems as $item)
+ {
+ $this->assertEquals(strtoupper($bodyMD5), $item->getMessageBodyMD5());
+ }
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ if ($e instanceof BatchSendFailException)
+ {
+ var_dump($e->getSendMessageResponseItems());
+ }
+ }
+
+ try
+ {
+ $res = $queue->batchPeekMessage($numOfMessages);
+ $this->assertTrue($res->isSucceed());
+
+ $messages = $res->getMessages();
+ $this->assertEquals($numOfMessages, count($messages));
+ foreach ($messages as $message)
+ {
+ $this->assertEquals(strtoupper($bodyMD5), $message->getMessageBodyMD5());
+ }
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $receiptHandles = array();
+ $request = new BatchReceiveMessageRequest($numOfMessages);
+ try
+ {
+ $res = $queue->batchReceiveMessage($request);
+ $this->assertTrue($res->isSucceed());
+
+ $messages = $res->getMessages();
+ $this->assertEquals($numOfMessages, count($messages));
+ foreach ($messages as $message)
+ {
+ $this->assertEquals(strtoupper($bodyMD5), $message->getMessageBodyMD5());
+ $receiptHandles[] = $message->getReceiptHandle();
+ }
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $errorReceiptHandle = "1-ODU4OTkzNDU5My0xNDM1MTk3NjAwLTItNg==";
+ $receiptHandles[] = $errorReceiptHandle;
+ try
+ {
+ $res = $queue->batchDeleteMessage($receiptHandles);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue($e instanceof BatchDeleteFailException);
+ $items = $e->getDeleteMessageErrorItems();
+ $this->assertEquals(1, count($items));
+ $this->assertEquals($errorReceiptHandle, $items[0]->getReceiptHandle());
+ }
+ }
+
+ public function testBatch()
+ {
+ $queueName = "testBatch" . uniqid();
+ $queue = $this->prepareQueue($queueName);
+
+ $messageBody = "test";
+ $bodyMD5 = md5(base64_encode($messageBody));
+
+ $numOfMessages = 3;
+
+ $item = new SendMessageRequestItem($messageBody);
+ $items = array($item, $item, $item);
+ $request = new BatchSendMessageRequest($items);
+ try
+ {
+ $res = $queue->batchSendMessage($request);
+ $this->assertTrue($res->isSucceed());
+
+ $responseItems = $res->getSendMessageResponseItems();
+ foreach ($responseItems as $item)
+ {
+ $this->assertEquals(strtoupper($bodyMD5), $item->getMessageBodyMD5());
+ }
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ if ($e instanceof BatchSendFailException)
+ {
+ var_dump($e->getSendMessageResponseItems());
+ }
+ }
+
+ try
+ {
+ $res = $queue->batchPeekMessage($numOfMessages);
+ $this->assertTrue($res->isSucceed());
+
+ $messages = $res->getMessages();
+ $this->assertEquals($numOfMessages, count($messages));
+ foreach ($messages as $message)
+ {
+ $this->assertEquals(strtoupper($bodyMD5), $message->getMessageBodyMD5());
+ }
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $receiptHandles = array();
+ $request = new BatchReceiveMessageRequest($numOfMessages);
+ try
+ {
+ $res = $queue->batchReceiveMessage($request);
+ $this->assertTrue($res->isSucceed());
+
+ $messages = $res->getMessages();
+ $this->assertEquals($numOfMessages, count($messages));
+ foreach ($messages as $message)
+ {
+ $this->assertEquals(strtoupper($bodyMD5), $message->getMessageBodyMD5());
+ $receiptHandles[] = $message->getReceiptHandle();
+ }
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $errorReceiptHandle = "1-ODU4OTkzNDU5My0xNDM1MTk3NjAwLTItNg==";
+ $receiptHandles[] = $errorReceiptHandle;
+ try
+ {
+ $res = $queue->batchDeleteMessage($receiptHandles);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue($e instanceof BatchDeleteFailException);
+ $items = $e->getDeleteMessageErrorItems();
+ $this->assertEquals(1, count($items));
+ $this->assertEquals($errorReceiptHandle, $items[0]->getReceiptHandle());
+ }
+ }
+}
+
+?>
diff --git a/Lib/Alisms/Tests/TopicTest.php b/Lib/Alisms/Tests/TopicTest.php
new file mode 100644
index 0000000..3b158e5
--- /dev/null
+++ b/Lib/Alisms/Tests/TopicTest.php
@@ -0,0 +1,522 @@
+endPoint = $ini_array["endpoint"];
+ $this->accessId = $ini_array["accessid"];
+ $this->accessKey = $ini_array["accesskey"];
+
+ $this->topicToDelete = array();
+
+ $this->client = new Client($this->endPoint, $this->accessId, $this->accessKey);
+ }
+
+ public function tearDown()
+ {
+ foreach ($this->topicToDelete as $topicName)
+ {
+ try
+ {
+ $this->client->deleteTopic($topicName);
+ }
+ catch (\Exception $e)
+ {
+ }
+ }
+ }
+
+ private function prepareTopic($topicName, $attributes = NULL)
+ {
+ $request = new CreateTopicRequest($topicName, $attributes);
+ $this->topicToDelete[] = $topicName;
+ try
+ {
+ $res = $this->client->createTopic($request);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ return $this->client->getTopicRef($topicName);
+ }
+
+ private function prepareSubscription(Topic $topic, $subscriptionName)
+ {
+ try
+ {
+ $attributes = new SubscriptionAttributes($subscriptionName, 'http://127.0.0.1', 'BACKOFF_RETRY', 'XML');
+ $topic->subscribe($attributes);
+ }
+ catch (MnsException $e)
+ {
+ }
+ }
+
+ public function testLoggingEnabled()
+ {
+ $topicName = "testLoggingEnabled";
+ $topic = $this->prepareTopic($topicName);
+
+ try
+ {
+ $attributes = new TopicAttributes;
+ $attributes->setLoggingEnabled(false);
+ $topic->setAttribute($attributes);
+ $res = $topic->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(false, $res->getTopicAttributes()->getLoggingEnabled());
+
+ $attributes = new TopicAttributes;
+ $attributes->setLoggingEnabled(true);
+ $topic->setAttribute($attributes);
+ $res = $topic->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(true, $res->getTopicAttributes()->getLoggingEnabled());
+
+ $attributes = new TopicAttributes;
+ $topic->setAttribute($attributes);
+ $res = $topic->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(true, $res->getTopicAttributes()->getLoggingEnabled());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ }
+
+ public function testTopicAttributes()
+ {
+ $topicName = "testTopicAttributes";
+ $topic = $this->prepareTopic($topicName);
+
+ try
+ {
+ $res = $topic->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals($topicName, $res->getTopicAttributes()->getTopicName());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $maximumMessageSize = 10 * 1024;
+ $attributes = new TopicAttributes;
+ $attributes->setMaximumMessageSize($maximumMessageSize);
+ try
+ {
+ $res = $topic->setAttribute($attributes);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $topic->getAttribute();
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals($res->getTopicAttributes()->getMaximumMessageSize(), $maximumMessageSize);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $this->client->deleteTopic($topicName);
+
+ try
+ {
+ $res = $topic->getAttribute();
+ $this->assertTrue(False, "Should throw TopicNotExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::TOPIC_NOT_EXIST);
+ }
+
+ try
+ {
+ $res = $topic->setAttribute($attributes);
+ $this->assertTrue(False, "Should throw TopicNotExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::TOPIC_NOT_EXIST);
+ }
+ }
+
+ public function testPublishMessage()
+ {
+ $topicName = "testPublishMessage" . uniqid();
+
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+ $request = new PublishMessageRequest($messageBody);
+
+ $topic = $this->prepareTopic($topicName);
+ try
+ {
+ $res = $topic->publishMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $this->client->deleteTopic($topic->getTopicName());
+ try
+ {
+ $res = $topic->publishMessage($request);
+ $this->assertTrue(False, "Should throw TopicNotExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::TOPIC_NOT_EXIST);
+ }
+ }
+
+ public function testPublishBatchSmsMessage()
+ {
+ $topicName = "testPublishBatchSmsMessage" . uniqid();
+
+ // now sub and send message
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+
+ $topic = $this->prepareTopic($topicName);
+ try
+ {
+ $smsEndpoint = $topic->generateSmsEndpoint();
+
+ $subscriptionName = 'testSubscribeSubscription' . uniqid();
+ $attributes = new SubscriptionAttributes($subscriptionName, $smsEndpoint);
+ $topic->subscribe($attributes);
+
+ $batchSmsAttributes = new BatchSmsAttributes("陈舟锋", "SMS_15535414");
+ $batchSmsAttributes->addReceiver("13735576932", array("name" => "phpsdk-batchsms"));
+ $messageAttributes = new MessageAttributes(array($batchSmsAttributes));
+ $request = new PublishMessageRequest($messageBody, $messageAttributes);
+
+ $res = $topic->publishMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ echo $res->getMessageId();
+ sleep(5);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $this->client->deleteTopic($topic->getTopicName());
+ }
+
+ public function testPublishDirectSmsMessage()
+ {
+ $topicName = "testPublishDirectSmsMessage" . uniqid();
+
+ // now sub and send message
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+
+ $topic = $this->prepareTopic($topicName);
+ try
+ {
+ $smsEndpoint = $topic->generateSmsEndpoint();
+
+ $subscriptionName = 'testSubscribeSubscription' . uniqid();
+ $attributes = new SubscriptionAttributes($subscriptionName, $smsEndpoint);
+ $topic->subscribe($attributes);
+
+ $smsParams = array("name" => "phpsdk");
+ $smsAttributes = new SmsAttributes("陈舟锋", "SMS_15535414", $smsParams, "13735576932");
+ $messageAttributes = new MessageAttributes($smsAttributes);
+ $request = new PublishMessageRequest($messageBody, $messageAttributes);
+
+ $res = $topic->publishMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ echo $res->getMessageId();
+ sleep(5);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $this->client->deleteTopic($topic->getTopicName());
+ }
+
+ public function testPublishMailMessage()
+ {
+ $topicName = "testPublishMailMessage" . uniqid();
+
+ // now sub and send message
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+
+ $topic = $this->prepareTopic($topicName);
+ try
+ {
+ $mailEndpoint = $topic->generateMailEndpoint("liji.canglj@alibaba-inc.com");
+
+ $subscriptionName = 'testSubscribeSubscription' . uniqid();
+ $attributes = new SubscriptionAttributes($subscriptionName, $mailEndpoint);
+ $topic->subscribe($attributes);
+
+ $mailAttributes = new MailAttributes("TestSubject", "TestAccountName");
+ $messageAttributes = new MessageAttributes($mailAttributes);
+ $request = new PublishMessageRequest($messageBody, $messageAttributes);
+
+ $res = $topic->publishMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+ echo $res->getMessageId();
+ sleep(5);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $this->client->deleteTopic($topic->getTopicName());
+ }
+
+ public function testPublishQueueMessage()
+ {
+ $topicName = "testPublishQueueMessage" . uniqid();
+
+ // prepare the queue
+ $queueName = "testPublishQueueMessageQueue";
+ $this->client->deleteQueue($queueName);
+ $request = new CreateQueueRequest($queueName);
+ $this->client->createQueue($request);
+
+ // now sub and send message
+ $messageBody = "test";
+ $bodyMD5 = md5($messageBody);
+
+ $topic = $this->prepareTopic($topicName);
+ try
+ {
+ $queue = $this->client->getQueueRef($queueName, FALSE);
+
+ $queueEndpoint = $topic->generateQueueEndpoint($queueName);
+ //echo($queueEndpoint);
+
+ $subscriptionName = 'testSubscribeSubscription' . uniqid();
+ $attributes = new SubscriptionAttributes($subscriptionName, $queueEndpoint);
+ $topic->subscribe($attributes);
+
+ $request = new PublishMessageRequest($messageBody);
+
+ $res = $topic->publishMessage($request);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals(strtoupper($bodyMD5), $res->getMessageBodyMD5());
+
+ $res = $queue->receiveMessage(30);
+ $this->assertTrue(strpos($res->getMessageBody(), "" . $messageBody . "") >= 0);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $this->client->deleteTopic($topic->getTopicName());
+ $this->client->deleteQueue($queueName);
+ }
+
+ public function testSubscribe()
+ {
+ $topicName = 'testSubscribeTopic' . uniqid();
+ $topic = $this->prepareTopic($topicName);
+
+ $subscriptionName = 'testSubscribeSubscription' . uniqid();
+ $attributes = new SubscriptionAttributes($subscriptionName, 'http://127.0.0.1', 'BACKOFF_RETRY', 'XML');
+ try
+ {
+ $topic->subscribe($attributes);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $attributes->setContentFormat('SIMPLIFIED');
+ $res = $topic->subscribe($attributes);
+ $this->assertTrue(False, "Should throw SubscriptionAlreadyExist");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::SUBSCRIPTION_ALREADY_EXIST);
+ }
+
+ $topic->unsubscribe($subscriptionName);
+ }
+
+ public function testSubscriptionAttributes()
+ {
+ $topicName = "testSubscriptionAttributes" . uniqid();
+ $subscriptionName = "testSubscriptionAttributes" . uniqid();
+ $topic = $this->prepareTopic($topicName);
+ $this->prepareSubscription($topic, $subscriptionName);
+
+ try
+ {
+ $res = $topic->getSubscriptionAttribute($subscriptionName);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals($topicName, $res->getSubscriptionAttributes()->getTopicName());
+ $this->assertEquals('BACKOFF_RETRY', $res->getSubscriptionAttributes()->getStrategy());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $strategy = 'EXPONENTIAL_DECAY_RETRY';
+ $attributes = new UpdateSubscriptionAttributes($subscriptionName);
+ $attributes->setStrategy($strategy);
+ try
+ {
+ $res = $topic->setSubscriptionAttribute($attributes);
+ $this->assertTrue($res->isSucceed());
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ try
+ {
+ $res = $topic->getSubscriptionAttribute($subscriptionName);
+ $this->assertTrue($res->isSucceed());
+ $this->assertEquals($res->getSubscriptionAttributes()->getStrategy(), $strategy);
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+
+ $topic->unsubscribe($subscriptionName);
+
+ try
+ {
+ $res = $topic->getSubscriptionAttribute($subscriptionName);
+ $this->assertTrue(False, "Should throw SubscriptionNotExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::SUBSCRIPTION_NOT_EXIST);
+ }
+
+ try
+ {
+ $res = $topic->setSubscriptionAttribute($attributes);
+ $this->assertTrue(False, "Should throw SubscriptionNotExistException");
+ }
+ catch (MnsException $e)
+ {
+ $this->assertEquals($e->getMnsErrorCode(), Constants::SUBSCRIPTION_NOT_EXIST);
+ }
+ }
+
+ public function testListSubscriptions()
+ {
+ $topicName = "testListSubscriptionsTopic" . uniqid();
+ $subscriptionNamePrefix = uniqid();
+ $subscriptionName1 = $subscriptionNamePrefix . "testListTopic1";
+ $subscriptionName2 = $subscriptionNamePrefix . "testListTopic2";
+
+ // 1. create Topic and Subscriptions
+ $topic = $this->prepareTopic($topicName);
+ $this->prepareSubscription($topic, $subscriptionName1);
+ $this->prepareSubscription($topic, $subscriptionName2);
+
+ // 2. list subscriptions
+ $subscriptionName1Found = FALSE;
+ $subscriptionName2Found = FALSE;
+
+ $count = 0;
+ $marker = '';
+ while ($count < 2) {
+ try
+ {
+ $res = $topic->listSubscription(1, $subscriptionNamePrefix, $marker);
+ $this->assertTrue($res->isSucceed());
+
+ $subscriptionNames = $res->getSubscriptionNames();
+ foreach ($subscriptionNames as $subscriptionName)
+ {
+ if ($subscriptionName == $subscriptionName1)
+ {
+ $subscriptionName1Found = TRUE;
+ }
+ elseif ($subscriptionName == $subscriptionName2)
+ {
+ $subscriptionName2Found = TRUE;
+ }
+ else
+ {
+ $this->assertTrue(FALSE, $subscriptionName . " Should not be here.");
+ }
+ }
+
+ if ($count > 0)
+ {
+ $this->assertTrue($res->isFinished(), implode(", ", $subscriptionNames));
+ }
+ $marker = $res->getNextMarker();
+ }
+ catch (MnsException $e)
+ {
+ $this->assertTrue(FALSE, $e);
+ }
+ $count += 1;
+ }
+
+ $this->assertTrue($subscriptionName1Found, $subscriptionName1 . " Not Found!");
+ $this->assertTrue($subscriptionName2Found, $subscriptionName2 . " Not Found!");
+ }
+}
+
+?>
diff --git a/Lib/Alisms/Tests/aliyun-mns.ini b/Lib/Alisms/Tests/aliyun-mns.ini
new file mode 100644
index 0000000..2dcc3e1
--- /dev/null
+++ b/Lib/Alisms/Tests/aliyun-mns.ini
@@ -0,0 +1,3 @@
+endpoint =
+accessid =
+accesskey =
diff --git a/Lib/Alisms/mns-autoloader.php b/Lib/Alisms/mns-autoloader.php
new file mode 100644
index 0000000..b274187
--- /dev/null
+++ b/Lib/Alisms/mns-autoloader.php
@@ -0,0 +1,183 @@
+ __DIR__ . '/AliyunMNS/Client.php',
+ 'AliyunMNS\Config' => __DIR__ . '/AliyunMNS/Config.php',
+ 'AliyunMNS\Constants' => __DIR__ . '/AliyunMNS/Constants.php',
+ 'AliyunMNS\Queue' => __DIR__ . '/AliyunMNS/Queue.php',
+ 'AliyunMNS\Topic' => __DIR__ . '/AliyunMNS/Topic.php',
+ 'AliyunMNS\AsyncCallback' => __DIR__ . '/AliyunMNS/AsyncCallback.php',
+ 'AliyunMNS\Common\XMLParser' => __DIR__ . '/AliyunMNS/Common/XMLParser.php',
+ 'AliyunMNS\Exception\MnsException' => __DIR__ . '/AliyunMNS/Exception/MnsException.php',
+ 'AliyunMNS\Exception\BatchDeleteFailException' => __DIR__ . '/AliyunMNS/Exception/BatchDeleteFailException.php',
+ 'AliyunMNS\Exception\InvalidArgumentException' => __DIR__ . '/AliyunMNS/Exception/InvalidArgumentException.php',
+ 'AliyunMNS\Exception\MessageNotExistException' => __DIR__ . '/AliyunMNS/Exception/MessageNotExistException.php',
+ 'AliyunMNS\Exception\QueueAlreadyExistException' => __DIR__ . '/AliyunMNS/Exception/QueueAlreadyExistException.php',
+ 'AliyunMNS\Exception\ReceiptHandleErrorException' => __DIR__ . '/AliyunMNS/Exception/ReceiptHandleErrorException.php',
+ 'AliyunMNS\Exception\BatchSendFailException' => __DIR__ . '/AliyunMNS/Exception/BatchSendFailException.php',
+ 'AliyunMNS\Exception\MalformedXMLException' => __DIR__ . '/AliyunMNS/Exception/MalformedXMLException.php',
+ 'AliyunMNS\Exception\QueueNotExistException' => __DIR__ . '/AliyunMNS/Exception/QueueNotExistException.php',
+ 'AliyunMNS\Exception\TopicAlreadyExistException' => __DIR__ . '/AliyunMNS/Exception/TopicAlreadyExistException.php',
+ 'AliyunMNS\Exception\TopicNotExistException' => __DIR__ . '/AliyunMNS/Exception/TopicNotExistException.php',
+ 'AliyunMNS\Exception\SubscriptionAlreadyExistException' => __DIR__ . '/AliyunMNS/Exception/SubscriptionAlreadyExistException.php',
+ 'AliyunMNS\Exception\SubscriptionNotExistException' => __DIR__ . '/AliyunMNS/Exception/SubscriptionNotExistException.php',
+ 'AliyunMNS\Http\HttpClient' => __DIR__ . '/AliyunMNS/Http/HttpClient.php',
+ 'AliyunMNS\Model\DeleteMessageErrorItem' => __DIR__ . '/AliyunMNS/Model/DeleteMessageErrorItem.php',
+ 'AliyunMNS\Model\Message' => __DIR__ . '/AliyunMNS/Model/Message.php',
+ 'AliyunMNS\Model\QueueAttributes' => __DIR__ . '/AliyunMNS/Model/QueueAttributes.php',
+ 'AliyunMNS\Model\MessageAttributes' => __DIR__ . '/AliyunMNS/Model/MessageAttributes.php',
+ 'AliyunMNS\Model\MailAttributes' => __DIR__ . '/AliyunMNS/Model/MailAttributes.php',
+ 'AliyunMNS\Model\SmsAttributes' => __DIR__ . '/AliyunMNS/Model/SmsAttributes.php',
+ 'AliyunMNS\Model\BatchSmsAttributes' => __DIR__ . '/AliyunMNS/Model/BatchSmsAttributes.php',
+ 'AliyunMNS\Model\WebSocketAttributes' => __DIR__ . '/AliyunMNS/Model/WebSocketAttributes.php',
+ 'AliyunMNS\Model\TopicAttributes' => __DIR__ . '/AliyunMNS/Model/TopicAttributes.php',
+ 'AliyunMNS\Model\AccountAttributes' => __DIR__ . '/AliyunMNS/Model/AccountAttributes.php',
+ 'AliyunMNS\Model\SubscriptionAttributes' => __DIR__ . '/AliyunMNS/Model/SubscriptionAttributes.php',
+ 'AliyunMNS\Model\UpdateSubscriptionAttributes' => __DIR__ . '/AliyunMNS/Model/UpdateSubscriptionAttributes.php',
+ 'AliyunMNS\Model\SendMessageRequestItem' => __DIR__ . '/AliyunMNS/Model/SendMessageRequestItem.php',
+ 'AliyunMNS\Model\SendMessageResponseItem' => __DIR__ . '/AliyunMNS/Model/SendMessageResponseItem.php',
+ 'AliyunMNS\Signature\Signature' => __DIR__ . '/AliyunMNS/Signature/Signature.php',
+ 'AliyunMNS\Traits\MessageIdAndMD5' => __DIR__ . '/AliyunMNS/Traits/MessageIdAndMD5.php',
+ 'AliyunMNS\Traits\MessagePropertiesForPeek' => __DIR__ . '/AliyunMNS/Traits/MessagePropertiesForPeek.php',
+ 'AliyunMNS\Traits\MessagePropertiesForReceive' => __DIR__ . '/AliyunMNS/Traits/MessagePropertiesForReceive.php',
+ 'AliyunMNS\Traits\MessagePropertiesForSend' => __DIR__ . '/AliyunMNS/Traits/MessagePropertiesForSend.php',
+ 'AliyunMNS\Traits\MessagePropertiesForPublish' => __DIR__ . '/AliyunMNS/Traits/MessagePropertiesForPublish.php',
+ 'AliyunMNS\Requests\BaseRequest' => __DIR__ . '/AliyunMNS/Requests/BaseRequest.php',
+ 'AliyunMNS\Requests\BatchDeleteMessageRequest' => __DIR__ . '/AliyunMNS/Requests/BatchDeleteMessageRequest.php',
+ 'AliyunMNS\Requests\BatchPeekMessageRequest' => __DIR__ . '/AliyunMNS/Requests/BatchPeekMessageRequest.php',
+ 'AliyunMNS\Requests\BatchReceiveMessageRequest' => __DIR__ . '/AliyunMNS/Requests/BatchReceiveMessageRequest.php',
+ 'AliyunMNS\Requests\BatchSendMessageRequest' => __DIR__ . '/AliyunMNS/Requests/BatchSendMessageRequest.php',
+ 'AliyunMNS\Requests\ChangeMessageVisibilityRequest' => __DIR__ . '/AliyunMNS/Requests/ChangeMessageVisibilityRequest.php',
+ 'AliyunMNS\Requests\CreateQueueRequest' => __DIR__ . '/AliyunMNS/Requests/CreateQueueRequest.php',
+ 'AliyunMNS\Requests\DeleteMessageRequest' => __DIR__ . '/AliyunMNS/Requests/DeleteMessageRequest.php',
+ 'AliyunMNS\Requests\DeleteQueueRequest' => __DIR__ . '/AliyunMNS/Requests/DeleteQueueRequest.php',
+ 'AliyunMNS\Requests\GetQueueAttributeRequest' => __DIR__ . '/AliyunMNS/Requests/GetQueueAttributeRequest.php',
+ 'AliyunMNS\Requests\GetAccountAttributesRequest' => __DIR__ . '/AliyunMNS/Requests/GetAccountAttributesRequest.php',
+ 'AliyunMNS\Requests\ListQueueRequest' => __DIR__ . '/AliyunMNS/Requests/ListQueueRequest.php',
+ 'AliyunMNS\Requests\PeekMessageRequest' => __DIR__ . '/AliyunMNS/Requests/PeekMessageRequest.php',
+ 'AliyunMNS\Requests\ReceiveMessageRequest' => __DIR__ . '/AliyunMNS/Requests/ReceiveMessageRequest.php',
+ 'AliyunMNS\Requests\SendMessageRequest' => __DIR__ . '/AliyunMNS/Requests/SendMessageRequest.php',
+ 'AliyunMNS\Requests\SetQueueAttributeRequest' => __DIR__ . '/AliyunMNS/Requests/SetQueueAttributeRequest.php',
+ 'AliyunMNS\Requests\SetAccountAttributesRequest' => __DIR__ . '/AliyunMNS/Requests/SetAccountAttributesRequest.php',
+ 'AliyunMNS\Requests\CreateTopicRequest' => __DIR__ . '/AliyunMNS/Requests/CreateTopicRequest.php',
+ 'AliyunMNS\Requests\DeleteTopicRequest' => __DIR__ . '/AliyunMNS/Requests/DeleteTopicRequest.php',
+ 'AliyunMNS\Requests\ListTopicRequest' => __DIR__ . '/AliyunMNS/Requests/ListTopicRequest.php',
+ 'AliyunMNS\Requests\GetTopicAttributeRequest' => __DIR__ . '/AliyunMNS/Requests/GetTopicAttributeRequest.php',
+ 'AliyunMNS\Requests\SetTopicAttributeRequest' => __DIR__ . '/AliyunMNS/Requests/SetTopicAttributeRequest.php',
+ 'AliyunMNS\Requests\PublishMessageRequest' => __DIR__ . '/AliyunMNS/Requests/PublishMessageRequest.php',
+ 'AliyunMNS\Requests\SubscribeRequest' => __DIR__ . '/AliyunMNS/Requests/SubscribeRequest.php',
+ 'AliyunMNS\Requests\UnsubscribeRequest' => __DIR__ . '/AliyunMNS/Requests/UnsubscribeRequest.php',
+ 'AliyunMNS\Requests\GetSubscriptionAttributeRequest' => __DIR__ . '/AliyunMNS/Requests/GetSubscriptionAttributeRequest.php',
+ 'AliyunMNS\Requests\SetSubscriptionAttributeRequest' => __DIR__ . '/AliyunMNS/Requests/SetSubscriptionAttributeRequest.php',
+ 'AliyunMNS\Requests\ListSubscriptionRequest' => __DIR__ . '/AliyunMNS/Requests/ListSubscriptionRequest.php',
+ 'AliyunMNS\Responses\BaseResponse' => __DIR__ . '/AliyunMNS/Responses/BaseResponse.php',
+ 'AliyunMNS\Responses\BatchDeleteMessageResponse' => __DIR__ . '/AliyunMNS/Responses/BatchDeleteMessageResponse.php',
+ 'AliyunMNS\Responses\BatchPeekMessageResponse' => __DIR__ . '/AliyunMNS/Responses/BatchPeekMessageResponse.php',
+ 'AliyunMNS\Responses\BatchReceiveMessageResponse' => __DIR__ . '/AliyunMNS/Responses/BatchReceiveMessageResponse.php',
+ 'AliyunMNS\Responses\BatchSendMessageResponse' => __DIR__ . '/AliyunMNS/Responses/BatchSendMessageResponse.php',
+ 'AliyunMNS\Responses\ChangeMessageVisibilityResponse' => __DIR__ . '/AliyunMNS/Responses/ChangeMessageVisibilityResponse.php',
+ 'AliyunMNS\Responses\CreateQueueResponse' => __DIR__ . '/AliyunMNS/Responses/CreateQueueResponse.php',
+ 'AliyunMNS\Responses\DeleteMessageResponse' => __DIR__ . '/AliyunMNS/Responses/DeleteMessageResponse.php',
+ 'AliyunMNS\Responses\DeleteQueueResponse' => __DIR__ . '/AliyunMNS/Responses/DeleteQueueResponse.php',
+ 'AliyunMNS\Responses\GetQueueAttributeResponse' => __DIR__ . '/AliyunMNS/Responses/GetQueueAttributeResponse.php',
+ 'AliyunMNS\Responses\GetAccountAttributesResponse' => __DIR__ . '/AliyunMNS/Responses/GetAccountAttributesResponse.php',
+ 'AliyunMNS\Responses\ListQueueResponse' => __DIR__ . '/AliyunMNS/Responses/ListQueueResponse.php',
+ 'AliyunMNS\Responses\MnsPromise' => __DIR__ . '/AliyunMNS/Responses/MnsPromise.php',
+ 'AliyunMNS\Responses\PeekMessageResponse' => __DIR__ . '/AliyunMNS/Responses/PeekMessageResponse.php',
+ 'AliyunMNS\Responses\ReceiveMessageResponse' => __DIR__ . '/AliyunMNS/Responses/ReceiveMessageResponse.php',
+ 'AliyunMNS\Responses\SendMessageResponse' => __DIR__ . '/AliyunMNS/Responses/SendMessageResponse.php',
+ 'AliyunMNS\Responses\SetQueueAttributeResponse' => __DIR__ . '/AliyunMNS/Responses/SetQueueAttributeResponse.php',
+ 'AliyunMNS\Responses\SetAccountAttributesResponse' => __DIR__ . '/AliyunMNS/Responses/SetAccountAttributesResponse.php',
+ 'AliyunMNS\Responses\CreateTopicResponse' => __DIR__ . '/AliyunMNS/Responses/CreateTopicResponse.php',
+ 'AliyunMNS\Responses\DeleteTopicResponse' => __DIR__ . '/AliyunMNS/Responses/DeleteTopicResponse.php',
+ 'AliyunMNS\Responses\ListTopicResponse' => __DIR__ . '/AliyunMNS/Responses/ListTopicResponse.php',
+ 'AliyunMNS\Responses\GetTopicAttributeResponse' => __DIR__ . '/AliyunMNS/Responses/GetTopicAttributeResponse.php',
+ 'AliyunMNS\Responses\SetTopicAttributeResponse' => __DIR__ . '/AliyunMNS/Responses/SetTopicAttributeResponse.php',
+ 'AliyunMNS\Responses\PublishMessageResponse' => __DIR__ . '/AliyunMNS/Responses/PublishMessageResponse.php',
+ 'AliyunMNS\Responses\SubscribeResponse' => __DIR__ . '/AliyunMNS/Responses/SubscribeResponse.php',
+ 'AliyunMNS\Responses\UnsubscribeResponse' => __DIR__ . '/AliyunMNS/Responses/UnsubscribeResponse.php',
+ 'AliyunMNS\Responses\GetSubscriptionAttributeResponse' => __DIR__ . '/AliyunMNS/Responses/GetSubscriptionAttributeResponse.php',
+ 'AliyunMNS\Responses\SetSubscriptionAttributeResponse' => __DIR__ . '/AliyunMNS/Responses/SetSubscriptionAttributeResponse.php',
+ 'AliyunMNS\Responses\ListSubscriptionResponse' => __DIR__ . '/AliyunMNS/Responses/ListSubscriptionResponse.php',
+ 'GuzzleHttp\Client' => __DIR__ . '/GuzzleHttp/Client.php',
+ 'GuzzleHttp\ClientInterface' => __DIR__ . '/GuzzleHttp/ClientInterface.php',
+ 'GuzzleHttp\Cookie\CookieJar' => __DIR__ . '/GuzzleHttp/Cookie/CookieJar.php',
+ 'GuzzleHttp\Cookie\CookieJarInterface' => __DIR__ . '/GuzzleHttp/Cookie/CookieJarInterface.php',
+ 'GuzzleHttp\Cookie\FileCookieJar' => __DIR__ . '/GuzzleHttp/Cookie/FileCookieJar.php',
+ 'GuzzleHttp\Cookie\SessionCookieJar' => __DIR__ . '/GuzzleHttp/Cookie/SessionCookieJar.php',
+ 'GuzzleHttp\Cookie\SetCookie' => __DIR__ . '/GuzzleHttp/Cookie/SetCookie.php',
+ 'GuzzleHttp\Exception\BadResponseException' => __DIR__ . '/GuzzleHttp/Exception/BadResponseException.php',
+ 'GuzzleHttp\Exception\ClientException' => __DIR__ . '/GuzzleHttp/Exception/ClientException.php',
+ 'GuzzleHttp\Exception\ConnectException' => __DIR__ . '/GuzzleHttp/Exception/ConnectException.php',
+ 'GuzzleHttp\Exception\GuzzleException' => __DIR__ . '/GuzzleHttp/Exception/GuzzleException.php',
+ 'GuzzleHttp\Exception\RequestException' => __DIR__ . '/GuzzleHttp/Exception/RequestException.php',
+ 'GuzzleHttp\Exception\SeekException' => __DIR__ . '/GuzzleHttp/Exception/SeekException.php',
+ 'GuzzleHttp\Exception\ServerException' => __DIR__ . '/GuzzleHttp/Exception/ServerException.php',
+ 'GuzzleHttp\Exception\TooManyRedirectsException' => __DIR__ . '/GuzzleHttp/Exception/TooManyRedirectsException.php',
+ 'GuzzleHttp\Exception\TransferException' => __DIR__ . '/GuzzleHttp/Exception/TransferException.php',
+ 'GuzzleHttp\functions' => __DIR__ . '/GuzzleHttp/functions.php',
+ 'GuzzleHttp\functions_include' => __DIR__ . '/GuzzleHttp/functions_include.php',
+ 'GuzzleHttp\Handler\CurlFactory' => __DIR__ . '/GuzzleHttp/Handler/CurlFactory.php',
+ 'GuzzleHttp\Handler\CurlFactoryInterface' => __DIR__ . '/GuzzleHttp/Handler/CurlFactoryInterface.php',
+ 'GuzzleHttp\Handler\CurlHandler' => __DIR__ . '/GuzzleHttp/Handler/CurlHandler.php',
+ 'GuzzleHttp\Handler\CurlMultiHandler' => __DIR__ . '/GuzzleHttp/Handler/CurlMultiHandler.php',
+ 'GuzzleHttp\Handler\EasyHandle' => __DIR__ . '/GuzzleHttp/Handler/EasyHandle.php',
+ 'GuzzleHttp\Handler\MockHandler' => __DIR__ . '/GuzzleHttp/Handler/MockHandler.php',
+ 'GuzzleHttp\Handler\Proxy' => __DIR__ . '/GuzzleHttp/Handler/Proxy.php',
+ 'GuzzleHttp\Handler\StreamHandler' => __DIR__ . '/GuzzleHttp/Handler/StreamHandler.php',
+ 'GuzzleHttp\HandlerStack' => __DIR__ . '/GuzzleHttp/HandlerStack.php',
+ 'GuzzleHttp\MessageFormatter' => __DIR__ . '/GuzzleHttp/MessageFormatter.php',
+ 'GuzzleHttp\Middleware' => __DIR__ . '/GuzzleHttp/Middleware.php',
+ 'GuzzleHttp\Pool' => __DIR__ . '/GuzzleHttp/Pool.php',
+ 'GuzzleHttp\PrepareBodyMiddleware' => __DIR__ . '/GuzzleHttp/PrepareBodyMiddleware.php',
+ 'GuzzleHttp\Promise\AggregateException' => __DIR__ . '/GuzzleHttp/Promise/AggregateException.php',
+ 'GuzzleHttp\Promise\CancellationException' => __DIR__ . '/GuzzleHttp/Promise/CancellationException.php',
+ 'GuzzleHttp\Promise\EachPromise' => __DIR__ . '/GuzzleHttp/Promise/EachPromise.php',
+ 'GuzzleHttp\Promise\FulfilledPromise' => __DIR__ . '/GuzzleHttp/Promise/FulfilledPromise.php',
+ 'GuzzleHttp\Promise\functions' => __DIR__ . '/GuzzleHttp/Promise/functions.php',
+ 'GuzzleHttp\Promise\functions_include' => __DIR__ . '/GuzzleHttp/Promise/functions_include.php',
+ 'GuzzleHttp\Promise\Promise' => __DIR__ . '/GuzzleHttp/Promise/Promise.php',
+ 'GuzzleHttp\Promise\PromiseInterface' => __DIR__ . '/GuzzleHttp/Promise/PromiseInterface.php',
+ 'GuzzleHttp\Promise\PromisorInterface' => __DIR__ . '/GuzzleHttp/Promise/PromisorInterface.php',
+ 'GuzzleHttp\Promise\RejectedPromise' => __DIR__ . '/GuzzleHttp/Promise/RejectedPromise.php',
+ 'GuzzleHttp\Promise\RejectionException' => __DIR__ . '/GuzzleHttp/Promise/RejectionException.php',
+ 'GuzzleHttp\Promise\TaskQueue' => __DIR__ . '/GuzzleHttp/Promise/TaskQueue.php',
+ 'GuzzleHttp\Psr7\AppendStream' => __DIR__ . '/GuzzleHttp/Psr7/AppendStream.php',
+ 'GuzzleHttp\Psr7\BufferStream' => __DIR__ . '/GuzzleHttp/Psr7/BufferStream.php',
+ 'GuzzleHttp\Psr7\CachingStream' => __DIR__ . '/GuzzleHttp/Psr7/CachingStream.php',
+ 'GuzzleHttp\Psr7\DroppingStream' => __DIR__ . '/GuzzleHttp/Psr7/DroppingStream.php',
+ 'GuzzleHttp\Psr7\FnStream' => __DIR__ . '/GuzzleHttp/Psr7/FnStream.php',
+ 'GuzzleHttp\Psr7\functions' => __DIR__ . '/GuzzleHttp/Psr7/functions.php',
+ 'GuzzleHttp\Psr7\functions_include' => __DIR__ . '/GuzzleHttp/Psr7/functions_include.php',
+ 'GuzzleHttp\Psr7\InflateStream' => __DIR__ . '/GuzzleHttp/Psr7/InflateStream.php',
+ 'GuzzleHttp\Psr7\LazyOpenStream' => __DIR__ . '/GuzzleHttp/Psr7/LazyOpenStream.php',
+ 'GuzzleHttp\Psr7\LimitStream' => __DIR__ . '/GuzzleHttp/Psr7/LimitStream.php',
+ 'GuzzleHttp\Psr7\MessageTrait' => __DIR__ . '/GuzzleHttp/Psr7/MessageTrait.php',
+ 'GuzzleHttp\Psr7\MultipartStream' => __DIR__ . '/GuzzleHttp/Psr7/MultipartStream.php',
+ 'GuzzleHttp\Psr7\NoSeekStream' => __DIR__ . '/GuzzleHttp/Psr7/NoSeekStream.php',
+ 'GuzzleHttp\Psr7\PumpStream' => __DIR__ . '/GuzzleHttp/Psr7/PumpStream.php',
+ 'GuzzleHttp\Psr7\Request' => __DIR__ . '/GuzzleHttp/Psr7/Request.php',
+ 'GuzzleHttp\Psr7\Response' => __DIR__ . '/GuzzleHttp/Psr7/Response.php',
+ 'GuzzleHttp\Psr7\Stream' => __DIR__ . '/GuzzleHttp/Psr7/Stream.php',
+ 'GuzzleHttp\Psr7\StreamDecoratorTrait' => __DIR__ . '/GuzzleHttp/Psr7/StreamDecoratorTrait.php',
+ 'GuzzleHttp\Psr7\StreamWrapper' => __DIR__ . '/GuzzleHttp/Psr7/StreamWrapper.php',
+ 'GuzzleHttp\Psr7\Uri' => __DIR__ . '/GuzzleHttp/Psr7/Uri.php',
+ 'GuzzleHttp\RedirectMiddleware' => __DIR__ . '/GuzzleHttp/RedirectMiddleware.php',
+ 'GuzzleHttp\RequestOptions' => __DIR__ . '/GuzzleHttp/RequestOptions.php',
+ 'GuzzleHttp\RetryMiddleware' => __DIR__ . '/GuzzleHttp/RetryMiddleware.php',
+ 'GuzzleHttp\TransferStats' => __DIR__ . '/GuzzleHttp/TransferStats.php',
+ 'GuzzleHttp\UriTemplate' => __DIR__ . '/GuzzleHttp/UriTemplate.php',
+ 'Psr\Http\Message\MessageInterface' => __DIR__ . '/Psr/Http/Message/MessageInterface.php',
+ 'Psr\Http\Message\RequestInterface' => __DIR__ . '/Psr/Http/Message/RequestInterface.php',
+ 'Psr\Http\Message\ResponseInterface' => __DIR__ . '/Psr/Http/Message/ResponseInterface.php',
+ 'Psr\Http\Message\ServerRequestInterface' => __DIR__ . '/Psr/Http/Message/ServerRequestInterface.php',
+ 'Psr\Http\Message\StreamInterface' => __DIR__ . '/Psr/Http/Message/StreamInterface.php',
+ 'Psr\Http\Message\UploadedFileInterface' => __DIR__ . '/Psr/Http/Message/UploadedFileInterface.php',
+ 'Psr\Http\Message\UriInterface' => __DIR__ . '/Psr/Http/Message/UriInterface.php',
+);
+
+spl_autoload_register(function ($class) use ($mapping) {
+ if (isset($mapping[$class])) {
+ require $mapping[$class];
+ }
+}, true);