HTTP Middlewares in PHP by Eugene Dounar

Preview:

DESCRIPTION

Minsk PHP User Group Meetup #5

Citation preview

HTTP Middlewares in PHP

http://igor.io @igorwhiletrue @eugene_dounar

Interface?

interface A { function doSomething(); function doSomethingElse();}

Универсальный интерфейс

find src -name '*.php' | grep -iv tests |

cut -f2- -d/ | cut -f1 -d\. |

awk '{ print length, $0 }' | sort -n |

tr / \\ ;

nc

xinetd

cgi

RFC 3875

The Common Gateway Interface (CGI) [22] allows an HTTP [1], [4] server and a CGI script to share responsibility for responding to client requests.

scriptПеременные окружения

ENV

Заголовки

Тело ответа

GET / HTTP/1.1Host: igor.ioAccept: */*

REQUEST_METHOD = GETPATH_INFO = /HTTP_HOST = igor.ioHTTP_ACCEPT = */*SERVER_NAME = igor.io

Content-Type: text/html

<!DOCTYPE html><html>...</html>

fcgi

nginx

script

Python?

WSGI

def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) yield 'Hello World\n'

Ruby?

app = lambda do |env| body = "Hello, World!" [200, { "Content-Type" => "text/plain", "Content-Length" => body.length.to_s }, [body]]end run app

PHP?

?

PHP?

sapi

$_SERVERheader()echoexit()

php_sapi_name()

➔ aolserver➔ apache➔ apache2filter➔ apache2handler➔ caudium➔ cgi (until PHP

5.3)➔ cgi-fcgi➔ cli➔ continuity➔ embed

➔ isapi➔ litespeed➔ milter➔ nsapi➔ phttpd➔ pi3web➔ roxen➔ thttpd➔ tux➔ webjame

s

Python :)Ruby :)PHP :(

HttpKernelInterface

<?php

namespace Symfony\Component\HttpKernel;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;interface HttpKernelInterface{ const MASTER_REQUEST = 1; const SUB_REQUEST = 2;

public function handle( Request $request, $type = self::MASTER_REQUEST, $catch = true );}

<?php

namespace Symfony\Component\HttpKernel;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;interface HttpKernelInterface{ const MASTER_REQUEST = 1; const SUB_REQUEST = 2;

public function handle( Request $request, $type = self::MASTER_REQUEST, $catch = true );}

kernel

sapi

Why?

Обернуть древний код для тестов?

Why?

Обернуть древний код для тестов?

exit(‘you lose’);

CgiHttpKernel

Адаптер CGI реализующий интерфейс HttpKernelInterface

Why?

Кэширование?

Why?

Кэширование?

$kernel = new AppCache($kernel);

Why?

Кэширование?

varnish

$kernel = new AppCache($kernel);

middleware

<?php$app = new CallableHttpKernel(function ($request) { return new Response('Hello World!');});

class Logger implements HttpKernelInterface{ private $app; private $logger; public function __construct(HttpKernelInterface $app, LoggerInterface $logger) { $this->app = $app; $this->logger = $logger; }

public function handle(Request $request, ...) { $response = $this->app->handle($request, $type, $catch); $this->log($request, $response);

return $response; }

private function log(Request $request, Response $response) { ... }}

$app = new Logger( $app, new Monolog\Logger());

Session

Authentication

Logger

App

Rack middlewares https://github.com/rack/rack/wiki/List-of-Middleware

WSGI middlewares http://wsgi.readthedocs.org/en/latest/libraries.html

HttpKernel middlewares ?

Идея: Выполнять код до и после

обработки каждого запроса

class Foo implements HttpKernelInterface{ private $app;

public function __construct(HttpKernelInterface $app) { $this->app = $app; }

public function handle(Request $request, ...) { $response = $this->app->handle($request, $type, $catch); return $response; }}

Идея: Выполнять код до и после

обработки каждого запроса

События?

$blog = new Silex\Application();$blog->get('/', function () { return 'This is the blog!';});$app = new Stack\UrlMap($app, [ '/blog' => $blog,]);

UrlMap

$app = new CallableHttpKernel(function ($request) { $session = $request->getSession(); ...});$app = new Stack\Session($app);

Session

$app = new Igorw\Stack\OAuth($app, [ 'key'=> 'foo', 'secret'=> 'bar', 'callback_url' => 'http://localhost:8080/auth/verify', 'success_url'=> '/', 'failure_url'=> '/auth',]);$app = new Stack\Session($app);

OAuth

$request->attributes->get('oauth.token');

Простая композиция:

$stack = (new Stack\Builder()) ->push('Stack\Session') ->push('Igorw\Stack\OAuth', [...]) ->push('Foo');$app = $stack->resolve($app);

Middlewares!

● HttpCache● GeoIp● Backstage● Basic Authentication● CORS● Firewall

● CookieGuard● IpRestrict● OAuth● Hawk● StackRobots

More?● Authentication (~Warden)● ForceSSL● Debug toolbar● ESI● OpenID● ...

stackphp.com

github.com/stackphp

@stackphp

“HttpKernel is a lie” by @igorwhiletrue

Recommended