![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/opensearch-project/opensearch-php/src/OpenSearch/ |
<?php declare(strict_types=1); /** * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 * * Elasticsearch PHP client * * @link https://github.com/elastic/elasticsearch-php/ * @copyright Copyright (c) Elasticsearch B.V (https://www.elastic.co) * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 * @license https://www.gnu.org/licenses/lgpl-2.1.html GNU Lesser General Public License, Version 2.1 * * Licensed to Elasticsearch B.V under one or more agreements. * Elasticsearch B.V licenses this file to you under the Apache 2.0 License or * the GNU Lesser General Public License, Version 2.1, at your option. * See the LICENSE file in the project root for more information. */ namespace OpenSearch; use OpenSearch\Common\Exceptions\InvalidArgumentException; use OpenSearch\Common\Exceptions\RuntimeException; use OpenSearch\Common\Exceptions\AuthenticationConfigException; use OpenSearch\ConnectionPool\AbstractConnectionPool; use OpenSearch\ConnectionPool\Selectors\RoundRobinSelector; use OpenSearch\ConnectionPool\StaticNoPingConnectionPool; use OpenSearch\Connections\ConnectionFactory; use OpenSearch\Connections\ConnectionFactoryInterface; use OpenSearch\Namespaces\NamespaceBuilderInterface; use OpenSearch\Serializers\SmartSerializer; use GuzzleHttp\Ring\Client\CurlHandler; use GuzzleHttp\Ring\Client\CurlMultiHandler; use GuzzleHttp\Ring\Client\Middleware; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use ReflectionClass; class ClientBuilder { /** * @var Transport */ private $transport; /** * @var callable */ private $endpoint; /** * @var NamespaceBuilderInterface[] */ private $registeredNamespacesBuilders = []; /** * @var ConnectionFactoryInterface */ private $connectionFactory; /** * @var callable */ private $handler; /** * @var LoggerInterface */ private $logger; /** * @var LoggerInterface */ private $tracer; /** * @var string */ private $connectionPool = StaticNoPingConnectionPool::class; /** * @var string */ private $serializer = SmartSerializer::class; /** * @var string */ private $selector = RoundRobinSelector::class; /** * @var array */ private $connectionPoolArgs = [ 'randomizeHosts' => true ]; /** * @var array */ private $hosts; /** * @var array */ private $connectionParams; /** * @var int */ private $retries; /** * @var bool */ private $sniffOnStart = false; /** * @var null|array */ private $sslCert; /** * @var null|array */ private $sslKey; /** * @var null|bool|string */ private $sslVerification; /** * @var bool */ private $includePortInHostHeader = false; /** * Create an instance of ClientBuilder */ public static function create(): ClientBuilder { return new static(); } /** * Can supply first parm to Client::__construct() when invoking manually or with dependency injection */ public function getTransport(): Transport { return $this->transport; } /** * Can supply second parm to Client::__construct() when invoking manually or with dependency injection */ public function getEndpoint(): callable { return $this->endpoint; } /** * Can supply third parm to Client::__construct() when invoking manually or with dependency injection * * @return NamespaceBuilderInterface[] */ public function getRegisteredNamespacesBuilders(): array { return $this->registeredNamespacesBuilders; } /** * Build a new client from the provided config. Hash keys * should correspond to the method name e.g. ['connectionPool'] * corresponds to setConnectionPool(). * * Missing keys will use the default for that setting if applicable * * Unknown keys will throw an exception by default, but this can be silenced * by setting `quiet` to true * * @param array $config * @param bool $quiet False if unknown settings throw exception, true to silently * ignore unknown settings * @throws Common\Exceptions\RuntimeException */ public static function fromConfig(array $config, bool $quiet = false): Client { $builder = new static(); foreach ($config as $key => $value) { $method = "set$key"; $reflection = new ReflectionClass($builder); if ($reflection->hasMethod($method)) { $func = $reflection->getMethod($method); if ($func->getNumberOfParameters() > 1) { $builder->$method(...$value); } else { $builder->$method($value); } unset($config[$key]); } } if ($quiet === false && count($config) > 0) { $unknown = implode(array_keys($config)); throw new RuntimeException("Unknown parameters provided: $unknown"); } return $builder->build(); } /** * Get the default handler * * @param array $multiParams * @param array $singleParams * @throws \RuntimeException */ public static function defaultHandler(array $multiParams = [], array $singleParams = []): callable { $future = null; if (extension_loaded('curl')) { $config = array_merge([ 'mh' => curl_multi_init() ], $multiParams); if (function_exists('curl_reset')) { $default = new CurlHandler($singleParams); $future = new CurlMultiHandler($config); } else { $default = new CurlMultiHandler($config); } } else { throw new \RuntimeException('OpenSearch-PHP requires cURL, or a custom HTTP handler.'); } return $future ? Middleware::wrapFuture($default, $future) : $default; } /** * Get the multi handler for async (CurlMultiHandler) * * @throws \RuntimeException */ public static function multiHandler(array $params = []): CurlMultiHandler { if (function_exists('curl_multi_init')) { return new CurlMultiHandler(array_merge([ 'mh' => curl_multi_init() ], $params)); } throw new \RuntimeException('CurlMulti handler requires cURL.'); } /** * Get the handler instance (CurlHandler) * * @throws \RuntimeException */ public static function singleHandler(): CurlHandler { if (function_exists('curl_reset')) { return new CurlHandler(); } throw new \RuntimeException('CurlSingle handler requires cURL.'); } /** * Set connection Factory * * @param ConnectionFactoryInterface $connectionFactory */ public function setConnectionFactory(ConnectionFactoryInterface $connectionFactory): ClientBuilder { $this->connectionFactory = $connectionFactory; return $this; } /** * Set the connection pool (default is StaticNoPingConnectionPool) * * @param AbstractConnectionPool|string $connectionPool * @param array $args * @throws \InvalidArgumentException */ public function setConnectionPool($connectionPool, array $args = []): ClientBuilder { if (is_string($connectionPool)) { $this->connectionPool = $connectionPool; $this->connectionPoolArgs = $args; } elseif (is_object($connectionPool)) { $this->connectionPool = $connectionPool; } else { throw new InvalidArgumentException("Serializer must be a class path or instantiated object extending AbstractConnectionPool"); } return $this; } /** * Set the endpoint * * @param callable $endpoint */ public function setEndpoint(callable $endpoint): ClientBuilder { $this->endpoint = $endpoint; return $this; } /** * Register namespace * * @param NamespaceBuilderInterface $namespaceBuilder */ public function registerNamespace(NamespaceBuilderInterface $namespaceBuilder): ClientBuilder { $this->registeredNamespacesBuilders[] = $namespaceBuilder; return $this; } /** * Set the transport * * @param Transport $transport */ public function setTransport(Transport $transport): ClientBuilder { $this->transport = $transport; return $this; } /** * Set the HTTP handler (cURL is default) * * @param mixed $handler */ public function setHandler($handler): ClientBuilder { $this->handler = $handler; return $this; } /** * Set the PSR-3 Logger * * @param LoggerInterface $logger */ public function setLogger(LoggerInterface $logger): ClientBuilder { $this->logger = $logger; return $this; } /** * Set the PSR-3 tracer * * @param LoggerInterface $tracer */ public function setTracer(LoggerInterface $tracer): ClientBuilder { $this->tracer = $tracer; return $this; } /** * Set the serializer * * @param \OpenSearch\Serializers\SerializerInterface|string $serializer */ public function setSerializer($serializer): ClientBuilder { $this->parseStringOrObject($serializer, $this->serializer, 'SerializerInterface'); return $this; } /** * Set the hosts (nodes) * * @param array $hosts */ public function setHosts(array $hosts): ClientBuilder { $this->hosts = $hosts; return $this; } /** * Set Basic access authentication * * @see https://en.wikipedia.org/wiki/Basic_access_authentication * @param string $username * @param string $password * * @throws AuthenticationConfigException */ public function setBasicAuthentication(string $username, string $password): ClientBuilder { if (isset($this->connectionParams['client']['curl']) === false) { $this->connectionParams['client']['curl'] = []; } $this->connectionParams['client']['curl'] += [ CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => $username.':'.$password ]; return $this; } /** * Set connection parameters * * @param array $params */ public function setConnectionParams(array $params): ClientBuilder { $this->connectionParams = $params; return $this; } /** * Set number or retries (default is equal to number of nodes) * * @param int $retries */ public function setRetries(int $retries): ClientBuilder { $this->retries = $retries; return $this; } /** * Set the selector algorithm * * @param \OpenSearch\ConnectionPool\Selectors\SelectorInterface|string $selector */ public function setSelector($selector): ClientBuilder { $this->parseStringOrObject($selector, $this->selector, 'SelectorInterface'); return $this; } /** * Set sniff on start * * @param bool $sniffOnStart enable or disable sniff on start */ public function setSniffOnStart(bool $sniffOnStart): ClientBuilder { $this->sniffOnStart = $sniffOnStart; return $this; } /** * Set SSL certificate * * @param string $cert The name of a file containing a PEM formatted certificate. * @param string $password if the certificate requires a password */ public function setSSLCert(string $cert, string $password = null): ClientBuilder { $this->sslCert = [$cert, $password]; return $this; } /** * Set SSL key * * @param string $key The name of a file containing a private SSL key * @param string $password if the private key requires a password */ public function setSSLKey(string $key, string $password = null): ClientBuilder { $this->sslKey = [$key, $password]; return $this; } /** * Set SSL verification * * @param bool|string $value */ public function setSSLVerification($value = true): ClientBuilder { $this->sslVerification = $value; return $this; } /** * Include the port in Host header * * @see https://github.com/elastic/elasticsearch-php/issues/993 */ public function includePortInHostHeader(bool $enable): ClientBuilder { $this->includePortInHostHeader = $enable; return $this; } /** * Build and returns the Client object */ public function build(): Client { $this->buildLoggers(); if (is_null($this->handler)) { $this->handler = ClientBuilder::defaultHandler(); } $sslOptions = null; if (isset($this->sslKey)) { $sslOptions['ssl_key'] = $this->sslKey; } if (isset($this->sslCert)) { $sslOptions['cert'] = $this->sslCert; } if (isset($this->sslVerification)) { $sslOptions['verify'] = $this->sslVerification; } if (!is_null($sslOptions)) { $sslHandler = function (callable $handler, array $sslOptions) { return function (array $request) use ($handler, $sslOptions) { // Add our custom headers foreach ($sslOptions as $key => $value) { $request['client'][$key] = $value; } // Send the request using the handler and return the response. return $handler($request); }; }; $this->handler = $sslHandler($this->handler, $sslOptions); } if (is_null($this->serializer)) { $this->serializer = new SmartSerializer(); } elseif (is_string($this->serializer)) { $this->serializer = new $this->serializer(); } $this->connectionParams['client']['port_in_header'] = $this->includePortInHostHeader; if (is_null($this->connectionFactory)) { if (is_null($this->connectionParams)) { $this->connectionParams = []; } // Make sure we are setting Content-Type and Accept (unless the user has explicitly // overridden it if (! isset($this->connectionParams['client']['headers'])) { $this->connectionParams['client']['headers'] = []; } $apiVersioning = getenv('ELASTIC_CLIENT_APIVERSIONING'); if (! isset($this->connectionParams['client']['headers']['Content-Type'])) { if ($apiVersioning === 'true' || $apiVersioning === '1') { $this->connectionParams['client']['headers']['Content-Type'] = ['application/vnd.elasticsearch+json;compatible-with=7']; } else { $this->connectionParams['client']['headers']['Content-Type'] = ['application/json']; } } if (! isset($this->connectionParams['client']['headers']['Accept'])) { if ($apiVersioning === 'true' || $apiVersioning === '1') { $this->connectionParams['client']['headers']['Accept'] = ['application/vnd.elasticsearch+json;compatible-with=7']; } else { $this->connectionParams['client']['headers']['Accept'] = ['application/json']; } } $this->connectionFactory = new ConnectionFactory($this->handler, $this->connectionParams, $this->serializer, $this->logger, $this->tracer); } if (is_null($this->hosts)) { $this->hosts = $this->getDefaultHost(); } if (is_null($this->selector)) { $this->selector = new RoundRobinSelector(); } elseif (is_string($this->selector)) { $this->selector = new $this->selector(); } $this->buildTransport(); if (is_null($this->endpoint)) { $serializer = $this->serializer; $this->endpoint = function ($class) use ($serializer) { $fullPath = '\\OpenSearch\\Endpoints\\' . $class; $reflection = new ReflectionClass($fullPath); $constructor = $reflection->getConstructor(); if ($constructor && $constructor->getParameters()) { return new $fullPath($serializer); } else { return new $fullPath(); } }; } $registeredNamespaces = []; foreach ($this->registeredNamespacesBuilders as $builder) { /** * @var NamespaceBuilderInterface $builder */ $registeredNamespaces[$builder->getName()] = $builder->getObject($this->transport, $this->serializer); } return $this->instantiate($this->transport, $this->endpoint, $registeredNamespaces); } protected function instantiate(Transport $transport, callable $endpoint, array $registeredNamespaces): Client { return new Client($transport, $endpoint, $registeredNamespaces); } private function buildLoggers(): void { if (is_null($this->logger)) { $this->logger = new NullLogger(); } if (is_null($this->tracer)) { $this->tracer = new NullLogger(); } } private function buildTransport(): void { $connections = $this->buildConnectionsFromHosts($this->hosts); if (is_string($this->connectionPool)) { $this->connectionPool = new $this->connectionPool( $connections, $this->selector, $this->connectionFactory, $this->connectionPoolArgs ); } elseif (is_null($this->connectionPool)) { $this->connectionPool = new StaticNoPingConnectionPool( $connections, $this->selector, $this->connectionFactory, $this->connectionPoolArgs ); } if (is_null($this->retries)) { $this->retries = count($connections); } if (is_null($this->transport)) { $this->transport = new Transport($this->retries, $this->connectionPool, $this->logger, $this->sniffOnStart); } } private function parseStringOrObject($arg, &$destination, $interface): void { if (is_string($arg)) { $destination = new $arg(); } elseif (is_object($arg)) { $destination = $arg; } else { throw new InvalidArgumentException("Serializer must be a class path or instantiated object implementing $interface"); } } private function getDefaultHost(): array { return ['localhost:9200']; } /** * @return \OpenSearch\Connections\Connection[] * @throws RuntimeException */ private function buildConnectionsFromHosts(array $hosts): array { $connections = []; foreach ($hosts as $host) { if (is_string($host)) { $host = $this->prependMissingScheme($host); $host = $this->extractURIParts($host); } elseif (is_array($host)) { $host = $this->normalizeExtendedHost($host); } else { $this->logger->error("Could not parse host: ".print_r($host, true)); throw new RuntimeException("Could not parse host: ".print_r($host, true)); } $connections[] = $this->connectionFactory->create($host); } return $connections; } /** * @throws RuntimeException */ private function normalizeExtendedHost(array $host): array { if (isset($host['host']) === false) { $this->logger->error("Required 'host' was not defined in extended format: ".print_r($host, true)); throw new RuntimeException("Required 'host' was not defined in extended format: ".print_r($host, true)); } if (isset($host['scheme']) === false) { $host['scheme'] = 'http'; } if (isset($host['port']) === false) { $host['port'] = 9200; } return $host; } /** * @throws InvalidArgumentException */ private function extractURIParts(string $host): array { $parts = parse_url($host); if ($parts === false) { throw new InvalidArgumentException(sprintf('Could not parse URI: "%s"', $host)); } if (isset($parts['port']) !== true) { $parts['port'] = 9200; } return $parts; } private function prependMissingScheme(string $host): string { if (!preg_match("/^https?:\/\//", $host)) { $host = 'http://' . $host; } return $host; } }