PSR-7‫و‬middleware-‫ها‬‫معرفی‬ ‫و‬end Expressive
‫عربی‬ ‫میالد‬
8‫برنامه‬ ‫سال‬
‫نویس‬PHP
‫دهنده‬ ‫توسعه‬BSS/CRM
milad.arabi@gmail.com
@ooghry
Linkedin
microphp.org
I am a PHP developer
• I am not a Zend Framework or Symfony or CakePHP developer
• I think PHP is complicated enough
I like building small things
• I like building small things with simple purposes
• I like to make things that solve problems
• I like building small things that work together to solve larger problems
I want less code, not more
• I want to write less code, not more
• I want to manage less code, not more
• I want to support less code, not more
• I need to justify every piece of code I add to a project
I like simple, readable code
• I want to write code that is easily understood
• I want code that is easily verifiable
‫دنیای‬PHP‫سال‬ ‫در‬
2016
http://www.php-fig.org/members/
PHP Standards Recommendations
PSR-0(DEPRECATED) Autoloading
PSR-1 Basic coding standard
PSR-2 Coding style
PSR-3 Logger
PSR-4 Autoloading
PSR-5(DRAFT) PHPDoc Standard
PSR-6 Caching Interface
PSR-7 HTTP Message Interface
PSR-8(DRAFT) Huggable Interface
PSR-9(DRAFT) Security Advisories
<?php
namespace SymfonyComponentHttpFoundation;
class Request
{
public static function createFromGlobals()
{
$request = self::createRequestFromFactory(
$_GET,
$_POST,
array(),
$_COOKIE,
$_FILES,
$server
);
return $request;
}
}
<?php
namespace ZendHttpPhpEnvironment;
class Request extends HttpRequest
{
public function __construct()
{
$this->setEnv(new Parameters($_ENV));
if ($_GET) {
$this->setQuery(new Parameters($_GET));
}
if ($_POST) {
$this->setPost(new Parameters($_POST));
}
if ($_COOKIE) {
$this->setCookies(new Parameters($_COOKIE));
}
if ($_FILES) {
// convert PHP $_FILES superglobal
$files = $this->mapPhpFiles();
$this->setFiles(new Parameters($files));
}
$this->setServer(new Parameters($_SERVER));
}
}
HTTP Message Interface
• PsrHttpMessageMessageInterface
o PsrHttpMessageResponseInterface
o PsrHttpMessageRequestInterface
 PsrHttpMessageServerRequestInterface
• PsrHttpMessageStreamInterface
• PsrHttpMessageUploadFileInterface
• PsrHttpMessageUriInterface
Message
ResponseRequestStream
Uploaded File Server Request URI
extends
Wrapper
Local filesystem file://
HTTP Address http:// https://
FTP ftp:// ftps://
SSL ssl:// tls://
MySQL tcp://
Zip zip://
MongoDB mongodb://
PHP php://input php://output
php://temp php://memory
<?php
file_get_contents('local_file.json');
file_get_contents('http://site.com/file.json');
Middleware
http://stackphp.com/
https://zend-expressive.readthedocs.io/en/latest/getting-started/features/
function(
RequestInterface $request,
ResponseInterface $response,
callable $next=null
):ReponseInterface
<?php
namespace Mine;
class XClacksOverhead
{
public function __invoke($request, $response, $next)
{
$response = $next($request, $response);
return $response->withHeader(
'X-Clacks-Overhead',
'GNU Terry Pratchett'
);
}
}
Zend Framework
https://github.com/zendframework
zend-diactoros
https://github.com/zendframework/zend-diactoros
PSR-7 HTTP Message implementation
zend-stratigility
https://github.com/zendframework/zend-stratigility
Middleware for PHP built on top of PSR-7
Zend Expressive
•Routing interface
•CountainerInterface
•Templating Interfaceoptional
•Error handlingoptional
composer create-project zendframework/zend-expressive-skeleton
 ZendExpressiveRouterRouterInterface
• public function addRoute(Route $route);
• public function match(Request $request);
• public function generateUri($name, array $substitutions = []);
 InteropContainerContainerInterface
• public function get($id);
• public function has($id);
 ZendExpressiveTemplateTemplateRendererInterface
• public function render($name, $params = []);
• public function addPath($path, $namespace = null);
• public function getPaths();
• public function addDefaultParam($templateName, $param, $value);
 ZendStratigilityFinalHandler
.1‫از‬ ‫استفاده‬ ‫با‬ ‫نصب‬composer
.2‫تعریف‬VirtualHost
.3‫فایل‬ ‫ویرایش‬hosts‫ویندوز‬
Invokable Factory
<?php
class iClass
{
public function method1()
{
return time();
}
}
<?php
class fClass
{
private $adapter;
public function __construct($adapter)
{
$this->adapter=$adapter;
}
public function method1()
{
return $this
->adapter
->someMethod();
}
}
//--------------------------
class fClassFactory
{
public function __invoke()
{
$adapter=new NSAdapterClass;
return new fClass($adapter);
}
}
https://github.com/ooghry/Zend-Expressive-CoderConf
composer require zendframework/zend-db
config/autoload/db.global.php
config/autoload/db.local.php
config/autoload/routes.global.php
[
'name' => 'user.list',
'path' => '/list',
'middleware'=>AppActionListAction::class,
'allowed_methods' => ['GET'],
],
templates/app/list.html.twig
AppActionListAction
AppActionListActionFactory
<?php
namespace AppAction;
use InteropContainerContainerInterface;
use ZendDbAdapterAdapterInterface;
use ZendExpressiveTemplateTemplateRendererInterface;
class ListActionFactory
{
public function __invoke(ContainerInterface $container)
{
$template = ($container->has(TemplateRendererInterface::class))
? $container->get(TemplateRendererInterface::class)
: null;
$adapter = ($container->has(AdapterInterface::class))
? $container->get(AdapterInterface::class)
: null;
return new ListAction($template,$adapter);
}
}
<?php
namespace AppAction;
use ...
class ListAction
{
private $adapter;
private $template;
public function __construct(TemplateRendererInterface $template, $adapter)
{
$this->adapter = $adapter;
$this->template = $template;
}
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next = null
){
$statement = $this->adapter->query('select * from profile');
$users = $statement->execute();
return new HtmlResponse(
$this->template->render('app::list', ['users' => $users])
);
}
}
<?php
namespace AppAction;
use ZendDiactorosResponseJsonResponse;
use PsrHttpMessageResponseInterface;
use PsrHttpMessageServerRequestInterface;
class PingAction
{
public function __invoke(
ServerRequestInterface $request,
ResponseInterface $response,
callable $next = null)
{
return new JsonResponse(['ack' => time()]);
}
}
config/autoload/middleware-pipeline.global.php
'always' => [
'middleware' => [
HelperServerUrlMiddleware::class,
AppMiddlewareAuthMiddleware::class,
],
'priority' => PHP_INT_MAX,
],
config/autoload/dependencies.global.php
'factories' => [
AppMiddlewareAuthMiddleware::class => AppMiddlewareAuthMiddlewareFactory::class,
],
App
Auth
src/App/Middleware/AuthMiddleware.php
<?php
namespace AppMiddleware;
use ...
class AuthMiddleware
{
private $helper;
public function __construct(UrlHelper $helper)
{
$this->helper=$helper;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
{
if($this->helper->generate('api.ping')!=$request->getUri()->getPath()) {
$auth = $this->parseAuth($request->getHeaderLine('Authorization'));
if (!$auth or !$this->checkUserPass($auth['user'], $auth['pass'])) {
return $response
->withHeader('WWW-Authenticate', 'Basic realm=""')
->withStatus(401);
}
}
$response = $next($request, $response);
return $response;
}
}
Download Middleware
config/autoload/routes.global.php
[
'name' => 'download',
'path' => '/download/{file:[_0-9a-zA-Z-]+.w{1,}}',
'middleware' => AppActionDownloadAction::class,
'allowed_methods' => ['GET'],
],
AppActionDownloadAction
class DownloadAction
{
public function __invoke($request, $response, $next = null)
{
$file='data'.$request->getUri()->getPath();
if(is_readable($file)){
return $response
->write(file_get_contents($file))
->withHeader(
'Content-Disposition',
'inline; filename="' . pathinfo($file,PATHINFO_BASENAME) . '"'
)
->withHeader('Content-type',pathinfo($file,PATHINFO_EXTENSION))
->withStatus(200);
}else{
return $next($request, $response);
}
}
}
App
Auth
Unavailable
config/autoload/middleware-pipeline.global.php
'middleware' => [
HelperServerUrlMiddleware::class,
AppMiddlewareUnavailableMiddleware::class,
AppMiddlewareAuthMiddleware::class,
],
AppMiddlewareUnavailableMiddleware
public function __invoke($request, $response, callable $next = null)
{
if (date('G') == '23' || (date('G') == '0' && date('i') < '30')) {
return new HtmlResponse($this->template->render('app::unavailable'));
}
$response = $next($request, $response);
return $response;
}
AppMiddlewareUnavailableMiddlewareFactory
templates/app/unavailable.html.twig
config/autoload/dependencies.global.php
‫متشکرم‬
PSR-7‫و‬middleware-‫معرفی‬ ‫و‬ ‫ها‬Zend Expressive
‫عربی‬ ‫میالد‬
milad.arabi@gmail.com
@ooghry
Linkedin
https://github.com/ooghry/Zend-Expressive-CoderConf

PSR-7 - Middleware - Zend Expressive