WebSocket.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. namespace Protocols;
  3. /**
  4. * WebSocket 协议解包和打包
  5. * @author walkor <walkor@workerman.net>
  6. */
  7. class WebSocket
  8. {
  9. /**
  10. * 检查包的完整性
  11. * @param unknown_type $buffer
  12. */
  13. public static function check($buffer)
  14. {
  15. // 数据长度
  16. $recv_len = strlen($buffer);
  17. // 长度不够
  18. if($recv_len < 6)
  19. {
  20. return 6-$recv_len;
  21. }
  22. // 握手阶段客户端发送HTTP协议
  23. if(0 === strpos($buffer, 'GET'))
  24. {
  25. // 判断\r\n\r\n边界
  26. if(strlen($buffer) - 4 === strpos($buffer, "\r\n\r\n"))
  27. {
  28. return 0;
  29. }
  30. return 1;
  31. }
  32. // 如果是flash的policy-file-request
  33. elseif(0 === strpos($buffer,'<polic'))
  34. {
  35. if('>' != $buffer[strlen($buffer) - 1])
  36. {
  37. return 1;
  38. }
  39. return 0;
  40. }
  41. // websocket二进制数据
  42. $data_len = ord($buffer[1]) & 127;
  43. $head_len = 6;
  44. if ($data_len === 126) {
  45. $pack = unpack('ntotal_len', substr($buffer, 2, 2));
  46. $data_len = $pack['total_len'];
  47. $head_len = 8;
  48. } else if ($data_len === 127) {
  49. $arr = unpack('N2', substr($buffer, 2, 8));
  50. $data_len = $arr[1]*4294967296 + $arr[2];
  51. $head_len = 14;
  52. }
  53. $remain_len = $head_len + $data_len - $recv_len;
  54. if($remain_len < 0)
  55. {
  56. return false;
  57. }
  58. return $remain_len;
  59. }
  60. /**
  61. * 打包
  62. * @param string $buffer
  63. */
  64. public static function encode($buffer)
  65. {
  66. $len = strlen($buffer);
  67. if($len<=125)
  68. {
  69. return "\x81".chr($len).$buffer;
  70. }
  71. else if($len<=65535)
  72. {
  73. return "\x81".chr(126).pack("n", $len).$buffer;
  74. }
  75. else
  76. {
  77. return "\x81".chr(127).pack("xxxxN", $len).$buffer;
  78. }
  79. }
  80. /**
  81. * 解包
  82. * @param string $buffer
  83. * @return string
  84. */
  85. public static function decode($buffer)
  86. {
  87. $len = $masks = $data = $decoded = null;
  88. $len = ord($buffer[1]) & 127;
  89. if ($len === 126) {
  90. $masks = substr($buffer, 4, 4);
  91. $data = substr($buffer, 8);
  92. } else if ($len === 127) {
  93. $masks = substr($buffer, 10, 4);
  94. $data = substr($buffer, 14);
  95. } else {
  96. $masks = substr($buffer, 2, 4);
  97. $data = substr($buffer, 6);
  98. }
  99. for ($index = 0; $index < strlen($data); $index++) {
  100. $decoded .= $data[$index] ^ $masks[$index % 4];
  101. }
  102. return $decoded;
  103. }
  104. /**
  105. * 是否是websocket断开的数据包
  106. * @param string $buffer
  107. */
  108. public static function isClosePacket($buffer)
  109. {
  110. $opcode = self::getOpcode($buffer);
  111. return $opcode == 8;
  112. }
  113. /**
  114. * 是否是websocket ping的数据包
  115. * @param string $buffer
  116. */
  117. public static function isPingPacket($buffer)
  118. {
  119. $opcode = self::getOpcode($buffer);
  120. return $opcode == 9;
  121. }
  122. /**
  123. * 是否是websocket pong的数据包
  124. * @param string $buffer
  125. */
  126. public static function isPongPacket($buffer)
  127. {
  128. $opcode = self::getOpcode($buffer);
  129. return $opcode == 0xa;
  130. }
  131. /**
  132. * 获取wbsocket opcode
  133. * @param string $buffer
  134. */
  135. public static function getOpcode($buffer)
  136. {
  137. return ord($buffer[0]) & 0xf;
  138. }
  139. }