diff --git a/.gitignore b/.gitignore index 9437702..4bb4723 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -api/vendor/ +/api/vendor/* +!/api/vendor/slim/ # OS generated files .DS_Store diff --git a/api/vendor/slim/slim/CONTRIBUTING.md b/api/vendor/slim/slim/CONTRIBUTING.md new file mode 100644 index 0000000..9bbb6b1 --- /dev/null +++ b/api/vendor/slim/slim/CONTRIBUTING.md @@ -0,0 +1,20 @@ +# How to Contribute + +## Pull Requests + +1. Fork the Slim Framework repository +2. Create a new branch for each feature or improvement +3. Send a pull request from each feature branch to the **develop** branch + +It is very important to separate new features or improvements into separate feature branches, and to send a +pull request for each branch. This allows me to review and pull in new features or improvements individually. + +## Style Guide + +All pull requests must adhere to the [PSR-2 standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). + +## Unit Testing + +All pull requests must be accompanied by passing unit tests and complete code coverage. The Slim Framework uses phpunit for testing. + +[Learn about PHPUnit](https://github.com/sebastianbergmann/phpunit/) diff --git a/api/vendor/slim/slim/LICENSE.md b/api/vendor/slim/slim/LICENSE.md new file mode 100644 index 0000000..0875f84 --- /dev/null +++ b/api/vendor/slim/slim/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) 2011-2016 Josh Lockhart + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/api/vendor/slim/slim/README.md b/api/vendor/slim/slim/README.md new file mode 100644 index 0000000..d20f393 --- /dev/null +++ b/api/vendor/slim/slim/README.md @@ -0,0 +1,84 @@ +# Slim Framework + +[](https://travis-ci.org/slimphp/Slim) +[](https://coveralls.io/r/slimphp/Slim) +[](https://packagist.org/packages/slim/slim) +[](https://packagist.org/packages/slim/slim) + +Slim is a PHP micro-framework that helps you quickly write simple yet powerful web applications and APIs. + +## Installation + +It's recommended that you use [Composer](https://getcomposer.org/) to install Slim. + +```bash +$ composer require slim/slim "^3.0" +``` + +This will install Slim and all required dependencies. Slim requires PHP 5.5.0 or newer. + +## Usage + +Create an index.php file with the following contents: + +```php +get('/hello/{name}', function ($request, $response, $args) { + $response->write("Hello, " . $args['name']); + return $response; +}); + +$app->run(); +``` + +You may quickly test this using the built-in PHP server: +```bash +$ php -S localhost:8000 +``` + +Going to http://localhost:8000/hello/world will now display "Hello, world". + +For more information on how to configure your web server, see the [Documentation](http://www.slimframework.com/docs/start/web-servers.html). + +## Tests + +To execute the test suite, you'll need phpunit. + +```bash +$ phpunit +``` + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Learn More + +Learn more at these links: + +- [Website](http://www.slimframework.com) +- [Documentation](http://www.slimframework.com/docs/start/installation.html) +- [Support Forum](http://help.slimframework.com) +- [Twitter](https://twitter.com/slimphp) +- [Resources](https://github.com/xssc/awesome-slim) + +## Security + +If you discover security related issues, please email security@slimframework.com instead of using the issue tracker. + +## Credits + +- [Josh Lockhart](https://github.com/codeguy) +- [Andrew Smith](https://github.com/silentworks) +- [Rob Allen](https://github.com/akrabat) +- [Gabriel Manricks](https://github.com/gmanricks) +- [All Contributors](../../contributors) + +## License + +The Slim Framework is licensed under the MIT license. See [License File](LICENSE.md) for more information. diff --git a/api/vendor/slim/slim/Slim/App.php b/api/vendor/slim/slim/Slim/App.php new file mode 100644 index 0000000..c083539 --- /dev/null +++ b/api/vendor/slim/slim/Slim/App.php @@ -0,0 +1,644 @@ +container = $container; + } + + /** + * Enable access to the DI container by consumers of $app + * + * @return ContainerInterface + */ + public function getContainer() + { + return $this->container; + } + + /** + * Add middleware + * + * This method prepends new middleware to the app's middleware stack. + * + * @param callable|string $callable The callback routine + * + * @return static + */ + public function add($callable) + { + return $this->addMiddleware(new DeferredCallable($callable, $this->container)); + } + + /** + * Calling a non-existant method on App checks to see if there's an item + * in the container that is callable and if so, calls it. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + if ($this->container->has($method)) { + $obj = $this->container->get($method); + if (is_callable($obj)) { + return call_user_func_array($obj, $args); + } + } + + throw new \BadMethodCallException("Method $method is not a valid method"); + } + + /******************************************************************************** + * Router proxy methods + *******************************************************************************/ + + /** + * Add GET route + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function get($pattern, $callable) + { + return $this->map(['GET'], $pattern, $callable); + } + + /** + * Add POST route + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function post($pattern, $callable) + { + return $this->map(['POST'], $pattern, $callable); + } + + /** + * Add PUT route + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function put($pattern, $callable) + { + return $this->map(['PUT'], $pattern, $callable); + } + + /** + * Add PATCH route + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function patch($pattern, $callable) + { + return $this->map(['PATCH'], $pattern, $callable); + } + + /** + * Add DELETE route + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function delete($pattern, $callable) + { + return $this->map(['DELETE'], $pattern, $callable); + } + + /** + * Add OPTIONS route + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function options($pattern, $callable) + { + return $this->map(['OPTIONS'], $pattern, $callable); + } + + /** + * Add route for any HTTP method + * + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return \Slim\Interfaces\RouteInterface + */ + public function any($pattern, $callable) + { + return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable); + } + + /** + * Add route with multiple methods + * + * @param string[] $methods Numeric array of HTTP method names + * @param string $pattern The route URI pattern + * @param callable|string $callable The route callback routine + * + * @return RouteInterface + */ + public function map(array $methods, $pattern, $callable) + { + if ($callable instanceof Closure) { + $callable = $callable->bindTo($this->container); + } + + $route = $this->container->get('router')->map($methods, $pattern, $callable); + if (is_callable([$route, 'setContainer'])) { + $route->setContainer($this->container); + } + + if (is_callable([$route, 'setOutputBuffering'])) { + $route->setOutputBuffering($this->container->get('settings')['outputBuffering']); + } + + return $route; + } + + /** + * Route Groups + * + * This method accepts a route pattern and a callback. All route + * declarations in the callback will be prepended by the group(s) + * that it is in. + * + * @param string $pattern + * @param callable $callable + * + * @return RouteGroupInterface + */ + public function group($pattern, $callable) + { + /** @var RouteGroup $group */ + $group = $this->container->get('router')->pushGroup($pattern, $callable); + $group->setContainer($this->container); + $group($this); + $this->container->get('router')->popGroup(); + return $group; + } + + /******************************************************************************** + * Runner + *******************************************************************************/ + + /** + * Run application + * + * This method traverses the application middleware stack and then sends the + * resultant Response object to the HTTP client. + * + * @param bool|false $silent + * @return ResponseInterface + * + * @throws Exception + * @throws MethodNotAllowedException + * @throws NotFoundException + */ + public function run($silent = false) + { + $request = $this->container->get('request'); + $response = $this->container->get('response'); + + $response = $this->process($request, $response); + + if (!$silent) { + $this->respond($response); + } + + return $response; + } + + /** + * Process a request + * + * This method traverses the application middleware stack and then returns the + * resultant Response object. + * + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return ResponseInterface + * + * @throws Exception + * @throws MethodNotAllowedException + * @throws NotFoundException + */ + public function process(ServerRequestInterface $request, ResponseInterface $response) + { + // Ensure basePath is set + $router = $this->container->get('router'); + if (is_callable([$request->getUri(), 'getBasePath']) && is_callable([$router, 'setBasePath'])) { + $router->setBasePath($request->getUri()->getBasePath()); + } + + // Dispatch the Router first if the setting for this is on + if ($this->container->get('settings')['determineRouteBeforeAppMiddleware'] === true) { + // Dispatch router (note: you won't be able to alter routes after this) + $request = $this->dispatchRouterAndPrepareRoute($request, $router); + } + + // Traverse middleware stack + try { + $response = $this->callMiddlewareStack($request, $response); + } catch (Exception $e) { + $response = $this->handleException($e, $request, $response); + } catch (Throwable $e) { + $response = $this->handlePhpError($e, $request, $response); + } + + $response = $this->finalize($response); + + return $response; + } + + /** + * Send the response the client + * + * @param ResponseInterface $response + */ + public function respond(ResponseInterface $response) + { + // Send response + if (!headers_sent()) { + // Status + header(sprintf( + 'HTTP/%s %s %s', + $response->getProtocolVersion(), + $response->getStatusCode(), + $response->getReasonPhrase() + )); + + // Headers + foreach ($response->getHeaders() as $name => $values) { + foreach ($values as $value) { + header(sprintf('%s: %s', $name, $value), false); + } + } + } + + // Body + if (!$this->isEmptyResponse($response)) { + $body = $response->getBody(); + if ($body->isSeekable()) { + $body->rewind(); + } + $settings = $this->container->get('settings'); + $chunkSize = $settings['responseChunkSize']; + + $contentLength = $response->getHeaderLine('Content-Length'); + if (!$contentLength) { + $contentLength = $body->getSize(); + } + + + if (isset($contentLength)) { + $amountToRead = $contentLength; + while ($amountToRead > 0 && !$body->eof()) { + $data = $body->read(min($chunkSize, $amountToRead)); + echo $data; + + $amountToRead -= strlen($data); + + if (connection_status() != CONNECTION_NORMAL) { + break; + } + } + } else { + while (!$body->eof()) { + echo $body->read($chunkSize); + if (connection_status() != CONNECTION_NORMAL) { + break; + } + } + } + } + } + + /** + * Invoke application + * + * This method implements the middleware interface. It receives + * Request and Response objects, and it returns a Response object + * after compiling the routes registered in the Router and dispatching + * the Request object to the appropriate Route callback routine. + * + * @param ServerRequestInterface $request The most recent Request object + * @param ResponseInterface $response The most recent Response object + * + * @return ResponseInterface + * @throws MethodNotAllowedException + * @throws NotFoundException + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response) + { + // Get the route info + $routeInfo = $request->getAttribute('routeInfo'); + + /** @var \Slim\Interfaces\RouterInterface $router */ + $router = $this->container->get('router'); + + // If router hasn't been dispatched or the URI changed then dispatch + if (null === $routeInfo || ($routeInfo['request'] !== [$request->getMethod(), (string) $request->getUri()])) { + $request = $this->dispatchRouterAndPrepareRoute($request, $router); + $routeInfo = $request->getAttribute('routeInfo'); + } + + if ($routeInfo[0] === Dispatcher::FOUND) { + $route = $router->lookupRoute($routeInfo[1]); + return $route->run($request, $response); + } elseif ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) { + if (!$this->container->has('notAllowedHandler')) { + throw new MethodNotAllowedException($request, $response, $routeInfo[1]); + } + /** @var callable $notAllowedHandler */ + $notAllowedHandler = $this->container->get('notAllowedHandler'); + return $notAllowedHandler($request, $response, $routeInfo[1]); + } + + if (!$this->container->has('notFoundHandler')) { + throw new NotFoundException($request, $response); + } + /** @var callable $notFoundHandler */ + $notFoundHandler = $this->container->get('notFoundHandler'); + return $notFoundHandler($request, $response); + } + + /** + * Perform a sub-request from within an application route + * + * This method allows you to prepare and initiate a sub-request, run within + * the context of the current request. This WILL NOT issue a remote HTTP + * request. Instead, it will route the provided URL, method, headers, + * cookies, body, and server variables against the set of registered + * application routes. The result response object is returned. + * + * @param string $method The request method (e.g., GET, POST, PUT, etc.) + * @param string $path The request URI path + * @param string $query The request URI query string + * @param array $headers The request headers (key-value array) + * @param array $cookies The request cookies (key-value array) + * @param string $bodyContent The request body + * @param ResponseInterface $response The response object (optional) + * @return ResponseInterface + */ + public function subRequest( + $method, + $path, + $query = '', + array $headers = [], + array $cookies = [], + $bodyContent = '', + ResponseInterface $response = null + ) { + $env = $this->container->get('environment'); + $uri = Uri::createFromEnvironment($env)->withPath($path)->withQuery($query); + $headers = new Headers($headers); + $serverParams = $env->all(); + $body = new Body(fopen('php://temp', 'r+')); + $body->write($bodyContent); + $body->rewind(); + $request = new Request($method, $uri, $headers, $cookies, $serverParams, $body); + + if (!$response) { + $response = $this->container->get('response'); + } + + return $this($request, $response); + } + + /** + * Dispatch the router to find the route. Prepare the route for use. + * + * @param ServerRequestInterface $request + * @param RouterInterface $router + * @return ServerRequestInterface + */ + protected function dispatchRouterAndPrepareRoute(ServerRequestInterface $request, RouterInterface $router) + { + $routeInfo = $router->dispatch($request); + + if ($routeInfo[0] === Dispatcher::FOUND) { + $routeArguments = []; + foreach ($routeInfo[2] as $k => $v) { + $routeArguments[$k] = urldecode($v); + } + + $route = $router->lookupRoute($routeInfo[1]); + $route->prepare($request, $routeArguments); + + // add route to the request's attributes in case a middleware or handler needs access to the route + $request = $request->withAttribute('route', $route); + } + + $routeInfo['request'] = [$request->getMethod(), (string) $request->getUri()]; + + return $request->withAttribute('routeInfo', $routeInfo); + } + + /** + * Finalize response + * + * @param ResponseInterface $response + * @return ResponseInterface + */ + protected function finalize(ResponseInterface $response) + { + // stop PHP sending a Content-Type automatically + ini_set('default_mimetype', ''); + + if ($this->isEmptyResponse($response)) { + return $response->withoutHeader('Content-Type')->withoutHeader('Content-Length'); + } + + // Add Content-Length header if `addContentLengthHeader` setting is set + if (isset($this->container->get('settings')['addContentLengthHeader']) && + $this->container->get('settings')['addContentLengthHeader'] == true) { + if (ob_get_length() > 0) { + throw new \RuntimeException("Unexpected data in output buffer. " . + "Maybe you have characters before an opening getBody()->getSize(); + if ($size !== null && !$response->hasHeader('Content-Length')) { + $response = $response->withHeader('Content-Length', (string) $size); + } + } + + return $response; + } + + /** + * Helper method, which returns true if the provided response must not output a body and false + * if the response could have a body. + * + * @see https://tools.ietf.org/html/rfc7231 + * + * @param ResponseInterface $response + * @return bool + */ + protected function isEmptyResponse(ResponseInterface $response) + { + if (method_exists($response, 'isEmpty')) { + return $response->isEmpty(); + } + + return in_array($response->getStatusCode(), [204, 205, 304]); + } + + /** + * Call relevant handler from the Container if needed. If it doesn't exist, + * then just re-throw. + * + * @param Exception $e + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * + * @return ResponseInterface + * @throws Exception if a handler is needed and not found + */ + protected function handleException(Exception $e, ServerRequestInterface $request, ResponseInterface $response) + { + if ($e instanceof MethodNotAllowedException) { + $handler = 'notAllowedHandler'; + $params = [$e->getRequest(), $e->getResponse(), $e->getAllowedMethods()]; + } elseif ($e instanceof NotFoundException) { + $handler = 'notFoundHandler'; + $params = [$e->getRequest(), $e->getResponse()]; + } elseif ($e instanceof SlimException) { + // This is a Stop exception and contains the response + return $e->getResponse(); + } else { + // Other exception, use $request and $response params + $handler = 'errorHandler'; + $params = [$request, $response, $e]; + } + + if ($this->container->has($handler)) { + $callable = $this->container->get($handler); + // Call the registered handler + return call_user_func_array($callable, $params); + } + + // No handlers found, so just throw the exception + throw $e; + } + + /** + * Call relevant handler from the Container if needed. If it doesn't exist, + * then just re-throw. + * + * @param Throwable $e + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return ResponseInterface + * @throws Throwable + */ + protected function handlePhpError(Throwable $e, ServerRequestInterface $request, ResponseInterface $response) + { + $handler = 'phpErrorHandler'; + $params = [$request, $response, $e]; + + if ($this->container->has($handler)) { + $callable = $this->container->get($handler); + // Call the registered handler + return call_user_func_array($callable, $params); + } + + // No handlers found, so just throw the exception + throw $e; + } +} diff --git a/api/vendor/slim/slim/Slim/CallableResolver.php b/api/vendor/slim/slim/Slim/CallableResolver.php new file mode 100644 index 0000000..169ac48 --- /dev/null +++ b/api/vendor/slim/slim/Slim/CallableResolver.php @@ -0,0 +1,90 @@ +container = $container; + } + + /** + * Resolve toResolve into a closure that that the router can dispatch. + * + * If toResolve is of the format 'class:method', then try to extract 'class' + * from the container otherwise instantiate it and then dispatch 'method'. + * + * @param mixed $toResolve + * + * @return callable + * + * @throws RuntimeException if the callable does not exist + * @throws RuntimeException if the callable is not resolvable + */ + public function resolve($toResolve) + { + $resolved = $toResolve; + + if (!is_callable($toResolve) && is_string($toResolve)) { + // check for slim callable as "class:method" + $callablePattern = '!^([^\:]+)\:([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)$!'; + if (preg_match($callablePattern, $toResolve, $matches)) { + $class = $matches[1]; + $method = $matches[2]; + + if ($this->container->has($class)) { + $resolved = [$this->container->get($class), $method]; + } else { + if (!class_exists($class)) { + throw new RuntimeException(sprintf('Callable %s does not exist', $class)); + } + $resolved = [new $class($this->container), $method]; + } + } else { + // check if string is something in the DIC that's callable or is a class name which + // has an __invoke() method + $class = $toResolve; + if ($this->container->has($class)) { + $resolved = $this->container->get($class); + } else { + if (!class_exists($class)) { + throw new RuntimeException(sprintf('Callable %s does not exist', $class)); + } + $resolved = new $class($this->container); + } + } + } + + if (!is_callable($resolved)) { + throw new RuntimeException(sprintf( + '%s is not resolvable', + is_array($toResolve) || is_object($toResolve) ? json_encode($toResolve) : $toResolve + )); + } + + return $resolved; + } +} diff --git a/api/vendor/slim/slim/Slim/CallableResolverAwareTrait.php b/api/vendor/slim/slim/Slim/CallableResolverAwareTrait.php new file mode 100644 index 0000000..f7ff485 --- /dev/null +++ b/api/vendor/slim/slim/Slim/CallableResolverAwareTrait.php @@ -0,0 +1,47 @@ +container instanceof ContainerInterface) { + return $callable; + } + + /** @var CallableResolverInterface $resolver */ + $resolver = $this->container->get('callableResolver'); + + return $resolver->resolve($callable); + } +} diff --git a/api/vendor/slim/slim/Slim/Collection.php b/api/vendor/slim/slim/Slim/Collection.php new file mode 100644 index 0000000..5d19734 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Collection.php @@ -0,0 +1,202 @@ +replace($items); + } + + /******************************************************************************** + * Collection interface + *******************************************************************************/ + + /** + * Set collection item + * + * @param string $key The data key + * @param mixed $value The data value + */ + public function set($key, $value) + { + $this->data[$key] = $value; + } + + /** + * Get collection item for key + * + * @param string $key The data key + * @param mixed $default The default value to return if data key does not exist + * + * @return mixed The key's value, or the default value + */ + public function get($key, $default = null) + { + return $this->has($key) ? $this->data[$key] : $default; + } + + /** + * Add item to collection, replacing existing items with the same data key + * + * @param array $items Key-value array of data to append to this collection + */ + public function replace(array $items) + { + foreach ($items as $key => $value) { + $this->set($key, $value); + } + } + + /** + * Get all items in collection + * + * @return array The collection's source data + */ + public function all() + { + return $this->data; + } + + /** + * Get collection keys + * + * @return array The collection's source data keys + */ + public function keys() + { + return array_keys($this->data); + } + + /** + * Does this collection have a given key? + * + * @param string $key The data key + * + * @return bool + */ + public function has($key) + { + return array_key_exists($key, $this->data); + } + + /** + * Remove item from collection + * + * @param string $key The data key + */ + public function remove($key) + { + unset($this->data[$key]); + } + + /** + * Remove all items from collection + */ + public function clear() + { + $this->data = []; + } + + /******************************************************************************** + * ArrayAccess interface + *******************************************************************************/ + + /** + * Does this collection have a given key? + * + * @param string $key The data key + * + * @return bool + */ + public function offsetExists($key) + { + return $this->has($key); + } + + /** + * Get collection item for key + * + * @param string $key The data key + * + * @return mixed The key's value, or the default value + */ + public function offsetGet($key) + { + return $this->get($key); + } + + /** + * Set collection item + * + * @param string $key The data key + * @param mixed $value The data value + */ + public function offsetSet($key, $value) + { + $this->set($key, $value); + } + + /** + * Remove item from collection + * + * @param string $key The data key + */ + public function offsetUnset($key) + { + $this->remove($key); + } + + /** + * Get number of items in collection + * + * @return int + */ + public function count() + { + return count($this->data); + } + + /******************************************************************************** + * IteratorAggregate interface + *******************************************************************************/ + + /** + * Get collection iterator + * + * @return \ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->data); + } +} diff --git a/api/vendor/slim/slim/Slim/Container.php b/api/vendor/slim/slim/Slim/Container.php new file mode 100644 index 0000000..2d15a8d --- /dev/null +++ b/api/vendor/slim/slim/Slim/Container.php @@ -0,0 +1,179 @@ + '1.1', + 'responseChunkSize' => 4096, + 'outputBuffering' => 'append', + 'determineRouteBeforeAppMiddleware' => false, + 'displayErrorDetails' => false, + 'addContentLengthHeader' => true, + 'routerCacheFile' => false, + ]; + + /** + * Create new container + * + * @param array $values The parameters or objects. + */ + public function __construct(array $values = []) + { + parent::__construct($values); + + $userSettings = isset($values['settings']) ? $values['settings'] : []; + $this->registerDefaultServices($userSettings); + } + + /** + * This function registers the default services that Slim needs to work. + * + * All services are shared - that is, they are registered such that the + * same instance is returned on subsequent calls. + * + * @param array $userSettings Associative array of application settings + * + * @return void + */ + private function registerDefaultServices($userSettings) + { + $defaultSettings = $this->defaultSettings; + + /** + * This service MUST return an array or an + * instance of \ArrayAccess. + * + * @return array|\ArrayAccess + */ + $this['settings'] = function () use ($userSettings, $defaultSettings) { + return new Collection(array_merge($defaultSettings, $userSettings)); + }; + + $defaultProvider = new DefaultServicesProvider(); + $defaultProvider->register($this); + } + + /******************************************************************************** + * Methods to satisfy Interop\Container\ContainerInterface + *******************************************************************************/ + + /** + * Finds an entry of the container by its identifier and returns it. + * + * @param string $id Identifier of the entry to look for. + * + * @throws ContainerValueNotFoundException No entry was found for this identifier. + * @throws ContainerException Error while retrieving the entry. + * + * @return mixed Entry. + */ + public function get($id) + { + if (!$this->offsetExists($id)) { + throw new ContainerValueNotFoundException(sprintf('Identifier "%s" is not defined.', $id)); + } + try { + return $this->offsetGet($id); + } catch (\InvalidArgumentException $exception) { + if ($this->exceptionThrownByContainer($exception)) { + throw new SlimContainerException( + sprintf('Container error while retrieving "%s"', $id), + null, + $exception + ); + } else { + throw $exception; + } + } + } + + /** + * Tests whether an exception needs to be recast for compliance with Container-Interop. This will be if the + * exception was thrown by Pimple. + * + * @param \InvalidArgumentException $exception + * + * @return bool + */ + private function exceptionThrownByContainer(\InvalidArgumentException $exception) + { + $trace = $exception->getTrace()[0]; + + return $trace['class'] === PimpleContainer::class && $trace['function'] === 'offsetGet'; + } + + /** + * Returns true if the container can return an entry for the given identifier. + * Returns false otherwise. + * + * @param string $id Identifier of the entry to look for. + * + * @return boolean + */ + public function has($id) + { + return $this->offsetExists($id); + } + + + /******************************************************************************** + * Magic methods for convenience + *******************************************************************************/ + + public function __get($name) + { + return $this->get($name); + } + + public function __isset($name) + { + return $this->has($name); + } +} diff --git a/api/vendor/slim/slim/Slim/DefaultServicesProvider.php b/api/vendor/slim/slim/Slim/DefaultServicesProvider.php new file mode 100644 index 0000000..5e1398d --- /dev/null +++ b/api/vendor/slim/slim/Slim/DefaultServicesProvider.php @@ -0,0 +1,203 @@ +get('environment')); + }; + } + + if (!isset($container['response'])) { + /** + * PSR-7 Response object + * + * @param Container $container + * + * @return ResponseInterface + */ + $container['response'] = function ($container) { + $headers = new Headers(['Content-Type' => 'text/html; charset=UTF-8']); + $response = new Response(200, $headers); + + return $response->withProtocolVersion($container->get('settings')['httpVersion']); + }; + } + + if (!isset($container['router'])) { + /** + * This service MUST return a SHARED instance + * of \Slim\Interfaces\RouterInterface. + * + * @param Container $container + * + * @return RouterInterface + */ + $container['router'] = function ($container) { + $routerCacheFile = false; + if (isset($container->get('settings')['routerCacheFile'])) { + $routerCacheFile = $container->get('settings')['routerCacheFile']; + } + + return (new Router)->setCacheFile($routerCacheFile); + }; + } + + if (!isset($container['foundHandler'])) { + /** + * This service MUST return a SHARED instance + * of \Slim\Interfaces\InvocationStrategyInterface. + * + * @return InvocationStrategyInterface + */ + $container['foundHandler'] = function () { + return new RequestResponse; + }; + } + + if (!isset($container['phpErrorHandler'])) { + /** + * This service MUST return a callable + * that accepts three arguments: + * + * 1. Instance of \Psr\Http\Message\ServerRequestInterface + * 2. Instance of \Psr\Http\Message\ResponseInterface + * 3. Instance of \Error + * + * The callable MUST return an instance of + * \Psr\Http\Message\ResponseInterface. + * + * @param Container $container + * + * @return callable + */ + $container['phpErrorHandler'] = function ($container) { + return new PhpError($container->get('settings')['displayErrorDetails']); + }; + } + + if (!isset($container['errorHandler'])) { + /** + * This service MUST return a callable + * that accepts three arguments: + * + * 1. Instance of \Psr\Http\Message\ServerRequestInterface + * 2. Instance of \Psr\Http\Message\ResponseInterface + * 3. Instance of \Exception + * + * The callable MUST return an instance of + * \Psr\Http\Message\ResponseInterface. + * + * @param Container $container + * + * @return callable + */ + $container['errorHandler'] = function ($container) { + return new Error($container->get('settings')['displayErrorDetails']); + }; + } + + if (!isset($container['notFoundHandler'])) { + /** + * This service MUST return a callable + * that accepts two arguments: + * + * 1. Instance of \Psr\Http\Message\ServerRequestInterface + * 2. Instance of \Psr\Http\Message\ResponseInterface + * + * The callable MUST return an instance of + * \Psr\Http\Message\ResponseInterface. + * + * @return callable + */ + $container['notFoundHandler'] = function () { + return new NotFound; + }; + } + + if (!isset($container['notAllowedHandler'])) { + /** + * This service MUST return a callable + * that accepts three arguments: + * + * 1. Instance of \Psr\Http\Message\ServerRequestInterface + * 2. Instance of \Psr\Http\Message\ResponseInterface + * 3. Array of allowed HTTP methods + * + * The callable MUST return an instance of + * \Psr\Http\Message\ResponseInterface. + * + * @return callable + */ + $container['notAllowedHandler'] = function () { + return new NotAllowed; + }; + } + + if (!isset($container['callableResolver'])) { + /** + * Instance of \Slim\Interfaces\CallableResolverInterface + * + * @param Container $container + * + * @return CallableResolverInterface + */ + $container['callableResolver'] = function ($container) { + return new CallableResolver($container); + }; + } + } +} diff --git a/api/vendor/slim/slim/Slim/DeferredCallable.php b/api/vendor/slim/slim/Slim/DeferredCallable.php new file mode 100644 index 0000000..af5aed7 --- /dev/null +++ b/api/vendor/slim/slim/Slim/DeferredCallable.php @@ -0,0 +1,45 @@ +callable = $callable; + $this->container = $container; + } + + public function __invoke() + { + $callable = $this->resolveCallable($this->callable); + if ($callable instanceof Closure) { + $callable = $callable->bindTo($this->container); + } + + $args = func_get_args(); + + return call_user_func_array($callable, $args); + } +} diff --git a/api/vendor/slim/slim/Slim/Exception/ContainerException.php b/api/vendor/slim/slim/Slim/Exception/ContainerException.php new file mode 100644 index 0000000..0200e1a --- /dev/null +++ b/api/vendor/slim/slim/Slim/Exception/ContainerException.php @@ -0,0 +1,20 @@ +allowedMethods = $allowedMethods; + } + + /** + * Get allowed methods + * + * @return string[] + */ + public function getAllowedMethods() + { + return $this->allowedMethods; + } +} diff --git a/api/vendor/slim/slim/Slim/Exception/NotFoundException.php b/api/vendor/slim/slim/Slim/Exception/NotFoundException.php new file mode 100644 index 0000000..65365eb --- /dev/null +++ b/api/vendor/slim/slim/Slim/Exception/NotFoundException.php @@ -0,0 +1,14 @@ +request = $request; + $this->response = $response; + } + + /** + * Get request + * + * @return ServerRequestInterface + */ + public function getRequest() + { + return $this->request; + } + + /** + * Get response + * + * @return ResponseInterface + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/AbstractError.php b/api/vendor/slim/slim/Slim/Handlers/AbstractError.php new file mode 100644 index 0000000..5a6cee3 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/AbstractError.php @@ -0,0 +1,99 @@ +displayErrorDetails = (bool) $displayErrorDetails; + } + + /** + * Write to the error log if displayErrorDetails is false + * + * @param \Exception|\Throwable $throwable + * + * @return void + */ + protected function writeToErrorLog($throwable) + { + if ($this->displayErrorDetails) { + return; + } + + $message = 'Slim Application Error:' . PHP_EOL; + $message .= $this->renderThrowableAsText($throwable); + while ($throwable = $throwable->getPrevious()) { + $message .= PHP_EOL . 'Previous error:' . PHP_EOL; + $message .= $this->renderThrowableAsText($throwable); + } + + $message .= PHP_EOL . 'View in rendered output by enabling the "displayErrorDetails" setting.' . PHP_EOL; + + $this->logError($message); + } + + /** + * Render error as Text. + * + * @param \Exception|\Throwable $throwable + * + * @return string + */ + protected function renderThrowableAsText($throwable) + { + $text = sprintf('Type: %s' . PHP_EOL, get_class($throwable)); + + if ($code = $throwable->getCode()) { + $text .= sprintf('Code: %s' . PHP_EOL, $code); + } + + if ($message = $throwable->getMessage()) { + $text .= sprintf('Message: %s' . PHP_EOL, htmlentities($message)); + } + + if ($file = $throwable->getFile()) { + $text .= sprintf('File: %s' . PHP_EOL, $file); + } + + if ($line = $throwable->getLine()) { + $text .= sprintf('Line: %s' . PHP_EOL, $line); + } + + if ($trace = $throwable->getTraceAsString()) { + $text .= sprintf('Trace: %s', $trace); + } + + return $text; + } + + /** + * Wraps the error_log function so that this can be easily tested + * + * @param $message + */ + protected function logError($message) + { + error_log($message); + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/AbstractHandler.php b/api/vendor/slim/slim/Slim/Handlers/AbstractHandler.php new file mode 100644 index 0000000..decdf72 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/AbstractHandler.php @@ -0,0 +1,59 @@ +getHeaderLine('Accept'); + $selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes); + + if (count($selectedContentTypes)) { + return current($selectedContentTypes); + } + + // handle +json and +xml specially + if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) { + $mediaType = 'application/' . $matches[1]; + if (in_array($mediaType, $this->knownContentTypes)) { + return $mediaType; + } + } + + return 'text/html'; + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/Error.php b/api/vendor/slim/slim/Slim/Handlers/Error.php new file mode 100644 index 0000000..b995188 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/Error.php @@ -0,0 +1,206 @@ +determineContentType($request); + switch ($contentType) { + case 'application/json': + $output = $this->renderJsonErrorMessage($exception); + break; + + case 'text/xml': + case 'application/xml': + $output = $this->renderXmlErrorMessage($exception); + break; + + case 'text/html': + $output = $this->renderHtmlErrorMessage($exception); + break; + + default: + throw new UnexpectedValueException('Cannot render unknown content type ' . $contentType); + } + + $this->writeToErrorLog($exception); + + $body = new Body(fopen('php://temp', 'r+')); + $body->write($output); + + return $response + ->withStatus(500) + ->withHeader('Content-type', $contentType) + ->withBody($body); + } + + /** + * Render HTML error page + * + * @param \Exception $exception + * + * @return string + */ + protected function renderHtmlErrorMessage(\Exception $exception) + { + $title = 'Slim Application Error'; + + if ($this->displayErrorDetails) { + $html = '
The application could not run because of the following error:
'; + $html .= 'A website error has occurred. Sorry for the temporary inconvenience.
'; + } + + $output = sprintf( + "" . + "%s', htmlentities($trace)); + } + + return $html; + } + + /** + * Render JSON error + * + * @param \Exception $exception + * + * @return string + */ + protected function renderJsonErrorMessage(\Exception $exception) + { + $error = [ + 'message' => 'Slim Application Error', + ]; + + if ($this->displayErrorDetails) { + $error['exception'] = []; + + do { + $error['exception'][] = [ + 'type' => get_class($exception), + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + 'trace' => explode("\n", $exception->getTraceAsString()), + ]; + } while ($exception = $exception->getPrevious()); + } + + return json_encode($error, JSON_PRETTY_PRINT); + } + + /** + * Render XML error + * + * @param \Exception $exception + * + * @return string + */ + protected function renderXmlErrorMessage(\Exception $exception) + { + $xml = "
" . $exception->getCode() . "
\n";
+ $xml .= " Method not allowed. Must be one of: $allow
+ +