PacketHandler.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <?php
  2. namespace app\lib\wclient;
  3. /**
  4. * Created by PhpStorm.
  5. * User: marsnowxiao
  6. * Date: 2017/6/15
  7. * Time: 下午5:12
  8. */
  9. use app\lib\wclient\WebSocketFrame as WebSocketFrame;
  10. class PacketHandler
  11. {
  12. const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
  13. const TOKEN_LENGHT = 16;
  14. const maxPacketSize = 2000000;
  15. private $key = "";
  16. private static function generateToken($length)
  17. {
  18. $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}';
  19. $useChars = array();
  20. // select some random chars:
  21. for ($i = 0; $i < $length; $i++) {
  22. $useChars[] = $characters[mt_rand(0, strlen($characters) - 1)];
  23. }
  24. // Add numbers
  25. array_push($useChars, rand(0, 9), rand(0, 9), rand(0, 9));
  26. shuffle($useChars);
  27. $randomString = trim(implode('', $useChars));
  28. $randomString = substr($randomString, 0, self::TOKEN_LENGHT);
  29. return base64_encode($randomString);
  30. }
  31. public function buildHandShakeRequest($host, $port, $getParas)
  32. {
  33. $this->key = static::generateToken(self::TOKEN_LENGHT);
  34. return "GET /{$getParas} HTTP/1.1" . "\r\n" .
  35. "Origin: null" . "\r\n" .
  36. "Host: {$host}:{$port}" . "\r\n" .
  37. "Sec-WebSocket-Key: {$this->key}" . "\r\n" .
  38. "User-Agent: SwooleWebsocketClient" . "/0.1.4" . "\r\n" .
  39. "Upgrade: Websocket" . "\r\n" .
  40. "Connection: Upgrade" . "\r\n" .
  41. "Sec-WebSocket-Protocol: wamp" . "\r\n" .
  42. "Sec-WebSocket-Version: 13" . "\r\n" . "\r\n";
  43. }
  44. public function verifyUpgrade($packet)
  45. {
  46. $headers = explode("\r\n", $packet);
  47. unset($headers[0]);
  48. $headerInfo = [];
  49. foreach ($headers as $header) {
  50. $arr = explode(":", $header);
  51. if (count($arr) == 2) {
  52. list($field, $value) = $arr;
  53. $headerInfo[trim($field)] = trim($value);
  54. }
  55. }
  56. return (isset($headerInfo['Sec-WebSocket-Accept']) && $headerInfo['Sec-WebSocket-Accept'] == base64_encode(pack('H*', sha1($this->key . self::GUID))));
  57. }
  58. public function processDataFrame(&$packet)
  59. {
  60. if (strlen($packet) < 2)
  61. return null;
  62. $header = substr($packet, 0, 2);
  63. $index = 0;
  64. //fin:1 rsv1:1 rsv2:1 rsv3:1 opcode:4
  65. $handle = ord($packet[$index]);
  66. $finish = ($handle >> 7) & 0x1;
  67. $rsv1 = ($handle >> 6) & 0x1;
  68. $rsv2 = ($handle >> 5) & 0x1;
  69. $rsv3 = ($handle >> 4) & 0x1;
  70. $opcode = $handle & 0xf;
  71. $index++;
  72. //mask:1 length:7
  73. $handle = ord($packet[$index]);
  74. $mask = ($handle >> 7) & 0x1;
  75. //0-125
  76. $length = $handle & 0x7f;
  77. $index++;
  78. //126 short
  79. if ($length == 0x7e) {
  80. if (strlen($packet) < $index + 2)
  81. return null;
  82. //2 byte
  83. $handle = unpack('nl', substr($packet, $index, 2));
  84. $index += 2;
  85. $length = $handle['l'];
  86. } //127 int64
  87. elseif ($length > 0x7e) {
  88. if (strlen($packet) < $index + 8)
  89. return null;
  90. //8 byte
  91. $handle = unpack('Nh/Nl', substr($packet, $index, 8));
  92. $index += 8;
  93. $length = $handle['l'];
  94. if ($length > static::maxPacketSize) {
  95. throw new \Exception("frame length is too big.\n");
  96. }
  97. }
  98. //mask-key: int32
  99. if ($mask) {
  100. if (strlen($packet) < $index + 4)
  101. return null;
  102. $mask = array_map('ord', str_split(substr($packet, $index, 4)));
  103. $index += 4;
  104. }
  105. if (strlen($packet) < $index + $length)
  106. return null;
  107. $data = substr($packet, $index, $length);
  108. $index += $length;
  109. $packet = substr($packet, $index);
  110. $frame = new WebSocketFrame;
  111. $frame->finish = $finish;
  112. $frame->opcode = $opcode;
  113. $frame->data = $data;
  114. return $frame;
  115. }
  116. }