git-svn-id: https://msi/svn/firstRepo/Service/branches/Slim3@40 0f545695-f87b-41b6-9a03-7f16563b5454

This commit is contained in:
2016-01-05 21:43:12 +00:00
parent 4318dd829f
commit 00d78a2ba8
46 changed files with 4960 additions and 32 deletions
+5
View File
@@ -0,0 +1,5 @@
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ serviceapp.php [QSA,L]
</ifModule>
+33
View File
@@ -0,0 +1,33 @@
<?php
class CheckFromMW
{
/**
* Example middleware invokable class
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke($request, $response, $next)
{
$currentRefererRequest = $request->getHost();
$currentRefererRequest = substr($currentRefererRequest, 7); //Senza http://
$indexDoublePoint = strpos($currentRefererRequest, ':');
$indexFirstSlash = strpos($currentRefererRequest, '/');
$currentRefererRequest = substr($currentRefererRequest, 0, $indexDoublePoint > 0 && $indexDoublePoint < $indexFirstSlash ? $indexDoublePoint : $indexFirstSlash );
if(!in_array($currentRefererRequest, $allowedHost))
{
return $response->withStatus(500)->write('Generic error occurred');
}
*/
$currentHostRequest = $app->request()->getHost();
if(!in_array($currentHostRequest, $allowedHost))
{
return $response->withStatus(403)->write('Request arrive from host not allowed');
}
return $next($request, $response);
}
}
+89
View File
@@ -0,0 +1,89 @@
<?php
class MysqlClass
{
// parametri per la connessione al database
/*private $nomehost = "mysql.hostinger.it";
private $nomeuser = "u766568765_lpm";
private $password = "8zX2gTIjfwXEdEgaSaWe";
private $mydb = "u766568765_lpm";
*/
private $nomehost = "sql.gruppolapastamadre.it";
private $nomeuser = "w18092_ricuser";
private $password = "RTvg0o6IESoqQyx8CCJn";
private $mydb = "w18092_ricettario";
// controllo sulle connessioni attive
private $attiva = false;
private $connessione = null;
// funzione per la connessione a MySQL
public function connetti()
{
if(!$this->attiva)
{
$this->connessione = mysql_connect($this->nomehost,$this->nomeuser,$this->password);
if ($this->connessione == FALSE)
die(mysql_error());
mysql_select_db($this->mydb, $this->connessione) or die ("Errore nella selezione del database. Verificare i parametri nel file config.inc.php");
$this->attiva = true;
}
else{
return true;
}
}
public function executeQuery($queryStr)
{
$this->connetti();
if (!$res = mysql_query($queryStr, $this->connessione)) die(mysql_error());
return true;
return false;
}
public function insertRecord($queryStr)
{
$this->connetti();
if (!$res = mysql_query($queryStr, $this->connessione)) die(mysql_error());
return mysql_insert_id();
}
public function queryToObject($queryStr)
{
$this->connetti();
$sth = mysql_query($queryStr, $this->connessione) or die(mysql_error());
$rows = array();
while($r = mysql_fetch_assoc($sth)) {
array_push($rows,array_map('utf8_encode', $r));
}
mysql_free_result($sth);
return $rows;
}
// funzione per la chiusura della connessione
public function disconnetti()
{
if($this->attiva)
{
if(mysql_close($this->connessione))
{
$this->attiva = false;
return true;
}
else
{
return false;
}
}
}
public function __destruct()
{
$this->disconnetti();
}
}
?>
+104
View File
@@ -0,0 +1,104 @@
<?php
class SimpleImage {
var $image;
var $image_type;
function load($filename) {
$image_info = getimagesize($filename);
$this->image_type = $image_info[2];
if ($this->image_type == IMAGETYPE_JPEG) {
$this->image = imagecreatefromjpeg($filename);
} elseif ($this->image_type == IMAGETYPE_GIF) {
$this->image = imagecreatefromgif($filename);
} elseif ($this->image_type == IMAGETYPE_PNG) {
$this->image = imagecreatefrompng($filename);
}
}
function saveas($filename, $image_type = IMAGETYPE_JPEG, $compression = 75, $permissions = null) {
if ($image_type == IMAGETYPE_JPEG) {
imagejpeg($this->image, $filename, $compression);
} elseif ($image_type == IMAGETYPE_GIF) {
imagegif($this->image, $filename);
} elseif ($image_type == IMAGETYPE_PNG) {
imagepng($this->image, $filename);
} if ($permissions != null) {
chmod($filename, $permissions);
}
}
function save($filename) {
if ($this->image_type == IMAGETYPE_JPEG) {
imagejpeg($this->image, $filename);
} elseif ($this->image_type == IMAGETYPE_GIF) {
imagegif($this->image, $filename);
} elseif ($this->image_type == IMAGETYPE_PNG) {
imagepng($this->image, $filename);
}
}
function output($image_type = IMAGETYPE_JPEG) {
if ($image_type == IMAGETYPE_JPEG) {
imagejpeg($this->image);
} elseif ($image_type == IMAGETYPE_GIF) {
imagegif($this->image);
} elseif ($image_type == IMAGETYPE_PNG) {
imagepng($this->image);
}
}
function getWidth() {
return imagesx($this->image);
}
function getHeight() {
return imagesy($this->image);
}
function resizeToHeight($height) {
$ratio = $height / $this->getHeight();
$width = $this->getWidth() * $ratio;
$this->resize($width, $height);
}
function resizeToWidth($width) {
$ratio = $width / $this->getWidth();
$height = $this->getheight() * $ratio;
$this->resize($width, $height);
}
function scale($scale) {
$width = $this->getWidth() * $scale / 100;
$height = $this->getheight() * $scale / 100;
$this->resize($width, $height);
}
function resize($width, $height) {
$new_image = imagecreatetruecolor($width, $height);
if ($this->image_type == IMAGETYPE_GIF || $this->image_type == IMAGETYPE_PNG) {
$current_transparent = imagecolortransparent($this->image);
if ($current_transparent != -1) {
$transparent_color = imagecolorsforindex($this->image, $current_transparent);
$current_transparent = imagecolorallocate($new_image, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
imagefill($new_image, 0, 0, $current_transparent);
imagecolortransparent($new_image, $current_transparent);
} elseif ($this->image_type == IMAGETYPE_PNG) {
imagealphablending($new_image, false);
$color = imagecolorallocatealpha($new_image, 0, 0, 0, 127);
imagefill($new_image, 0, 0, $color);
imagesavealpha($new_image, true);
}
}
imagecopyresampled($new_image, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight());
$this->image = $new_image;
}
function close()
{
imagedestroy($this->image);
}
}
?>
+555
View File
@@ -0,0 +1,555 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use Exception;
use Closure;
use InvalidArgumentException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Interop\Container\ContainerInterface;
use FastRoute\Dispatcher;
use Slim\Exception\SlimException;
use Slim\Exception\MethodNotAllowedException;
use Slim\Exception\NotFoundException;
use Slim\Http\Uri;
use Slim\Http\Headers;
use Slim\Http\Body;
use Slim\Http\Request;
use Slim\Interfaces\Http\EnvironmentInterface;
use Slim\Interfaces\RouteGroupInterface;
use Slim\Interfaces\RouteInterface;
use Slim\Interfaces\RouterInterface;
/**
* App
*
* This is the primary class with which you instantiate,
* configure, and run a Slim Framework application.
* The \Slim\App class also accepts Slim Framework middleware.
*
* @property-read array $settings App settings
* @property-read EnvironmentInterface $environment
* @property-read RequestInterface $request
* @property-read ResponseInterface $response
* @property-read RouterInterface $router
* @property-read callable $errorHandler
* @property-read callable $notFoundHandler function($request, $response)
* @property-read callable $notAllowedHandler function($request, $response, $allowedHttpMethods)
*/
class App
{
use CallableResolverAwareTrait;
use MiddlewareAwareTrait;
/**
* Current version
*
* @var string
*/
const VERSION = '3.0.0';
/**
* Container
*
* @var ContainerInterface
*/
private $container;
/********************************************************************************
* Constructor
*******************************************************************************/
/**
* Create new application
*
* @param ContainerInterface|array $container Either a ContainerInterface or an associative array of application settings
* @throws InvalidArgumentException when no container is provided that implements ContainerInterface
*/
public function __construct($container = [])
{
if (is_array($container)) {
$container = new Container($container);
}
if (!$container instanceof ContainerInterface) {
throw new InvalidArgumentException('Expected a ContainerInterface');
}
$this->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 mixed $callable The callback routine
*
* @return static
*/
public function add($callable)
{
$callable = $this->resolveCallable($callable);
if ($callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
return $this->addMiddleware($callable);
}
/**
* Calling a non-existant method on App checks to see if there's an item
* in the container than 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);
}
}
}
/********************************************************************************
* Router proxy methods
*******************************************************************************/
/**
* Add GET route
*
* @param string $pattern The route URI pattern
* @param mixed $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 mixed $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 mixed $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 mixed $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 mixed $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 mixed $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 mixed $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 mixed $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');
// 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 (MethodNotAllowedException $e) {
if (!$this->container->has('notAllowedHandler')) {
throw $e;
}
/** @var callable $notAllowedHandler */
$notAllowedHandler = $this->container->get('notAllowedHandler');
$response = $notAllowedHandler($e->getRequest(), $e->getResponse(), $e->getAllowedMethods());
} catch (NotFoundException $e) {
if (!$this->container->has('notFoundHandler')) {
throw $e;
}
/** @var callable $notFoundHandler */
$notFoundHandler = $this->container->get('notFoundHandler');
$response = $notFoundHandler($e->getRequest(), $e->getResponse());
} catch (SlimException $e) {
$response = $e->getResponse();
} catch (Exception $e) {
if (!$this->container->has('errorHandler')) {
throw $e;
}
/** @var callable $errorHandler */
$errorHandler = $this->container->get('errorHandler');
$response = $errorHandler($request, $response, $e);
}
$response = $this->finalize($response);
if (!$silent) {
$this->respond($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();
}
$totalChunks = ceil($contentLength / $chunkSize);
$lastChunkSize = $contentLength % $chunkSize;
$currentChunk = 0;
while (!$body->eof() && $currentChunk < $totalChunks) {
if (++$currentChunk == $totalChunks && $lastChunkSize > 0) {
$chunkSize = $lastChunkSize;
}
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');
}
$size = $response->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]);
}
}
+87
View File
@@ -0,0 +1,87 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use RuntimeException;
use Interop\Container\ContainerInterface;
use Slim\Interfaces\CallableResolverInterface;
/**
* This class resolves a string of the format 'class:method' into a closure
* that can be dispatched.
*/
final class CallableResolver implements CallableResolverInterface
{
/**
* @var ContainerInterface
*/
private $container;
/**
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->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', $toResolve));
}
return $resolved;
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use RuntimeException;
use Interop\Container\ContainerInterface;
use Slim\Interfaces\CallableResolverInterface;
/**
* ResolveCallable
*
* This is an internal class that enables resolution of 'class:method' strings
* into a closure. This class is an implementation detail and is used only inside
* of the Slim application.
*
* @property ContainerInterface $container
*/
trait CallableResolverAwareTrait
{
/**
* Resolve a string of the format 'class:method' into a closure that the
* router can dispatch.
*
* @param mixed $callable
*
* @return \Closure
*
* @throws RuntimeException If the string cannot be resolved as a callable
*/
protected function resolveCallable($callable)
{
if (!$this->container instanceof ContainerInterface) {
return $callable;
}
/** @var CallableResolverInterface $resolver */
$resolver = $this->container->get('callableResolver');
return $resolver->resolve($callable);
}
}
+204
View File
@@ -0,0 +1,204 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use ArrayIterator;
use Slim\Interfaces\CollectionInterface;
/**
* Collection
*
* This class provides a common interface used by many other
* classes in a Slim application that manage "collections"
* of data that must be inspected and/or manipulated
*/
class Collection implements CollectionInterface
{
/**
* The source data
*
* @var array
*/
protected $data = [];
/**
* Create new collection
*
* @param array $items Pre-populate collection with this key-value array
*/
public function __construct(array $items = [])
{
foreach ($items as $key => $value) {
$this->set($key, $value);
}
}
/********************************************************************************
* 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
*
* @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);
}
}
+296
View File
@@ -0,0 +1,296 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use Interop\Container\ContainerInterface;
use Interop\Container\Exception\ContainerException;
use Pimple\Container as PimpleContainer;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Exception\ContainerValueNotFoundException;
use Slim\Handlers\Error;
use Slim\Handlers\NotFound;
use Slim\Handlers\NotAllowed;
use Slim\Handlers\Strategies\RequestResponse;
use Slim\Http\Environment;
use Slim\Http\Headers;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Interfaces\CallableResolverInterface;
use Slim\Interfaces\Http\EnvironmentInterface;
use Slim\Interfaces\InvocationStrategyInterface;
use Slim\Interfaces\RouterInterface;
/**
* Slim's default DI container is Pimple.
*
* Slim\App expects a container that implements Interop\Container\ContainerInterface
* with these service keys configured and ready for use:
*
* - settings: an array or instance of \ArrayAccess
* - environment: an instance of \Slim\Interfaces\Http\EnvironmentInterface
* - request: an instance of \Psr\Http\Message\ServerRequestInterface
* - response: an instance of \Psr\Http\Message\ResponseInterface
* - router: an instance of \Slim\Interfaces\RouterInterface
* - foundHandler: an instance of \Slim\Interfaces\InvocationStrategyInterface
* - errorHandler: a callable with the signature: function($request, $response, $exception)
* - notFoundHandler: a callable with the signature: function($request, $response)
* - notAllowedHandler: a callable with the signature: function($request, $response, $allowedHttpMethods)
* - callableResolver: an instance of callableResolver
*
* @property-read array settings
* @property-read \Slim\Interfaces\Http\EnvironmentInterface environment
* @property-read \Psr\Http\Message\ServerRequestInterface request
* @property-read \Psr\Http\Message\ResponseInterface response
* @property-read \Slim\Interfaces\RouterInterface router
* @property-read \Slim\Interfaces\InvocationStrategyInterface foundHandler
* @property-read callable errorHandler
* @property-read callable notFoundHandler
* @property-read callable notAllowedHandler
* @property-read \Slim\Interfaces\CallableResolverInterface callableResolver
*/
final class Container extends PimpleContainer implements ContainerInterface
{
/**
* Default settings
*
* @var array
*/
private $defaultSettings = [
'httpVersion' => '1.1',
'responseChunkSize' => 4096,
'outputBuffering' => 'append',
'determineRouteBeforeAppMiddleware' => false,
'displayErrorDetails' => 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));
};
if (!isset($this['environment'])) {
/**
* This service MUST return a shared instance
* of \Slim\Interfaces\Http\EnvironmentInterface.
*
* @return EnvironmentInterface
*/
$this['environment'] = function () {
return new Environment($_SERVER);
};
}
if (!isset($this['request'])) {
/**
* PSR-7 Request object
*
* @param Container $c
*
* @return ServerRequestInterface
*/
$this['request'] = function ($c) {
return Request::createFromEnvironment($c->get('environment'));
};
}
if (!isset($this['response'])) {
/**
* PSR-7 Response object
*
* @param Container $c
*
* @return ResponseInterface
*/
$this['response'] = function ($c) {
$headers = new Headers(['Content-Type' => 'text/html; charset=UTF-8']);
$response = new Response(200, $headers);
return $response->withProtocolVersion($c->get('settings')['httpVersion']);
};
}
if (!isset($this['router'])) {
/**
* This service MUST return a SHARED instance
* of \Slim\Interfaces\RouterInterface.
*
* @return RouterInterface
*/
$this['router'] = function () {
return new Router;
};
}
if (!isset($this['foundHandler'])) {
/**
* This service MUST return a SHARED instance
* of \Slim\Interfaces\InvocationStrategyInterface.
*
* @return InvocationStrategyInterface
*/
$this['foundHandler'] = function () {
return new RequestResponse;
};
}
if (!isset($this['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 $c
*
* @return callable
*/
$this['errorHandler'] = function ($c) {
return new Error($c->get('settings')['displayErrorDetails']);
};
}
if (!isset($this['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
*/
$this['notFoundHandler'] = function () {
return new NotFound;
};
}
if (!isset($this['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
*/
$this['notAllowedHandler'] = function () {
return new NotAllowed;
};
}
if (!isset($this['callableResolver'])) {
/**
* Instance of \Slim\Interfaces\CallableResolverInterface
*
* @param Container $c
*
* @return CallableResolverInterface
*/
$this['callableResolver'] = function ($c) {
return new CallableResolver($c);
};
}
}
/********************************************************************************
* 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));
}
return $this->offsetGet($id);
}
/**
* 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);
}
}
@@ -0,0 +1,20 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/codeguy/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/codeguy/Slim/blob/master/LICENSE (MIT License)
*/
namespace Slim\Exception;
use RuntimeException;
use Interop\Container\Exception\NotFoundException as InteropNotFoundException;
/**
* Not Found Exception
*/
class ContainerValueNotFoundException extends RuntimeException implements InteropNotFoundException
{
}
@@ -0,0 +1,39 @@
<?php
namespace Slim\Exception;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
class MethodNotAllowedException extends SlimException
{
/**
* HTTP methods allowed
*
* @var string[]
*/
protected $allowedMethods;
/**
* Create new exception
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param string[] $allowedMethods
*/
public function __construct(ServerRequestInterface $request, ResponseInterface $response, array $allowedMethods)
{
parent::__construct($request, $response);
$this->allowedMethods = $allowedMethods;
}
/**
* Get allowed methods
*
* @return string[]
*/
public function getAllowedMethods()
{
return $this->allowedMethods;
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace Slim\Exception;
class NotFoundException extends SlimException
{
}
+69
View File
@@ -0,0 +1,69 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Exception;
use Exception;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Stop Exception
*
* This Exception is thrown when the Slim application needs to abort
* processing and return control flow to the outer PHP script.
*/
class SlimException extends Exception
{
/**
* A request object
*
* @var ServerRequestInterface
*/
protected $request;
/**
* A response object to send to the HTTP client
*
* @var ResponseInterface
*/
protected $response;
/**
* Create new exception
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
*/
public function __construct(ServerRequestInterface $request, ResponseInterface $response)
{
parent::__construct();
$this->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;
}
}
+239
View File
@@ -0,0 +1,239 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Handlers;
use Exception;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Http\Body;
/**
* Default Slim application error handler
*
* It outputs the error message and diagnostic information in either JSON, XML,
* or HTML based on the Accept header.
*/
class Error
{
protected $displayErrorDetails;
/**
* Known handled content types
*
* @var array
*/
protected $knownContentTypes = [
'application/json',
'application/xml',
'text/xml',
'text/html',
];
/**
* Constructor
*
* @param boolean $displayErrorDetails Set to true to display full details
*/
public function __construct($displayErrorDetails = false)
{
$this->displayErrorDetails = (bool)$displayErrorDetails;
}
/**
* Invoke error handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param ResponseInterface $response The most recent Response object
* @param Exception $exception The caught Exception object
*
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Exception $exception)
{
$contentType = $this->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;
}
$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 = '<p>The application could not run because of the following error:</p>';
$html .= '<h2>Details</h2>';
$html .= $this->renderHtmlException($exception);
while ($exception = $exception->getPrevious()) {
$html .= '<h2>Previous exception</h2>';
$html .= $this->renderHtmlException($exception);
}
} else {
$html = '<p>A website error has occurred. Sorry for the temporary inconvenience.</p>';
}
$output = sprintf(
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>" .
"<title>%s</title><style>body{margin:0;padding:30px;font:12px/1.5 Helvetica,Arial,Verdana," .
"sans-serif;}h1{margin:0;font-size:48px;font-weight:normal;line-height:48px;}strong{" .
"display:inline-block;width:65px;}</style></head><body><h1>%s</h1>%s</body></html>",
$title,
$title,
$html
);
return $output;
}
/**
* Render exception as HTML.
*
* @param Exception $exception
*
* @return string
*/
protected function renderHtmlException(Exception $exception)
{
$html = sprintf('<div><strong>Type:</strong> %s</div>', get_class($exception));
if (($code = $exception->getCode())) {
$html .= sprintf('<div><strong>Code:</strong> %s</div>', $code);
}
if (($message = $exception->getMessage())) {
$html .= sprintf('<div><strong>Message:</strong> %s</div>', htmlentities($message));
}
if (($file = $exception->getFile())) {
$html .= sprintf('<div><strong>File:</strong> %s</div>', $file);
}
if (($line = $exception->getLine())) {
$html .= sprintf('<div><strong>Line:</strong> %s</div>', $line);
}
if (($trace = $exception->getTraceAsString())) {
$html .= '<h2>Trace</h2>';
$html .= sprintf('<pre>%s</pre>', 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 = "<error>\n <message>Slim Application Error</message>\n";
if ($this->displayErrorDetails) {
do {
$xml .= " <exception>\n";
$xml .= " <type>" . get_class($exception) . "</type>\n";
$xml .= " <code>" . $exception->getCode() . "</code>\n";
$xml .= " <message>" . $this->createCdataSection($exception->getMessage()) . "</message>\n";
$xml .= " <file>" . $exception->getFile() . "</file>\n";
$xml .= " <line>" . $exception->getLine() . "</line>\n";
$xml .= " <trace>" . $this->createCdataSection($exception->getTraceAsString()) . "</trace>\n";
$xml .= " </exception>\n";
} while ($exception = $exception->getPrevious());
}
$xml .= "</error>";
return $xml;
}
/**
* Returns a CDATA section with the given content.
*
* @param string $content
* @return string
*/
private function createCdataSection($content)
{
return sprintf('<![CDATA[%s]]>', str_replace(']]>', ']]]]><![CDATA[>', $content));
}
/**
* Determine which content type we know about is wanted using Accept header
*
* @param ServerRequestInterface $request
* @return string
*/
private function determineContentType(ServerRequestInterface $request)
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes);
if (count($selectedContentTypes)) {
return $selectedContentTypes[0];
}
return 'text/html';
}
}
+173
View File
@@ -0,0 +1,173 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Handlers;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Http\Body;
/**
* Default Slim application not allowed handler
*
* It outputs a simple message in either JSON, XML or HTML based on the
* Accept header.
*/
class NotAllowed
{
/**
* Known handled content types
*
* @var array
*/
protected $knownContentTypes = [
'application/json',
'application/xml',
'text/xml',
'text/html',
];
/**
* Invoke error handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param ResponseInterface $response The most recent Response object
* @param string[] $methods Allowed HTTP methods
*
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, array $methods)
{
if ($request->getMethod() === 'OPTIONS') {
$status = 200;
$contentType = 'text/plain';
$output = $this->renderPlainNotAllowedMessage($methods);
} else {
$status = 405;
$contentType = $this->determineContentType($request);
switch ($contentType) {
case 'application/json':
$output = $this->renderJsonNotAllowedMessage($methods);
break;
case 'text/xml':
case 'application/xml':
$output = $this->renderXmlNotAllowedMessage($methods);
break;
case 'text/html':
$output = $this->renderHtmlNotAllowedMessage($methods);
break;
}
}
$body = new Body(fopen('php://temp', 'r+'));
$body->write($output);
$allow = implode(', ', $methods);
return $response
->withStatus($status)
->withHeader('Content-type', $contentType)
->withHeader('Allow', $allow)
->withBody($body);
}
/**
* Determine which content type we know about is wanted using Accept header
*
* @param ServerRequestInterface $request
* @return string
*/
private function determineContentType(ServerRequestInterface $request)
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes);
if (count($selectedContentTypes)) {
return $selectedContentTypes[0];
}
return 'text/html';
}
/**
* Render PLAIN not allowed message
*
* @param array $methods
* @return string
*/
protected function renderPlainNotAllowedMessage($methods)
{
$allow = implode(', ', $methods);
return 'Allowed methods: ' . $allow;
}
/**
* Render JSON not allowed message
*
* @param array $methods
* @return string
*/
protected function renderJsonNotAllowedMessage($methods)
{
$allow = implode(', ', $methods);
return '{"message":"Method not allowed. Must be one of: ' . $allow . '"}';
}
/**
* Render XML not allowed message
*
* @param array $methods
* @return string
*/
protected function renderXmlNotAllowedMessage($methods)
{
$allow = implode(', ', $methods);
return "<root><message>Method not allowed. Must be one of: $allow</message></root>";
}
/**
* Render HTML not allowed message
*
* @param array $methods
* @return string
*/
protected function renderHtmlNotAllowedMessage($methods)
{
$allow = implode(', ', $methods);
$output = <<<END
<html>
<head>
<title>Method not allowed</title>
<style>
body{
margin:0;
padding:30px;
font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;
}
h1{
margin:0;
font-size:48px;
font-weight:normal;
line-height:48px;
}
</style>
</head>
<body>
<h1>Method not allowed</h1>
<p>Method not allowed. Must be one of: <strong>$allow</strong></p>
</body>
</html>
END;
return $output;
}
}
+157
View File
@@ -0,0 +1,157 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Handlers;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Slim\Http\Body;
/**
* Default Slim application not found handler.
*
* It outputs a simple message in either JSON, XML or HTML based on the
* Accept header.
*/
class NotFound
{
/**
* Known handled content types
*
* @var array
*/
protected $knownContentTypes = [
'application/json',
'application/xml',
'text/xml',
'text/html',
];
/**
* Invoke not found handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param ResponseInterface $response The most recent Response object
*
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
{
$contentType = $this->determineContentType($request);
switch ($contentType) {
case 'application/json':
$output = $this->renderJsonNotFoundOutput($request, $response);
break;
case 'text/xml':
case 'application/xml':
$output = $this->renderXmlNotFoundOutput($request, $response);
break;
case 'text/html':
$output = $this->renderHtmlNotFoundOutput($request, $response);
}
$body = new Body(fopen('php://temp', 'r+'));
$body->write($output);
return $response->withStatus(404)
->withHeader('Content-Type', $contentType)
->withBody($body);
}
/**
* Determine which content type we know about is wanted using Accept header
*
* @param ServerRequestInterface $request
* @return string
*/
private function determineContentType(ServerRequestInterface $request)
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(explode(',', $acceptHeader), $this->knownContentTypes);
if (count($selectedContentTypes)) {
return $selectedContentTypes[0];
}
return 'text/html';
}
/**
* Return a response for application/json content not found
*
* @param ServerRequestInterface $request The most recent Request object
* @param ResponseInterface $response The most recent Response object
*
* @return ResponseInterface
*/
protected function renderJsonNotFoundOutput(ServerRequestInterface $request, ResponseInterface $response)
{
return '{"message":"Not found"}';
}
/**
* Return a response for xml content not found
*
* @param ServerRequestInterface $request The most recent Request object
* @param ResponseInterface $response The most recent Response object
*
* @return ResponseInterface
*/
protected function renderXmlNotFoundOutput(ServerRequestInterface $request, ResponseInterface $response)
{
return '<root><message>Not found</message></root>';
}
/**
* Return a response for text/html content not found
*
* @param ServerRequestInterface $request The most recent Request object
* @param ResponseInterface $response The most recent Response object
*
* @return ResponseInterface
*/
protected function renderHtmlNotFoundOutput(ServerRequestInterface $request, ResponseInterface $response)
{
$homeUrl = (string)($request->getUri()->withPath('')->withQuery('')->withFragment(''));
return <<<END
<html>
<head>
<title>Page Not Found</title>
<style>
body{
margin:0;
padding:30px;
font:12px/1.5 Helvetica,Arial,Verdana,sans-serif;
}
h1{
margin:0;
font-size:48px;
font-weight:normal;
line-height:48px;
}
strong{
display:inline-block;
width:65px;
}
</style>
</head>
<body>
<h1>Page Not Found</h1>
<p>
The page you are looking for could not be found. Check the address bar
to ensure your URL is spelled correctly. If all else fails, you can
visit our home page at the link below.
</p>
<a href='$homeUrl'>Visit the Home Page</a>
</body>
</html>
END;
}
}
@@ -0,0 +1,43 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\InvocationStrategyInterface;
/**
* Default route callback strategy with route parameters as an array of arguments.
*/
class RequestResponse implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response, and all route parameters
* as an array of arguments.
*
* @param array|callable $callable
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param array $routeArguments
*
* @return mixed
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
) {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
return call_user_func($callable, $request, $response, $routeArguments);
}
}
@@ -0,0 +1,42 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Handlers\Strategies;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\InvocationStrategyInterface;
/**
* Route callback strategy with route parameters as individual arguments.
*/
class RequestResponseArgs implements InvocationStrategyInterface
{
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array|callable $callable
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param array $routeArguments
*
* @return mixed
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
) {
array_unshift($routeArguments, $request, $response);
return call_user_func_array($callable, $routeArguments);
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
/**
* Body
*
* This class represents an HTTP message body and encapsulates a
* streamable resource according to the PSR-7 standard.
*
* @link https://github.com/php-fig/http-message/blob/master/src/StreamInterface.php
*/
class Body extends Stream
{
}
+52
View File
@@ -0,0 +1,52 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
use Slim\Collection;
use Slim\Interfaces\Http\EnvironmentInterface;
/**
* Environment
*
* This class decouples the Slim application from the global PHP environment.
* This is particularly useful for unit testing, but it also lets us create
* custom sub-requests.
*/
class Environment extends Collection implements EnvironmentInterface
{
/**
* Create mock environment
*
* @param array $userData Array of custom environment keys and values
*
* @return self
*/
public static function mock(array $userData = [])
{
$data = array_merge([
'SERVER_PROTOCOL' => 'HTTP/1.1',
'REQUEST_METHOD' => 'GET',
'SCRIPT_NAME' => '',
'REQUEST_URI' => '',
'QUERY_STRING' => '',
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
'HTTP_HOST' => 'localhost',
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8',
'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'HTTP_USER_AGENT' => 'Slim Framework',
'REMOTE_ADDR' => '127.0.0.1',
'REQUEST_TIME' => time(),
'REQUEST_TIME_FLOAT' => microtime(true),
], $userData);
return new static($data);
}
}
+295
View File
@@ -0,0 +1,295 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
use InvalidArgumentException;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;
/**
* Abstract message (base class for Request and Response)
*
* This class represents a general HTTP message. It provides common properties and methods for
* the HTTP request and response, as defined in the PSR-7 MessageInterface.
*
* @link https://github.com/php-fig/http-message/blob/master/src/MessageInterface.php
* @see Slim\Http\Request
* @see Slim\Http\Response
*/
abstract class Message implements MessageInterface
{
/**
* Protocol version
*
* @var string
*/
protected $protocolVersion = '1.1';
/**
* Headers
*
* @var \Slim\Interfaces\Http\HeadersInterface
*/
protected $headers;
/**
* Body object
*
* @var \Psr\Http\Message\StreamInterface
*/
protected $body;
/**
* Disable magic setter to ensure immutability
*/
public function __set($name, $value)
{
// Do nothing
}
/*******************************************************************************
* Protocol
******************************************************************************/
/**
* Retrieves the HTTP protocol version as a string.
*
* The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
*
* @return string HTTP protocol version.
*/
public function getProtocolVersion()
{
return $this->protocolVersion;
}
/**
* Return an instance with the specified HTTP protocol version.
*
* The version string MUST contain only the HTTP version number (e.g.,
* "1.1", "1.0").
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return an instance that has the
* new protocol version.
*
* @param string $version HTTP protocol version
* @return static
* @throws InvalidArgumentException if the http version is an invalid number
*/
public function withProtocolVersion($version)
{
static $valid = [
'1.0' => true,
'1.1' => true,
'2.0' => true,
];
if (!isset($valid[$version])) {
throw new InvalidArgumentException('Invalid HTTP version. Must be one of: 1.0, 1.1, 2.0');
}
$clone = clone $this;
$clone->protocolVersion = $version;
return $clone;
}
/*******************************************************************************
* Headers
******************************************************************************/
/**
* Retrieves all message header values.
*
* The keys represent the header name as it will be sent over the wire, and
* each value is an array of strings associated with the header.
*
* // Represent the headers as a string
* foreach ($message->getHeaders() as $name => $values) {
* echo $name . ": " . implode(", ", $values);
* }
*
* // Emit headers iteratively:
* foreach ($message->getHeaders() as $name => $values) {
* foreach ($values as $value) {
* header(sprintf('%s: %s', $name, $value), false);
* }
* }
*
* While header names are not case-sensitive, getHeaders() will preserve the
* exact case in which headers were originally specified.
*
* @return array Returns an associative array of the message's headers. Each
* key MUST be a header name, and each value MUST be an array of strings
* for that header.
*/
public function getHeaders()
{
return $this->headers->all();
}
/**
* Checks if a header exists by the given case-insensitive name.
*
* @param string $name Case-insensitive header field name.
* @return bool Returns true if any header names match the given header
* name using a case-insensitive string comparison. Returns false if
* no matching header name is found in the message.
*/
public function hasHeader($name)
{
return $this->headers->has($name);
}
/**
* Retrieves a message header value by the given case-insensitive name.
*
* This method returns an array of all the header values of the given
* case-insensitive header name.
*
* If the header does not appear in the message, this method MUST return an
* empty array.
*
* @param string $name Case-insensitive header field name.
* @return string[] An array of string values as provided for the given
* header. If the header does not appear in the message, this method MUST
* return an empty array.
*/
public function getHeader($name)
{
return $this->headers->get($name, []);
}
/**
* Retrieves a comma-separated string of the values for a single header.
*
* This method returns all of the header values of the given
* case-insensitive header name as a string concatenated together using
* a comma.
*
* NOTE: Not all header values may be appropriately represented using
* comma concatenation. For such headers, use getHeader() instead
* and supply your own delimiter when concatenating.
*
* If the header does not appear in the message, this method MUST return
* an empty string.
*
* @param string $name Case-insensitive header field name.
* @return string A string of values as provided for the given header
* concatenated together using a comma. If the header does not appear in
* the message, this method MUST return an empty string.
*/
public function getHeaderLine($name)
{
return implode(',', $this->headers->get($name, []));
}
/**
* Return an instance with the provided value replacing the specified header.
*
* While header names are case-insensitive, the casing of the header will
* be preserved by this function, and returned from getHeaders().
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return an instance that has the
* new and/or updated header and value.
*
* @param string $name Case-insensitive header field name.
* @param string|string[] $value Header value(s).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
*/
public function withHeader($name, $value)
{
$clone = clone $this;
$clone->headers->set($name, $value);
return $clone;
}
/**
* Return an instance with the specified header appended with the given value.
*
* Existing values for the specified header will be maintained. The new
* value(s) will be appended to the existing list. If the header did not
* exist previously, it will be added.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return an instance that has the
* new header and/or value.
*
* @param string $name Case-insensitive header field name to add.
* @param string|string[] $value Header value(s).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
*/
public function withAddedHeader($name, $value)
{
$clone = clone $this;
$clone->headers->add($name, $value);
return $clone;
}
/**
* Return an instance without the specified header.
*
* Header resolution MUST be done without case-sensitivity.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return an instance that removes
* the named header.
*
* @param string $name Case-insensitive header field name to remove.
* @return static
*/
public function withoutHeader($name)
{
$clone = clone $this;
$clone->headers->remove($name);
return $clone;
}
/*******************************************************************************
* Body
******************************************************************************/
/**
* Gets the body of the message.
*
* @return StreamInterface Returns the body as a stream.
*/
public function getBody()
{
return $this->body;
}
/**
* Return an instance with the specified message body.
*
* The body MUST be a StreamInterface object.
*
* This method MUST be implemented in such a way as to retain the
* immutability of the message, and MUST return a new instance that has the
* new body stream.
*
* @param StreamInterface $body Body.
* @return static
* @throws \InvalidArgumentException When the body is not valid.
*/
public function withBody(StreamInterface $body)
{
// TODO: Test for invalid body?
$clone = clone $this;
$clone->body = $body;
return $clone;
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
/**
* Provides a PSR-7 implementation of a reusable raw request body
*/
class RequestBody extends Body
{
/**
* Create a new RequestBody.
*/
public function __construct()
{
$stream = fopen('php://temp', 'w+');
stream_copy_to_stream(fopen('php://input', 'r'), $stream);
rewind($stream);
parent::__construct($stream);
}
}
+409
View File
@@ -0,0 +1,409 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
/**
* Represents a data stream as defined in PSR-7.
*
* @link https://github.com/php-fig/http-message/blob/master/src/StreamInterface.php
*/
class Stream implements StreamInterface
{
/**
* Resource modes
*
* @var array
* @link http://php.net/manual/function.fopen.php
*/
protected static $modes = [
'readable' => ['r', 'r+', 'w+', 'a+', 'x+', 'c+'],
'writable' => ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+'],
];
/**
* The underlying stream resource
*
* @var resource
*/
protected $stream;
/**
* Stream metadata
*
* @var array
*/
protected $meta;
/**
* Is this stream readable?
*
* @var bool
*/
protected $readable;
/**
* Is this stream writable?
*
* @var bool
*/
protected $writable;
/**
* Is this stream seekable?
*
* @var bool
*/
protected $seekable;
/**
* The size of the stream if known
*
* @var null|int
*/
protected $size;
/**
* Create a new Stream.
*
* @param resource $stream A PHP resource handle.
*
* @throws InvalidArgumentException If argument is not a resource.
*/
public function __construct($stream)
{
$this->attach($stream);
}
/**
* Get stream metadata as an associative array or retrieve a specific key.
*
* The keys returned are identical to the keys returned from PHP's
* stream_get_meta_data() function.
*
* @link http://php.net/manual/en/function.stream-get-meta-data.php
*
* @param string $key Specific metadata to retrieve.
*
* @return array|mixed|null Returns an associative array if no key is
* provided. Returns a specific key value if a key is provided and the
* value is found, or null if the key is not found.
*/
public function getMetadata($key = null)
{
$this->meta = stream_get_meta_data($this->stream);
if (is_null($key) === true) {
return $this->meta;
}
return isset($this->meta[$key]) ? $this->meta[$key] : null;
}
/**
* Is a resource attached to this stream?
*
* Note: This method is not part of the PSR-7 standard.
*
* @return bool
*/
protected function isAttached()
{
return is_resource($this->stream);
}
/**
* Attach new resource to this object.
*
* Note: This method is not part of the PSR-7 standard.
*
* @param resource $newStream A PHP resource handle.
*
* @throws InvalidArgumentException If argument is not a valid PHP resource.
*/
protected function attach($newStream)
{
if (is_resource($newStream) === false) {
throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource');
}
if ($this->isAttached() === true) {
$this->detach();
}
$this->stream = $newStream;
}
/**
* Separates any underlying resources from the stream.
*
* After the stream has been detached, the stream is in an unusable state.
*
* @return resource|null Underlying PHP stream, if any
*/
public function detach()
{
$oldResource = $this->stream;
$this->stream = null;
$this->meta = null;
$this->readable = null;
$this->writable = null;
$this->seekable = null;
$this->size = null;
return $oldResource;
}
/**
* Reads all data from the stream into a string, from the beginning to end.
*
* This method MUST attempt to seek to the beginning of the stream before
* reading data and read the stream until the end is reached.
*
* Warning: This could attempt to load a large amount of data into memory.
*
* This method MUST NOT raise an exception in order to conform with PHP's
* string casting operations.
*
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
* @return string
*/
public function __toString()
{
if (!$this->isAttached()) {
return '';
}
try {
$this->rewind();
return $this->getContents();
} catch (RuntimeException $e) {
return '';
}
}
/**
* Closes the stream and any underlying resources.
*/
public function close()
{
if ($this->isAttached() === true) {
fclose($this->stream);
}
$this->detach();
}
/**
* Get the size of the stream if known.
*
* @return int|null Returns the size in bytes if known, or null if unknown.
*/
public function getSize()
{
if (!$this->size && $this->isAttached() === true) {
$stats = fstat($this->stream);
$this->size = isset($stats['size']) ? $stats['size'] : null;
}
return $this->size;
}
/**
* Returns the current position of the file read/write pointer
*
* @return int Position of the file pointer
*
* @throws RuntimeException on error.
*/
public function tell()
{
if (!$this->isAttached() || ($position = ftell($this->stream)) === false) {
throw new RuntimeException('Could not get the position of the pointer in stream');
}
return $position;
}
/**
* Returns true if the stream is at the end of the stream.
*
* @return bool
*/
public function eof()
{
return $this->isAttached() ? feof($this->stream) : true;
}
/**
* Returns whether or not the stream is readable.
*
* @return bool
*/
public function isReadable()
{
if ($this->readable === null) {
$this->readable = false;
if ($this->isAttached()) {
$meta = $this->getMetadata();
foreach (self::$modes['readable'] as $mode) {
if (strpos($meta['mode'], $mode) === 0) {
$this->readable = true;
break;
}
}
}
}
return $this->readable;
}
/**
* Returns whether or not the stream is writable.
*
* @return bool
*/
public function isWritable()
{
if ($this->writable === null) {
$this->writable = false;
if ($this->isAttached()) {
$meta = $this->getMetadata();
foreach (self::$modes['writable'] as $mode) {
if (strpos($meta['mode'], $mode) === 0) {
$this->writable = true;
break;
}
}
}
}
return $this->writable;
}
/**
* Returns whether or not the stream is seekable.
*
* @return bool
*/
public function isSeekable()
{
if ($this->seekable === null) {
$this->seekable = false;
if ($this->isAttached()) {
$meta = $this->getMetadata();
$this->seekable = $meta['seekable'];
}
}
return $this->seekable;
}
/**
* Seek to a position in the stream.
*
* @link http://www.php.net/manual/en/function.fseek.php
*
* @param int $offset Stream offset
* @param int $whence Specifies how the cursor position will be calculated
* based on the seek offset. Valid values are identical to the built-in
* PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
* offset bytes SEEK_CUR: Set position to current location plus offset
* SEEK_END: Set position to end-of-stream plus offset.
*
* @throws RuntimeException on failure.
*/
public function seek($offset, $whence = SEEK_SET)
{
// Note that fseek returns 0 on success!
if (!$this->isSeekable() || fseek($this->stream, $offset, $whence) === -1) {
throw new RuntimeException('Could not seek in stream');
}
}
/**
* Seek to the beginning of the stream.
*
* If the stream is not seekable, this method will raise an exception;
* otherwise, it will perform a seek(0).
*
* @see seek()
*
* @link http://www.php.net/manual/en/function.fseek.php
*
* @throws RuntimeException on failure.
*/
public function rewind()
{
if (!$this->isSeekable() || rewind($this->stream) === false) {
throw new RuntimeException('Could not rewind stream');
}
}
/**
* Read data from the stream.
*
* @param int $length Read up to $length bytes from the object and return
* them. Fewer than $length bytes may be returned if underlying stream
* call returns fewer bytes.
*
* @return string Returns the data read from the stream, or an empty string
* if no bytes are available.
*
* @throws RuntimeException if an error occurs.
*/
public function read($length)
{
if (!$this->isReadable() || ($data = fread($this->stream, $length)) === false) {
throw new RuntimeException('Could not read from stream');
}
return $data;
}
/**
* Write data to the stream.
*
* @param string $string The string that is to be written.
*
* @return int Returns the number of bytes written to the stream.
*
* @throws RuntimeException on failure.
*/
public function write($string)
{
if (!$this->isWritable() || ($written = fwrite($this->stream, $string)) === false) {
throw new RuntimeException('Could not write to stream');
}
// reset size so that it will be recalculated on next call to getSize()
$this->size = null;
return $written;
}
/**
* Returns the remaining contents in a string
*
* @return string
*
* @throws RuntimeException if unable to read or an error occurs while
* reading.
*/
public function getContents()
{
if (!$this->isReadable() || ($contents = stream_get_contents($this->stream)) === false) {
throw new RuntimeException('Could not get contents of stream');
}
return $contents;
}
}
+317
View File
@@ -0,0 +1,317 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
use RuntimeException;
use InvalidArgumentException;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
/**
* Represents Uploaded Files.
*
* It manages and normalizes uploaded files according to the PSR-7 standard.
*
* @link https://github.com/php-fig/http-message/blob/master/src/UploadedFileInterface.php
* @link https://github.com/php-fig/http-message/blob/master/src/StreamInterface.php
*/
class UploadedFile implements UploadedFileInterface
{
/**
* The client-provided file name.
*
* @var string
*/
protected $name;
/**
* The client-provided media type of the file.
*
* @var string
*/
protected $type;
/**
* The size of the file in bytes.
*
* @var int
*/
protected $size;
/**
* A valid PHP UPLOAD_ERR_xxx code for the file upload.
*
* @var int
*/
protected $error = UPLOAD_ERR_OK;
/**
* Indicates if the upload is from a SAPI environment.
*
* @var bool
*/
protected $sapi = false;
/**
* An optional StreamInterface wrapping the file resource.
*
* @var StreamInterface
*/
protected $stream;
/**
* Indicates if the uploaded file has already been moved.
*
* @var bool
*/
protected $moved = false;
/**
* Create a normalized tree of UploadedFile instances from the Environment.
*
* @param Environment $env The environment
*
* @return array|null A normalized tree of UploadedFile instances or null if none are provided.
*/
public static function createFromEnvironment(Environment $env)
{
if (is_array($env['slim.files']) && $env->has('slim.files')) {
return $env['slim.files'];
} elseif (isset($_FILES)) {
return static::parseUploadedFiles($_FILES);
}
return [];
}
/**
* Parse a non-normalized, i.e. $_FILES superglobal, tree of uploaded file data.
*
* @param array $uploadedFiles The non-normalized tree of uploaded file data.
*
* @return array A normalized tree of UploadedFile instances.
*/
private static function parseUploadedFiles(array $uploadedFiles)
{
$parsed = [];
foreach ($uploadedFiles as $field => $uploadedFile) {
if (!isset($uploadedFile['error'])) {
if (is_array($uploadedFile)) {
$parsed[$field] = static::parseUploadedFiles($uploadedFile);
}
continue;
}
$parsed[$field] = [];
if (!is_array($uploadedFile['error'])) {
$parsed[$field] = new static(
$uploadedFile['tmp_name'],
isset($uploadedFile['tmp_name']) ? $uploadedFile['name'] : null,
isset($uploadedFile['type']) ? $uploadedFile['type'] : null,
isset($uploadedFile['size']) ? $uploadedFile['size'] : null,
$uploadedFile['error'],
true
);
} else {
foreach ($uploadedFile['error'] as $fileIdx => $error) {
$parsed[$field][] = new static(
$uploadedFile['tmp_name'][$fileIdx],
isset($uploadedFile['tmp_name']) ? $uploadedFile['name'][$fileIdx] : null,
isset($uploadedFile['type']) ? $uploadedFile['type'][$fileIdx] : null,
isset($uploadedFile['size']) ? $uploadedFile['size'][$fileIdx] : null,
$uploadedFile['error'][$fileIdx],
true
);
}
}
}
return $parsed;
}
/**
* Construct a new UploadedFile instance.
*
* @param string $file The full path to the uploaded file provided by the client.
* @param string|null $name The file name.
* @param string|null $type The file media type.
* @param int|null $size The file size in bytes.
* @param int $error The UPLOAD_ERR_XXX code representing the status of the upload.
* @param bool $sapi Indicates if the upload is in a SAPI environment.
*/
public function __construct($file, $name = null, $type = null, $size = null, $error = UPLOAD_ERR_OK, $sapi = false)
{
$this->file = $file;
$this->name = $name;
$this->type = $type;
$this->size = $size;
$this->error = $error;
$this->sapi = $sapi;
}
/**
* Retrieve a stream representing the uploaded file.
*
* This method MUST return a StreamInterface instance, representing the
* uploaded file. The purpose of this method is to allow utilizing native PHP
* stream functionality to manipulate the file upload, such as
* stream_copy_to_stream() (though the result will need to be decorated in a
* native PHP stream wrapper to work with such functions).
*
* If the moveTo() method has been called previously, this method MUST raise
* an exception.
*
* @return StreamInterface Stream representation of the uploaded file.
* @throws \RuntimeException in cases when no stream is available or can be
* created.
*/
public function getStream()
{
if ($this->moved) {
throw new \RuntimeException(sprintf('Uploaded file %1s has already been moved', $this->name));
}
if ($this->stream === null) {
$this->stream = new Stream(fopen($this->file, 'r'));
}
return $this->stream;
}
/**
* Move the uploaded file to a new location.
*
* Use this method as an alternative to move_uploaded_file(). This method is
* guaranteed to work in both SAPI and non-SAPI environments.
* Implementations must determine which environment they are in, and use the
* appropriate method (move_uploaded_file(), rename(), or a stream
* operation) to perform the operation.
*
* $targetPath may be an absolute path, or a relative path. If it is a
* relative path, resolution should be the same as used by PHP's rename()
* function.
*
* The original file or stream MUST be removed on completion.
*
* If this method is called more than once, any subsequent calls MUST raise
* an exception.
*
* When used in an SAPI environment where $_FILES is populated, when writing
* files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be
* used to ensure permissions and upload status are verified correctly.
*
* If you wish to move to a stream, use getStream(), as SAPI operations
* cannot guarantee writing to stream destinations.
*
* @see http://php.net/is_uploaded_file
* @see http://php.net/move_uploaded_file
*
* @param string $targetPath Path to which to move the uploaded file.
*
* @throws InvalidArgumentException if the $path specified is invalid.
* @throws RuntimeException on any error during the move operation, or on
* the second or subsequent call to the method.
*/
public function moveTo($targetPath)
{
if ($this->moved) {
throw new RuntimeException('Uploaded file already moved');
}
if (!is_writable(dirname($targetPath))) {
throw new InvalidArgumentException('Upload target path is not writable');
}
$targetIsStream = strpos($targetPath, '://') > 0;
if ($targetIsStream) {
if (!copy($this->file, $targetPath)) {
throw new RuntimeException(sprintf('Error moving uploaded file %1s to %2s', $this->name, $targetPath));
}
if (!unlink($this->file)) {
throw new RuntimeException(sprintf('Error removing uploaded file %1s', $this->name));
}
} elseif ($this->sapi) {
if (!is_uploaded_file($this->file)) {
throw new RuntimeException(sprintf('%1s is not a valid uploaded file', $this->file));
}
if (!move_uploaded_file($this->file, $targetPath)) {
throw new RuntimeException(sprintf('Error moving uploaded file %1s to %2s', $this->name, $targetPath));
}
} else {
if (!rename($this->file, $targetPath)) {
throw new RuntimeException(sprintf('Error moving uploaded file %1s to %2s', $this->name, $targetPath));
}
}
$this->moved = true;
}
/**
* Retrieve the error associated with the uploaded file.
*
* The return value MUST be one of PHP's UPLOAD_ERR_XXX constants.
*
* If the file was uploaded successfully, this method MUST return
* UPLOAD_ERR_OK.
*
* Implementations SHOULD return the value stored in the "error" key of
* the file in the $_FILES array.
*
* @see http://php.net/manual/en/features.file-upload.errors.php
*
* @return int One of PHP's UPLOAD_ERR_XXX constants.
*/
public function getError()
{
return $this->error;
}
/**
* Retrieve the filename sent by the client.
*
* Do not trust the value returned by this method. A client could send
* a malicious filename with the intention to corrupt or hack your
* application.
*
* Implementations SHOULD return the value stored in the "name" key of
* the file in the $_FILES array.
*
* @return string|null The filename sent by the client or null if none
* was provided.
*/
public function getClientFilename()
{
return $this->name;
}
/**
* Retrieve the media type sent by the client.
*
* Do not trust the value returned by this method. A client could send
* a malicious media type with the intention to corrupt or hack your
* application.
*
* Implementations SHOULD return the value stored in the "type" key of
* the file in the $_FILES array.
*
* @return string|null The media type sent by the client or null if none
* was provided.
*/
public function getClientMediaType()
{
return $this->type;
}
/**
* Retrieve the file size.
*
* Implementations SHOULD return the value stored in the "size" key of
* the file in the $_FILES array if available, as PHP calculates this based
* on the actual size transmitted.
*
* @return int|null The file size in bytes or null if unknown.
*/
public function getSize()
{
return $this->size;
}
}
+809
View File
@@ -0,0 +1,809 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Http;
use InvalidArgumentException;
use \Psr\Http\Message\UriInterface;
use Slim\Http\Environment;
/**
* Value object representing a URI.
*
* This interface is meant to represent URIs according to RFC 3986 and to
* provide methods for most common operations. Additional functionality for
* working with URIs can be provided on top of the interface or externally.
* Its primary use is for HTTP requests, but may also be used in other
* contexts.
*
* Instances of this interface are considered immutable; all methods that
* might change state MUST be implemented such that they retain the internal
* state of the current instance and return an instance that contains the
* changed state.
*
* Typically the Host header will be also be present in the request message.
* For server-side requests, the scheme will typically be discoverable in the
* server parameters.
*
* @link http://tools.ietf.org/html/rfc3986 (the URI specification)
*/
class Uri implements UriInterface
{
/**
* Uri scheme (without "://" suffix)
*
* @var string
*/
protected $scheme = '';
/**
* Uri user
*
* @var string
*/
protected $user = '';
/**
* Uri password
*
* @var string
*/
protected $password = '';
/**
* Uri host
*
* @var string
*/
protected $host = '';
/**
* Uri port number
*
* @var null|int
*/
protected $port;
/**
* Uri base path
*
* @var string
*/
protected $basePath = '';
/**
* Uri path
*
* @var string
*/
protected $path = '';
/**
* Uri query string (without "?" prefix)
*
* @var string
*/
protected $query = '';
/**
* Uri fragment string (without "#" prefix)
*
* @var string
*/
protected $fragment = '';
/**
* Create new Uri.
*
* @param string $scheme Uri scheme.
* @param string $host Uri host.
* @param int $port Uri port number.
* @param string $path Uri path.
* @param string $query Uri query string.
* @param string $fragment Uri fragment.
* @param string $user Uri user.
* @param string $password Uri password.
*/
public function __construct($scheme, $host, $port = null, $path = '/', $query = '', $fragment = '', $user = '', $password = '')
{
$this->scheme = $this->filterScheme($scheme);
$this->host = $host;
$this->port = $this->filterPort($port);
$this->path = empty($path) ? '/' : $this->filterPath($path);
$this->query = $this->filterQuery($query);
$this->fragment = $this->filterQuery($fragment);
$this->user = $user;
$this->password = $password;
}
/**
* Create new Uri from string.
*
* @param string $uri Complete Uri string
* (i.e., https://user:pass@host:443/path?query).
*
* @return self
*/
public static function createFromString($uri)
{
if (!is_string($uri) && !method_exists($uri, '__toString')) {
throw new InvalidArgumentException('Uri must be a string');
}
$parts = parse_url($uri);
$scheme = isset($parts['scheme']) ? $parts['scheme'] : '';
$user = isset($parts['user']) ? $parts['user'] : '';
$pass = isset($parts['pass']) ? $parts['pass'] : '';
$host = isset($parts['host']) ? $parts['host'] : '';
$port = isset($parts['port']) ? $parts['port'] : null;
$path = isset($parts['path']) ? $parts['path'] : '';
$query = isset($parts['query']) ? $parts['query'] : '';
$fragment = isset($parts['fragment']) ? $parts['fragment'] : '';
return new static($scheme, $host, $port, $path, $query, $fragment, $user, $pass);
}
/**
* Create new Uri from environment.
*
* @param Environment $env
*
* @return self
*/
public static function createFromEnvironment(Environment $env)
{
// Scheme
$isSecure = $env->get('HTTPS');
$scheme = (empty($isSecure) || $isSecure === 'off') ? 'http' : 'https';
// Authority: Username and password
$username = $env->get('PHP_AUTH_USER', '');
$password = $env->get('PHP_AUTH_PW', '');
// Authority: Host
if ($env->has('HTTP_HOST')) {
$host = $env->get('HTTP_HOST');
} else {
$host = $env->get('SERVER_NAME');
}
// Authority: Port
$port = (int)$env->get('SERVER_PORT', 80);
if (preg_match('/^(\[[a-fA-F0-9:.]+\])(:\d+)?\z/', $host, $matches)) {
$host = $matches[1];
if ($matches[2]) {
$port = (int) substr($matches[2], 1);
}
} else {
$pos = strpos($host, ':');
if ($pos !== false) {
$port = (int) substr($host, $pos + 1);
$host = strstr($host, ':', true);
}
}
// Path
$requestScriptName = parse_url($env->get('SCRIPT_NAME'), PHP_URL_PATH);
$requestScriptDir = dirname($requestScriptName);
$requestUri = parse_url($env->get('REQUEST_URI'), PHP_URL_PATH);
$basePath = '';
$virtualPath = $requestUri;
if (stripos($requestUri, $requestScriptName) === 0) {
$basePath = $requestScriptName;
} elseif ($requestScriptDir !== '/' && stripos($requestUri, $requestScriptDir) === 0) {
$basePath = $requestScriptDir;
}
if ($basePath) {
$virtualPath = ltrim(substr($requestUri, strlen($basePath)), '/');
}
// Query string
$queryString = $env->get('QUERY_STRING', '');
// Fragment
$fragment = '';
// Build Uri
$uri = new static($scheme, $host, $port, $virtualPath, $queryString, $fragment, $username, $password);
if ($basePath) {
$uri = $uri->withBasePath($basePath);
}
return $uri;
}
/********************************************************************************
* Scheme
*******************************************************************************/
/**
* Retrieve the scheme component of the URI.
*
* If no scheme is present, this method MUST return an empty string.
*
* The value returned MUST be normalized to lowercase, per RFC 3986
* Section 3.1.
*
* The trailing ":" character is not part of the scheme and MUST NOT be
* added.
*
* @see https://tools.ietf.org/html/rfc3986#section-3.1
* @return string The URI scheme.
*/
public function getScheme()
{
return $this->scheme;
}
/**
* Return an instance with the specified scheme.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified scheme.
*
* Implementations MUST support the schemes "http" and "https" case
* insensitively, and MAY accommodate other schemes if required.
*
* An empty scheme is equivalent to removing the scheme.
*
* @param string $scheme The scheme to use with the new instance.
* @return self A new instance with the specified scheme.
* @throws \InvalidArgumentException for invalid or unsupported schemes.
*/
public function withScheme($scheme)
{
$scheme = $this->filterScheme($scheme);
$clone = clone $this;
$clone->scheme = $scheme;
return $clone;
}
/**
* Filter Uri scheme.
*
* @param string $scheme Raw Uri scheme.
* @return string
*
* @throws InvalidArgumentException If the Uri scheme is not a string.
* @throws InvalidArgumentException If Uri scheme is not "", "https", or "http".
*/
protected function filterScheme($scheme)
{
static $valid = [
'' => true,
'https' => true,
'http' => true,
];
if (!is_string($scheme) && !method_exists($scheme, '__toString')) {
throw new InvalidArgumentException('Uri scheme must be a string');
}
$scheme = str_replace('://', '', strtolower((string)$scheme));
if (!isset($valid[$scheme])) {
throw new InvalidArgumentException('Uri scheme must be one of: "", "https", "http"');
}
return $scheme;
}
/********************************************************************************
* Authority
*******************************************************************************/
/**
* Retrieve the authority component of the URI.
*
* If no authority information is present, this method MUST return an empty
* string.
*
* The authority syntax of the URI is:
*
* <pre>
* [user-info@]host[:port]
* </pre>
*
* If the port component is not set or is the standard port for the current
* scheme, it SHOULD NOT be included.
*
* @see https://tools.ietf.org/html/rfc3986#section-3.2
* @return string The URI authority, in "[user-info@]host[:port]" format.
*/
public function getAuthority()
{
$userInfo = $this->getUserInfo();
$host = $this->getHost();
$port = $this->getPort();
return ($userInfo ? $userInfo . '@' : '') . $host . ($port !== null ? ':' . $port : '');
}
/**
* Retrieve the user information component of the URI.
*
* If no user information is present, this method MUST return an empty
* string.
*
* If a user is present in the URI, this will return that value;
* additionally, if the password is also present, it will be appended to the
* user value, with a colon (":") separating the values.
*
* The trailing "@" character is not part of the user information and MUST
* NOT be added.
*
* @return string The URI user information, in "username[:password]" format.
*/
public function getUserInfo()
{
return $this->user . ($this->password ? ':' . $this->password : '');
}
/**
* Return an instance with the specified user information.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified user information.
*
* Password is optional, but the user information MUST include the
* user; an empty string for the user is equivalent to removing user
* information.
*
* @param string $user The user name to use for authority.
* @param null|string $password The password associated with $user.
* @return self A new instance with the specified user information.
*/
public function withUserInfo($user, $password = null)
{
$clone = clone $this;
$clone->user = $user;
$clone->password = $password ? $password : '';
return $clone;
}
/**
* Retrieve the host component of the URI.
*
* If no host is present, this method MUST return an empty string.
*
* The value returned MUST be normalized to lowercase, per RFC 3986
* Section 3.2.2.
*
* @see http://tools.ietf.org/html/rfc3986#section-3.2.2
* @return string The URI host.
*/
public function getHost()
{
return $this->host;
}
/**
* Return an instance with the specified host.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified host.
*
* An empty host value is equivalent to removing the host.
*
* @param string $host The hostname to use with the new instance.
* @return self A new instance with the specified host.
* @throws \InvalidArgumentException for invalid hostnames.
*/
public function withHost($host)
{
$clone = clone $this;
$clone->host = $host;
return $clone;
}
/**
* Retrieve the port component of the URI.
*
* If a port is present, and it is non-standard for the current scheme,
* this method MUST return it as an integer. If the port is the standard port
* used with the current scheme, this method SHOULD return null.
*
* If no port is present, and no scheme is present, this method MUST return
* a null value.
*
* If no port is present, but a scheme is present, this method MAY return
* the standard port for that scheme, but SHOULD return null.
*
* @return null|int The URI port.
*/
public function getPort()
{
return $this->port && !$this->hasStandardPort() ? $this->port : null;
}
/**
* Return an instance with the specified port.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified port.
*
* Implementations MUST raise an exception for ports outside the
* established TCP and UDP port ranges.
*
* A null value provided for the port is equivalent to removing the port
* information.
*
* @param null|int $port The port to use with the new instance; a null value
* removes the port information.
* @return self A new instance with the specified port.
* @throws \InvalidArgumentException for invalid ports.
*/
public function withPort($port)
{
$port = $this->filterPort($port);
$clone = clone $this;
$clone->port = $port;
return $clone;
}
/**
* Does this Uri use a standard port?
*
* @return bool
*/
protected function hasStandardPort()
{
return ($this->scheme === 'http' && $this->port === 80) || ($this->scheme === 'https' && $this->port === 443);
}
/**
* Filter Uri port.
*
* @param null|int $port The Uri port number.
* @return null|int
*
* @throws InvalidArgumentException If the port is invalid.
*/
protected function filterPort($port)
{
if (is_null($port) || (is_integer($port) && ($port >= 1 && $port <= 65535))) {
return $port;
}
throw new InvalidArgumentException('Uri port must be null or an integer between 1 and 65535 (inclusive)');
}
/********************************************************************************
* Path
*******************************************************************************/
/**
* Retrieve the path component of the URI.
*
* The path can either be empty or absolute (starting with a slash) or
* rootless (not starting with a slash). Implementations MUST support all
* three syntaxes.
*
* Normally, the empty path "" and absolute path "/" are considered equal as
* defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
* do this normalization because in contexts with a trimmed base path, e.g.
* the front controller, this difference becomes significant. It's the task
* of the user to handle both "" and "/".
*
* The value returned MUST be percent-encoded, but MUST NOT double-encode
* any characters. To determine what characters to encode, please refer to
* RFC 3986, Sections 2 and 3.3.
*
* As an example, if the value should include a slash ("/") not intended as
* delimiter between path segments, that value MUST be passed in encoded
* form (e.g., "%2F") to the instance.
*
* @see https://tools.ietf.org/html/rfc3986#section-2
* @see https://tools.ietf.org/html/rfc3986#section-3.3
* @return string The URI path.
*/
public function getPath()
{
return $this->path;
}
/**
* Return an instance with the specified path.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified path.
*
* The path can either be empty or absolute (starting with a slash) or
* rootless (not starting with a slash). Implementations MUST support all
* three syntaxes.
*
* If the path is intended to be domain-relative rather than path relative then
* it must begin with a slash ("/"). Paths not starting with a slash ("/")
* are assumed to be relative to some base path known to the application or
* consumer.
*
* Users can provide both encoded and decoded path characters.
* Implementations ensure the correct encoding as outlined in getPath().
*
* @param string $path The path to use with the new instance.
* @return self A new instance with the specified path.
* @throws \InvalidArgumentException for invalid paths.
*/
public function withPath($path)
{
if (!is_string($path)) {
throw new InvalidArgumentException('Uri path must be a string');
}
$clone = clone $this;
$clone->path = $this->filterPath($path);
// if the path is absolute, then clear basePath
if (substr($path, 0, 1) == '/') {
$clone->basePath = '';
}
return $clone;
}
/**
* Retrieve the base path segment of the URI.
*
* Note: This method is not part of the PSR-7 standard.
*
* This method MUST return a string; if no path is present it MUST return
* an empty string.
*
* @return string The base path segment of the URI.
*/
public function getBasePath()
{
return $this->basePath;
}
/**
* Set base path.
*
* Note: This method is not part of the PSR-7 standard.
*
* @param string $basePath
* @return self
*/
public function withBasePath($basePath)
{
if (!is_string($basePath)) {
throw new InvalidArgumentException('Uri path must be a string');
}
if (!empty($basePath)) {
$basePath = '/' . trim($basePath, '/'); // <-- Trim on both sides
}
$clone = clone $this;
if ($basePath !== '/') {
$clone->basePath = $this->filterPath($basePath);
}
return $clone;
}
/**
* Filter Uri path.
*
* This method percent-encodes all reserved
* characters in the provided path string. This method
* will NOT double-encode characters that are already
* percent-encoded.
*
* @param string $path The raw uri path.
* @return string The RFC 3986 percent-encoded uri path.
* @link http://www.faqs.org/rfcs/rfc3986.html
*/
protected function filterPath($path)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
function ($match) {
return rawurlencode($match[0]);
},
$path
);
}
/********************************************************************************
* Query
*******************************************************************************/
/**
* Retrieve the query string of the URI.
*
* If no query string is present, this method MUST return an empty string.
*
* The leading "?" character is not part of the query and MUST NOT be
* added.
*
* The value returned MUST be percent-encoded, but MUST NOT double-encode
* any characters. To determine what characters to encode, please refer to
* RFC 3986, Sections 2 and 3.4.
*
* As an example, if a value in a key/value pair of the query string should
* include an ampersand ("&") not intended as a delimiter between values,
* that value MUST be passed in encoded form (e.g., "%26") to the instance.
*
* @see https://tools.ietf.org/html/rfc3986#section-2
* @see https://tools.ietf.org/html/rfc3986#section-3.4
* @return string The URI query string.
*/
public function getQuery()
{
return $this->query;
}
/**
* Return an instance with the specified query string.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified query string.
*
* Users can provide both encoded and decoded query characters.
* Implementations ensure the correct encoding as outlined in getQuery().
*
* An empty query string value is equivalent to removing the query string.
*
* @param string $query The query string to use with the new instance.
* @return self A new instance with the specified query string.
* @throws \InvalidArgumentException for invalid query strings.
*/
public function withQuery($query)
{
if (!is_string($query) && !method_exists($query, '__toString')) {
throw new InvalidArgumentException('Uri query must be a string');
}
$query = ltrim((string)$query, '?');
$clone = clone $this;
$clone->query = $this->filterQuery($query);
return $clone;
}
/**
* Filters the query string or fragment of a URI.
*
* @param string $query The raw uri query string.
* @return string The percent-encoded query string.
*/
protected function filterQuery($query)
{
return preg_replace_callback(
'/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
function ($match) {
return rawurlencode($match[0]);
},
$query
);
}
/********************************************************************************
* Fragment
*******************************************************************************/
/**
* Retrieve the fragment component of the URI.
*
* If no fragment is present, this method MUST return an empty string.
*
* The leading "#" character is not part of the fragment and MUST NOT be
* added.
*
* The value returned MUST be percent-encoded, but MUST NOT double-encode
* any characters. To determine what characters to encode, please refer to
* RFC 3986, Sections 2 and 3.5.
*
* @see https://tools.ietf.org/html/rfc3986#section-2
* @see https://tools.ietf.org/html/rfc3986#section-3.5
* @return string The URI fragment.
*/
public function getFragment()
{
return $this->fragment;
}
/**
* Return an instance with the specified URI fragment.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified URI fragment.
*
* Users can provide both encoded and decoded fragment characters.
* Implementations ensure the correct encoding as outlined in getFragment().
*
* An empty fragment value is equivalent to removing the fragment.
*
* @param string $fragment The fragment to use with the new instance.
* @return self A new instance with the specified fragment.
*/
public function withFragment($fragment)
{
if (!is_string($fragment) && !method_exists($fragment, '__toString')) {
throw new InvalidArgumentException('Uri fragment must be a string');
}
$fragment = ltrim((string)$fragment, '#');
$clone = clone $this;
$clone->fragment = $this->filterQuery($fragment);
return $clone;
}
/********************************************************************************
* Helpers
*******************************************************************************/
/**
* Return the string representation as a URI reference.
*
* Depending on which components of the URI are present, the resulting
* string is either a full URI or relative reference according to RFC 3986,
* Section 4.1. The method concatenates the various components of the URI,
* using the appropriate delimiters:
*
* - If a scheme is present, it MUST be suffixed by ":".
* - If an authority is present, it MUST be prefixed by "//".
* - The path can be concatenated without delimiters. But there are two
* cases where the path has to be adjusted to make the URI reference
* valid as PHP does not allow to throw an exception in __toString():
* - If the path is rootless and an authority is present, the path MUST
* be prefixed by "/".
* - If the path is starting with more than one "/" and no authority is
* present, the starting slashes MUST be reduced to one.
* - If a query is present, it MUST be prefixed by "?".
* - If a fragment is present, it MUST be prefixed by "#".
*
* @see http://tools.ietf.org/html/rfc3986#section-4.1
* @return string
*/
public function __toString()
{
$scheme = $this->getScheme();
$authority = $this->getAuthority();
$basePath = $this->getBasePath();
$path = $this->getPath();
$query = $this->getQuery();
$fragment = $this->getFragment();
$path = $basePath . '/' . ltrim($path, '/');
return ($scheme ? $scheme . ':' : '')
. ($authority ? '//' . $authority : '')
. $path
. ($query ? '?' . $query : '')
. ($fragment ? '#' . $fragment : '');
}
/**
* Return the fully qualified base URL.
*
* Note that this method never includes a trailing /
*
* This method is not part of PSR-7.
*
* @return string
*/
public function getBaseUrl()
{
$scheme = $this->getScheme();
$authority = $this->getAuthority();
$basePath = $this->getBasePath();
if ($authority && substr($basePath, 0, 1) !== '/') {
$basePath = $basePath . '/' . $basePath;
}
return ($scheme ? $scheme . ':' : '')
. ($authority ? '//' . $authority : '')
. rtrim($basePath, '/');
}
}
@@ -0,0 +1,27 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces;
/**
* Resolves a callable.
*
* @package Slim
* @since 3.0.0
*/
interface CallableResolverInterface
{
/**
* Invoke the resolved callable.
*
* @param mixed $toResolve
*
* @return callable
*/
public function resolve($toResolve);
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces;
/**
* Collection Interface
*
* @package Slim
* @since 3.0.0
*/
interface CollectionInterface extends \ArrayAccess, \Countable, \IteratorAggregate
{
public function set($key, $value);
public function get($key, $default = null);
public function replace(array $items);
public function all();
public function has($key);
public function remove($key);
public function clear();
}
+23
View File
@@ -0,0 +1,23 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces\Http;
/**
* Cookies Interface
*
* @package Slim
* @since 3.0.0
*/
interface CookiesInterface
{
public function get($name, $default = null);
public function set($name, $value);
public function toHeaders();
public static function parseHeader($header);
}
@@ -0,0 +1,20 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces\Http;
/**
* Environment Interface
*
* @package Slim
* @since 3.0.0
*/
interface EnvironmentInterface
{
public static function mock(array $settings = []);
}
+24
View File
@@ -0,0 +1,24 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces\Http;
use Slim\Interfaces\CollectionInterface;
/**
* Headers Interface
*
* @package Slim
* @since 3.0.0
*/
interface HeadersInterface extends CollectionInterface
{
public function add($key, $value);
public function normalizeKey($key);
}
@@ -0,0 +1,30 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Defines a contract for invoking a route callable.
*/
interface InvocationStrategyInterface
{
/**
* Invoke a route callable.
*
* @param callable $callable The callable to invoke using the strategy.
* @param ServerRequestInterface $request The request object.
* @param ResponseInterface $response The response object.
* @param array $routeArguments The route's placholder arguments
*
* @return ResponseInterface|string The response from the callable.
*/
public function __invoke(callable $callable, ServerRequestInterface $request, ResponseInterface $response, array $routeArguments);
}
+46
View File
@@ -0,0 +1,46 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces;
use Slim\App;
/**
* RouteGroup Interface
*
* @package Slim
* @since 3.0.0
*/
interface RouteGroupInterface
{
/**
* Get route pattern
*
* @return string
*/
public function getPattern();
/**
* Prepend middleware to the group middleware collection
*
* @param mixed $callable The callback routine
*
* @return RouteGroupInterface
*/
public function add($callable);
/**
* Execute route group callable in the context of the Slim App
*
* This method invokes the route group object's callable, collecting
* nested route objects
*
* @param App $app
*/
public function __invoke(App $app);
}
+129
View File
@@ -0,0 +1,129 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Route Interface
*
* @package Slim
* @since 3.0.0
*/
interface RouteInterface
{
/**
* Retrieve a specific route argument
*
* @param string $name
* @param mixed $default
*
* @return mixed
*/
public function getArgument($name, $default = null);
/**
* Get route arguments
*
* @return array
*/
public function getArguments();
/**
* Get route name
*
* @return null|string
*/
public function getName();
/**
* Get route pattern
*
* @return string
*/
public function getPattern();
/**
* Set a route argument
*
* @param string $name
* @param string $value
*
* @return static
*/
public function setArgument($name, $value);
/**
* Replace route arguments
*
* @param array $arguments
*
* @return static
*/
public function setArguments(array $arguments);
/**
* Set route name
*
* @param string $name
*
* @return static
* @throws InvalidArgumentException if the route name is not a string
*/
public function setName($name);
/**
* Add middleware
*
* This method prepends new middleware to the route's middleware stack.
*
* @param mixed $callable The callback routine
*
* @return RouteInterface
*/
public function add($callable);
/**
* Prepare the route for use
*
* @param ServerRequestInterface $request
* @param array $arguments
*/
public function prepare(ServerRequestInterface $request, array $arguments);
/**
* Run route
*
* This method traverses the middleware stack, including the route's callable
* and captures the resultant HTTP response object. It then sends the response
* back to the Application.
*
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @return ResponseInterface
*/
public function run(ServerRequestInterface $request, ResponseInterface $response);
/**
* Dispatch route callable against current Request and Response objects
*
* This method invokes the route object's callable. If middleware is
* registered for the route, each callable middleware is invoked in
* the order specified.
*
* @param ServerRequestInterface $request The current Request object
* @param ResponseInterface $response The current Response object
*
* @return ResponseInterface
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response);
}
+107
View File
@@ -0,0 +1,107 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim\Interfaces;
use RuntimeException;
use InvalidArgumentException;
use Psr\Http\Message\ServerRequestInterface;
/**
* Router Interface
*
* @package Slim
* @since 3.0.0
*/
interface RouterInterface
{
/**
* Add route
*
* @param string[] $methods Array of HTTP methods
* @param string $pattern The route pattern
* @param callable $handler The route callable
*
* @return RouteInterface
*/
public function map($methods, $pattern, $handler);
/**
* Dispatch router for HTTP request
*
* @param ServerRequestInterface $request The current HTTP request object
*
* @return array
*
* @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
*/
public function dispatch(ServerRequestInterface $request);
/**
* Add a route group to the array
*
* @param string $pattern The group pattern
* @param callable $callable A group callable
*
* @return RouteGroupInterface
*/
public function pushGroup($pattern, $callable);
/**
* Removes the last route group from the array
*
* @return bool True if successful, else False
*/
public function popGroup();
/**
* Get named route object
*
* @param string $name Route name
*
* @return \Slim\Interfaces\RouteInterface
*
* @throws RuntimeException If named route does not exist
*/
public function getNamedRoute($name);
/**
* @param $identifier
*
* @return \Slim\Interfaces\RouteInterface
*/
public function lookupRoute($identifier);
/**
* Build the path for a named route excluding the base path
*
* @param string $name Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @return string
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function relativePathFor($name, array $data = [], array $queryParams = []);
/**
* Build the path for a named route including the base path
*
* @param string $name Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @return string
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function pathFor($name, array $data = [], array $queryParams = []);
}
+118
View File
@@ -0,0 +1,118 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use RuntimeException;
use SplStack;
use SplDoublyLinkedList;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use UnexpectedValueException;
/**
* Middleware
*
* This is an internal class that enables concentric middleware layers. This
* class is an implementation detail and is used only inside of the Slim
* application; it is not visible to—and should not be used by—end users.
*/
trait MiddlewareAwareTrait
{
/**
* Middleware call stack
*
* @var \SplStack
* @link http://php.net/manual/class.splstack.php
*/
protected $stack;
/**
* Middleware stack lock
*
* @var bool
*/
protected $middlewareLock = false;
/**
* Add middleware
*
* This method prepends new middleware to the application middleware stack.
*
* @param callable $callable Any callable that accepts three arguments:
* 1. A Request object
* 2. A Response object
* 3. A "next" middleware callable
* @return static
*
* @throws RuntimeException If middleware is added while the stack is dequeuing
* @throws UnexpectedValueException If the middleware doesn't return an instance of \Psr\Http\Message\ResponseInterface
*/
protected function addMiddleware(callable $callable)
{
if ($this->middlewareLock) {
throw new RuntimeException('Middleware cant be added once the stack is dequeuing');
}
if (is_null($this->stack)) {
$this->seedMiddlewareStack();
}
$next = $this->stack->top();
$this->stack[] = function (ServerRequestInterface $req, ResponseInterface $res) use ($callable, $next) {
$result = call_user_func($callable, $req, $res, $next);
if ($result instanceof ResponseInterface === false) {
throw new UnexpectedValueException('Middleware must return instance of \Psr\Http\Message\ResponseInterface');
}
return $result;
};
return $this;
}
/**
* Seed middleware stack with first callable
*
* @param callable $kernel The last item to run as middleware
*
* @throws RuntimeException if the stack is seeded more than once
*/
protected function seedMiddlewareStack(callable $kernel = null)
{
if (!is_null($this->stack)) {
throw new RuntimeException('MiddlewareStack can only be seeded once.');
}
if ($kernel === null) {
$kernel = $this;
}
$this->stack = new SplStack;
$this->stack->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO | SplDoublyLinkedList::IT_MODE_KEEP);
$this->stack[] = $kernel;
}
/**
* Call middleware stack
*
* @param ServerRequestInterface $req A request object
* @param ResponseInterface $res A response object
*
* @return ResponseInterface
*/
public function callMiddlewareStack(ServerRequestInterface $req, ResponseInterface $res)
{
if (is_null($this->stack)) {
$this->seedMiddlewareStack();
}
/** @var callable $start */
$start = $this->stack->top();
$this->middlewareLock = true;
$resp = $start($req, $res);
$this->middlewareLock = false;
return $resp;
}
}
+102
View File
@@ -0,0 +1,102 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use Closure;
use Interop\Container\ContainerInterface;
/**
* A routable, middleware-aware object
*
* @package Slim
* @since 3.0.0
*/
abstract class Routable
{
use CallableResolverAwareTrait;
/**
* Route callable
*
* @var callable
*/
protected $callable;
/**
* Container
*
* @var ContainerInterface
*/
protected $container;
/**
* Route middleware
*
* @var callable[]
*/
protected $middleware = [];
/**
* Route pattern
*
* @var string
*/
protected $pattern;
/**
* Get the middleware registered for the group
*
* @return callable[]
*/
public function getMiddleware()
{
return $this->middleware;
}
/**
* Get the route pattern
*
* @return string
*/
public function getPattern()
{
return $this->pattern;
}
/**
* Set container for use with resolveCallable
*
* @param ContainerInterface $container
*
* @return self
*/
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
return $this;
}
/**
* Prepend middleware to the middleware collection
*
* @param mixed $callable The callback routine
*
* @return static
*/
public function add($callable)
{
$callable = $this->resolveCallable($callable);
if ($callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
$this->middleware[] = $callable;
return $this;
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
/**
* Slim Framework (http://slimframework.com)
*
* @link https://github.com/slimphp/Slim
* @copyright Copyright (c) 2011-2015 Josh Lockhart
* @license https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
*/
namespace Slim;
use Closure;
use Slim\Interfaces\RouteGroupInterface;
/**
* A collector for Routable objects with a common middleware stack
*
* @package Slim
*/
class RouteGroup extends Routable implements RouteGroupInterface
{
/**
* Create a new RouteGroup
*
* @param string $pattern The pattern prefix for the group
* @param callable $callable The group callable
*/
public function __construct($pattern, $callable)
{
$this->pattern = $pattern;
$this->callable = $callable;
}
/**
* Invoke the group to register any Routable objects within it.
*
* @param App $app The App to bind the callable to.
*/
public function __invoke(App $app = null)
{
$callable = $this->resolveCallable($this->callable);
if ($callable instanceof Closure && $app !== null) {
$callable = $callable->bindTo($app);
}
$callable();
}
}
+12
View File
@@ -0,0 +1,12 @@
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ serviceapp.php [QSA,L]
</ifModule>
<Limit GET POST PUT DELETE>
# Allow from app.gruppolapastamadre.it
</Limit>
#Header set Access-Control-Allow-Origin "app.gruppolapastamadre.it"
#Header set Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
+82
View File
@@ -0,0 +1,82 @@
<?php
// inclusione del file contenente la classe
require_once "./include.php";
require_once "./myDropBoxObj.php";
use PHPImageWorkshop\ImageWorkshop;
require_once 'PHPImageWorkshop/ImageWorkshop.php'; // Be sure of the path to the class
//include "./SimpleImage.php";
$app->put('/photos/publish/:imageID', function ($imageID) use ($app) {
$mysqlconnetion = new MysqlClass;
$query = "update immagini set published = 1, published_date = NOW() where id = " . $imageID;
$mysqlconnetion->insertRecord($query);
$mysqlconnetion->disconnetti();
});
$app->post('/photos', function () use ($app) {
$idRicette = $app->request()->post('ricetta_id');
$profileID = $app->request()->post('keyStore');
$tmpFileName = $_FILES['image']["tmp_name"];
$layer = ImageWorkshop::initFromPath($tmpFileName);
// istanza della classe
$mysqlconnetion = new MysqlClass;
//$mysqlconneti on->connetti();
$query = "insert into immagini(id_ricette, type_format, from_profile_id, uploaded_date) " .
"values(" . $idRicette . ", '" . image_type_to_mime_type(exif_imagetype($tmpFileName)) .
"', '" . $profileID . "', NOW())";
$newID = $mysqlconnetion->insertRecord($query);
$ext = image_type_to_extension(exif_imagetype($tmpFileName), FALSE);
$folder = $dirRicetteDropBox . "/" . $idRicette;
$imageFileName = $newID . "_full_ricetta." . $ext;
$dropBoxObj = new myDropBox();
resizeImage($dropBoxObj, $layer, 640, dirname($tmpFileName), $imageFileName, $folder);
$imageMediumFileName = $newID . "_medium_ricetta." . $ext;
resizeImage($dropBoxObj, $layer, 320, dirname($tmpFileName), $imageMediumFileName, $folder);
$thumbFileName = $newID . "_thumb_ricetta." . $ext;
resizeImage($dropBoxObj, $layer, 80, dirname($tmpFileName), $thumbFileName, $folder);
$mysqlconnetion->disconnetti();
echo $newID;
});
$app->put('/photos/:imageID', function ($imageID) use ($app) {
$tmpFileName = $_FILES['image']["tmp_name"];
$layer = ImageWorkshop::initFromPath($tmpFileName);
// istanza della classe
$mysqlconnetion = new MysqlClass;
//$mysqlconneti on->connetti();
$query = "update immagini set (type_format = '" . image_type_to_mime_type(exif_imagetype($tmpFileName)) . "', " .
" where id=" . $imageID;
$newID = $mysqlconnetion->insertRecord($query);
$folder = $dirRicetteDropBox . "/" . $newID;
$imageFileName = $newID . "_full_ricetta." . $ext;
resizeImage($dropBoxObj, $layer, 640, dirname($tmpFileName), $imageFileName, $folder);
$imageMediumFileName = $newID . "_medium_ricetta." . $ext;
resizeImage($dropBoxObj, $layer, 320, dirname($tmpFileName), $imageMediumFileName, $folder);
$thumbFileName = $newID . "_thumb_ricetta." . $ext;
resizeImage($dropBoxObj, $layer, 80, dirname($tmpFileName), $thumbFileName, $folder);
$mysqlconnetion->disconnetti();
return $newID;
});
View File
-9
View File
@@ -1,9 +0,0 @@
browser.id=Chrome.INTEGRATED
copy.src.files=false
copy.src.on.open=false
copy.src.target=
hostname=localhost
port=8888
router=mdbTester.php
run.as=INTERNAL
url=http://localhost:8888/
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group/>
</open-files>
</project-private>
-7
View File
@@ -1,7 +0,0 @@
include.path=${php.global.include.path}
php.version=PHP_53
source.encoding=UTF-8
src.dir=.
tags.asp=false
tags.short=false
web.root=.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.php.project</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/php-project/1">
<name>Service</name>
</data>
</configuration>
</project>
+19
View File
@@ -0,0 +1,19 @@
<?php
// inclusione del file contenente la classe
include "./MySqlClass.php";
include "./utility.php";
include "./ricette.php";
include "./profile.php";
include "./image.php";
/*
$img = imagecreatefrompng("https://www.google.it/images/srpr/chrome_ntp_white_logo2.png");
echo "caricato immagine";
importImage(28, $img, '10203753344023406');
*/
?>
<img src="<?php getThumbnailImage(11) ?>">
<img src="<?php getImage(11) ?>">
+1
View File
@@ -0,0 +1 @@
a:2:{s:1:"t";s:16:"s1ti76srenx4b7aj";s:1:"s";s:15:"qshrdehad4dzz6n";}