2007/10/03 カテゴリ : PHP  Flash  Tech 

PHPとFlashでチャット

こんにちは、中川です。
PHPでチャットサーバが作れるか試してみました。

結論からいいますと、簡単なものでしたら、「PHPlet」というライブラリを使えば、
マルチプロセスで動作するものが、意外にあっさり作ることができました。

まず、【PHPlet】から、ライブラリをダウンロードして、「ext」フォルダのみを配置します。
そして、サーバ側プログラムは、以下のようになっています。
(※PEAR::Net_Serverを使えば実装できるみたいです。)

[chatd.php]
  1. <?php
  2. require_once 'ext/Server.php';
  3. require_once 'ext/Server/Handler.php';
  4.  
  5. class Net_Server_Handler_Talkback extends Net_Server_Handler {
  6.     var $clientStatus = array();
  7.     
  8.     function onConnect($clientId = 0)
  9.     {
  10.         $this->setClientStatus($clientId);
  11.         $this->_server->sendData($clientId, "Hello. [quit] to exit\r\n");
  12.         $this->_server->broadcastDataToNeighbors($clientId, "\r\nclient {$clientId} entry!!\r\n");
  13.     }
  14.     
  15.     function onReceiveData($clientId = 0, $data = '')
  16.     {
  17.         $client = $this->getClientStatus($clientId);
  18.         $data = trim($data);
  19.         if($data=='') return;
  20.         switch($data){
  21.             case "quit":
  22.                 $this->_server->closeConnection($clientId);
  23.                 break;
  24.             default:
  25.                 $data = htmlspecialchars($data);
  26.                 $res = "USER: " . $clientId . " : " . $data . "\r\n";
  27.                 $this->_server->broadcastData($res);
  28.                 break;
  29.         }
  30.     }
  31.  
  32.     function onIdle(){
  33.         $this->_server->sendData(0,  "Please say something!\r\n");
  34.     }
  35.  
  36.     function onClose($clientId = 0){
  37.         $this->_server->sendData($clientId, "Bye!\r\n");
  38.     }
  39.  
  40.     function setClientStatus($clientId) {
  41.         if(isset($this->clientStatus[$clientId])) return;
  42.         $this->clientStatus[$clientId] = new clientStatus();
  43.     }
  44.     
  45.     function getClientStatus($clientId) {
  46.         return $this->clientStatus[$clientId];
  47.     }
  48. }
  49.  
  50. class clientStatus {
  51.     var $name;
  52.     function __construct() {
  53.       
  54.     }
  55. }
  56.  
  57. $server = &Net_Server::create('Multiprocess', "192.168.1.10", 8080);
  58. $server->setMaxClients(1);
  59. $server->_debug = false;
  60. $handler = &new Net_Server_Handler_Talkback();
  61. $server->setCallbackObject($handler);
  62. $server->start();
  63. ?>

上記のソースでは、接続しているユーザ全てにデータを送信します。

次にクライアント側ですが、AS3の勉強もかねてFlashを使っています。

[clientsample.as]
  1. package  {  
  2.   import flash.display.*;
  3.   import flash.events.*;
  4.   import flash.net.*;
  5.   import flash.ui.*;
  6.   import flash.utils.*;
  7.   import flash.text.*
  8.   
  9.   public class ClientSample extends Sprite {
  10.     
  11.     private var txt:TextField;
  12.     private var socket:Socket;
  13.     private var sendText:TextField;
  14.         
  15.     public function ClientSample() {
  16.       txt = addTextField(10, 50, 300, 300);
  17.       this.addChild(txt);
  18.       
  19.       sendText = addTextField(10,10,300,20);
  20.       sendText.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHander);
  21.       this.addChild(sendText);
  22.       
  23.       socket = new Socket("192.168.1.10", 8080);
  24.       socket.addEventListener(Event.CONNECT, connectHandler);
  25.       socket.addEventListener(Event.CLOSE, closeHandler);
  26.       socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
  27.     }
  28.     private function addTextField(x:int,y:int,w:uint,h:uint):TextField {
  29.       var textField:TextField=new TextField();
  30.       addChild(textField);
  31.       textField.x=x;
  32.       textField.y=y;
  33.       textField.width=w;
  34.       textField.height=h;
  35.       textField.text="";
  36.       textField.selectable=true;
  37.       textField.border=true;
  38.       textField.type=TextFieldType.INPUT;
  39.       return textField;
  40.     }
  41.     
  42.     private function keyDownHander(evt:KeyboardEvent):void {
  43.       if(!socket.connected) return;
  44.       if (evt.keyCode == Keyboard.ENTER) {
  45.         socket.writeUTFBytes(sendText.text + "\n");
  46.         socket.flush();
  47.         sendText.text = "";
  48.       }
  49.     }
  50.     
  51.     private function connectHandler(evt:Event):void {
  52.       txt.text = "接続開始";
  53.     }
  54.     
  55.     private function closeHandler(evt:Event):void {
  56.       txt.text = "接続終了";
  57.     }
  58.     
  59.     private function socketDataHandler(evt:ProgressEvent):void {
  60.       var data:String=socket.readUTFBytes(socket.bytesAvailable);
  61.             txt.text=data+"\n"+txt.text;
  62.     }
  63.   
  64.   }
  65. }


最後に、Flash表示用のHTMLをひとつ作成します。

[index.html]
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
  3. <head>
  4. <title>php-chat-sample</title>
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6. </head>
  7. <body>
  8. <h1>php-chat-sample</h1>
  9. <object 
  10.  id="clientsample" 
  11.  classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" 
  12.  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" 
  13. > 
  14.   <param name="movie"   value="clientsample.swf" />
  15.   <param name="quality" value="high" />
  16.   <param name="width" value="500" />
  17.   <param name="height" value="500" />
  18.   <param name="allowScriptAccess" value="always" />
  19.   <embed 
  20.    name="clientsample" 
  21.    src="clientsample.swf" 
  22.    width="500"
  23.    height="500"
  24.    FlashVars="" 
  25.    quality="high" 
  26.    type="application/x-shockwave-flash" 
  27.    pluginspage="http://www.macromedia.com/go/getflashplayer" 
  28.    allowScriptAccess="always" 
  29.   />
  30. </object>
  31. </body>
  32. </html>

IPやポートはとりあえず、スクリプト内で指定していますので、
あとは、サーバ側でchatd.phpを実行して、index.htmlにアクセスします。


案外簡単に実装はできました。(スクリプトはやっつけっぽいですが・・・)
本番投入には問題がいろいろあるとは思いますが、PHPでもやろうと思えばできるものですね。

※今回の記事のスクリプトは以下のサイトを非常に参考にさせていただきました。
・サーバ側 
  ・【JavaScriptとFlash(socketjsのSocketConnect)でリアルタイムチャットを作ってみる】
  ・【PEAR::Net_Serverでサーバデーモンを作ろう - PHPプロ!TIPS+】
・クライアント側
  ・【ActionScript 3.0メモ(ソケットの使用) 】

コメント

    • ふもも
    • 2007年10月04日 12:59
    • amfphp使ったほうが簡単じゃね?
      FlexでAMF3できるしActionscriptのコードもシンプルになるしね。
    • 中川
    • 2007年10月04日 13:36
    • 今度試してみます。ありがとうございます。
    • 通りすがり
    • 2011年05月16日 23:34
    • 参考になりました。ありがとうございます。
      amfphpで同じ動作となるとタイマーの仕込みなどが面倒なのでおそらくチャットという目的であればソケットでの通信確立がベストだと思います。
      えらい古い記事にレスつけてしまってますが、ともかく参考になりました。

コメントフォーム

認証
captcha_key
 
 

トラックバックURI

最近の記事

アシアルPHP書籍情報