diff --git a/.gitignore b/.gitignore index 485dee6..090a1f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +.DS_Store diff --git a/README.md b/README.md index c7cfeda..e5c8717 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,12 @@ Nginx配置 } ``` + +调试 +------------- +var_dump、echo都是输出到控制台,不方便调试。可以使用\feehi\console\dump()函数,输出数组、对象、字符串、布尔值到浏览器 + + 其他 ------------- 以上是把swoole启动/关闭/重启命令集成到了yii2 console里面,如果你并不想使用集成到yii2 console的swoole,可以复制vendor/feehi/yii2-swoole下的backend.php和frontend.php,修改$rootDir = "/path/to/project"为真正的yii2项目根目录,然后执行php backend.php以及php frontend.php启动swoole \ No newline at end of file diff --git a/src/console/SwooleController.php b/src/console/SwooleController.php index d16fbd9..9561a96 100644 --- a/src/console/SwooleController.php +++ b/src/console/SwooleController.php @@ -9,109 +9,13 @@ namespace feehi\console; use yii; - -/** - * Class SwooleController - * - * @package feehi\console\controllers - * - * @description - * - * 支持的命令 - * - * ./yii swoole/start 启动前台swoole - * ./yii swoole/stop 关闭前台swoole - * ./yii swoole/restart 重启前台swoole - * - * ./yii swoole-backend/start 启动后台swoole - * ./yii swoole-backend/stop 关闭后台swoole - * ./yii swoole-backend/restart 重启后台swoole - * - * - * 配置示例 - 'controllerMap'=>[ - ... - 'swoole' => [ - 'class' => feehi\console\SwooleController::className(), - 'rootDir' => str_replace('console/config', '', __DIR__ ),//yii2项目根路径 - 'app' => 'frontend',//app目录地址 - 'host' => '127.0.0.1',//监听地址 - 'port' => 9999,//监听端口 - 'swooleConfig' => [//标准的swoole配置项都可以再此加入 - 'reactor_num' => 2, - 'worker_num' => 4, - 'daemonize' => false, - 'log_file' => __DIR__ . '/../../frontend/runtime/logs/swoole.log', - 'log_level' => 0, - 'pid_file' => __DIR__ . '/../../frontend/runtime/server.pid', - ], - ], - 'swoole-backend' => [ - 'class' => feehi\console\SwooleController::className(), - 'rootDir' => str_replace('console/config', '', __DIR__ ),//yii2项目根路径 - 'app' => 'backend', - 'host' => '127.0.0.1', - 'port' => 9998, - 'swooleConfig' => [ - 'reactor_num' => 2, - 'worker_num' => 4, - 'daemonize' => false, - 'log_file' => __DIR__ . '/../../backend/runtime/logs/swoole.log', - 'log_level' => 0, - 'pid_file' => __DIR__ . '/../../backend/runtime/server.pid', - ], - ] - ... - ] - * - * nginx 配置示列 //虽然swoole从1.9.8开始支持静态资源,但是性能很差,线上环境务必搭配nginx使用 - * - * 前台 - * - server { - set $web /www/cms-swoole/frontend/web; - root $web; - server_name swoole.cms.test.docker; - - location ~* .(ico|gif|bmp|jpg|jpeg|png|swf|js|css|mp3) { - root $web; - } - - location ~ timthumb\.php$ {//若部分功能仍需要使用php-fpm则做类似配置,否则删除此段 - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include fastcgi_params; - } - - location / { - proxy_http_version 1.1; - proxy_set_header Connection "keep-alive"; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host http://swoole.cms.test.docker; - proxy_pass http://127.0.0.1:9999; - } - } - * - 后台 - server { - set $web /www/cms-swoole/backend/web; - root $web; - server_name swoole-admin.cms.test.docker; - - location ~* .(ico|gif|bmp|jpg|jpeg|png|swf|js|css|mp3) { - root $web; - } - - location / { - proxy_http_version 1.1; - proxy_set_header Connection "keep-alive"; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host http://swoole-admin.cms.test.docker; - proxy_pass http://127.0.0.1:9998; - } - } - */ +use yii\helpers\ArrayHelper; +use feehi\web\Request; +use feehi\web\Response; +use feehi\web\Session; +use feehi\swoole\SwooleServer; +use yii\web\AssetManager; +use yii\web\Application; class SwooleController extends \yii\console\Controller { @@ -120,12 +24,18 @@ class SwooleController extends \yii\console\Controller public $port = 9999; + public $mode = SWOOLE_PROCESS; + + public $socketType = SWOOLE_TCP; + public $rootDir = ""; public $app = "frontend"; public $swooleConfig = []; + public $gcSessionInterval = 60000;//启动session回收的间隔时间,单位为毫秒 + public function actionStart() @@ -142,7 +52,7 @@ public function actionStart() require($rootDir . '/common/config/bootstrap.php'); require($rootDir . $this->app . '/config/bootstrap.php'); - $config = yii\helpers\ArrayHelper::merge( + $config = ArrayHelper::merge( require($rootDir . '/common/config/main.php'), require($rootDir . '/common/config/main-local.php'), require($rootDir . $this->app . '/config/main.php'), @@ -154,24 +64,25 @@ public function actionStart() 'enable_static_handler' => true, ], $this->swooleConfig); - $server = new \feehi\swoole\SwooleServer($this->host, $this->port, $this->swooleConfig); + $server = new SwooleServer($this->host, $this->port, $this->mode, $this->socketType, $this->swooleConfig, ['gcSessionInterval'=>$this->gcSessionInterval]); + + function dump($var){ + if( is_array($var) || is_object($var) ){ + $body = print_r($var, true); + }else{ + $body = $var; + } + if( isset(yii::$app->getResponse()->swooleResponse) ){ + echo "dump function must called in request period" . PHP_EOL; + } + yii::$app->getResponse()->swooleResponse->end($body); + } /** * @param \swoole_http_request $request * @param \swoole_http_response $response */ $server->runApp = function ($request, $response) use ($config, $web) { - /*$uri = $request->server['request_uri']; - if (strpos($uri, 'timthumb')) { - $image = new \feehi\components\PicFilter(); - $image->initialize([ - 'source_image' => $web . "/uploads/article/thumb/5998ec3c119ea_a6.jpg", - 'width' => 200, - 'height' => 200, - ]); - $image->resize(); - exit; - }*/ $aliases = [ '@web' => $web, '@webroot' => $web, @@ -179,29 +90,29 @@ public function actionStart() $config['aliases'] = isset($config['aliases']) ? array_merge($aliases, $config['aliases']) : $aliases; $requestComponent = [ - 'class' => \feehi\web\Request::className(), + 'class' => Request::className(), 'swooleRequest' => $request, ]; $config['components']['request'] = isset($config['components']['request']) ? array_merge($config['components']['request'], $requestComponent) : $requestComponent; $responseComponent = [ - 'class' => \feehi\web\Response::className(), + 'class' => Response::className(), 'swooleResponse' => $response, ]; $config['components']['response'] = isset($config['components']['response']) ? array_merge($config['components']['response'], $responseComponent) : $responseComponent; $authManagerComponent = [ - 'class' => yii\web\AssetManager::className(), + 'class' => AssetManager::className(), 'baseUrl' => '/assets' ]; $config['components']['assetManager'] = isset( $config['components']['assetManager'] ) ? array_merge($authManagerComponent, $config['components']['assetManager']) : $authManagerComponent; $config['components']['session'] = [ - "class" => \feehi\web\Session::className() + "class" => Session::className() ]; try { - $application = new \yii\web\Application($config); + $application = new Application($config); yii::setAlias('@web', $web); yii::$app->setAliases($aliases); $application->run(); @@ -251,7 +162,7 @@ private function sendSignal($sig) if ($pid = $this->getPid()) { posix_kill($pid, $sig); } else { - $this->stdout("not running!" . PHP_EOL); + $this->stdout("server is not running!" . PHP_EOL); exit(1); } } diff --git a/src/swoole/SwooleServer.php b/src/swoole/SwooleServer.php index b54782b..455b06d 100644 --- a/src/swoole/SwooleServer.php +++ b/src/swoole/SwooleServer.php @@ -9,19 +9,23 @@ namespace feehi\swoole; use feehi\web\Session; +use swoole_http_server; class SwooleServer extends \yii\base\Object { public $swoole; - public static $swooleConfig; + public $webRoot; + + public $config = ['gcSessionInterval' => 60000]; public $runApp; - public function __construct($host, $port, $swooleConfig=[]) + public function __construct($host, $port, $mode, $socketType, $swooleConfig=[], $config=[]) { - $this->swoole = new \swoole_http_server($host, $port); - self::$swooleConfig = $swooleConfig; + $this->swoole = new swoole_http_server($host, $port, $mode, $socketType); + $this->webRoot = $swooleConfig['document_root']; + if( !empty($this->config) ) $this->config = array_merge($this->config, $config); $this->swoole->set($swooleConfig); $this->swoole->on('request', [$this, 'onRequest']); $this->swoole->on('WorkerStart', [$this, 'onWorkerStart']); @@ -53,7 +57,7 @@ public function onRequest($request, $response) public function onWorkerStart( $serv , $worker_id) { if( $worker_id == 0 ) { - \swoole_timer_tick(60000, function(){//一分钟清理一次session + swoole_timer_tick($this->config['gcSessionInterval'], function(){//一分钟清理一次session (new Session())->gcSession(); }); } @@ -84,19 +88,19 @@ private function staticRequest($request, $response) $extension = pathinfo($uri, PATHINFO_EXTENSION); if( !empty($extension) && in_array($extension, ['js', 'css', 'jpg', 'jpeg', 'png', 'gif', 'webp']) ){ - $web = self::$swooleConfig['document_root']; + $web = $this->webRoot; rtrim($web, '/'); $file = $web . '/' . $uri; if( is_file( $file )){ $temp = strrev($file); if( strpos($uri, 'sj.') === 0 ) { - $response->header('Content-Type', 'application/x-javascript'); + $response->header('Content-Type', 'application/x-javascript', false); }else if(strpos($temp, 'ssc.') === 0){ - $response->header('Content-Type', 'text/css'); + $response->header('Content-Type', 'text/css', false); }else { - $response->header('Content-Type', 'application/octet-stream'); + $response->header('Content-Type', 'application/octet-stream', false); } - $response->sendfile($file); + $response->sendfile($file, 0); }else{ $response->status(404); $response->end(''); diff --git a/src/web/Session.php b/src/web/Session.php index 8b6019d..9a708f1 100644 --- a/src/web/Session.php +++ b/src/web/Session.php @@ -13,9 +13,6 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co /* @description $savePath session存储目录,执行swoole的用户必须对目录有读和写的权限 */ public $savePath = "/tmp/"; - /* @description $lifeTime session有效时间(秒) */ - public $lifeTime = 1400; - public $flashParam = '__flash'; private $_started = false; @@ -50,14 +47,18 @@ public function persist() file_put_contents($this->getSessionFullName(), json_encode($_SESSION)); } + /** + * swoole每隔设置的毫秒数执行此方法回收session + */ public function gcSession() { $handle = opendir( $this->getSavePath() ); while (false !== ($file = readdir($handle))) { if ($file != "." && $file != ".." && (strpos($file, $this->_prefix) === 0) && is_file($this->getSavePath() . $file)) { + if( strpos($file, $this->_prefix) !== 0 ) continue; $lastUpdatedAt = filemtime($this->getSavePath() . $file); - if( time() - $lastUpdatedAt > $this->lifeTime ){ + if( time() - $lastUpdatedAt > $this->getCookieParams()['lifetime'] ){ unlink($this->getSavePath() . $file); } } @@ -69,6 +70,15 @@ public function open() if ($this->getIsActive()) { return; } + if( !is_dir($this->getSavePath()) ){ + throw new InvalidConfigException("SESSION save path {$this->savePath} is not exists"); + } + if( !is_readable($this->getSavePath()) ){ + throw new InvalidConfigException("SESSION saved path {$this->savePath} is not readable"); + } + if( !is_writable($this->getSavePath()) ){ + throw new InvalidConfigException("SESSION saved path {$this->savePath} is not writable"); + } $file = $this->getSessionFullName(); if( file_exists($file) && is_file($file) ) { $data = file_get_contents($file); @@ -85,11 +95,12 @@ public function getCookieParams() } public function setCookieParams(array $config){ - $this->_cookieParams; + $this->_cookieParams = $config; } public function destroy() { + $this->open(); if ($this->getIsActive()) { $_SESSION = []; } @@ -147,12 +158,6 @@ public function getSavePath() if( strrpos( $this->savePath, '/') !==0 ){ $this->savePath .= '/'; } - if( !is_readable($this->savePath) ){ - throw new InvalidConfigException("SESSION saved path {$this->savePath} is not readable"); - } - if( !is_writable($this->savePath) ){ - throw new InvalidConfigException("SESSION saved path {$this->savePath} is not writable"); - } return $this->savePath; } @@ -175,6 +180,7 @@ public function getCount() public function count() { + $this->open(); return $this->getCount(); } @@ -217,6 +223,7 @@ public function has($key) protected function updateFlashCounters() { + $this->open(); $counters = $this->get($this->flashParam, []); if (is_array($counters)) { foreach ($counters as $key => $count) { @@ -233,8 +240,9 @@ protected function updateFlashCounters() } } - public function getFlash($key, $defaultValue = null, $delete = false) + public function getFlash($key, $defaultValue = null, $delete = true) { + $this->open(); $counters = $this->get($this->flashParam, []); if (isset($counters[$key])) { $value = $this->get($key, $defaultValue); @@ -252,6 +260,7 @@ public function getFlash($key, $defaultValue = null, $delete = false) public function getAllFlashes($delete = false) { + $this->open(); $counters = $this->get($this->flashParam, []); $flashes = []; foreach (array_keys($counters) as $key) { @@ -273,6 +282,7 @@ public function getAllFlashes($delete = false) public function setFlash($key, $value = true, $removeAfterAccess = true) { + $this->open(); $counters = $this->get($this->flashParam, []); $counters[$key] = $removeAfterAccess ? -1 : 0; $_SESSION[$key] = $value; @@ -281,6 +291,7 @@ public function setFlash($key, $value = true, $removeAfterAccess = true) public function addFlash($key, $value = true, $removeAfterAccess = true) { + $this->open(); $counters = $this->get($this->flashParam, []); $counters[$key] = $removeAfterAccess ? -1 : 0; $_SESSION[$this->flashParam] = $counters; @@ -297,6 +308,7 @@ public function addFlash($key, $value = true, $removeAfterAccess = true) public function removeFlash($key) { + $this->open(); $counters = $this->get($this->flashParam, []); $value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null; unset($counters[$key], $_SESSION[$key]); @@ -306,6 +318,7 @@ public function removeFlash($key) public function removeAllFlashes() { + $this->open(); $counters = $this->get($this->flashParam, []); foreach (array_keys($counters) as $key) { unset($_SESSION[$key]); @@ -315,6 +328,7 @@ public function removeAllFlashes() public function hasFlash($key) { + $this->open(); return $this->getFlash($key) !== null; }