Slide 1

Slide 1 text

PHP Middleware i njegova upotreba Nenad Lukić • 03.08.2016 Make PHP great again.

Slide 2

Slide 2 text

Biografija Programerčić od 2005. Web developer od 2007. Arhitekta od 2015.

Slide 3

Slide 3 text

Problemi u starom načinu obrade Nepostojanje standarda Korišćenje superglobalnih Headeri su random 3

Slide 4

Slide 4 text

Problemi u starom načinu obrade [ 'files' => [ 0 => [ 'name' => 'file0.txt', 'type' => 'text/plain', ], 1 => [ 'name' => 'file1.html', 'type' => 'text/html', ], ], ]; [ 'files' => [ 'name' => [ 0 => 'file0.txt', 1 => 'file1.html', ], 'type' => [ 0 => 'text/plain, 1 => 'text/html', ], ], ]; Nelogično Logično 4

Slide 5

Slide 5 text

PHP-FIG && PSR PHP Framework Interop Group PHP Standards Recommendations 5

Slide 6

Slide 6 text

Usvojeni PSR standardi 1. Basic Coding Standard - Paul M. Jones 2. Coding Style Guide - Paul M. Jones 3. Logger Interface - Jordi Boggiano 4. Autoloading Standard - Paul M. Jones 6. Caching Interface - Larry Garfield 7. HTTP Message Interface - Matthew Weier O'Phinney 6

Slide 7

Slide 7 text

Usvajanje PSR-7 HTTP Messages Urednik: Matthew Weier O'Phinney 2012. - Prvi nacrt prijedloga 2015. - Usvojen 7

Slide 8

Slide 8 text

HTTP Request Immutability HTTP Response public function withProtocolVersion($version) { if ( $this->protocol === $version ) { return $this; } $new = clone $this; $new->protocol = $version; return $new; } 8

Slide 9

Slide 9 text

HTTP Request Immutability HTTP Response $request = $request ->withMethod('POST') ->withUrl(new Url('http://example.org/') ->withHeader('Content-Type', 'text/plain'); 9

Slide 10

Slide 10 text

Primjeri $headerValues = $request->getHeader('Cookie'); $headerLine = $request->getHeaderLine('Accept'); $headers = $request->getHeaders(); $body = $request->getBody(); $message = $response->withHeader('Foo', 'Bar'); $message = $response->withBody($stream); 10

Slide 11

Slide 11 text

Utisci Pozitivne strane: Interfejs postavlja pravila. Implementacije interfejsa mogu da se razlikuju. Jednostavan pristup objektima* Skidanje limita na velicinu poruka korišćenjem stream-ova Aplikacija uvijek ima pristup originalnim request i response objektima Osim $response->getContents() - Stream 11

Slide 12

Slide 12 text

Utisci Negativne strane: Za svaku promjenu kreira se nova instanca. 10 promjena 10 instanci. $response->getContents() - Stream $newRequest = $oldRequest ->withHeader('X-Powered-By', 'Dafed'); $newRequest->getBody()->getContents(); $oldRequest->getBody()->getContents(); 12

Slide 13

Slide 13 text

Middleware Nezavisan dio aplikacije ko služi za obradu i pripremu requesta. Dio HTTP Messages standarda. Prijedlog novog PSR-15 standarda koji se specifično odnosi na Middleware. 13

Slide 14

Slide 14 text

Middleware Tri podjele middleware-a: ● Single pass (Request\Next) ● Double pass (Request\Response\Next) ● Closure ● Callable ● Before ● After 14

Slide 15

Slide 15 text

Obrada Requesta Standardna obrada Obrada sa middlewareom 15

Slide 16

Slide 16 text

Prva podjela middleware-a Single pass Double pass public function __invoke( RequestInterface $request, callable $next ) { return $next($request); } public function __invoke( RequestInterface $request, ResponseInterface $response, callable $next ) { return $next($request, $response); } 16

Slide 17

Slide 17 text

Druga podjela middleware-a Closure Callable function(Request $request, Closure $next) { return $next($request); } class CustomMiddleware extends MiddlewarePipe { public function __invoke(Request $request, callable $next) { return $next($request); } } 17

Slide 18

Slide 18 text

Treća podjela middleware-a Before After function(Request $request, Closure $next) { return $next($request); } function(Request $request, Closure $next) { $response = $next($request); return $response; } 18

Slide 19

Slide 19 text

Upotreba ➔ Autorizacija ➔ Autentifikacija ➔ CSRF validacija ➔ Validacija podataka ➔ Obrada i priprema podataka ➔ Obrada Response-a ➔ Obrada Request-a ➔ Logovanje ➔ Statistika ➔ itd…. 19

Slide 20

Slide 20 text

Autentifikacija public function handle($request, Closure $next) { if ($this->auth->guest()) { if ($request->ajax()) { return response('Unauthorized.', 401); } else { return redirect()->guest('auth/login'); } } return $next($request); } 20

Slide 21

Slide 21 text

Access log public function __invoke(ServerRequestInterface $request, callable $next) { if (!self::hasAttribute($request, ClientIp::KEY)) { throw new RuntimeException( 'AccessLog middleware needs ClientIp executed before' ); } $response = $next($request, $response); $message = $this->combined ? self::combinedFormat($request, $response) : self::commonFormat($request, $response); if ( $response->getStatusCode() >= 400 && $response->getStatusCode() < 600 ) { $this->logger->error($message); } else { $this->logger->info($message); } return $response; } 21

Slide 22

Slide 22 text

Response obrada public function __invoke(ServerRequestInterface $request, callable $next) { $response = $next($request, $response); return $response->withHeader('X-Powered-By', 'This Blog'); } 22

Slide 23

Slide 23 text

Obrada Requesta Onion 23 public function peel($request, Closure $core) { $coreFunction = $this->createCoreFunction($core); $layers = array_reverse($this->layers); $completeOnion = array_reduce($layers, function($nextLayer, $layer){ return $this->createLayer($nextLayer, $layer); }, $coreFunction); return $completeOnion($request); } private function createCoreFunction(Closure $core) { return function($request) use($core) { return call_user_func($core, $request); }; } private function createLayer($nextLayer, $layer) { return function($request) use($nextLayer, $layer){ return call_user_func_array([$layer, 'peel'], [$request, $nextLayer]); }; }

Slide 24

Slide 24 text

Obrada Requesta Onion 24 class BeforeLayer implements LayerInterface { public function peel($request, Closure $next) { $request>runs[] = 'before'; return $next($request); } } class AfterLayer implements LayerInterface { public function peel($request, Closure $next) { $response = $next($request); $request>runs[] = 'after'; return $response; } }

Slide 25

Slide 25 text

Obrada Requesta Onion 25 $request = new StdClass; $request->runs = []; $onion = new Onion; $end = $onion->layer([ new AfterLayer(), new BeforeLayer(), new AfterLayer(), new BeforeLayer() ])->peel($request, function($request){ $request->runs[] = 'core'; return $request; }); var_dump($end);

Slide 26

Slide 26 text

Obrada Requesta Onion 26 object(stdClass)#1 (1) { ["runs"]=> array(5) { [0]=> string(6) "before" [1]=> string(6) "before" [2]=> string(4) "core" [3]=> string(5) "after" [4]=> string(5) "after" } }

Slide 27

Slide 27 text

U drugim tehnologijama Ruby (via Rack) Python (via WSGI) Node (via Connect / ExpressJS) PHP Framerworks: ● StackPHP ● Laravel ● Symfony ● Slim ● Zend etc... 27

Slide 28

Slide 28 text

Opšte smjernice koje Middleware treba da poštuje ● Primi request i response objekte od prethodnog middlewarea kao parametre, kao i sledeći middleware u stack-u. ● Ukoliko je potrebno, napravi novi request objektat sa izmjenjenim parametrima. ● Ukoliko je potrebno, pozovi sledeći middleware sa prosledjenim ili promjenjenim objektima ● Ukoliko je potrebno modifikuj response objekat kreiranjem novog objekta sa izmjenjenim parametrima ● Vrati response objekat prethodnim middleware-ovima. 28

Slide 29

Slide 29 text

Primjeri u praksi 29

Slide 30

Slide 30 text

Laravel Fullstack MVC framework Middleware od verzije 5.0 30

Slide 31

Slide 31 text

Laravel Bootstrapping 31

Slide 32

Slide 32 text

Laravel Termination 32

Slide 33

Slide 33 text

Laravel Default middleware stack // Global middleware 'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode', 'Illuminate\Cookie\Middleware\EncryptCookies', 'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse', 'Illuminate\Session\Middleware\StartSession', 'Illuminate\View\Middleware\ShareErrorsFromSession', 'App\Http\Middleware\VerifyCsrfToken', // Route middleware 'auth' => 'App\Http\Middleware\Authenticate', 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', 'guest' => 'App\Http\Middleware\RedirectIfAuthenticated', 33

Slide 34

Slide 34 text

Laravel Check for maintenance mode app = $app; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if ($this->app->isDownForMaintenance()) { throw new HttpException(503); } return $next($request); } } 34

Slide 35

Slide 35 text

Laravel $ php artisan make:middleware DafedCheck $ php artisan make:middleware DafedCheck Middleware created successfully. $ ll /app/Http/Middleware total 10 -rw-r--r-- 1 bbs 197121 751 Apr 30 2015 Authenticate.php -rw-r--r-- 1 bbs 197121 295 Jul 31 18:18 DafedCheck.php -rw-r--r-- 1 bbs 197121 706 Apr 30 2015 RedirectIfAuthenticated.php -rw-r--r-- 1 bbs 197121 412 Apr 30 2015 VerifyCsrfToken.php 35

Slide 36

Slide 36 text

path() === ‘dafedWelcome’)) { return redirect('welcome'); } return $next($request); } } Laravel 36

Slide 37

Slide 37 text

Route::get('/dafedWelcome, function () { // })->middleware('auth', ‘DafedCheck’); Laravel Laravel //// 'DafedCheck'=> 'App\Http\Middleware\DafedCheck, //// Route::group(['middleware' => [‘DafedCheck’]], function () { // }); 37

Slide 38

Slide 38 text

Laravel Laravel

Slide 39

Slide 39 text

Laravel Laravel path() === ‘dafedWelcome’ && $param === ‘perform’)) { return redirect('welcome'); } return $next($request); } } Route::get('/dafedWelcome, function () { // })->middleware('auth', ‘DafedCheck:perform); 39

Slide 40

Slide 40 text

Laravel Laravel pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING)); $log->info('Visit'); } } 40

Slide 41

Slide 41 text

Hvala na pažnji Pitanja? 41

Slide 42

Slide 42 text

Reference 1. http://www.php-fig.org/psr/psr-7 2. http://blog.ircmaxell.com/2016/05/all-about-middleware.html?m=1 3. https://github.com/php-fig/fig-standards/blob/master/proposed/http-middleware/mi ddleware-meta.md 4. http://relayphp.com/ 5. https://github.com/phly/conduit 6. http://stackphp.com 7. http://www.slimframework.com/docs/concepts/middleware.html 8. https://laravel.com/ 9. https://evertpot.com/psr-7-issues/ 42