├── .gitignore ├── LICENSE ├── README.md ├── TestHelper.php ├── composer.json ├── do.sh ├── phpunit.xml ├── src ├── Core │ ├── Client.php │ └── Server.php └── Helpers │ ├── magics.php │ ├── starter.php │ ├── swoole.php │ └── timers.php └── tests ├── ClientTest.php └── application └── controllers └── tests └── Test.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .DS_Store 3 | .idea 4 | composer.lock 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 lanlin 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Codeigniter Swoole Adapter 3 | 4 | You want long-run task? timers? FPM to CLI? Code reusing in both FPM & CLI mode? 5 | 6 | "It's so easy!" 7 | 8 | This adapter would make it so easy to using swoole within Codeigniter framework. 9 | 10 | With this adapter, you can start a task(CLI) any where(FPM) you want from your code. 11 | 12 | That's means you can start a CLI task from a FPM process. 13 | 14 | 15 | ## Install 16 | 17 | ```shell 18 | composer require lanlin/codeigniter-swoole 19 | ``` 20 | 21 | 22 | ## How to 23 | 24 | 1. first, of course you must install `codeigniter-swoole` to your codeigniter project. 25 | 2. (this step is option) copy these two config files `swoole.php` and `timers.php` from `src/Helper` to your `application/config` folder. 26 | 3. start swoole server `php index.php swoole/server/start` 27 | 4. you can use `\CiSwoole\Core\Client::send($data)` to start a task now! 28 | 5. there's no step 5. 29 | 30 | 31 | ## What is a task? 32 | A task is just a method of your codeigniter controlloer, so almost any controller method can be used as a task. 33 | 34 | Let's see the code 35 | 36 | ```php 37 | \CiSwoole\Core\Client::send( 38 | [ 39 | 'route' => 'your/route/uri/to/a/method' 40 | 'params' => ['test' => 666] 41 | ]); 42 | ``` 43 | 44 | The `route` is used for find which method to be call as a task, and `params` is the parameters array that you may want to pass to the task. 45 | 46 | So, that's all of it! 47 | 48 | 49 | ## Server CLI Commands 50 | 51 | ```shell 52 | 53 | // start the swoole server 54 | php index.php swoole/server/start 55 | 56 | // stop the swoole server 57 | php index.php swoole/server/stop 58 | 59 | // reload all wokers of swoole server 60 | php index.php swoole/server/reload 61 | 62 | ``` 63 | 64 | 65 | ## A little more 66 | 67 | The step 2 copied files were config files for this adapter. 68 | 69 | `swoole.php` file can set host, port, log file and so on. 70 | 71 | `timers.php` file can set some timer methods for swoole server, these timers will be started once the server inited. 72 | 73 | You can copy `tests/application` to your `application` for testing. The demos are same as below shows. 74 | 75 | 76 | ```php 77 | class Test extends CI_Controller 78 | { 79 | 80 | // ------------------------------------------------------------------------------ 81 | 82 | /** 83 | * here's the task 'tests/test/task' 84 | */ 85 | public function task() 86 | { 87 | $data = $this->input->post(); // as you see, params worked like normally post data 88 | 89 | log_message('info', var_export($data, true)); 90 | } 91 | 92 | // ------------------------------------------------------------------------------ 93 | 94 | /** 95 | * here's the timer method 96 | * 97 | * you should copay timers.php to your config folder, 98 | * then add $timers['tests/test/task_timer'] = 10000; and start the swoole server. 99 | * 100 | * this method would be called every 10 seconds per time. 101 | */ 102 | public function task_timer() 103 | { 104 | log_message('info', 'timer works!'); 105 | } 106 | 107 | // ------------------------------------------------------------------------------ 108 | 109 | /** 110 | * send data to task 111 | */ 112 | public function send() 113 | { 114 | try 115 | { 116 | \CiSwoole\Core\Client::send( 117 | [ 118 | 'route' => 'tests/test/task', 119 | 'params' => ['hope' => 'it works!'], 120 | ]); 121 | } 122 | catch (\Exception $e) 123 | { 124 | log_message('error', $e->getMessage()); 125 | log_message('error', $e->getTraceAsString()); 126 | } 127 | } 128 | 129 | // ------------------------------------------------------------------------------ 130 | 131 | } 132 | ``` 133 | 134 | 135 | ## License 136 | 137 | This project is licensed under the MIT license. 138 | 139 | ## 补充说明 140 | [codeigniter-swoole 的主要应用场景](https://github.com/lanlin/codeigniter-swoole/issues/4) 141 | -------------------------------------------------------------------------------- /TestHelper.php: -------------------------------------------------------------------------------- 1 | =5.6", 17 | "ext-swoole": "^4.0.0" 18 | }, 19 | "require-dev": { 20 | "phpunit/phpunit": "^8.2", 21 | "swoole/ide-helper": "@dev" 22 | }, 23 | "autoload": { 24 | "files": [ "src/Helpers/magics.php" ], 25 | "psr-4": { 26 | "CiSwoole\\": "src/", 27 | "CiSwooleTests\\": "tests/" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /do.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo =================================================== 4 | echo Start Testing... 5 | echo =================================================== 6 | 7 | phpdbg -qrr ./vendor/bin/phpunit $1 $2 $3 $4 $5 -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | ./tests 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Core/Client.php: -------------------------------------------------------------------------------- 1 | '☯', // \u262F 26 | 'server_port' => null, 27 | 'server_host' => '/var/run/swoole.sock', 28 | 'server_type' => SWOOLE_SOCK_UNIX_STREAM, 29 | 'debug_file' => APPPATH . 'logs/swoole_debug.log', 30 | ]; 31 | 32 | // ------------------------------------------------------------------------------ 33 | 34 | /** 35 | * connect to swoole server then send data 36 | * 37 | * @param array $data 38 | * [ 39 | * 'route' => 'your/route/uri', // the route uri will be call 40 | * 'params' => [], // params will be passed to your method 41 | * ]; 42 | */ 43 | public static function send(array $data) 44 | { 45 | self::initConfig(); 46 | 47 | // select mode 48 | $sapi = php_sapi_name(); 49 | $mode = ($sapi === 'cli') ? SWOOLE_SOCK_ASYNC : SWOOLE_SOCK_SYNC; 50 | 51 | /** 52 | * @property array $stamsel 53 | */ 54 | $client = new \Swoole\Client(self::$config['server_type'], $mode); 55 | 56 | // dynamic custom data 57 | $client->CiSwooleData = $data; 58 | 59 | // set eof charactor 60 | $client->set( 61 | [ 62 | 'open_eof_split' => true, 63 | 'package_eof' => self::$config['package_eof'], 64 | ]); 65 | 66 | // client init 67 | ($mode === SWOOLE_SOCK_ASYNC) ? self::asyncInit($client) : self::syncInit($client); 68 | } 69 | 70 | // ------------------------------------------------------------------------------ 71 | 72 | /** 73 | * reload swoole server 74 | */ 75 | public static function reload() 76 | { 77 | self::send(['reload' => true]); 78 | } 79 | 80 | // ------------------------------------------------------------------------------ 81 | 82 | /** 83 | * shutdown swoole server 84 | */ 85 | public static function shutdown() 86 | { 87 | self::send(['shutdown' => true]); 88 | } 89 | 90 | // ------------------------------------------------------------------------------ 91 | 92 | /** 93 | * trigger when connect 94 | * 95 | * @param \Swoole\Client $client 96 | */ 97 | public static function onConnect(\Swoole\Client $client) 98 | { 99 | $post = serialize($client->CiSwooleData); 100 | $post .= self::$config['package_eof']; 101 | 102 | $client->send($post); 103 | } 104 | 105 | // ------------------------------------------------------------------------------ 106 | 107 | /** 108 | * trigger on error 109 | * 110 | * @param \Swoole\Client $client 111 | */ 112 | public static function onError(\Swoole\Client $client) 113 | { 114 | $msg = "swoole client error code: {$client->errCode}"; 115 | 116 | error_log($msg, 3, self::$config['debug_file']); 117 | } 118 | 119 | // ------------------------------------------------------------------------------ 120 | 121 | /** 122 | * trigger on buffer empty 123 | * 124 | * @param \Swoole\Client $client 125 | */ 126 | public static function onBufferEmpty(\Swoole\Client $client) 127 | { 128 | $client->close(); 129 | } 130 | 131 | // ------------------------------------------------------------------------------ 132 | 133 | /** 134 | * trigger when receive 135 | * 136 | * @param \Swoole\Client $client 137 | * @param string $data 138 | */ 139 | public static function onReceive(\Swoole\Client $client, $data) 140 | { 141 | return; 142 | } 143 | 144 | // ------------------------------------------------------------------------------ 145 | 146 | /** 147 | * trigger when close 148 | * 149 | * @param \Swoole\Client $client 150 | */ 151 | public static function onClose(\Swoole\Client $client) 152 | { 153 | return; 154 | } 155 | 156 | // ------------------------------------------------------------------------------ 157 | 158 | /** 159 | * init config 160 | * 161 | * @throws \Exception 162 | */ 163 | private static function initConfig() 164 | { 165 | $config = getCiSwooleConfig('swoole'); 166 | 167 | self::$config = array_merge(self::$config, $config); 168 | } 169 | 170 | // ------------------------------------------------------------------------------ 171 | 172 | /** 173 | * async mode init 174 | * 175 | * @param \Swoole\Client $client 176 | */ 177 | private static function asyncInit(\Swoole\Client $client) 178 | { 179 | // event listener 180 | $client->on('Close', [Client::class, 'onClose']); 181 | $client->on('Error', [Client::class, 'onError']); 182 | $client->on('Connect', [Client::class, 'onConnect']); 183 | $client->on('Receive', [Client::class, 'onReceive']); 184 | $client->on('BufferEmpty', [Client::class, 'onBufferEmpty']); 185 | 186 | // connect server 187 | $client->connect(self::$config['server_host'], self::$config['server_port']); 188 | } 189 | 190 | // ------------------------------------------------------------------------------ 191 | 192 | /** 193 | * sync mode init 194 | * 195 | * @param \Swoole\Client $client 196 | */ 197 | private static function syncInit(\Swoole\Client $client) 198 | { 199 | $cnnt = $client->connect(self::$config['server_host'], self::$config['server_port']); 200 | 201 | if (!$cnnt) 202 | { 203 | $msg = "swoole client error code: {$client->errCode}"; 204 | 205 | error_log($msg, 3, self::$config['debug_file']); 206 | return; 207 | } 208 | 209 | $post = serialize($client->CiSwooleData); 210 | $post .= self::$config['package_eof']; 211 | $check = $client->send($post); 212 | 213 | if ($check === false) 214 | { 215 | $msg = "swoole client error code: {$client->errCode}"; 216 | 217 | error_log($msg, 3, self::$config['debug_file']); 218 | } 219 | 220 | $client->close(); 221 | } 222 | 223 | // ------------------------------------------------------------------------------ 224 | 225 | } 226 | -------------------------------------------------------------------------------- /src/Core/Server.php: -------------------------------------------------------------------------------- 1 | null, 24 | 'server_host' => '/var/run/swoole.sock', 25 | 'server_type' => SWOOLE_SOCK_UNIX_STREAM, 26 | 'debug_file' => APPPATH . 'logs/swoole_debug.log', 27 | ]; 28 | 29 | // ------------------------------------------------------------------------------ 30 | 31 | /** 32 | * server config 33 | * 34 | * warning: do not change this 35 | * 36 | * @var array 37 | */ 38 | private static $config = 39 | [ 40 | 'daemonize' => true, // using as daemonize? 41 | 'package_eof' => '☯', // \u262F 42 | 'reload_async' => true, 43 | 'open_eof_split' => true, 44 | 'open_eof_check' => true, 45 | ]; 46 | 47 | // ------------------------------------------------------------------------------ 48 | 49 | /** 50 | * start a swoole server in cli 51 | * 52 | * @return mixed 53 | */ 54 | public static function start() 55 | { 56 | self::initConfig(); 57 | 58 | $serv = new \Swoole\Server 59 | ( 60 | self::$cfgs['server_host'], 61 | self::$cfgs['server_port'], 62 | SWOOLE_PROCESS, 63 | self::$cfgs['server_type'] 64 | ); 65 | 66 | // init config 67 | $serv->set(self::$config); 68 | 69 | // listen on server init 70 | $serv->on('ManagerStart', [Server::class, 'onManagerStart']); 71 | $serv->on('WorkerStart', [Server::class, 'onWorkerStart']); 72 | $serv->on('Start', [Server::class, 'onMasterStart']); 73 | 74 | // listen on base event 75 | $serv->on('Connect', [Server::class, 'onConnect']); 76 | $serv->on('Receive', [Server::class, 'onReceive']); 77 | $serv->on('Finish', [Server::class, 'onFinish']); 78 | $serv->on('Close', [Server::class, 'onClose']); 79 | $serv->on('Task', [Server::class, 'onTask']); 80 | 81 | // start server 82 | return $serv->start(); 83 | } 84 | 85 | // ------------------------------------------------------------------------------ 86 | 87 | /** 88 | * listen on master start 89 | * 90 | * @param \Swoole\Server $serv 91 | */ 92 | public static function onMasterStart(\Swoole\Server $serv) 93 | { 94 | if (self::$cfgs['server_port'] === null) 95 | { 96 | @chmod(self::$cfgs['server_host'], 0777); 97 | } 98 | 99 | @swoole_set_process_name($serv->setting['process_name'].'-MASTER'); 100 | 101 | $msg = "SWOOLE MASTER: {$serv->manager_pid}\n"; 102 | 103 | error_log($msg, 3, self::$cfgs['debug_file']); 104 | } 105 | 106 | // ------------------------------------------------------------------------------ 107 | 108 | /** 109 | * listen on manager start 110 | * 111 | * @param \Swoole\Server $serv 112 | */ 113 | public static function onManagerStart(\Swoole\Server $serv) 114 | { 115 | @swoole_set_process_name($serv->setting['process_name'].'-MANAGER'); 116 | 117 | $msg = "SWOOLE MANAGER: {$serv->manager_pid}\n"; 118 | 119 | error_log($msg, 3, self::$cfgs['debug_file']); 120 | } 121 | 122 | // ------------------------------------------------------------------------------ 123 | 124 | /** 125 | * listen on workers start & set timers 126 | * 127 | * @param \Swoole\Server $serv 128 | * @param int $workerId 129 | */ 130 | public static function onWorkerStart(\Swoole\Server $serv, $workerId) 131 | { 132 | // set process name 133 | ($workerId >= $serv->setting['worker_num']) ? 134 | @swoole_set_process_name($serv->setting['process_name'].'-TASK') : 135 | @swoole_set_process_name($serv->setting['process_name'].'-WORKER'); 136 | 137 | // when task start, return 138 | if ($serv->taskworker) { return; } 139 | 140 | // init all timers 141 | self::initTimers($serv); 142 | } 143 | 144 | // ------------------------------------------------------------------------------ 145 | 146 | /** 147 | * listen on receive data 148 | * 149 | * @param \Swoole\Server $serv 150 | * @param int $fd 151 | * @param int $reactorId 152 | * @param string $data 153 | */ 154 | public static function onReceive(\Swoole\Server $serv, $fd, $reactorId, $data = '') 155 | { 156 | // close client 157 | $serv->close($fd); 158 | 159 | // format passed 160 | $data = str_replace(self::$config['package_eof'], '', $data); 161 | $data = unserialize($data); 162 | 163 | if (!$data) { return; } 164 | 165 | // check is command 166 | if(!empty($data['shutdown'])) 167 | { 168 | $serv->shutdown(); 169 | return; 170 | } 171 | 172 | // reload command 173 | if (!empty($data['reload'])) 174 | { 175 | $serv->reload(); 176 | return; 177 | } 178 | 179 | // start a task 180 | $serv->task($data); 181 | } 182 | 183 | // ------------------------------------------------------------------------------ 184 | 185 | /** 186 | * listen on task 187 | * 188 | * @param \Swoole\Server $serv 189 | * @param int $taskId 190 | * @param int $workerId 191 | * @param array $data 192 | */ 193 | public static function onTask(\Swoole\Server $serv, $taskId, $workerId, $data) 194 | { 195 | try 196 | { 197 | $_SERVER['argv'] = 198 | [ 199 | 0 => SELF, 200 | 1 => $data['route'], 201 | ]; 202 | 203 | $_POST = $data['params'] ?? []; 204 | 205 | getCiSwooleConfig('starter'); 206 | } 207 | 208 | // kill process 209 | catch (\Throwable $e) { self::logs($e); } 210 | finally { \Swoole\Process::kill(getmypid()); } 211 | } 212 | 213 | // ------------------------------------------------------------------------------ 214 | 215 | /** 216 | * listen on connect 217 | * 218 | * @param \Swoole\Server $serv 219 | * @param int $fd 220 | */ 221 | public static function onConnect(\Swoole\Server $serv, $fd) 222 | { 223 | return; 224 | } 225 | 226 | // ------------------------------------------------------------------------------ 227 | 228 | /** 229 | * listen on close 230 | * 231 | * @param \Swoole\Server $serv 232 | * @param int $fd 233 | */ 234 | public static function onClose(\Swoole\Server $serv, $fd) 235 | { 236 | return; 237 | } 238 | 239 | // ------------------------------------------------------------------------------ 240 | 241 | /** 242 | * listen on task finish 243 | * 244 | * @param \Swoole\Server $serv 245 | * @param int $taskId 246 | * @param mixed $data 247 | */ 248 | public static function onFinish(\Swoole\Server $serv, $taskId, $data) 249 | { 250 | return; 251 | } 252 | 253 | // ------------------------------------------------------------------------------ 254 | 255 | /** 256 | * init config 257 | * 258 | * @throws \Exception 259 | */ 260 | private static function initConfig() 261 | { 262 | $config = getCiSwooleConfig('swoole'); 263 | 264 | self::$cfgs['debug_file'] = $config['debug_file']; 265 | self::$cfgs['server_host'] = $config['server_host']; 266 | self::$cfgs['server_port'] = $config['server_port']; 267 | self::$cfgs['server_type'] = $config['server_type']; 268 | 269 | unset( 270 | $config['debug_file'], $config['server_host'], 271 | $config['server_port'], $config['server_type'], 272 | ); 273 | 274 | self::$config = array_merge($config, self::$config); 275 | } 276 | 277 | // ------------------------------------------------------------------------------ 278 | 279 | /** 280 | * log message to debug 281 | * 282 | * @param \Throwable $msg 283 | */ 284 | private static function logs(\Throwable $msg) 285 | { 286 | $strings = $msg->getMessage() . "\n"; 287 | $strings .= $msg->getTraceAsString(); 288 | 289 | $time_nw = date('Y-m-d H:i:s'); 290 | $content = "\n== {$time_nw} ============================\n"; 291 | $content .= "{$strings}"; 292 | $content .= "\n===================================================\n\n"; 293 | 294 | error_log($content, 3, self::$cfgs['debug_file']); 295 | } 296 | 297 | // ------------------------------------------------------------------------------ 298 | 299 | /** 300 | * init timers for stamsel 301 | * 302 | * @param \Swoole\Server $serv 303 | */ 304 | private static function initTimers(\Swoole\Server $serv) 305 | { 306 | try 307 | { 308 | $timers = getCiSwooleConfig('timers'); 309 | 310 | foreach ($timers as $route => $microSeconds) 311 | { 312 | $data = 313 | [ 314 | 'route' => $route, 315 | 'params' => [], 316 | ]; 317 | 318 | $serv->tick($microSeconds, function () use ($serv, $data) 319 | { 320 | $stats = $serv->stats(); 321 | 322 | if ($stats['tasking_num'] < 4) { $serv->task($data); } 323 | }); 324 | } 325 | } 326 | 327 | catch (\Throwable $e) { self::logs($e); } 328 | finally { unset($timers); } 329 | } 330 | 331 | // ------------------------------------------------------------------------------ 332 | 333 | } 334 | -------------------------------------------------------------------------------- /src/Helpers/magics.php: -------------------------------------------------------------------------------- 1 | getMessage()}\n"; 64 | $log .= "{$e->getTraceAsString()}\n"; 65 | 66 | die("Operation Failed.\n{$log}"); 67 | } 68 | } 69 | 70 | // ------------------------------------------------------------------------------ 71 | 72 | /** 73 | * Let's start perform magic tricks 74 | */ 75 | ____intercepter____(); 76 | 77 | // ------------------------------------------------------------------------------ 78 | -------------------------------------------------------------------------------- /src/Helpers/starter.php: -------------------------------------------------------------------------------- 1 | mark('total_execution_time_start'); 18 | $BM->mark('loading_time:_base_classes_start'); 19 | /* 20 | * ------------------------------------------------------ 21 | * Instantiate the config class 22 | * ------------------------------------------------------ 23 | * 24 | * Note: It is important that Config is loaded first as 25 | * most other classes depend on it either directly or by 26 | * depending on another class that uses it. 27 | * 28 | */ 29 | $CFG =& load_class('Config', 'core'); 30 | // Do we have any manually set config items in the index.php file? 31 | if (isset($assign_to_config) && is_array($assign_to_config)) 32 | { 33 | foreach ($assign_to_config as $key => $value) 34 | { 35 | $CFG->set_item($key, $value); 36 | } 37 | } 38 | /* 39 | * ------------------------------------------------------ 40 | * Instantiate the hooks class 41 | * ------------------------------------------------------ 42 | */ 43 | $EXT =& load_class('Hooks', 'core', $CFG); 44 | /* 45 | * ------------------------------------------------------ 46 | * Is there a "pre_system" hook? 47 | * ------------------------------------------------------ 48 | */ 49 | $EXT->call_hook('pre_system'); 50 | /* 51 | * ------------------------------------------------------ 52 | * Important charset-related stuff 53 | * ------------------------------------------------------ 54 | * 55 | * Configure mbstring and/or iconv if they are enabled 56 | * and set MB_ENABLED and ICONV_ENABLED constants, so 57 | * that we don't repeatedly do extension_loaded() or 58 | * function_exists() calls. 59 | * 60 | * Note: UTF-8 class depends on this. It used to be done 61 | * in it's constructor, but it's _not_ class-specific. 62 | * 63 | */ 64 | $charset = strtoupper(config_item('charset')); 65 | ini_set('default_charset', $charset); 66 | if (extension_loaded('mbstring')) 67 | { 68 | !defined('MB_ENABLED') AND define('MB_ENABLED', TRUE); 69 | // mbstring.internal_encoding is deprecated starting with PHP 5.6 70 | // and it's usage triggers E_DEPRECATED messages. 71 | @ini_set('mbstring.internal_encoding', $charset); 72 | // This is required for mb_convert_encoding() to strip invalid characters. 73 | // That's utilized by CI_Utf8, but it's also done for consistency with iconv. 74 | mb_substitute_character('none'); 75 | } 76 | else 77 | { 78 | !defined('MB_ENABLED') AND define('MB_ENABLED', FALSE); 79 | } 80 | // There's an ICONV_IMPL constant, but the PHP manual says that using 81 | // iconv's predefined constants is "strongly discouraged". 82 | if (extension_loaded('iconv')) 83 | { 84 | !defined('ICONV_ENABLED') AND define('ICONV_ENABLED', TRUE); 85 | // iconv.internal_encoding is deprecated starting with PHP 5.6 86 | // and it's usage triggers E_DEPRECATED messages. 87 | @ini_set('iconv.internal_encoding', $charset); 88 | } 89 | else 90 | { 91 | !defined('ICONV_ENABLED') AND define('ICONV_ENABLED', FALSE); 92 | } 93 | if (is_php('5.6')) 94 | { 95 | ini_set('php.internal_encoding', $charset); 96 | } 97 | /* 98 | * ------------------------------------------------------ 99 | * Load compatibility features 100 | * ------------------------------------------------------ 101 | */ 102 | require_once(BASEPATH.'core/compat/mbstring.php'); 103 | require_once(BASEPATH.'core/compat/hash.php'); 104 | require_once(BASEPATH.'core/compat/password.php'); 105 | require_once(BASEPATH.'core/compat/standard.php'); 106 | /* 107 | * ------------------------------------------------------ 108 | * Instantiate the UTF-8 class 109 | * ------------------------------------------------------ 110 | */ 111 | $UNI =& load_class('Utf8', 'core', $charset); 112 | /* 113 | * ------------------------------------------------------ 114 | * Instantiate the URI class 115 | * ------------------------------------------------------ 116 | */ 117 | $URI =& load_class('URI', 'core', $CFG); 118 | /* 119 | * ------------------------------------------------------ 120 | * Instantiate the routing class and set the routing 121 | * ------------------------------------------------------ 122 | */ 123 | $RTR =& load_class('Router', 'core', isset($routing) ? $routing : NULL); 124 | /* 125 | * ------------------------------------------------------ 126 | * Instantiate the output class 127 | * ------------------------------------------------------ 128 | */ 129 | $OUT =& load_class('Output', 'core'); 130 | /* 131 | * ------------------------------------------------------ 132 | * Is there a valid cache file? If so, we're done... 133 | * ------------------------------------------------------ 134 | */ 135 | if ($EXT->call_hook('cache_override') === FALSE && $OUT->_display_cache($CFG, $URI) === TRUE) 136 | { 137 | exit; 138 | } 139 | /* 140 | * ----------------------------------------------------- 141 | * Load the security class for xss and csrf support 142 | * ----------------------------------------------------- 143 | */ 144 | $SEC =& load_class('Security', 'core', $charset); 145 | /* 146 | * ------------------------------------------------------ 147 | * Load the Input class and sanitize globals 148 | * ------------------------------------------------------ 149 | */ 150 | $IN =& load_class('Input', 'core', $SEC); 151 | /* 152 | * ------------------------------------------------------ 153 | * Load the Language class 154 | * ------------------------------------------------------ 155 | */ 156 | $LANG =& load_class('Lang', 'core'); 157 | /* 158 | * ------------------------------------------------------ 159 | * Load the app controller and local controller 160 | * ------------------------------------------------------ 161 | * 162 | */ 163 | // Load the base controller class 164 | require_once BASEPATH.'core/Controller.php'; 165 | /** 166 | * Reference to the CI_Controller method. 167 | * 168 | * Returns current CI instance object 169 | * 170 | * @return CI_Controller 171 | */ 172 | if (! function_exists('get_instance')) // check 173 | { 174 | function &get_instance() 175 | { 176 | return CI_Controller::get_instance(); 177 | } 178 | } 179 | if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php')) 180 | { 181 | require_once APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; 182 | } 183 | // Set a mark point for benchmarking 184 | $BM->mark('loading_time:_base_classes_end'); 185 | /* 186 | * ------------------------------------------------------ 187 | * Sanity checks 188 | * ------------------------------------------------------ 189 | * 190 | * The Router class has already validated the request, 191 | * leaving us with 3 options here: 192 | * 193 | * 1) an empty class name, if we reached the default 194 | * controller, but it didn't exist; 195 | * 2) a query string which doesn't go through a 196 | * file_exists() check 197 | * 3) a regular request for a non-existing page 198 | * 199 | * We handle all of these as a 404 error. 200 | * 201 | * Furthermore, none of the methods in the app controller 202 | * or the loader class can be called via the URI, nor can 203 | * controller methods that begin with an underscore. 204 | */ 205 | $e404 = FALSE; 206 | $class = ucfirst($RTR->class); 207 | $method = $RTR->method; 208 | if (empty($class) OR ! file_exists(APPPATH.'controllers/'.$RTR->directory.$class.'.php')) 209 | { 210 | $e404 = TRUE; 211 | } 212 | else 213 | { 214 | require_once(APPPATH.'controllers/'.$RTR->directory.$class.'.php'); 215 | if ( ! class_exists($class, FALSE) OR $method[0] === '_' OR method_exists('CI_Controller', $method)) 216 | { 217 | $e404 = TRUE; 218 | } 219 | elseif (method_exists($class, '_remap')) 220 | { 221 | $params = array($method, array_slice($URI->rsegments, 2)); 222 | $method = '_remap'; 223 | } 224 | elseif ( ! method_exists($class, $method)) 225 | { 226 | $e404 = TRUE; 227 | } 228 | /** 229 | * DO NOT CHANGE THIS, NOTHING ELSE WORKS! 230 | * 231 | * - method_exists() returns true for non-public methods, which passes the previous elseif 232 | * - is_callable() returns false for PHP 4-style constructors, even if there's a __construct() 233 | * - method_exists($class, '__construct') won't work because CI_Controller::__construct() is inherited 234 | * - People will only complain if this doesn't work, even though it is documented that it shouldn't. 235 | * 236 | * ReflectionMethod::isConstructor() is the ONLY reliable check, 237 | * knowing which method will be executed as a constructor. 238 | */ 239 | elseif ( ! is_callable(array($class, $method))) 240 | { 241 | $reflection = new ReflectionMethod($class, $method); 242 | if ( ! $reflection->isPublic() OR $reflection->isConstructor()) 243 | { 244 | $e404 = TRUE; 245 | } 246 | } 247 | } 248 | if ($e404) 249 | { 250 | if ( ! empty($RTR->routes['404_override'])) 251 | { 252 | if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $error_class, $error_method) !== 2) 253 | { 254 | $error_method = 'index'; 255 | } 256 | $error_class = ucfirst($error_class); 257 | if ( ! class_exists($error_class, FALSE)) 258 | { 259 | if (file_exists(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php')) 260 | { 261 | require_once(APPPATH.'controllers/'.$RTR->directory.$error_class.'.php'); 262 | $e404 = ! class_exists($error_class, FALSE); 263 | } 264 | // Were we in a directory? If so, check for a global override 265 | elseif ( ! empty($RTR->directory) && file_exists(APPPATH.'controllers/'.$error_class.'.php')) 266 | { 267 | require_once(APPPATH.'controllers/'.$error_class.'.php'); 268 | if (($e404 = ! class_exists($error_class, FALSE)) === FALSE) 269 | { 270 | $RTR->directory = ''; 271 | } 272 | } 273 | } 274 | else 275 | { 276 | $e404 = FALSE; 277 | } 278 | } 279 | // Did we reset the $e404 flag? If so, set the rsegments, starting from index 1 280 | if ( ! $e404) 281 | { 282 | $class = $error_class; 283 | $method = $error_method; 284 | $URI->rsegments = array( 285 | 1 => $class, 286 | 2 => $method 287 | ); 288 | } 289 | else 290 | { 291 | show_404($RTR->directory.$class.'/'.$method); 292 | } 293 | } 294 | if ($method !== '_remap') 295 | { 296 | $params = array_slice($URI->rsegments, 2); 297 | } 298 | /* 299 | * ------------------------------------------------------ 300 | * Is there a "pre_controller" hook? 301 | * ------------------------------------------------------ 302 | */ 303 | $EXT->call_hook('pre_controller'); 304 | /* 305 | * ------------------------------------------------------ 306 | * Instantiate the requested controller 307 | * ------------------------------------------------------ 308 | */ 309 | // Mark a start point so we can benchmark the controller 310 | $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); 311 | $CI = new $class(); 312 | /* 313 | * ------------------------------------------------------ 314 | * Is there a "post_controller_constructor" hook? 315 | * ------------------------------------------------------ 316 | */ 317 | $EXT->call_hook('post_controller_constructor'); 318 | /* 319 | * ------------------------------------------------------ 320 | * Call the requested method 321 | * ------------------------------------------------------ 322 | */ 323 | call_user_func_array(array(&$CI, $method), $params); 324 | // Mark a benchmark end point 325 | $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); 326 | /* 327 | * ------------------------------------------------------ 328 | * Is there a "post_controller" hook? 329 | * ------------------------------------------------------ 330 | */ 331 | $EXT->call_hook('post_controller'); 332 | /* 333 | * ------------------------------------------------------ 334 | * Send the final rendered output to the browser 335 | * ------------------------------------------------------ 336 | */ 337 | if ($EXT->call_hook('display_override') === FALSE) 338 | { 339 | $OUT->_display(); 340 | } 341 | /* 342 | * ------------------------------------------------------ 343 | * Is there a "post_system" hook? 344 | * ------------------------------------------------------ 345 | */ 346 | $EXT->call_hook('post_system'); 347 | 348 | 349 | /* 350 | * ------------------------------------------------------ 351 | * Finally Return An Array (required) 352 | * ------------------------------------------------------ 353 | */ 354 | return []; 355 | -------------------------------------------------------------------------------- /src/Helpers/swoole.php: -------------------------------------------------------------------------------- 1 | 'tests/test/abc', 28 | 'params' => ['demo' => '666'], 29 | ]); 30 | } 31 | catch (\Exception $e) 32 | { 33 | $check = false; 34 | 35 | print_r($e->getMessage()); 36 | print_r($e->getTraceAsString()); 37 | } 38 | 39 | $this->assertTrue($check); 40 | } 41 | 42 | // ------------------------------------------------------------------------------ 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/application/controllers/tests/Test.php: -------------------------------------------------------------------------------- 1 | input->post(); 24 | 25 | log_message('error', var_export($data, true)); 26 | } 27 | 28 | // ------------------------------------------------------------------------------ 29 | 30 | /** 31 | * here's the timer method 32 | */ 33 | public function task_timer() 34 | { 35 | log_message('error', 'timer works!'); 36 | } 37 | 38 | // ------------------------------------------------------------------------------ 39 | 40 | /** 41 | * send data to task 42 | */ 43 | public function send() 44 | { 45 | try 46 | { 47 | \CiSwoole\Core\Client::send( 48 | [ 49 | 'route' => 'tests/test/task', 50 | 'params' => ['hope' => 'it works!'], 51 | ]); 52 | } 53 | catch (\Exception $e) 54 | { 55 | log_message('error', $e->getMessage()); 56 | log_message('error', $e->getTraceAsString()); 57 | } 58 | } 59 | 60 | // ------------------------------------------------------------------------------ 61 | 62 | } 63 | --------------------------------------------------------------------------------