怎么用PHP实现wscat
发表于:2025-12-03 作者:千家信息网编辑
千家信息网最后更新 2025年12月03日,本篇内容介绍了"怎么用PHP实现wscat"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!使用php
千家信息网最后更新 2025年12月03日怎么用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安全错误
数据库的锁怎样保障安全
哪些数据库可采集数据
英泰移动数通链路状态数据库
设计软件开发公司有哪些
软件开发管理学专升本
影牙要塞服务器
销售软件开发系统的发票
嘉兴通信网络技术服务
大连市网络安全宣传
百度云服务器满秋
数据库双引号中引用变量
蓝韵超声工作站数据库
搜索引擎无法连接服务器
软件开发方面大学学什么专业
外文期刊数据库检索官网
删除安卓的sqlite数据库
通过视频会议网络安全培训
对网络技术专业的认识
政府确保网络安全
河北希幔软件开发有限公司
网网络安全的手抄报模式
科技前沿互联网
软件开发需保密的内容
xp系统数据库怎么设置
网络安全国家联合实验室
关于数据库安全的研究
江苏前端软件开发
软件开发笔试问题
湖北专业软件开发设施标准
软件后台服务器和运营端怎么操作
服务器被锁机打不开是什么原因