Passed
Push — 6.0 ( a6b3cd...d3a96b )
by liu
02:43
created

Http::getRoutePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use think\exception\HttpException;
16
use Throwable;
17
18
/**
19
 * Web应用管理类
20
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
21
class Http
22
{
23
24
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
25
     * @var App
26
     */
27
    protected $app;
28
29
    /**
30
     * 应用路径
31
     * @var string
32
     */
33
    protected $path;
34
35
    /**
36
     * 是否多应用模式
37
     * @var bool
38
     */
39
    protected $multi = false;
40
41
    /**
42
     * 是否域名绑定应用
43
     * @var bool
44
     */
45
    protected $bindDomain = false;
46
47
    /**
48
     * 应用名称
49
     * @var string
50
     */
51
    protected $name;
52
53
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing function doc comment
Loading history...
54
    {
55
        $this->app   = $app;
56
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
57
    }
58
59
    /**
60
     * 是否域名绑定应用
61
     * @access public
62
     * @return bool
63
     */
64
    public function isBindDomain(): bool
65
    {
66
        return $this->bindDomain;
67
    }
68
69
    /**
70
     * 设置应用模式
71
     * @access public
72
     * @param bool $multi
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
73
     * @return $this
74
     */
75
    public function multi(bool $multi)
76
    {
77
        $this->multi = $multi;
78
        return $this;
79
    }
80
81
    /**
82
     * 是否为多应用模式
83
     * @access public
84
     * @return bool
85
     */
86
    public function isMulti(): bool
87
    {
88
        return $this->multi;
89
    }
90
91
    /**
92
     * 设置应用名称
93
     * @access public
94
     * @param string $name 应用名称
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
95
     * @return $this
96
     */
97
    public function name(string $name)
98
    {
99
        $this->name = $name;
100
        return $this;
101
    }
102
103
    /**
104
     * 获取应用名称
105
     * @access public
106
     * @return string
107
     */
108
    public function getName(): string
109
    {
110
        return $this->name ?: '';
111
    }
112
113
    /**
114
     * 设置应用目录
115
     * @access public
116
     * @param string $path 应用目录
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
117
     * @return $this
118
     */
119
    public function path(string $path)
120
    {
121
        $this->path = $path;
122
        return $this;
123
    }
124
125
    /**
126
     * 执行应用程序
127
     * @access public
128
     * @param Request|null $request
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
129
     * @return Response
130
     */
131
    public function run(Request $request = null): Response
132
    {
133
        //自动创建request对象
134
        $request = $request ?? $this->app->make('request', [], true);
135
        $this->app->instance('request', $request);
136
137
        try {
138
            $response = $this->runWithRequest($request);
139
        } catch (Throwable $e) {
140
            $this->reportException($e);
141
142
            $response = $this->renderException($request, $e);
143
        }
144
145
        return $response;
146
    }
147
148
    /**
149
     * 初始化
150
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
151
    protected function initialize()
152
    {
153
        if (!$this->app->initialized()) {
154
            $this->app->initialize();
155
        }
156
    }
157
158
    /**
159
     * 执行应用程序
160
     * @param Request $request
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
161
     * @return mixed
162
     */
163
    protected function runWithRequest(Request $request)
164
    {
165
        $this->initialize();
166
167
        if ($this->multi) {
168
            $this->parseMultiApp();
169
        }
170
171
        // 设置开启事件机制
172
        $this->app->event->withEvent($this->app->config->get('app.with_event', true));
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get('app.with_event', true) can also be of type array and array; however, parameter $event of think\Event::withEvent() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

172
        $this->app->event->withEvent(/** @scrutinizer ignore-type */ $this->app->config->get('app.with_event', true));
Loading history...
173
174
        // 监听HttpRun
175
        $this->app->event->trigger('HttpRun');
176
177
        // Session初始化
178
        $varSessionId = $this->app->config->get('route.var_session_id');
179
        if ($varSessionId && $this->request->request($varSessionId)) {
0 ignored issues
show
Bug Best Practice introduced by
The property request does not exist on think\Http. Did you maybe forget to declare it?
Loading history...
180
            $this->app->session->setId($this->request->request($varSessionId));
181
        } else {
182
            $sessionId = $this->app->cookie->get($this->app->config->get('session.cookie_name', 'PHPSESSID')) ?: '';
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get(...kie_name', 'PHPSESSID') can also be of type array and array; however, parameter $name of think\Cookie::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
            $sessionId = $this->app->cookie->get(/** @scrutinizer ignore-type */ $this->app->config->get('session.cookie_name', 'PHPSESSID')) ?: '';
Loading history...
183
            $this->app->session->setId($sessionId);
184
        }
185
186
        $this->app->request->withCookie($this->app->cookie);
0 ignored issues
show
Bug introduced by
$this->app->cookie of type think\Cookie is incompatible with the type think\facade\Cookie expected by parameter $cookie of think\Request::withCookie(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

186
        $this->app->request->withCookie(/** @scrutinizer ignore-type */ $this->app->cookie);
Loading history...
187
        $this->app->request->withSession($this->app->session);
0 ignored issues
show
Bug introduced by
$this->app->session of type think\Session is incompatible with the type think\facade\Session expected by parameter $session of think\Request::withSession(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
        $this->app->request->withSession(/** @scrutinizer ignore-type */ $this->app->session);
Loading history...
188
189
        $withRoute = $this->app->config->get('app.with_route', true) ? function () {
190
            $this->loadRoutes();
191
        } : null;
192
193
        return $this->app->route->dispatch($request, $withRoute);
194
    }
195
196
    /**
197
     * 加载路由
198
     * @access protected
199
     * @return void
200
     */
201
    protected function loadRoutes(): void
202
    {
203
        // 加载路由定义
204
        if (is_dir($this->getRoutePath())) {
205
            $files = glob($this->getRoutePath() . '*.php');
206
            foreach ($files as $file) {
207
                include $file;
208
            }
209
        }
210
211
        if ($this->app->route->config('route_annotation')) {
212
            // 自动生成注解路由定义
213
            if ($this->app->isDebug()) {
214
                $this->app->build->buildRoute();
215
            }
216
217
            $filename = $this->app->getRuntimePath() . 'build_route.php';
218
219
            if (is_file($filename)) {
220
                include $filename;
221
            }
222
        }
223
    }
224
225
    /**
226
     * 获取路由目录
227
     * @access protected
228
     * @return string
229
     */
230
    protected function getRoutePath(): string
231
    {
232
        return $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . ($this->isMulti() ? $this->getName() . DIRECTORY_SEPARATOR : '');
233
    }
234
235
    /**
236
     * Report the exception to the exception handler.
237
     *
238
     * @param Throwable $e
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
239
     * @return void
240
     */
241
    protected function reportException(Throwable $e)
242
    {
243
        $this->app['error_handle']->report($e);
244
    }
245
246
    /**
247
     * Render the exception to a response.
248
     *
249
     * @param Request    $request
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
250
     * @param Throwable $e
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
251
     * @return Response
252
     */
253
    protected function renderException($request, Throwable $e)
254
    {
255
        return $this->app['error_handle']->render($request, $e);
256
    }
257
258
    /**
259
     * 获取当前运行入口名称
260
     * @access protected
261
     * @return string
262
     */
263
    protected function getScriptName(): string
264
    {
265
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
266
            $file = $_SERVER['SCRIPT_FILENAME'];
267
        } elseif (isset($_SERVER['argv'][0])) {
268
            $file = realpath($_SERVER['argv'][0]);
269
        }
270
271
        return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : '';
272
    }
273
274
    /**
275
     * 解析多应用
276
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
277
    protected function parseMultiApp(): void
278
    {
279
        if ($this->app->config->get('app.auto_multi_app', false)) {
280
            // 自动多应用识别
281
            $this->bindDomain = false;
282
283
            $bind = $this->app->config->get('app.domain_bind', []);
284
285
            if (!empty($bind)) {
286
                // 获取当前子域名
287
                $subDomain = $this->app->request->subDomain();
288
                $domain    = $this->app->request->host();
289
290
                if (isset($bind[$domain])) {
291
                    $appName          = $bind[$domain];
292
                    $this->bindDomain = true;
293
                } elseif (isset($bind[$subDomain])) {
294
                    $appName          = $bind[$subDomain];
295
                    $this->bindDomain = true;
296
                }
297
            }
298
299
            if (!$this->bindDomain) {
300
                $map  = $this->app->config->get('app.app_map', []);
301
                $path = $this->app->request->pathinfo();
302
                $name = current(explode('/', $path));
303
304
                if (isset($map[$name])) {
305
                    if ($map[$name] instanceof \Closure) {
306
                        call_user_func_array($map[$name], [$this->app]);
307
                    } else {
308
                        $appName = $map[$name];
309
                    }
310
                } elseif ($name && false !== array_search($name, $map)) {
311
                    throw new HttpException(404, 'app not exists:' . $name);
312
                } else {
313
                    $appName = $name;
314
                }
315
316
                if ($name) {
317
                    $this->app->request->setRoot($name);
318
                    $this->app->request->setPathinfo(strpos($path, '/') ? ltrim(strstr($path, '/'), '/') : '');
319
                }
320
            }
321
        } else {
322
            $appName = $this->name ?: $this->getScriptName();
323
        }
324
325
        $this->loadApp($appName ?: $this->app->config->get('app.default_app', 'index'));
0 ignored issues
show
Bug introduced by
It seems like $appName ?: $this->app->....default_app', 'index') can also be of type array and array; however, parameter $appName of think\Http::loadApp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

325
        $this->loadApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
Comprehensibility Best Practice introduced by
The variable $appName does not seem to be defined for all execution paths leading up to this point.
Loading history...
326
    }
327
328
    /**
329
     * 加载应用文件
330
     * @param string $appName 应用名
1 ignored issue
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
331
     * @return void
332
     */
333
    protected function loadApp(string $appName): void
334
    {
335
        $this->name = $appName;
336
        $this->app->request->setApp($appName);
337
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
338
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
339
340
        //加载app文件
341
        if (is_file($this->app->getRuntimePath() . 'init.php')) {
342
            //直接加载缓存
343
            include $this->app->getRuntimePath() . 'init.php';
344
        } else {
345
            $appPath = $this->app->getAppPath();
346
347
            if (is_file($appPath . 'common.php')) {
348
                include_once $appPath . 'common.php';
349
            }
350
351
            $configPath = $this->app->getConfigPath();
352
353
            $files = [];
354
355
            if (is_dir($appPath . 'config')) {
356
                $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
0 ignored issues
show
Bug introduced by
It seems like glob($appPath . 'config'...s->app->getConfigExt()) can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

356
                $files = array_merge($files, /** @scrutinizer ignore-type */ glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
Loading history...
357
            } elseif (is_dir($configPath . $appName)) {
358
                $files = array_merge($files, glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
359
            }
360
361
            foreach ($files as $file) {
362
                $this->app->config->load($file, pathinfo($file, PATHINFO_FILENAME));
363
            }
364
365
            if (is_file($appPath . 'event.php')) {
366
                $this->app->loadEvent(include $appPath . 'event.php');
367
            }
368
369
            if (is_file($appPath . 'middleware.php')) {
370
                $this->app->middleware->import(include $appPath . 'middleware.php');
371
            }
372
373
            if (is_file($appPath . 'provider.php')) {
374
                $this->app->bind(include $appPath . 'provider.php');
375
            }
376
        }
377
378
        $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get(...') ?: 'app\' . $appName can also be of type array; however, parameter $namespace of think\App::setNamespace() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

378
        $this->app->setNamespace(/** @scrutinizer ignore-type */ $this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
Loading history...
379
    }
380
381
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $response should have a doc-comment as per coding-style.
Loading history...
382
     * HttpEnd
383
     * @return void
384
     */
385
    public function end(Response $response): void
386
    {
387
        $this->app->event->trigger('HttpEnd', $response);
388
389
        // 写入日志
390
        $this->app->log->save();
391
        // 写入Session
392
        $this->app->session->save();
393
    }
394
}
395