PHP meets NodeJS

42
PHP meets NodeJS PHP に簡単に PUSH 機能を組み込む 1384日日曜日

description

PHPにPUSH通知(リアルタイム処理)機能を導入するために、NodeJSと連携するための簡単な概要を説明してみました。特にどこかで発表した資料とかでは無いっす。 資料のライセンスはMITです。

Transcript of PHP meets NodeJS

Page 1: PHP meets NodeJS

PHP meets NodeJSPHPに簡単にPUSH機能を組み込む

13年8月4日日曜日

Page 2: PHP meets NodeJS

まずは自己紹介簡単に自己紹介

Name : takyam (たくやむ)

Work : WEBアプリケーションエンジニア?

Twitter : @takyam

Blog : http://new.takyam.com/

GitHub : http://github.com/takyam-git

Bitbucket : https://bitbucket.org/takyam

13年8月4日日曜日

Page 3: PHP meets NodeJS

PHPで通知機能

PHPでFacebookの通知機能のようなものを実装したい事ありますよね?

画面遷移を挟まずにユーザーへの通知が表示される機能です。

私はPUSH通知と呼んでるのですがこれをPHPで作りたいとおもいます

13年8月4日日曜日

Page 4: PHP meets NodeJS

通知機能を作るにはサーバー側からPUSHする必要がありますが、いくつかの手法があります

ポーリング(実際はPUSHでは無い)

Commet

Websocket

それぞれメリット・デメリットがあります

今回はWebsocketを使ってみたいと思います

13年8月4日日曜日

Page 5: PHP meets NodeJS

Websocketを使う

PHP単体でもWebsocketを扱えるようなライブラリはあります

とはいえWAFに組み込むのは難しいので今回はNodeJSを使います

Websocketの部分はNodeJSに全ておまかせです!

13年8月4日日曜日

Page 6: PHP meets NodeJS

NodeJS分かんねぇよ

そんな硬派なPHPerも大丈夫!

NodeJSは全部で100行くらいなので、コピペすりゃOK

一度作ればNodeJSメンテナンス不要なイケてるシステムです

13年8月4日日曜日

Page 7: PHP meets NodeJS

今回のシステムの前提今回のPUSHを実現するための前提条件が2つあります

NodeJSがPHPと同ドメイン(ポート違いOK)で運用できる

Redisが使える

これだけ!

13年8月4日日曜日

Page 8: PHP meets NodeJS

まずはイメージをつかむ

文字で説明するのも大変なので簡単なイメージ図をご紹介

まず最終的な完成形のイメージを掴んでください

13年8月4日日曜日

Page 9: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

13年8月4日日曜日

Page 10: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

投稿に対してのコメントをAjaxでPHPにPOSTリクエスト

13年8月4日日曜日

Page 11: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

コメントのDBへの保存処理などを実施

13年8月4日日曜日

Page 12: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

コメントが来たよ通知JSONをRedisにPUBLISH

13年8月4日日曜日

Page 13: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

SUBSCRIBEしてるNodeJSが通知JSONを受信

13年8月4日日曜日

Page 14: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

通知JSONから通知対象のユーザーを選択する

13年8月4日日曜日

Page 15: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

通知対象のユーザーのWebsocketを使ってPUSH通知(JSON)を送信!

13年8月4日日曜日

Page 16: PHP meets NodeJS

最終的な構成HTTP POST

Redis PUBLISH

Redis SUBSCRIBEWebsocket Connections

受け取ったPUSH通知JSONを元に画面の表示を更新

13年8月4日日曜日

Page 17: PHP meets NodeJS

どうですか?そんなに複雑な構成では無いとおもいます

ポイントは以下の3つ

ユーザーからのデータ送信はAjaxので処理する

Redis経由でPHPがNodeJSに、一方通行でJSONを送る

NodeはPHPからのJSONを元にWebsocketでデータを送信する

13年8月4日日曜日

Page 18: PHP meets NodeJS

なんでAjax?

コレ以上Nodeに複雑な処理持たせたくないから

PHP側だけで処理できる事はPHPだけでやった方が楽ですよね

13年8月4日日曜日

Page 19: PHP meets NodeJS

Redisのpub/sub?

これもNode側の実装が楽だから

HTTPリクエスト処理するための何やかんや用意しなくてOK

JSONかわいいよJSON

13年8月4日日曜日

Page 20: PHP meets NodeJS

Nodeが送信?

Nodeは決まったフォーマットのJSONに従ってJSONを配信するだけ

つまり、かなり定型的な処理しか行わない

つまり、Nodeの実装が楽っ☆

13年8月4日日曜日

Page 21: PHP meets NodeJS

つまり

いかにNodeを触らなくて良いかを考えた構成になってます

Node大好きっ子ですが、メインがPHPなので複雑にしたくなかったのです

13年8月4日日曜日

Page 22: PHP meets NodeJS

PHP/Node間のJSON“target_user_ids” のWebsocketに対して “data” を送るだけですね

{ “target_user_ids”: [1,2,10,22], “data”: { “type”: “notice_message”, “message”: “コメントがありました”,

“datetime”: “2013-08-03 15:12:32” }}

←配信対象のユーザーIDリスト

←配信データ}13年8月4日日曜日

Page 23: PHP meets NodeJS

“target_user_ids”???

ユーザーIDはPHP側にしか持ってません

NodeJS側は会員認証も何も持ってないのだから

ユーザーID渡されてもどのWebsocketがどのユーザーIDか分からなくね?

13年8月4日日曜日

Page 24: PHP meets NodeJS

ユーザーIDをNodeと共有

というわけで、ここが肝なのですが、ユーザーIDをNode側に知らせる必要があります

方法は簡単、ユーザーIDを返すAPIをPHP側に用意するだけ!

ではイメージ図いってみましょう

13年8月4日日曜日

Page 25: PHP meets NodeJS

ユーザーID取得処理

13年8月4日日曜日

Page 26: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

13年8月4日日曜日

Page 27: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

2. HTML/JSを返す

13年8月4日日曜日

Page 28: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

13年8月4日日曜日

Page 29: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

13年8月4日日曜日

Page 30: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

4. Websocket接続確立

13年8月4日日曜日

Page 31: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

4. Websocket接続確立

13年8月4日日曜日

Page 32: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

Session Cookie受け取ったSession

Cookieを添えて

4. Websocket接続確立

13年8月4日日曜日

Page 33: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

Session Cookie受け取ったSession

Cookieを添えて

6.ユーザーIDを返す4. Websocket接続確立

13年8月4日日曜日

Page 34: PHP meets NodeJS

ユーザーID取得処理1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

Session Cookie受け取ったSession

Cookieを添えて

6.ユーザーIDを返す4. Websocket接続確立

7.WebsocketとユーザーIDを紐付ける

13年8月4日日曜日

Page 35: PHP meets NodeJS

ポイントは1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

Session Cookie受け取ったSession

Cookieを添えて

6.ユーザーIDを返す4. Websocket接続確立

7.WebsocketとユーザーIDを紐付ける

13年8月4日日曜日

Page 36: PHP meets NodeJS

ポイントは1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

Session Cookie受け取ったSession

Cookieを添えて

6.ユーザーIDを返す4. Websocket接続確立

7.WebsocketとユーザーIDを紐付ける

Websocketコネクション時のHandshakeの時に

PHP側のSessionCookieが送られる

13年8月4日日曜日

Page 37: PHP meets NodeJS

ポイントは1.ページを開く(GETリクエスト)

3. Websocketを繋ぐ(リクエスト)

2. HTML/JSを返す

Session Cookie

SessionCookieが同時に送られる

5.NodeからPHPにHTTPリクエスト

Session Cookie受け取ったSession

Cookieを添えて

6.ユーザーIDを返す4. Websocket接続確立

7.WebsocketとユーザーIDを紐付ける

SessionCookieを含めてPHPにリクエストつまり、PHP的にはユーザーからのリクエストと一緒

13年8月4日日曜日

Page 38: PHP meets NodeJS

Nodeがユーザーになりきれる

Node側がユーザーを偽装する事ができますね!

PHP側がリクエストユーザーの、ユーザーIDを返すAPIを用意すればOK

これで、WebsocketにPHP側のユーザーIDを紐付ける事ができます

13年8月4日日曜日

Page 39: PHP meets NodeJS

ユーザーID偽装のために

PHP側のSessionCookieをNode側に送信する必要があります

Cookieの送信ポリシー的に同じドメインである必要があります

なので、ポートは違っていいですが、NodeもPHPも同ドメインで運用してください

13年8月4日日曜日

Page 40: PHP meets NodeJS

というわけで

省エネでPHPからPUSH通知を送る事ができます

例としてPHPあげましたが、PerlでもRubyでも同じ事はできるはずです

13年8月4日日曜日

Page 41: PHP meets NodeJS

最後にこの資料作るきっかけになった投稿をくれた方々に感謝です

https://groups.google.com/forum/#!topic/nodejs_jp/gU2347-33PQ

簡単なサンプル(通知ではなくてチャットですが)も作りましたのでよろしければ

https://github.com/takyam-git/phpchat_example/

13年8月4日日曜日

Page 42: PHP meets NodeJS

ありがとうございました

ご連絡は @takyam までぜひぜひ~

ブログも見てね~

http://new.takyam.com/

13年8月4日日曜日