Request.php 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2018 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. class Request {
  13. /**
  14. * @var object 对象实例
  15. */
  16. protected static $instance;
  17. protected $method;
  18. /**
  19. * @var string 域名(含协议和端口)
  20. */
  21. protected $domain;
  22. /**
  23. * @var string URL地址
  24. */
  25. protected $url;
  26. /**
  27. * @var string 基础URL
  28. */
  29. protected $baseUrl;
  30. /**
  31. * @var string 当前执行的文件
  32. */
  33. protected $baseFile;
  34. /**
  35. * @var string 访问的ROOT地址
  36. */
  37. protected $root;
  38. /**
  39. * @var string pathinfo
  40. */
  41. protected $pathinfo;
  42. /**
  43. * @var string pathinfo(不含后缀)
  44. */
  45. protected $path;
  46. /**
  47. * @var array 当前路由信息
  48. */
  49. protected $routeInfo = [];
  50. /**
  51. * @var array 环境变量
  52. */
  53. protected $env;
  54. /**
  55. * @var array 当前调度信息
  56. */
  57. protected $dispatch = [];
  58. protected $module;
  59. protected $controller;
  60. protected $action;
  61. // 当前语言集
  62. protected $langset;
  63. /**
  64. * @var array 请求参数
  65. */
  66. protected $param = [];
  67. protected $get = [];
  68. protected $post = [];
  69. protected $request = [];
  70. protected $route = [];
  71. protected $put;
  72. protected $session = [];
  73. protected $file = [];
  74. protected $cookie = [];
  75. protected $server = [];
  76. protected $header = [];
  77. /**
  78. * @var array 资源类型
  79. */
  80. protected $mimeType
  81. = [
  82. 'xml' => 'application/xml,text/xml,application/x-xml',
  83. 'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
  84. 'js' => 'text/javascript,application/javascript,application/x-javascript',
  85. 'css' => 'text/css',
  86. 'rss' => 'application/rss+xml',
  87. 'yaml' => 'application/x-yaml,text/yaml',
  88. 'atom' => 'application/atom+xml',
  89. 'pdf' => 'application/pdf',
  90. 'text' => 'text/plain',
  91. 'image' => 'image/png,image/jpg,image/jpeg,image/pjpeg,image/gif,image/webp,image/*',
  92. 'csv' => 'text/csv',
  93. 'html' => 'text/html,application/xhtml+xml,*/*',
  94. ];
  95. protected $content;
  96. // 全局过滤规则
  97. protected $filter;
  98. // Hook扩展方法
  99. protected static $hook = [];
  100. // 绑定的属性
  101. protected $bind = [];
  102. // php://input
  103. protected $input;
  104. // 请求缓存
  105. protected $cache;
  106. // 缓存是否检查
  107. protected $isCheckCache;
  108. /**
  109. * 是否合并Param
  110. *
  111. * @var bool
  112. */
  113. protected $mergeParam = false;
  114. /**
  115. * 构造函数
  116. *
  117. * @access protected
  118. *
  119. * @param array $options 参数
  120. */
  121. protected function __construct($options = []) {
  122. foreach ($options as $name => $item) {
  123. if (property_exists($this, $name)) {
  124. $this->$name = $item;
  125. }
  126. }
  127. if (is_null($this->filter)) {
  128. $this->filter = Config::get('default_filter');
  129. }
  130. // 保存 php://input
  131. $this->input = file_get_contents('php://input');
  132. }
  133. public function __call($method, $args) {
  134. if (array_key_exists($method, self::$hook)) {
  135. array_unshift($args, $this);
  136. return call_user_func_array(self::$hook[$method], $args);
  137. } else {
  138. throw new Exception('method not exists:'.__CLASS__.'->'.$method);
  139. }
  140. }
  141. /**
  142. * Hook 方法注入
  143. *
  144. * @access public
  145. *
  146. * @param string|array $method 方法名
  147. * @param mixed $callback callable
  148. *
  149. * @return void
  150. */
  151. public static function hook($method, $callback = null) {
  152. if (is_array($method)) {
  153. self::$hook = array_merge(self::$hook, $method);
  154. } else {
  155. self::$hook[$method] = $callback;
  156. }
  157. }
  158. /**
  159. * 初始化
  160. *
  161. * @access public
  162. *
  163. * @param array $options 参数
  164. *
  165. * @return \think\Request
  166. */
  167. public static function instance($options = []) {
  168. if (is_null(self::$instance)) {
  169. self::$instance = new static($options);
  170. }
  171. return self::$instance;
  172. }
  173. /**
  174. * 销毁当前请求对象
  175. *
  176. * @access public
  177. * @return void
  178. */
  179. public static function destroy() {
  180. if (!is_null(self::$instance)) {
  181. self::$instance = null;
  182. }
  183. }
  184. /**
  185. * 创建一个URL请求
  186. *
  187. * @access public
  188. *
  189. * @param string $uri URL地址
  190. * @param string $method 请求类型
  191. * @param array $params 请求参数
  192. * @param array $cookie
  193. * @param array $files
  194. * @param array $server
  195. * @param string $content
  196. *
  197. * @return \think\Request
  198. */
  199. public static function create(
  200. $uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null
  201. ) {
  202. $server['PATH_INFO'] = '';
  203. $server['REQUEST_METHOD'] = strtoupper($method);
  204. $info = parse_url($uri);
  205. if (isset($info['host'])) {
  206. $server['SERVER_NAME'] = $info['host'];
  207. $server['HTTP_HOST'] = $info['host'];
  208. }
  209. if (isset($info['scheme'])) {
  210. if ('https' === $info['scheme']) {
  211. $server['HTTPS'] = 'on';
  212. $server['SERVER_PORT'] = 443;
  213. } else {
  214. unset($server['HTTPS']);
  215. $server['SERVER_PORT'] = 80;
  216. }
  217. }
  218. if (isset($info['port'])) {
  219. $server['SERVER_PORT'] = $info['port'];
  220. $server['HTTP_HOST'] = $server['HTTP_HOST'].':'.$info['port'];
  221. }
  222. if (isset($info['user'])) {
  223. $server['PHP_AUTH_USER'] = $info['user'];
  224. }
  225. if (isset($info['pass'])) {
  226. $server['PHP_AUTH_PW'] = $info['pass'];
  227. }
  228. if (!isset($info['path'])) {
  229. $info['path'] = '/';
  230. }
  231. $options = [];
  232. $options[strtolower($method)] = $params;
  233. $queryString = '';
  234. if (isset($info['query'])) {
  235. parse_str(html_entity_decode($info['query']), $query);
  236. if (!empty($params)) {
  237. $params = array_replace($query, $params);
  238. $queryString = http_build_query($params, '', '&');
  239. } else {
  240. $params = $query;
  241. $queryString = $info['query'];
  242. }
  243. } elseif (!empty($params)) {
  244. $queryString = http_build_query($params, '', '&');
  245. }
  246. if ($queryString) {
  247. parse_str($queryString, $get);
  248. $options['get'] = isset($options['get']) ? array_merge($get, $options['get']) : $get;
  249. }
  250. $server['REQUEST_URI'] = $info['path'].('' !== $queryString ? '?'.$queryString : '');
  251. $server['QUERY_STRING'] = $queryString;
  252. $options['cookie'] = $cookie;
  253. $options['param'] = $params;
  254. $options['file'] = $files;
  255. $options['server'] = $server;
  256. $options['url'] = $server['REQUEST_URI'];
  257. $options['baseUrl'] = $info['path'];
  258. $options['pathinfo'] = '/' == $info['path'] ? '/' : ltrim($info['path'], '/');
  259. $options['method'] = $server['REQUEST_METHOD'];
  260. $options['domain'] = isset($info['scheme']) ? $info['scheme'].'://'.$server['HTTP_HOST'] : '';
  261. $options['content'] = $content;
  262. self::$instance = new self($options);
  263. return self::$instance;
  264. }
  265. /**
  266. * 设置或获取当前包含协议的域名
  267. *
  268. * @access public
  269. *
  270. * @param string $domain 域名
  271. *
  272. * @return string
  273. */
  274. public function domain($domain = null) {
  275. if (!is_null($domain)) {
  276. $this->domain = $domain;
  277. return $this;
  278. } elseif (!$this->domain) {
  279. $this->domain = $this->scheme().'://'.$this->host();
  280. }
  281. return $this->domain;
  282. }
  283. /**
  284. * 设置或获取当前完整URL 包括QUERY_STRING
  285. *
  286. * @access public
  287. *
  288. * @param string|true $url URL地址 true 带域名获取
  289. *
  290. * @return string
  291. */
  292. public function url($url = null) {
  293. if (!is_null($url) && true !== $url) {
  294. $this->url = $url;
  295. return $this;
  296. } elseif (!$this->url) {
  297. if (IS_CLI) {
  298. $this->url = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
  299. } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
  300. $this->url = $_SERVER['HTTP_X_REWRITE_URL'];
  301. } elseif (isset($_SERVER['REQUEST_URI'])) {
  302. $this->url = $_SERVER['REQUEST_URI'];
  303. } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
  304. $this->url = $_SERVER['ORIG_PATH_INFO'].(!empty($_SERVER['QUERY_STRING']) ? '?'.$_SERVER['QUERY_STRING']
  305. : '');
  306. } else {
  307. $this->url = '';
  308. }
  309. }
  310. return true === $url ? $this->domain().$this->url : $this->url;
  311. }
  312. /**
  313. * 设置或获取当前URL 不含QUERY_STRING
  314. *
  315. * @access public
  316. *
  317. * @param string $url URL地址
  318. *
  319. * @return string
  320. */
  321. public function baseUrl($url = null) {
  322. if (!is_null($url) && true !== $url) {
  323. $this->baseUrl = $url;
  324. return $this;
  325. } elseif (!$this->baseUrl) {
  326. $str = $this->url();
  327. $this->baseUrl = strpos($str, '?') ? strstr($str, '?', true) : $str;
  328. }
  329. return true === $url ? $this->domain().$this->baseUrl : $this->baseUrl;
  330. }
  331. /**
  332. * 设置或获取当前执行的文件 SCRIPT_NAME
  333. *
  334. * @access public
  335. *
  336. * @param string $file 当前执行的文件
  337. *
  338. * @return string
  339. */
  340. public function baseFile($file = null) {
  341. if (!is_null($file) && true !== $file) {
  342. $this->baseFile = $file;
  343. return $this;
  344. } elseif (!$this->baseFile) {
  345. $url = '';
  346. if (!IS_CLI) {
  347. $script_name = basename($_SERVER['SCRIPT_FILENAME']);
  348. if (basename($_SERVER['SCRIPT_NAME']) === $script_name) {
  349. $url = $_SERVER['SCRIPT_NAME'];
  350. } elseif (basename($_SERVER['PHP_SELF']) === $script_name) {
  351. $url = $_SERVER['PHP_SELF'];
  352. } elseif (isset($_SERVER['ORIG_SCRIPT_NAME'])
  353. && basename($_SERVER['ORIG_SCRIPT_NAME']) === $script_name) {
  354. $url = $_SERVER['ORIG_SCRIPT_NAME'];
  355. } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/'.$script_name)) !== false) {
  356. $url = substr($_SERVER['SCRIPT_NAME'], 0, $pos).'/'.$script_name;
  357. } elseif (isset($_SERVER['DOCUMENT_ROOT'])
  358. && strpos(
  359. $_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']
  360. ) === 0) {
  361. $url = str_replace(
  362. '\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME'])
  363. );
  364. }
  365. }
  366. $this->baseFile = $url;
  367. }
  368. return true === $file ? $this->domain().$this->baseFile : $this->baseFile;
  369. }
  370. /**
  371. * 设置或获取URL访问根地址
  372. *
  373. * @access public
  374. *
  375. * @param string $url URL地址
  376. *
  377. * @return string
  378. */
  379. public function root($url = null) {
  380. if (!is_null($url) && true !== $url) {
  381. $this->root = $url;
  382. return $this;
  383. } elseif (!$this->root) {
  384. $file = $this->baseFile();
  385. if ($file && 0 !== strpos($this->url(), $file)) {
  386. $file = str_replace('\\', '/', dirname($file));
  387. }
  388. $this->root = rtrim($file, '/');
  389. }
  390. return true === $url ? $this->domain().$this->root : $this->root;
  391. }
  392. /**
  393. * 获取当前请求URL的pathinfo信息(含URL后缀)
  394. *
  395. * @access public
  396. * @return string
  397. */
  398. public function pathinfo() {
  399. if (is_null($this->pathinfo)) {
  400. if (isset($_GET[Config::get('var_pathinfo')])) {
  401. // 判断URL里面是否有兼容模式参数
  402. $_SERVER['PATH_INFO'] = $_GET[Config::get('var_pathinfo')];
  403. unset($_GET[Config::get('var_pathinfo')]);
  404. } elseif (IS_CLI) {
  405. // CLI模式下 index.php module/controller/action/params/...
  406. $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
  407. }
  408. // 分析PATHINFO信息
  409. if (!isset($_SERVER['PATH_INFO'])) {
  410. foreach (Config::get('pathinfo_fetch') as $type) {
  411. if (!empty($_SERVER[$type])) {
  412. $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?
  413. substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];
  414. break;
  415. }
  416. }
  417. }
  418. $this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');
  419. }
  420. return $this->pathinfo;
  421. }
  422. /**
  423. * 获取当前请求URL的pathinfo信息(不含URL后缀)
  424. *
  425. * @access public
  426. * @return string
  427. */
  428. public function path() {
  429. if (is_null($this->path)) {
  430. $suffix = Config::get('url_html_suffix');
  431. $pathinfo = $this->pathinfo();
  432. if (false === $suffix) {
  433. // 禁止伪静态访问
  434. $this->path = $pathinfo;
  435. } elseif ($suffix) {
  436. // 去除正常的URL后缀
  437. $this->path = preg_replace('/\.('.ltrim($suffix, '.').')$/i', '', $pathinfo);
  438. } else {
  439. // 允许任何后缀访问
  440. $this->path = preg_replace('/\.'.$this->ext().'$/i', '', $pathinfo);
  441. }
  442. }
  443. return $this->path;
  444. }
  445. /**
  446. * 当前URL的访问后缀
  447. *
  448. * @access public
  449. * @return string
  450. */
  451. public function ext() {
  452. return pathinfo($this->pathinfo(), PATHINFO_EXTENSION);
  453. }
  454. /**
  455. * 获取当前请求的时间
  456. *
  457. * @access public
  458. *
  459. * @param bool $float 是否使用浮点类型
  460. *
  461. * @return integer|float
  462. */
  463. public function time($float = false) {
  464. return $float ? $_SERVER['REQUEST_TIME_FLOAT'] : $_SERVER['REQUEST_TIME'];
  465. }
  466. /**
  467. * 当前请求的资源类型
  468. *
  469. * @access public
  470. * @return false|string
  471. */
  472. public function type() {
  473. $accept = $this->server('HTTP_ACCEPT');
  474. if (empty($accept)) {
  475. return false;
  476. }
  477. foreach ($this->mimeType as $key => $val) {
  478. $array = explode(',', $val);
  479. foreach ($array as $k => $v) {
  480. if (stristr($accept, $v)) {
  481. return $key;
  482. }
  483. }
  484. }
  485. return false;
  486. }
  487. /**
  488. * 设置资源类型
  489. *
  490. * @access public
  491. *
  492. * @param string|array $type 资源类型名
  493. * @param string $val 资源类型
  494. *
  495. * @return void
  496. */
  497. public function mimeType($type, $val = '') {
  498. if (is_array($type)) {
  499. $this->mimeType = array_merge($this->mimeType, $type);
  500. } else {
  501. $this->mimeType[$type] = $val;
  502. }
  503. }
  504. /**
  505. * 当前的请求类型
  506. *
  507. * @access public
  508. *
  509. * @param bool $method true 获取原始请求类型
  510. *
  511. * @return string
  512. */
  513. public function method($method = false) {
  514. if (true === $method) {
  515. // 获取原始请求类型
  516. return $this->server('REQUEST_METHOD') ?: 'GET';
  517. } elseif (!$this->method) {
  518. if (isset($_POST[Config::get('var_method')])) {
  519. $method = strtoupper($_POST[Config::get('var_method')]);
  520. if (in_array($method, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) {
  521. $this->method = $method;
  522. $this->{$this->method}($_POST);
  523. } else {
  524. $this->method = 'POST';
  525. }
  526. unset($_POST[Config::get('var_method')]);
  527. } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
  528. $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
  529. } else {
  530. $this->method = $this->server('REQUEST_METHOD') ?: 'GET';
  531. }
  532. }
  533. return $this->method;
  534. }
  535. /**
  536. * 是否为GET请求
  537. *
  538. * @access public
  539. * @return bool
  540. */
  541. public function isGet() {
  542. return $this->method() == 'GET';
  543. }
  544. /**
  545. * 是否为POST请求
  546. *
  547. * @access public
  548. * @return bool
  549. */
  550. public function isPost() {
  551. return $this->method() == 'POST';
  552. }
  553. /**
  554. * 是否为PUT请求
  555. *
  556. * @access public
  557. * @return bool
  558. */
  559. public function isPut() {
  560. return $this->method() == 'PUT';
  561. }
  562. /**
  563. * 是否为DELTE请求
  564. *
  565. * @access public
  566. * @return bool
  567. */
  568. public function isDelete() {
  569. return $this->method() == 'DELETE';
  570. }
  571. /**
  572. * 是否为HEAD请求
  573. *
  574. * @access public
  575. * @return bool
  576. */
  577. public function isHead() {
  578. return $this->method() == 'HEAD';
  579. }
  580. /**
  581. * 是否为PATCH请求
  582. *
  583. * @access public
  584. * @return bool
  585. */
  586. public function isPatch() {
  587. return $this->method() == 'PATCH';
  588. }
  589. /**
  590. * 是否为OPTIONS请求
  591. *
  592. * @access public
  593. * @return bool
  594. */
  595. public function isOptions() {
  596. return $this->method() == 'OPTIONS';
  597. }
  598. /**
  599. * 是否为cli
  600. *
  601. * @access public
  602. * @return bool
  603. */
  604. public function isCli() {
  605. return PHP_SAPI == 'cli';
  606. }
  607. /**
  608. * 是否为cgi
  609. *
  610. * @access public
  611. * @return bool
  612. */
  613. public function isCgi() {
  614. return strpos(PHP_SAPI, 'cgi') === 0;
  615. }
  616. /**
  617. * 获取当前请求的参数
  618. *
  619. * @access public
  620. *
  621. * @param string|array $name 变量名
  622. * @param mixed $default 默认值
  623. * @param string|array $filter 过滤方法
  624. *
  625. * @return mixed
  626. */
  627. public function param($name = '', $default = null, $filter = '') {
  628. if (empty($this->mergeParam)) {
  629. $method = $this->method(true);
  630. // 自动获取请求变量
  631. switch ($method) {
  632. case 'POST':
  633. $vars = $this->post(false);
  634. break;
  635. case 'PUT':
  636. case 'DELETE':
  637. case 'PATCH':
  638. $vars = $this->put(false);
  639. break;
  640. default:
  641. $vars = [];
  642. }
  643. // 当前请求参数和URL地址中的参数合并
  644. $this->param = array_merge($this->param, $this->get(false), $vars, $this->route(false));
  645. $this->mergeParam = true;
  646. }
  647. if (true === $name) {
  648. // 获取包含文件上传信息的数组
  649. $file = $this->file();
  650. $data = is_array($file) ? array_merge($this->param, $file) : $this->param;
  651. return $this->input($data, '', $default, $filter);
  652. }
  653. return $this->input($this->param, $name, $default, $filter);
  654. }
  655. /**
  656. * 设置获取路由参数
  657. *
  658. * @access public
  659. *
  660. * @param string|array $name 变量名
  661. * @param mixed $default 默认值
  662. * @param string|array $filter 过滤方法
  663. *
  664. * @return mixed
  665. */
  666. public function route($name = '', $default = null, $filter = '') {
  667. if (is_array($name)) {
  668. $this->param = [];
  669. $this->mergeParam = false;
  670. return $this->route = array_merge($this->route, $name);
  671. }
  672. return $this->input($this->route, $name, $default, $filter);
  673. }
  674. /**
  675. * 设置获取GET参数
  676. *
  677. * @access public
  678. *
  679. * @param string|array $name 变量名
  680. * @param mixed $default 默认值
  681. * @param string|array $filter 过滤方法
  682. *
  683. * @return mixed
  684. */
  685. public function get($name = '', $default = null, $filter = '') {
  686. if (empty($this->get)) {
  687. $this->get = $_GET;
  688. }
  689. if (is_array($name)) {
  690. $this->param = [];
  691. $this->mergeParam = false;
  692. return $this->get = array_merge($this->get, $name);
  693. }
  694. return $this->input($this->get, $name, $default, $filter);
  695. }
  696. /**
  697. * 设置获取POST参数
  698. *
  699. * @access public
  700. *
  701. * @param string $name 变量名
  702. * @param mixed $default 默认值
  703. * @param string|array $filter 过滤方法
  704. *
  705. * @return mixed
  706. */
  707. public function post($name = '', $default = null, $filter = '') {
  708. if (empty($this->post)) {
  709. $content = $this->input;
  710. if (empty($_POST) && false !== strpos($this->contentType(), 'application/json')) {
  711. $this->post = (array)json_decode($content, true);
  712. } else {
  713. $this->post = $_POST;
  714. }
  715. }
  716. if (is_array($name)) {
  717. $this->param = [];
  718. $this->mergeParam = false;
  719. return $this->post = array_merge($this->post, $name);
  720. }
  721. return $this->input($this->post, $name, $default, $filter);
  722. }
  723. /**
  724. * 设置获取PUT参数
  725. *
  726. * @access public
  727. *
  728. * @param string|array $name 变量名
  729. * @param mixed $default 默认值
  730. * @param string|array $filter 过滤方法
  731. *
  732. * @return mixed
  733. */
  734. public function put($name = '', $default = null, $filter = '') {
  735. if (is_null($this->put)) {
  736. $content = $this->input;
  737. if (false !== strpos($this->contentType(), 'application/json')) {
  738. $this->put = (array)json_decode($content, true);
  739. } else {
  740. parse_str($content, $this->put);
  741. }
  742. }
  743. if (is_array($name)) {
  744. $this->param = [];
  745. $this->mergeParam = false;
  746. return $this->put = is_null($this->put) ? $name : array_merge($this->put, $name);
  747. }
  748. return $this->input($this->put, $name, $default, $filter);
  749. }
  750. /**
  751. * 设置获取DELETE参数
  752. *
  753. * @access public
  754. *
  755. * @param string|array $name 变量名
  756. * @param mixed $default 默认值
  757. * @param string|array $filter 过滤方法
  758. *
  759. * @return mixed
  760. */
  761. public function delete($name = '', $default = null, $filter = '') {
  762. return $this->put($name, $default, $filter);
  763. }
  764. /**
  765. * 设置获取PATCH参数
  766. *
  767. * @access public
  768. *
  769. * @param string|array $name 变量名
  770. * @param mixed $default 默认值
  771. * @param string|array $filter 过滤方法
  772. *
  773. * @return mixed
  774. */
  775. public function patch($name = '', $default = null, $filter = '') {
  776. return $this->put($name, $default, $filter);
  777. }
  778. /**
  779. * 获取request变量
  780. *
  781. * @param string $name 数据名称
  782. * @param string $default 默认值
  783. * @param string|array $filter 过滤方法
  784. *
  785. * @return mixed
  786. */
  787. public function request($name = '', $default = null, $filter = '') {
  788. if (empty($this->request)) {
  789. $this->request = $_REQUEST;
  790. }
  791. if (is_array($name)) {
  792. $this->param = [];
  793. $this->mergeParam = false;
  794. return $this->request = array_merge($this->request, $name);
  795. }
  796. return $this->input($this->request, $name, $default, $filter);
  797. }
  798. /**
  799. * 获取session数据
  800. *
  801. * @access public
  802. *
  803. * @param string|array $name 数据名称
  804. * @param string $default 默认值
  805. * @param string|array $filter 过滤方法
  806. *
  807. * @return mixed
  808. */
  809. public function session($name = '', $default = null, $filter = '') {
  810. if (empty($this->session)) {
  811. $this->session = Session::get();
  812. }
  813. if (is_array($name)) {
  814. return $this->session = array_merge($this->session, $name);
  815. }
  816. return $this->input($this->session, $name, $default, $filter);
  817. }
  818. /**
  819. * 获取cookie参数
  820. *
  821. * @access public
  822. *
  823. * @param string|array $name 数据名称
  824. * @param string $default 默认值
  825. * @param string|array $filter 过滤方法
  826. *
  827. * @return mixed
  828. */
  829. public function cookie($name = '', $default = null, $filter = '') {
  830. if (empty($this->cookie)) {
  831. $this->cookie = Cookie::get();
  832. }
  833. if (is_array($name)) {
  834. return $this->cookie = array_merge($this->cookie, $name);
  835. } elseif (!empty($name)) {
  836. $data = Cookie::has($name) ? Cookie::get($name) : $default;
  837. } else {
  838. $data = $this->cookie;
  839. }
  840. // 解析过滤器
  841. $filter = $this->getFilter($filter, $default);
  842. if (is_array($data)) {
  843. array_walk_recursive($data, [$this, 'filterValue'], $filter);
  844. reset($data);
  845. } else {
  846. $this->filterValue($data, $name, $filter);
  847. }
  848. return $data;
  849. }
  850. /**
  851. * 获取server参数
  852. *
  853. * @access public
  854. *
  855. * @param string|array $name 数据名称
  856. * @param string $default 默认值
  857. * @param string|array $filter 过滤方法
  858. *
  859. * @return mixed
  860. */
  861. public function server($name = '', $default = null, $filter = '') {
  862. if (empty($this->server)) {
  863. $this->server = $_SERVER;
  864. }
  865. if (is_array($name)) {
  866. return $this->server = array_merge($this->server, $name);
  867. }
  868. return $this->input($this->server, false === $name ? false : strtoupper($name), $default, $filter);
  869. }
  870. /**
  871. * 获取上传的文件信息
  872. *
  873. * @access public
  874. *
  875. * @param string|array $name 名称
  876. *
  877. * @return null|array|\think\File
  878. */
  879. public function file($name = '') {
  880. if (empty($this->file)) {
  881. $this->file = isset($_FILES) ? $_FILES : [];
  882. }
  883. if (is_array($name)) {
  884. return $this->file = array_merge($this->file, $name);
  885. }
  886. $files = $this->file;
  887. if (!empty($files)) {
  888. // 处理上传文件
  889. $array = [];
  890. foreach ($files as $key => $file) {
  891. if (is_array($file['name'])) {
  892. $item = [];
  893. $keys = array_keys($file);
  894. $count = count($file['name']);
  895. for ($i = 0; $i < $count; $i++) {
  896. if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name'][$i])) {
  897. continue;
  898. }
  899. $temp['key'] = $key;
  900. foreach ($keys as $_key) {
  901. $temp[$_key] = $file[$_key][$i];
  902. }
  903. $item[] = (new File($temp['tmp_name']))->setUploadInfo($temp);
  904. }
  905. $array[$key] = $item;
  906. } else {
  907. if ($file instanceof File) {
  908. $array[$key] = $file;
  909. } else {
  910. if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) {
  911. continue;
  912. }
  913. $array[$key] = (new File($file['tmp_name']))->setUploadInfo($file);
  914. }
  915. }
  916. }
  917. if (strpos($name, '.')) {
  918. list($name, $sub) = explode('.', $name);
  919. }
  920. if ('' === $name) {
  921. // 获取全部文件
  922. return $array;
  923. } elseif (isset($sub) && isset($array[$name][$sub])) {
  924. return $array[$name][$sub];
  925. } elseif (isset($array[$name])) {
  926. return $array[$name];
  927. }
  928. }
  929. return;
  930. }
  931. /**
  932. * 获取环境变量
  933. *
  934. * @param string|array $name 数据名称
  935. * @param string $default 默认值
  936. * @param string|array $filter 过滤方法
  937. *
  938. * @return mixed
  939. */
  940. public function env($name = '', $default = null, $filter = '') {
  941. if (empty($this->env)) {
  942. $this->env = $_ENV;
  943. }
  944. if (is_array($name)) {
  945. return $this->env = array_merge($this->env, $name);
  946. }
  947. return $this->input($this->env, false === $name ? false : strtoupper($name), $default, $filter);
  948. }
  949. /**
  950. * 设置或者获取当前的Header
  951. *
  952. * @access public
  953. *
  954. * @param string|array $name header名称
  955. * @param string $default 默认值
  956. *
  957. * @return string
  958. */
  959. public function header($name = '', $default = null) {
  960. if (empty($this->header)) {
  961. $header = [];
  962. if (function_exists('apache_request_headers') && $result = apache_request_headers()) {
  963. $header = $result;
  964. } else {
  965. $server = $this->server ?: $_SERVER;
  966. foreach ($server as $key => $val) {
  967. if (0 === strpos($key, 'HTTP_')) {
  968. $key = str_replace('_', '-', strtolower(substr($key, 5)));
  969. $header[$key] = $val;
  970. }
  971. }
  972. if (isset($server['CONTENT_TYPE'])) {
  973. $header['content-type'] = $server['CONTENT_TYPE'];
  974. }
  975. if (isset($server['CONTENT_LENGTH'])) {
  976. $header['content-length'] = $server['CONTENT_LENGTH'];
  977. }
  978. }
  979. $this->header = array_change_key_case($header);
  980. }
  981. if (is_array($name)) {
  982. return $this->header = array_merge($this->header, $name);
  983. }
  984. if ('' === $name) {
  985. return $this->header;
  986. }
  987. $name = str_replace('_', '-', strtolower($name));
  988. return isset($this->header[$name]) ? $this->header[$name] : $default;
  989. }
  990. /**
  991. * 获取变量 支持过滤和默认值
  992. *
  993. * @param array $data 数据源
  994. * @param string|false $name 字段名
  995. * @param mixed $default 默认值
  996. * @param string|array $filter 过滤函数
  997. *
  998. * @return mixed
  999. */
  1000. public function input($data = [], $name = '', $default = null, $filter = '') {
  1001. if (false === $name) {
  1002. // 获取原始数据
  1003. return $data;
  1004. }
  1005. $name = (string)$name;
  1006. if ('' != $name) {
  1007. // 解析name
  1008. if (strpos($name, '/')) {
  1009. list($name, $type) = explode('/', $name);
  1010. } else {
  1011. $type = 's';
  1012. }
  1013. // 按.拆分成多维数组进行判断
  1014. foreach (explode('.', $name) as $val) {
  1015. if (isset($data[$val])) {
  1016. $data = $data[$val];
  1017. } else {
  1018. // 无输入数据,返回默认值
  1019. return $default;
  1020. }
  1021. }
  1022. if (is_object($data)) {
  1023. return $data;
  1024. }
  1025. }
  1026. // 解析过滤器
  1027. $filter = $this->getFilter($filter, $default);
  1028. if (is_array($data)) {
  1029. array_walk_recursive($data, [$this, 'filterValue'], $filter);
  1030. reset($data);
  1031. } else {
  1032. $this->filterValue($data, $name, $filter);
  1033. }
  1034. if (isset($type) && $data !== $default) {
  1035. // 强制类型转换
  1036. $this->typeCast($data, $type);
  1037. }
  1038. return $data;
  1039. }
  1040. /**
  1041. * 设置或获取当前的过滤规则
  1042. *
  1043. * @param mixed $filter 过滤规则
  1044. *
  1045. * @return mixed
  1046. */
  1047. public function filter($filter = null) {
  1048. if (is_null($filter)) {
  1049. return $this->filter;
  1050. } else {
  1051. $this->filter = $filter;
  1052. }
  1053. }
  1054. protected function getFilter($filter, $default) {
  1055. if (is_null($filter)) {
  1056. $filter = [];
  1057. } else {
  1058. $filter = $filter ?: $this->filter;
  1059. if (is_string($filter) && false === strpos($filter, '/')) {
  1060. $filter = explode(',', $filter);
  1061. } else {
  1062. $filter = (array)$filter;
  1063. }
  1064. }
  1065. $filter[] = $default;
  1066. return $filter;
  1067. }
  1068. /**
  1069. * 递归过滤给定的值
  1070. *
  1071. * @param mixed $value 键值
  1072. * @param mixed $key 键名
  1073. * @param array $filters 过滤方法+默认值
  1074. *
  1075. * @return mixed
  1076. */
  1077. private function filterValue(&$value, $key, $filters) {
  1078. $default = array_pop($filters);
  1079. foreach ($filters as $filter) {
  1080. if (is_callable($filter)) {
  1081. // 调用函数或者方法过滤
  1082. $value = call_user_func($filter, $value);
  1083. } elseif (is_scalar($value)) {
  1084. if (false !== strpos($filter, '/')) {
  1085. // 正则过滤
  1086. if (!preg_match($filter, $value)) {
  1087. // 匹配不成功返回默认值
  1088. $value = $default;
  1089. break;
  1090. }
  1091. } elseif (!empty($filter)) {
  1092. // filter函数不存在时, 则使用filter_var进行过滤
  1093. // filter为非整形值时, 调用filter_id取得过滤id
  1094. $value = filter_var($value, is_int($filter) ? $filter : filter_id($filter));
  1095. if (false === $value) {
  1096. $value = $default;
  1097. break;
  1098. }
  1099. }
  1100. }
  1101. }
  1102. return $this->filterExp($value);
  1103. }
  1104. /**
  1105. * 过滤表单中的表达式
  1106. *
  1107. * @param string $value
  1108. *
  1109. * @return void
  1110. */
  1111. public function filterExp(&$value) {
  1112. // 过滤查询特殊字符
  1113. if (is_string($value)
  1114. && preg_match(
  1115. '/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT LIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOT EXISTS|NOTEXISTS|EXISTS|NOT NULL|NOTNULL|NULL|BETWEEN TIME|NOT BETWEEN TIME|NOTBETWEEN TIME|NOTIN|NOT IN|IN)$/i',
  1116. $value
  1117. )) {
  1118. $value .= ' ';
  1119. }
  1120. // TODO 其他安全过滤
  1121. }
  1122. /**
  1123. * 强制类型转换
  1124. *
  1125. * @param string $data
  1126. * @param string $type
  1127. *
  1128. * @return mixed
  1129. */
  1130. private function typeCast(&$data, $type) {
  1131. switch (strtolower($type)) {
  1132. // 数组
  1133. case 'a':
  1134. $data = (array)$data;
  1135. break;
  1136. // 数字
  1137. case 'd':
  1138. $data = (int)$data;
  1139. break;
  1140. // 浮点
  1141. case 'f':
  1142. $data = (float)$data;
  1143. break;
  1144. // 布尔
  1145. case 'b':
  1146. $data = (boolean)$data;
  1147. break;
  1148. // 字符串
  1149. case 's':
  1150. default:
  1151. if (is_scalar($data)) {
  1152. $data = (string)$data;
  1153. } else {
  1154. throw new \InvalidArgumentException('variable type error:'.gettype($data));
  1155. }
  1156. }
  1157. }
  1158. /**
  1159. * 是否存在某个请求参数
  1160. *
  1161. * @access public
  1162. *
  1163. * @param string $name 变量名
  1164. * @param string $type 变量类型
  1165. * @param bool $checkEmpty 是否检测空值
  1166. *
  1167. * @return mixed
  1168. */
  1169. public function has($name, $type = 'param', $checkEmpty = false) {
  1170. if (empty($this->$type)) {
  1171. $param = $this->$type();
  1172. } else {
  1173. $param = $this->$type;
  1174. }
  1175. // 按.拆分成多维数组进行判断
  1176. foreach (explode('.', $name) as $val) {
  1177. if (isset($param[$val])) {
  1178. $param = $param[$val];
  1179. } else {
  1180. return false;
  1181. }
  1182. }
  1183. return ($checkEmpty && '' === $param) ? false : true;
  1184. }
  1185. /**
  1186. * 获取指定的参数
  1187. *
  1188. * @access public
  1189. *
  1190. * @param string|array $name 变量名
  1191. * @param string $type 变量类型
  1192. *
  1193. * @return mixed
  1194. */
  1195. public function only($name, $type = 'param') {
  1196. $param = $this->$type();
  1197. if (is_string($name)) {
  1198. $name = explode(',', $name);
  1199. }
  1200. $item = [];
  1201. foreach ($name as $key) {
  1202. if (isset($param[$key])) {
  1203. $item[$key] = $param[$key];
  1204. }
  1205. }
  1206. return $item;
  1207. }
  1208. /**
  1209. * 排除指定参数获取
  1210. *
  1211. * @access public
  1212. *
  1213. * @param string|array $name 变量名
  1214. * @param string $type 变量类型
  1215. *
  1216. * @return mixed
  1217. */
  1218. public function except($name, $type = 'param') {
  1219. $param = $this->$type();
  1220. if (is_string($name)) {
  1221. $name = explode(',', $name);
  1222. }
  1223. foreach ($name as $key) {
  1224. if (isset($param[$key])) {
  1225. unset($param[$key]);
  1226. }
  1227. }
  1228. return $param;
  1229. }
  1230. /**
  1231. * 当前是否ssl
  1232. *
  1233. * @access public
  1234. * @return bool
  1235. */
  1236. public function isSsl() {
  1237. $server = array_merge($_SERVER, $this->server);
  1238. if (isset($server['HTTPS']) && ('1' == $server['HTTPS'] || 'on' == strtolower($server['HTTPS']))) {
  1239. return true;
  1240. } elseif (isset($server['REQUEST_SCHEME']) && 'https' == $server['REQUEST_SCHEME']) {
  1241. return true;
  1242. } elseif (isset($server['SERVER_PORT']) && ('443' == $server['SERVER_PORT'])) {
  1243. return true;
  1244. } elseif (isset($server['HTTP_X_FORWARDED_PROTO']) && 'https' == $server['HTTP_X_FORWARDED_PROTO']) {
  1245. return true;
  1246. } elseif (Config::get('https_agent_name') && isset($server[Config::get('https_agent_name')])) {
  1247. return true;
  1248. }
  1249. return false;
  1250. }
  1251. /**
  1252. * 当前是否Ajax请求
  1253. *
  1254. * @access public
  1255. *
  1256. * @param bool $ajax true 获取原始ajax请求
  1257. *
  1258. * @return bool
  1259. */
  1260. public function isAjax($ajax = false) {
  1261. $value = $this->server('HTTP_X_REQUESTED_WITH', '', 'strtolower');
  1262. $result = ('xmlhttprequest' == $value) ? true : false;
  1263. if (true === $ajax) {
  1264. return $result;
  1265. } else {
  1266. $result = $this->param(Config::get('var_ajax')) ? true : $result;
  1267. $this->mergeParam = false;
  1268. return $result;
  1269. }
  1270. }
  1271. /**
  1272. * 当前是否Pjax请求
  1273. *
  1274. * @access public
  1275. *
  1276. * @param bool $pjax true 获取原始pjax请求
  1277. *
  1278. * @return bool
  1279. */
  1280. public function isPjax($pjax = false) {
  1281. $result = !is_null($this->server('HTTP_X_PJAX')) ? true : false;
  1282. if (true === $pjax) {
  1283. return $result;
  1284. } else {
  1285. $result = $this->param(Config::get('var_pjax')) ? true : $result;
  1286. $this->mergeParam = false;
  1287. return $result;
  1288. }
  1289. }
  1290. /**
  1291. * 获取客户端IP地址
  1292. *
  1293. * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
  1294. * @param boolean $adv 是否进行高级模式获取(有可能被伪装)
  1295. *
  1296. * @return mixed
  1297. */
  1298. public function ip($type = 0, $adv = true) {
  1299. $type = $type ? 1 : 0;
  1300. static $ip = null;
  1301. if (null !== $ip) {
  1302. return $ip[$type];
  1303. }
  1304. $httpAgentIp = Config::get('http_agent_ip');
  1305. if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) {
  1306. $ip = $_SERVER[$httpAgentIp];
  1307. } elseif ($adv) {
  1308. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  1309. $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
  1310. $pos = array_search('unknown', $arr);
  1311. if (false !== $pos) {
  1312. unset($arr[$pos]);
  1313. }
  1314. $ip = trim(current($arr));
  1315. } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
  1316. $ip = $_SERVER['HTTP_CLIENT_IP'];
  1317. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  1318. $ip = $_SERVER['REMOTE_ADDR'];
  1319. }
  1320. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  1321. $ip = $_SERVER['REMOTE_ADDR'];
  1322. }
  1323. // IP地址合法验证
  1324. $long = sprintf("%u", ip2long($ip));
  1325. $ip = $long ? [$ip, $long] : ['0.0.0.0', 0];
  1326. return $ip[$type];
  1327. }
  1328. /**
  1329. * 获取当前客户端类型 返回android 和 ios
  1330. *
  1331. * @access public
  1332. * @return bool
  1333. */
  1334. function getDeviceOsType() {
  1335. $type = 'other';
  1336. if (isset($_SERVER['HTTP_USER_AGENT'])) {
  1337. $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
  1338. if (strpos($agent, 'iphone')) {
  1339. $type = 'ios';
  1340. } else if (strpos($agent, 'ipad')) {
  1341. $type = 'ios';
  1342. } else if (strpos($agent, 'android')) {
  1343. $type = 'android';
  1344. }
  1345. }
  1346. return $type;
  1347. }
  1348. /**
  1349. * 获取当前客户端类型 返回android 和 ios
  1350. *
  1351. * @access public
  1352. * @return bool
  1353. */
  1354. public function isMobile() {
  1355. if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) {
  1356. return true;
  1357. } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) {
  1358. return true;
  1359. } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) {
  1360. return true;
  1361. } elseif (isset($_SERVER['HTTP_USER_AGENT'])
  1362. && preg_match(
  1363. '/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i',
  1364. $_SERVER['HTTP_USER_AGENT']
  1365. )) {
  1366. return true;
  1367. } else {
  1368. return false;
  1369. }
  1370. }
  1371. /* Modified by wuyonghong BEGIN 2018/12/19 ISSUES 添加来源判断 */
  1372. /**
  1373. * 检测是否使用IOS设备访问
  1374. *
  1375. * @access public
  1376. * @return bool
  1377. */
  1378. public function isIos() {
  1379. if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/iphone|ipod|ipad/i', $_SERVER['HTTP_USER_AGENT'])) {
  1380. return true;
  1381. } else {
  1382. return false;
  1383. }
  1384. }
  1385. /**
  1386. * 检测是否使用ipad设备访问
  1387. *
  1388. * @access public
  1389. * @return bool
  1390. */
  1391. public function isIpad() {
  1392. if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/ipad/i', $_SERVER['HTTP_USER_AGENT'])) {
  1393. return true;
  1394. } else {
  1395. return false;
  1396. }
  1397. }
  1398. /**
  1399. * 检测是否使用IOS设备访问
  1400. *
  1401. * @access public
  1402. * @return bool
  1403. */
  1404. public function isAndroid() {
  1405. if (isset($_SERVER['HTTP_USER_AGENT']) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'android')) {
  1406. return true;
  1407. } else {
  1408. return false;
  1409. }
  1410. }
  1411. /**
  1412. * 检测是否微信访问
  1413. *
  1414. * @access public
  1415. * @return bool
  1416. */
  1417. public function isWeixin() {
  1418. if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false) {
  1419. return true;
  1420. }
  1421. return false;
  1422. }
  1423. /**
  1424. * 检测是否微信小程序
  1425. *
  1426. * @return bool
  1427. */
  1428. public function isMiniProgram() {
  1429. if ((strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false)
  1430. && (strpos($_SERVER['HTTP_USER_AGENT'], 'miniprogram') !== false
  1431. || strpos($_SERVER['HTTP_USER_AGENT'], 'miniProgram') !== false)) {
  1432. return true;
  1433. }
  1434. return false;
  1435. }
  1436. /**
  1437. * 检测是否safari访问
  1438. *
  1439. * @access public
  1440. * @return bool
  1441. */
  1442. public function isSafari() {
  1443. if (strpos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
  1444. return true;
  1445. }
  1446. return false;
  1447. }
  1448. /* END 2018/12/19 ISSUES: */
  1449. /**
  1450. * 当前URL地址中的scheme参数
  1451. *
  1452. * @access public
  1453. * @return string
  1454. */
  1455. public function scheme() {
  1456. return $this->isSsl() ? 'https' : 'http';
  1457. }
  1458. /**
  1459. * 当前请求URL地址中的query参数
  1460. *
  1461. * @access public
  1462. * @return string
  1463. */
  1464. public function query() {
  1465. return $this->server('QUERY_STRING');
  1466. }
  1467. /**
  1468. * 当前请求的host
  1469. *
  1470. * @access public
  1471. *
  1472. * @param bool $strict true 仅仅获取HOST
  1473. *
  1474. * @return string
  1475. */
  1476. public function host($strict = false) {
  1477. if (isset($_SERVER['HTTP_X_REAL_HOST'])) {
  1478. $host = $_SERVER['HTTP_X_REAL_HOST'];
  1479. } else {
  1480. $host = $this->server('HTTP_HOST');
  1481. }
  1482. return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host;
  1483. }
  1484. /**
  1485. * 当前请求URL地址中的port参数
  1486. *
  1487. * @access public
  1488. * @return integer
  1489. */
  1490. public function port() {
  1491. return $this->server('SERVER_PORT');
  1492. }
  1493. /**
  1494. * 当前请求 SERVER_PROTOCOL
  1495. *
  1496. * @access public
  1497. * @return integer
  1498. */
  1499. public function protocol() {
  1500. return $this->server('SERVER_PROTOCOL');
  1501. }
  1502. /**
  1503. * 当前请求 REMOTE_PORT
  1504. *
  1505. * @access public
  1506. * @return integer
  1507. */
  1508. public function remotePort() {
  1509. return $this->server('REMOTE_PORT');
  1510. }
  1511. /**
  1512. * 当前请求 HTTP_CONTENT_TYPE
  1513. *
  1514. * @access public
  1515. * @return string
  1516. */
  1517. public function contentType() {
  1518. $contentType = $this->server('CONTENT_TYPE');
  1519. if ($contentType) {
  1520. if (strpos($contentType, ';')) {
  1521. list($type) = explode(';', $contentType);
  1522. } else {
  1523. $type = $contentType;
  1524. }
  1525. return trim($type);
  1526. }
  1527. return '';
  1528. }
  1529. /**
  1530. * 获取当前请求的路由信息
  1531. *
  1532. * @access public
  1533. *
  1534. * @param array $route 路由名称
  1535. *
  1536. * @return array
  1537. */
  1538. public function routeInfo($route = []) {
  1539. if (!empty($route)) {
  1540. $this->routeInfo = $route;
  1541. } else {
  1542. return $this->routeInfo;
  1543. }
  1544. }
  1545. /**
  1546. * 设置或者获取当前请求的调度信息
  1547. *
  1548. * @access public
  1549. *
  1550. * @param array $dispatch 调度信息
  1551. *
  1552. * @return array
  1553. */
  1554. public function dispatch($dispatch = null) {
  1555. if (!is_null($dispatch)) {
  1556. $this->dispatch = $dispatch;
  1557. }
  1558. return $this->dispatch;
  1559. }
  1560. /**
  1561. * 设置或者获取当前的模块名
  1562. *
  1563. * @access public
  1564. *
  1565. * @param string $module 模块名
  1566. *
  1567. * @return string|Request
  1568. */
  1569. public function module($module = null) {
  1570. if (!is_null($module)) {
  1571. $this->module = $module;
  1572. return $this;
  1573. } else {
  1574. return $this->module ?: '';
  1575. }
  1576. }
  1577. /**
  1578. * 设置或者获取当前的控制器名
  1579. *
  1580. * @access public
  1581. *
  1582. * @param string $controller 控制器名
  1583. *
  1584. * @return string|Request
  1585. */
  1586. public function controller($controller = null) {
  1587. if (!is_null($controller)) {
  1588. $this->controller = $controller;
  1589. return $this;
  1590. } else {
  1591. return $this->controller ?: '';
  1592. }
  1593. }
  1594. /**
  1595. * 设置或者获取当前的操作名
  1596. *
  1597. * @access public
  1598. *
  1599. * @param string $action 操作名
  1600. *
  1601. * @return string|Request
  1602. */
  1603. public function action($action = null) {
  1604. if (!is_null($action) && !is_bool($action)) {
  1605. $this->action = $action;
  1606. return $this;
  1607. } else {
  1608. $name = $this->action ?: '';
  1609. return true === $action ? $name : strtolower($name);
  1610. }
  1611. }
  1612. /**
  1613. * 设置或者获取当前的语言
  1614. *
  1615. * @access public
  1616. *
  1617. * @param string $lang 语言名
  1618. *
  1619. * @return string|Request
  1620. */
  1621. public function langset($lang = null) {
  1622. if (!is_null($lang)) {
  1623. $this->langset = $lang;
  1624. return $this;
  1625. } else {
  1626. return $this->langset ?: '';
  1627. }
  1628. }
  1629. /**
  1630. * 设置或者获取当前请求的content
  1631. *
  1632. * @access public
  1633. * @return string
  1634. */
  1635. public function getContent() {
  1636. if (is_null($this->content)) {
  1637. $this->content = $this->input;
  1638. }
  1639. return $this->content;
  1640. }
  1641. /**
  1642. * 获取当前请求的php://input
  1643. *
  1644. * @access public
  1645. * @return string
  1646. */
  1647. public function getInput() {
  1648. return $this->input;
  1649. }
  1650. /**
  1651. * 生成请求令牌
  1652. *
  1653. * @access public
  1654. *
  1655. * @param string $name 令牌名称
  1656. * @param mixed $type 令牌生成方法
  1657. *
  1658. * @return string
  1659. */
  1660. public function token($name = '__token__', $type = 'md5') {
  1661. $type = is_callable($type) ? $type : 'md5';
  1662. $token = call_user_func($type, $_SERVER['REQUEST_TIME_FLOAT']);
  1663. if ($this->isAjax()) {
  1664. header($name.': '.$token);
  1665. }
  1666. Session::set($name, $token);
  1667. return $token;
  1668. }
  1669. /**
  1670. * 设置当前地址的请求缓存
  1671. *
  1672. * @access public
  1673. *
  1674. * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id
  1675. * @param mixed $expire 缓存有效期
  1676. * @param array $except 缓存排除
  1677. * @param string $tag 缓存标签
  1678. *
  1679. * @return void
  1680. */
  1681. public function cache($key, $expire = null, $except = [], $tag = null) {
  1682. if (!is_array($except)) {
  1683. $tag = $except;
  1684. $except = [];
  1685. }
  1686. if (false !== $key && $this->isGet() && !$this->isCheckCache) {
  1687. // 标记请求缓存检查
  1688. $this->isCheckCache = true;
  1689. if (false === $expire) {
  1690. // 关闭当前缓存
  1691. return;
  1692. }
  1693. if ($key instanceof \Closure) {
  1694. $key = call_user_func_array($key, [$this]);
  1695. } elseif (true === $key) {
  1696. foreach ($except as $rule) {
  1697. if (0 === stripos($this->url(), $rule)) {
  1698. return;
  1699. }
  1700. }
  1701. // 自动缓存功能
  1702. $key = '__URL__';
  1703. } elseif (strpos($key, '|')) {
  1704. list($key, $fun) = explode('|', $key);
  1705. }
  1706. // 特殊规则替换
  1707. if (false !== strpos($key, '__')) {
  1708. $key = str_replace(
  1709. ['__MODULE__', '__CONTROLLER__', '__ACTION__', '__URL__', ''],
  1710. [$this->module, $this->controller, $this->action, md5($this->url(true))], $key
  1711. );
  1712. }
  1713. if (false !== strpos($key, ':')) {
  1714. $param = $this->param();
  1715. foreach ($param as $item => $val) {
  1716. if (is_string($val) && false !== strpos($key, ':'.$item)) {
  1717. $key = str_replace(':'.$item, $val, $key);
  1718. }
  1719. }
  1720. } elseif (strpos($key, ']')) {
  1721. if ('['.$this->ext().']' == $key) {
  1722. // 缓存某个后缀的请求
  1723. $key = md5($this->url());
  1724. } else {
  1725. return;
  1726. }
  1727. }
  1728. if (isset($fun)) {
  1729. $key = $fun($key);
  1730. }
  1731. if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) {
  1732. // 读取缓存
  1733. $response = Response::create()->code(304);
  1734. throw new \think\exception\HttpResponseException($response);
  1735. } elseif (Cache::has($key)) {
  1736. list($content, $header) = Cache::get($key);
  1737. $response = Response::create($content)->header($header);
  1738. throw new \think\exception\HttpResponseException($response);
  1739. } else {
  1740. $this->cache = [$key, $expire, $tag];
  1741. }
  1742. }
  1743. }
  1744. /**
  1745. * 读取请求缓存设置
  1746. *
  1747. * @access public
  1748. * @return array
  1749. */
  1750. public function getCache() {
  1751. return $this->cache;
  1752. }
  1753. /**
  1754. * 设置当前请求绑定的对象实例
  1755. *
  1756. * @access public
  1757. *
  1758. * @param string|array $name 绑定的对象标识
  1759. * @param mixed $obj 绑定的对象实例
  1760. *
  1761. * @return mixed
  1762. */
  1763. public function bind($name, $obj = null) {
  1764. if (is_array($name)) {
  1765. $this->bind = array_merge($this->bind, $name);
  1766. } else {
  1767. $this->bind[$name] = $obj;
  1768. }
  1769. }
  1770. public function __set($name, $value) {
  1771. $this->bind[$name] = $value;
  1772. }
  1773. public function __get($name) {
  1774. return isset($this->bind[$name]) ? $this->bind[$name] : null;
  1775. }
  1776. public function __isset($name) {
  1777. return isset($this->bind[$name]);
  1778. }
  1779. }