SlideShare a Scribd company logo
PHP meets NodeJS
PHPに簡単にPUSH機能を組み込む
13年8月4日日曜日
まずは自己紹介
簡単に自己紹介
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日日曜日
PHPで通知機能
PHPでFacebookの通知機能のようなものを実装したい事ありますよね?
画面遷移を挟まずにユーザーへの通知が表示される機能です。
私はPUSH通知と呼んでるのですがこれをPHPで作りたいとおもいます
13年8月4日日曜日
通知機能を作るには
サーバー側からPUSHする必要がありますが、いくつかの手法があります
ポーリング(実際はPUSHでは無い)
Commet
Websocket
それぞれメリット・デメリットがあります
今回はWebsocketを使ってみたいと思います
13年8月4日日曜日
Websocketを使う
PHP単体でもWebsocketを扱えるようなライブラリはあります
とはいえWAFに組み込むのは難しいので今回はNodeJSを使います
Websocketの部分はNodeJSに全ておまかせです!
13年8月4日日曜日
NodeJS分かんねぇよ
そんな硬派なPHPerも大丈夫!
NodeJSは全部で100行くらいなので、コピペすりゃOK
一度作ればNodeJSメンテナンス不要なイケてるシステムです
13年8月4日日曜日
今回のシステムの前提
今回のPUSHを実現するための前提条件が2つあります
NodeJSがPHPと同ドメイン(ポート違いOK)で運用できる
Redisが使える
これだけ!
13年8月4日日曜日
まずはイメージをつかむ
文字で説明するのも大変なので簡単なイメージ図をご紹介
まず最終的な完成形のイメージを掴んでください
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
投稿に対してのコメントを
AjaxでPHPにPOSTリクエスト
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
コメントのDBへの保存処理などを実施
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
コメントが来たよ通知JSONを
RedisにPUBLISH
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
SUBSCRIBEしてるNodeJSが
通知JSONを受信
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
通知JSONから通知対象のユーザーを選択する
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
通知対象のユーザーのWebsocketを使って
PUSH通知(JSON)を送信!
13年8月4日日曜日
最終的な構成
HTTP POST
Redis PUBLISH
Redis SUBSCRIBE
Websocket Connections
受け取ったPUSH通知JSONを元に
画面の表示を更新
13年8月4日日曜日
どうですか?
そんなに複雑な構成では無いとおもいます
ポイントは以下の3つ
ユーザーからのデータ送信はAjaxので処理する
Redis経由でPHPがNodeJSに、一方通行でJSONを送る
NodeはPHPからのJSONを元にWebsocketでデータを送信する
13年8月4日日曜日
なんでAjax?
コレ以上Nodeに複雑な処理持たせたくないから
PHP側だけで処理できる事はPHPだけでやった方が楽ですよね
13年8月4日日曜日
Redisのpub/sub?
これもNode側の実装が楽だから
HTTPリクエスト処理するための何やかんや用意しなくてOK
JSONかわいいよJSON
13年8月4日日曜日
Nodeが送信?
Nodeは決まったフォーマットのJSONに従ってJSONを配信するだけ
つまり、かなり定型的な処理しか行わない
つまり、Nodeの実装が楽っ☆
13年8月4日日曜日
つまり
いかにNodeを触らなくて良いかを考えた構成になってます
Node大好きっ子ですが、メインがPHPなので複雑にしたくなかったのです
13年8月4日日曜日
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日日曜日
target_user_ids ???
ユーザーIDはPHP側にしか持ってません
NodeJS側は会員認証も何も持ってないのだから
ユーザーID渡されてもどのWebsocketがどのユーザーIDか分からなくね?
13年8月4日日曜日
ユーザーIDをNodeと共有
というわけで、ここが肝なのですが、ユーザーIDをNode側に知らせる必要があります
方法は簡単、ユーザーIDを返すAPIをPHP側に用意するだけ!
ではイメージ図いってみましょう
13年8月4日日曜日
ユーザーID取得処理
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
2. HTML/JSを返す
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
3. Websocketを繋ぐ(リクエスト)
2. HTML/JSを返す
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
3. Websocketを繋ぐ(リクエスト)
2. HTML/JSを返す
Session Cookie
SessionCookieが同時に送られる
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
3. Websocketを繋ぐ(リクエスト)
2. HTML/JSを返す
Session Cookie
SessionCookieが同時に送られる
4. Websocket接続確立
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
3. Websocketを繋ぐ(リクエスト)
2. HTML/JSを返す
Session Cookie
SessionCookieが同時に送られる
5.NodeからPHPにHTTPリクエスト
4. Websocket接続確立
13年8月4日日曜日
ユーザーID取得処理
1.ページを開く(GETリクエスト)
3. Websocketを繋ぐ(リクエスト)
2. HTML/JSを返す
Session Cookie
SessionCookieが同時に送られる
5.NodeからPHPにHTTPリクエスト
Session Cookie
受け取ったSession
Cookieを添えて
4. Websocket接続確立
13年8月4日日曜日
ユーザー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日日曜日
ユーザー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日日曜日
ポイントは
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日日曜日
ポイントは
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日日曜日
ポイントは
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日日曜日
Nodeがユーザーになりきれる
Node側がユーザーを偽装する事ができますね!
PHP側がリクエストユーザーの、ユーザーIDを返すAPIを用意すればOK
これで、WebsocketにPHP側のユーザーIDを紐付ける事ができます
13年8月4日日曜日
ユーザーID偽装のために
PHP側のSessionCookieをNode側に送信する必要があります
Cookieの送信ポリシー的に同じドメインである必要があります
なので、ポートは違っていいですが、NodeもPHPも同ドメインで運用してください
13年8月4日日曜日
というわけで
省エネでPHPからPUSH通知を送る事ができます
例としてPHPあげましたが、PerlでもRubyでも同じ事はできるはずです
13年8月4日日曜日
最後に
この資料作るきっかけになった投稿をくれた方々に感謝です
https://groups.google.com/forum/#!topic/nodejs_jp/gU2347-33PQ
簡単なサンプル(通知ではなくてチャットですが)も作りましたのでよろしければ
https://github.com/takyam-git/phpchat_example/
13年8月4日日曜日
ありがとうございました
ご連絡は @takyam までぜひぜひ∼
ブログも見てね∼
http://new.takyam.com/
13年8月4日日曜日

More Related Content

PHP meets NodeJS