[ 'method' => $type, 'ignore_errors' => true, 'header' => $headerText, 'content' => $content ] ]); $data = @file_get_contents($url, false, $context); if ($data === false) { // The request never reached the service, so there is no // status and no body to read. Without this, false went on // to validateResponse(), where the strict types this file // declares turned it into a type error naming that method, // and $http_response_header was never set either, so the // caller heard nothing about the connection. $error = error_get_last(); throw new CloudRequestException(sprintf( Constants::MESSAGE_REQUEST_FAILED, $url, $error['message'] ?? 'the reason was not reported' )); } $statusCode = $this->getHttpCode($http_response_header); // Validate cloud response for errors. $this->validateResponse($data, $statusCode, $http_response_header, $url); return $data; } $ch = curl_init($url); curl_setopt($ch, CURLOPT_HEADER, true); if (!empty($originHeader)) { curl_setopt($ch, CURLOPT_HTTPHEADER, [ $headerText ]); } if (!empty($type) && strcasecmp($type, 'POST') === 0) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $content); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); } else { curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); } $data = curl_exec($ch); if ($data === false) { // curl could not make the request at all, for example where the // name does not resolve, the connection is refused, the // certificate cannot be checked or the request times out. There // is nothing to read, so the reason curl gave is reported. // Without this the false went on to substr() and the caller saw // a type error naming this file instead. $error = curl_error($ch); curl_close($ch); throw new CloudRequestException(sprintf( Constants::MESSAGE_REQUEST_FAILED, $url, $error === '' ? 'the reason was not reported' : $error )); } $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Get headers length $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); // Get response header and body using header length $headerStr = substr($data, 0, $headerSize); $bodyStr = substr($data, $headerSize); $responseHeaders = explode("\r\n", $headerStr); // Validate cloud response body for errors. $this->validateResponse($bodyStr, $httpCode, $responseHeaders, $url); curl_close($ch); return $bodyStr; } /** * Parser function to get formatted headers. * * @param array $headers * @return array */ public function parseHeaders(array $headers): array { $head = []; foreach ($headers as $k => $v) { $t = explode(':', $v, 2); if (isset($t[1])) { $head[trim($t[0])] = trim($t[1]); } } return $head; } /** * @param null|array $http_response_header * @return int */ private function getHttpCode(?array $http_response_header): int { if (is_array($http_response_header)) { $parts = explode(' ', $http_response_header[0]); if (count($parts) > 1) { // HTTP/1.0 return intval($parts[1]); } // Get code } return 0; } /** * @param array $httpResponseHeaders * @throws \fiftyone\pipeline\cloudrequestengine\CloudRequestException */ private function validateResponse(string $cloudResponse, int $httpStatusCode, array $httpResponseHeaders, string $url): void { $message = null; if ($cloudResponse) { $json = json_decode($cloudResponse, true); if (isset($json['errors']) && count($json['errors'])) { $message = implode(',', $json['errors']); } elseif ($httpStatusCode !== 200) { // If there were no errors returned but the response code was non // success then throw an exception. $message = sprintf(Constants::MESSAGE_ERROR_CODE_RETURNED, $url, $httpStatusCode, $cloudResponse); } } else { // If there were no errors but there was also no other data // in the response then add an explanation to the list of // messages. $message = sprintf(Constants::MESSAGE_NO_DATA_IN_RESPONSE, $url); } if (isset($message)) { // Get the response headers. $responseHeaders = $this->parseHeaders($httpResponseHeaders); $cloudError = sprintf(Constants::EXCEPTION_CLOUD_ERROR, $message); throw new CloudRequestException($cloudError, $httpStatusCode, $responseHeaders); } } }