Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 134
OpenSearchClient
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 14
1482
0.00% covered (danger)
0.00%
0 / 134
 __construct
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 18
 get
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 put
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 post
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 delete
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 patch
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 call
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 21
 _nonce
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 _signature
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 21
 _buildQuery
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 1
 _filter
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 11
 _getHeaders
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 12
 _curl
0.00% covered (danger)
0.00%
0 / 1
56
0.00% covered (danger)
0.00%
0 / 35
 getDebugInfo
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 9
<?php
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
namespace OpenSearch\Client;
use OpenSearch\Generated\OpenSearch\OpenSearch;
use OpenSearch\Generated\OpenSearch\Constant;
use OpenSearch\Generated\Common\OpenSearchResult;
use OpenSearch\Generated\Common\TraceInfo;
class OpenSearchClient extends OpenSearch {
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_DELETE = 'DELETE';
    const METHOD_PATCH = 'PATCH';
    const API_VERSION = '3';
    const SDK_VERSION = '3.0.0';
    const API_TYPE = 'openapi';
    private $debug = false;
    public $timeout = 10;
    public $connectTimeout = 1;
    public function __construct($accessKey, $secret, $host, $options = array()) {
        $args = array(
            'accessKey' => trim($accessKey),
            'secret' => trim($secret),
            'host' => trim($host),
            'options' => $options
        );
        if (isset($options['gzip'])) {
            $args['gzip'] = $options['gzip'];
        }
        if (isset($options['timeout'])) {
            $args['timeout'] = $options['timeout'];
        }
        if (isset($options['connectTimeout'])) {
            $args['connectTimeout'] = $options['connectTimeout'];
        }
        if (isset($options['debug'])) {
            $this->debug = (boolean) $options['debug'];
        }
        parent::__construct($args);
    }
    public function get($uri, $params = array()) {
        return $this->call($uri, $params, '', self::METHOD_GET);
    }
    public function put($uri, $body = '') {
        return $this->call($uri, array(), $body, self::METHOD_PUT);
    }
    public function post($uri, $body = '') {
        return $this->call($uri, array(), $body, self::METHOD_POST);
    }
    public function delete($uri, $body = '') {
        return $this->call($uri, array(), $body, self::METHOD_DELETE);
    }
    public function patch($uri, $body = '') {
        return $this->call($uri, array(), $body, self::METHOD_PATCH);
    }
    public function call($uri, array $params, $body, $method) {
        $path = "/v" . self::API_VERSION . "/" . self::API_TYPE . "{$uri}";
        $url = $this->host . $path;
        $items = array();
        $items['method'] = $method;
        $items['request_path'] = $path;
        $items['content_type'] = "application/json";
        $items['accept_language'] = "zh-cn";
        $items['date'] = gmdate('Y-m-d\TH:i:s\Z');
        $items['opensearch_headers'] = array();
        $items['content_md5'] = "";
        $items['opensearch_headers']['X-Opensearch-Nonce'] = $this->_nonce();
        if ($method != self::METHOD_GET) {
            if (!empty($body)) {
                $items['content_md5'] = md5($body);
                $items['body_json'] = $body;
            }
        }
        $items['query_params'] = $params;
        $signature = $this->_signature($this->secret, $items);
        $items['authorization'] = "OPENSEARCH {$this->accessKey}:{$signature}";
        return $this->_curl($url, $items);
    }
    private function _nonce() {
        return intval(microtime(true) * 1000) . mt_rand(10000, 99999);
    }
    private function _signature($secret, $items) {
        $params = isset($items['query_params']) ? $items['query_params'] : "";
        $signature = '';
        $string = '';
        $string .= strtoupper($items['method']) . "\n";
        $string .= $items['content_md5'] . "\n";
        $string .= $items['content_type'] . "\n";
        $string .= $items['date'] . "\n";
        $headers = self::_filter($items['opensearch_headers']);
        foreach($headers as $key => $value){
          $string .= strtolower($key) . ":" . $value."\n";
        }
        $resource = str_replace('%2F', '/', rawurlencode($items['request_path']));
        $sortParams = self::_filter($params);
        $queryString = http_build_query($sortParams, null, '&', PHP_QUERY_RFC3986);
        $canonicalizedResource = $resource;
        if(!empty($queryString)){
          $canonicalizedResource .= '?'.$queryString;
        }
        $string .= $canonicalizedResource;
        $signature = base64_encode(hash_hmac('sha1', $string, $secret, true));
        return $signature;
    }
    private function _buildQuery($params) {
        return !empty($params) ? http_build_query($params, null, '&', PHP_QUERY_RFC3986) : '';
    }
    private function _filter($parameters = array()){
        $params = array();
        if(!empty($parameters)){
            while (list ($key, $val) = each ($parameters)) {
                if ($key == "Signature" ||$val === "" || $val === NULL){
                    continue;
                } else {
                    $params[$key] = $parameters[$key];
                }
            }
            uksort($params,'strnatcasecmp');
            reset($params);
        }
        return $params;
    }
    private function _getHeaders($items) {
        $headers = array();
        $headers[] = 'Content-Type: '.$items['content_type'];
        $headers[] = 'Date: '.$items['date'];
        $headers[] = 'Accept-Language: '.$items['accept_language'];
        $headers[] = 'Content-Md5: '.$items['content_md5'];
        $headers[] = 'Authorization: '.$items['authorization'];
        if (is_array($items['opensearch_headers'])) {
            foreach($items['opensearch_headers'] as $key => $value){
                $headers[] = $key . ": " . $value;
            }
        }
        return $headers;
    }
    private function _curl($url, $items) {
        $method = strtoupper($items['method']);
        $options = array(
            CURLOPT_HTTP_VERSION => 'CURL_HTTP_VERSION_1_1',
            CURLOPT_CONNECTTIMEOUT => $this->connectTimeout,
            CURLOPT_TIMEOUT => $this->timeout,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HEADER => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_USERAGENT => "opensearch/php sdk " . self::SDK_VERSION,
            CURLOPT_HTTPHEADER => $this->_getHeaders($items),
        );
        if ($method == self::METHOD_GET) {
            $query = $this->_buildQuery($items['query_params']);
            $url .= preg_match('/\?/i', $url) ? '&' . $query : '?' . $query;
        } else{
            if(!empty($items['body_json'])){
                $options[CURLOPT_POSTFIELDS] = $items['body_json'];
            }
        }
        if ($this->gzip) {
            $options[CURLOPT_ENCODING] = 'gzip';
        }
        if ($this->debug) {
            $out = fopen('php://temp','rw');
            $options[CURLOPT_VERBOSE] = true;
            $options[CURLOPT_STDERR] = $out;
        }
        $session = curl_init($url);
        curl_setopt_array($session, $options);
        $response = curl_exec($session);
        curl_close($session);
        $openSearchResult = new OpenSearchResult();
        $openSearchResult->result = $response;
        if ($this->debug) {
            $openSearchResult->traceInfo = $this->getDebugInfo($out, $items);
        }
        return $openSearchResult;
    }
    private function getDebugInfo($handler, $items) {
        rewind($handler);
        $trace = new TraceInfo();
        $header = stream_get_contents($handler);
        fclose($handler);
        if(!empty($items['body_json'])){
            $header = str_replace("\r\n\r\n", "\r\n\r\n" . $items['body_json'] . "\n", $header);
        }
        $trace->tracer = "\n" . $header;
        return $trace;
    }
}