Upload
sasezaki
View
1.182
Download
1
Embed Size (px)
Citation preview
HTTPメッセージ、PHPの
事情ば分かっとっと?
第102回 PHP勉強会@東京@sasezaki
『開発者は、ウェブアプリケーションを構築する際に
HTTPメッセージとどう対峙していけばいいのだろ
う?そのためには、SAPI・ストリーム・出力バッファ
リングと向きあなわければいけないのでは?』が今日
のテーマです。
2016.05.25
● 自己紹介ここ数年の記事とか発表– 2015年03月 日記
PHP - 憂鬱な希望としての PSR-7 http://sasezaki.hatenablog.com/entry/2015/03/07/195908
– 2015年06月 Symfony Meetup
Symfony ユーザ向け psr-7 zend-diactoros Middleware 入門http://psr7.net/sasezaki/slide20150620/
– 2015年06月 動作確認
ストリーム 関連のプロジェクトの話https://gistlog.co/sasezaki/fb703148b0542d61f0bb
– 2015年11月 PHP勉強会@相模原
PSR-7 - これは何だhttp://psr7.net/sasezaki/slide20151110/
● 自己紹介ここ数年の記事とか発表– 2016年05月 PHPカンファレンス福岡2016
HTTPメッセージ - PHPで扱う場合の再入門http://psr7.net/sasezaki/phpconfuk2016/
NEW
・・・ということで、察しがついたかも知れませんが、今日の話は先日の発表をベースにしてます。
https://twitter.com/chobi_e/status/193717178615345153
せやな(汗
...........SAPIって何?
「PHPの実行環境は、主にWebサーバ(でのモジュール)」「サーバにはapache以外にも色々ある。」「CLIもサーバ」
『第1回 身近なWeb[PDF] – 放送大学』よりhttp://morimoto.code.ouj.ac.jp/resources/2015_web/01.pdf
図コピペ元:http://tech.respect-pal.jp/php-helloworld/
サーバーリクエスト (Incoming Request )
Webサーバ
HTTPリクエスト
PHPスクリプトコード
・ $_SERVER,$_GET,$_POST,$_COOKIE,$_FILES ・ apache_request_headers() ・ php://input
apache_request_headers()が必要な場面について “In particular, it SHOULD remove any header fields
carrying authentication information, such as 'Authorization'; or that are available to the script in other variables, “
(RFC 3875より)
最大サイズ・最大長などの制限を設けてる● 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より)
サーバーリクエストからのスーパーグローバルへ
『今の若い人は CGI なんか知らないと思いますが、そういうのがあって、昔はとてもよく使われてたんですよ。この CGI の仕様を借りて WSGI が Environment の仕様を決め、Rack もそれを継承しています。そのため、CGI を知らない人から見ると奇妙な仕様に見えるでしょう。「なんで User-Agent ヘッダーが HTTP_USER_AGENT に変わってるの?そのまま User-Agent 文字列を使えばいいのに。」のような感想が出てきそうです。』
$_SERVER, CGI, Environment(wsgi, rack)
http://qiita.com/kwatch/items/67657fef43666479bb99
※ ちなみに、PHPにおける”リアル”とは
PHPのひょうじゅんAPIつらぽよ
E_WARNING: Cannot modify header information - headers already sent by (output started at ...
スーパーグローバルを直に触るのはつらいheader()を先に呼ばなきゃいけないのがつらいファイル配列操作がつらいリクエストURIの操作がつらい
『PSR-7: HTTP Message Meta Document』から意訳&抜粋
アプリケーション実装者が行いたいことは、リクエストを受け取って、レスポンスを生成する
function dispatch($request,$response);
HTTPリクエスト
ディスパッチャ ( index.php )
ブートストラップ
コントローラ
ルーティング
リクエスト
レスポンス
View / テンプレート
リクエストルーター利用でのプロジェクト構成(例)
かくして、PHP開発者はHTTPメッセージと末永く暮らしていきましたとさ。
めでたし。めでた.....
Fatal error: Allowed memory size of 6291456 bytes exhausted (tried to allocate 2097153 bytes)
ひー
PHP、おまえだったのか。
いつもHTTPメッセージを
運んでくれたのは
メッセージボディは、文字列で決定やな。 * * @return string */ public function getContent() {
HTTPメッセージコンポーネント設計者
・・・なんや問題あるんか?
何が問題?
メモリを制限なく消費する可能性→ ヘッダやボディに最大長についてRFC規定あっただろうか? 例えばApacheの場合、LimitRequestBodyにて許可バイト数設定
開発者は諦めてアクションでecho→ getContent()にてコールバックを許容した場合、 戻り値の方が一致しない
Streamリソース利用の発想が抜けている→ HTTPクライアントとして、ストリームは利用しているのに...
レスポンスボディの出力・フラッシュ標準の設定では、echoがあれば直ちに送信や文字列すべてを出力はしないパフォーマンスのためにデフォルトのphp.iniではoutput_buffering = 4096 に設定されている。※ CLIは除く
ob_start() コールバック関数ob_start() での引数、またはphp.iniでのoutput_handlerの指定により、出力バッファの内容を操作できる。 ob_gzhandler()関数など
テンプレートエンジン / Viewレンダラーでの応用出力内容を文字列として取得するために、ob_start() ob_get_contents()を行っている。ここでもメモリ使用量増大の可能性
出力出力バッファリング制御制御
せや、streamや!
* * @return stream */ public function getContent() {
HTTPメッセージコンポーネント設計者
抽象化 I/OPHP 4.3から登場したresourceオブジェクト普段のファイルシステムやhttpなどのスキーマは、デフォルトのラッパーにすぎない
入出力ストリームphp://temp により、メモリならびにテンポラリファイルへの読み書きが行える
ストリームフィルタストリームはカスタムフィルタを作成し、登録できる
PHPPHPにおにおけるStreamStream
レスポンス作成時の例外・エラー処理レスポンス作成時の例外・エラー処理 ストリームや出力バッファリング制御 の利用により、メモリ利用量を抑えレスポンス出力時に処理を実行することは可能でしょう。 ただし、レスポンスボディ作成時の例外(DBコネク
ションエラーなど)などを考慮すると一度テンポラリーに書き出しておき、そのストリームリソースを再度渡すなどの対応も考慮すべきでは。
HTTPメッセージコンポーネントがおおすぎる
• Cake\Network\{Request,Response}• CI_Input, CI_Output• Nette\Http\{Request,Response}• PHPixie\HTTP\{Request,Responses}• Symfony\Component\HttpFoundation\{Request,Response}• yii\web\{Request,Response}• Zend\Http\{Request,Response}
Rob Allen 『HTTP, PSR-7 and Middleware』から
依存を抑え、リクエスト・レスポンスを扱う処理
を相互運用するには?
HTTPレスポンス
ディスパッチャ
ブートストラップ
コントローラ
ルーティング
リクエスト
レスポンス
View / テンプレート
Debugツールバー
Authentication
ミドルウェア・ランナー
MiddlewareMiddleware
Middleware
Middleware
ミドルウェア利用でのプロジェクト構成例
while (! $stream->eof()) { echo $stream->read(8192);}
リクエストを受け取って、レスポンスを合成し、次の処理へ渡す
function __invoke( ServerRequestInterface $request, ResponseInterface $response, callable $next);
psr-7はHTTPメッセージの値についてのinterfaceを定義している従来のレスポンスクラスでは、send()メソッドなんて用意していた
サーバーリクエストには、アプリケーションでの相互運用のために attributesプロパティが用意されているミドルウェアシグネチャでの議論・検討の余地従来のEventManagerを利用したプラグインとの使い分けは?HTTPクライアントでのミドルウェアはどうあるべきか?インターフェイスなどにて別途psrを定義すべきでは?
PSR-7 とミドルウェア
PSR-7 PSR-7 に対するご意見に対するご意見
● PHPカンファレンス福岡2016で出た質問・余談
–Q「ストリームだと、今までの文字列関数を利用したフィルタリングに比べて大変では?」●私見「レスポンスボディ全体を文字列置換?(困惑)」(“エンコード”の範囲なら、今までのstream filterの想定範囲と同様に効力あるかと)
● PHPカンファレンス福岡2016で出た質問・余談
–Q「echo に比べてストリーム大変ですよ。。」
これを
● PHPカンファレンス福岡2016で出た質問・余談
–Q「echo に比べてストリーム大変ですよ。。」
こうしたり
● PHPカンファレンス福岡2016で出た質問・余談
–Q「echo に比べてストリーム大変ですよ。。」
こうじゃ!
● PHPカンファレンス福岡2016で出た質問・余談
–Q「PSR-7だと今のPHP組み込みのセッション機構と整合性がないのでは?」●私見「Cookieを利用したセッションということで?本発表で述べたように、PHPはHTTPメッセージ解釈機能を併せ持ってこそツールとしての価値があるのです。私は、それを崩そうとは思いません。従来の($_SESSIONをラップした)セッションコンポーネント使います。」(本音「そこまで、深く考えてなかったンゴwww」 今までのHTTPメッセージコンポーネントでも同様の問題では。。)※ 「PSR-7 and Session Cookies」http://paul-m-jones.com/archives/6310 という記事にセッションのクッキーヘッダーへのハック周りについて記載があります。
おわりです
ご清聴ありがとうございました
イラスト素材●http://www.wanpug.com/●http://hiyokoyarou.com/
参考文献● 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 deephttp://jpauli.github.io/2014/12/19/php-output-buffer-in-deep.html
● PSR-7: HTTP message interfaceshttp://www.php-fig.org/psr/psr-7/
● PSR-7: HTTP Message Meta Documenthttp://www.php-fig.org/psr/psr-7/meta/
● A Case for Higher Level PHP Streams in PSR-7http://mtdowling.com/blog/2014/07/03/a-case-for-higher-level-php-streams/