├── .gitignore ├── LICENSE ├── README.md ├── app ├── Controller │ ├── Controller.php │ └── RoomController.php ├── Lib │ └── Log.php ├── WebSocket.php └── view │ ├── index.view.php │ ├── js.view.php │ └── room.view.php ├── bootstrap └── app.php ├── composer.json ├── composer.lock ├── config ├── config.php └── session.php ├── handle.php ├── log └── .gitignore ├── public ├── .gitignore ├── css │ ├── OwO.css │ ├── chat.css │ └── s.css ├── img │ └── header_bg.png ├── index.php ├── js │ ├── OwO.js │ ├── OwO.json │ └── Reconnect.js └── robots.txt ├── route └── web.php ├── run.php └── start_chat.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/* 3 | vendor/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 flxxyz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-chat-websocket 2 | 3 | 这是一个基础聊天室,使用session区分各个用户,使用identicon来做随机头像 4 | 5 | ps:不清楚identicon的可以看看[identicon wiki][1] 6 | 7 | ## Init 8 | 依次执行下面命令 9 | ```shell 10 | git clone https://github.com/flxxyz/php-chat-websocket.git && cd php-chat-websocket 11 | composer update --no-dev 12 | ``` 13 | 14 | ## Usage 15 | 1. 修改 `config/config.php` 4行 16 | ```php 17 | 'url' => 'http://domain/', //保留最后的斜杠 18 | ``` 19 | 20 | 2. 修改`app/view/js.view.php` **155行**为websocket链接🔗 21 | ```javascript 22 | var socket = new ReconnectingWebSocket('ws://你的域名:9501', null, {debug: false, reconnectInterval: 2000, timeoutInterval: 3000}); 23 | ``` 24 | 25 | 3. 自定义ip端口号 26 | ```php 27 | Chat::run('自定义ip', '自定义端口号'); 28 | ``` 29 | 30 | 4. 开启websocket服务器 31 | ```shell 32 | php run.php // 同步检查控制台输出信息 33 | ``` 34 | 35 | 如需要后台挂起服务看这里↓ 36 | ```shell 37 | chmod +x start_chat.sh 38 | ./start_chat.sh 39 | ``` 40 | 41 | 5. 伪静态设置 42 | nginx和apache需要设置伪静态规则,在这里只提供nginx的规则,apache不熟 43 | ``` 44 | location / { 45 | try_files $uri $uri/ /index.php$is_args$query_string; 46 | } 47 | ``` 48 | 49 | 50 | ## Route 51 | | 路径 | 说明 | 52 | |:--- |:--- | 53 | | / | 首页界面 | 54 | | /logout | 注销当前登陆用户 | 55 | | /room | 房间界面 | 56 | 57 | 58 | 59 | [1]: http://en.wikipedia.org/wiki/Identicon -------------------------------------------------------------------------------- /app/Controller/Controller.php: -------------------------------------------------------------------------------- 1 | id = session_id(); 18 | $this->config = config('config'); 19 | 20 | session()->reset(); 21 | } 22 | 23 | public function request() 24 | { 25 | return new Request; 26 | } 27 | 28 | public function json(string $msg = '', int $code = 200, $result = []) 29 | { 30 | $data = [ 31 | 'message' => $msg, 32 | 'code' => $code, 33 | ]; 34 | 35 | if ($code === 200) { 36 | $data['data'] = $result; 37 | } 38 | 39 | exit(json($data)); 40 | } 41 | } -------------------------------------------------------------------------------- /app/Controller/RoomController.php: -------------------------------------------------------------------------------- 1 | get('id')) && is_null(session()->get('name')) && is_null(session()->get('sex')) && is_null(session()->get('icon'))) { 11 | //redirect($this->config['url']); 12 | } 13 | 14 | view('index'); 15 | } 16 | 17 | public function login() { 18 | $query = $this->request()->query; 19 | session()->set(['id' => mt_rand(1000, 1999)]); 20 | session()->set(['name' => $query['username']]); 21 | session()->set(['sex' => $query['sex']]); 22 | 23 | $identicon = new Identicon(); 24 | //$identicon->displayImage($this->session->name); 25 | //$imageData = $identicon->getImageData('bar'); 26 | $imageDataUri = $identicon->getImageDataUri(session()->get('name')); 27 | 28 | session()->set(['icon' => $imageDataUri]); 29 | 30 | redirect($this->config['url'] . 'room'); 31 | } 32 | 33 | public function logout() { 34 | unset($_SESSION['id']); 35 | unset($_SESSION['name']); 36 | unset($_SESSION['sex']); 37 | unset($_SESSION['icon']); 38 | 39 | sleep(1); 40 | redirect($this->config['url']); 41 | } 42 | 43 | public function room() { 44 | if(is_null(session()->get('id')) && is_null(session()->get('name')) && is_null(session()->get('sex')) && is_null(session()->get('icon'))) { 45 | return redirect($this->config['url']); 46 | } 47 | 48 | view('room', [ 49 | 'user' => [ 50 | 'id' => session()->get('id'), 51 | 'name' => session()->get('name'), 52 | 'sex' => session()->get('sex'), 53 | 'icon' => session()->get('icon'), 54 | ], 55 | ]); 56 | } 57 | } -------------------------------------------------------------------------------- /app/Lib/Log.php: -------------------------------------------------------------------------------- 1 | pushHandler(new StreamHandler('log/' . $channel . '.log'), Logger::INFO); 21 | $log->info($message, $param); 22 | } 23 | 24 | /** 25 | * 输出notice类型消息 26 | * @param string $channel 27 | * @param string $message 28 | * @param array $param 29 | */ 30 | static function notice(string $channel, string $message, array $param = []) 31 | { 32 | echo self::message('NOTICE', $message, $param); 33 | $log = new Logger($channel); 34 | $log->pushHandler(new StreamHandler('log/' . $channel . '.log'), Logger::NOTICE); 35 | $log->notice($message, $param); 36 | } 37 | 38 | /** 39 | * 输出debug类型消息 40 | * @param string $channel 41 | * @param string $message 42 | * @param array $param 43 | */ 44 | static function debug(string $channel, string $message, array $param = []) 45 | { 46 | echo self::message('DEBUG', $message, $param); 47 | $log = new Logger($channel); 48 | $log->pushHandler(new StreamHandler('log/' . $channel . '.log'), Logger::DEBUG); 49 | $log->debug($message, $param); 50 | } 51 | 52 | /** 53 | * 输出warn类型消息 54 | * @param string $channel 55 | * @param string $message 56 | * @param array $param 57 | */ 58 | static function warn(string $channel, string $message, array $param = []) 59 | { 60 | echo self::message('WARNING', $message, $param); 61 | $log = new Logger($channel); 62 | $log->pushHandler(new StreamHandler('log/' . $channel . '.log'), Logger::WARNING); 63 | $log->warn($message, $param); 64 | } 65 | 66 | /** 67 | * 输出err类型消息 68 | * @param string $channel 69 | * @param string $message 70 | * @param array $param 71 | */ 72 | static function err(string $channel, string $message, array $param = []) 73 | { 74 | echo self::message('ERROR', $message, $param); 75 | $log = new Logger($channel); 76 | $log->pushHandler(new StreamHandler('log/' . $channel . '.log'), Logger::ERROR); 77 | $log->err($message, $param); 78 | } 79 | 80 | /** 81 | * 命令行输出消息 82 | * @param $type 83 | * @param string $message 84 | * @param array $param 85 | * @return false|string 86 | */ 87 | private static function message($type, string $message = '', array $param = []) 88 | { 89 | $str = date('Y-m-d H:i:s'); 90 | $str .= " [{$type}] {$message} "; 91 | $str .= json_encode($param); 92 | $str .= "\n"; 93 | return $str; 94 | } 95 | } -------------------------------------------------------------------------------- /app/WebSocket.php: -------------------------------------------------------------------------------- 1 | host = $host; 23 | $this->port = $port; 24 | $this->serve = new swoole_websocket_server($this->host, $this->port); 25 | } 26 | 27 | /** 28 | * 打开websocket链接 29 | */ 30 | public function open() 31 | { 32 | $this->serve->on('open', function (swoole_websocket_server $server, $request) { 33 | $fd = $request->fd; 34 | $server->users[$fd] = ['fd' => $fd]; //获取客户端id插入table 35 | 36 | // 记录创建链接数 37 | Log::info('user', "第{$fd}个连接, 创建成功"); 38 | }); 39 | } 40 | 41 | /** 42 | * 接受发送消息websocket 43 | */ 44 | public function message() 45 | { 46 | $this->serve->on('message', function (swoole_websocket_server $server, $frame) { 47 | $fd = $frame->fd; 48 | $state = $frame->opcode; 49 | $data = json_decode($frame->data); 50 | 51 | 52 | $id = isset($data->id) ? $data->id : ''; 53 | $name = isset($data->name) ? $data->name : ''; 54 | $sex = isset($data->sex) ? $data->sex : ''; 55 | $icon = isset($data->icon) ? $data->icon : ''; 56 | $message = isset($data->message) ? $data->message : ''; 57 | $result = []; 58 | 59 | if ($data->type == 'init') { 60 | $type = 'tips'; 61 | $result['message'] = "欢迎{$name}进入"; 62 | } else if ($data->type == 'message') { 63 | $type = 'message'; 64 | $user = $server->users[$fd]['info']; 65 | $result['id'] = $user['id']; 66 | $result['name'] = $user['name']; 67 | $result['sex'] = $user['sex']; 68 | $result['icon'] = $user['icon']; 69 | $result['message'] = $message; 70 | 71 | // 记录用户发送消息 72 | $message = "{$user['name']}: {$message}"; 73 | Log::notice('user', $message); 74 | } else { 75 | $type = 'other'; 76 | } 77 | $result['type'] = $type; 78 | 79 | // 保留用户信息 80 | foreach ($server->users as $user) { 81 | if (!isset($server->users[$user['fd']]['info'])) { 82 | $server->users[$user['fd']]['info'] = [ 83 | 'id' => $id, 84 | 'name' => $name, 85 | 'sex' => $sex, 86 | 'icon' => $icon, 87 | ]; 88 | } 89 | } 90 | 91 | foreach ($server->users as $user) { 92 | $server->push($user['fd'], json_encode($result));//消息广播给所有客户端 93 | } 94 | }); 95 | } 96 | 97 | /** 98 | * 退出websocket 99 | */ 100 | public function close() 101 | { 102 | $this->serve->on('close', function (swoole_websocket_server $server, $fd) { 103 | $users = $server->users; 104 | $name = ''; 105 | foreach ($users as $user) { 106 | if (isset($user['fd'])) { 107 | $userInfo = $users[$fd]['info']; 108 | $server->push($user['fd'], json_encode([ 109 | 'type' => 'tips', 110 | 'name' => $userInfo['name'], 111 | 'message' => "用户{$userInfo['name']}退出", 112 | ]));//消息广播给所有客户端(除自己) 113 | $name = $userInfo['name']; 114 | } 115 | } 116 | 117 | // 记录用户退出 118 | $message = "用户{$name}退出"; 119 | Log::info('user', $message); 120 | }); 121 | } 122 | 123 | /** 124 | * 调用websocket 125 | */ 126 | public function start() 127 | { 128 | // 记录系统 129 | $message = "websocket服务器运行在"; 130 | Log::info('system', $message, ['host' => $this->host, 'port' => $this->port]); 131 | $this->serve->start(); 132 | } 133 | } -------------------------------------------------------------------------------- /app/view/index.view.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 首页 | php-chat-websockt 9 | 10 | 11 |
12 |
13 | 14 | 15 | 注: 3-12位 16 |
17 |
18 | 19 | 24 |
25 |
26 | 27 |
28 |
29 | 30 | 41 | 42 | -------------------------------------------------------------------------------- /app/view/js.view.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/view/room.view.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 房间内 | php-chat-websockt 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |

php-chat-websockt

18 |
19 | 36 | 56 | 57 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | file: {$errfile}"; 27 | $error .= "
line: {$errline}"; 28 | $str = "error_code: {$errno}
" . $error; 29 | exit($error); 30 | } 31 | 32 | require_once BASE_DIR . 'vendor/autoload.php'; 33 | 34 | $core = Col\Core::instance(); 35 | $core->request = Col\Request::instance(); 36 | $core->route = Col\Route::instance($core->request); 37 | $core->session = Col\Session::make(config('session')); 38 | $route = $core->route; 39 | 40 | require_once BASE_DIR . 'route/web.php'; 41 | 42 | $route->end(); 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-chat-websocket", 3 | "version": "2.0", 4 | "require": { 5 | "php": ">=7.0.0", 6 | "monolog/monolog": "1.2.*", 7 | "yzalis/identicon": "^1.2", 8 | "gregwar/captcha": "1.*", 9 | "flxxyz/col": "*", 10 | "vrana/notorm": "dev-master" 11 | }, 12 | "autoload": { 13 | "psr-4": { 14 | "Chat\\": "app/" 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "a00a36b9bf8429d0767d74927ab883a5", 8 | "packages": [ 9 | { 10 | "name": "flxxyz/col", 11 | "version": "0.1.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/flxxyz/Col.git", 15 | "reference": "370247b70a47b8a4b1093f2c7a4dcd405b38fc49" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://files.phpcomposer.com/files/flxxyz/Col/370247b70a47b8a4b1093f2c7a4dcd405b38fc49.zip", 20 | "reference": "370247b70a47b8a4b1093f2c7a4dcd405b38fc49", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=7.0", 25 | "php-curl-class/php-curl-class": "^8.0", 26 | "vrana/notorm": "dev-master" 27 | }, 28 | "type": "library", 29 | "autoload": { 30 | "psr-4": { 31 | "Col\\": "src/" 32 | } 33 | }, 34 | "notification-url": "https://packagist.org/downloads/", 35 | "license": [ 36 | "MIT" 37 | ], 38 | "authors": [ 39 | { 40 | "name": "flxxyz", 41 | "email": "i@0bug.work", 42 | "homepage": "https://toyou.ren" 43 | } 44 | ], 45 | "description": "This is a simple PHP framework", 46 | "homepage": "http://github.com/flxxyz/Col", 47 | "keywords": [ 48 | "Simple", 49 | "framework", 50 | "notorm", 51 | "php", 52 | "简单框架" 53 | ], 54 | "time": "2018-03-01T03:29:33+00:00" 55 | }, 56 | { 57 | "name": "gregwar/captcha", 58 | "version": "v1.1.5", 59 | "source": { 60 | "type": "git", 61 | "url": "https://github.com/Gregwar/Captcha.git", 62 | "reference": "1d06ac8e12d2b3e0df39586d78b9f50e086a0bea" 63 | }, 64 | "dist": { 65 | "type": "zip", 66 | "url": "https://files.phpcomposer.com/files/Gregwar/Captcha/1d06ac8e12d2b3e0df39586d78b9f50e086a0bea.zip", 67 | "reference": "1d06ac8e12d2b3e0df39586d78b9f50e086a0bea", 68 | "shasum": "" 69 | }, 70 | "require": { 71 | "ext-gd": "*", 72 | "ext-mbstring": "*", 73 | "php": ">=5.3.0", 74 | "symfony/finder": "~3.0|~4.0" 75 | }, 76 | "require-dev": { 77 | "phpunit/phpunit": "^6.4" 78 | }, 79 | "type": "captcha", 80 | "autoload": { 81 | "psr-4": { 82 | "Gregwar\\": "src/Gregwar" 83 | } 84 | }, 85 | "notification-url": "https://packagist.org/downloads/", 86 | "license": [ 87 | "MIT" 88 | ], 89 | "authors": [ 90 | { 91 | "name": "Grégoire Passault", 92 | "email": "g.passault@gmail.com", 93 | "homepage": "http://www.gregwar.com/" 94 | }, 95 | { 96 | "name": "Jeremy Livingston", 97 | "email": "jeremy.j.livingston@gmail.com" 98 | } 99 | ], 100 | "description": "Captcha generator", 101 | "homepage": "https://github.com/Gregwar/Captcha", 102 | "keywords": [ 103 | "bot", 104 | "captcha", 105 | "spam" 106 | ], 107 | "time": "2017-12-30T16:18:44+00:00" 108 | }, 109 | { 110 | "name": "monolog/monolog", 111 | "version": "1.2.1", 112 | "source": { 113 | "type": "git", 114 | "url": "https://github.com/Seldaek/monolog.git", 115 | "reference": "d16496318c3e08e3bccfc3866e104e49cf25488a" 116 | }, 117 | "dist": { 118 | "type": "zip", 119 | "url": "https://api.github.com/repos/Seldaek/monolog/zipball/d16496318c3e08e3bccfc3866e104e49cf25488a", 120 | "reference": "d16496318c3e08e3bccfc3866e104e49cf25488a", 121 | "shasum": "" 122 | }, 123 | "require": { 124 | "php": ">=5.3.0" 125 | }, 126 | "require-dev": { 127 | "mlehner/gelf-php": "1.0.*" 128 | }, 129 | "suggest": { 130 | "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", 131 | "ext-mongo": "Allow sending log messages to a MongoDB server", 132 | "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server" 133 | }, 134 | "type": "library", 135 | "extra": { 136 | "branch-alias": { 137 | "dev-master": "1.3.x-dev" 138 | } 139 | }, 140 | "autoload": { 141 | "psr-0": { 142 | "Monolog": "src/" 143 | } 144 | }, 145 | "notification-url": "https://packagist.org/downloads/", 146 | "license": [ 147 | "MIT" 148 | ], 149 | "authors": [ 150 | { 151 | "name": "Jordi Boggiano", 152 | "email": "j.boggiano@seld.be", 153 | "homepage": "http://seld.be", 154 | "role": "Developer" 155 | } 156 | ], 157 | "description": "Logging for PHP 5.3", 158 | "homepage": "http://github.com/Seldaek/monolog", 159 | "keywords": [ 160 | "log", 161 | "logging" 162 | ], 163 | "time": "2012-08-29T11:53:20+00:00" 164 | }, 165 | { 166 | "name": "php-curl-class/php-curl-class", 167 | "version": "8.0.1", 168 | "source": { 169 | "type": "git", 170 | "url": "https://github.com/php-curl-class/php-curl-class.git", 171 | "reference": "bdfe1fcca0c32562050c84e01e3a4cbdc31e22fd" 172 | }, 173 | "dist": { 174 | "type": "zip", 175 | "url": "https://api.github.com/repos/php-curl-class/php-curl-class/zipball/bdfe1fcca0c32562050c84e01e3a4cbdc31e22fd", 176 | "reference": "bdfe1fcca0c32562050c84e01e3a4cbdc31e22fd", 177 | "shasum": "" 178 | }, 179 | "require": { 180 | "ext-curl": "*", 181 | "php": ">=5.3" 182 | }, 183 | "require-dev": { 184 | "phpunit/phpunit": "*", 185 | "squizlabs/php_codesniffer": "*" 186 | }, 187 | "type": "library", 188 | "autoload": { 189 | "psr-4": { 190 | "Curl\\": "src/Curl/" 191 | } 192 | }, 193 | "notification-url": "https://packagist.org/downloads/", 194 | "license": [ 195 | "Unlicense" 196 | ], 197 | "authors": [ 198 | { 199 | "name": "Zach Borboa" 200 | } 201 | ], 202 | "description": "PHP Curl Class makes it easy to send HTTP requests and integrate with web APIs.", 203 | "homepage": "https://github.com/php-curl-class/php-curl-class", 204 | "keywords": [ 205 | "api", 206 | "class", 207 | "client", 208 | "curl", 209 | "framework", 210 | "http", 211 | "http client", 212 | "json", 213 | "php", 214 | "requests", 215 | "rest", 216 | "restful", 217 | "web service", 218 | "xml" 219 | ], 220 | "time": "2018-01-27T15:40:39+00:00" 221 | }, 222 | { 223 | "name": "symfony/finder", 224 | "version": "v4.0.5", 225 | "source": { 226 | "type": "git", 227 | "url": "https://github.com/symfony/finder.git", 228 | "reference": "552e244df10237f845a94fd64b194f848805e34b" 229 | }, 230 | "dist": { 231 | "type": "zip", 232 | "url": "https://files.phpcomposer.com/files/symfony/finder/552e244df10237f845a94fd64b194f848805e34b.zip", 233 | "reference": "552e244df10237f845a94fd64b194f848805e34b", 234 | "shasum": "" 235 | }, 236 | "require": { 237 | "php": "^7.1.3" 238 | }, 239 | "type": "library", 240 | "extra": { 241 | "branch-alias": { 242 | "dev-master": "4.0-dev" 243 | } 244 | }, 245 | "autoload": { 246 | "psr-4": { 247 | "Symfony\\Component\\Finder\\": "" 248 | }, 249 | "exclude-from-classmap": [ 250 | "/Tests/" 251 | ] 252 | }, 253 | "notification-url": "https://packagist.org/downloads/", 254 | "license": [ 255 | "MIT" 256 | ], 257 | "authors": [ 258 | { 259 | "name": "Fabien Potencier", 260 | "email": "fabien@symfony.com" 261 | }, 262 | { 263 | "name": "Symfony Community", 264 | "homepage": "https://symfony.com/contributors" 265 | } 266 | ], 267 | "description": "Symfony Finder Component", 268 | "homepage": "https://symfony.com", 269 | "time": "2018-02-11T17:17:44+00:00" 270 | }, 271 | { 272 | "name": "vrana/notorm", 273 | "version": "dev-master", 274 | "source": { 275 | "type": "git", 276 | "url": "https://github.com/vrana/notorm.git", 277 | "reference": "e49d5d2f1bfe440dc82b61f46172635dfcb6f6dd" 278 | }, 279 | "dist": { 280 | "type": "zip", 281 | "url": "https://api.github.com/repos/vrana/notorm/zipball/e49d5d2f1bfe440dc82b61f46172635dfcb6f6dd", 282 | "reference": "e49d5d2f1bfe440dc82b61f46172635dfcb6f6dd", 283 | "shasum": "" 284 | }, 285 | "type": "library", 286 | "autoload": { 287 | "files": [ 288 | "NotORM.php" 289 | ] 290 | }, 291 | "notification-url": "https://packagist.org/downloads/", 292 | "license": [ 293 | "Apache-2.0", 294 | "GPL-2.0+" 295 | ], 296 | "authors": [ 297 | { 298 | "name": "Jakub Vrana", 299 | "homepage": "http://www.vrana.cz/" 300 | } 301 | ], 302 | "description": "NotORM is a PHP library for simple working with data in the database.", 303 | "homepage": "http://www.notorm.com/", 304 | "keywords": [ 305 | "database", 306 | "dbal" 307 | ], 308 | "time": "2014-10-30T16:55:08+00:00" 309 | }, 310 | { 311 | "name": "yzalis/identicon", 312 | "version": "1.2.0", 313 | "source": { 314 | "type": "git", 315 | "url": "https://github.com/yzalis/Identicon.git", 316 | "reference": "228eca74299a45163be40fd82d334bf21e66b86b" 317 | }, 318 | "dist": { 319 | "type": "zip", 320 | "url": "https://api.github.com/repos/yzalis/Identicon/zipball/228eca74299a45163be40fd82d334bf21e66b86b", 321 | "reference": "228eca74299a45163be40fd82d334bf21e66b86b", 322 | "shasum": "" 323 | }, 324 | "require": { 325 | "php": ">=5.5.0" 326 | }, 327 | "require-dev": { 328 | "ext-imagick": "*", 329 | "fzaninotto/faker": "^1.2.0", 330 | "phpunit/phpunit": "^4.0 || ^5.0" 331 | }, 332 | "type": "library", 333 | "extra": { 334 | "branch-alias": { 335 | "dev-master": "1.2-dev" 336 | } 337 | }, 338 | "autoload": { 339 | "psr-4": { 340 | "Identicon\\": "src/Identicon/" 341 | } 342 | }, 343 | "notification-url": "https://packagist.org/downloads/", 344 | "license": [ 345 | "MIT" 346 | ], 347 | "authors": [ 348 | { 349 | "name": "Benjamin Laugueux", 350 | "email": "benjamin@yzalis.com" 351 | } 352 | ], 353 | "description": "Create awesome unique avatar.", 354 | "homepage": "http://identicon-php.org", 355 | "keywords": [ 356 | "avatar", 357 | "identicon", 358 | "image" 359 | ], 360 | "time": "2017-08-01T14:39:05+00:00" 361 | } 362 | ], 363 | "packages-dev": [], 364 | "aliases": [], 365 | "minimum-stability": "stable", 366 | "stability-flags": { 367 | "vrana/notorm": 20 368 | }, 369 | "prefer-stable": false, 370 | "prefer-lowest": false, 371 | "platform": { 372 | "php": ">=7.0.0" 373 | }, 374 | "platform-dev": [] 375 | } 376 | -------------------------------------------------------------------------------- /config/config.php: -------------------------------------------------------------------------------- 1 | true, 4 | 'url' => 'http://127.0.0.1:8080/', //保留最后的斜杠 5 | 'timezone' => 'PRC', 6 | 'key' => '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 7 | ]; 8 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | true, 4 | 'expire' => 360, // 单位: 分钟 5 | 'limiter' => 'private', 6 | 'perfix' => 'chat', 7 | ]; 8 | -------------------------------------------------------------------------------- /handle.php: -------------------------------------------------------------------------------- 1 | open(); 17 | $socket->message(); 18 | $socket->close(); 19 | $socket->start(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .* 3 | !.htaccess 4 | /log/* 5 | !/log/README.md 6 | !.gitignore 7 | 8 | application/cache/* 9 | !application/cache/index.html 10 | !application/cache/.htaccess 11 | 12 | application/logs/* 13 | !application/logs/index.html 14 | !application/logs/.htaccess 15 | 16 | composer.lock 17 | 18 | user_guide_src/build/* 19 | user_guide_src/cilexer/build/* 20 | user_guide_src/cilexer/dist/* 21 | user_guide_src/cilexer/pycilexer.egg-info/* 22 | /vendor/ 23 | 24 | # IDE Files 25 | #------------------------- 26 | /nbproject/ 27 | .idea/* 28 | 29 | ## Sublime Text cache files 30 | *.tmlanguage.cache 31 | *.tmPreferences.cache 32 | *.stTheme.cache 33 | *.sublime-workspace 34 | *.sublime-project 35 | -------------------------------------------------------------------------------- /public/css/OwO.css: -------------------------------------------------------------------------------- 1 | .OwO { 2 | position: relative; 3 | -webkit-user-select: none; 4 | -moz-user-select: none; 5 | -ms-user-select: none; 6 | user-select: none; 7 | } 8 | 9 | 10 | 11 | .OwO.OwO-open .OwO-logo { 12 | border-radius: 4px 4px 0 0; 13 | border-bottom: none; 14 | color: #444; 15 | } 16 | 17 | 18 | 19 | .OwO:hover .OwO-logo { 20 | color: #444; 21 | } 22 | 23 | 24 | .OwO.OwO-open .OwO-body { 25 | display: block; 26 | } 27 | 28 | 29 | .OwO.OwO-up .OwO-body { 30 | top: inherit; 31 | bottom: 21px; 32 | border-radius: 4px 4px 4px 0; 33 | } 34 | 35 | .OwO.OwO-up .OwO-body .OwO-bar .OwO-packages li:nth-child(1) { 36 | border-radius: 0; 37 | } 38 | 39 | .OwO.OwO-up.OwO-open .OwO-logo { 40 | border: 1px solid #ddd; 41 | border-radius: 0 0 4px 4px; 42 | border-top: none; 43 | } 44 | 45 | .OwO .OwO-logo { 46 | position: relative; 47 | display: inline-block; 48 | color: #888; 49 | background: #fff; 50 | border: 1px solid #ddd; 51 | border-radius: 4px; 52 | font-size: 13px; 53 | padding: 2px 5px; 54 | cursor: pointer; 55 | height: 22px; 56 | box-sizing: border-box; 57 | z-index: 2; 58 | line-height: 16px; 59 | } 60 | 61 | .OwO .OwO-logo:hover span { 62 | display: inline-block; 63 | -webkit-animation: a 5s infinite ease-in-out; 64 | animation: a 5s infinite ease-in-out; 65 | } 66 | 67 | .OwO .OwO-body { 68 | display: none; 69 | position: absolute; 70 | width: 200px; 71 | background: #fff; 72 | border: 1px solid #ddd; 73 | z-index: 1; 74 | top: 21px; 75 | border-radius: 0 4px 4px 4px; 76 | } 77 | .OwO .OwO-body .OwO-items { 78 | -webkit-user-select: none; 79 | -moz-user-select: none; 80 | -ms-user-select: none; 81 | user-select: none; 82 | display: none; 83 | padding: 10px; 84 | margin: 0; 85 | overflow: scroll; 86 | font-size: 0; 87 | } 88 | 89 | .OwO .OwO-body .OwO-items .OwO-item { 90 | list-style-type: none; 91 | background: #f7f7f7; 92 | padding: 5px 10px; 93 | border-radius: 5px; 94 | display: inline-block; 95 | font-size: 12px; 96 | line-height: 14px; 97 | margin: 0 10px 12px 0; 98 | cursor: pointer; 99 | -webkit-transition: .3s; 100 | transition: .3s; 101 | } 102 | 103 | .OwO .OwO-body .OwO-items .OwO-item:hover { 104 | background: #eee; 105 | box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12); 106 | -webkit-animation: a 5s infinite ease-in-out; 107 | animation: a 5s infinite ease-in-out; 108 | } 109 | 110 | .OwO .OwO-body .OwO-items-emoji .OwO-item { 111 | font-size: 20px; 112 | line-height: 19px; 113 | } 114 | 115 | .OwO .OwO-body .OwO-items-image .OwO-item { 116 | max-width: calc(25% - 10px); 117 | box-sizing: border-box; 118 | } 119 | 120 | .OwO .OwO-body .OwO-items-image .OwO-item img { 121 | max-width: 100%; 122 | } 123 | 124 | .OwO .OwO-body .OwO-items-show { 125 | display: block; 126 | } 127 | 128 | .OwO .OwO-body .OwO-bar { 129 | width: 100%; 130 | height: 30px; 131 | border-top: 1px solid #ddd; 132 | background: #fff; 133 | border-radius: 0 0 4px 4px; 134 | color: #444; 135 | } 136 | 137 | .OwO .OwO-body .OwO-bar .OwO-packages { 138 | margin: 0; 139 | padding: 0; 140 | font-size: 0; 141 | } 142 | 143 | .OwO .OwO-body .OwO-bar .OwO-packages li { 144 | list-style-type: none; 145 | display: inline-block; 146 | line-height: 30px; 147 | font-size: 14px; 148 | padding: 0 10px; 149 | cursor: pointer; 150 | margin-right: 3px; 151 | } 152 | 153 | .OwO .OwO-body .OwO-bar .OwO-packages li:nth-child(1) { 154 | border-radius: 0 0 0 3px; 155 | } 156 | 157 | .OwO .OwO-body .OwO-bar .OwO-packages li:hover { 158 | background: #eee; 159 | } 160 | 161 | .OwO .OwO-body .OwO-bar .OwO-packages .OwO-package-active { 162 | background: #eee; 163 | -webkit-transition: .3s; 164 | transition: .3s; 165 | } 166 | @-webkit-keyframes a { 167 | 2% { 168 | -webkit-transform: translateY(1.5px) rotate(1.5deg); 169 | transform: translateY(1.5px) rotate(1.5deg); 170 | } 171 | 172 | 4% { 173 | -webkit-transform: translateY(-1.5px) rotate(-.5deg); 174 | transform: translateY(-1.5px) rotate(-.5deg); 175 | } 176 | 177 | 6% { 178 | -webkit-transform: translateY(1.5px) rotate(-1.5deg); 179 | transform: translateY(1.5px) rotate(-1.5deg); 180 | } 181 | 182 | 8% { 183 | -webkit-transform: translateY(-1.5px) rotate(-1.5deg); 184 | transform: translateY(-1.5px) rotate(-1.5deg); 185 | } 186 | 187 | 10% { 188 | -webkit-transform: translateY(2.5px) rotate(1.5deg); 189 | transform: translateY(2.5px) rotate(1.5deg); 190 | } 191 | 192 | 12% { 193 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 194 | transform: translateY(-.5px) rotate(1.5deg); 195 | } 196 | 197 | 14% { 198 | -webkit-transform: translateY(-1.5px) rotate(1.5deg); 199 | transform: translateY(-1.5px) rotate(1.5deg); 200 | } 201 | 202 | 16% { 203 | -webkit-transform: translateY(-.5px) rotate(-1.5deg); 204 | transform: translateY(-.5px) rotate(-1.5deg); 205 | } 206 | 207 | 18% { 208 | -webkit-transform: translateY(.5px) rotate(-1.5deg); 209 | transform: translateY(.5px) rotate(-1.5deg); 210 | } 211 | 212 | 20% { 213 | -webkit-transform: translateY(-1.5px) rotate(2.5deg); 214 | transform: translateY(-1.5px) rotate(2.5deg); 215 | } 216 | 217 | 22% { 218 | -webkit-transform: translateY(.5px) rotate(-1.5deg); 219 | transform: translateY(.5px) rotate(-1.5deg); 220 | } 221 | 222 | 24% { 223 | -webkit-transform: translateY(1.5px) rotate(1.5deg); 224 | transform: translateY(1.5px) rotate(1.5deg); 225 | } 226 | 227 | 26% { 228 | -webkit-transform: translateY(.5px) rotate(.5deg); 229 | transform: translateY(.5px) rotate(.5deg); 230 | } 231 | 232 | 28% { 233 | -webkit-transform: translateY(.5px) rotate(1.5deg); 234 | transform: translateY(.5px) rotate(1.5deg); 235 | } 236 | 237 | 30% { 238 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 239 | transform: translateY(-.5px) rotate(2.5deg); 240 | } 241 | 242 | 32%,34% { 243 | -webkit-transform: translateY(1.5px) rotate(-.5deg); 244 | transform: translateY(1.5px) rotate(-.5deg); 245 | } 246 | 247 | 36% { 248 | -webkit-transform: translateY(-1.5px) rotate(2.5deg); 249 | transform: translateY(-1.5px) rotate(2.5deg); 250 | } 251 | 252 | 38% { 253 | -webkit-transform: translateY(1.5px) rotate(-1.5deg); 254 | transform: translateY(1.5px) rotate(-1.5deg); 255 | } 256 | 257 | 40% { 258 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 259 | transform: translateY(-.5px) rotate(2.5deg); 260 | } 261 | 262 | 42% { 263 | -webkit-transform: translateY(2.5px) rotate(-1.5deg); 264 | transform: translateY(2.5px) rotate(-1.5deg); 265 | } 266 | 267 | 44% { 268 | -webkit-transform: translateY(1.5px) rotate(.5deg); 269 | transform: translateY(1.5px) rotate(.5deg); 270 | } 271 | 272 | 46% { 273 | -webkit-transform: translateY(-1.5px) rotate(2.5deg); 274 | transform: translateY(-1.5px) rotate(2.5deg); 275 | } 276 | 277 | 48% { 278 | -webkit-transform: translateY(-.5px) rotate(.5deg); 279 | transform: translateY(-.5px) rotate(.5deg); 280 | } 281 | 282 | 50% { 283 | -webkit-transform: translateY(.5px) rotate(.5deg); 284 | transform: translateY(.5px) rotate(.5deg); 285 | } 286 | 287 | 52% { 288 | -webkit-transform: translateY(2.5px) rotate(2.5deg); 289 | transform: translateY(2.5px) rotate(2.5deg); 290 | } 291 | 292 | 54% { 293 | -webkit-transform: translateY(-1.5px) rotate(1.5deg); 294 | transform: translateY(-1.5px) rotate(1.5deg); 295 | } 296 | 297 | 56% { 298 | -webkit-transform: translateY(2.5px) rotate(2.5deg); 299 | transform: translateY(2.5px) rotate(2.5deg); 300 | } 301 | 302 | 58% { 303 | -webkit-transform: translateY(.5px) rotate(2.5deg); 304 | transform: translateY(.5px) rotate(2.5deg); 305 | } 306 | 307 | 60% { 308 | -webkit-transform: translateY(2.5px) rotate(2.5deg); 309 | transform: translateY(2.5px) rotate(2.5deg); 310 | } 311 | 312 | 62% { 313 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 314 | transform: translateY(-.5px) rotate(2.5deg); 315 | } 316 | 317 | 64% { 318 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 319 | transform: translateY(-.5px) rotate(1.5deg); 320 | } 321 | 322 | 66% { 323 | -webkit-transform: translateY(1.5px) rotate(-.5deg); 324 | transform: translateY(1.5px) rotate(-.5deg); 325 | } 326 | 327 | 68% { 328 | -webkit-transform: translateY(-1.5px) rotate(-.5deg); 329 | transform: translateY(-1.5px) rotate(-.5deg); 330 | } 331 | 332 | 70% { 333 | -webkit-transform: translateY(1.5px) rotate(.5deg); 334 | transform: translateY(1.5px) rotate(.5deg); 335 | } 336 | 337 | 72% { 338 | -webkit-transform: translateY(2.5px) rotate(1.5deg); 339 | transform: translateY(2.5px) rotate(1.5deg); 340 | } 341 | 342 | 74% { 343 | -webkit-transform: translateY(-.5px) rotate(.5deg); 344 | transform: translateY(-.5px) rotate(.5deg); 345 | } 346 | 347 | 76% { 348 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 349 | transform: translateY(-.5px) rotate(2.5deg); 350 | } 351 | 352 | 78% { 353 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 354 | transform: translateY(-.5px) rotate(1.5deg); 355 | } 356 | 357 | 80% { 358 | -webkit-transform: translateY(1.5px) rotate(1.5deg); 359 | transform: translateY(1.5px) rotate(1.5deg); 360 | } 361 | 362 | 82% { 363 | -webkit-transform: translateY(-.5px) rotate(.5deg); 364 | transform: translateY(-.5px) rotate(.5deg); 365 | } 366 | 367 | 84% { 368 | -webkit-transform: translateY(1.5px) rotate(2.5deg); 369 | transform: translateY(1.5px) rotate(2.5deg); 370 | } 371 | 372 | 86% { 373 | -webkit-transform: translateY(-1.5px) rotate(-1.5deg); 374 | transform: translateY(-1.5px) rotate(-1.5deg); 375 | } 376 | 377 | 88% { 378 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 379 | transform: translateY(-.5px) rotate(2.5deg); 380 | } 381 | 382 | 90% { 383 | -webkit-transform: translateY(2.5px) rotate(-.5deg); 384 | transform: translateY(2.5px) rotate(-.5deg); 385 | } 386 | 387 | 92% { 388 | -webkit-transform: translateY(.5px) rotate(-.5deg); 389 | transform: translateY(.5px) rotate(-.5deg); 390 | } 391 | 392 | 94% { 393 | -webkit-transform: translateY(2.5px) rotate(.5deg); 394 | transform: translateY(2.5px) rotate(.5deg); 395 | } 396 | 397 | 96% { 398 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 399 | transform: translateY(-.5px) rotate(1.5deg); 400 | } 401 | 402 | 98% { 403 | -webkit-transform: translateY(-1.5px) rotate(-.5deg); 404 | transform: translateY(-1.5px) rotate(-.5deg); 405 | } 406 | 407 | 0%,to { 408 | -webkit-transform: translate(0) rotate(0deg); 409 | transform: translate(0) rotate(0deg); 410 | } 411 | } 412 | 413 | @keyframes a { 414 | 2% { 415 | -webkit-transform: translateY(1.5px) rotate(1.5deg); 416 | transform: translateY(1.5px) rotate(1.5deg); 417 | } 418 | 419 | 4% { 420 | -webkit-transform: translateY(-1.5px) rotate(-.5deg); 421 | transform: translateY(-1.5px) rotate(-.5deg); 422 | } 423 | 424 | 6% { 425 | -webkit-transform: translateY(1.5px) rotate(-1.5deg); 426 | transform: translateY(1.5px) rotate(-1.5deg); 427 | } 428 | 429 | 8% { 430 | -webkit-transform: translateY(-1.5px) rotate(-1.5deg); 431 | transform: translateY(-1.5px) rotate(-1.5deg); 432 | } 433 | 434 | 10% { 435 | -webkit-transform: translateY(2.5px) rotate(1.5deg); 436 | transform: translateY(2.5px) rotate(1.5deg); 437 | } 438 | 439 | 12% { 440 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 441 | transform: translateY(-.5px) rotate(1.5deg); 442 | } 443 | 444 | 14% { 445 | -webkit-transform: translateY(-1.5px) rotate(1.5deg); 446 | transform: translateY(-1.5px) rotate(1.5deg); 447 | } 448 | 449 | 16% { 450 | -webkit-transform: translateY(-.5px) rotate(-1.5deg); 451 | transform: translateY(-.5px) rotate(-1.5deg); 452 | } 453 | 454 | 18% { 455 | -webkit-transform: translateY(.5px) rotate(-1.5deg); 456 | transform: translateY(.5px) rotate(-1.5deg); 457 | } 458 | 459 | 20% { 460 | -webkit-transform: translateY(-1.5px) rotate(2.5deg); 461 | transform: translateY(-1.5px) rotate(2.5deg); 462 | } 463 | 464 | 22% { 465 | -webkit-transform: translateY(.5px) rotate(-1.5deg); 466 | transform: translateY(.5px) rotate(-1.5deg); 467 | } 468 | 469 | 24% { 470 | -webkit-transform: translateY(1.5px) rotate(1.5deg); 471 | transform: translateY(1.5px) rotate(1.5deg); 472 | } 473 | 474 | 26% { 475 | -webkit-transform: translateY(.5px) rotate(.5deg); 476 | transform: translateY(.5px) rotate(.5deg); 477 | } 478 | 479 | 28% { 480 | -webkit-transform: translateY(.5px) rotate(1.5deg); 481 | transform: translateY(.5px) rotate(1.5deg); 482 | } 483 | 484 | 30% { 485 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 486 | transform: translateY(-.5px) rotate(2.5deg); 487 | } 488 | 489 | 32%,34% { 490 | -webkit-transform: translateY(1.5px) rotate(-.5deg); 491 | transform: translateY(1.5px) rotate(-.5deg); 492 | } 493 | 494 | 36% { 495 | -webkit-transform: translateY(-1.5px) rotate(2.5deg); 496 | transform: translateY(-1.5px) rotate(2.5deg); 497 | } 498 | 499 | 38% { 500 | -webkit-transform: translateY(1.5px) rotate(-1.5deg); 501 | transform: translateY(1.5px) rotate(-1.5deg); 502 | } 503 | 504 | 40% { 505 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 506 | transform: translateY(-.5px) rotate(2.5deg); 507 | } 508 | 509 | 42% { 510 | -webkit-transform: translateY(2.5px) rotate(-1.5deg); 511 | transform: translateY(2.5px) rotate(-1.5deg); 512 | } 513 | 514 | 44% { 515 | -webkit-transform: translateY(1.5px) rotate(.5deg); 516 | transform: translateY(1.5px) rotate(.5deg); 517 | } 518 | 519 | 46% { 520 | -webkit-transform: translateY(-1.5px) rotate(2.5deg); 521 | transform: translateY(-1.5px) rotate(2.5deg); 522 | } 523 | 524 | 48% { 525 | -webkit-transform: translateY(-.5px) rotate(.5deg); 526 | transform: translateY(-.5px) rotate(.5deg); 527 | } 528 | 529 | 50% { 530 | -webkit-transform: translateY(.5px) rotate(.5deg); 531 | transform: translateY(.5px) rotate(.5deg); 532 | } 533 | 534 | 52% { 535 | -webkit-transform: translateY(2.5px) rotate(2.5deg); 536 | transform: translateY(2.5px) rotate(2.5deg); 537 | } 538 | 539 | 54% { 540 | -webkit-transform: translateY(-1.5px) rotate(1.5deg); 541 | transform: translateY(-1.5px) rotate(1.5deg); 542 | } 543 | 544 | 56% { 545 | -webkit-transform: translateY(2.5px) rotate(2.5deg); 546 | transform: translateY(2.5px) rotate(2.5deg); 547 | } 548 | 549 | 58% { 550 | -webkit-transform: translateY(.5px) rotate(2.5deg); 551 | transform: translateY(.5px) rotate(2.5deg); 552 | } 553 | 554 | 60% { 555 | -webkit-transform: translateY(2.5px) rotate(2.5deg); 556 | transform: translateY(2.5px) rotate(2.5deg); 557 | } 558 | 559 | 62% { 560 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 561 | transform: translateY(-.5px) rotate(2.5deg); 562 | } 563 | 564 | 64% { 565 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 566 | transform: translateY(-.5px) rotate(1.5deg); 567 | } 568 | 569 | 66% { 570 | -webkit-transform: translateY(1.5px) rotate(-.5deg); 571 | transform: translateY(1.5px) rotate(-.5deg); 572 | } 573 | 574 | 68% { 575 | -webkit-transform: translateY(-1.5px) rotate(-.5deg); 576 | transform: translateY(-1.5px) rotate(-.5deg); 577 | } 578 | 579 | 70% { 580 | -webkit-transform: translateY(1.5px) rotate(.5deg); 581 | transform: translateY(1.5px) rotate(.5deg); 582 | } 583 | 584 | 72% { 585 | -webkit-transform: translateY(2.5px) rotate(1.5deg); 586 | transform: translateY(2.5px) rotate(1.5deg); 587 | } 588 | 589 | 74% { 590 | -webkit-transform: translateY(-.5px) rotate(.5deg); 591 | transform: translateY(-.5px) rotate(.5deg); 592 | } 593 | 594 | 76% { 595 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 596 | transform: translateY(-.5px) rotate(2.5deg); 597 | } 598 | 599 | 78% { 600 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 601 | transform: translateY(-.5px) rotate(1.5deg); 602 | } 603 | 604 | 80% { 605 | -webkit-transform: translateY(1.5px) rotate(1.5deg); 606 | transform: translateY(1.5px) rotate(1.5deg); 607 | } 608 | 609 | 82% { 610 | -webkit-transform: translateY(-.5px) rotate(.5deg); 611 | transform: translateY(-.5px) rotate(.5deg); 612 | } 613 | 614 | 84% { 615 | -webkit-transform: translateY(1.5px) rotate(2.5deg); 616 | transform: translateY(1.5px) rotate(2.5deg); 617 | } 618 | 619 | 86% { 620 | -webkit-transform: translateY(-1.5px) rotate(-1.5deg); 621 | transform: translateY(-1.5px) rotate(-1.5deg); 622 | } 623 | 624 | 88% { 625 | -webkit-transform: translateY(-.5px) rotate(2.5deg); 626 | transform: translateY(-.5px) rotate(2.5deg); 627 | } 628 | 629 | 90% { 630 | -webkit-transform: translateY(2.5px) rotate(-.5deg); 631 | transform: translateY(2.5px) rotate(-.5deg); 632 | } 633 | 634 | 92% { 635 | -webkit-transform: translateY(.5px) rotate(-.5deg); 636 | transform: translateY(.5px) rotate(-.5deg); 637 | } 638 | 639 | 94% { 640 | -webkit-transform: translateY(2.5px) rotate(.5deg); 641 | transform: translateY(2.5px) rotate(.5deg); 642 | } 643 | 644 | 96% { 645 | -webkit-transform: translateY(-.5px) rotate(1.5deg); 646 | transform: translateY(-.5px) rotate(1.5deg); 647 | } 648 | 649 | 98% { 650 | -webkit-transform: translateY(-1.5px) rotate(-.5deg); 651 | transform: translateY(-1.5px) rotate(-.5deg); 652 | } 653 | 654 | 0%,to { 655 | -webkit-transform: translate(0) rotate(0deg); 656 | transform: translate(0) rotate(0deg); 657 | } 658 | 659 | } -------------------------------------------------------------------------------- /public/css/chat.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | html,body { 6 | width: 100%; 7 | height: 100%; 8 | } 9 | body { 10 | overflow: hidden; 11 | } 12 | input, button, textarea{ 13 | border: 0; 14 | outline: 0; 15 | outline-offset: 0; 16 | } 17 | :after,:before { 18 | box-sizing: border-box; 19 | } 20 | ::-webkit-scrollbar { 21 | width: 2px; 22 | background-color: #f5f5f5; 23 | } 24 | ::-webkit-scrollbar-thumb { 25 | background-color: #999; 26 | } 27 | ::-webkit-scrollbar-track { 28 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 29 | -moz-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 30 | box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 31 | background-color: #f5f5f5; 32 | } 33 | ::-webkit-scrollbar:window-inactive,::-webkit-scrollbar-track:window-inactive,::-webkit-scrollbar-thumb:window-inactive { 34 | visibility: hidden; 35 | } 36 | 37 | 38 | #chat-header { 39 | position: relative; 40 | top: 0; 41 | left: 0; 42 | padding: 8px 0; 43 | width: 100%; 44 | text-align: center; 45 | font-size: 1em; 46 | color: #fff; 47 | background-color: #3097D1; 48 | background-image: url(../img/header_bg.png); 49 | } 50 | #chat-list { 51 | position: relative; 52 | top: 0; 53 | left: 0; 54 | max-width: 100%; 55 | width: 100%; 56 | height: 86%; 57 | background: #F1F2F7; 58 | overflow: scroll; 59 | overflow-x: hidden; 60 | overflow-y: scroll; 61 | } 62 | #chat-footer { 63 | position: fixed; 64 | bottom: 0; 65 | left: 0; 66 | width: 100%; 67 | height: 10%; 68 | background: #F1F2F7; 69 | } 70 | 71 | .chat { 72 | padding: 15px 0; 73 | position: relative; 74 | top: 0; 75 | left: 0; 76 | } 77 | .chat-img { 78 | position: absolute; 79 | top: 25px; 80 | margin-top: -10px; 81 | width: 50px; 82 | height: 50px; 83 | -webkit-border-radius: 50%; 84 | -moz-border-radius: 50%; 85 | border-radius: 50%; 86 | background: #fff; 87 | } 88 | .chat-info { 89 | font-size: .3em; 90 | } 91 | .chat-s { 92 | padding: 0 5px; 93 | color: #fff; 94 | background: #FF988A; 95 | -webkit-border-radius: 7px; 96 | -moz-border-radius: 7px; 97 | border-radius: 7px; 98 | } 99 | .chat-name { 100 | color: rgb(144,145,149); 101 | } 102 | .chat-sex { 103 | font-size: 4em; 104 | font-weight: bold; 105 | } 106 | .chat-sex.male { 107 | color: #5FD4F2; 108 | } 109 | .chat-sex.female { 110 | color: #FF758F; 111 | } 112 | .chat-sex.maf { 113 | color: rgb(205,33,230); 114 | } 115 | .chat-message { 116 | margin: 5px 70px 0 70px; 117 | word-wrap:break-word; 118 | word-break:normal; 119 | display: inline-block; 120 | padding: 5px; 121 | border: 1px solid #fff; 122 | -webkit-border-radius: 5px; 123 | -moz-border-radius: 5px; 124 | border-radius: 5px; 125 | background: #fff; 126 | box-shadow: 2px 2px 2px 0 rgba(0,0,0,.1); 127 | } 128 | .chat-message:after { 129 | content: ""; 130 | position: absolute; 131 | border-bottom: 8px solid rgba(255, 255, 255, 0); 132 | } 133 | .chat-message > img { 134 | max-width: 100%; 135 | width: 100%; 136 | } 137 | .chat-me { 138 | text-align: right; 139 | } 140 | .chat-me > img { 141 | right: 10px; 142 | } 143 | .chat-me > p:after { 144 | right: 60px; 145 | top: 50px; 146 | border-left: 12px solid #fff; 147 | } 148 | .chat-me > .chat-info { 149 | margin-right: 70px; 150 | } 151 | .chat-ta { 152 | text-align: left; 153 | } 154 | .chat-ta > img { 155 | left: 10px; 156 | } 157 | .chat-ta > p:after { 158 | left: 60px; 159 | top: 50px; 160 | border-right: 12px solid #fff; 161 | } 162 | .chat-ta > .chat-info { 163 | margin-left: 70px; 164 | } 165 | /* 用户 */ 166 | .chat-type-message { 167 | 168 | } 169 | /* 系统 */ 170 | .chat-type-system { 171 | 172 | } 173 | /* 小提示 */ 174 | .chat-type-tips { 175 | 176 | } 177 | .chat-type-system, .chat-type-tips { 178 | text-align: center; 179 | font-size: .5em; 180 | } 181 | .chat-type-system > span { 182 | display: inline-block; 183 | padding: 4px; 184 | color: #ffffff; 185 | background-color: #cccccc; 186 | -webkit-border-radius: 7px; 187 | -moz-border-radius: 7px; 188 | border-radius: 7px; 189 | } 190 | .chat-type-tips > span { 191 | padding: 2px 8px; 192 | color: #fff; 193 | background: #FF0000; 194 | -webkit-border-radius: 7px; 195 | -moz-border-radius: 7px; 196 | border-radius: 7px; 197 | } 198 | .chat-input > .message { 199 | margin: 2px 0 2px 3%; 200 | padding: 5px 3px; 201 | width: 80%; 202 | height: 24px; 203 | -webkit-border-radius: 2px; 204 | -moz-border-radius: 2px; 205 | border-radius: 3px; 206 | background: #fff; 207 | } 208 | .chat-input > .message:focus { 209 | box-shadow: inset 0 0 1px 2px rgba(0,0,0,0.1) 210 | } 211 | .chat-input > .message:active { 212 | box-shadow: inset 0 0 1px 2px rgba(0,0,0,0.1) 213 | } 214 | .chat-input > .message::-webkit-scrollbar { 215 | width: 1px; 216 | background-color: #f5f5f5; 217 | } 218 | .chat-input > .message::-webkit-scrollbar-thumb { 219 | background-color: #999; 220 | } 221 | .chat-input > .message::-webkit-scrollbar-track { 222 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 223 | -moz-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 224 | box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); 225 | background-color: #f5f5f5; 226 | } 227 | .chat-input > .btn { 228 | margin: 1px 1.5% 1px 1.5%; 229 | width: 12%; 230 | height: 36px; 231 | float: right; 232 | border-radius: 6px; 233 | color: #fff; 234 | } 235 | .chat-input > .btn.y { 236 | background: #12B7F5; 237 | } 238 | .chat-input > .btn.n { 239 | background: #DDDEE2; 240 | } 241 | .chat-more { 242 | margin: 0 3%; 243 | } 244 | -------------------------------------------------------------------------------- /public/css/s.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flxxyz/php-chat-websocket/a6717d073f26685651ab9c5a2e3239841684ca80/public/css/s.css -------------------------------------------------------------------------------- /public/img/header_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flxxyz/php-chat-websocket/a6717d073f26685651ab9c5a2e3239841684ca80/public/img/header_bg.png -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | = 200 && i.status < 300 || 304 === i.status ? (a.odata = JSON.parse(i.responseText), a.init(t)) : console.log("OwO data request was unsuccessful: " + i.status)) 40 | }, i.open("get", t.api, !0), i.send(null) 41 | } 42 | 43 | return _createClass(e, [{ 44 | key: "init", 45 | value: function (e) { 46 | var t = this; 47 | this.area = e.target, this.packages = Object.keys(this.odata); 48 | for (var a = '\n \n
', s = 0; s < this.packages.length; s++) { 49 | a += '\n " 52 | } 53 | a += '\n
\n \n
\n
\n ", this.container.innerHTML = a, this.logo = this.container.getElementsByClassName("OwO-logo")[0], this.logo.addEventListener("click", function () { 56 | t.toggle() 57 | }), this.container.getElementsByClassName("OwO-body")[0].addEventListener("click", function (e) { 58 | var a = null; 59 | if (e.target.classList.contains("OwO-item") ? a = e.target : e.target.parentNode.classList.contains("OwO-item") && (a = e.target.parentNode), a) { 60 | var s = t.area.selectionEnd, n = t.area.value; 61 | if(//.test(a.innerHTML)) { 62 | return; 63 | } 64 | t.area.value = n.slice(0, s) + a.innerHTML + n.slice(s),t.area.focus() //t.toggle() 65 | } 66 | }), this.packagesEle = this.container.getElementsByClassName("OwO-packages")[0]; 67 | for (var c = function (e) { 68 | !function (a) { 69 | t.packagesEle.children[e].addEventListener("click", function () { 70 | t.tab(a) 71 | }) 72 | }(e) 73 | }, l = 0; l < this.packagesEle.children.length; l++) c(l); 74 | this.tab(0) 75 | } 76 | }, { 77 | key: "toggle", 78 | value: function () { 79 | this.container.classList.contains("OwO-open") ? this.container.classList.remove("OwO-open") : this.container.classList.add("OwO-open") 80 | } 81 | }, { 82 | key: "tab", 83 | value: function (e) { 84 | var t = this.container.getElementsByClassName("OwO-items-show")[0]; 85 | t && t.classList.remove("OwO-items-show"), this.container.getElementsByClassName("OwO-items")[e].classList.add("OwO-items-show"); 86 | var a = this.container.getElementsByClassName("OwO-package-active")[0]; 87 | a && a.classList.remove("OwO-package-active"), this.packagesEle.getElementsByTagName("li")[e].classList.add("OwO-package-active") 88 | } 89 | }]), e 90 | }(); 91 | "undefined" != typeof module && "undefined" != typeof module.exports ? module.exports = e : window.OwO = e 92 | }(); -------------------------------------------------------------------------------- /public/js/OwO.json: -------------------------------------------------------------------------------- 1 | { 2 | "颜文字": { 3 | "type": "emoticon", 4 | "container": [ 5 | { 6 | "icon": "OωO", 7 | "text": "Author: DIYgod" 8 | }, 9 | { 10 | "icon": "|´・ω・)ノ", 11 | "text": "Hi" 12 | }, 13 | { 14 | "icon": "ヾ(≧∇≦*)ゝ", 15 | "text": "开心" 16 | }, 17 | { 18 | "icon": "(☆ω☆)", 19 | "text": "星星眼" 20 | }, 21 | { 22 | "icon": "(╯‵□′)╯︵┴─┴", 23 | "text": "掀桌" 24 | }, 25 | { 26 | "icon": " ̄﹃ ̄", 27 | "text": "流口水" 28 | }, 29 | { 30 | "icon": "(/ω\)", 31 | "text": "捂脸" 32 | }, 33 | { 34 | "icon": "∠( ᐛ 」∠)_", 35 | "text": "给跪" 36 | }, 37 | { 38 | "icon": "(๑•̀ㅁ•́ฅ)", 39 | "text": "Hi" 40 | }, 41 | { 42 | "icon": "→_→", 43 | "text": "斜眼" 44 | }, 45 | { 46 | "icon": "୧(๑•̀⌄•́๑)૭", 47 | "text": "加油" 48 | }, 49 | { 50 | "icon": "٩(ˊᗜˋ*)و", 51 | "text": "有木有WiFi" 52 | }, 53 | { 54 | "icon": "(ノ°ο°)ノ", 55 | "text": "前方高能预警" 56 | }, 57 | { 58 | "icon": "(´இ皿இ`)", 59 | "text": "我从未见过如此厚颜无耻之人" 60 | }, 61 | { 62 | "icon": "⌇●﹏●⌇", 63 | "text": "吓死宝宝惹" 64 | }, 65 | { 66 | "icon": "(ฅ´ω`ฅ)", 67 | "text": "已阅留爪" 68 | }, 69 | { 70 | "icon": "(╯°A°)╯︵○○○", 71 | "text": "去吧大师球" 72 | }, 73 | { 74 | "icon": "φ( ̄∇ ̄o)", 75 | "text": "太萌惹" 76 | }, 77 | { 78 | "icon": "ヾ(´・ ・`。)ノ\"", 79 | "text": "咦咦咦" 80 | }, 81 | { 82 | "icon": "( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃", 83 | "text": "气呼呼" 84 | }, 85 | { 86 | "icon": "(ó﹏ò。)", 87 | "text": "我受到了惊吓" 88 | }, 89 | { 90 | "icon": "Σ(っ °Д °;)っ", 91 | "text": "什么鬼" 92 | }, 93 | { 94 | "icon": "( ,,´・ω・)ノ\"(´っω・`。)", 95 | "text": "摸摸头" 96 | }, 97 | { 98 | "icon": "╮(╯▽╰)╭ ", 99 | "text": "无奈" 100 | }, 101 | { 102 | "icon": "o(*////▽////*)q ", 103 | "text": "脸红" 104 | }, 105 | { 106 | "icon": ">﹏<", 107 | "text": "" 108 | }, 109 | { 110 | "icon": "( ๑´•ω•) \"(ㆆᴗㆆ)", 111 | "text": "" 112 | }, 113 | { 114 | "icon": "(。•ˇ‸ˇ•。)", 115 | "text": "" 116 | } 117 | ] 118 | }, 119 | "emoji": { 120 | "type": "emoji", 121 | "container": [ 122 | { 123 | "icon": "😂", 124 | "text": "" 125 | }, 126 | { 127 | "icon": "😀", 128 | "text": "" 129 | }, 130 | { 131 | "icon": "😅", 132 | "text": "" 133 | }, 134 | { 135 | "icon": "😊", 136 | "text": "" 137 | }, 138 | { 139 | "icon": "🙂", 140 | "text": "" 141 | }, 142 | { 143 | "icon": "🙃", 144 | "text": "" 145 | }, 146 | { 147 | "icon": "😌", 148 | "text": "" 149 | }, 150 | { 151 | "icon": "😍", 152 | "text": "" 153 | }, 154 | { 155 | "icon": "😘 ", 156 | "text": "" 157 | }, 158 | { 159 | "icon": "😜", 160 | "text": "" 161 | }, 162 | { 163 | "icon": "😝", 164 | "text": "" 165 | }, 166 | { 167 | "icon": "😏", 168 | "text": "" 169 | }, 170 | { 171 | "icon": "😒", 172 | "text": "" 173 | }, 174 | { 175 | "icon": "🙄", 176 | "text": "" 177 | }, 178 | { 179 | "icon": "😳 ", 180 | "text": "" 181 | }, 182 | { 183 | "icon": "😡", 184 | "text": "" 185 | }, 186 | { 187 | "icon": "😔", 188 | "text": "" 189 | }, 190 | { 191 | "icon": "😫", 192 | "text": "" 193 | }, 194 | { 195 | "icon": "😱", 196 | "text": "" 197 | }, 198 | { 199 | "icon": "😭", 200 | "text": "" 201 | }, 202 | { 203 | "icon": "💩", 204 | "text": "" 205 | }, 206 | { 207 | "icon": "👻", 208 | "text": "" 209 | }, 210 | { 211 | "icon": "🙌", 212 | "text": "" 213 | }, 214 | { 215 | "icon": "🖕", 216 | "text": "" 217 | }, 218 | { 219 | "icon": "👍", 220 | "text": "" 221 | }, 222 | { 223 | "icon": "👫", 224 | "text": "" 225 | }, 226 | { 227 | "icon": "👬", 228 | "text": "" 229 | }, 230 | { 231 | "icon": "👭", 232 | "text": "" 233 | }, 234 | { 235 | "icon": "🌚", 236 | "text": "" 237 | }, 238 | { 239 | "icon": "🌝", 240 | "text": "" 241 | }, 242 | { 243 | "icon": "🙈", 244 | "text": "" 245 | }, 246 | { 247 | "icon": "💊", 248 | "text": "" 249 | }, 250 | { 251 | "icon": "😶", 252 | "text": "" 253 | }, 254 | { 255 | "icon": "🙏", 256 | "text": "" 257 | }, 258 | { 259 | "icon": "🍦", 260 | "text": "" 261 | }, 262 | { 263 | "icon": "🍉", 264 | "text": "" 265 | }, 266 | { 267 | "icon": "😣", 268 | "text": "" 269 | } 270 | ] 271 | }, 272 | "斗图模式": { 273 | "type": "image", 274 | "container": [ 275 | { 276 | "icon": "", 277 | "text": "face1" 278 | }, 279 | { 280 | "icon": "", 281 | "text": "face2" 282 | }, 283 | { 284 | "icon": "", 285 | "text": "face3" 286 | }, 287 | { 288 | "icon": "", 289 | "text": "face4" 290 | }, 291 | { 292 | "icon": "", 293 | "text": "face5" 294 | }, 295 | { 296 | "icon": "", 297 | "text": "face6" 298 | }, 299 | { 300 | "icon": "", 301 | "text": "face7" 302 | }, 303 | { 304 | "icon": "", 305 | "text": "face8" 306 | }, 307 | { 308 | "icon": "", 309 | "text": "face9" 310 | }, 311 | { 312 | "icon": "", 313 | "text": "face10" 314 | }, 315 | { 316 | "icon": "", 317 | "text": "face11" 318 | }, 319 | { 320 | "icon": "", 321 | "text": "face12" 322 | }, 323 | { 324 | "icon": "", 325 | "text": "face13" 326 | }, 327 | { 328 | "icon": "", 329 | "text": "face14" 330 | }, 331 | { 332 | "icon": "", 333 | "text": "face15" 334 | }, 335 | { 336 | "icon": "", 337 | "text": "face16" 338 | }, 339 | { 340 | "icon": "", 341 | "text": "face17" 342 | }, 343 | { 344 | "icon": "", 345 | "text": "face18" 346 | }, 347 | { 348 | "icon": "", 349 | "text": "face19" 350 | }, 351 | { 352 | "icon": "", 353 | "text": "face20" 354 | }, 355 | { 356 | "icon": "", 357 | "text": "face21" 358 | }, 359 | { 360 | "icon": "", 361 | "text": "face22" 362 | }, 363 | { 364 | "icon": "", 365 | "text": "face23" 366 | }, 367 | { 368 | "icon": "", 369 | "text": "face24" 370 | }, 371 | { 372 | "icon": "", 373 | "text": "face25" 374 | }, 375 | { 376 | "icon": "", 377 | "text": "face26" 378 | }, 379 | { 380 | "icon": "", 381 | "text": "face27" 382 | }, 383 | { 384 | "icon": "", 385 | "text": "face28" 386 | } 387 | ] 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /public/js/Reconnect.js: -------------------------------------------------------------------------------- 1 | !function(a,b){"function"==typeof define&&define.amd?define([],b):"undefined"!=typeof module&&module.exports?module.exports=b():a.ReconnectingWebSocket=b()}(this,function(){function a(b,c,d){function l(a,b){var c=document.createEvent("CustomEvent");return c.initCustomEvent(a,!1,!1,b),c}var e={debug:!1,automaticOpen:!0,reconnectInterval:1e3,maxReconnectInterval:3e4,reconnectDecay:1.5,timeoutInterval:2e3};d||(d={});for(var f in e)this[f]="undefined"!=typeof d[f]?d[f]:e[f];this.url=b,this.reconnectAttempts=0,this.readyState=WebSocket.CONNECTING,this.protocol=null;var h,g=this,i=!1,j=!1,k=document.createElement("div");k.addEventListener("open",function(a){g.onopen(a)}),k.addEventListener("close",function(a){g.onclose(a)}),k.addEventListener("connecting",function(a){g.onconnecting(a)}),k.addEventListener("message",function(a){g.onmessage(a)}),k.addEventListener("error",function(a){g.onerror(a)}),this.addEventListener=k.addEventListener.bind(k),this.removeEventListener=k.removeEventListener.bind(k),this.dispatchEvent=k.dispatchEvent.bind(k),this.open=function(b){h=new WebSocket(g.url,c||[]),b||k.dispatchEvent(l("connecting")),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","attempt-connect",g.url);var d=h,e=setTimeout(function(){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","connection-timeout",g.url),j=!0,d.close(),j=!1},g.timeoutInterval);h.onopen=function(){clearTimeout(e),(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onopen",g.url),g.protocol=h.protocol,g.readyState=WebSocket.OPEN,g.reconnectAttempts=0;var d=l("open");d.isReconnect=b,b=!1,k.dispatchEvent(d)},h.onclose=function(c){if(clearTimeout(e),h=null,i)g.readyState=WebSocket.CLOSED,k.dispatchEvent(l("close"));else{g.readyState=WebSocket.CONNECTING;var d=l("connecting");d.code=c.code,d.reason=c.reason,d.wasClean=c.wasClean,k.dispatchEvent(d),b||j||((g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onclose",g.url),k.dispatchEvent(l("close")));var e=g.reconnectInterval*Math.pow(g.reconnectDecay,g.reconnectAttempts);setTimeout(function(){g.reconnectAttempts++,g.open(!0)},e>g.maxReconnectInterval?g.maxReconnectInterval:e)}},h.onmessage=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onmessage",g.url,b.data);var c=l("message");c.data=b.data,k.dispatchEvent(c)},h.onerror=function(b){(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","onerror",g.url,b),k.dispatchEvent(l("error"))}},1==this.automaticOpen&&this.open(!1),this.send=function(b){if(h)return(g.debug||a.debugAll)&&console.debug("ReconnectingWebSocket","send",g.url,b),h.send(b);throw"INVALID_STATE_ERR : Pausing to reconnect websocket"},this.close=function(a,b){"undefined"==typeof a&&(a=1e3),i=!0,h&&h.close(a,b)},this.refresh=function(){h&&h.close()}}return a.prototype.onopen=function(){},a.prototype.onclose=function(){},a.prototype.onconnecting=function(){},a.prototype.onmessage=function(){},a.prototype.onerror=function(){},a.debugAll=!1,a.CONNECTING=WebSocket.CONNECTING,a.OPEN=WebSocket.OPEN,a.CLOSING=WebSocket.CLOSING,a.CLOSED=WebSocket.CLOSED,a}); -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | allow: / -------------------------------------------------------------------------------- /route/web.php: -------------------------------------------------------------------------------- 1 | group('/', function() { 6 | $this->get('/', [new RoomController, 'index']); 7 | 8 | $this->get('/login', [new RoomController, 'login']); 9 | 10 | $this->get('/logout', [new RoomController, 'logout']); 11 | 12 | $this->get('/room', [new RoomController, 'room']); 13 | }); 14 | -------------------------------------------------------------------------------- /run.php: -------------------------------------------------------------------------------- 1 | /dev/null 2>&1 & 3 | --------------------------------------------------------------------------------