怎么用PHP实现wscat
发表于:2025-02-06 作者:千家信息网编辑
千家信息网最后更新 2025年02月06日,本篇内容介绍了"怎么用PHP实现wscat"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!使用php
千家信息网最后更新 2025年02月06日怎么用PHP实现wscat
本篇内容介绍了"怎么用PHP实现wscat"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
使用
php websocket-client.php -c we://localhost:10001/hello
源码https://github.com/dreamsxin/cphalcon7/blob/master/examples/async/websocket-client.php
0, 'text' => 1, 'binary' => 2, 'close' => 8, 'ping' => 9, 'pong' => 10, ); public function __construct($url, $callback = NULL, array $options = NULL) { $this->url = $url; $this->options = $options; $url_parts = parse_url($this->url); if ($url_parts) { $this->scheme = \Phalcon\Arr::get($url_parts, 'scheme'); $this->host = \Phalcon\Arr::get($url_parts, 'host'); $this->user = isset($url_parts['user']) ? $url_parts['user'] : ''; $this->pass = isset($url_parts['pass']) ? $url_parts['pass'] : ''; $this->port = isset($url_parts['port']) ? $url_parts['port'] : ($this->scheme === 'wss' ? 443 : 80); $this->path = isset($url_parts['path']) ? $url_parts['path'] : '/'; $this->query = isset($url_parts['query']) ? $url_parts['query'] : ''; $this->fragment = isset($url_parts['fragment']) ? $url_parts['fragment'] : ''; } if (!in_array($this->scheme, array('ws', 'wss'))) { throw new \Exception( "Url should have scheme ws or wss, not '$scheme' from URI '$this->socket_uri' ." ); } $this->fullpath = $this->path; if (!empty($this->query)) { $this->fullpath .= '?' . $this->query; } if (!empty($this->fragment)) { $this->fullpath .= '#' . $this->fragment; } if ($callback && \is_callable($callback)) { $callback = Closure::bind($callback, $this); } $this->stdin = Phalcon\Async\Stream\ReadablePipe::getStdin(); $this->stdout = Phalcon\Async\Stream\WritablePipe::getStdout(); $this->callback = $callback; } public function __destruct() { if ($this->socket && !$this->socket->is_closing) { $this->socket->close(); $this->socket = null; } } /** * Generate a random string for WebSocket key. * @return string Random string */ protected static function generateKey() { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"$&/()=[]{}0123456789'; $key = ''; $chars_length = strlen($chars); for ($i = 0; $i < 16; $i++) { $key .= $chars[mt_rand(0, $chars_length-1)]; } return base64_encode($key); } public function sendHeader() { // Generate the WebSocket key. $this->socket->key = self::generateKey(); // Default headers (using lowercase for simpler array_merge below). $headers = array( 'Host' => $this->host . ":" . $this->port, 'User-Agent' => 'websocket-client-php', 'Connection' => 'Upgrade', 'Upgrade' => 'websocket', 'Sec-WebSocket-Key' => $this->socket->key, 'Sec-Websocket-Version' => '13', ); // Handle basic authentication. if ($this->user || $this->pass) { $headers['authorization'] = 'Basic ' . base64_encode($this->user . ':' . $this->pass) . "\r\n"; } // Deprecated way of adding origin (use headers instead). if (isset($this->options['origin'])) { $headers['origin'] = $this->options['origin']; } // Add and override with headers from options. if (isset($this->options['headers'])) { $headers = array_merge($headers, array_change_key_case($this->options['headers'])); } $header = "GET " . $this->fullpath . " HTTP/1.1\r\n"; $headers = array_map(function($key, $value) { return $key.': '.$value; }, array_keys($headers), $headers); $header .= implode("\r\n", $headers) . "\r\n\r\n"; // Send headers. $this->socket->write($header); return true; } public function connect($callback = NULL) { if ($callback && \is_callable($callback)) { $callback = Closure::bind($callback, $this); } $defer = new \Phalcon\Async\Deferred(); try { $tls = NULL; if ($this->scheme == 'wss') { $tls = new \Phalcon\Async\TlsClientEncryption(); $tls = $tls->withAllowSelfSigned(true); } $socket = \Phalcon\Async\Network\TcpSocket::connect($this->host, $this->port, $tls); $socket->is_closing = false; $socket->fragment_status = 0; $socket->fragment_length = 0; $socket->fragment_size = 4096; $socket->read_length = 0; $socket->huge_payload = ''; $socket->payload = ''; $socket->headers = NULL; $socket->isHandshake = false; $this->socket = $socket; $this->sendHeader(); // 接收握手数据 \Phalcon\Async\Task::async(function () use ($defer, $socket) { try { $buffer = ''; while (!$socket->isHandshake && null !== ($chunk = $socket->read())) { $buffer .= $chunk; $pos = strpos($buffer, "\r\n\r\n"); if ($pos) { if ($this->handShake($socket, $buffer)) { $socket->isHandshake = true; $buffer = substr($buffer, $pos+4); $defer->resolve('connected'); } } } $defer->resolve('connected'); } catch (\Throwable $e) { $defer->fail($e); } $socket->close(); $socket->is_closing = true; }); } catch (\Throwable $e) { self::err($e->getMessage()); exit; } $ws = $this; \Phalcon\Async\Task::await(Phalcon\Async\Deferred::transform($defer->awaitable(), function (?\Throwable $e, ?string $v = null) use ($ws, $callback) { if ($e) { self::err($e->getMessage()); return; } $ws->recv($ws->stdin); if ($callback && \is_callable($callback)) { $callback(); } })); } public function recv($stdin) { $socket = $this->socket; $callback = $this->callback; // 接收数据 \Phalcon\Async\Task::async(function () use ($socket, $callback, $stdin) { try { $buffer = ''; while (!$socket->is_closing && null !== ($chunk = $socket->read())) { $buffer .= $chunk; if ($this->process($socket, $buffer)) { $buffer = substr($buffer, $socket->read_length); if ($callback && \is_callable($callback)) { $callback($socket->payload); } $socket->fragment_status = 0; $socket->fragment_length = 0; $socket->read_length = 0; $socket->huge_payload = ''; $socket->payload = ''; } } } catch (\Throwable $e) { self::err($e->getMessage()); } $socket->close(); $socket->is_closing = true; echo PHP_EOL.\Phalcon\Cli\Color::success('disconnected'); $stdin->close(); }); } public function isClose() { return !$this->socket || $this->socket->is_closing; } public function send($data) { if ($this->isClose()) { self::err("No connection established or connection closed"); return false; } self::sendFragment($this->socket, $data); } public function handShake($socket, $buffer) { // Validate response. if (!preg_match('#Sec-WebSocket-Accept:(.*)$#mUi', $buffer, $matches)) { throw new \Exception('Connection failed: Server sent invalid upgrade response:'.PHP_EOL . $buffer); } $keyAccept = trim($matches[1]); $expectedResonse = base64_encode(pack('H*', sha1($this->socket->key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); if ($keyAccept !== $expectedResonse) { throw new \Exception('Server sent bad upgrade response.'); } $socket->isHandshake = true; return true; } static public function readFragment0($socket, $buffer) { if (strlen($buffer) < 2) { return false; } $data = substr($buffer, 0, 2); $socket->read_length = 2; // Is this the final fragment? // Bit 0 in byte 0 /// @todo Handle huge payloads with multiple fragments. $socket->final = (boolean) (ord($data[0]) & 1 << 7); // Should be unused, and must be false… // Bits 1, 2, & 3 $rsv1 = (boolean) (ord($data[0]) & 1 << 6); $rsv2 = (boolean) (ord($data[0]) & 1 << 5); $rsv3 = (boolean) (ord($data[0]) & 1 << 4); // Parse opcode $opcode_int = ord($data[0]) & 31; // Bits 4-7 $opcode_ints = array_flip(self::$opcodes); if (!array_key_exists($opcode_int, $opcode_ints)) { throw new \Exception('Bad opcode in websocket frame: '.$opcode_int); } $opcode = $opcode_ints[$opcode_int]; // record the opcode if we are not receiving a continutation fragment if ($opcode !== 'continuation') { $socket->last_opcode = $opcode; } // Masking? $socket->mask = (boolean) (ord($data[1]) >> 7); // Bit 0 in byte 1 $socket->payload = ''; // Payload length $socket->payload_length = (integer) ord($data[1]) & 127; // Bits 1-7 in byte 1 if ($socket->payload_length > 125) { $socket->fragment_status = 1; } else { $socket->fragment_status = 2; } return true; } static public function readFragment1($socket, $buffer) { if ($socket->payload_length === 126) { if ($socket->fragment_length - $socket->read_length < 2) { return false; } $data = substr($buffer, $socket->read_length, 2); // 126: Payload is a 16-bit unsigned int $socket->read_length += 2; } else { if ($socket->fragment_length - $socket->read_length < 8) { return false; } $data = substr($buffer, $socket->read_length, 8); // 127: Payload is a 64-bit unsigned int $socket->read_length += 8; } $socket->payload_length = bindec(self::sprintB($data)); $socket->fragment_status = 2; return true; } static public function readFragment2($socket, $buffer) { // Get masking key. if ($socket->mask) { if ($socket->fragment_length - $socket->read_length < (4 + $socket->payload_length)) { return false; } $masking_key = substr($buffer, $socket->read_length, 4); $socket->read_length += 4; } elseif ($socket->fragment_length - $socket->read_length < $socket->payload_length) { return false; } // Get the actual payload, if any (might not be for e.g. close frames. if ($socket->payload_length > 0) { $data = substr($buffer, $socket->read_length, $socket->payload_length); $socket->read_length += $socket->payload_length; if ($socket->mask) { // Unmask payload. for ($i = 0; $i < $socket->payload_length; $i++) { $socket->payload .= ($data[$i] ^ $masking_key[$i % 4]); } } else { $socket->payload = $data; } } $socket->fragment_status = 3; return true; } static public function sendFragment($socket, $payload, $opcode = 'text', $masked = true) { if (!in_array($opcode, array_keys(self::$opcodes))) { throw new \Exception('Bad opcode '.$opcode.', try text or binary.'); } // record the length of the payload $payload_length = strlen($payload); $fragment_cursor = 0; // while we have data to send while ($payload_length > $fragment_cursor) { // get a fragment of the payload $sub_payload = substr($payload, $fragment_cursor, $socket->fragment_size); // advance the cursor $fragment_cursor += $socket->fragment_size; // is this the final fragment to send? $final = $payload_length <= $fragment_cursor; // send the fragment self::send_frame($socket, $final, $sub_payload, $opcode, $masked); // all fragments after the first will be marked a continuation $opcode = 'continuation'; } } static public function send_frame($socket, $final, $payload, $opcode, $masked) { // Binary string for header. $frame_head_binstr = ''; // Write FIN, final fragment bit. $frame_head_binstr .= (bool) $final ? '1' : '0'; // RSV 1, 2, & 3 false and unused. $frame_head_binstr .= '000'; // Opcode rest of the byte. $frame_head_binstr .= sprintf('b', self::$opcodes[$opcode]); // Use masking? $frame_head_binstr .= $masked ? '1' : '0'; // 7 bits of payload length... $payload_length = strlen($payload); if ($payload_length > 65535) { $frame_head_binstr .= decbin(127); $frame_head_binstr .= sprintf('4b', $payload_length); } elseif ($payload_length > 125) { $frame_head_binstr .= decbin(126); $frame_head_binstr .= sprintf('6b', $payload_length); } else { $frame_head_binstr .= sprintf('b', $payload_length); } $frame = ''; // Write frame head to frame. foreach (str_split($frame_head_binstr, 8) as $binstr) $frame .= chr(bindec($binstr)); // Handle masking if ($masked) { // generate a random mask: $mask = ''; for ($i = 0; $i < 4; $i++) $mask .= chr(rand(0, 255)); $frame .= $mask; } // Append payload to frame: for ($i = 0; $i < $payload_length; $i++) { $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i]; } $socket->write($frame); } /** * Helper to convert a binary to a string of '0' and '1'. */ protected static function sprintB($string) { $ret = ''; for ($i = 0; $i < strlen($string); $i++) { $ret .= sprintf("b", ord($string[$i])); } return $ret; } /** * 解析数据包 * * @return string */ static public function process($socket, $buffer) {startfragment: self::info('process fragment_status:'.$socket->fragment_status.' buffer length:'.strlen($buffer)); $socket->fragment_length = strlen($buffer); switch ($socket->fragment_status) { case 0: // Just read the main fragment information first. if (!self::readFragment0($socket, $buffer)) { return false; } goto startfragment; break; case 1: if (!self::readFragment1($socket, $buffer)) { return false; } goto startfragment; break; case 2: if (!self::readFragment2($socket, $buffer)) { return false; } goto startfragment; break; case 3: { if ($socket->last_opcode === 'close') { // Get the close status. if ($socket->payload_length >= 2) { $status_bin = $socket->payload[0] . $socket->payload[1]; $status = bindec(sprintf("bb", ord($socket->payload[0]), ord($socket->payload[1]))); $socket->close_status = $status; $socket->payload = substr($socket->payload, 2); self::sendFragment($socket, $status_bin . 'Close acknowledged: ' . $status, 'close', true); // Respond. } $socket->is_closing = true; // A close response, all done. } // if this is not the last fragment, then we need to save the payload if (!$socket->final) { $socket->huge_payload .= $socket->payload; self::info('final:'.$socket->final.', payload:'.$socket->payload); return false; } else { // sp we need to retreive the whole payload $socket->huge_payload .= $socket->payload; $socket->payload = $socket->huge_payload; $socket->huge_payload = null; self::info('final:'.$socket->final.', payload:'.$socket->payload); return true; } break; } } return false; } static public function info($message) { if (self::$debug) { echo Phalcon\Cli\Color::info($message).PHP_EOL; } } static public function err($message) { echo Phalcon\Cli\Color::error($message).PHP_EOL; }}/** * 客户端测试 * php -d extension=phalcon.so websocket-client.php -c ws://localhost:10001 */error_reporting(-1);ini_set('display_errors', (DIRECTORY_SEPARATOR == '\\') ? '0' : '1');$opts = new \Phalcon\Cli\Options('Websocket CLI');$opts->add([ 'type' => \Phalcon\Cli\Options::TYPE_STRING, 'name' => 'connect', 'shortName' => 'c', 'required' => true, 'help' => "connect to a websocket server",]);$vals = $opts->parse();if (!isset($vals['connect'])) { return;}// WebsocketClient::$debug = true;$ws = new WebsocketClient($vals['connect'], function($data) { $this->stdout->write(Phalcon\Cli\Color::colorize('< '.$data, Phalcon\Cli\Color::FG_BLUE, NULL, Phalcon\Cli\Color::BG_LIGHT_GRAY)); $this->stdout->write(PHP_EOL.'> ');});try { $ws->connect(function() use ($ws) { echo \Phalcon\Cli\Color::success('connected (press CTRL+C to quit)'); $this->stdout->write('> '); while (null !== ($chunk = $this->stdin->read(100))) { $ws->send(trim($chunk)); } });} catch (\Throwable $e) {}
"怎么用PHP实现wscat"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
内容
数据
更多
知识
实用
学有所成
接下来
困境
实际
客户
客户端
情况
文章
案例
源码
编带
网站
行业
过程
高质量
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
华盾服务器
软件开发自我介绍求职
前端一般做什么软件开发
网络安全示范创建情况
国内最顶级的网络安全360
数据库为什么输不进汉字
网络技术标准规范
360杯网络安全技能大赛题目
3d软件开发教学
华为有软件开发部门吗
用什么工具搭建服务器环境
以岭药业oa服务器地址
上海4u服务器生产厂商
海康存储服务器管理口名字
校园网络安全事件应急演练
裕华伟禾网络技术服务中心
网络安全与应用本科毕业论文
软件开发都是外包吗
网络安全防线42844
免费esxi云服务器
怎么关闭网络安全上网
明日之后绿径溪服务器什么好卖
网络安全示范创建情况
找一个网络安全主题画
文件管理 轻量云服务器
数据库未设置
软件开发公司管理办法
服务器一键登录设置
华为的服务器芯片构架
南宁手机软件开发