Websocket.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <?php
  2. namespace Workerman\Protocols;
  3. /**
  4. * WebSocket 协议服务端解包和打包
  5. * @author walkor <walkor@workerman.net>
  6. */
  7. use Workerman\Connection\ConnectionInterface;
  8. class Websocket implements \Workerman\Protocols\ProtocolInterface
  9. {
  10. /**
  11. * 检查包的完整性
  12. * @param string $buffer
  13. */
  14. public static function input($buffer, ConnectionInterface $connection)
  15. {
  16. // 数据长度
  17. $recv_len = strlen($buffer);
  18. // 长度不够
  19. if($recv_len < 6)
  20. {
  21. return 0;
  22. }
  23. // 还没有握手
  24. if(empty($connection->handshake))
  25. {
  26. // 握手阶段客户端发送HTTP协议
  27. if(0 === strpos($buffer, 'GET'))
  28. {
  29. // 判断\r\n\r\n边界
  30. $heder_end_pos = strpos($buffer, "\r\n\r\n");
  31. if(!$heder_end_pos)
  32. {
  33. return 0;
  34. }
  35. // 解析Sec-WebSocket-Key
  36. $Sec_WebSocket_Key = '';
  37. if(preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/", $buffer, $match))
  38. {
  39. $Sec_WebSocket_Key = $match[1];
  40. }
  41. $new_key = base64_encode(sha1($Sec_WebSocket_Key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
  42. // 握手返回的数据
  43. $new_message = "HTTP/1.1 101 Switching Protocols\r\n";
  44. $new_message .= "Upgrade: websocket\r\n";
  45. $new_message .= "Sec-WebSocket-Version: 13\r\n";
  46. $new_message .= "Connection: Upgrade\r\n";
  47. $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
  48. $connection->handshake = true;
  49. $connection->consumeRecvBuffer(strlen($buffer));
  50. $connection->send($new_message, true);
  51. return 0;
  52. }
  53. // 如果是flash的policy-file-request
  54. elseif(0 === strpos($buffer,'<polic'))
  55. {
  56. if('>' != $buffer[strlen($buffer) - 1])
  57. {
  58. return 0;
  59. }
  60. $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>'."\0";
  61. $connection->send($policy_xml, true);
  62. $connection->consumeRecvBuffer(strlen($buffer));
  63. return 0;
  64. }
  65. // error
  66. $connection->close();
  67. return 0;
  68. }
  69. // close package
  70. if(ord($buffer[0]) & 0xf == 8)
  71. {
  72. $connection->close();
  73. return 0;
  74. }
  75. // websocket二进制数据
  76. $data_len = ord($buffer[1]) & 127;
  77. $head_len = 6;
  78. if ($data_len === 126) {
  79. $pack = unpack('ntotal_len', substr($buffer, 2, 2));
  80. $data_len = $pack['total_len'];
  81. $head_len = 8;
  82. } else if ($data_len === 127) {
  83. $arr = unpack('N2', substr($buffer, 2, 8));
  84. $data_len = $arr[1]*4294967296 + $arr[2];
  85. $head_len = 14;
  86. }
  87. return $head_len + $data_len;
  88. }
  89. /**
  90. * 打包
  91. * @param string $buffer
  92. */
  93. public static function encode($buffer, ConnectionInterface $connection)
  94. {
  95. $len = strlen($buffer);
  96. if($len<=125)
  97. {
  98. return "\x81".chr($len).$buffer;
  99. }
  100. else if($len<=65535)
  101. {
  102. return "\x81".chr(126).pack("n", $len).$buffer;
  103. }
  104. else
  105. {
  106. return "\x81".chr(127).pack("xxxxN", $len).$buffer;
  107. }
  108. }
  109. /**
  110. * 解包
  111. * @param string $buffer
  112. * @return string
  113. */
  114. public static function decode($buffer, ConnectionInterface $connection)
  115. {
  116. $len = $masks = $data = $decoded = null;
  117. $len = ord($buffer[1]) & 127;
  118. if ($len === 126) {
  119. $masks = substr($buffer, 4, 4);
  120. $data = substr($buffer, 8);
  121. } else if ($len === 127) {
  122. $masks = substr($buffer, 10, 4);
  123. $data = substr($buffer, 14);
  124. } else {
  125. $masks = substr($buffer, 2, 4);
  126. $data = substr($buffer, 6);
  127. }
  128. for ($index = 0; $index < strlen($data); $index++) {
  129. $decoded .= $data[$index] ^ $masks[$index % 4];
  130. }
  131. return $decoded;
  132. }
  133. }