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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | + |