/** * @param ClientContext $context * @param string $method * @param string $host * @param string $path * @param array $params * @param array $data * @param int $connectTimeout * @param int $readTimeout * * @return mixed * * @throws AlgoliaException * @throws \Exception */ public function doRequest($context, $method, $host, $path, $params, $data, $connectTimeout, $readTimeout) { if (strpos($host, 'http') === 0) { $url = $host . $path; } else { $url = 'https://' . $host . $path; } if ($params != null && count($params) > 0) { $params2 = array(); foreach ($params as $key => $val) { if (is_array($val)) { $params2[$key] = Json::encode($val); } else { $params2[$key] = $val; } } $url .= '?' . http_build_query($params2); } // initialize curl library $curlHandle = curl_init(); // set curl options try { foreach ($this->curlOptions as $curlOption => $optionValue) { curl_setopt($curlHandle, constant($curlOption), $optionValue); } } catch (\Exception $e) { $this->invalidOptions($this->curlOptions, $e->getMessage()); } //curl_setopt($curlHandle, CURLOPT_VERBOSE, true); $defaultHeaders = null; if ($context->adminAPIKey == null) { $defaultHeaders = array('X-Algolia-Application-Id' => $context->applicationID, 'X-Algolia-API-Key' => $context->apiKey, 'Content-type' => 'application/json'); } else { $defaultHeaders = array('X-Algolia-Application-Id' => $context->applicationID, 'X-Algolia-API-Key' => $context->adminAPIKey, 'X-Forwarded-For' => $context->endUserIP, 'X-Algolia-UserToken' => $context->algoliaUserToken, 'X-Forwarded-API-Key' => $context->rateLimitAPIKey, 'Content-type' => 'application/json'); } $headers = array_merge($defaultHeaders, $context->headers); $curlHeaders = array(); foreach ($headers as $key => $value) { $curlHeaders[] = $key . ': ' . $value; } curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $curlHeaders); curl_setopt($curlHandle, CURLOPT_USERAGENT, Version::getUserAgent()); //Return the output instead of printing it curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlHandle, CURLOPT_FAILONERROR, true); curl_setopt($curlHandle, CURLOPT_ENCODING, ''); curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curlHandle, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($curlHandle, CURLOPT_CAINFO, $this->caInfoPath); curl_setopt($curlHandle, CURLOPT_URL, $url); $version = curl_version(); if (version_compare(phpversion(), '5.2.3', '>=') && version_compare($version['version'], '7.16.2', '>=') && $connectTimeout < 1) { curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT_MS, $connectTimeout * 1000); curl_setopt($curlHandle, CURLOPT_TIMEOUT_MS, $readTimeout * 1000); } else { curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, $connectTimeout); curl_setopt($curlHandle, CURLOPT_TIMEOUT, $readTimeout); } // The problem is that on (Li|U)nix, when libcurl uses the standard name resolver, // a SIGALRM is raised during name resolution which libcurl thinks is the timeout alarm. curl_setopt($curlHandle, CURLOPT_NOSIGNAL, 1); curl_setopt($curlHandle, CURLOPT_FAILONERROR, false); if ($method === 'GET') { curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($curlHandle, CURLOPT_HTTPGET, true); curl_setopt($curlHandle, CURLOPT_POST, false); } else { if ($method === 'POST') { $body = $data ? Json::encode($data) : ''; curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($curlHandle, CURLOPT_POST, true); curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); } elseif ($method === 'DELETE') { curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'DELETE'); curl_setopt($curlHandle, CURLOPT_POST, false); } elseif ($method === 'PUT') { $body = $data ? Json::encode($data) : ''; curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); curl_setopt($curlHandle, CURLOPT_POST, true); } } $mhandle = $context->getMHandle($curlHandle); // Do all the processing. $running = null; do { $mrc = curl_multi_exec($mhandle, $running); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($running && $mrc == CURLM_OK) { if (curl_multi_select($mhandle, 0.1) == -1) { usleep(100); } do { $mrc = curl_multi_exec($mhandle, $running); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } $http_status = (int) curl_getinfo($curlHandle, CURLINFO_HTTP_CODE); $response = curl_multi_getcontent($curlHandle); $error = curl_error($curlHandle); if (!empty($error)) { throw new \Exception($error); } if ($http_status === 0 || $http_status === 503) { // Could not reach host or service unavailable, try with another one if we have it $context->releaseMHandle($curlHandle); curl_close($curlHandle); return; } $answer = Json::decode($response, true); $context->releaseMHandle($curlHandle); curl_close($curlHandle); if (intval($http_status / 100) == 4) { throw new AlgoliaException(isset($answer['message']) ? $answer['message'] : $http_status + ' error'); } elseif (intval($http_status / 100) != 2) { throw new \Exception($http_status . ': ' . $response); } return $answer; }
/** * @param ClientContext $context * @param string $method * @param string $host * @param string $path * @param array $params * @param array $data * @param int $connectTimeout * @param int $readTimeout * * @return mixed * * @throws AlgoliaException * @throws \Exception */ public function doRequest($context, $method, $host, $path, $params, $data, $connectTimeout, $readTimeout) { if (strpos($host, 'http') === 0) { $url = $host . $path; } else { $url = 'https://' . $host . $path; } if ($params != null && count($params) > 0) { $params2 = []; foreach ($params as $key => $val) { if (is_array($val)) { $params2[$key] = json_encode($val); } else { $params2[$key] = $val; } } $url .= '?' . http_build_query($params2); } // initialize curl library $curlHandle = curl_init(); // set curl options try { foreach ($this->curlOptions as $curlOption => $optionValue) { curl_setopt($curlHandle, constant($curlOption), $optionValue); } } catch (\Exception $e) { $this->invalidOptions($this->curlOptions, $e->getMessage()); } //curl_setopt($curlHandle, CURLOPT_VERBOSE, true); if ($context->adminAPIKey == null) { curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array_merge(['X-Algolia-Application-Id: ' . $context->applicationID, 'X-Algolia-API-Key: ' . $context->apiKey, 'Content-type: application/json'], $context->headers)); } else { curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array_merge(['X-Algolia-Application-Id: ' . $context->applicationID, 'X-Algolia-API-Key: ' . $context->adminAPIKey, 'X-Forwarded-For: ' . $context->endUserIP, 'X-Algolia-UserToken: ' . $context->algoliaUserToken, 'X-Forwarded-API-Key: ' . $context->rateLimitAPIKey, 'Content-type: application/json'], $context->headers)); } curl_setopt($curlHandle, CURLOPT_USERAGENT, 'Algolia for PHP ' . Version::get()); //Return the output instead of printing it curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlHandle, CURLOPT_FAILONERROR, true); curl_setopt($curlHandle, CURLOPT_ENCODING, ''); curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curlHandle, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($curlHandle, CURLOPT_CAINFO, $this->caInfoPath); curl_setopt($curlHandle, CURLOPT_URL, $url); $version = curl_version(); if (version_compare(phpversion(), '5.2.3', '>=') && version_compare($version['version'], '7.16.2', '>=') && $connectTimeout < 1) { curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT_MS, $connectTimeout * 1000); curl_setopt($curlHandle, CURLOPT_TIMEOUT_MS, $readTimeout * 1000); } else { curl_setopt($curlHandle, CURLOPT_CONNECTTIMEOUT, $connectTimeout); curl_setopt($curlHandle, CURLOPT_TIMEOUT, $readTimeout); } // The problem is that on (Li|U)nix, when libcurl uses the standard name resolver, // a SIGALRM is raised during name resolution which libcurl thinks is the timeout alarm. curl_setopt($curlHandle, CURLOPT_NOSIGNAL, 1); curl_setopt($curlHandle, CURLOPT_FAILONERROR, false); if ($method === 'GET') { curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($curlHandle, CURLOPT_HTTPGET, true); curl_setopt($curlHandle, CURLOPT_POST, false); } else { if ($method === 'POST') { $body = $data ? json_encode($data) : ''; curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($curlHandle, CURLOPT_POST, true); curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); } elseif ($method === 'DELETE') { curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'DELETE'); curl_setopt($curlHandle, CURLOPT_POST, false); } elseif ($method === 'PUT') { $body = $data ? json_encode($data) : ''; curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $body); curl_setopt($curlHandle, CURLOPT_POST, true); } } $mhandle = $context->getMHandle($curlHandle); // Do all the processing. $running = null; do { $mrc = curl_multi_exec($mhandle, $running); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($running && $mrc == CURLM_OK) { if (curl_multi_select($mhandle, 0.1) == -1) { usleep(100); } do { $mrc = curl_multi_exec($mhandle, $running); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } $http_status = (int) curl_getinfo($curlHandle, CURLINFO_HTTP_CODE); $response = curl_multi_getcontent($curlHandle); $error = curl_error($curlHandle); if (!empty($error)) { throw new \Exception($error); } if ($http_status === 0 || $http_status === 503) { // Could not reach host or service unavailable, try with another one if we have it $context->releaseMHandle($curlHandle); curl_close($curlHandle); return; } $answer = json_decode($response, true); $context->releaseMHandle($curlHandle); curl_close($curlHandle); if (intval($http_status / 100) == 4) { throw new AlgoliaException(isset($answer['message']) ? $answer['message'] : $http_status + ' error'); } elseif (intval($http_status / 100) != 2) { throw new \Exception($http_status . ': ' . $response); } switch (json_last_error()) { case JSON_ERROR_DEPTH: $errorMsg = 'JSON parsing error: maximum stack depth exceeded'; break; case JSON_ERROR_CTRL_CHAR: $errorMsg = 'JSON parsing error: unexpected control character found'; break; case JSON_ERROR_SYNTAX: $errorMsg = 'JSON parsing error: syntax error, malformed JSON'; break; case JSON_ERROR_STATE_MISMATCH: $errorMsg = 'JSON parsing error: underflow or the modes mismatch'; break; // PHP 5.3 less than 1.2.2 (Ubuntu 10.04 LTS) // PHP 5.3 less than 1.2.2 (Ubuntu 10.04 LTS) case defined('JSON_ERROR_UTF8') ? JSON_ERROR_UTF8 : -1: $errorMsg = 'JSON parsing error: malformed UTF-8 characters, possibly incorrectly encoded'; break; case JSON_ERROR_NONE: default: $errorMsg = null; break; } if ($errorMsg !== null) { throw new AlgoliaException($errorMsg); } return $answer; }