OpenSearchClient.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <?php
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. */
  20. namespace OpenSearch\Client;
  21. use OpenSearch\Generated\OpenSearch\OpenSearch;
  22. use OpenSearch\Generated\OpenSearch\Constant;
  23. use OpenSearch\Generated\Common\OpenSearchResult;
  24. use OpenSearch\Generated\Common\TraceInfo;
  25. class OpenSearchClient extends OpenSearch {
  26. const METHOD_GET = 'GET';
  27. const METHOD_POST = 'POST';
  28. const METHOD_PUT = 'PUT';
  29. const METHOD_DELETE = 'DELETE';
  30. const METHOD_PATCH = 'PATCH';
  31. const API_VERSION = '3';
  32. const API_TYPE = 'openapi';
  33. const SDK_VERSION = '3.1.0';
  34. const SDK_TYPE = 'opensearch_sdk';
  35. private $debug = false;
  36. public $timeout = 10;
  37. public $connectTimeout = 1;
  38. /**
  39. * 构造方法。
  40. *
  41. * @param string $accessKey 指定您的accessKeyId,在 https://ak-console.aliyun.com/#/accesskey 中可以创建。
  42. * @param string $secret 指定您的secret。
  43. * @param string $host 指定您要访问的区域的endPoint,在控制台应用详情页中有指定。
  44. * @param array @options 指定一些可选参数,debug:true/false,是否开启debug模式(默认不开启),gzip:true/false 是否开启gzip压缩(默认不开启),timeout:超时时间,seconds(默认10秒),connectTimeout: 连接超时时间,seconds(默认1秒)
  45. * @return void
  46. */
  47. public function __construct($accessKey, $secret, $host, $options = array()) {
  48. $args = array(
  49. 'accessKey' => trim($accessKey),
  50. 'secret' => trim($secret),
  51. 'host' => trim($host),
  52. 'options' => $options
  53. );
  54. if (isset($options['gzip'])) {
  55. $args['gzip'] = $options['gzip'];
  56. }
  57. if (isset($options['timeout'])) {
  58. $args['timeout'] = $options['timeout'];
  59. }
  60. if (isset($options['connectTimeout'])) {
  61. $args['connectTimeout'] = $options['connectTimeout'];
  62. }
  63. if (isset($options['debug'])) {
  64. $this->debug = (boolean) $options['debug'];
  65. }
  66. parent::__construct($args);
  67. }
  68. /**
  69. * 发送一个GET请求。
  70. *
  71. * @param string $uri 发起GET请求的uri。
  72. * @param array $params 发起GET请求的参数,以param_key => param_value的方式体现。
  73. * @return \OpenSearch\Generated\Common\OpenSearchResult
  74. */
  75. public function get($uri, $params = array()) {
  76. return $this->call($uri, $params, '', self::METHOD_GET);
  77. }
  78. /**
  79. * 发送一个PUT请求。
  80. *
  81. * @param string $uri 发起PUT请求的uri。
  82. * @param string $body 发起PUT请求的body体,为一个原始的json格式的string。
  83. * @return \OpenSearch\Generated\Common\OpenSearchResult
  84. */
  85. public function put($uri, $body = '') {
  86. return $this->call($uri, array(), $body, self::METHOD_PUT);
  87. }
  88. /**
  89. * 发送一个POST请求。
  90. *
  91. * @param string $uri 发起POST请求的uri。
  92. * @param string $body 发起POST请求的body体,为一个原始的json格式的string。
  93. * @return \OpenSearch\Generated\Common\OpenSearchResult
  94. */
  95. public function post($uri, $body = '') {
  96. return $this->call($uri, array(), $body, self::METHOD_POST);
  97. }
  98. /**
  99. * 发送一个DELETE请求。
  100. *
  101. * @param string $uri 发起DELETE请求的uri。
  102. * @param string $body 发起DELETE请求的body体,为一个原始的json格式的string。
  103. * @return \OpenSearch\Generated\Common\OpenSearchResult
  104. */
  105. public function delete($uri, $body = '') {
  106. return $this->call($uri, array(), $body, self::METHOD_DELETE);
  107. }
  108. /**
  109. * 发送一个PATCH请求。
  110. *
  111. * @param string $uri 发起PATCH请求的uri。
  112. * @param string $body 发起PATCH请求的body体,为一个原始的json格式的string。
  113. * @return \OpenSearch\Generated\Common\OpenSearchResult
  114. */
  115. public function patch($uri, $body = '') {
  116. return $this->call($uri, array(), $body, self::METHOD_PATCH);
  117. }
  118. /**
  119. * 发送一个请求。
  120. *
  121. * @param string $uri 发起请求的uri。
  122. * @param array $params 指定的url中的query string 列表。
  123. * @param string $body 发起请求的body体,为一个原始的json格式的string。
  124. * @param string $method 发起请求的方法,有GET/POST/DELETE/PUT/PATCH等
  125. * @return \OpenSearch\Generated\Common\OpenSearchResult
  126. */
  127. public function call($uri, array $params, $body, $method) {
  128. $path = "/v" . self::API_VERSION . "/" . self::API_TYPE . "{$uri}";
  129. $url = $this->host . $path;
  130. $items = array();
  131. $items['method'] = $method;
  132. $items['request_path'] = $path;
  133. $items['content_type'] = "application/json";
  134. $items['accept_language'] = "zh-cn";
  135. $items['date'] = gmdate('Y-m-d\TH:i:s\Z');
  136. $items['opensearch_headers'] = array();
  137. $items['content_md5'] = "";
  138. $items['opensearch_headers']['X-Opensearch-Nonce'] = $this->_nonce();
  139. if ($method != self::METHOD_GET) {
  140. if (!empty($body)) {
  141. $items['content_md5'] = md5($body);
  142. $items['body_json'] = $body;
  143. }
  144. }
  145. $items['query_params'] = $params;
  146. $signature = $this->_signature($this->secret, $items);
  147. $items['authorization'] = "OPENSEARCH {$this->accessKey}:{$signature}";
  148. return $this->_curl($url, $items);
  149. }
  150. private function _nonce() {
  151. return intval(microtime(true) * 1000) . mt_rand(10000, 99999);
  152. }
  153. private function _signature($secret, $items) {
  154. $params = isset($items['query_params']) ? $items['query_params'] : "";
  155. $signature = '';
  156. $string = '';
  157. $string .= strtoupper($items['method']) . "\n";
  158. $string .= $items['content_md5'] . "\n";
  159. $string .= $items['content_type'] . "\n";
  160. $string .= $items['date'] . "\n";
  161. $headers = self::_filter($items['opensearch_headers']);
  162. foreach($headers as $key => $value){
  163. $string .= strtolower($key) . ":" . $value."\n";
  164. }
  165. $resource = str_replace('%2F', '/', rawurlencode($items['request_path']));
  166. $sortParams = self::_filter($params);
  167. $queryString = $this->_buildQuery($sortParams);
  168. $canonicalizedResource = $resource;
  169. if(!empty($queryString)){
  170. $canonicalizedResource .= '?'.$queryString;
  171. }
  172. $string .= $canonicalizedResource;
  173. $signature = base64_encode(hash_hmac('sha1', $string, $secret, true));
  174. return $signature;
  175. }
  176. private function _buildQuery($params) {
  177. $query = '';
  178. if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
  179. $query = !empty($params) ? http_build_query($params, null, '&', PHP_QUERY_RFC3986) : '';
  180. } else {
  181. $arg = '';
  182. foreach ($params as $key => $val) {
  183. $arg .= rawurlencode($key) . "=" . rawurlencode($val) . "&";
  184. }
  185. $query = substr($arg, 0, count($arg) - 2);
  186. }
  187. return $query;
  188. }
  189. private function _filter($parameters = array()){
  190. $params = array();
  191. if(!empty($parameters)){
  192. foreach ($parameters as $key => $val) {
  193. if ($key == "Signature" ||$val === "" || $val === NULL){
  194. continue;
  195. } else {
  196. $params[$key] = $parameters[$key];
  197. }
  198. }
  199. uksort($params,'strnatcasecmp');
  200. reset($params);
  201. }
  202. return $params;
  203. }
  204. private function _getHeaders($items) {
  205. $headers = array();
  206. $headers[] = 'Content-Type: '.$items['content_type'];
  207. $headers[] = 'Date: '.$items['date'];
  208. $headers[] = 'Accept-Language: '.$items['accept_language'];
  209. $headers[] = 'Content-Md5: '.$items['content_md5'];
  210. $headers[] = 'Authorization: '.$items['authorization'];
  211. if (is_array($items['opensearch_headers'])) {
  212. foreach($items['opensearch_headers'] as $key => $value){
  213. $headers[] = $key . ": " . $value;
  214. }
  215. }
  216. return $headers;
  217. }
  218. private function _curl($url, $items) {
  219. $method = strtoupper($items['method']);
  220. $options = array(
  221. CURLOPT_HTTP_VERSION => 'CURL_HTTP_VERSION_1_1',
  222. CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
  223. CURLOPT_TIMEOUT => $this->timeout,
  224. CURLOPT_CUSTOMREQUEST => $method,
  225. CURLOPT_HEADER => false,
  226. CURLOPT_RETURNTRANSFER => true,
  227. CURLOPT_USERAGENT => "opensearch/php sdk " . self::SDK_VERSION . "/" . PHP_VERSION,
  228. CURLOPT_HTTPHEADER => $this->_getHeaders($items),
  229. );
  230. if ($method == self::METHOD_GET) {
  231. $query = $this->_buildQuery($items['query_params']);
  232. $url .= preg_match('/\?/i', $url) ? '&' . $query : '?' . $query;
  233. } else{
  234. if(!empty($items['body_json'])){
  235. $options[CURLOPT_POSTFIELDS] = $items['body_json'];
  236. }
  237. }
  238. if ($this->gzip) {
  239. $options[CURLOPT_ENCODING] = 'gzip';
  240. }
  241. if ($this->debug) {
  242. $out = fopen('php://temp','rw');
  243. $options[CURLOPT_VERBOSE] = true;
  244. $options[CURLOPT_STDERR] = $out;
  245. }
  246. $session = curl_init($url);
  247. curl_setopt_array($session, $options);
  248. $response = curl_exec($session);
  249. curl_close($session);
  250. $openSearchResult = new OpenSearchResult();
  251. $openSearchResult->result = $response;
  252. if ($this->debug) {
  253. $openSearchResult->traceInfo = $this->getDebugInfo($out, $items);
  254. }
  255. return $openSearchResult;
  256. }
  257. private function getDebugInfo($handler, $items) {
  258. rewind($handler);
  259. $trace = new TraceInfo();
  260. $header = stream_get_contents($handler);
  261. fclose($handler);
  262. $trace->tracer = "\n" . $header;
  263. return $trace;
  264. }
  265. }