/** * Constructor * * @param DoliDb $db Database handler * @param string $cachedir Cache dir */ function __construct($db, $cachedir = '') { global $conf; if (empty($cachedir)) { $cachedir = $conf->api->dir_temp; } Defaults::$cacheDirectory = $cachedir; $this->db = $db; $production_mode = empty($conf->global->API_PRODUCTION_MODE) ? false : true; $this->r = new Restler($production_mode); }
public function __isAllowed() { //hardcoded api_key=>role for brevity $roles = array('12345' => 'user', '67890' => 'admin'); $userClass = Defaults::$userIdentifierClass; if (isset($_GET['api_key'])) { if (!array_key_exists($_GET['api_key'], $roles)) { $userClass::setCacheIdentifier($_GET['api_key']); return false; } } else { return false; } static::$role = $roles[$_GET['api_key']]; $userClass::setCacheIdentifier(static::$role); Defaults::$accessControlFunction = 'AccessControl::verifyAccess'; return static::$requires == static::$role || static::$role == 'admin'; }
<?php /* * Testing all the attributes for @param annotation */ use Luracast\Restler\Restler; use Luracast\Restler\Defaults; require_once "../../../vendor/restler.php"; Defaults::$crossOriginResourceSharing = true; $r = new Restler(); $r->addAPIClass('MinMax'); $r->addAPIClass('MinMaxFix'); $r->addAPIClass('Type'); $r->addAPIClass('Resources'); $r->handle();
/** * 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; } }
<?php /** * Restler 2 compatibility mode enabler */ use Luracast\Restler\Defaults; use Luracast\Restler\AutoLoader; use Luracast\Restler\CommentParser; //changes in auto loading $classMap = array(); //find lowercase php files representing a class/interface foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) { foreach (new DirectoryIterator($path) as $fileInfo) { if ($fileInfo->isFile() && 'php' === $fileInfo->getExtension() && ctype_lower($fileInfo->getBasename('.php')) && preg_match('/^ *(class|interface|abstract +class)' . ' +([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)/m', file_get_contents($fileInfo->getPathname()), $matches)) { $classMap[$matches[2]] = $fileInfo->getPathname(); } } } AutoLoader::seen($classMap); //changes in iAuthenticate Defaults::$authenticationMethod = '__isAuthenticated'; include __DIR__ . '/iAuthenticate.php'; //changes in auto routing Defaults::$smartAutoRouting = false; Defaults::$smartParameterParsing = false; Defaults::$autoValidationEnabled = false; //changes in parsing embedded data in comments CommentParser::$embeddedDataPattern = '/\\((\\S+)\\)/ms'; CommentParser::$embeddedDataIndex = 1;
} catch (Exception $exception) { header("HTTP/1.0 403 Forbidden"); $GLOBALS['Response']->sendJSON(array('error' => $exception->getMessage())); die; } preg_match('/^\\/api\\/v(\\d+)\\//', $_SERVER['REQUEST_URI'], $matches); $version = floor(file_get_contents(__DIR__ . '/VERSION')); if ($matches && isset($matches[1]) && $matches[1] == 2) { $version = 2; } // Do not put .json at the end of the resource Resources::$useFormatAsExtension = false; //Do not hide the API Resources::$hideProtected = false; // Use /api/v1/projects uri Defaults::$useUrlBasedVersioning = true; if (ForgeConfig::get('DEBUG_MODE')) { $restler = new Restler(false, true); } else { $restler = new Restler(); } $restler->setAPIVersion($version); $restler->setSupportedFormats('JsonFormat', 'XmlFormat'); $core_resources_injector = new Tuleap\REST\ResourcesInjector(); $core_resources_injector->populate($restler); switch ($version) { case 2: $event = Event::REST_RESOURCES_V2; break; default: $event = Event::REST_RESOURCES;
> **Note:-** > > 1. Using session variables as DB and Cache is useless for real life and wrong. We are using it > Only for demo purpose. Since API Explorer is browser based it works well with that. > > 2. We are using Author.php to document return type of `GET authors/{id}` using `@return` comment If you have hit the API Rate Limit or screwed up the Authors DB, you can easily reset by deleting PHP_SESSION cookie using the Developer Tools in your browser. Helpers: Author Footer: *[Author.php]: _009_rate_limiting/Author.php */ use Luracast\Restler\Defaults; use Luracast\Restler\Filter\RateLimit; use Luracast\Restler\Restler; require_once '../../../vendor/restler.php'; //reuse the SessionDB from CRUD Example require_once '../_007_crud/DB/Session.php'; //used only for demo, comment the following line Defaults::$cacheClass = 'SessionCache'; //set extreme value for quick testing RateLimit::setLimit('hour', 10); $r = new Restler(); $r->addAPIClass('ratelimited\\Authors'); $r->addAPIClass('Resources'); $r->addFilterClass('RateLimit'); $r->addAuthenticationClass('KeyAuth'); $r->handle();
public function composeHeaders(RestException $e = null) { //only GET method should be cached if allowed by API developer $expires = $this->requestMethod == 'GET' ? Defaults::$headerExpires : 0; if (!is_array(Defaults::$headerCacheControl)) { Defaults::$headerCacheControl = array(Defaults::$headerCacheControl); } $cacheControl = Defaults::$headerCacheControl[0]; if ($expires > 0) { $cacheControl = $this->apiMethodInfo->accessLevel ? 'private, ' : 'public, '; $cacheControl .= end(Defaults::$headerCacheControl); $cacheControl = str_replace('{expires}', $expires, $cacheControl); $expires = gmdate('D, d M Y H:i:s \\G\\M\\T', time() + $expires); } @header('Cache-Control: ' . $cacheControl); @header('Expires: ' . $expires); @header('X-Powered-By: Luracast Restler v' . Restler::VERSION); if (Defaults::$crossOriginResourceSharing && isset($_SERVER['HTTP_ORIGIN'])) { header('Access-Control-Allow-Origin: ' . (Defaults::$accessControlAllowOrigin == '*' ? $_SERVER['HTTP_ORIGIN'] : Defaults::$accessControlAllowOrigin)); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Max-Age: 86400'); } $this->responseFormat->setCharset(Defaults::$charset); $charset = $this->responseFormat->getCharset() ?: Defaults::$charset; @header('Content-Type: ' . (Defaults::$useVendorMIMEVersioning ? 'application/vnd.' . Defaults::$apiVendor . "-v{$this->requestedApiVersion}" . '+' . $this->responseFormat->getExtension() : $this->responseFormat->getMIME()) . '; charset=' . $charset); @header('Content-Language: ' . Defaults::$language); if (isset($this->apiMethodInfo->metadata['header'])) { foreach ($this->apiMethodInfo->metadata['header'] as $header) { @header($header, true); } } $code = 200; if (!Defaults::$suppressResponseCode) { if ($e) { $code = $e->getCode(); } elseif (isset($this->apiMethodInfo->metadata['status'])) { $code = $this->apiMethodInfo->metadata['status']; } } $this->responseCode = $code; @header("{$_SERVER['SERVER_PROTOCOL']} {$code} " . (isset(RestException::$codes[$code]) ? RestException::$codes[$code] : '')); }
$version = floor(file_get_contents(__DIR__ . '/VERSION')); if ($matches && isset($matches[1]) && $matches[1] == 2) { $version = 2; } // Do not put .json at the end of the resource Explorer::$useFormatAsExtension = false; //Do not hide the API Explorer::$hideProtected = false; // Use /api/v1/projects uri Defaults::$useUrlBasedVersioning = true; if (ForgeConfig::get('DEBUG_MODE')) { $restler = new Restler(false, true); $restler->setSupportedFormats('JsonFormat', 'XmlFormat', 'HtmlFormat'); } else { $restler_cache = new RestlerCache(); Defaults::$cacheDirectory = $restler_cache->getAndInitiateCacheDirectory($version); $restler = new Restler(true, false); $restler->setSupportedFormats('JsonFormat', 'XmlFormat'); } // Do not let Restler find itself the domain, when behind a reverse proxy, it's // a mess. $restler->setBaseUrl($sys_default_domain); $restler->setAPIVersion($version); $core_resources_injector = new Tuleap\REST\ResourcesInjector(); $core_resources_injector->populate($restler); switch ($version) { case 2: $event = Event::REST_RESOURCES_V2; break; default: $event = Event::REST_RESOURCES;
public function composeHeaders(RestException $e = null) { //only GET method should be cached if allowed by API developer $expires = $this->requestMethod == 'GET' ? Defaults::$headerExpires : 0; if (!is_array(Defaults::$headerCacheControl)) { Defaults::$headerCacheControl = array(Defaults::$headerCacheControl); } $cacheControl = Defaults::$headerCacheControl[0]; if ($expires > 0) { $cacheControl = $this->apiMethodInfo->accessLevel ? 'private, ' : 'public, '; $cacheControl .= end(Defaults::$headerCacheControl); $cacheControl = str_replace('{expires}', $expires, $cacheControl); $expires = gmdate('D, d M Y H:i:s \\G\\M\\T', time() + $expires); } $this->headerData->set(new HeaderKey('Cache-Control', $cacheControl)); $this->headerData->set(new HeaderKey('Expires', $expires)); $this->headerData->set(new HeaderKey('X-Powered-By', 'Luracast Restler v' . Restler::VERSION)); $server_origin = null; if (is_null($this->requestFromObject)) { if (\array_key_exists('HTTP_ORIGIN', $_SERVER)) { $server_origin = $_SERVER['HTTP_ORIGIN']; } } else { $server_origin = $this->requestFromObject->getHeader()->get('Origin'); if (!is_null($server_origin)) { $server_origin = $server_origin->getValue(); } } if (Defaults::$crossOriginResourceSharing && !is_null($server_origin)) { $this->headerData->set(new HeaderKey('Access-Control-Allow-Origin', Defaults::$accessControlAllowOrigin == '*' ? $server_origin : Defaults::$accessControlAllowOrigin)); $this->headerData->set(new HeaderKey('Access-Control-Allow-Credentials', 'true')); $this->headerData->set(new HeaderKey('Access-Control-Max-Age', '86400')); } $this->responseFormat->setCharset(Defaults::$charset); $charset = $this->responseFormat->getCharset() ?: Defaults::$charset; $this->headerData->set(new HeaderKey('Content-Type', (Defaults::$useVendorMIMEVersioning ? 'application/vnd.' . Defaults::$apiVendor . "-v{$this->requestedApiVersion}" . '+' . $this->responseFormat->getExtension() : $this->responseFormat->getMIME()) . '; charset=' . $charset)); $this->headerData->set(new HeaderKey('Content-Language', Defaults::$language)); if (isset($this->apiMethodInfo->metadata['header'])) { foreach ($this->apiMethodInfo->metadata['header'] as $header) { if (strpos(':', $header) !== false) { $header = \explode(':', $header); $this->headerData->set(new HeaderKey($header[0], $header[1]), true); continue; } $this->headerData->set(new HeaderKey(null, $header), true); } } $code = 200; if (!Defaults::$suppressResponseCode) { if ($e) { $code = $e->getCode(); } elseif (isset($this->apiMethodInfo->metadata['status'])) { $code = $this->apiMethodInfo->metadata['status']; } } $this->responseCode = $code; if (is_null($this->requestFromObject)) { $this->headerData->setVersion($_SERVER['SERVER_PROTOCOL']); } else { $this->headerData->setVersion($this->requestFromObject->getVersion()); } $this->headerData->setStatusCode($code); }
*/ require_once 'vendor/restler.php'; use Luracast\Restler\Restler; use Luracast\Restler\Responder; use Luracast\Restler\Defaults; /* * There was a need for more complex validation return messages. this showed the way: * http://stackoverflow.com/questions/13107318/how-can-i-return-a-data-object-when-throwing-a-restexception * In a nutshell, extend the Responder class (that restler uses for giving a structure to the error and success response) * like below: */ class MyResponder extends Responder { public static $data = null; public function formatError($statusCode, $message) { $r = array('error' => array('code' => $statusCode, 'message' => $message)); if (isset(self::$data)) { $r['data'] = self::$data; } return $r; } } Defaults::$responderClass = 'MyResponder'; require_once 'pbo/property.php'; // Restler setup. See the following for details: http://restler3.phpfogapp.com/examples/ $r = new Restler(); $r->addAPIClass('Luracast\\Restler\\Resources'); //this creates resources.json at API Root $r->addAPIClass('Property'); $r->handle();
<?php /** * Created by PhpStorm. * User: MartinTiefengrabner * Date: 20/08/15 * Time: 10:20 */ require_once '../doc/vendor/restler.php'; use Luracast\Restler\Restler; use Luracast\Restler\Defaults; //set the defaults to match your requirements Defaults::$throttle = 20; //time in milliseconds for bandwidth throttling //setup restler $r = new Restler(); $r->addAPIClass('YourApiClassNameHere'); // repeat for more $r->addAPIClass('Resources'); //from restler framework for API Explorer $r->addFilterClass('RateLimit'); //Add Filters as needed $r->handle(); //serve the response
protected function negotiateLanguage() { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $found = false; $langList = Util::sortByPriority($_SERVER['HTTP_ACCEPT_LANGUAGE']); foreach ($langList as $lang => $quality) { foreach (Defaults::$supportedLanguages as $supported) { if (strcasecmp($supported, $lang) == 0) { $found = true; Defaults::$language = $supported; break 2; } } } if (!$found) { if (strpos($_SERVER['HTTP_ACCEPT_LANGUAGE'], '*') !== false) { //use default language } else { //ignore } } } }
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();
return class_alias($app['config']['app.aliases'][$className], $className); } return false; }, true, true); /* |-------------------------------------------------------------------------- | Bind Paths |-------------------------------------------------------------------------- | | Here we are binding the paths configured in paths.php to the app. You | should not be changing these here. If you need to change these you | may do so within the paths.php file and they will be bound here. | */ $app->bindInstallPaths(require __DIR__ . '/paths.php'); /* |-------------------------------------------------------------------------- | Configure Restler to adapt to Laravel 4.2 structure |-------------------------------------------------------------------------- */ use Luracast\Restler\Defaults; use Luracast\Restler\Format\HtmlFormat; use Luracast\Restler\UI\Forms; use Luracast\Restler\UI\FormStyles; use Luracast\Restler\Scope; $app['config']['app.aliases'] += Scope::$classAliases + ['Scope' => 'Luracast\\Restler\\Scope']; HtmlFormat::$viewPath = $app['path'] . '/views'; HtmlFormat::$cacheDirectory = $app['path.storage'] . '/views'; Defaults::$cacheDirectory = $app['path.storage'] . '/cache'; HtmlFormat::$template = 'blade'; Forms::$style = FormStyles::$bootstrap3;