WebSocket.php 3.4 KB

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