Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

PHP、おまえだったのか。 いつもHTTPメッセージを 運んでくれたのは。

4,054 views

Published on

PHPカンファレンス福岡2016『HTTPメッセージ - PHPで扱う場合の再入門』

http://psr7.net/sasezaki/phpconfuk2016/

Published in: Technology
  • Be the first to comment

PHP、おまえだったのか。 いつもHTTPメッセージを 運んでくれたのは。

  1. 1. PHP、おまえだったのか。 いつもHTTPメッセージを 運んでくれたのは。 PHPカンファレンス福岡2016 HTTPメッセージ – PHPであつかう場合の再入門 @sasezaki
  2. 2. ● ※ PHPカンファレンス福岡2016にて利用したスライド です。http://psr7.net/sasezaki/phpconfuk2016/ も 参照ください ● 概要 PHPがWebのために開発され利用され20年。直観的な ものであったPHPのAPIも複雑性を生み出す一因となっ てしまいました。抽象化の理解とその導入が煩雑さを 避けるために必要となります。HTTPメッセージ利用に ついて、PHP自体の機能とPHPプロジェクトでのアー キテクチャの変遷を踏まえつつ、開発者が意識してお きたい点を話したいと思います。SAPI・ストリーム・ 出力バッファリング・Middlewareについて考えていき ます。
  3. 3. 4.0 よりちょっと前の頃の話 (~2000年)
  4. 4. CGI Common Gateway Interface
  5. 5. use CGI qw(:standard); print header; print start_html('Form Example'), h1('My Example Form'), start_form, "Name:", textfield('name'), p, "Age:", textfield('age'), p, submit, end_form; if (param()) { print "Hi ", em(param('name')), "You are ", em(param('age')), "years old "; } print end_html; HTMLフォーム (Perl CGI.pm利用) 『例解PHP』(2001年) 序文より (Rasmus Lerdorf)
  6. 6. 『当時筆者が感じたことと言えば、Perlインター プリタを毎回起動するオーバーヘッドが馬鹿に ならないことと、CGIプログラムをCで書くのは とても退屈な作業だということでした。しか し、それでもいろいろなプログラムをCで書いて るうちに、同じコードを何度も繰り返し書いて いることに気付きました。つまり、CGIスクリプ トのHTML部分とCコードを分離する簡単なラッ パーさえあれば、HTMLを変更してもCコードを 再コンパイルしなくて済む悟ったわけです。』 『例解PHP』(2001年) 序文より (Rasmus Lerdorf)
  7. 7. <HTML><header><title>Form Example</title></header> <body><h1>My Example Form</h1> <form action="<?echo $PHP_SELF?>" method="POST"> Name : <input type="text" name="name"> Age : <input type="text" name="age"> <input type="submit"> </form> <?if ($name):?> Hi <?echo $name?>, you are <?echo $age?> years old <?endif?> </body></html> HTMLフォーム (PHP) 『例解PHP』(2001年) 序文より (Rasmus Lerdorf)
  8. 8. <HTML><header><title>Form Example</title></header> <body><h1>My Example Form</h1> <form action="<?echo $PHP_SELF?>" method="POST"> Name : <input type="text" name="name"> Age : <input type="text" name="age"> <input type="submit"> </form> <?if ($name):?> Hi <?echo $name?>, you are <?echo $age?> years old <?endif?> </body></html> HTMLフォーム (PHP) 『例解PHP』(2001年) 序文より (Rasmus Lerdorf) XSS!
  9. 9. PHPにはその昔、 リクエスト値をとことん楽に 扱える機能に register globalsや マジッククオートといった ものがありました。。
  10. 10. 忘れろ!
  11. 11. HTTPメッセージを平文で 渡してやってもええんやで。
  12. 12. サーバーリクエスト (Incoming Request ) Webサーバ HTTPリクエスト PHP スクリプトコード ・ $_SERVER,$_GET,$_POST,$_COOKIE,$_FILES ・ apache_request_headers() ・ php://input
  13. 13. サーバーリクエスト Webサーバ HTTPリクエスト PHP スクリプトコード ・ $_SERVER,$_GET,$_POST,$_COOKIE,$_FILES ・ apache_request_headers() ・ php://input request startup php_output_activate sapi activate zend_compile zend_activate zend_activate_modules
  14. 14. かくして、PHPはHTTPリクエ ストと末永く暮らしていきま したとさ。 めでたし。めでた.....
  15. 15. Warning: POST Content-Length of ... bytes exceeds the limit of ヒー
  16. 16. PHP、おまえだったのか。 いつもpost_max_sizeから かばってくれていたのは
  17. 17. HTTPリクエスト Webサーバ HTTPリクエスト PHP スクリプトコード ・ $_SERVER,$_GET,$_POST,$_COOKIE,$_FILES ・ apache_request_headers() ・ php://input スクリプト実行前に、ini値の post_max_sizeを チェックし、最大値をこえる場合 は、$_POST・$_FILESの値は空 sapi activate
  18. 18. 最大サイズ・最大長などの制限を設けてる ● HashDosで知られるmax_input_varsの導入はPHP 5.3.9から ● もちろん、サーバソフト側でも制限設定項目はあり ● ApacheのLimitRequestBody ディレクティブなど POSTメソッドでの場合の$_POSTへの変換 ● sapi_activateでのsapi_read_post_dataのコールにて取得 php-src/main/SAPI.c 参照 ● php.ini のenable_post_data_reading にて$_POST や $_FILESへ の格納を無効化可能 (PHP 5.4より) $_SERVERとリクエストヘッダー ● ヘッダーが"HTTP_”プリフィクスなどはCGIの環境変数由来 ● Just In Timeでの利用時でのグローバル変数としての評価 http://php.net/ini.core#ini.auto-globals-jit “有効にした場合、SERVER および ENV 変数はスクリプトの開始時ではなく、 最 初に使用された時 (Just In Time)に作成される。”( php_variables.cのphp_startup_auto_globals など参照) サーバーリクエストとスーパーグローバル
  19. 19. PHPのひょうじゅんAPI つらぽよ
  20. 20. E_WARNING: Cannot modify header information - headers already sent by (output started at ...
  21. 21. スーパーグローバルを直に触るのはつらい header()を先に呼ばなきゃいけないのがつらい ファイル配列操作がつらい リクエストURIの操作がつらい 『PSR-7: HTTP Message Meta Document』から意訳&抜粋
  22. 22. アプリケーション実装者が行いたいことは、 リクエストを受け取って、レスポンスを生成する
  23. 23. function dispatch($request,$response);
  24. 24. HTTP リクエスト ディスパッチャ ( index.php ) ブートストラップ コントローラ ルーティング リクエスト レスポンス View / テンプレート リクエストルーター利用でのプロジェクト構成(例)
  25. 25. かくして、PHP開発者はHTTP メッセージと末永く暮らしていき ましたとさ。 めでたし。めでた.....
  26. 26. Fatal error: Allowed memory size of 6291456 bytes exhausted (tried to allocate 2097153 bytes) ぶー
  27. 27. PHP、おまえだったのか。 出力バッファリング制御をお こなってくれてたのは
  28. 28. メッセージボディは、 文字列で決定やな。 * * @return string */ public function getContent() { HTTPメッセージコンポーネント設計者 ・・・なんや問題あるんか?
  29. 29. 何が問題?   メモリを制限なく消費する可能性 → ヘッダやボディに最大長についてRFC規定あっただろうか? 例えばApacheの場合、LimitRequestBodyにて許可バイト数設定 開発者は諦めてアクションでecho → getContent()にてコールバックを許容した場合、  戻り値の方が一致しない Streamリソース利用の発想が抜けている → HTTPクライアントとして、ストリームは利用しているのに...
  30. 30. SAPIでの出力データの流れ(概略イメージ) request_shut_down php_output_end_all php_output_stack_pop php_output_write
  31. 31. レスポンスボディの出力・フラッシュ 標準の設定では、echoがあれば直ちに送信や文字列すべてを出力 はしない パフォーマンスのためにデフォルトのphp.iniでは output_buffering = 4096に設定されている。※ CLIは除く ob_start() コールバック関数 ob_start() での引数、またはphp.iniでのoutput_handlerの指定 により、出力バッファの内容を操作できる。 ob_gzhandler()関数など テンプレートエンジン / Viewレンダラーでの応用 出力内容を文字列として取得するために、ob_start() ob_get_contents()を行っている。 ここでもメモリ使用量増大の可能性 出力出力バッファリング制御制御
  32. 32. せや、streamや! * * @return stream */ public function getContent() { HTTPメッセージコンポーネント設計者
  33. 33. 抽象化 I/O PHP 4.3から登場したresourceオブジェクト 普段のファイルシステムやhttpなどのスキーマは、デフォルトの ラッパーにすぎない 入出力ストリーム php://temp により、メモリならびにテンポラリファイルへの読 み書きが行える ストリームフィルタ ストリームはカスタムフィルタを作成し、登録できる PHPPHPにおにおけるStreamStream
  34. 34. レスポンス作成時の例外・エラー処理レスポンス作成時の例外・エラー処理  ストリームや出力バッファリング制御 の利用によ り、メモリ利用量を抑えレスポンス出力時に処理を 実行することは可能でしょう。  ただし、レスポンスボディ作成時の例外(DBコネク ションエラーなど)などを考慮すると一度テンポラリーに 書き出しておき、そのストリームリソースを再度渡 すなどの対応も考慮すべきでは。
  35. 35. HTTPメッセージ コンポーネントが おおすぎる
  36. 36. • CakeNetwork{Request,Response} • CI_Input, CI_Output • NetteHttp{Request,Response} • PHPixieHTTP{Request,Responses} • SymfonyComponentHttpFoundation{Request,Response} • yiiweb{Request,Response} • ZendHttp{Request,Response} Rob Allen 『HTTP, PSR-7 and Middleware』から
  37. 37. 依存を抑え、 リクエスト・レスポンスを扱う処理 を相互運用するには?
  38. 38. HTTP レスポンス ディスパッチャ ブートストラップ コントローラ ルーティング リクエスト レスポンス View / テンプレート セッション(独自の) Authentication ミドルウェア・ ランナー MiddlewareMiddleware Middleware Middleware ミドルウェア利用でのプロジェクト構成例 while (! $stream->eof()) { echo $stream->read(8192); }
  39. 39. リクエストを受け取って、レスポンスを合成し、 次の処理へ渡す
  40. 40. function __invoke( ServerRequestInterface $request, ResponseInterface $response, callable $next);
  41. 41. psr-7はHTTPメッセージの値についてのinterfaceを定 義している 従来のレスポンスクラスでは、send()メソッドなんて用意していた サーバーリクエストには、アプリケーションでの相互 運用のために attributesプロパティが用意されている ミドルウェアシグネチャでの議論・検討の余地 従来のEventManagerを利用したプラグインとの使い分けは? HTTPクライアントでのミドルウェアはどうあるべきか? インターフェイスなどにて別途psrを定義すべきでは? PSR-7 とミドルウェア
  42. 42. PSR-7PSR-7 に対する批判に対する批判
  43. 43. 最後に ● HTTPリクエストに対し、どうHTTPレスポンスを返す か?データの流れはどのような工夫が必要だったか? PHP内部と周辺プロジェクトの状況を簡単に俯瞰して みました。 ● 普段のコーディングでは内部の動作についてはあまり 意識していないかも知れません。しかし、現実的な問 題(アプリケーションロジック)に専念するためにも、再 度振り返っていただければと思います。
  44. 44. おわりです ご清聴ありがとうございました
  45. 45. イラスト素材 ● http://www.wanpug.com/ ● http://www.irasutoya.com/ ● http://hiyokoyarou.com/
  46. 46. 参考文献 ● php と sapi と zendengine2 と.. http://www.slideshare.net/do_aki/php-and-sapi-and-zendengine2-and ● PHP による hello world入門 http://tech.respect-pal.jp/php-helloworld/ ● PHP output buffer in deep http://jpauli.github.io/2014/12/19/php-output-buffer-in-deep.html ● PSR-7: HTTP message interfaces http://www.php-fig.org/psr/psr-7/ ● PSR-7: HTTP Message Meta Document http://www.php-fig.org/psr/psr-7/meta/ ● A Case for Higher Level PHP Streams in PSR-7 http://mtdowling.com/blog/2014/07/03/a-case-for-higher-level-php-streams/
  47. 47. For Further Reading - HTTP - ● 『ハイパフォーマンス ブラウザネットワーキング――ネットワーク アプリケーションのためのパフォーマンス最適化』 https://www.oreilly.co.jp/books/9784873116761/ ● HTTP/2 Frequently AskedQuestions http://http2.info/faq.html ● なぜH2Oを作るのか 〜HTTP/2の未踏性〜 https://www.youtube.com/watch?v=ykp0fZigChs ● 新しいHTTPの話をしよう (HTTP/1.1 RFCs) http://blog.hmm.jp/entry/new-http1.1-rfcs ● メタ変数群 HTTP_* (CGI) https://wiki.suikawiki.org/n/HTTP_$1022
  48. 48. For Further Reading - PHP - ● The Php Life Cycle http://www.slideshare.net/laruence/the-php-life-cycle ● Phpをいじり倒す10の方法 http://www.slideshare.net/moriyoshi/php10 ● php.ini-recommendedで、variables_orderがGPCSである理由 と、PHP5のauto_globals_jit http://d.hatena.ne.jp/i_ogi/20071217/1197912203
  49. 49. For Further Reading - PHPのストリーム - ● ZF-6736: Allow writing the response body into a stream http://framework.zend.com/issues/browse/ZF-6736 ● PHP Iterators and Streams are awesome http://fabien.potencier.org/php-iterators-and-streams-are-awesome.html ● Writing and using php streams and sockets http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and- sockets-zendcon-2011 ● PHP stream for beginners http://hnw.jp/pdf/phpcon-20100925.pdf ● Good Parts of PHP and theUNIX Philosophys http://www.slideshare.net/taketyan/good-parts-of-php-and-the-unix-philosophy ● Prototype for an object oriented streams API in PHP https://github.com/DaveRandom/php-streams
  50. 50. For Further Reading - ミドルウェア - ● 次世代の Rack や WSGI を考えてみる http://qiita.com/kwatch/items/67657fef43666479bb99 ● HttpKernel middlewares https://igor.io/2013/02/02/http-kernel-middlewares.html ● beberlei/http-client-middleware https://github.com/beberlei/http-client-middleware ● Overview and Features - Expressive https://zendframework.github.io/zend-expressive/getting-started/features/

×