Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
PHP、おまえだったのか。 いつもHTTPメッセージを 運んでくれたのは。 | PDF
[go: Go Back, main page]

PHP、おまえだったのか。
いつもHTTPメッセージを
運んでくれたのは。
PHPカンファレンス福岡2016
HTTPメッセージ – PHPであつかう場合の再入門
@sasezaki
●
※ PHPカンファレンス福岡2016にて利用したスライド
です。http://psr7.net/sasezaki/phpconfuk2016/ も
参照ください
●
概要
PHPがWebのために開発され利用され20年。直観的な
ものであったPHPのAPIも複雑性を生み出す一因となっ
てしまいました。抽象化の理解とその導入が煩雑さを
避けるために必要となります。HTTPメッセージ利用に
ついて、PHP自体の機能とPHPプロジェクトでのアー
キテクチャの変遷を踏まえつつ、開発者が意識してお
きたい点を話したいと思います。SAPI・ストリーム・
出力バッファリング・Middlewareについて考えていき
ます。
4.0 よりちょっと前の頃の話
(~2000年)
CGI
Common Gateway Interface
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)
『当時筆者が感じたことと言えば、Perlインター
プリタを毎回起動するオーバーヘッドが馬鹿に
ならないことと、CGIプログラムをCで書くのは
とても退屈な作業だということでした。しか
し、それでもいろいろなプログラムをCで書いて
るうちに、同じコードを何度も繰り返し書いて
いることに気付きました。つまり、CGIスクリプ
トのHTML部分とCコードを分離する簡単なラッ
パーさえあれば、HTMLを変更してもCコードを
再コンパイルしなくて済む悟ったわけです。』
『例解PHP』(2001年)
序文より
(Rasmus Lerdorf)
<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)
<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!
PHPにはその昔、
リクエスト値をとことん楽に
扱える機能に
register globalsや
マジッククオートといった
ものがありました。。
忘れろ!
HTTPメッセージを平文で
渡してやってもええんやで。
サーバーリクエスト (Incoming Request )
Webサーバ
HTTPリクエスト
PHP
スクリプトコード
・ $_SERVER,$_GET,$_POST,$_COOKIE,$_FILES
・ apache_request_headers()
・ php://input
サーバーリクエスト
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
かくして、PHPはHTTPリクエ
ストと末永く暮らしていきま
したとさ。
めでたし。めでた.....
Warning: POST Content-Length
of ... bytes exceeds the limit
of
ヒー
PHP、おまえだったのか。
いつもpost_max_sizeから
かばってくれていたのは
HTTPリクエスト
Webサーバ
HTTPリクエスト
PHP
スクリプトコード
・ $_SERVER,$_GET,$_POST,$_COOKIE,$_FILES
・ apache_request_headers()
・ php://input
スクリプト実行前に、ini値の
post_max_sizeを
チェックし、最大値をこえる場合
は、$_POST・$_FILESの値は空
sapi activate
最大サイズ・最大長などの制限を設けてる
●
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
など参照)
サーバーリクエストとスーパーグローバル
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、おまえだったのか。
出力バッファリング制御をお
こなってくれてたのは
メッセージボディは、
文字列で決定やな。
*
* @return string
*/
public function getContent()
{
HTTPメッセージコンポーネント設計者
・・・なんや問題あるんか?
何が問題?
 
メモリを制限なく消費する可能性
→ ヘッダやボディに最大長についてRFC規定あっただろうか?
例えばApacheの場合、LimitRequestBodyにて許可バイト数設定
開発者は諦めてアクションでecho
→ getContent()にてコールバックを許容した場合、
 戻り値の方が一致しない
Streamリソース利用の発想が抜けている
→ HTTPクライアントとして、ストリームは利用しているのに...
SAPIでの出力データの流れ(概略イメージ)
request_shut_down
php_output_end_all
php_output_stack_pop
php_output_write
レスポンスボディの出力・フラッシュ
標準の設定では、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/O
PHP 4.3から登場したresourceオブジェクト
普段のファイルシステムやhttpなどのスキーマは、デフォルトの
ラッパーにすぎない
入出力ストリーム
php://temp により、メモリならびにテンポラリファイルへの読
み書きが行える
ストリームフィルタ
ストリームはカスタムフィルタを作成し、登録できる
PHPPHPにおにおけるStreamStream
レスポンス作成時の例外・エラー処理レスポンス作成時の例外・エラー処理
 ストリームや出力バッファリング制御 の利用によ
り、メモリ利用量を抑えレスポンス出力時に処理を
実行することは可能でしょう。
 ただし、レスポンスボディ作成時の例外(DBコネク
ションエラーなど)などを考慮すると一度テンポラリーに
書き出しておき、そのストリームリソースを再度渡
すなどの対応も考慮すべきでは。
HTTPメッセージ
コンポーネントが
おおすぎる
• 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』から
依存を抑え、
リクエスト・レスポンスを扱う処理
を相互運用するには?
HTTP
レスポンス
ディスパッチャ
ブートストラップ
コントローラ
ルーティング
リクエスト
レスポンス
View /
テンプレート
セッション(独自の)
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-7PSR-7 に対する批判に対する批判
最後に
●
HTTPリクエストに対し、どうHTTPレスポンスを返す
か?データの流れはどのような工夫が必要だったか?
PHP内部と周辺プロジェクトの状況を簡単に俯瞰して
みました。
●
普段のコーディングでは内部の動作についてはあまり
意識していないかも知れません。しかし、現実的な問
題(アプリケーションロジック)に専念するためにも、再
度振り返っていただければと思います。
おわりです
ご清聴ありがとうございました
イラスト素材
●
http://www.wanpug.com/
●
http://www.irasutoya.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 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/
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
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
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
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/

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