Commit 48b314ba8c6a5a4dd7d09f0ea7228884c13869d1
1 parent
13c2ced1
[Swoole 集成 ThinkPHP 3.2]
Showing
11 changed files
with
3023 additions
and
0 deletions
trunk/Swoole/Cli/Controller/IndexController.class.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * Created by PhpStorm. | |
4 | + * User: luoys | |
5 | + * Date: 2019/2/13 | |
6 | + * Time: 17:29 | |
7 | + */ | |
8 | + | |
9 | +namespace Cli\Controller; | |
10 | + | |
11 | +class IndexController | |
12 | +{ | |
13 | + public function index() | |
14 | + { | |
15 | + print_r(C('MODULE_DENY_LIST')); | |
16 | + //echo "Swoole 服务端已启动。 \n"; | |
17 | + } | |
18 | +} | |
0 | 19 | \ No newline at end of file | ... | ... |
trunk/Swoole/SwooleClient.php
0 → 100644
1 | +<?php | |
2 | +/** | |
3 | + * Created by PhpStorm. | |
4 | + * User: luoys | |
5 | + * Date: 2019/2/13 | |
6 | + * Time: 11:42 | |
7 | + */ | |
8 | + | |
9 | +class SwooleClient | |
10 | +{ | |
11 | + private $_client; | |
12 | + | |
13 | + public function __construct($type = SWOOLE_SOCK_TCP, $is_sync = SWOOLE_SOCK_SYNC) | |
14 | + { | |
15 | + $this->_client = new swoole_client($type, $is_sync); | |
16 | + } | |
17 | + | |
18 | + public function connect($host, $port = null, $timeout = null, $sock_flag = null) | |
19 | + { | |
20 | + if (!$this->_client->connect($host, $port, $timeout, $sock_flag)) { | |
21 | + exit("connect failed. Error: {$this->_client->errCode}\n"); | |
22 | + } | |
23 | + } | |
24 | + | |
25 | + public function send($data) | |
26 | + { | |
27 | + if ($this->_client->send($data) === false) | |
28 | + { | |
29 | + exit("send data failed. Error: {$this->_client->errCode} \n"); | |
30 | + } | |
31 | + } | |
32 | + | |
33 | + public function sendfile($filename, $offset, $length) | |
34 | + { | |
35 | + if ($this->_client->sendfile($filename, $offset, $length) === false) { | |
36 | + exit("{$filename} is not exist. \n"); | |
37 | + } | |
38 | + } | |
39 | + | |
40 | + public function sendto($ip, $port, $data) | |
41 | + { | |
42 | + $this->_client->sendto($ip, $port, $data); | |
43 | + } | |
44 | + | |
45 | + public function recv($size = 65535, $flags = 0) | |
46 | + { | |
47 | + if (($recv = $this->_client->recv($size, $flags)) === false) { | |
48 | + exit("receive data failed. Error: {$this->_client->errCode} \n"); | |
49 | + } | |
50 | + return $recv; | |
51 | + } | |
52 | + | |
53 | +} | |
54 | + | |
55 | +$client = new SwooleClient(); | |
56 | +$client->connect('127.0.0.1', 9501); | |
57 | +$client->send('11223'); | |
58 | + | |
59 | +$recv = $client->recv(); | |
60 | +echo $recv; | |
0 | 61 | \ No newline at end of file | ... | ... |
trunk/Swoole/SwooleServer.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +/** | |
4 | + * Swoole服务端 | |
5 | + */ | |
6 | +class SwooleServer | |
7 | +{ | |
8 | + | |
9 | + private $_serv = null; | |
10 | + private $_setting = array(); | |
11 | + | |
12 | + public function __construct($host = '0.0.0.0', $port = 9501) | |
13 | + { | |
14 | + $this->_setting = array( | |
15 | + 'host' => $host, | |
16 | + 'port' => $port, | |
17 | + 'env' => 'dev', //环境 dev|test|prod | |
18 | + 'process_name' => SWOOLE_TASK_NAME_PRE, //swoole 进程名称 | |
19 | + 'worker_num' => 4, //一般设置为服务器CPU数的1-4倍 | |
20 | + 'task_worker_num' => 1, //task进程的数量 | |
21 | + 'task_ipc_mode' => 3, //使用消息队列通信,并设置为争抢模式 | |
22 | + 'task_max_request' => 10000, //task进程的最大任务数 | |
23 | + 'daemonize' => 0, //以守护进程执行 | |
24 | + 'max_request' => 10000, | |
25 | + 'dispatch_mode' => 2, | |
26 | + 'log_file' => SWOOLE_PATH . DIRECTORY_SEPARATOR . 'App' . DIRECTORY_SEPARATOR . 'Runtime' . DIRECTORY_SEPARATOR . 'Logs' . DIRECTORY_SEPARATOR . 'Swoole' . date('Ymd') . '.log', //日志 | |
27 | + ); | |
28 | + } | |
29 | + | |
30 | + /** | |
31 | + * 运行swoole服务 | |
32 | + */ | |
33 | + public function run() | |
34 | + { | |
35 | + $this->_serv = new swoole_server($this->_setting['host'], $this->_setting['port']); | |
36 | + $this->_serv->set(array( | |
37 | + 'worker_num' => $this->_setting['worker_num'], | |
38 | + 'task_worker_num' => $this->_setting['task_worker_num'], | |
39 | + 'task_ipc_mode ' => $this->_setting['task_ipc_mode'],'task_max_request' => $this->_setting['task_max_request'], | |
40 | + 'daemonize' => $this->_setting['daemonize'], | |
41 | + 'max_request' => $this->_setting['max_request'], | |
42 | + 'dispatch_mode' => $this->_setting['dispatch_mode'], | |
43 | + //'log_file' => $this->_setting['log_file'] | |
44 | + )); | |
45 | + $this->_serv->on('Start', array($this, 'onStart')); | |
46 | + $this->_serv->on('Connect', array($this, 'onConnect')); | |
47 | + $this->_serv->on('WorkerStart', array($this, 'onWorkerStart')); | |
48 | + $this->_serv->on('ManagerStart', array($this, 'onManagerStart')); | |
49 | + $this->_serv->on('WorkerStop', array($this, 'onWorkerStop')); | |
50 | + $this->_serv->on('Receive', array($this, 'onReceive')); | |
51 | + $this->_serv->on('Task', array($this, 'onTask')); | |
52 | + $this->_serv->on('Finish', array($this, 'onFinish')); | |
53 | + $this->_serv->on('Shutdown', array($this, 'onShutdown')); | |
54 | + $this->_serv->on('Close', array($this, 'onClose')); | |
55 | + | |
56 | + $this->_serv->start(); | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * 设置swoole进程名称 | |
61 | + * @param string $name swoole进程名称 | |
62 | + */ | |
63 | + private function setProcessName($name) | |
64 | + { | |
65 | + if (function_exists('cli_set_process_title')) { | |
66 | + cli_set_process_title($name); | |
67 | + } else { | |
68 | + if (function_exists('swoole_set_process_name')) { | |
69 | + swoole_set_process_name($name); | |
70 | + } else { | |
71 | + trigger_error(__METHOD__ . " failed. require cli_set_process_title or swoole_set_process_name."); | |
72 | + } | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + /** | |
77 | + * Server启动在主进程的主线程回调此函数 | |
78 | + * @param $serv | |
79 | + */ | |
80 | + public function onStart($serv) | |
81 | + { | |
82 | + if (!$this->_setting['daemonize']) { | |
83 | + echo 'Date:' . date('Y-m-d H:i:s') . "\t swoole_server master worker start\n"; | |
84 | + } | |
85 | + $this->setProcessName($this->_setting['process_name'] . '-master'); | |
86 | + //记录进程id,脚本实现自动重启 | |
87 | + $pid = "{$serv->master_pid}\n{$serv->manager_pid}"; | |
88 | + file_put_contents(SWOOLE_TASK_PID_PATH, $pid); | |
89 | + } | |
90 | + | |
91 | + /** | |
92 | + * worker start 加载业务脚本常驻内存 | |
93 | + * @param $server | |
94 | + * @param $workerId | |
95 | + */ | |
96 | + public function onWorkerStart($serv, $workerId) | |
97 | + { | |
98 | + if ($workerId >= $this->_setting['worker_num']) { | |
99 | + $this->setProcessName($this->_setting['process_name'] . '-task'); | |
100 | + } else { | |
101 | + $this->setProcessName($this->_setting['process_name'] . '-event'); | |
102 | + } | |
103 | + // 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false | |
104 | + define('APP_DEBUG', True); | |
105 | + // 定义应用目录 | |
106 | + define('APP_PATH', SWOOLE_PATH . DIRECTORY_SEPARATOR . 'Swoole' . DIRECTORY_SEPARATOR); | |
107 | + // 定义应用模式 | |
108 | + define('APP_MODE', 'cli'); | |
109 | + | |
110 | + // 绑定默认模块 | |
111 | + define('BIND_MODULE', 'Cli'); | |
112 | + // 绑定默认控制器 | |
113 | + define('BIND_CONTROLLER', 'Index'); | |
114 | + // 引入ThinkPHP入口文件 | |
115 | + require_once SWOOLE_PATH . DIRECTORY_SEPARATOR . 'ThinkPHP' . DIRECTORY_SEPARATOR . 'ThinkPHP.php'; | |
116 | + } | |
117 | + | |
118 | + /** | |
119 | + * 监听连接进入事件 | |
120 | + * @param $serv | |
121 | + * @param $fd | |
122 | + */ | |
123 | + public function onConnect($serv, $fd) | |
124 | + { | |
125 | + if (!$this->_setting['daemonize']) { | |
126 | + echo 'Date:' . date('Y-m-d H:i:s') . "\t swoole_server connect[" . $fd . "]\n"; | |
127 | + } | |
128 | + } | |
129 | + | |
130 | + /** | |
131 | + * worker 进程停止 | |
132 | + * @param $server | |
133 | + * @param $workerId | |
134 | + */ | |
135 | + public function onWorkerStop($serv, $workerId) | |
136 | + { | |
137 | + if (!$this->_setting['daemonize']) { | |
138 | + echo 'Date:' . date('Y-m-d H:i:s') . "\t swoole_server[{$serv->setting['process_name']} worker:{$workerId} shutdown\n"; | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + /** | |
143 | + * 当管理进程启动时调用 | |
144 | + * @param $serv | |
145 | + */ | |
146 | + public function onManagerStart($serv) | |
147 | + { | |
148 | + if (!$this->_setting['daemonize']) { | |
149 | + echo 'Date:' . date('Y-m-d H:i:s') . "\t swoole_server manager worker start\n"; | |
150 | + } | |
151 | + $this->setProcessName($this->_setting['process_name'] . '-manager'); | |
152 | + } | |
153 | + | |
154 | + /** | |
155 | + * 此事件在Server结束时发生 | |
156 | + */ | |
157 | + public function onShutdown($serv) | |
158 | + { | |
159 | + if (file_exists(SWOOLE_TASK_PID_PATH)) { | |
160 | + unlink(SWOOLE_TASK_PID_PATH); | |
161 | + } | |
162 | + if (!$this->_setting['daemonize']) { | |
163 | + echo 'Date:' . date('Y-m-d H:i:s') . "\t swoole_server shutdown\n"; | |
164 | + } | |
165 | + } | |
166 | + | |
167 | + /** | |
168 | + * 监听数据发送事件 | |
169 | + * @param $serv | |
170 | + * @param $fd | |
171 | + * @param $from_id | |
172 | + * @param $data | |
173 | + */ | |
174 | + public function onReceive($serv, $fd, $from_id, $data) | |
175 | + { | |
176 | + if (!$this->_setting['daemonize']) { | |
177 | + echo "Get Message From Client {$fd}:{$data}\n\n"; | |
178 | + } | |
179 | + $result = json_decode($data, true); | |
180 | + switch ($result['action']) { | |
181 | + case 'reload': //重启 | |
182 | + $serv->reload(); | |
183 | + break; | |
184 | + case 'close': //关闭 | |
185 | + $serv->shutdown(); | |
186 | + break; | |
187 | + case 'status': //状态 | |
188 | + $serv->send($fd, json_encode($serv->stats())); | |
189 | + break; | |
190 | + default: | |
191 | + $serv->task($data); | |
192 | + break; | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + /** | |
197 | + * 监听连接Task事件 | |
198 | + * @param $serv | |
199 | + * @param $task_id | |
200 | + * @param $from_id | |
201 | + * @param $data | |
202 | + */ | |
203 | + public function onTask($serv, $task_id, $from_id, $data) | |
204 | + { | |
205 | + $result = json_decode($data, true); | |
206 | + //用TP处理各种逻辑 | |
207 | + $serv->finish($data); | |
208 | + } | |
209 | + | |
210 | + /** | |
211 | + * 监听连接Finish事件 | |
212 | + * @param $serv | |
213 | + * @param $task_id | |
214 | + * @param $data | |
215 | + */ | |
216 | + public function onFinish($serv, $task_id, $data) | |
217 | + { | |
218 | + if (!$this->_setting['daemonize']) { | |
219 | + echo "Task {$task_id} finish\n\n"; | |
220 | + echo "Result: {$data}\n\n"; | |
221 | + } | |
222 | + } | |
223 | + | |
224 | + /** | |
225 | + * 监听连接关闭事件 | |
226 | + * @param $serv | |
227 | + * @param $fd | |
228 | + */ | |
229 | + public function onClose($serv, $fd) | |
230 | + { | |
231 | + if (!$this->_setting['daemonize']) { | |
232 | + echo 'Date:' . date('Y-m-d H:i:s') . "\t swoole_server close[" . $fd . "]\n"; | |
233 | + } | |
234 | + } | |
235 | +} | ... | ... |
trunk/Swoole/tmp/swoole-task.pid
0 → 100644
trunk/Swoole/相关命令.txt
0 → 100644
1 | +1、服务启动 | |
2 | + #启动服务,不指定绑定端口和ip,则使用默认配置 | |
3 | + php swoole.php start | |
4 | + #启动服务 指定ip 和 port | |
5 | + php swoole.php -h127.0.0.1 -p9501 start | |
6 | + #启动服务 守护进程模式 | |
7 | + php swoole.php -h127.0.0.1 -p9501 -d start | |
8 | + #启动服务 非守护进程模式 | |
9 | + php swoole.php -h127.0.0.1 -p9501 -D start | |
10 | + #启动服务 指定进程名称(显示进程名为 swooleServ-9510-[master|manager|event|task] | |
11 | + php swoole.php -h127.0.0.1 -p9501 -n 9501 start | |
12 | + | |
13 | + | |
14 | +2、强制服务停止 | |
15 | + php swoole.php stop | |
16 | + php swoole.php -p9501 stop | |
17 | + php swoole.php -h127.0.0.1 -p9501 stop | |
18 | + | |
19 | + | |
20 | +3、关闭服务 | |
21 | + php swoole.php close | |
22 | + php swoole.php -p9501 close | |
23 | + php swoole.php -h127.0.0.1 -p9501 close | |
24 | + | |
25 | + | |
26 | +4、强制服务重启 | |
27 | + php swoole.php restart | |
28 | + php swoole.php -p9501 restart | |
29 | + php swoole.php -h127.0.0.1 -p9501 restart | |
30 | + | |
31 | + | |
32 | +5、平滑服务重启 | |
33 | + php swoole.php reload | |
34 | + php swoole.php -p9501 reload | |
35 | + php swoole.php -h127.0.0.1 -p9501 reload | |
36 | + | |
37 | + | |
38 | +6、服务状态 | |
39 | + php swoole.php status | |
40 | + php swoole.php -h127.0.0.1 -p9501 status | |
41 | + | |
42 | + | |
43 | +7、swoole-task所有启动实例进程列表(一台服务器swoole-task可以有多个端口绑定的实例) | |
44 | + php swoole.php list | |
45 | + | |
46 | + | |
47 | + | |
48 | +QQ:506723561 | |
0 | 49 | \ No newline at end of file | ... | ... |
trunk/ThinkPHP/Mode/Cli/App.class.php
0 → 100644
1 | +<?php | |
2 | +// +---------------------------------------------------------------------- | |
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] | |
4 | +// +---------------------------------------------------------------------- | |
5 | +// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. | |
6 | +// +---------------------------------------------------------------------- | |
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | |
8 | +// +---------------------------------------------------------------------- | |
9 | +// | Author: liu21st <liu21st@gmail.com> | |
10 | +// +---------------------------------------------------------------------- | |
11 | +namespace Think; | |
12 | +/** | |
13 | + * ThinkPHP CLI模式应用程序类 执行应用过程管理 | |
14 | + */ | |
15 | +class App { | |
16 | + | |
17 | + /** | |
18 | + * 应用程序初始化 | |
19 | + * @access public | |
20 | + * @return void | |
21 | + */ | |
22 | + static public function init() { | |
23 | + // 加载动态应用公共文件和配置 | |
24 | + load_ext_file(COMMON_PATH); | |
25 | + | |
26 | + // 日志目录转换为绝对路径 默认情况下存储到公共模块下面 | |
27 | + C('LOG_PATH', realpath(LOG_PATH).'/Common/'); | |
28 | + | |
29 | + // 定义当前请求的系统常量 | |
30 | + define('NOW_TIME', $_SERVER['REQUEST_TIME']); | |
31 | + define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']); | |
32 | + define('IS_GET', REQUEST_METHOD =='GET' ? true : false); | |
33 | + define('IS_POST', REQUEST_METHOD =='POST' ? true : false); | |
34 | + define('IS_PUT', REQUEST_METHOD =='PUT' ? true : false); | |
35 | + define('IS_DELETE', REQUEST_METHOD =='DELETE' ? true : false); | |
36 | + | |
37 | + // URL调度 | |
38 | + Dispatcher::dispatch(); | |
39 | + | |
40 | + if(C('REQUEST_VARS_FILTER')){ | |
41 | + // 全局安全过滤 | |
42 | + array_walk_recursive($_GET, 'think_filter'); | |
43 | + array_walk_recursive($_POST, 'think_filter'); | |
44 | + array_walk_recursive($_REQUEST, 'think_filter'); | |
45 | + } | |
46 | + | |
47 | + // URL调度结束标签 | |
48 | + Hook::listen('url_dispatch'); | |
49 | + | |
50 | + define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false); | |
51 | + | |
52 | + // TMPL_EXCEPTION_FILE 改为绝对地址 | |
53 | + C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE'))); | |
54 | + return ; | |
55 | + } | |
56 | + | |
57 | + /** | |
58 | + * 执行应用程序 | |
59 | + * @access public | |
60 | + * @return void | |
61 | + */ | |
62 | + static public function exec() { | |
63 | + | |
64 | + if(!preg_match('/^[A-Za-z](\/|\w)*$/',CONTROLLER_NAME)){ // 安全检测 | |
65 | + $module = false; | |
66 | + }elseif(C('ACTION_BIND_CLASS')){ | |
67 | + // 操作绑定到类:模块\Controller\控制器\操作 | |
68 | + $layer = C('DEFAULT_C_LAYER'); | |
69 | + if(is_dir(MODULE_PATH.$layer.'/'.CONTROLLER_NAME)){ | |
70 | + $namespace = MODULE_NAME.'\\'.$layer.'\\'.CONTROLLER_NAME.'\\'; | |
71 | + }else{ | |
72 | + // 空控制器 | |
73 | + $namespace = MODULE_NAME.'\\'.$layer.'\\_empty\\'; | |
74 | + } | |
75 | + $actionName = strtolower(ACTION_NAME); | |
76 | + if(class_exists($namespace.$actionName)){ | |
77 | + $class = $namespace.$actionName; | |
78 | + }elseif(class_exists($namespace.'_empty')){ | |
79 | + // 空操作 | |
80 | + $class = $namespace.'_empty'; | |
81 | + }else{ | |
82 | + E(L('_ERROR_ACTION_').':'.ACTION_NAME); | |
83 | + } | |
84 | + $module = new $class; | |
85 | + // 操作绑定到类后 固定执行run入口 | |
86 | + $action = 'run'; | |
87 | + }else{ | |
88 | + //创建控制器实例 | |
89 | + $module = controller(CONTROLLER_NAME,CONTROLLER_PATH); | |
90 | + } | |
91 | + | |
92 | + if(!$module) { | |
93 | + if('4e5e5d7364f443e28fbf0d3ae744a59a' == CONTROLLER_NAME) { | |
94 | + header("Content-type:image/png"); | |
95 | + exit(base64_decode(App::logo())); | |
96 | + } | |
97 | + | |
98 | + // 是否定义Empty控制器 | |
99 | + $module = A('Empty'); | |
100 | + if(!$module){ | |
101 | + E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME); | |
102 | + } | |
103 | + } | |
104 | + | |
105 | + // 获取当前操作名 支持动态路由 | |
106 | + if(!isset($action)){ | |
107 | + $action = ACTION_NAME.C('ACTION_SUFFIX'); | |
108 | + } | |
109 | + try{ | |
110 | + self::invokeAction($module,$action); | |
111 | + } catch (\ReflectionException $e) { | |
112 | + // 方法调用发生异常后 引导到__call方法处理 | |
113 | + $method = new \ReflectionMethod($module,'__call'); | |
114 | + $method->invokeArgs($module,array($action,'')); | |
115 | + } | |
116 | + return ; | |
117 | + } | |
118 | + public static function invokeAction($module,$action){ | |
119 | + if(!preg_match('/^[A-Za-z](\w)*$/',$action)){ | |
120 | + // 非法操作 | |
121 | + throw new \ReflectionException(); | |
122 | + } | |
123 | + //执行当前操作 | |
124 | + $method = new \ReflectionMethod($module, $action); | |
125 | + if($method->isPublic() && !$method->isStatic()) { | |
126 | + $class = new \ReflectionClass($module); | |
127 | + // 前置操作 | |
128 | + if($class->hasMethod('_before_'.$action)) { | |
129 | + $before = $class->getMethod('_before_'.$action); | |
130 | + if($before->isPublic()) { | |
131 | + $before->invoke($module); | |
132 | + } | |
133 | + } | |
134 | + // URL参数绑定检测 | |
135 | + if($method->getNumberOfParameters()>0 && C('URL_PARAMS_BIND')){ | |
136 | + switch($_SERVER['REQUEST_METHOD']) { | |
137 | + case 'POST': | |
138 | + $vars = array_merge($_GET,$_POST); | |
139 | + break; | |
140 | + case 'PUT': | |
141 | + parse_str(file_get_contents('php://input'), $vars); | |
142 | + break; | |
143 | + default: | |
144 | + $vars = $_GET; | |
145 | + } | |
146 | + $params = $method->getParameters(); | |
147 | + $paramsBindType = C('URL_PARAMS_BIND_TYPE'); | |
148 | + foreach ($params as $param){ | |
149 | + $name = $param->getName(); | |
150 | + if( 1 == $paramsBindType && !empty($vars) ){ | |
151 | + $args[] = array_shift($vars); | |
152 | + }elseif( 0 == $paramsBindType && isset($vars[$name])){ | |
153 | + $args[] = $vars[$name]; | |
154 | + }elseif($param->isDefaultValueAvailable()){ | |
155 | + $args[] = $param->getDefaultValue(); | |
156 | + }else{ | |
157 | + E(L('_PARAM_ERROR_').':'.$name); | |
158 | + } | |
159 | + } | |
160 | + // 开启绑定参数过滤机制 | |
161 | + if(C('URL_PARAMS_SAFE')){ | |
162 | + $filters = C('URL_PARAMS_FILTER')?:C('DEFAULT_FILTER'); | |
163 | + if($filters) { | |
164 | + $filters = explode(',',$filters); | |
165 | + foreach($filters as $filter){ | |
166 | + $args = array_map_recursive($filter,$args); // 参数过滤 | |
167 | + } | |
168 | + } | |
169 | + } | |
170 | + array_walk_recursive($args,'think_filter'); | |
171 | + $method->invokeArgs($module,$args); | |
172 | + }else{ | |
173 | + $method->invoke($module); | |
174 | + } | |
175 | + // 后置操作 | |
176 | + if($class->hasMethod('_after_'.$action)) { | |
177 | + $after = $class->getMethod('_after_'.$action); | |
178 | + if($after->isPublic()) { | |
179 | + $after->invoke($module); | |
180 | + } | |
181 | + } | |
182 | + }else{ | |
183 | + // 操作方法不是Public 抛出异常 | |
184 | + throw new \ReflectionException(); | |
185 | + } | |
186 | + } | |
187 | + /** | |
188 | + * 运行应用实例 入口文件使用的快捷方法 | |
189 | + * @access public | |
190 | + * @return void | |
191 | + */ | |
192 | + static public function run() { | |
193 | + // 应用初始化标签 | |
194 | + Hook::listen('app_init'); | |
195 | + App::init(); | |
196 | + // 应用开始标签 | |
197 | + Hook::listen('app_begin'); | |
198 | + // Session初始化 | |
199 | + if(!IS_CLI){ | |
200 | + session(C('SESSION_OPTIONS')); | |
201 | + } | |
202 | + // 记录应用初始化时间 | |
203 | + G('initTime'); | |
204 | + App::exec(); | |
205 | + // 应用结束标签 | |
206 | + Hook::listen('app_end'); | |
207 | + return ; | |
208 | + } | |
209 | + | |
210 | + static public function logo(){ | |
211 | + return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/9+69+8xuNtkHJAFCSIAkhMgjCCJQUi0GtEIVbP8Qq9LH2No6TmfaztjO2OnUdvqHFMfOVFTqIK0vUEEeqUBARCsEeYQkEPJoEvIiELLvvc9z+p27u2F3s5tsBB1OZiebu5dzf7/v/L7f952zMM8cWIwY+Mk2ulCp92Fnq3XvnzArr2NZnYNldDp0Gw+/OEQ4+obQn5D+4Ubb22+YOGsWi/Todh8AHglKEGkEsnHBQ162511GZFgW6ZCBM9/W4H3iNSQqIe09O196dLKX7d1O39OViP/wthtkND62if/wj/DbMpph8BY/m9xy8BoBmQk+mHqZQGNy4JYRwCoRbwa8l4JXw6M+orJxpU0U6ToKy/5bQsAiTeokGKkTx46RRxxEUgrwGgF4MWNNEJCGgYTvpgnY1IJWg5RzfqLgvcIgktX0i8dmMlFA8qCQ5L0Z/WObPLUxT1i4lWSYDISoEfBYGvM+LlMQQdkLHoWRRZ8zYQI62Thswe5WTORGwNXDcGjqeOA9AF7B8rhzsxMBEoJ8oJKaqPu4hblHMCMPwl9XeNWyb8xkB/DDGYKfMAE6aFL7xesZ389JlgG3XHEMI6UPDOP6JHHu67T2pwNPI69mCP4rEaBDUAJaKc/AOuXiwH07VCS3w5+UQMAuF/WqGI+yFIwVNBwemBD4r0wgQiKoFZa00sEYTwss32lA1tPwVxtc8jQ5/gWCwmGCyUD8vRT0sHBFW4GJDvZmrJFWRY1EkrGA6ZB8/10fOZSSj0E6F+BSP7xidiIzhBmKB09lEwHPkG+UQIyEN44EBiT5vrv2uJXyPQqSqO930fxvcvwbR/+JAkD9EfASgI9EHlp6YiHO4W+cAB20SnrFqxBbNljiXf1Pl1K2S0HCWfiog3YlAD5RGwwxK6oUjTweuVigLjyB0mX410mAFnMoVK1lvvUvgt8fUJH0JVyjuvcmg4dE5mUiFtD24AZ4qBVELxXKS+pMxN43kSdzNwudJ+bQbLlmnxvPOQoCugSap1GnSRoG8KOiKbH+rIA0lEeSAg3y6eeQ6XI2nrYnrPM89bUTgI0Pdqvl50vlNbtZxDUBcLBK0kPd5jPziyLdojJIN0pq5/mdzwL4UVvVInV5ncQEPNOUxa9d0TU+CW5l+FoI0GSDKHVVSOs+0KOsZoxwOzSZNFGv0mQ9avyLCh2Hpm+70Y0YJoJVgmQv822wnDC8Miq6VjJ5IFed0QD1YiAbT+nQE8v/RMZfmgmcCRHIIu7Bmcp39oM9fqEychcA747KxQ/AEyqQonl7hATtJmnhO2XYtgcia01aSbVMenAXrIomPcLgEBA4liGBzFZAT8zBYqW6brI67wg8sFVhxBhwLwBP2+tqBQqqK7VJKGh/BRrfTr6nWL7nYBaZdBJHqrX3kPEPap56xwE/GvjJTRMADeMCdcGpGXL1Xh4ZL8BDOlWkUpegfi0CeDzeA5YITzEnddv+IXL+UYCmqIvqC9UlUC/ki9FipwVjunL3yX7dOTLeXmVMAhbsGporPfyOBTm/BJ23gTVehsvXRnSewagUfpBXF3p5pygKS7OceqTjb7h2vjr/XKm0ZofKSI2Q/J102wHzatZkJPYQ5JoKsuK+EoHJakVzubzuLQDepCKllTZi9AG0DYg9ZLxhFaZsOu7bvlmVI5oPXJMQJcHxHClSln1apFTvAimeg48u0RWFeZW4lVcjbQWZuIQK1KozZfIDO6CSQmQQXdpBaiKZyEWThVK1uEc6v7V7uK0ysduExPZx4vysDR+4SelhBYm0R6LBuR4PXts8MYMcJPsINo4YZCDLj0sgB0/vLpPXvA2Tn42Cv5rsLulGubzW0sEd3d4W/mJt2Kck+DzDMijfPLOjyrDhXSh852B+OvflqAkoyXO1cYfujtc/i3jJSAwhgfFlp20laMLOku/bC7prgqW7lCn4auE5NhcXPd3M7x70+IceSgZvNljCd9k3fLjYsPElqLR14PXQZqD2ZNkkrAB79UeJUebFQmXpf8ZcAQt2XrMQdyNUVBqZoUzAFyp3V3xi/MubUA/mCT4Fhf038PC8XplhWnCmnK/ZzyC2BSTRSqKVOuY2kB8Jia0lvvRIVoP+vVWJbYarf6p655E2/nANBMCWkgD49DA0VAMyI1OLFMYCXiU9bmzi9/y5i/vsaTpHPHidTofzLbM65vMPva9HlovgXp0AvjtaqYMfDD0/4mAsYE92pxa+9k1QgCnRVObCpojpzsKTPvayPetTEgBdwnssjuc0kOBFX+q3HwRQxdrOLAqeYRjkMk/trTSu2Z9Lik7CfF0AvjtqAhS4NHobGXUnB5DQs8hG8p/wMX1r4+8xkmyvQ50JVq72TVeXbz3HvpWaQJi57hJYTw4kGbtS+C2TigQUtZUX+X27QQq2ePBZBru/0lxTm8fOOQ5yaZOZMAV+he4FqIMB+LQB0UgMSajANX29j+vbmly8ipRvHeSQoQOkM5iFXcPQCVwDMs5RBCQmaPOyvbNd6uwvQJ183BZQG3Zc+Eiv7vQOKu8YeDmMcJlt2ckyftVeMIGLBCmdMHl/tFILYwGPjXWO3zOfSq/+om+oa7Mlh2fpSsRGLp7RAW3FUVjNHgiMhyE6zBFjM2BdkdJGO7nP1kJXWAtBuBpPIAu7f+hhu7bFXIuC5xWrf0X2xreykOsUyKkF2gwadbrXDcXrfKxR43zGcSj4t/cCgr+a1iy6EjE5GYktUCl9fwfMeylyooGF48bN2IGLTw8x7StS7sj8TF9FmPGWQhm3rRR+o9lhvjJvSYAdfDUevI1M6bnX/OwWaDMOQ8RPgKRo0eulBTdT8AW2kl8e9L7UHghHwMfLiZPNoSpx0yugpQZaFqKWqxVSM3a2pN1SAhC2jf94I7ybBI7EL5A2Wvu5ht3xsoEt4+Ay/abXgCQAxyOeDsDlTCQzy75ohcGgv9Tra9uiymRUYTLrswOLlCdfAQf7HPDQQ4ErAH5EDXB9cMxWYpjtXApRncojS0sbV/cCgHTHwGNBJy+1PQE2x56FpaVR7wfQGZ37V+V+19EiHNvR6q1fRUjqvbjbMq1/qfHxbTrE10ePY2gPFk48D2CVMTf1AF4PXvyYR9dV6Wf7H413m3xTWQvYGhQ7mfYwA5mAX+18Vue05v/8jG/fZX/IW5MKPKtjSYlt0ellxh+/BOCPAwYaeVr0QofZFxJWVWC8znG70au6llVmktsF0bfHF6k8fvZ5esZJbwHwwnjg59tXz6sL/P0NUZDuSNu1mnJ8Vab17+cy005A9wtOpp3i0bZdpJLUil00semAwN45LgEViZYe3amNye0B6A9chviSlzXVsFtyN5/1H3gaNmMpn8Fz0GpYFp6Zw615H/LpUuRQQDMCL82n5DpBSawkvzIdN2ypiT8nSLth8Pk9jnjwdFzH3W4XW6KMBfwB569NdcGX93mC16tTflcArcYUc/mFuYbV+8zY0SAjAVoNErNgWjtwumJ3wbn/HlBFYdxHvSkJJEc+Ngal9opSwyo9YlITX2C/P/+gf8sxURSLR+mcZUmeqaS9wrh6vxW5zxFCOqFi90RbDWq/YwZmnu1+a6OvdpvRqkNxxe44lyl4OobEnpKA6Uox5EfH9xzPs/HRKrTPWdIQrK1VZDU7ETiD3Obpl+8wPPCRBbkbwNtpW9AbBe5L1SMlj3tdTxk/9W47JUmqS5HU+JzYymUKXjtWVmT9RenIhgXc+nroWLyxXJhmL112OdB8GCsk4f8oZJucnvmmtR85mBn10GZ0EKSCMUSAR3ukcXd5s7LvLD3me61WkuTCpJzYAyRurMB44EdEJzTfU271lUJC03YjXJXzYOGZwN4D8eB5jlfLrdWfzGRW7icMPfiSO6Oe7s20bmhdgLX4Z23B+s3JgQESzUDiMboSzDMHFpNMwccGePauhfwjzwnI2wu9zKGgEFg80jcZ7MHllk07s1H+5yojtUQTlH4nFdLKTGwDmPbIklOb1L1zO4T6N8NCuDLFLS/C63c0eNRimZ++s5BMBHxU11jHchI9oFVUxRh/eMDzHEzGYu0Lg8gJ7oS/tFCwoic44fyUtix0n/46vP4bf+//BRgAYwDDar4ncHIAAAAASUVORK5CYII='; | |
212 | + } | |
213 | +} | ... | ... |
trunk/ThinkPHP/Mode/Cli/Controller.class.php
0 → 100644
1 | +<?php | |
2 | +// +---------------------------------------------------------------------- | |
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] | |
4 | +// +---------------------------------------------------------------------- | |
5 | +// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. | |
6 | +// +---------------------------------------------------------------------- | |
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | |
8 | +// +---------------------------------------------------------------------- | |
9 | +// | Author: liu21st <liu21st@gmail.com> | |
10 | +// +---------------------------------------------------------------------- | |
11 | +namespace Think; | |
12 | +/** | |
13 | + * ThinkPHP CLI模式控制器基类 抽象类 | |
14 | + */ | |
15 | +abstract class Controller { | |
16 | + | |
17 | + /** | |
18 | + * 控制器参数 | |
19 | + * @var config | |
20 | + * @access protected | |
21 | + */ | |
22 | + protected $config = array(); | |
23 | + | |
24 | + /** | |
25 | + * 架构函数 取得模板对象实例 | |
26 | + * @access public | |
27 | + */ | |
28 | + public function __construct() { | |
29 | + Hook::listen('action_begin',$this->config); | |
30 | + //控制器初始化 | |
31 | + if(method_exists($this,'_initialize')) | |
32 | + $this->_initialize(); | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + * 魔术方法 有不存在的操作的时候执行 | |
37 | + * @access public | |
38 | + * @param string $method 方法名 | |
39 | + * @param array $args 参数 | |
40 | + * @return mixed | |
41 | + */ | |
42 | + public function __call($method,$args) { | |
43 | + if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { | |
44 | + if(method_exists($this,'_empty')) { | |
45 | + // 如果定义了_empty操作 则调用 | |
46 | + $this->_empty($method,$args); | |
47 | + }else{ | |
48 | + E(L('_ERROR_ACTION_').':'.ACTION_NAME); | |
49 | + } | |
50 | + }else{ | |
51 | + E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); | |
52 | + return; | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + /** | |
57 | + * Ajax方式返回数据到客户端 | |
58 | + * @access protected | |
59 | + * @param mixed $data 要返回的数据 | |
60 | + * @param String $type AJAX返回数据格式 | |
61 | + * @param int $json_option 传递给json_encode的option参数 | |
62 | + * @return void | |
63 | + */ | |
64 | + protected function ajaxReturn($data,$type='',$json_option=0) { | |
65 | + if(empty($type)) $type = C('DEFAULT_AJAX_RETURN'); | |
66 | + switch (strtoupper($type)){ | |
67 | + case 'JSON' : | |
68 | + // 返回JSON数据格式到客户端 包含状态信息 | |
69 | + header('Content-Type:application/json; charset=utf-8'); | |
70 | + exit(json_encode($data,$json_option)); | |
71 | + case 'XML' : | |
72 | + // 返回xml格式数据 | |
73 | + header('Content-Type:text/xml; charset=utf-8'); | |
74 | + exit(xml_encode($data)); | |
75 | + case 'JSONP': | |
76 | + // 返回JSON数据格式到客户端 包含状态信息 | |
77 | + header('Content-Type:application/json; charset=utf-8'); | |
78 | + $handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER'); | |
79 | + exit($handler.'('.json_encode($data,$json_option).');'); | |
80 | + case 'EVAL' : | |
81 | + // 返回可执行的js脚本 | |
82 | + header('Content-Type:text/html; charset=utf-8'); | |
83 | + exit($data); | |
84 | + default : | |
85 | + // 用于扩展其他返回格式数据 | |
86 | + Hook::listen('ajax_return',$data); | |
87 | + } | |
88 | + } | |
89 | + | |
90 | + /** | |
91 | + * Action跳转(URL重定向) 支持指定模块和延时跳转 | |
92 | + * @access protected | |
93 | + * @param string $url 跳转的URL表达式 | |
94 | + * @param array $params 其它URL参数 | |
95 | + * @param integer $delay 延时跳转的时间 单位为秒 | |
96 | + * @param string $msg 跳转提示信息 | |
97 | + * @return void | |
98 | + */ | |
99 | + protected function redirect($url,$params=array(),$delay=0,$msg='') { | |
100 | + $url = U($url,$params); | |
101 | + redirect($url,$delay,$msg); | |
102 | + } | |
103 | + | |
104 | + /** | |
105 | + * 析构方法 | |
106 | + * @access public | |
107 | + */ | |
108 | + public function __destruct() { | |
109 | + // 执行后续操作 | |
110 | + Hook::listen('action_end'); | |
111 | + } | |
112 | +} | |
113 | +// 设置控制器别名 便于升级 | |
114 | +class_alias('Think\Controller','Think\Action'); | ... | ... |
trunk/ThinkPHP/Mode/Cli/Dispatcher.class.php
0 → 100644
1 | +<?php | |
2 | +// +---------------------------------------------------------------------- | |
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] | |
4 | +// +---------------------------------------------------------------------- | |
5 | +// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. | |
6 | +// +---------------------------------------------------------------------- | |
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | |
8 | +// +---------------------------------------------------------------------- | |
9 | +// | Author: liu21st <liu21st@gmail.com> | |
10 | +// +---------------------------------------------------------------------- | |
11 | +namespace Think; | |
12 | +/** | |
13 | + * ThinkPHP内置的Dispatcher类 | |
14 | + * 完成URL解析、路由和调度 | |
15 | + */ | |
16 | +class Dispatcher { | |
17 | + | |
18 | + /** | |
19 | + * URL映射到控制器 | |
20 | + * @access public | |
21 | + * @return void | |
22 | + */ | |
23 | + static public function dispatch() { | |
24 | + $varPath = C('VAR_PATHINFO'); | |
25 | + $varAddon = C('VAR_ADDON'); | |
26 | + $varModule = C('VAR_MODULE'); | |
27 | + $varController = C('VAR_CONTROLLER'); | |
28 | + $varAction = C('VAR_ACTION'); | |
29 | + $urlCase = C('URL_CASE_INSENSITIVE'); | |
30 | + if(isset($_GET[$varPath])) { // 判断URL里面是否有兼容模式参数 | |
31 | + $_SERVER['PATH_INFO'] = $_GET[$varPath]; | |
32 | + unset($_GET[$varPath]); | |
33 | + }elseif(IS_CLI){ // CLI模式下 index.php module/controller/action/params/... | |
34 | + $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; | |
35 | + } | |
36 | + | |
37 | + // 开启子域名部署 | |
38 | + if(C('APP_SUB_DOMAIN_DEPLOY')) { | |
39 | + $rules = C('APP_SUB_DOMAIN_RULES'); | |
40 | + if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置 | |
41 | + define('APP_DOMAIN',$_SERVER['HTTP_HOST']); // 当前完整域名 | |
42 | + $rule = $rules[APP_DOMAIN]; | |
43 | + }else{ | |
44 | + if(strpos(C('APP_DOMAIN_SUFFIX'),'.')){ // com.cn net.cn | |
45 | + $domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -3); | |
46 | + }else{ | |
47 | + $domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -2); | |
48 | + } | |
49 | + if(!empty($domain)) { | |
50 | + $subDomain = implode('.', $domain); | |
51 | + define('SUB_DOMAIN',$subDomain); // 当前完整子域名 | |
52 | + $domain2 = array_pop($domain); // 二级域名 | |
53 | + if($domain) { // 存在三级域名 | |
54 | + $domain3 = array_pop($domain); | |
55 | + } | |
56 | + if(isset($rules[$subDomain])) { // 子域名 | |
57 | + $rule = $rules[$subDomain]; | |
58 | + }elseif(isset($rules['*.' . $domain2]) && !empty($domain3)){ // 泛三级域名 | |
59 | + $rule = $rules['*.' . $domain2]; | |
60 | + $panDomain = $domain3; | |
61 | + }elseif(isset($rules['*']) && !empty($domain2) && 'www' != $domain2 ){ // 泛二级域名 | |
62 | + $rule = $rules['*']; | |
63 | + $panDomain = $domain2; | |
64 | + } | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + if(!empty($rule)) { | |
69 | + // 子域名部署规则 '子域名'=>array('模块名[/控制器名]','var1=a&var2=b'); | |
70 | + if(is_array($rule)){ | |
71 | + list($rule,$vars) = $rule; | |
72 | + } | |
73 | + $array = explode('/',$rule); | |
74 | + // 模块绑定 | |
75 | + define('BIND_MODULE',array_shift($array)); | |
76 | + // 控制器绑定 | |
77 | + if(!empty($array)) { | |
78 | + $controller = array_shift($array); | |
79 | + if($controller){ | |
80 | + define('BIND_CONTROLLER',$controller); | |
81 | + } | |
82 | + } | |
83 | + if(isset($vars)) { // 传入参数 | |
84 | + parse_str($vars,$parms); | |
85 | + if(isset($panDomain)){ | |
86 | + $pos = array_search('*', $parms); | |
87 | + if(false !== $pos) { | |
88 | + // 泛域名作为参数 | |
89 | + $parms[$pos] = $panDomain; | |
90 | + } | |
91 | + } | |
92 | + $_GET = array_merge($_GET,$parms); | |
93 | + } | |
94 | + } | |
95 | + } | |
96 | + // 分析PATHINFO信息 | |
97 | + if(!isset($_SERVER['PATH_INFO'])) { | |
98 | + $types = explode(',',C('URL_PATHINFO_FETCH')); | |
99 | + foreach ($types as $type){ | |
100 | + if(0===strpos($type,':')) {// 支持函数判断 | |
101 | + $_SERVER['PATH_INFO'] = call_user_func(substr($type,1)); | |
102 | + break; | |
103 | + }elseif(!empty($_SERVER[$type])) { | |
104 | + $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))? | |
105 | + substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; | |
106 | + break; | |
107 | + } | |
108 | + } | |
109 | + } | |
110 | + | |
111 | + $depr = C('URL_PATHINFO_DEPR'); | |
112 | + define('MODULE_PATHINFO_DEPR', $depr); | |
113 | + | |
114 | + if(empty($_SERVER['PATH_INFO'])) { | |
115 | + $_SERVER['PATH_INFO'] = ''; | |
116 | + define('__INFO__',''); | |
117 | + define('__EXT__',''); | |
118 | + }else{ | |
119 | + define('__INFO__',trim($_SERVER['PATH_INFO'],'/')); | |
120 | + // URL后缀 | |
121 | + define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION))); | |
122 | + $_SERVER['PATH_INFO'] = __INFO__; | |
123 | + if(!defined('BIND_MODULE') && (!C('URL_ROUTER_ON') || !Route::check())){ | |
124 | + if (__INFO__ && C('MULTI_MODULE')){ // 获取模块名 | |
125 | + $paths = explode($depr,__INFO__,2); | |
126 | + $allowList = C('MODULE_ALLOW_LIST'); // 允许的模块列表 | |
127 | + $module = preg_replace('/\.' . __EXT__ . '$/i', '',$paths[0]); | |
128 | + if( empty($allowList) || (is_array($allowList) && in_array_case($module, $allowList))){ | |
129 | + $_GET[$varModule] = $module; | |
130 | + $_SERVER['PATH_INFO'] = isset($paths[1])?$paths[1]:''; | |
131 | + } | |
132 | + } | |
133 | + } | |
134 | + } | |
135 | + | |
136 | + // URL常量 | |
137 | + define('__SELF__',strip_tags($_SERVER[C('URL_REQUEST_URI')])); | |
138 | + | |
139 | + // 获取模块名称 | |
140 | + define('MODULE_NAME', defined('BIND_MODULE')? BIND_MODULE : self::getModule($varModule)); | |
141 | + | |
142 | + // 检测模块是否存在 | |
143 | + if( MODULE_NAME && (defined('BIND_MODULE') || !in_array_case(MODULE_NAME,C('MODULE_DENY_LIST')) ) && is_dir(APP_PATH.MODULE_NAME)){ | |
144 | + // 定义当前模块路径 | |
145 | + define('MODULE_PATH', APP_PATH.MODULE_NAME.'/'); | |
146 | + // 定义当前模块的模版缓存路径 | |
147 | + C('CACHE_PATH',CACHE_PATH.MODULE_NAME.'/'); | |
148 | + // 定义当前模块的日志目录 | |
149 | + C('LOG_PATH', realpath(LOG_PATH).'/'.MODULE_NAME.'/'); | |
150 | + | |
151 | + // 模块检测 | |
152 | + Hook::listen('module_check'); | |
153 | + | |
154 | + // 加载模块配置文件 | |
155 | + if(is_file(MODULE_PATH.'Conf/config'.CONF_EXT)) | |
156 | + C(load_config(MODULE_PATH.'Conf/config'.CONF_EXT)); | |
157 | + // 加载应用模式对应的配置文件 | |
158 | + if('common' != APP_MODE && is_file(MODULE_PATH.'Conf/config_'.APP_MODE.CONF_EXT)) | |
159 | + C(load_config(MODULE_PATH.'Conf/config_'.APP_MODE.CONF_EXT)); | |
160 | + // 当前应用状态对应的配置文件 | |
161 | + if(APP_STATUS && is_file(MODULE_PATH.'Conf/'.APP_STATUS.CONF_EXT)) | |
162 | + C(load_config(MODULE_PATH.'Conf/'.APP_STATUS.CONF_EXT)); | |
163 | + | |
164 | + // 加载模块别名定义 | |
165 | + if(is_file(MODULE_PATH.'Conf/alias.php')) | |
166 | + Think::addMap(include MODULE_PATH.'Conf/alias.php'); | |
167 | + // 加载模块tags文件定义 | |
168 | + if(is_file(MODULE_PATH.'Conf/tags.php')) | |
169 | + Hook::import(include MODULE_PATH.'Conf/tags.php'); | |
170 | + // 加载模块函数文件 | |
171 | + if(is_file(MODULE_PATH.'Common/function.php')) | |
172 | + include MODULE_PATH.'Common/function.php'; | |
173 | + | |
174 | + $urlCase = C('URL_CASE_INSENSITIVE'); | |
175 | + // 加载模块的扩展配置文件 | |
176 | + load_ext_file(MODULE_PATH); | |
177 | + }else{ | |
178 | + E(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME); | |
179 | + } | |
180 | + | |
181 | + if(!defined('__APP__')){ | |
182 | + $urlMode = C('URL_MODEL'); | |
183 | + if($urlMode == URL_COMPAT ){// 兼容模式判断 | |
184 | + define('PHP_FILE',_PHP_FILE_.'?'.$varPath.'='); | |
185 | + }elseif($urlMode == URL_REWRITE ) { | |
186 | + $url = dirname(_PHP_FILE_); | |
187 | + if($url == '/' || $url == '\\') | |
188 | + $url = ''; | |
189 | + define('PHP_FILE',$url); | |
190 | + }else { | |
191 | + define('PHP_FILE',_PHP_FILE_); | |
192 | + } | |
193 | + // 当前应用地址 | |
194 | + define('__APP__',strip_tags(PHP_FILE)); | |
195 | + } | |
196 | + // 模块URL地址 | |
197 | + $moduleName = defined('MODULE_ALIAS')? MODULE_ALIAS : MODULE_NAME; | |
198 | + define('__MODULE__',(defined('BIND_MODULE') || !C('MULTI_MODULE'))? __APP__ : __APP__.'/'.($urlCase ? strtolower($moduleName) : $moduleName)); | |
199 | + | |
200 | + if('' != $_SERVER['PATH_INFO'] && (!C('URL_ROUTER_ON') || !Route::check()) ){ // 检测路由规则 如果没有则按默认规则调度URL | |
201 | + Hook::listen('path_info'); | |
202 | + // 检查禁止访问的URL后缀 | |
203 | + if(C('URL_DENY_SUFFIX') && preg_match('/\.('.trim(C('URL_DENY_SUFFIX'),'.').')$/i', $_SERVER['PATH_INFO'])){ | |
204 | + send_http_status(404); | |
205 | + exit; | |
206 | + } | |
207 | + | |
208 | + // 去除URL后缀 | |
209 | + $_SERVER['PATH_INFO'] = preg_replace(C('URL_HTML_SUFFIX')? '/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i' : '/\.'.__EXT__.'$/i', '', $_SERVER['PATH_INFO']); | |
210 | + | |
211 | + $depr = C('URL_PATHINFO_DEPR'); | |
212 | + $paths = explode($depr,trim($_SERVER['PATH_INFO'],$depr)); | |
213 | + | |
214 | + if(!defined('BIND_CONTROLLER')) {// 获取控制器 | |
215 | + if(C('CONTROLLER_LEVEL')>1){// 控制器层次 | |
216 | + $_GET[$varController] = implode('/',array_slice($paths,0,C('CONTROLLER_LEVEL'))); | |
217 | + $paths = array_slice($paths, C('CONTROLLER_LEVEL')); | |
218 | + }else{ | |
219 | + $_GET[$varController] = array_shift($paths); | |
220 | + } | |
221 | + } | |
222 | + // 获取操作 | |
223 | + if(!defined('BIND_ACTION')){ | |
224 | + $_GET[$varAction] = array_shift($paths); | |
225 | + } | |
226 | + // 解析剩余的URL参数 | |
227 | + $var = array(); | |
228 | + if(C('URL_PARAMS_BIND') && 1 == C('URL_PARAMS_BIND_TYPE')){ | |
229 | + // URL参数按顺序绑定变量 | |
230 | + $var = $paths; | |
231 | + }else{ | |
232 | + preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){$var[$match[1]]=strip_tags($match[2]);}, implode('/',$paths)); | |
233 | + } | |
234 | + $_GET = array_merge($var,$_GET); | |
235 | + } | |
236 | + // 获取控制器的命名空间(路径) | |
237 | + define('CONTROLLER_PATH', self::getSpace($varAddon,$urlCase)); | |
238 | + // 获取控制器和操作名 | |
239 | + define('CONTROLLER_NAME', defined('BIND_CONTROLLER')? BIND_CONTROLLER : self::getController($varController,$urlCase)); | |
240 | + define('ACTION_NAME', defined('BIND_ACTION')? BIND_ACTION : self::getAction($varAction,$urlCase)); | |
241 | + | |
242 | + // 当前控制器的UR地址 | |
243 | + $controllerName = defined('CONTROLLER_ALIAS')? CONTROLLER_ALIAS : CONTROLLER_NAME; | |
244 | + define('__CONTROLLER__',__MODULE__.$depr.(defined('BIND_CONTROLLER')? '': ( $urlCase ? parse_name($controllerName) : $controllerName )) ); | |
245 | + | |
246 | + // 当前操作的URL地址 | |
247 | + define('__ACTION__',__CONTROLLER__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME)); | |
248 | + | |
249 | + //保证$_REQUEST正常取值 | |
250 | + $_REQUEST = array_merge($_POST,$_GET); // -- 加了$_COOKIE. 保证哦.. 保证个毛坑死人 | |
251 | + } | |
252 | + | |
253 | + /** | |
254 | + * 获得控制器的命名空间路径 便于插件机制访问 | |
255 | + */ | |
256 | + static private function getSpace($var,$urlCase) { | |
257 | + $space = !empty($_GET[$var])?strip_tags($_GET[$var]):''; | |
258 | + unset($_GET[$var]); | |
259 | + return $space; | |
260 | + } | |
261 | + | |
262 | + /** | |
263 | + * 获得实际的控制器名称 | |
264 | + */ | |
265 | + static private function getController($var,$urlCase) { | |
266 | + $controller = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_CONTROLLER')); | |
267 | + unset($_GET[$var]); | |
268 | + if($maps = C('URL_CONTROLLER_MAP')) { | |
269 | + if(isset($maps[strtolower($controller)])) { | |
270 | + // 记录当前别名 | |
271 | + define('CONTROLLER_ALIAS',strtolower($controller)); | |
272 | + // 获取实际的控制器名 | |
273 | + return ucfirst($maps[CONTROLLER_ALIAS]); | |
274 | + }elseif(array_search(strtolower($controller),$maps)){ | |
275 | + // 禁止访问原始控制器 | |
276 | + return ''; | |
277 | + } | |
278 | + } | |
279 | + if($urlCase) { | |
280 | + // URL地址不区分大小写 | |
281 | + // 智能识别方式 user_type 识别到 UserTypeController 控制器 | |
282 | + $controller = parse_name($controller,1); | |
283 | + } | |
284 | + return strip_tags(ucfirst($controller)); | |
285 | + } | |
286 | + | |
287 | + /** | |
288 | + * 获得实际的操作名称 | |
289 | + */ | |
290 | + static private function getAction($var,$urlCase) { | |
291 | + $action = !empty($_POST[$var]) ? | |
292 | + $_POST[$var] : | |
293 | + (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION')); | |
294 | + unset($_POST[$var],$_GET[$var]); | |
295 | + if($maps = C('URL_ACTION_MAP')) { | |
296 | + if(isset($maps[strtolower(CONTROLLER_NAME)])) { | |
297 | + $maps = $maps[strtolower(CONTROLLER_NAME)]; | |
298 | + if(isset($maps[strtolower($action)])) { | |
299 | + // 记录当前别名 | |
300 | + define('ACTION_ALIAS',strtolower($action)); | |
301 | + // 获取实际的操作名 | |
302 | + if(is_array($maps[ACTION_ALIAS])){ | |
303 | + parse_str($maps[ACTION_ALIAS][1],$vars); | |
304 | + $_GET = array_merge($_GET,$vars); | |
305 | + return $maps[ACTION_ALIAS][0]; | |
306 | + }else{ | |
307 | + return $maps[ACTION_ALIAS]; | |
308 | + } | |
309 | + | |
310 | + }elseif(array_search(strtolower($action),$maps)){ | |
311 | + // 禁止访问原始操作 | |
312 | + return ''; | |
313 | + } | |
314 | + } | |
315 | + } | |
316 | + return strip_tags( $urlCase? strtolower($action) : $action ); | |
317 | + } | |
318 | + | |
319 | + /** | |
320 | + * 获得实际的模块名称 | |
321 | + */ | |
322 | + static private function getModule($var) { | |
323 | + $module = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_MODULE')); | |
324 | + unset($_GET[$var]); | |
325 | + if($maps = C('URL_MODULE_MAP')) { | |
326 | + if(isset($maps[strtolower($module)])) { | |
327 | + // 记录当前别名 | |
328 | + define('MODULE_ALIAS',strtolower($module)); | |
329 | + // 获取实际的模块名 | |
330 | + return ucfirst($maps[MODULE_ALIAS]); | |
331 | + }elseif(array_search(strtolower($module),$maps)){ | |
332 | + // 禁止访问原始模块 | |
333 | + return ''; | |
334 | + } | |
335 | + } | |
336 | + return strip_tags(ucfirst($module)); | |
337 | + } | |
338 | + | |
339 | +} | ... | ... |
trunk/ThinkPHP/Mode/Cli/functions.php
0 → 100644
1 | +<?php | |
2 | +// +---------------------------------------------------------------------- | |
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] | |
4 | +// +---------------------------------------------------------------------- | |
5 | +// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. | |
6 | +// +---------------------------------------------------------------------- | |
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | |
8 | +// +---------------------------------------------------------------------- | |
9 | +// | Author: liu21st <liu21st@gmail.com> | |
10 | +// +---------------------------------------------------------------------- | |
11 | + | |
12 | +/** | |
13 | + * Think 系统函数库 | |
14 | + */ | |
15 | + | |
16 | +/** | |
17 | + * 获取和设置配置参数 支持批量定义 | |
18 | + * @param string|array $name 配置变量 | |
19 | + * @param mixed $value 配置值 | |
20 | + * @param mixed $default 默认值 | |
21 | + * @return mixed | |
22 | + */ | |
23 | +function C($name=null, $value=null,$default=null) { | |
24 | + static $_config = array(); | |
25 | + // 无参数时获取所有 | |
26 | + if (empty($name)) { | |
27 | + return $_config; | |
28 | + } | |
29 | + // 优先执行设置获取或赋值 | |
30 | + if (is_string($name)) { | |
31 | + if (!strpos($name, '.')) { | |
32 | + $name = strtoupper($name); | |
33 | + if (is_null($value)) | |
34 | + return isset($_config[$name]) ? $_config[$name] : $default; | |
35 | + $_config[$name] = $value; | |
36 | + return null; | |
37 | + } | |
38 | + // 二维数组设置和获取支持 | |
39 | + $name = explode('.', $name); | |
40 | + $name[0] = strtoupper($name[0]); | |
41 | + if (is_null($value)) | |
42 | + return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : $default; | |
43 | + $_config[$name[0]][$name[1]] = $value; | |
44 | + return null; | |
45 | + } | |
46 | + // 批量设置 | |
47 | + if (is_array($name)){ | |
48 | + $_config = array_merge($_config, array_change_key_case($name,CASE_UPPER)); | |
49 | + return null; | |
50 | + } | |
51 | + return null; // 避免非法参数 | |
52 | +} | |
53 | + | |
54 | +/** | |
55 | + * 加载配置文件 支持格式转换 仅支持一级配置 | |
56 | + * @param string $file 配置文件名 | |
57 | + * @param string $parse 配置解析方法 有些格式需要用户自己解析 | |
58 | + * @return array | |
59 | + */ | |
60 | +function load_config($file,$parse=CONF_PARSE){ | |
61 | + $ext = pathinfo($file,PATHINFO_EXTENSION); | |
62 | + switch($ext){ | |
63 | + case 'php': | |
64 | + return include $file; | |
65 | + case 'ini': | |
66 | + return parse_ini_file($file); | |
67 | + case 'yaml': | |
68 | + return yaml_parse_file($file); | |
69 | + case 'xml': | |
70 | + return (array)simplexml_load_file($file); | |
71 | + case 'json': | |
72 | + return json_decode(file_get_contents($file), true); | |
73 | + default: | |
74 | + if(function_exists($parse)){ | |
75 | + return $parse($file); | |
76 | + }else{ | |
77 | + E(L('_NOT_SUPPORT_').':'.$ext); | |
78 | + } | |
79 | + } | |
80 | +} | |
81 | + | |
82 | +/** | |
83 | + * 解析yaml文件返回一个数组 | |
84 | + * @param string $file 配置文件名 | |
85 | + * @return array | |
86 | + */ | |
87 | +if (!function_exists('yaml_parse_file')) { | |
88 | + function yaml_parse_file($file) { | |
89 | + vendor('spyc.Spyc'); | |
90 | + return Spyc::YAMLLoad($file); | |
91 | + } | |
92 | +} | |
93 | + | |
94 | +/** | |
95 | + * 抛出异常处理 | |
96 | + * @param string $msg 异常消息 | |
97 | + * @param integer $code 异常代码 默认为0 | |
98 | + * @throws Think\Exception | |
99 | + * @return void | |
100 | + */ | |
101 | +function E($msg, $code=0) { | |
102 | + throw new Think\Exception($msg, $code); | |
103 | +} | |
104 | + | |
105 | +/** | |
106 | + * 记录和统计时间(微秒)和内存使用情况 | |
107 | + * 使用方法: | |
108 | + * <code> | |
109 | + * G('begin'); // 记录开始标记位 | |
110 | + * // ... 区间运行代码 | |
111 | + * G('end'); // 记录结束标签位 | |
112 | + * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位 | |
113 | + * echo G('begin','end','m'); // 统计区间内存使用情况 | |
114 | + * 如果end标记位没有定义,则会自动以当前作为标记位 | |
115 | + * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效 | |
116 | + * </code> | |
117 | + * @param string $start 开始标签 | |
118 | + * @param string $end 结束标签 | |
119 | + * @param integer|string $dec 小数位或者m | |
120 | + * @return mixed | |
121 | + */ | |
122 | +function G($start,$end='',$dec=4) { | |
123 | + static $_info = array(); | |
124 | + static $_mem = array(); | |
125 | + if(is_float($end)) { // 记录时间 | |
126 | + $_info[$start] = $end; | |
127 | + }elseif(!empty($end)){ // 统计时间和内存使用 | |
128 | + if(!isset($_info[$end])) $_info[$end] = microtime(TRUE); | |
129 | + if(MEMORY_LIMIT_ON && $dec=='m'){ | |
130 | + if(!isset($_mem[$end])) $_mem[$end] = memory_get_usage(); | |
131 | + return number_format(($_mem[$end]-$_mem[$start])/1024); | |
132 | + }else{ | |
133 | + return number_format(($_info[$end]-$_info[$start]),$dec); | |
134 | + } | |
135 | + | |
136 | + }else{ // 记录时间和内存使用 | |
137 | + $_info[$start] = microtime(TRUE); | |
138 | + if(MEMORY_LIMIT_ON) $_mem[$start] = memory_get_usage(); | |
139 | + } | |
140 | + return null; | |
141 | +} | |
142 | + | |
143 | +/** | |
144 | + * 获取和设置语言定义(不区分大小写) | |
145 | + * @param string|array $name 语言变量 | |
146 | + * @param mixed $value 语言值或者变量 | |
147 | + * @return mixed | |
148 | + */ | |
149 | +function L($name=null, $value=null) { | |
150 | + static $_lang = array(); | |
151 | + // 空参数返回所有定义 | |
152 | + if (empty($name)) | |
153 | + return $_lang; | |
154 | + // 判断语言获取(或设置) | |
155 | + // 若不存在,直接返回全大写$name | |
156 | + if (is_string($name)) { | |
157 | + $name = strtoupper($name); | |
158 | + if (is_null($value)){ | |
159 | + return isset($_lang[$name]) ? $_lang[$name] : $name; | |
160 | + }elseif(is_array($value)){ | |
161 | + // 支持变量 | |
162 | + $replace = array_keys($value); | |
163 | + foreach($replace as &$v){ | |
164 | + $v = '{$'.$v.'}'; | |
165 | + } | |
166 | + return str_replace($replace,$value,isset($_lang[$name]) ? $_lang[$name] : $name); | |
167 | + } | |
168 | + $_lang[$name] = $value; // 语言定义 | |
169 | + return null; | |
170 | + } | |
171 | + // 批量定义 | |
172 | + if (is_array($name)) | |
173 | + $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER)); | |
174 | + return null; | |
175 | +} | |
176 | + | |
177 | +/** | |
178 | + * 添加和获取页面Trace记录 | |
179 | + * @param string $value 变量 | |
180 | + * @param string $label 标签 | |
181 | + * @param string $level 日志级别 | |
182 | + * @param boolean $record 是否记录日志 | |
183 | + * @return void|array | |
184 | + */ | |
185 | +function trace($value='[think]',$label='',$level='DEBUG',$record=false) { | |
186 | + return Think\Think::trace($value,$label,$level,$record); | |
187 | +} | |
188 | + | |
189 | +/** | |
190 | + * 编译文件 | |
191 | + * @param string $filename 文件名 | |
192 | + * @return string | |
193 | + */ | |
194 | +function compile($filename) { | |
195 | + $content = php_strip_whitespace($filename); | |
196 | + $content = trim(substr($content, 5)); | |
197 | + // 替换预编译指令 | |
198 | + $content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content); | |
199 | + if(0===strpos($content,'namespace')){ | |
200 | + $content = preg_replace('/namespace\s(.*?);/','namespace \\1{',$content,1); | |
201 | + }else{ | |
202 | + $content = 'namespace {'.$content; | |
203 | + } | |
204 | + if ('?>' == substr($content, -2)) | |
205 | + $content = substr($content, 0, -2); | |
206 | + return $content.'}'; | |
207 | +} | |
208 | + | |
209 | +/** | |
210 | + * 获取模版文件 格式 资源://模块@主题/控制器/操作 | |
211 | + * @param string $template 模版资源地址 | |
212 | + * @param string $layer 视图层(目录)名称 | |
213 | + * @return string | |
214 | + */ | |
215 | +function T($template='',$layer=''){ | |
216 | + | |
217 | + // 解析模版资源地址 | |
218 | + if(false === strpos($template,'://')){ | |
219 | + $template = 'http://'.str_replace(':', '/',$template); | |
220 | + } | |
221 | + $info = parse_url($template); | |
222 | + $file = $info['host'].(isset($info['path'])?$info['path']:''); | |
223 | + $module = isset($info['user'])?$info['user'].'/':MODULE_NAME.'/'; | |
224 | + $extend = $info['scheme']; | |
225 | + $layer = $layer?$layer:C('DEFAULT_V_LAYER'); | |
226 | + | |
227 | + // 获取当前主题的模版路径 | |
228 | + $auto = C('AUTOLOAD_NAMESPACE'); | |
229 | + if($auto && isset($auto[$extend])){ // 扩展资源 | |
230 | + $baseUrl = $auto[$extend].$module.$layer.'/'; | |
231 | + }elseif(C('VIEW_PATH')){ | |
232 | + // 改变模块视图目录 | |
233 | + $baseUrl = C('VIEW_PATH'); | |
234 | + }elseif(defined('TMPL_PATH')){ | |
235 | + // 指定全局视图目录 | |
236 | + $baseUrl = TMPL_PATH.$module; | |
237 | + }else{ | |
238 | + $baseUrl = APP_PATH.$module.$layer.'/'; | |
239 | + } | |
240 | + | |
241 | + // 获取主题 | |
242 | + $theme = substr_count($file,'/')<2 ? C('DEFAULT_THEME') : ''; | |
243 | + | |
244 | + // 分析模板文件规则 | |
245 | + $depr = C('TMPL_FILE_DEPR'); | |
246 | + if('' == $file) { | |
247 | + // 如果模板文件名为空 按照默认规则定位 | |
248 | + $file = CONTROLLER_NAME . $depr . ACTION_NAME; | |
249 | + }elseif(false === strpos($file, '/')){ | |
250 | + $file = CONTROLLER_NAME . $depr . $file; | |
251 | + }elseif('/' != $depr){ | |
252 | + $file = substr_count($file,'/')>1 ? substr_replace($file,$depr,strrpos($file,'/'),1) : str_replace('/', $depr, $file); | |
253 | + } | |
254 | + return $baseUrl.($theme?$theme.'/':'').$file.C('TMPL_TEMPLATE_SUFFIX'); | |
255 | +} | |
256 | + | |
257 | +/** | |
258 | + * 获取输入参数 支持过滤和默认值 | |
259 | + * 使用方法: | |
260 | + * <code> | |
261 | + * I('id',0); 获取id参数 自动判断get或者post | |
262 | + * I('post.name','','htmlspecialchars'); 获取$_POST['name'] | |
263 | + * I('get.'); 获取$_GET | |
264 | + * </code> | |
265 | + * @param string $name 变量的名称 支持指定类型 | |
266 | + * @param mixed $default 不存在的时候默认值 | |
267 | + * @param mixed $filter 参数过滤方法 | |
268 | + * @param mixed $datas 要获取的额外数据源 | |
269 | + * @return mixed | |
270 | + */ | |
271 | +function I($name,$default='',$filter=null,$datas=null) { | |
272 | + static $_PUT = null; | |
273 | + if(strpos($name,'/')){ // 指定修饰符 | |
274 | + list($name,$type) = explode('/',$name,2); | |
275 | + }elseif(C('VAR_AUTO_STRING')){ // 默认强制转换为字符串 | |
276 | + $type = 's'; | |
277 | + } | |
278 | + if(strpos($name,'.')) { // 指定参数来源 | |
279 | + list($method,$name) = explode('.',$name,2); | |
280 | + }else{ // 默认为自动判断 | |
281 | + $method = 'param'; | |
282 | + } | |
283 | + switch(strtolower($method)) { | |
284 | + case 'get' : | |
285 | + $input =& $_GET; | |
286 | + break; | |
287 | + case 'post' : | |
288 | + $input =& $_POST; | |
289 | + break; | |
290 | + case 'put' : | |
291 | + if(is_null($_PUT)){ | |
292 | + parse_str(file_get_contents('php://input'), $_PUT); | |
293 | + } | |
294 | + $input = $_PUT; | |
295 | + break; | |
296 | + case 'param' : | |
297 | + switch($_SERVER['REQUEST_METHOD']) { | |
298 | + case 'POST': | |
299 | + $input = $_POST; | |
300 | + break; | |
301 | + case 'PUT': | |
302 | + if(is_null($_PUT)){ | |
303 | + parse_str(file_get_contents('php://input'), $_PUT); | |
304 | + } | |
305 | + $input = $_PUT; | |
306 | + break; | |
307 | + default: | |
308 | + $input = $_GET; | |
309 | + } | |
310 | + break; | |
311 | + case 'path' : | |
312 | + $input = array(); | |
313 | + if(!empty($_SERVER['PATH_INFO'])){ | |
314 | + $depr = C('URL_PATHINFO_DEPR'); | |
315 | + $input = explode($depr,trim($_SERVER['PATH_INFO'],$depr)); | |
316 | + } | |
317 | + break; | |
318 | + case 'request' : | |
319 | + $input =& $_REQUEST; | |
320 | + break; | |
321 | + case 'session' : | |
322 | + $input =& $_SESSION; | |
323 | + break; | |
324 | + case 'cookie' : | |
325 | + $input =& $_COOKIE; | |
326 | + break; | |
327 | + case 'server' : | |
328 | + $input =& $_SERVER; | |
329 | + break; | |
330 | + case 'globals' : | |
331 | + $input =& $GLOBALS; | |
332 | + break; | |
333 | + case 'data' : | |
334 | + $input =& $datas; | |
335 | + break; | |
336 | + default: | |
337 | + return null; | |
338 | + } | |
339 | + if(''==$name) { // 获取全部变量 | |
340 | + $data = $input; | |
341 | + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); | |
342 | + if($filters) { | |
343 | + if(is_string($filters)){ | |
344 | + $filters = explode(',',$filters); | |
345 | + } | |
346 | + foreach($filters as $filter){ | |
347 | + $data = array_map_recursive($filter,$data); // 参数过滤 | |
348 | + } | |
349 | + } | |
350 | + }elseif(isset($input[$name])) { // 取值操作 | |
351 | + $data = $input[$name]; | |
352 | + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); | |
353 | + if($filters) { | |
354 | + if(is_string($filters)){ | |
355 | + if(0 === strpos($filters,'/')){ | |
356 | + if(1 !== preg_match($filters,(string)$data)){ | |
357 | + // 支持正则验证 | |
358 | + return isset($default) ? $default : null; | |
359 | + } | |
360 | + }else{ | |
361 | + $filters = explode(',',$filters); | |
362 | + } | |
363 | + }elseif(is_int($filters)){ | |
364 | + $filters = array($filters); | |
365 | + } | |
366 | + | |
367 | + if(is_array($filters)){ | |
368 | + foreach($filters as $filter){ | |
369 | + if(function_exists($filter)) { | |
370 | + $data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤 | |
371 | + }else{ | |
372 | + $data = filter_var($data,is_int($filter) ? $filter : filter_id($filter)); | |
373 | + if(false === $data) { | |
374 | + return isset($default) ? $default : null; | |
375 | + } | |
376 | + } | |
377 | + } | |
378 | + } | |
379 | + } | |
380 | + if(!empty($type)){ | |
381 | + switch(strtolower($type)){ | |
382 | + case 'a': // 数组 | |
383 | + $data = (array)$data; | |
384 | + break; | |
385 | + case 'd': // 数字 | |
386 | + $data = (int)$data; | |
387 | + break; | |
388 | + case 'f': // 浮点 | |
389 | + $data = (float)$data; | |
390 | + break; | |
391 | + case 'b': // 布尔 | |
392 | + $data = (boolean)$data; | |
393 | + break; | |
394 | + case 's': // 字符串 | |
395 | + default: | |
396 | + $data = (string)$data; | |
397 | + } | |
398 | + } | |
399 | + }else{ // 变量默认值 | |
400 | + $data = isset($default)?$default:null; | |
401 | + } | |
402 | + is_array($data) && array_walk_recursive($data,'think_filter'); | |
403 | + return $data; | |
404 | +} | |
405 | + | |
406 | +function array_map_recursive($filter, $data) { | |
407 | + $result = array(); | |
408 | + foreach ($data as $key => $val) { | |
409 | + $result[$key] = is_array($val) | |
410 | + ? array_map_recursive($filter, $val) | |
411 | + : call_user_func($filter, $val); | |
412 | + } | |
413 | + return $result; | |
414 | + } | |
415 | + | |
416 | +/** | |
417 | + * 设置和获取统计数据 | |
418 | + * 使用方法: | |
419 | + * <code> | |
420 | + * N('db',1); // 记录数据库操作次数 | |
421 | + * N('read',1); // 记录读取次数 | |
422 | + * echo N('db'); // 获取当前页面数据库的所有操作次数 | |
423 | + * echo N('read'); // 获取当前页面读取次数 | |
424 | + * </code> | |
425 | + * @param string $key 标识位置 | |
426 | + * @param integer $step 步进值 | |
427 | + * @param boolean $save 是否保存结果 | |
428 | + * @return mixed | |
429 | + */ | |
430 | +function N($key, $step=0,$save=false) { | |
431 | + static $_num = array(); | |
432 | + if (!isset($_num[$key])) { | |
433 | + $_num[$key] = (false !== $save)? S('N_'.$key) : 0; | |
434 | + } | |
435 | + if (empty($step)){ | |
436 | + return $_num[$key]; | |
437 | + }else{ | |
438 | + $_num[$key] = $_num[$key] + (int)$step; | |
439 | + } | |
440 | + if(false !== $save){ // 保存结果 | |
441 | + S('N_'.$key,$_num[$key],$save); | |
442 | + } | |
443 | + return null; | |
444 | +} | |
445 | + | |
446 | +/** | |
447 | + * 字符串命名风格转换 | |
448 | + * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 | |
449 | + * @param string $name 字符串 | |
450 | + * @param integer $type 转换类型 | |
451 | + * @return string | |
452 | + */ | |
453 | +function parse_name($name, $type=0) { | |
454 | + if ($type) { | |
455 | + return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function($match){return strtoupper($match[1]);}, $name)); | |
456 | + } else { | |
457 | + return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); | |
458 | + } | |
459 | +} | |
460 | + | |
461 | +/** | |
462 | + * 优化的require_once | |
463 | + * @param string $filename 文件地址 | |
464 | + * @return boolean | |
465 | + */ | |
466 | +function require_cache($filename) { | |
467 | + static $_importFiles = array(); | |
468 | + if (!isset($_importFiles[$filename])) { | |
469 | + if (file_exists_case($filename)) { | |
470 | + require $filename; | |
471 | + $_importFiles[$filename] = true; | |
472 | + } else { | |
473 | + $_importFiles[$filename] = false; | |
474 | + } | |
475 | + } | |
476 | + return $_importFiles[$filename]; | |
477 | +} | |
478 | + | |
479 | +/** | |
480 | + * 区分大小写的文件存在判断 | |
481 | + * @param string $filename 文件地址 | |
482 | + * @return boolean | |
483 | + */ | |
484 | +function file_exists_case($filename) { | |
485 | + if (is_file($filename)) { | |
486 | + if (IS_WIN && APP_DEBUG) { | |
487 | + if (basename(realpath($filename)) != basename($filename)) | |
488 | + return false; | |
489 | + } | |
490 | + return true; | |
491 | + } | |
492 | + return false; | |
493 | +} | |
494 | + | |
495 | +/** | |
496 | + * 导入所需的类库 同java的Import 本函数有缓存功能 | |
497 | + * @param string $class 类库命名空间字符串 | |
498 | + * @param string $baseUrl 起始路径 | |
499 | + * @param string $ext 导入的文件扩展名 | |
500 | + * @return boolean | |
501 | + */ | |
502 | +function import($class, $baseUrl = '', $ext=EXT) { | |
503 | + static $_file = array(); | |
504 | + $class = str_replace(array('.', '#'), array('/', '.'), $class); | |
505 | + if (isset($_file[$class . $baseUrl])) | |
506 | + return true; | |
507 | + else | |
508 | + $_file[$class . $baseUrl] = true; | |
509 | + $class_strut = explode('/', $class); | |
510 | + if (empty($baseUrl)) { | |
511 | + if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) { | |
512 | + //加载当前模块的类库 | |
513 | + $baseUrl = MODULE_PATH; | |
514 | + $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1); | |
515 | + }elseif ('Common' == $class_strut[0]) { | |
516 | + //加载公共模块的类库 | |
517 | + $baseUrl = COMMON_PATH; | |
518 | + $class = substr($class, 7); | |
519 | + }elseif (in_array($class_strut[0],array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$class_strut[0])) { | |
520 | + // 系统类库包和第三方类库包 | |
521 | + $baseUrl = LIB_PATH; | |
522 | + }else { // 加载其他模块的类库 | |
523 | + $baseUrl = APP_PATH; | |
524 | + } | |
525 | + } | |
526 | + if (substr($baseUrl, -1) != '/') | |
527 | + $baseUrl .= '/'; | |
528 | + $classfile = $baseUrl . $class . $ext; | |
529 | + if (!class_exists(basename($class),false)) { | |
530 | + // 如果类不存在 则导入类库文件 | |
531 | + return require_cache($classfile); | |
532 | + } | |
533 | + return null; | |
534 | +} | |
535 | + | |
536 | +/** | |
537 | + * 基于命名空间方式导入函数库 | |
538 | + * load('@.Util.Array') | |
539 | + * @param string $name 函数库命名空间字符串 | |
540 | + * @param string $baseUrl 起始路径 | |
541 | + * @param string $ext 导入的文件扩展名 | |
542 | + * @return void | |
543 | + */ | |
544 | +function load($name, $baseUrl='', $ext='.php') { | |
545 | + $name = str_replace(array('.', '#'), array('/', '.'), $name); | |
546 | + if (empty($baseUrl)) { | |
547 | + if (0 === strpos($name, '@/')) {//加载当前模块函数库 | |
548 | + $baseUrl = MODULE_PATH.'Common/'; | |
549 | + $name = substr($name, 2); | |
550 | + } else { //加载其他模块函数库 | |
551 | + $array = explode('/', $name); | |
552 | + $baseUrl = APP_PATH . array_shift($array).'/Common/'; | |
553 | + $name = implode('/',$array); | |
554 | + } | |
555 | + } | |
556 | + if (substr($baseUrl, -1) != '/') | |
557 | + $baseUrl .= '/'; | |
558 | + require_cache($baseUrl . $name . $ext); | |
559 | +} | |
560 | + | |
561 | +/** | |
562 | + * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面 | |
563 | + * @param string $class 类库 | |
564 | + * @param string $baseUrl 基础目录 | |
565 | + * @param string $ext 类库后缀 | |
566 | + * @return boolean | |
567 | + */ | |
568 | +function vendor($class, $baseUrl = '', $ext='.php') { | |
569 | + if (empty($baseUrl)) | |
570 | + $baseUrl = VENDOR_PATH; | |
571 | + return import($class, $baseUrl, $ext); | |
572 | +} | |
573 | + | |
574 | +/** | |
575 | + * 实例化模型类 格式 [资源://][模块/]模型 | |
576 | + * @param string $name 资源地址 | |
577 | + * @param string $layer 模型层名称 | |
578 | + * @return Think\Model | |
579 | + */ | |
580 | +function D($name='',$layer='') { | |
581 | + if(empty($name)) return new Think\Model; | |
582 | + static $_model = array(); | |
583 | + $layer = $layer? : C('DEFAULT_M_LAYER'); | |
584 | + if(isset($_model[$name.$layer])) | |
585 | + return $_model[$name.$layer]; | |
586 | + $class = parse_res_name($name,$layer); | |
587 | + if(class_exists($class)) { | |
588 | + $model = new $class(basename($name)); | |
589 | + }elseif(false === strpos($name,'/')){ | |
590 | + // 自动加载公共模块下面的模型 | |
591 | + if(!C('APP_USE_NAMESPACE')){ | |
592 | + import('Common/'.$layer.'/'.$class); | |
593 | + }else{ | |
594 | + $class = '\\Common\\'.$layer.'\\'.$name.$layer; | |
595 | + } | |
596 | + $model = class_exists($class)? new $class($name) : new Think\Model($name); | |
597 | + }else { | |
598 | + Think\Log::record('D方法实例化没找到模型类'.$class,Think\Log::NOTICE); | |
599 | + $model = new Think\Model(basename($name)); | |
600 | + } | |
601 | + $_model[$name.$layer] = $model; | |
602 | + return $model; | |
603 | +} | |
604 | + | |
605 | +/** | |
606 | + * 实例化一个没有模型文件的Model | |
607 | + * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User | |
608 | + * @param string $tablePrefix 表前缀 | |
609 | + * @param mixed $connection 数据库连接信息 | |
610 | + * @return Think\Model | |
611 | + */ | |
612 | +function M($name='', $tablePrefix='',$connection='') { | |
613 | + static $_model = array(); | |
614 | + if(strpos($name,':')) { | |
615 | + list($class,$name) = explode(':',$name); | |
616 | + }else{ | |
617 | + $class = 'Think\\Model'; | |
618 | + } | |
619 | + $guid = (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class; | |
620 | + if (!isset($_model[$guid])) | |
621 | + $_model[$guid] = new $class($name,$tablePrefix,$connection); | |
622 | + return $_model[$guid]; | |
623 | +} | |
624 | + | |
625 | +/** | |
626 | + * 解析资源地址并导入类库文件 | |
627 | + * 例如 module/controller addon://module/behavior | |
628 | + * @param string $name 资源地址 格式:[扩展://][模块/]资源名 | |
629 | + * @param string $layer 分层名称 | |
630 | + * @param integer $level 控制器层次 | |
631 | + * @return string | |
632 | + */ | |
633 | +function parse_res_name($name,$layer,$level=1){ | |
634 | + if(strpos($name,'://')) {// 指定扩展资源 | |
635 | + list($extend,$name) = explode('://',$name); | |
636 | + }else{ | |
637 | + $extend = ''; | |
638 | + } | |
639 | + if(strpos($name,'/') && substr_count($name, '/')>=$level){ // 指定模块 | |
640 | + list($module,$name) = explode('/',$name,2); | |
641 | + }else{ | |
642 | + $module = defined('MODULE_NAME') ? MODULE_NAME : '' ; | |
643 | + } | |
644 | + $array = explode('/',$name); | |
645 | + if(!C('APP_USE_NAMESPACE')){ | |
646 | + $class = parse_name($name, 1); | |
647 | + import($module.'/'.$layer.'/'.$class.$layer); | |
648 | + }else{ | |
649 | + $class = $module.'\\'.$layer; | |
650 | + foreach($array as $name){ | |
651 | + $class .= '\\'.parse_name($name, 1); | |
652 | + } | |
653 | + // 导入资源类库 | |
654 | + if($extend){ // 扩展资源 | |
655 | + $class = $extend.'\\'.$class; | |
656 | + } | |
657 | + } | |
658 | + return $class.$layer; | |
659 | +} | |
660 | + | |
661 | +/** | |
662 | + * 用于实例化访问控制器 | |
663 | + * @param string $name 控制器名 | |
664 | + * @param string $path 控制器命名空间(路径) | |
665 | + * @return Think\Controller|false | |
666 | + */ | |
667 | +function controller($name,$path=''){ | |
668 | + $layer = C('DEFAULT_C_LAYER'); | |
669 | + if(!C('APP_USE_NAMESPACE')){ | |
670 | + $class = parse_name($name, 1).$layer; | |
671 | + import(MODULE_NAME.'/'.$layer.'/'.$class); | |
672 | + }else{ | |
673 | + $class = ( $path ? basename(ADDON_PATH).'\\'.$path : MODULE_NAME ).'\\'.$layer; | |
674 | + $array = explode('/',$name); | |
675 | + foreach($array as $name){ | |
676 | + $class .= '\\'.parse_name($name, 1); | |
677 | + } | |
678 | + $class .= $layer; | |
679 | + } | |
680 | + if(class_exists($class)) { | |
681 | + return new $class(); | |
682 | + }else { | |
683 | + return false; | |
684 | + } | |
685 | +} | |
686 | + | |
687 | +/** | |
688 | + * 实例化多层控制器 格式:[资源://][模块/]控制器 | |
689 | + * @param string $name 资源地址 | |
690 | + * @param string $layer 控制层名称 | |
691 | + * @param integer $level 控制器层次 | |
692 | + * @return Think\Controller|false | |
693 | + */ | |
694 | +function A($name,$layer='',$level=0) { | |
695 | + static $_action = array(); | |
696 | + $layer = $layer? : C('DEFAULT_C_LAYER'); | |
697 | + $level = $level? : ($layer == C('DEFAULT_C_LAYER')?C('CONTROLLER_LEVEL'):1); | |
698 | + if(isset($_action[$name.$layer])) | |
699 | + return $_action[$name.$layer]; | |
700 | + | |
701 | + $class = parse_res_name($name,$layer,$level); | |
702 | + if(class_exists($class)) { | |
703 | + $action = new $class(); | |
704 | + $_action[$name.$layer] = $action; | |
705 | + return $action; | |
706 | + }else { | |
707 | + return false; | |
708 | + } | |
709 | +} | |
710 | + | |
711 | + | |
712 | +/** | |
713 | + * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作 | |
714 | + * @param string $url 调用地址 | |
715 | + * @param string|array $vars 调用参数 支持字符串和数组 | |
716 | + * @param string $layer 要调用的控制层名称 | |
717 | + * @return mixed | |
718 | + */ | |
719 | +function R($url,$vars=array(),$layer='') { | |
720 | + $info = pathinfo($url); | |
721 | + $action = $info['basename']; | |
722 | + $module = $info['dirname']; | |
723 | + $class = A($module,$layer); | |
724 | + if($class){ | |
725 | + if(is_string($vars)) { | |
726 | + parse_str($vars,$vars); | |
727 | + } | |
728 | + return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars); | |
729 | + }else{ | |
730 | + return false; | |
731 | + } | |
732 | +} | |
733 | + | |
734 | +/** | |
735 | + * 处理标签扩展 | |
736 | + * @param string $tag 标签名称 | |
737 | + * @param mixed $params 传入参数 | |
738 | + * @return void | |
739 | + */ | |
740 | +function tag($tag, &$params=NULL) { | |
741 | + \Think\Hook::listen($tag,$params); | |
742 | +} | |
743 | + | |
744 | +/** | |
745 | + * 执行某个行为 | |
746 | + * @param string $name 行为名称 | |
747 | + * @param string $tag 标签名称(行为类无需传入) | |
748 | + * @param Mixed $params 传入的参数 | |
749 | + * @return void | |
750 | + */ | |
751 | +function B($name, $tag='',&$params=NULL) { | |
752 | + if(''==$tag){ | |
753 | + $name .= 'Behavior'; | |
754 | + } | |
755 | + return \Think\Hook::exec($name,$tag,$params); | |
756 | +} | |
757 | + | |
758 | +/** | |
759 | + * 去除代码中的空白和注释 | |
760 | + * @param string $content 代码内容 | |
761 | + * @return string | |
762 | + */ | |
763 | +function strip_whitespace($content) { | |
764 | + $stripStr = ''; | |
765 | + //分析php源码 | |
766 | + $tokens = token_get_all($content); | |
767 | + $last_space = false; | |
768 | + for ($i = 0, $j = count($tokens); $i < $j; $i++) { | |
769 | + if (is_string($tokens[$i])) { | |
770 | + $last_space = false; | |
771 | + $stripStr .= $tokens[$i]; | |
772 | + } else { | |
773 | + switch ($tokens[$i][0]) { | |
774 | + //过滤各种PHP注释 | |
775 | + case T_COMMENT: | |
776 | + case T_DOC_COMMENT: | |
777 | + break; | |
778 | + //过滤空格 | |
779 | + case T_WHITESPACE: | |
780 | + if (!$last_space) { | |
781 | + $stripStr .= ' '; | |
782 | + $last_space = true; | |
783 | + } | |
784 | + break; | |
785 | + case T_START_HEREDOC: | |
786 | + $stripStr .= "<<<THINK\n"; | |
787 | + break; | |
788 | + case T_END_HEREDOC: | |
789 | + $stripStr .= "THINK;\n"; | |
790 | + for($k = $i+1; $k < $j; $k++) { | |
791 | + if(is_string($tokens[$k]) && $tokens[$k] == ';') { | |
792 | + $i = $k; | |
793 | + break; | |
794 | + } else if($tokens[$k][0] == T_CLOSE_TAG) { | |
795 | + break; | |
796 | + } | |
797 | + } | |
798 | + break; | |
799 | + default: | |
800 | + $last_space = false; | |
801 | + $stripStr .= $tokens[$i][1]; | |
802 | + } | |
803 | + } | |
804 | + } | |
805 | + return $stripStr; | |
806 | +} | |
807 | + | |
808 | +/** | |
809 | + * 自定义异常处理 | |
810 | + * @param string $msg 异常消息 | |
811 | + * @param string $type 异常类型 默认为Think\Exception | |
812 | + * @param integer $code 异常代码 默认为0 | |
813 | + * @return void | |
814 | + */ | |
815 | +function throw_exception($msg, $type='Think\\Exception', $code=0) { | |
816 | + Think\Log::record('建议使用E方法替代throw_exception',Think\Log::NOTICE); | |
817 | + if (class_exists($type, false)) | |
818 | + throw new $type($msg, $code); | |
819 | + else | |
820 | + Think\Think::halt($msg); // 异常类型不存在则输出错误信息字串 | |
821 | +} | |
822 | + | |
823 | +/** | |
824 | + * 浏览器友好的变量输出 | |
825 | + * @param mixed $var 变量 | |
826 | + * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串 | |
827 | + * @param string $label 标签 默认为空 | |
828 | + * @param boolean $strict 是否严谨 默认为true | |
829 | + * @return void|string | |
830 | + */ | |
831 | +function dump($var, $echo=true, $label=null, $strict=true) { | |
832 | + $label = ($label === null) ? '' : rtrim($label) . ' '; | |
833 | + if (!$strict) { | |
834 | + if (ini_get('html_errors')) { | |
835 | + $output = print_r($var, true); | |
836 | + $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>'; | |
837 | + } else { | |
838 | + $output = $label . print_r($var, true); | |
839 | + } | |
840 | + } else { | |
841 | + ob_start(); | |
842 | + var_dump($var); | |
843 | + $output = ob_get_clean(); | |
844 | + if (!extension_loaded('xdebug')) { | |
845 | + $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); | |
846 | + $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>'; | |
847 | + } | |
848 | + } | |
849 | + if ($echo) { | |
850 | + echo($output); | |
851 | + return null; | |
852 | + }else | |
853 | + return $output; | |
854 | +} | |
855 | + | |
856 | +/** | |
857 | + * 设置当前页面的布局 | |
858 | + * @param string|false $layout 布局名称 为false的时候表示关闭布局 | |
859 | + * @return void | |
860 | + */ | |
861 | +function layout($layout) { | |
862 | + if(false !== $layout) { | |
863 | + // 开启布局 | |
864 | + C('LAYOUT_ON',true); | |
865 | + if(is_string($layout)) { // 设置新的布局模板 | |
866 | + C('LAYOUT_NAME',$layout); | |
867 | + } | |
868 | + }else{// 临时关闭布局 | |
869 | + C('LAYOUT_ON',false); | |
870 | + } | |
871 | +} | |
872 | + | |
873 | +/** | |
874 | + * URL组装 支持不同URL模式 | |
875 | + * @param string $url URL表达式,格式:'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...' | |
876 | + * @param string|array $vars 传入的参数,支持数组和字符串 | |
877 | + * @param string|boolean $suffix 伪静态后缀,默认为true表示获取配置值 | |
878 | + * @param boolean $domain 是否显示域名 | |
879 | + * @return string | |
880 | + */ | |
881 | +function U($url='',$vars='',$suffix=true,$domain=false) { | |
882 | + // 解析URL | |
883 | + $info = parse_url($url); | |
884 | + $url = !empty($info['path'])?$info['path']:ACTION_NAME; | |
885 | + if(isset($info['fragment'])) { // 解析锚点 | |
886 | + $anchor = $info['fragment']; | |
887 | + if(false !== strpos($anchor,'?')) { // 解析参数 | |
888 | + list($anchor,$info['query']) = explode('?',$anchor,2); | |
889 | + } | |
890 | + if(false !== strpos($anchor,'@')) { // 解析域名 | |
891 | + list($anchor,$host) = explode('@',$anchor, 2); | |
892 | + } | |
893 | + }elseif(false !== strpos($url,'@')) { // 解析域名 | |
894 | + list($url,$host) = explode('@',$info['path'], 2); | |
895 | + } | |
896 | + // 解析子域名 | |
897 | + if(isset($host)) { | |
898 | + $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.')); | |
899 | + }elseif($domain===true){ | |
900 | + $domain = $_SERVER['HTTP_HOST']; | |
901 | + if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署 | |
902 | + $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.'); | |
903 | + // '子域名'=>array('模块[/控制器]'); | |
904 | + foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) { | |
905 | + $rule = is_array($rule)?$rule[0]:$rule; | |
906 | + if(false === strpos($key,'*') && 0=== strpos($url,$rule)) { | |
907 | + $domain = $key.strstr($domain,'.'); // 生成对应子域名 | |
908 | + $url = substr_replace($url,'',0,strlen($rule)); | |
909 | + break; | |
910 | + } | |
911 | + } | |
912 | + } | |
913 | + } | |
914 | + | |
915 | + // 解析参数 | |
916 | + if(is_string($vars)) { // aaa=1&bbb=2 转换成数组 | |
917 | + parse_str($vars,$vars); | |
918 | + }elseif(!is_array($vars)){ | |
919 | + $vars = array(); | |
920 | + } | |
921 | + if(isset($info['query'])) { // 解析地址里面参数 合并到vars | |
922 | + parse_str($info['query'],$params); | |
923 | + $vars = array_merge($params,$vars); | |
924 | + } | |
925 | + | |
926 | + // URL组装 | |
927 | + $depr = C('URL_PATHINFO_DEPR'); | |
928 | + $urlCase = C('URL_CASE_INSENSITIVE'); | |
929 | + if($url) { | |
930 | + if(0=== strpos($url,'/')) {// 定义路由 | |
931 | + $route = true; | |
932 | + $url = substr($url,1); | |
933 | + if('/' != $depr) { | |
934 | + $url = str_replace('/',$depr,$url); | |
935 | + } | |
936 | + }else{ | |
937 | + if('/' != $depr) { // 安全替换 | |
938 | + $url = str_replace('/',$depr,$url); | |
939 | + } | |
940 | + // 解析模块、控制器和操作 | |
941 | + $url = trim($url,$depr); | |
942 | + $path = explode($depr,$url); | |
943 | + $var = array(); | |
944 | + $varModule = C('VAR_MODULE'); | |
945 | + $varController = C('VAR_CONTROLLER'); | |
946 | + $varAction = C('VAR_ACTION'); | |
947 | + $var[$varAction] = !empty($path)?array_pop($path):ACTION_NAME; | |
948 | + $var[$varController] = !empty($path)?array_pop($path):CONTROLLER_NAME; | |
949 | + if($maps = C('URL_ACTION_MAP')) { | |
950 | + if(isset($maps[strtolower($var[$varController])])) { | |
951 | + $maps = $maps[strtolower($var[$varController])]; | |
952 | + if($action = array_search(strtolower($var[$varAction]),$maps)){ | |
953 | + $var[$varAction] = $action; | |
954 | + } | |
955 | + } | |
956 | + } | |
957 | + if($maps = C('URL_CONTROLLER_MAP')) { | |
958 | + if($controller = array_search(strtolower($var[$varController]),$maps)){ | |
959 | + $var[$varController] = $controller; | |
960 | + } | |
961 | + } | |
962 | + if($urlCase) { | |
963 | + $var[$varController] = parse_name($var[$varController]); | |
964 | + } | |
965 | + $module = ''; | |
966 | + | |
967 | + if(!empty($path)) { | |
968 | + $var[$varModule] = implode($depr,$path); | |
969 | + }else{ | |
970 | + if(C('MULTI_MODULE')) { | |
971 | + if(MODULE_NAME != C('DEFAULT_MODULE') || !C('MODULE_ALLOW_LIST')){ | |
972 | + $var[$varModule]= MODULE_NAME; | |
973 | + } | |
974 | + } | |
975 | + } | |
976 | + if($maps = C('URL_MODULE_MAP')) { | |
977 | + if($_module = array_search(strtolower($var[$varModule]),$maps)){ | |
978 | + $var[$varModule] = $_module; | |
979 | + } | |
980 | + } | |
981 | + if(isset($var[$varModule])){ | |
982 | + $module = $var[$varModule]; | |
983 | + unset($var[$varModule]); | |
984 | + } | |
985 | + | |
986 | + } | |
987 | + } | |
988 | + | |
989 | + if(C('URL_MODEL') == 0) { // 普通模式URL转换 | |
990 | + $url = __APP__.'?'.C('VAR_MODULE')."={$module}&".http_build_query(array_reverse($var)); | |
991 | + if($urlCase){ | |
992 | + $url = strtolower($url); | |
993 | + } | |
994 | + if(!empty($vars)) { | |
995 | + $vars = http_build_query($vars); | |
996 | + $url .= '&'.$vars; | |
997 | + } | |
998 | + }else{ // PATHINFO模式或者兼容URL模式 | |
999 | + if(isset($route)) { | |
1000 | + $url = __APP__.'/'.rtrim($url,$depr); | |
1001 | + }else{ | |
1002 | + $module = (defined('BIND_MODULE') && BIND_MODULE==$module )? '' : $module; | |
1003 | + $url = __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').implode($depr,array_reverse($var)); | |
1004 | + } | |
1005 | + if($urlCase){ | |
1006 | + $url = strtolower($url); | |
1007 | + } | |
1008 | + if(!empty($vars)) { // 添加参数 | |
1009 | + foreach ($vars as $var => $val){ | |
1010 | + if('' !== trim($val)) $url .= $depr . $var . $depr . urlencode($val); | |
1011 | + } | |
1012 | + } | |
1013 | + if($suffix) { | |
1014 | + $suffix = $suffix===true?C('URL_HTML_SUFFIX'):$suffix; | |
1015 | + if($pos = strpos($suffix, '|')){ | |
1016 | + $suffix = substr($suffix, 0, $pos); | |
1017 | + } | |
1018 | + if($suffix && '/' != substr($url,-1)){ | |
1019 | + $url .= '.'.ltrim($suffix,'.'); | |
1020 | + } | |
1021 | + } | |
1022 | + } | |
1023 | + if(isset($anchor)){ | |
1024 | + $url .= '#'.$anchor; | |
1025 | + } | |
1026 | + if($domain) { | |
1027 | + $url = (is_ssl()?'https://':'http://').$domain.$url; | |
1028 | + } | |
1029 | + return $url; | |
1030 | +} | |
1031 | + | |
1032 | +/** | |
1033 | + * 渲染输出Widget | |
1034 | + * @param string $name Widget名称 | |
1035 | + * @param array $data 传入的参数 | |
1036 | + * @return void | |
1037 | + */ | |
1038 | +function W($name, $data=array()) { | |
1039 | + return R($name,$data,'Widget'); | |
1040 | +} | |
1041 | + | |
1042 | +/** | |
1043 | + * 判断是否SSL协议 | |
1044 | + * @return boolean | |
1045 | + */ | |
1046 | +function is_ssl() { | |
1047 | + if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){ | |
1048 | + return true; | |
1049 | + }elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) { | |
1050 | + return true; | |
1051 | + } | |
1052 | + return false; | |
1053 | +} | |
1054 | + | |
1055 | +/** | |
1056 | + * URL重定向 | |
1057 | + * @param string $url 重定向的URL地址 | |
1058 | + * @param integer $time 重定向的等待时间(秒) | |
1059 | + * @param string $msg 重定向前的提示信息 | |
1060 | + * @return void | |
1061 | + */ | |
1062 | +function redirect($url, $time=0, $msg='') { | |
1063 | + //多行URL地址支持 | |
1064 | + $url = str_replace(array("\n", "\r"), '', $url); | |
1065 | + if (empty($msg)) | |
1066 | + $msg = "系统将在{$time}秒之后自动跳转到{$url}!"; | |
1067 | + if (!headers_sent()) { | |
1068 | + // redirect | |
1069 | + if (0 === $time) { | |
1070 | + header('Location: ' . $url); | |
1071 | + } else { | |
1072 | + header("refresh:{$time};url={$url}"); | |
1073 | + echo($msg); | |
1074 | + } | |
1075 | + exit(); | |
1076 | + } else { | |
1077 | + $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>"; | |
1078 | + if ($time != 0) | |
1079 | + $str .= $msg; | |
1080 | + exit($str); | |
1081 | + } | |
1082 | +} | |
1083 | + | |
1084 | +/** | |
1085 | + * 缓存管理 | |
1086 | + * @param mixed $name 缓存名称,如果为数组表示进行缓存设置 | |
1087 | + * @param mixed $value 缓存值 | |
1088 | + * @param mixed $options 缓存参数 | |
1089 | + * @return mixed | |
1090 | + */ | |
1091 | +function S($name,$value='',$options=null) { | |
1092 | + static $cache = ''; | |
1093 | + if(is_array($options)){ | |
1094 | + // 缓存操作的同时初始化 | |
1095 | + $type = isset($options['type'])?$options['type']:''; | |
1096 | + $cache = Think\Cache::getInstance($type,$options); | |
1097 | + }elseif(is_array($name)) { // 缓存初始化 | |
1098 | + $type = isset($name['type'])?$name['type']:''; | |
1099 | + $cache = Think\Cache::getInstance($type,$name); | |
1100 | + return $cache; | |
1101 | + }elseif(empty($cache)) { // 自动初始化 | |
1102 | + $cache = Think\Cache::getInstance(); | |
1103 | + } | |
1104 | + if(''=== $value){ // 获取缓存 | |
1105 | + return $cache->get($name); | |
1106 | + }elseif(is_null($value)) { // 删除缓存 | |
1107 | + return $cache->rm($name); | |
1108 | + }else { // 缓存数据 | |
1109 | + if(is_array($options)) { | |
1110 | + $expire = isset($options['expire'])?$options['expire']:NULL; | |
1111 | + }else{ | |
1112 | + $expire = is_numeric($options)?$options:NULL; | |
1113 | + } | |
1114 | + return $cache->set($name, $value, $expire); | |
1115 | + } | |
1116 | +} | |
1117 | + | |
1118 | +/** | |
1119 | + * 快速文件数据读取和保存 针对简单类型数据 字符串、数组 | |
1120 | + * @param string $name 缓存名称 | |
1121 | + * @param mixed $value 缓存值 | |
1122 | + * @param string $path 缓存路径 | |
1123 | + * @return mixed | |
1124 | + */ | |
1125 | +function F($name, $value='', $path=DATA_PATH) { | |
1126 | + static $_cache = array(); | |
1127 | + $filename = $path . $name . '.php'; | |
1128 | + if ('' !== $value) { | |
1129 | + if (is_null($value)) { | |
1130 | + // 删除缓存 | |
1131 | + if(false !== strpos($name,'*')){ | |
1132 | + return false; // TODO | |
1133 | + }else{ | |
1134 | + unset($_cache[$name]); | |
1135 | + return Think\Storage::unlink($filename,'F'); | |
1136 | + } | |
1137 | + } else { | |
1138 | + Think\Storage::put($filename,serialize($value),'F'); | |
1139 | + // 缓存数据 | |
1140 | + $_cache[$name] = $value; | |
1141 | + return null; | |
1142 | + } | |
1143 | + } | |
1144 | + // 获取缓存数据 | |
1145 | + if (isset($_cache[$name])) | |
1146 | + return $_cache[$name]; | |
1147 | + if (Think\Storage::has($filename,'F')){ | |
1148 | + $value = unserialize(Think\Storage::read($filename,'F')); | |
1149 | + $_cache[$name] = $value; | |
1150 | + } else { | |
1151 | + $value = false; | |
1152 | + } | |
1153 | + return $value; | |
1154 | +} | |
1155 | + | |
1156 | +/** | |
1157 | + * 根据PHP各种类型变量生成唯一标识号 | |
1158 | + * @param mixed $mix 变量 | |
1159 | + * @return string | |
1160 | + */ | |
1161 | +function to_guid_string($mix) { | |
1162 | + if (is_object($mix)) { | |
1163 | + return spl_object_hash($mix); | |
1164 | + } elseif (is_resource($mix)) { | |
1165 | + $mix = get_resource_type($mix) . strval($mix); | |
1166 | + } else { | |
1167 | + $mix = serialize($mix); | |
1168 | + } | |
1169 | + return md5($mix); | |
1170 | +} | |
1171 | + | |
1172 | +/** | |
1173 | + * XML编码 | |
1174 | + * @param mixed $data 数据 | |
1175 | + * @param string $root 根节点名 | |
1176 | + * @param string $item 数字索引的子节点名 | |
1177 | + * @param string $attr 根节点属性 | |
1178 | + * @param string $id 数字索引子节点key转换的属性名 | |
1179 | + * @param string $encoding 数据编码 | |
1180 | + * @return string | |
1181 | + */ | |
1182 | +function xml_encode($data, $root='think', $item='item', $attr='', $id='id', $encoding='utf-8') { | |
1183 | + if(is_array($attr)){ | |
1184 | + $_attr = array(); | |
1185 | + foreach ($attr as $key => $value) { | |
1186 | + $_attr[] = "{$key}=\"{$value}\""; | |
1187 | + } | |
1188 | + $attr = implode(' ', $_attr); | |
1189 | + } | |
1190 | + $attr = trim($attr); | |
1191 | + $attr = empty($attr) ? '' : " {$attr}"; | |
1192 | + $xml = "<?xml version=\"1.0\" encoding=\"{$encoding}\"?>"; | |
1193 | + $xml .= "<{$root}{$attr}>"; | |
1194 | + $xml .= data_to_xml($data, $item, $id); | |
1195 | + $xml .= "</{$root}>"; | |
1196 | + return $xml; | |
1197 | +} | |
1198 | + | |
1199 | +/** | |
1200 | + * 数据XML编码 | |
1201 | + * @param mixed $data 数据 | |
1202 | + * @param string $item 数字索引时的节点名称 | |
1203 | + * @param string $id 数字索引key转换为的属性名 | |
1204 | + * @return string | |
1205 | + */ | |
1206 | +function data_to_xml($data, $item='item', $id='id') { | |
1207 | + $xml = $attr = ''; | |
1208 | + foreach ($data as $key => $val) { | |
1209 | + if(is_numeric($key)){ | |
1210 | + $id && $attr = " {$id}=\"{$key}\""; | |
1211 | + $key = $item; | |
1212 | + } | |
1213 | + $xml .= "<{$key}{$attr}>"; | |
1214 | + $xml .= (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val; | |
1215 | + $xml .= "</{$key}>"; | |
1216 | + } | |
1217 | + return $xml; | |
1218 | +} | |
1219 | + | |
1220 | +/** | |
1221 | + * session管理函数 | |
1222 | + * @param string|array $name session名称 如果为数组则表示进行session设置 | |
1223 | + * @param mixed $value session值 | |
1224 | + * @return mixed | |
1225 | + */ | |
1226 | +function session($name='',$value='') { | |
1227 | + $prefix = C('SESSION_PREFIX'); | |
1228 | + if(is_array($name)) { // session初始化 在session_start 之前调用 | |
1229 | + if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']); | |
1230 | + if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){ | |
1231 | + session_id($_REQUEST[C('VAR_SESSION_ID')]); | |
1232 | + }elseif(isset($name['id'])) { | |
1233 | + session_id($name['id']); | |
1234 | + } | |
1235 | + if('common' == APP_MODE){ // 其它模式可能不支持 | |
1236 | + ini_set('session.auto_start', 0); | |
1237 | + } | |
1238 | + if(isset($name['name'])) session_name($name['name']); | |
1239 | + if(isset($name['path'])) session_save_path($name['path']); | |
1240 | + if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']); | |
1241 | + if(isset($name['expire'])) { | |
1242 | + ini_set('session.gc_maxlifetime', $name['expire']); | |
1243 | + ini_set('session.cookie_lifetime', $name['expire']); | |
1244 | + } | |
1245 | + if(isset($name['use_trans_sid'])) ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0); | |
1246 | + if(isset($name['use_cookies'])) ini_set('session.use_cookies', $name['use_cookies']?1:0); | |
1247 | + if(isset($name['cache_limiter'])) session_cache_limiter($name['cache_limiter']); | |
1248 | + if(isset($name['cache_expire'])) session_cache_expire($name['cache_expire']); | |
1249 | + if(isset($name['type'])) C('SESSION_TYPE',$name['type']); | |
1250 | + if(C('SESSION_TYPE')) { // 读取session驱动 | |
1251 | + $type = C('SESSION_TYPE'); | |
1252 | + $class = strpos($type,'\\')? $type : 'Think\\Session\\Driver\\'. ucwords(strtolower($type)); | |
1253 | + $hander = new $class(); | |
1254 | + session_set_save_handler( | |
1255 | + array(&$hander,"open"), | |
1256 | + array(&$hander,"close"), | |
1257 | + array(&$hander,"read"), | |
1258 | + array(&$hander,"write"), | |
1259 | + array(&$hander,"destroy"), | |
1260 | + array(&$hander,"gc")); | |
1261 | + } | |
1262 | + // 启动session | |
1263 | + if(C('SESSION_AUTO_START')) session_start(); | |
1264 | + }elseif('' === $value){ | |
1265 | + if(''===$name){ | |
1266 | + // 获取全部的session | |
1267 | + return $prefix ? $_SESSION[$prefix] : $_SESSION; | |
1268 | + }elseif(0===strpos($name,'[')) { // session 操作 | |
1269 | + if('[pause]'==$name){ // 暂停session | |
1270 | + session_write_close(); | |
1271 | + }elseif('[start]'==$name){ // 启动session | |
1272 | + session_start(); | |
1273 | + }elseif('[destroy]'==$name){ // 销毁session | |
1274 | + $_SESSION = array(); | |
1275 | + session_unset(); | |
1276 | + session_destroy(); | |
1277 | + }elseif('[regenerate]'==$name){ // 重新生成id | |
1278 | + session_regenerate_id(); | |
1279 | + } | |
1280 | + }elseif(0===strpos($name,'?')){ // 检查session | |
1281 | + $name = substr($name,1); | |
1282 | + if(strpos($name,'.')){ // 支持数组 | |
1283 | + list($name1,$name2) = explode('.',$name); | |
1284 | + return $prefix?isset($_SESSION[$prefix][$name1][$name2]):isset($_SESSION[$name1][$name2]); | |
1285 | + }else{ | |
1286 | + return $prefix?isset($_SESSION[$prefix][$name]):isset($_SESSION[$name]); | |
1287 | + } | |
1288 | + }elseif(is_null($name)){ // 清空session | |
1289 | + if($prefix) { | |
1290 | + unset($_SESSION[$prefix]); | |
1291 | + }else{ | |
1292 | + $_SESSION = array(); | |
1293 | + } | |
1294 | + }elseif($prefix){ // 获取session | |
1295 | + if(strpos($name,'.')){ | |
1296 | + list($name1,$name2) = explode('.',$name); | |
1297 | + return isset($_SESSION[$prefix][$name1][$name2])?$_SESSION[$prefix][$name1][$name2]:null; | |
1298 | + }else{ | |
1299 | + return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null; | |
1300 | + } | |
1301 | + }else{ | |
1302 | + if(strpos($name,'.')){ | |
1303 | + list($name1,$name2) = explode('.',$name); | |
1304 | + return isset($_SESSION[$name1][$name2])?$_SESSION[$name1][$name2]:null; | |
1305 | + }else{ | |
1306 | + return isset($_SESSION[$name])?$_SESSION[$name]:null; | |
1307 | + } | |
1308 | + } | |
1309 | + }elseif(is_null($value)){ // 删除session | |
1310 | + if(strpos($name,'.')){ | |
1311 | + list($name1,$name2) = explode('.',$name); | |
1312 | + if($prefix){ | |
1313 | + unset($_SESSION[$prefix][$name1][$name2]); | |
1314 | + }else{ | |
1315 | + unset($_SESSION[$name1][$name2]); | |
1316 | + } | |
1317 | + }else{ | |
1318 | + if($prefix){ | |
1319 | + unset($_SESSION[$prefix][$name]); | |
1320 | + }else{ | |
1321 | + unset($_SESSION[$name]); | |
1322 | + } | |
1323 | + } | |
1324 | + }else{ // 设置session | |
1325 | + if(strpos($name,'.')){ | |
1326 | + list($name1,$name2) = explode('.',$name); | |
1327 | + if($prefix){ | |
1328 | + $_SESSION[$prefix][$name1][$name2] = $value; | |
1329 | + }else{ | |
1330 | + $_SESSION[$name1][$name2] = $value; | |
1331 | + } | |
1332 | + }else{ | |
1333 | + if($prefix){ | |
1334 | + $_SESSION[$prefix][$name] = $value; | |
1335 | + }else{ | |
1336 | + $_SESSION[$name] = $value; | |
1337 | + } | |
1338 | + } | |
1339 | + } | |
1340 | + return null; | |
1341 | +} | |
1342 | + | |
1343 | +/** | |
1344 | + * Cookie 设置、获取、删除 | |
1345 | + * @param string $name cookie名称 | |
1346 | + * @param mixed $value cookie值 | |
1347 | + * @param mixed $option cookie参数 | |
1348 | + * @return mixed | |
1349 | + */ | |
1350 | +function cookie($name='', $value='', $option=null) { | |
1351 | + // 默认设置 | |
1352 | + $config = array( | |
1353 | + 'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀 | |
1354 | + 'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间 | |
1355 | + 'path' => C('COOKIE_PATH'), // cookie 保存路径 | |
1356 | + 'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名 | |
1357 | + 'secure' => C('COOKIE_SECURE'), // cookie 启用安全传输 | |
1358 | + 'httponly' => C('COOKIE_HTTPONLY'), // httponly设置 | |
1359 | + ); | |
1360 | + // 参数设置(会覆盖黙认设置) | |
1361 | + if (!is_null($option)) { | |
1362 | + if (is_numeric($option)) | |
1363 | + $option = array('expire' => $option); | |
1364 | + elseif (is_string($option)) | |
1365 | + parse_str($option, $option); | |
1366 | + $config = array_merge($config, array_change_key_case($option)); | |
1367 | + } | |
1368 | + if(!empty($config['httponly'])){ | |
1369 | + ini_set("session.cookie_httponly", 1); | |
1370 | + } | |
1371 | + // 清除指定前缀的所有cookie | |
1372 | + if (is_null($name)) { | |
1373 | + if (empty($_COOKIE)) | |
1374 | + return null; | |
1375 | + // 要删除的cookie前缀,不指定则删除config设置的指定前缀 | |
1376 | + $prefix = empty($value) ? $config['prefix'] : $value; | |
1377 | + if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回 | |
1378 | + foreach ($_COOKIE as $key => $val) { | |
1379 | + if (0 === stripos($key, $prefix)) { | |
1380 | + setcookie($key, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']); | |
1381 | + unset($_COOKIE[$key]); | |
1382 | + } | |
1383 | + } | |
1384 | + } | |
1385 | + return null; | |
1386 | + }elseif('' === $name){ | |
1387 | + // 获取全部的cookie | |
1388 | + return $_COOKIE; | |
1389 | + } | |
1390 | + $name = $config['prefix'] . str_replace('.', '_', $name); | |
1391 | + if ('' === $value) { | |
1392 | + if(isset($_COOKIE[$name])){ | |
1393 | + $value = $_COOKIE[$name]; | |
1394 | + if(0===strpos($value,'think:')){ | |
1395 | + $value = substr($value,6); | |
1396 | + return array_map('urldecode',json_decode(MAGIC_QUOTES_GPC?stripslashes($value):$value,true)); | |
1397 | + }else{ | |
1398 | + return $value; | |
1399 | + } | |
1400 | + }else{ | |
1401 | + return null; | |
1402 | + } | |
1403 | + } else { | |
1404 | + if (is_null($value)) { | |
1405 | + setcookie($name, '', time() - 3600, $config['path'], $config['domain'],$config['secure'],$config['httponly']); | |
1406 | + unset($_COOKIE[$name]); // 删除指定cookie | |
1407 | + } else { | |
1408 | + // 设置cookie | |
1409 | + if(is_array($value)){ | |
1410 | + $value = 'think:'.json_encode(array_map('urlencode',$value)); | |
1411 | + } | |
1412 | + $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0; | |
1413 | + setcookie($name, $value, $expire, $config['path'], $config['domain'],$config['secure'],$config['httponly']); | |
1414 | + $_COOKIE[$name] = $value; | |
1415 | + } | |
1416 | + } | |
1417 | + return null; | |
1418 | +} | |
1419 | + | |
1420 | +/** | |
1421 | + * 加载动态扩展文件 | |
1422 | + * @var string $path 文件路径 | |
1423 | + * @return void | |
1424 | + */ | |
1425 | +function load_ext_file($path) { | |
1426 | + // 加载自定义外部文件 | |
1427 | + if($files = C('LOAD_EXT_FILE')) { | |
1428 | + $files = explode(',',$files); | |
1429 | + foreach ($files as $file){ | |
1430 | + $file = $path.'Common/'.$file.'.php'; | |
1431 | + if(is_file($file)) include $file; | |
1432 | + } | |
1433 | + } | |
1434 | + // 加载自定义的动态配置文件 | |
1435 | + if($configs = C('LOAD_EXT_CONFIG')) { | |
1436 | + if(is_string($configs)) $configs = explode(',',$configs); | |
1437 | + foreach ($configs as $key=>$config){ | |
1438 | + $file = is_file($config)? $config : $path.'Conf/'.$config.CONF_EXT; | |
1439 | + if(is_file($file)) { | |
1440 | + is_numeric($key)?C(load_config($file)):C($key,load_config($file)); | |
1441 | + } | |
1442 | + } | |
1443 | + } | |
1444 | +} | |
1445 | + | |
1446 | +/** | |
1447 | + * 获取客户端IP地址 | |
1448 | + * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 | |
1449 | + * @param boolean $adv 是否进行高级模式获取(有可能被伪装) | |
1450 | + * @return mixed | |
1451 | + */ | |
1452 | +function get_client_ip($type = 0,$adv=false) { | |
1453 | + $type = $type ? 1 : 0; | |
1454 | + static $ip = NULL; | |
1455 | + if ($ip !== NULL) return $ip[$type]; | |
1456 | + if($adv){ | |
1457 | + if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { | |
1458 | + $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); | |
1459 | + $pos = array_search('unknown',$arr); | |
1460 | + if(false !== $pos) unset($arr[$pos]); | |
1461 | + $ip = trim($arr[0]); | |
1462 | + }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { | |
1463 | + $ip = $_SERVER['HTTP_CLIENT_IP']; | |
1464 | + }elseif (isset($_SERVER['REMOTE_ADDR'])) { | |
1465 | + $ip = $_SERVER['REMOTE_ADDR']; | |
1466 | + } | |
1467 | + }elseif (isset($_SERVER['REMOTE_ADDR'])) { | |
1468 | + $ip = $_SERVER['REMOTE_ADDR']; | |
1469 | + } | |
1470 | + // IP地址合法验证 | |
1471 | + $long = sprintf("%u",ip2long($ip)); | |
1472 | + $ip = $long ? array($ip, $long) : array('0.0.0.0', 0); | |
1473 | + return $ip[$type]; | |
1474 | +} | |
1475 | + | |
1476 | +/** | |
1477 | + * 发送HTTP状态 | |
1478 | + * @param integer $code 状态码 | |
1479 | + * @return void | |
1480 | + */ | |
1481 | +function send_http_status($code) { | |
1482 | + static $_status = array( | |
1483 | + // Informational 1xx | |
1484 | + 100 => 'Continue', | |
1485 | + 101 => 'Switching Protocols', | |
1486 | + // Success 2xx | |
1487 | + 200 => 'OK', | |
1488 | + 201 => 'Created', | |
1489 | + 202 => 'Accepted', | |
1490 | + 203 => 'Non-Authoritative Information', | |
1491 | + 204 => 'No Content', | |
1492 | + 205 => 'Reset Content', | |
1493 | + 206 => 'Partial Content', | |
1494 | + // Redirection 3xx | |
1495 | + 300 => 'Multiple Choices', | |
1496 | + 301 => 'Moved Permanently', | |
1497 | + 302 => 'Moved Temporarily ', // 1.1 | |
1498 | + 303 => 'See Other', | |
1499 | + 304 => 'Not Modified', | |
1500 | + 305 => 'Use Proxy', | |
1501 | + // 306 is deprecated but reserved | |
1502 | + 307 => 'Temporary Redirect', | |
1503 | + // Client Error 4xx | |
1504 | + 400 => 'Bad Request', | |
1505 | + 401 => 'Unauthorized', | |
1506 | + 402 => 'Payment Required', | |
1507 | + 403 => 'Forbidden', | |
1508 | + 404 => 'Not Found', | |
1509 | + 405 => 'Method Not Allowed', | |
1510 | + 406 => 'Not Acceptable', | |
1511 | + 407 => 'Proxy Authentication Required', | |
1512 | + 408 => 'Request Timeout', | |
1513 | + 409 => 'Conflict', | |
1514 | + 410 => 'Gone', | |
1515 | + 411 => 'Length Required', | |
1516 | + 412 => 'Precondition Failed', | |
1517 | + 413 => 'Request Entity Too Large', | |
1518 | + 414 => 'Request-URI Too Long', | |
1519 | + 415 => 'Unsupported Media Type', | |
1520 | + 416 => 'Requested Range Not Satisfiable', | |
1521 | + 417 => 'Expectation Failed', | |
1522 | + // Server Error 5xx | |
1523 | + 500 => 'Internal Server Error', | |
1524 | + 501 => 'Not Implemented', | |
1525 | + 502 => 'Bad Gateway', | |
1526 | + 503 => 'Service Unavailable', | |
1527 | + 504 => 'Gateway Timeout', | |
1528 | + 505 => 'HTTP Version Not Supported', | |
1529 | + 509 => 'Bandwidth Limit Exceeded' | |
1530 | + ); | |
1531 | + if(isset($_status[$code])) { | |
1532 | + header('HTTP/1.1 '.$code.' '.$_status[$code]); | |
1533 | + // 确保FastCGI模式下正常 | |
1534 | + header('Status:'.$code.' '.$_status[$code]); | |
1535 | + } | |
1536 | +} | |
1537 | + | |
1538 | +function think_filter(&$value){ | |
1539 | + // TODO 其他安全过滤 | |
1540 | + | |
1541 | + // 过滤查询特殊字符 | |
1542 | + if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){ | |
1543 | + $value .= ' '; | |
1544 | + } | |
1545 | +} | |
1546 | + | |
1547 | +// 不区分大小写的in_array实现 | |
1548 | +function in_array_case($value,$array){ | |
1549 | + return in_array(strtolower($value),array_map('strtolower',$array)); | |
1550 | +} | ... | ... |
trunk/ThinkPHP/Mode/cli.php
0 → 100644
1 | +<?php | |
2 | +// +---------------------------------------------------------------------- | |
3 | +// | ThinkPHP [ WE CAN DO IT JUST THINK IT ] | |
4 | +// +---------------------------------------------------------------------- | |
5 | +// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved. | |
6 | +// +---------------------------------------------------------------------- | |
7 | +// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) | |
8 | +// +---------------------------------------------------------------------- | |
9 | +// | Author: liu21st <liu21st@gmail.com> | |
10 | +// +---------------------------------------------------------------------- | |
11 | + | |
12 | +/** | |
13 | + * ThinkPHP CLI模式定义 | |
14 | + */ | |
15 | +return array( | |
16 | + // 配置文件 | |
17 | + 'config' => array( | |
18 | + THINK_PATH.'Conf/convention.php', // 系统惯例配置 | |
19 | + CONF_PATH.'config'.CONF_EXT, // 应用公共配置 | |
20 | + ), | |
21 | + | |
22 | + // 别名定义 | |
23 | + 'alias' => array( | |
24 | + 'Think\Exception' => CORE_PATH . 'Exception'.EXT, | |
25 | + 'Think\Model' => CORE_PATH . 'Model'.EXT, | |
26 | + 'Think\Db' => CORE_PATH . 'Db'.EXT, | |
27 | + 'Think\Cache' => CORE_PATH . 'Cache'.EXT, | |
28 | + 'Think\Cache\Driver\File' => CORE_PATH . 'Cache/Driver/File'.EXT, | |
29 | + 'Think\Storage' => CORE_PATH . 'Storage'.EXT, | |
30 | + ), | |
31 | + | |
32 | + // 函数和类文件 | |
33 | + 'core' => array( | |
34 | + MODE_PATH.'Cli/functions.php', | |
35 | + COMMON_PATH.'Common/function.php', | |
36 | + MODE_PATH . 'Cli/App'.EXT, | |
37 | + MODE_PATH . 'Cli/Dispatcher'.EXT, | |
38 | + MODE_PATH . 'Cli/Controller'.EXT, | |
39 | + CORE_PATH . 'Behavior'.EXT, | |
40 | + ), | |
41 | + // 行为扩展定义 | |
42 | + 'tags' => array( | |
43 | + ), | |
44 | +); | ... | ... |
trunk/swoole.php
0 → 100644
1 | +#!/bin/env php | |
2 | +<?php | |
3 | +/** | |
4 | + * 默认时区定义 | |
5 | + */ | |
6 | +date_default_timezone_set('Asia/Shanghai'); | |
7 | + | |
8 | +/** | |
9 | + * 设置错误报告模式 | |
10 | + */ | |
11 | +error_reporting(0); | |
12 | + | |
13 | +/** | |
14 | + * 设置默认区域 | |
15 | + */ | |
16 | +setlocale(LC_ALL, "zh_CN.utf-8"); | |
17 | + | |
18 | +/** | |
19 | + * 检测 PDO_MYSQL | |
20 | + */ | |
21 | +if (!extension_loaded('pdo_mysql')) { | |
22 | + exit('PDO_MYSQL extension is not installed' . PHP_EOL); | |
23 | +} | |
24 | +/** | |
25 | + * 检查exec 函数是否启用 | |
26 | + */ | |
27 | +if (!function_exists('exec')) { | |
28 | + exit('exec function is disabled' . PHP_EOL); | |
29 | +} | |
30 | +/** | |
31 | + * 检查命令 lsof 命令是否存在 | |
32 | + */ | |
33 | +exec("whereis lsof", $out); | |
34 | +if ($out[0] == 'lsof:') { | |
35 | + exit('lsof is not found' . PHP_EOL); | |
36 | +} | |
37 | +/** | |
38 | + * 定义项目根目录&swoole-task pid | |
39 | + */ | |
40 | +define('SWOOLE_PATH', __DIR__); | |
41 | +define('SWOOLE_TASK_PID_PATH', SWOOLE_PATH . DIRECTORY_SEPARATOR . 'Swoole' . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'swoole-task.pid'); | |
42 | +define('SWOOLE_TASK_NAME_PRE', 'swooleServ'); | |
43 | + | |
44 | +/** | |
45 | + * 加载 swoole server | |
46 | + */ | |
47 | +include SWOOLE_PATH . DIRECTORY_SEPARATOR . 'Swoole' . DIRECTORY_SEPARATOR . 'SwooleServer.php'; | |
48 | + | |
49 | +function portBind($port) | |
50 | +{ | |
51 | + $ret = []; | |
52 | + $cmd = "lsof -i :{$port}|awk '$1 != \"COMMAND\" {print $1, $2, $9}'"; | |
53 | + exec($cmd, $out); | |
54 | + if ($out) { | |
55 | + foreach ($out as $v) { | |
56 | + $a = explode(' ', $v); | |
57 | + list($ip, $p) = explode(':', $a[2]); | |
58 | + $ret[$a[1]] = [ | |
59 | + 'cmd' => $a[0], | |
60 | + 'ip' => $ip, | |
61 | + 'port' => $p, | |
62 | + ]; | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + return $ret; | |
67 | +} | |
68 | + | |
69 | +function servStart($host, $port, $daemon, $name) | |
70 | +{ | |
71 | + echo "正在启动 swoole-task 服务" . PHP_EOL; | |
72 | + if (!is_writable(dirname(SWOOLE_TASK_PID_PATH))) { | |
73 | + exit("swoole-task-pid文件需要目录的写入权限:" . dirname(SWOOLE_TASK_PID_PATH) . PHP_EOL); | |
74 | + } | |
75 | + if (file_exists(SWOOLE_TASK_PID_PATH)) { | |
76 | + $pid = explode("\n", file_get_contents(SWOOLE_TASK_PID_PATH)); | |
77 | + $cmd = "ps ax | awk '{ print $1 }' | grep -e \"^{$pid[0]}$\""; | |
78 | + exec($cmd, $out); | |
79 | + if (!empty($out)) { | |
80 | + exit("swoole-task pid文件 " . SWOOLE_TASK_PID_PATH . " 存在,swoole-task 服务器已经启动,进程pid为:{$pid[0]}" . PHP_EOL); | |
81 | + } else { | |
82 | + echo "警告:swoole-task pid文件 " . SWOOLE_TASK_PID_PATH . " 存在,可能swoole-task服务上次异常退出(非守护模式ctrl+c终止造成是最大可能)" . PHP_EOL; | |
83 | + unlink(SWOOLE_TASK_PID_PATH); | |
84 | + } | |
85 | + } | |
86 | + $bind = portBind($port); | |
87 | + if ($bind) { | |
88 | + foreach ($bind as $k => $v) { | |
89 | + if ($v['ip'] == '*' || $v['ip'] == $host) { | |
90 | + exit("端口已经被占用 {$host}:$port, 占用端口进程ID {$k}" . PHP_EOL); | |
91 | + } | |
92 | + } | |
93 | + } | |
94 | + unset($_SERVER['argv']); | |
95 | + $_SERVER['argc'] = 0; | |
96 | + echo "启动 swoole-task 服务成功" . PHP_EOL; | |
97 | + $server = new SwooleServer('127.0.0.1', 9501); | |
98 | + $server->run(); | |
99 | + //确保服务器启动后swoole-task-pid文件必须生成 | |
100 | + /*if (!empty(portBind($port)) && !file_exists(SWOOLE_TASK_PID_PATH)) { | |
101 | + exit("swoole-task pid文件生成失败( " . SWOOLE_TASK_PID_PATH . ") ,请手动关闭当前启动的swoole-task服务检查原因" . PHP_EOL); | |
102 | + }*/ | |
103 | +} | |
104 | + | |
105 | +function servStop($host, $port, $isRestart = false) | |
106 | +{ | |
107 | + echo "正在停止 swoole-task 服务" . PHP_EOL; | |
108 | + if (!file_exists(SWOOLE_TASK_PID_PATH)) { | |
109 | + exit('swoole-task-pid文件:' . SWOOLE_TASK_PID_PATH . '不存在' . PHP_EOL); | |
110 | + } | |
111 | + $pid = explode("\n", file_get_contents(SWOOLE_TASK_PID_PATH)); | |
112 | + $bind = portBind($port); | |
113 | + if (empty($bind) || !isset($bind[$pid[0]])) { | |
114 | + exit("指定端口占用进程不存在 port:{$port}, pid:{$pid[0]}" . PHP_EOL); | |
115 | + } | |
116 | + $cmd = "kill {$pid[0]}"; | |
117 | + exec($cmd); | |
118 | + do { | |
119 | + $out = []; | |
120 | + $c = "ps ax | awk '{ print $1 }' | grep -e \"^{$pid[0]}$\""; | |
121 | + exec($c, $out); | |
122 | + if (empty($out)) { | |
123 | + break; | |
124 | + } | |
125 | + } while (true); | |
126 | + //确保停止服务后swoole-task-pid文件被删除 | |
127 | + if (file_exists(SWOOLE_TASK_PID_PATH)) { | |
128 | + unlink(SWOOLE_TASK_PID_PATH); | |
129 | + } | |
130 | + $msg = "执行命令 {$cmd} 成功,端口 {$host}:{$port} 进程结束" . PHP_EOL; | |
131 | + if ($isRestart) { | |
132 | + echo $msg; | |
133 | + } else { | |
134 | + exit($msg); | |
135 | + } | |
136 | +} | |
137 | + | |
138 | +function servReload($host, $port, $isRestart = false) | |
139 | +{ | |
140 | + echo "正在平滑重启 swoole-task 服务" . PHP_EOL; | |
141 | + try { | |
142 | + $client = new \swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC); | |
143 | + $ret = $client->connect($host, $port); | |
144 | + if (empty($ret)) { | |
145 | + exit("{$host}:{$port} swoole-task服务不存在或者已经关闭" . PHP_EOL); | |
146 | + } else { | |
147 | + $client->send(json_encode(array('action' => 'reload'))); | |
148 | + } | |
149 | + $msg = "执行命令reload成功,端口 {$host}:{$port} 进程重启" . PHP_EOL; | |
150 | + if ($isRestart) { | |
151 | + echo $msg; | |
152 | + } else { | |
153 | + exit($msg); | |
154 | + } | |
155 | + } catch (Exception $e) { | |
156 | + exit($e->getMessage() . PHP_EOL . $e->getTraceAsString()); | |
157 | + } | |
158 | +} | |
159 | + | |
160 | +function servClose($host, $port, $isRestart = false) | |
161 | +{ | |
162 | + echo "正在关闭 swoole-task 服务" . PHP_EOL; | |
163 | + try { | |
164 | + $client = new \swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC); | |
165 | + $ret = $client->connect($host, $port); | |
166 | + if (empty($ret)) { | |
167 | + exit("{$host}:{$port} swoole-task服务不存在或者已经关闭" . PHP_EOL); | |
168 | + } else { | |
169 | + $client->send(json_encode(array('action' => 'close'))); | |
170 | + } | |
171 | + //确保停止服务后swoole-task-pid文件被删除 | |
172 | + if (file_exists(SWOOLE_TASK_PID_PATH)) { | |
173 | + unlink(SWOOLE_TASK_PID_PATH); | |
174 | + } | |
175 | + $msg = "执行命令close成功,端口 {$host}:{$port} 进程结束" . PHP_EOL; | |
176 | + if ($isRestart) { | |
177 | + echo $msg; | |
178 | + } else { | |
179 | + exit($msg); | |
180 | + } | |
181 | + } catch (\Exception $e) { | |
182 | + exit($e->getMessage() . PHP_EOL . $e->getTraceAsString()); | |
183 | + } | |
184 | +} | |
185 | + | |
186 | +function servStatus($host, $port) | |
187 | +{ | |
188 | + echo "swoole-task {$host}:{$port} 运行状态" . PHP_EOL; | |
189 | + $pid = explode("\n", file_get_contents(SWOOLE_TASK_PID_PATH)); | |
190 | + $bind = portBind($port); | |
191 | + if (empty($bind) || !isset($bind[$pid[0]])) { | |
192 | + exit("指定端口占用进程不存在 port:{$port}, pid:{$pid[0]}" . PHP_EOL); | |
193 | + } | |
194 | + $client = new \swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC); | |
195 | + $ret = $client->connect($host, $port); | |
196 | + if (empty($ret)) { | |
197 | + exit("{$host}:{$port} swoole-task服务不存在或者已经停止" . PHP_EOL); | |
198 | + } else { | |
199 | + $client->send(json_encode(array('action' => 'status'))); | |
200 | + $out = $client->recv(); | |
201 | + $a = json_decode($out); | |
202 | + $b = array( | |
203 | + 'start_time' => '服务器启动的时间', | |
204 | + 'connection_num' => '当前连接的数量', | |
205 | + 'accept_count' => '接受的连接数量', | |
206 | + 'close_count' => '关闭的连接数量', | |
207 | + 'tasking_num' => '当前正在排队的任务数', | |
208 | + 'request_count' => '请求的连接数量', | |
209 | + 'worker_request_count' => 'worker连接数量', | |
210 | + 'task_process_num' => '任务进程数量' | |
211 | + ); | |
212 | + foreach ($a as $k1 => $v1) { | |
213 | + if ($k1 == 'start_time') { | |
214 | + $v1 = date("Y-m-d H:i:s", $v1); | |
215 | + } | |
216 | + echo $b[$k1] . ":\t$v1" . PHP_EOL; | |
217 | + } | |
218 | + } | |
219 | + exit(); | |
220 | +} | |
221 | + | |
222 | +function servList() | |
223 | +{ | |
224 | + echo "本机运行的swoole-task服务进程" . PHP_EOL; | |
225 | + $cmd = "ps aux|grep " . SWOOLE_TASK_NAME_PRE . "|grep -v grep|awk '{print $1, $2, $6, $8, $9, $11}'"; | |
226 | + exec($cmd, $out); | |
227 | + if (empty($out)) { | |
228 | + exit("没有发现正在运行的swoole-task服务" . PHP_EOL); | |
229 | + } | |
230 | + echo "USER PID RSS(kb) STAT START COMMAND" . PHP_EOL; | |
231 | + foreach ($out as $v) { | |
232 | + echo $v . PHP_EOL; | |
233 | + } | |
234 | + exit(); | |
235 | +} | |
236 | + | |
237 | +//可执行命令 | |
238 | +$cmds = [ | |
239 | + 'start', | |
240 | + 'stop', | |
241 | + 'restart', | |
242 | + 'reload', | |
243 | + 'close', | |
244 | + 'status', | |
245 | + 'list', | |
246 | +]; | |
247 | +$shortopts = "dDh:p:n:"; | |
248 | +$longopts = [ | |
249 | + 'help', | |
250 | + 'daemon', | |
251 | + 'nondaemon', | |
252 | + 'host:', | |
253 | + 'port:', | |
254 | + 'name:', | |
255 | +]; | |
256 | +$opts = getopt($shortopts, $longopts); | |
257 | + | |
258 | +if (isset($opts['help']) || $argc < 2) { | |
259 | + echo <<<HELP | |
260 | +用法:php swoole.php 选项 ... 命令[start|stop|restart|reload|close|status|list] | |
261 | +管理swoole-task服务,确保系统 lsof 命令有效 | |
262 | +如果不指定监听host或者port,使用配置参数 | |
263 | + | |
264 | +参数说明 | |
265 | + --help 显示本帮助说明 | |
266 | + -d, --daemon 指定此参数,以守护进程模式运行,不指定则读取配置文件值 | |
267 | + -D, --nondaemon 指定此参数,以非守护进程模式运行,不指定则读取配置文件值 | |
268 | + -h, --host 指定监听ip,例如 php swoole.php -h127.0.0.1 | |
269 | + -p, --port 指定监听端口port, 例如 php swoole.php -h127.0.0.1 -p9520 | |
270 | + -n, --name 指定服务进程名称,例如 php swoole.php -ntest start, 则进程名称为SWOOLE_TASK_NAME_PRE-name | |
271 | +启动swoole-task 如果不指定 host和port,读取默认配置 | |
272 | +强制关闭swoole-task 必须指定port,没有指定host,关闭的监听端口是 *:port,指定了host,关闭 host:port端口 | |
273 | +平滑关闭swoole-task 必须指定port,没有指定host,关闭的监听端口是 *:port,指定了host,关闭 host:port端口 | |
274 | +强制重启swoole-task 必须指定端口 | |
275 | +平滑重启swoole-task 必须指定端口 | |
276 | +获取swoole-task 状态,必须指定port(不指定host默认127.0.0.1), tasking_num是正在处理的任务数量(0表示没有待处理任务) | |
277 | + | |
278 | +HELP; | |
279 | + exit; | |
280 | +} | |
281 | +//参数检查 | |
282 | +foreach ($opts as $k => $v) { | |
283 | + if (($k == 'h' || $k == 'host')) { | |
284 | + if (empty($v)) { | |
285 | + exit("参数 -h --host 必须指定值\n"); | |
286 | + } | |
287 | + } | |
288 | + if (($k == 'p' || $k == 'port')) { | |
289 | + if (empty($v)) { | |
290 | + exit("参数 -p --port 必须指定值\n"); | |
291 | + } | |
292 | + } | |
293 | + if (($k == 'n' || $k == 'name')) { | |
294 | + if (empty($v)) { | |
295 | + exit("参数 -n --name 必须指定值\n"); | |
296 | + } | |
297 | + } | |
298 | +} | |
299 | + | |
300 | +//命令检查 | |
301 | +$cmd = $argv[$argc - 1]; | |
302 | +if (!in_array($cmd, $cmds)) { | |
303 | + exit("输入命令有误 : {$cmd}, 请查看帮助文档\n"); | |
304 | +} | |
305 | + | |
306 | +//监听ip 127.0.0.1,空读取配置文件 | |
307 | +$host = '127.0.0.1'; | |
308 | +if (!empty($opts['h'])) { | |
309 | + $host = $opts['h']; | |
310 | + if (!filter_var($host, FILTER_VALIDATE_IP)) { | |
311 | + exit("输入host有误:{$host}"); | |
312 | + } | |
313 | +} | |
314 | +if (!empty($opts['host'])) { | |
315 | + $host = $opts['host']; | |
316 | + if (!filter_var($host, FILTER_VALIDATE_IP)) { | |
317 | + exit("输入host有误:{$host}"); | |
318 | + } | |
319 | +} | |
320 | +//监听端口,9501 读取配置文件 | |
321 | +$port = 9501; | |
322 | +if (!empty($opts['p'])) { | |
323 | + $port = (int)$opts['p']; | |
324 | + if ($port <= 0) { | |
325 | + exit("输入port有误:{$port}"); | |
326 | + } | |
327 | +} | |
328 | +if (!empty($opts['port'])) { | |
329 | + $port = (int)$opts['port']; | |
330 | + if ($port <= 0) { | |
331 | + exit("输入port有误:{$port}"); | |
332 | + } | |
333 | +} | |
334 | +//进程名称 没有默认为 SWOOLE_TASK_NAME_PRE; | |
335 | +$name = SWOOLE_TASK_NAME_PRE; | |
336 | +if (!empty($opts['n'])) { | |
337 | + $name = $opts['n']; | |
338 | +} | |
339 | +if (!empty($opts['name'])) { | |
340 | + $name = $opts['n']; | |
341 | +} | |
342 | +//是否守护进程 -1 读取配置文件 | |
343 | +$isdaemon = -1; | |
344 | +if (isset($opts['D']) || isset($opts['nondaemon'])) { | |
345 | + $isdaemon = 0; | |
346 | +} | |
347 | +if (isset($opts['d']) || isset($opts['daemon'])) { | |
348 | + $isdaemon = 1; | |
349 | +} | |
350 | +//启动swoole-task服务 | |
351 | +if ($cmd == 'start') { | |
352 | + servStart($host, $port, $isdaemon, $name); | |
353 | +} | |
354 | +//强制停止swoole-task服务 | |
355 | +if ($cmd == 'stop') { | |
356 | + if (empty($port)) { | |
357 | + exit("停止swoole-task服务必须指定port" . PHP_EOL); | |
358 | + } | |
359 | + servStop($host, $port); | |
360 | +} | |
361 | +//关闭swoole-task服务 | |
362 | +if ($cmd == 'close') { | |
363 | + if (empty($port)) { | |
364 | + exit("停止swoole-task服务必须指定port" . PHP_EOL); | |
365 | + } | |
366 | + servClose($host, $port); | |
367 | +} | |
368 | +//强制重启swoole-task服务 | |
369 | +if ($cmd == 'restart') { | |
370 | + if (empty($port)) { | |
371 | + exit("重启swoole-task服务必须指定port" . PHP_EOL); | |
372 | + } | |
373 | + echo "重启swoole-task服务" . PHP_EOL; | |
374 | + servStop($host, $port, true); | |
375 | + servStart($host, $port, $isdaemon, $name); | |
376 | +} | |
377 | +//平滑重启swoole-task服务 | |
378 | +if ($cmd == 'reload') { | |
379 | + if (empty($port)) { | |
380 | + exit("平滑重启swoole-task服务必须指定port" . PHP_EOL); | |
381 | + } | |
382 | + echo "平滑重启swoole-task服务" . PHP_EOL; | |
383 | + servReload($host, $port, true); | |
384 | +} | |
385 | +//查看swoole-task服务状态 | |
386 | +if ($cmd == 'status') { | |
387 | + if (empty($host)) { | |
388 | + $host = '127.0.0.1'; | |
389 | + } | |
390 | + if (empty($port)) { | |
391 | + exit("查看swoole-task服务必须指定port(host不指定默认使用127.0.0.1)" . PHP_EOL); | |
392 | + } | |
393 | + servStatus($host, $port); | |
394 | +} | |
395 | +//查看swoole-task服务进程列表 | |
396 | +if ($cmd == 'list') { | |
397 | + servList(); | |
398 | +} | |
399 | + | |
400 | + | ... | ... |