WebsocketParser.Class.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: phperstar
  5. * Date: 2020/11/6
  6. * Time: 10:28 AM
  7. */
  8. namespace Mall\Framework\Swoole\WebsocketClient;
  9. class WebsocketParser
  10. {
  11. public $maxFrameSize = 2000000;
  12. protected $buffer = '';
  13. /**
  14. * @var WebSocketFrame
  15. */
  16. protected $frame = null;
  17. const ERR_TOO_LONG = 10001;
  18. /**
  19. * 压入解析队列
  20. * @param $data
  21. */
  22. function push($data)
  23. {
  24. $this->buffer .= $data;
  25. }
  26. /**
  27. * 弹出frame
  28. * @return bool|WebSocketFrame
  29. * @throws \Exception
  30. */
  31. function pop()
  32. {
  33. //当前有等待的frame
  34. if ($this->frame)
  35. {
  36. if (strlen($this->buffer) >= $this->frame->length)
  37. {
  38. //分包
  39. $this->frame->data = substr($this->buffer, 0, $this->frame->length);
  40. self::unMask($this->frame);
  41. $frame = $this->frame;
  42. //进入新的frame解析流程
  43. $this->frame = null;
  44. $this->buffer = substr($this->buffer, $frame->length);
  45. return $frame;
  46. }
  47. else
  48. {
  49. return false;
  50. }
  51. }
  52. $buffer = &$this->buffer;
  53. if (strlen($buffer) < 2)
  54. {
  55. return false;
  56. }
  57. $frame = new WebSocketFrame;
  58. $data_offset = 0;
  59. //fin:1 rsv1:1 rsv2:1 rsv3:1 opcode:4
  60. $handle = ord($buffer[$data_offset]);
  61. $frame->finish = ($handle >> 7) & 0x1;
  62. $frame->rsv1 = ($handle >> 6) & 0x1;
  63. $frame->rsv2 = ($handle >> 5) & 0x1;
  64. $frame->rsv3 = ($handle >> 4) & 0x1;
  65. $frame->opcode = $handle & 0xf;
  66. $data_offset++;
  67. //mask:1 length:7
  68. $handle = ord($buffer[$data_offset]);
  69. $frame->mask = ($handle >> 7) & 0x1;
  70. //0-125
  71. $frame->length = $handle & 0x7f;
  72. $length = &$frame->length;
  73. $data_offset++;
  74. //126 short
  75. if ($length == 0x7e)
  76. {
  77. //2 byte
  78. $handle = unpack('nl', substr($buffer, $data_offset, 2));
  79. $data_offset += 2;
  80. $length = $handle['l'];
  81. }
  82. //127 int64
  83. elseif ($length > 0x7e)
  84. {
  85. //8 byte
  86. $handle = unpack('Nh/Nl', substr($buffer, $data_offset, 8));
  87. $data_offset += 8;
  88. $length = $handle['l'];
  89. //超过最大允许的长度了,恶意的连接,需要关闭
  90. if ($length > $this->maxFrameSize)
  91. {
  92. throw new \Exception("frame length is too big.", self::ERR_TOO_LONG);
  93. }
  94. }
  95. //mask-key: int32
  96. if ($frame->mask)
  97. {
  98. $frame->mask = array_map('ord', str_split(substr($buffer, $data_offset, 4)));
  99. $data_offset += 4;
  100. }
  101. //把头去掉
  102. $buffer = substr($buffer, $data_offset);
  103. //数据长度为0的帧
  104. if (0 === $length)
  105. {
  106. $frame->finish = true;
  107. $frame->data = '';
  108. return $frame;
  109. }
  110. //完整的一个数据帧
  111. if (strlen($buffer) >= $length)
  112. {
  113. $frame->finish = true;
  114. $frame->data = substr($buffer, 0, $length);
  115. //清理buffer
  116. $buffer = substr($buffer, $length);
  117. self::unMask($frame);
  118. return $frame;
  119. }
  120. //需要继续等待数据
  121. else
  122. {
  123. $frame->finish = false;
  124. $this->frame = $frame;
  125. return false;
  126. }
  127. }
  128. /**
  129. * @param $frame WebSocketFrame
  130. */
  131. static function unMask($frame)
  132. {
  133. if ($frame->mask)
  134. {
  135. $maskC = 0;
  136. $data = $frame->data;
  137. for ($j = 0, $_length = $frame->length; $j < $_length; ++$j)
  138. {
  139. $data[$j] = chr(ord($frame->data[$j]) ^ $frame->mask[$maskC]);
  140. $maskC = ($maskC + 1) % 4;
  141. }
  142. $frame->data = $data;
  143. }
  144. }
  145. }
  146. class WebSocketFrame
  147. {
  148. public $finish = false;
  149. public $opcode;
  150. public $data;
  151. public $length;
  152. public $rsv1;
  153. public $rsv2;
  154. public $rsv3;
  155. public $mask;
  156. }