PageRenderTime 44ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/websocket.class.php

https://github.com/aabhasgarg/ariel
PHP | 162 lines | 129 code | 17 blank | 16 comment | 17 complexity | 348028ed1a412f9e77c34c3c172ef4c5 MD5 | raw file
  1. <?php
  2. // Usage: $master=new WebSocket("localhost",12345);
  3. class WebSocket{
  4. var $master;
  5. var $sockets = array();
  6. var $users = array();
  7. var $debug = false;
  8. function __construct($address,$port){
  9. error_reporting(E_ALL);
  10. set_time_limit(0);
  11. ob_implicit_flush();
  12. $this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
  13. socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
  14. socket_bind($this->master, $address, $port) or die("socket_bind() failed");
  15. socket_listen($this->master,20) or die("socket_listen() failed");
  16. $this->sockets[] = $this->master;
  17. $this->say("Server Started : ".date('Y-m-d H:i:s'));
  18. $this->say("Listening on : ".$address." port ".$port);
  19. $this->say("Master socket : ".$this->master."\n");
  20. while(true){
  21. $changed = $this->sockets;
  22. socket_select($changed,$write=NULL,$except=NULL,NULL);
  23. foreach($changed as $socket){
  24. if($socket==$this->master){
  25. $client=socket_accept($this->master);
  26. if($client<0){ $this->log("socket_accept() failed"); continue; }
  27. else{ $this->connect($client); }
  28. }
  29. else{
  30. $bytes = @socket_recv($socket,$buffer,2048,0);
  31. if($bytes==0){ $this->disconnect($socket); }
  32. else{
  33. $user = $this->getuserbysocket($socket);
  34. if(!$user->handshake){ $this->dohandshake($user,$buffer); }
  35. else{ $this->process($user,$this->unwrap($buffer)); }
  36. }
  37. }
  38. }
  39. }
  40. }
  41. function process($user,$msg){
  42. /* Extend and modify this method to suit your needs */
  43. /* Basic usage is to echo incoming messages back to client */
  44. $this->send($user->socket,$msg);
  45. }
  46. function send($client,$msg){
  47. $this->say("> ".$msg);
  48. $msg = $this->wrap($msg);
  49. socket_write($client,$msg,strlen($msg));
  50. }
  51. function connect($socket){
  52. $user = new User();
  53. $user->id = uniqid();
  54. $user->socket = $socket;
  55. array_push($this->users,$user);
  56. array_push($this->sockets,$socket);
  57. $this->log($socket." CONNECTED!");
  58. $this->log(date("d/n/Y ")."at ".date("H:i:s T"));
  59. $this->say($user->id. "connected");
  60. }
  61. function disconnect($socket){
  62. $found=null;
  63. $n=count($this->users);
  64. for($i=0;$i<$n;$i++){
  65. if($this->users[$i]->socket==$socket){ $found=$i; break; }
  66. }
  67. if(!is_null($found)){ array_splice($this->users,$found,1); }
  68. $index=array_search($socket,$this->sockets);
  69. socket_close($socket);
  70. $this->log($socket." DISCONNECTED!");
  71. if($index>=0){ array_splice($this->sockets,$index,1); }
  72. }
  73. function dohandshake($user,$buffer){
  74. $this->log("\nRequesting handshake...");
  75. $this->log($buffer);
  76. list($resource,$host,$origin,$key1,$key2,$l8b) = $this->getheaders($buffer);
  77. $this->log("Handshaking...");
  78. //$port = explode(":",$host);
  79. //$port = $port[1];
  80. //$this->log($origin."\r\n".$host);
  81. $upgrade = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" .
  82. "Upgrade: WebSocket\r\n" .
  83. "Connection: Upgrade\r\n" .
  84. //"WebSocket-Origin: " . $origin . "\r\n" .
  85. //"WebSocket-Location: ws://" . $host . $resource . "\r\n" .
  86. "Sec-WebSocket-Origin: " . $origin . "\r\n" .
  87. "Sec-WebSocket-Location: ws://" . $host . $resource . "\r\n" .
  88. //"Sec-WebSocket-Protocol: icbmgame\r\n" . //Client doesn't send this
  89. "\r\n" .
  90. $this->calcKey($key1,$key2,$l8b) . "\r\n";// .
  91. //"\r\n";
  92. socket_write($user->socket,$upgrade.chr(0),strlen($upgrade.chr(0)));
  93. $user->handshake=true;
  94. $this->log($upgrade);
  95. $this->log("Done handshaking...");
  96. return true;
  97. }
  98. function calcKey($key1,$key2,$l8b){
  99. //Get the numbers
  100. preg_match_all('/([\d]+)/', $key1, $key1_num);
  101. preg_match_all('/([\d]+)/', $key2, $key2_num);
  102. //Number crunching [/bad pun]
  103. $this->log("Key1: " . $key1_num = implode($key1_num[0]) );
  104. $this->log("Key2: " . $key2_num = implode($key2_num[0]) );
  105. //Count spaces
  106. preg_match_all('/([ ]+)/', $key1, $key1_spc);
  107. preg_match_all('/([ ]+)/', $key2, $key2_spc);
  108. //How many spaces did it find?
  109. $this->log("Key1 Spaces: " . $key1_spc = strlen(implode($key1_spc[0])) );
  110. $this->log("Key2 Spaces: " . $key2_spc = strlen(implode($key2_spc[0])) );
  111. if($key1_spc==0|$key2_spc==0){ $this->log("Invalid key");return; }
  112. //Some math
  113. $key1_sec = pack("N",$key1_num / $key1_spc); //Get the 32bit secret key, minus the other thing
  114. $key2_sec = pack("N",$key2_num / $key2_spc);
  115. //This needs checking, I'm not completely sure it should be a binary string
  116. return md5($key1_sec.$key2_sec.$l8b,1); //The result, I think
  117. }
  118. function getheaders($req){
  119. $r=$h=$o=null;
  120. if(preg_match("/GET (.*) HTTP/" ,$req,$match)){ $r=$match[1]; }
  121. if(preg_match("/Host: (.*)\r\n/" ,$req,$match)){ $h=$match[1]; }
  122. if(preg_match("/Origin: (.*)\r\n/" ,$req,$match)){ $o=$match[1]; }
  123. if(preg_match("/Sec-WebSocket-Key1: (.*)\r\n/",$req,$match)){ $this->log("Sec Key1: ".$sk1=$match[1]); }
  124. if(preg_match("/Sec-WebSocket-Key2: (.*)\r\n/",$req,$match)){ $this->log("Sec Key2: ".$sk2=$match[1]); }
  125. if($match=substr($req,-8)) { $this->log("Last 8 bytes: ".$l8b=$match); }
  126. return array($r,$h,$o,$sk1,$sk2,$l8b);
  127. }
  128. function getuserbysocket($socket){
  129. $found=null;
  130. foreach($this->users as $user){
  131. if($user->socket==$socket){ $found=$user; break; }
  132. }
  133. return $found;
  134. }
  135. function say($msg=""){ echo $msg."\n"; }
  136. function log($msg=""){ if($this->debug){ echo $msg."\n"; } }
  137. function wrap($msg=""){ return chr(0).$msg.chr(255); }
  138. function unwrap($msg=""){ return substr($msg,1,strlen($msg)-2); }
  139. }
  140. class User{
  141. var $id;
  142. var $socket;
  143. var $handshake;
  144. }
  145. ?>