/** * Parses the request to figure out the best format for response. * Extension, if present, overrides the Accept header * * @throws RestException * @return iFormat * @example JsonFormat */ protected function negotiateResponseFormat() { $metadata = Util::nestedValue($this, 'apiMethodInfo', 'metadata'); //check if the api method insists on response format using @format comment if ($metadata && isset($metadata['format'])) { $formats = explode(',', (string) $metadata['format']); foreach ($formats as $i => $f) { $f = trim($f); if (!in_array($f, $this->formatOverridesMap)) { throw new RestException(500, "Given @format is not present in overriding formats. Please call `\$r->setOverridingFormats('{$f}');` first."); } $formats[$i] = $f; } call_user_func_array(array($this, 'setSupportedFormats'), $formats); } // check if client has specified an extension /** @var $format iFormat*/ $format = null; $extensions = explode('.', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); while ($extensions) { $extension = array_pop($extensions); $extension = explode('/', $extension); $extension = array_shift($extension); if ($extension && isset($this->formatMap[$extension])) { $format = Scope::get($this->formatMap[$extension]); $format->setExtension($extension); // echo "Extension $extension"; return $format; } } // check if client has sent list of accepted data formats if (isset($_SERVER['HTTP_ACCEPT'])) { $acceptList = Util::sortByPriority($_SERVER['HTTP_ACCEPT']); foreach ($acceptList as $accept => $quality) { if (isset($this->formatMap[$accept])) { $format = Scope::get($this->formatMap[$accept]); $format->setMIME($accept); //echo "MIME $accept"; // Tell cache content is based on Accept header @header('Vary: Accept'); return $format; } elseif (false !== ($index = strrpos($accept, '+'))) { $mime = substr($accept, 0, $index); if (is_string(Defaults::$apiVendor) && 0 === stripos($mime, 'application/vnd.' . Defaults::$apiVendor . '-v')) { $extension = substr($accept, $index + 1); if (isset($this->formatMap[$extension])) { //check the MIME and extract version $version = intval(substr($mime, 18 + strlen(Defaults::$apiVendor))); if ($version > 0 && $version <= $this->apiVersion) { $this->requestedApiVersion = $version; $format = Scope::get($this->formatMap[$extension]); $format->setExtension($extension); // echo "Extension $extension"; Defaults::$useVendorMIMEVersioning = true; @header('Vary: Accept'); return $format; } } } } } } else { // RFC 2616: If no Accept header field is // present, then it is assumed that the // client accepts all media types. $_SERVER['HTTP_ACCEPT'] = '*/*'; } if (strpos($_SERVER['HTTP_ACCEPT'], '*') !== false) { if (false !== strpos($_SERVER['HTTP_ACCEPT'], 'application/*')) { $format = Scope::get('JsonFormat'); } elseif (false !== strpos($_SERVER['HTTP_ACCEPT'], 'text/*')) { $format = Scope::get('XmlFormat'); } elseif (false !== strpos($_SERVER['HTTP_ACCEPT'], '*/*')) { $format = Scope::get($this->formatMap['default']); } } if (empty($format)) { // RFC 2616: If an Accept header field is present, and if the // server cannot send a response which is acceptable according to // the combined Accept field value, then the server SHOULD send // a 406 (not acceptable) response. $format = Scope::get($this->formatMap['default']); $this->responseFormat = $format; throw new RestException(406, 'Content negotiation failed. ' . 'Try `' . $format->getMIME() . '` instead.'); } else { // Tell cache content is based at Accept header @header("Vary: Accept"); return $format; } }
/** * Parses the request to figure out the best format for response. * Extension, if present, overrides the Accept header * * @return iFormat any class that implements iFormat * @example JsonFormat */ protected function getResponseFormat() { // check if client has specified an extension /** * * @var iFormat */ $format = null; $extensions = explode('.', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); while ($extensions) { $extension = array_pop($extensions); $extension = explode('/', $extension); $extension = array_shift($extension); if ($extension && isset($this->formatMap[$extension])) { $format = $this->formatMap[$extension]; $format = is_string($format) ? new $format() : $format; $format->setExtension($extension); // echo "Extension $extension"; return $format; } } // check if client has sent list of accepted data formats if (isset($_SERVER['HTTP_ACCEPT'])) { $acceptList = Util::sortByPriority($_SERVER['HTTP_ACCEPT']); foreach ($acceptList as $accept => $quality) { if (isset($this->formatMap[$accept])) { $format = $this->formatMap[$accept]; $format = is_string($format) ? new $format() : $format; //TODO: check if the string verfication above is needed $format->setMIME($accept); //echo "MIME $accept"; // Tell cache content is based on Accept header @header('Vary: Accept'); return $format; } elseif (false !== ($index = strrpos($accept, '+'))) { $mime = substr($accept, 0, $index); if (is_string(Defaults::$apiVendor) && 0 === strpos($mime, 'application/vnd.' . Defaults::$apiVendor . '-v')) { $extension = substr($accept, $index + 1); if (isset($this->formatMap[$extension])) { //check the MIME and extract version $version = intVal(substr($mime, 18 + strlen(Defaults::$apiVendor))); if ($version > 0 && $version <= $this->apiVersion) { $this->requestedApiVersion = $version; $format = $this->formatMap[$extension]; $format = is_string($format) ? new $format() : $format; $format->setExtension($extension); // echo "Extension $extension"; Defaults::$useVendorMIMEVersioning = true; @header('Vary: Accept'); return $format; } } } } } } else { // RFC 2616: If no Accept header field is // present, then it is assumed that the // client accepts all media types. $_SERVER['HTTP_ACCEPT'] = '*/*'; } if (strpos($_SERVER['HTTP_ACCEPT'], '*') !== false) { if (strpos($_SERVER['HTTP_ACCEPT'], 'application/*') !== false) { $format = new JsonFormat(); } elseif (strpos($_SERVER['HTTP_ACCEPT'], 'text/*') !== false) { $format = new XmlFormat(); } elseif (strpos($_SERVER['HTTP_ACCEPT'], '*/*') !== false) { $format = $this->formatMap['default']; $format = new $format(); } } if (empty($format)) { // RFC 2616: If an Accept header field is present, and if the // server cannot send a response which is acceptable according to // the combined Accept field value, then the server SHOULD send // a 406 (not acceptable) response. $format = $this->formatMap['default']; $format = new $format(); $this->responseFormat = $format; $this->handleError(406, 'Content negotiation failed. ' . 'Try \'' . $format->getMIME() . '\' instead.'); } else { // Tell cache content is based at Accept header @header("Vary: Accept"); return $format; } }
Set-Cookie: ZDEDebuggerPresent=php,phtml,php3; path=/ Vary: Accept Cache-Control: no-cache, must-revalidate Expires: 0 Content-Language: en Content-Length: 209 Content-Type: application/vnd.SomeVendor-v2+json; charset=utf-8 { "bmi": 31.77, "message": "Obesity", "metric": { "height": "162.6 centimeters", "weight": "84 kilograms" }, "imperial": { "height": "5 feet 4 inches", "weight": "185.19 pounds" } } ``` */ require_once '../../../vendor/restler.php'; use Luracast\Restler\Defaults; use Luracast\Restler\Restler; Defaults::$apiVendor = "SomeVendor"; Defaults::$useVendorMIMEVersioning = true; $r = new Restler(); $r->setAPIVersion(2); $r->addAPIClass('SomeVendor\\BMI'); $r->addAPIClass('Resources'); $r->handle();