Request.class.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. <?php
  2. namespace KIF\Core;
  3. use KIF\Route;
  4. use KIF\String\String;
  5. use KIF\String\Filter;
  6. use Exception;
  7. use KIF\Exception\ParamsException;
  8. use KIF\Core\Config;
  9. use KIF\Verify;
  10. /**
  11. * 封装了一些方法,用于方便的处理从客户端提交过来的数据
  12. * @author gaoxiaogang@gmail.com
  13. */
  14. class Request {
  15. /**
  16. *
  17. * 存放当前请求的参数
  18. * @var array
  19. */
  20. protected $params;
  21. static protected $instance;
  22. # 不允许被new
  23. private function __construct() {
  24. }
  25. static public function getInstance() {
  26. if (is_null(self::$instance)) {
  27. self::$instance = new self();
  28. }
  29. self::$instance->params = self::params();
  30. return self::$instance;
  31. }
  32. /**
  33. * 获取ip地址
  34. *
  35. * @return string ip地址:如 59.151.9.90
  36. */
  37. public function ip() {
  38. if (isset($_SERVER)) {
  39. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  40. $realip = $_SERVER['HTTP_X_FORWARDED_FOR'];
  41. } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
  42. $realip = $_SERVER['HTTP_CLIENT_IP'];
  43. } else {
  44. $realip = $_SERVER['REMOTE_ADDR'];
  45. }
  46. } else {
  47. if (getenv("HTTP_X_FORWARDED_FOR")) {
  48. $realip = getenv("HTTP_X_FORWARDED_FOR");
  49. } elseif (getenv("HTTP_CLIENT_IP")) {
  50. $realip = getenv("HTTP_CLIENT_IP");
  51. } else {
  52. $realip = getenv("REMOTE_ADDR");
  53. }
  54. }
  55. $realip = preg_replace('#,.*$#', '', $realip);
  56. $realip = preg_replace('#[^\d\.]+#', '', $realip);// 从支付平台发现,有时会获取到这种ip,%20%2058.255.8.39,说明前面有有空格,处理一下
  57. return $realip;
  58. }
  59. /**
  60. * 从 REQUEST_URI 字段获取请求路径
  61. * 如:/article/index.php?id=857&action=show 会被处理成:article/index.php
  62. *
  63. * @param string | null $request_uri
  64. * @return string
  65. */
  66. public function path($request_uri = null) {
  67. if (is_null($request_uri)) {
  68. $request_uri = $_SERVER['REQUEST_URI'];
  69. }
  70. if (($iPos = strpos($request_uri, '?')) !== false) {
  71. $request_uri = substr($request_uri, 0, $iPos);
  72. }
  73. $request_uri = str_replace(' ', '/', trim(str_replace('/', ' ', $request_uri)));
  74. $request_uri = urldecode($request_uri);
  75. return $request_uri;
  76. }
  77. /**
  78. *
  79. * 获取当前请求的url
  80. * @return String 完整的url,如:http://www.kimiss.com/test.php?c=Default
  81. */
  82. public function url() {
  83. $port = $_SERVER['SERVER_PORT'] == '80' ? '' : ":{$_SERVER['SERVER_PORT']}";
  84. $url = "http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
  85. return $url;
  86. }
  87. /**
  88. *
  89. * 获取分类url的模版
  90. * @param string $pageKey 请求里表示分页的参数
  91. * @return string
  92. */
  93. public function pageUrlTpl($pageKey = 'page') {
  94. $routeParams = Route::getInstance()->getsRouteParams();
  95. if ($routeParams) {
  96. $routeParams[$pageKey] = '{page}';
  97. $path = Route::getInstance()->reverse($routeParams);
  98. $url = "http://{$_SERVER['HTTP_HOST']}/" . $path;
  99. return String::jointUrl($url, array_diff_key($_GET, $routeParams));
  100. } else {
  101. $request_params = $_GET;
  102. $request_params[$pageKey] = '{page}';
  103. $url = "http://{$_SERVER['HTTP_HOST']}/" . $this->path();
  104. return String::jointUrl($url, $request_params);
  105. }
  106. }
  107. /**
  108. *
  109. * 获取带请求协议的域名url,如:https://kimiss.com
  110. * @return string
  111. */
  112. static public function schemeDomain() {
  113. $protocol_str = $_SERVER['SERVER_PROTOCOL'];
  114. if (!$protocol_str) {
  115. return '';
  116. }
  117. list($protocol,) = explode('/', $protocol_str);
  118. return strtolower($protocol) . "://{$_SERVER['HTTP_HOST']}";
  119. }
  120. /**
  121. *
  122. * 获取当前请求的顶级域名
  123. * @param string $host
  124. * @return string
  125. */
  126. public function rootDomain($host = null) {
  127. if (is_null($host))
  128. $host = $_SERVER['HTTP_HOST'];
  129. if (empty($host)) {
  130. return '';
  131. }
  132. $host = strtolower($host);
  133. # 是个ip直访的url
  134. if (filter_var($host, FILTER_VALIDATE_IP)) {
  135. return '';
  136. }
  137. # 不带.,可能是绑host的域名
  138. if (strpos($host, '.') === FALSE) {
  139. return $host;
  140. }
  141. $domain_suffs = array(
  142. '.com', '.cn', '.net', '.com.cn', '.net.cn',
  143. '.org', '.me', '.biz', '.name', '.org.cn', '.gov.cn',
  144. '.info', '.so', '.tel', '.mobi', '.asia', '.cc', '.tv', '.co',
  145. );
  146. foreach ($domain_suffs as $suff) {
  147. $tmp_stuff_pos = strrpos($host, $suff);
  148. if ($tmp_stuff_pos === false) {
  149. continue;
  150. }
  151. $tmp_rootdomain_pos = strrpos($host, '.', 0-strlen(substr($host, $tmp_stuff_pos))-1);
  152. if ($tmp_rootdomain_pos === false) {
  153. return $host;
  154. }
  155. return substr($host, $tmp_rootdomain_pos+1);
  156. }
  157. }
  158. /**
  159. * 获取请求url中的查询字符串
  160. *
  161. * @return string
  162. */
  163. static public function queryString() {
  164. return $_SERVER['QUERY_STRING'];
  165. }
  166. /**
  167. *
  168. * 获取请求的referer
  169. * @return string
  170. */
  171. static public function referer() {
  172. return $_SERVER['HTTP_REFERER'];
  173. }
  174. /**
  175. * 是否POST请求
  176. *
  177. * @return boolean
  178. */
  179. static public function isPost() {
  180. return strtoupper($_SERVER['REQUEST_METHOD']) == 'POST';
  181. }
  182. /**
  183. * 是否GET请求
  184. *
  185. * @return boolean
  186. */
  187. static public function isGet() {
  188. return strtoupper($_SERVER['REQUEST_METHOD']) == 'GET';
  189. }
  190. /**
  191. * 该请求是否由 蜘蛛 发出
  192. *
  193. * @return boolean
  194. */
  195. public function isSpider() {
  196. if (self::isCLI()) {
  197. return false;
  198. }
  199. if (!isset($_SERVER['HTTP_USER_AGENT'])) {
  200. return false;
  201. }
  202. $bots = array(
  203. 'Googebot', 'Baiduspider', 'Yahoo! Slurp', 'Sosospider', 'Sogou', 'Sogou-Test-Spider',
  204. 'Sogou head spider', 'YoudaoBot', 'qihoobot', 'iaskspider', 'LeapTag', 'MSIECrawler'
  205. );
  206. foreach ($bots as $bot) {
  207. if (strpos($_SERVER['HTTP_USER_AGENT'], $bot) !== false) {
  208. return true;
  209. }
  210. }
  211. if (stristr($_SERVER['HTTP_USER_AGENT'], 'Windows') !== false) {
  212. return false;
  213. }
  214. $bots = array(
  215. 'spider', 'bit', 'crawler', 'slurp', 'subscriber', 'http',
  216. 'rssreader', 'blogline', 'greatnews', 'feed', 'alexa', 'php'
  217. );
  218. foreach ($bots as $bot) {
  219. if (stristr($_SERVER['HTTP_USER_AGENT'], $bot) !== false) {
  220. return true;
  221. }
  222. }
  223. return false;
  224. }
  225. /**
  226. * 该请求是否从相同的主机过来,即来源页是否与当前页处于相同域下
  227. *
  228. * @return boolean
  229. */
  230. public function isFromSameHost() {
  231. if (!isset($_SERVER['HTTP_REFERER'])) {
  232. return true;
  233. }
  234. $url_parts = parse_url($_SERVER['HTTP_REFERER']);
  235. $host = $url_parts['host'];
  236. if ($_SERVER['HTTP_HOST'] == $host) {
  237. return true;
  238. }
  239. return false;
  240. }
  241. /**
  242. * 从请求的 $_GET 变量里获取 变量的整数值,如果不存在该变量或不为整数,则返回 $default 值
  243. * @param string $varName 变量名
  244. * @param int $default 默认值
  245. * @return int
  246. */
  247. public function varGetInt($varName, $default = 0) {
  248. if (!isset($_GET[$varName])) {
  249. return $default;
  250. }
  251. if (!Verify::unsignedInt($_GET[$varName])) {
  252. return $default;
  253. }
  254. return $_GET[$varName];
  255. }
  256. /**
  257. * 从请求的 $_POST 变量里获取 变量的整数值,如果不存在该变量或不为整数,则返回 $default 值
  258. * @param string $varName 变量名
  259. * @param int $default 默认值
  260. * @return int
  261. */
  262. public function varPostInt($varName, $default = 0) {
  263. if (!isset($_POST[$varName])) {
  264. return $default;
  265. }
  266. if (!Verify::unsignedInt($_POST[$varName])) {
  267. return $default;
  268. }
  269. return $_POST[$varName];
  270. }
  271. /**
  272. * 从请求的 $_POST 变量里获取 变量的整数值,如果不存在该变量或不为整数,则返回 $default 值
  273. * @param string $varName 变量名
  274. * @param int $default 默认值
  275. * @return int
  276. */
  277. public function varRequestInt($varName, $default = 0) {
  278. if (!isset($_REQUEST[$varName])) {
  279. return $default;
  280. }
  281. if (!Verify::unsignedInt($_REQUEST[$varName])) {
  282. return $default;
  283. }
  284. return $_REQUEST[$varName];
  285. }
  286. /**
  287. * 获取请求的参数集。
  288. * 支持http访问的参数 以及 命令行下访问的参数
  289. * demo1:php test.php -p3 -t=abc --opt=valopt --opt2 valopt2
  290. * demo2 http://test.kimiss.com/index.php?c=xxx&a=ddd
  291. * @return array
  292. */
  293. public function params() {
  294. if (self::isCLI()) {
  295. return self::cliParams();
  296. } else {
  297. return $_REQUEST;
  298. }
  299. }
  300. /**
  301. *
  302. * 获取命令行下传递进来的参数
  303. * 只支持以 - 或 -- 开头的参数
  304. * demo:php test.php -p3 -t=abc --opt=valopt --opt2 valopt2
  305. * @return array
  306. */
  307. private function cliParams() {
  308. $result = array();
  309. $params = $GLOBALS['argv'];
  310. array_shift($params);
  311. reset($params);
  312. do {
  313. $tmpEachResult = each($params);
  314. if (!$tmpEachResult) {
  315. break;
  316. }
  317. list($tmp, $p) = $tmpEachResult;
  318. if ($p{0} == '-') {
  319. $pname = substr($p, 1);
  320. $value = false;
  321. if ($pname{0} == '-') {// 长选项 (--<param>)
  322. $pname = substr($pname, 1);
  323. if (strpos($p, '=') !== false) {
  324. // value specified inline (--<param>=<value>)
  325. list($pname, $value) = explode('=', substr($p, 2), 2);
  326. }
  327. } else {// 短选项
  328. if (strpos($p, '=') !== false) {
  329. // value specified inline (-<param>=<value>)
  330. list($pname, $value) = explode('=', substr($p, 1), 2);
  331. } else if (strlen($p) > 1) {
  332. $pname = substr($p, 1, 1);
  333. $value = substr($p, 2);
  334. }
  335. }
  336. # 如果上面没有取到值,并且下一个不是以-开头的,则下一个值为当前参数的值
  337. $nextparm = current($params);
  338. if ($value === false
  339. && $nextparm !== false
  340. && $nextparm{0} != '-'
  341. ) {
  342. list($tmp, $value) = each($params);
  343. }
  344. $result[$pname] = (string) $value;// 将 false转为空串,以便与http访问时对参数的处理一致
  345. } else {
  346. # 不是以-指定开始的参数,一律丢弃
  347. //$result[] = $p;
  348. }
  349. } while (true);
  350. return $result;
  351. }
  352. /**
  353. *
  354. * 获取 $_GET 里指定key $name 的值,同时可以指定 $filters 过滤方法处理值
  355. *
  356. * 用法:
  357. * 1、对值不做任何处理:Request::getInstance()->get('content', null);
  358. * 2、对值做html转义处理:Request::getInstance()->get('name');
  359. *
  360. * @param string $name
  361. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  362. * $filters支持以下格式:
  363. * 1) 标量类型,如:
  364. * Filter::HTMLSPECIALCHARS;
  365. * 2) 多个filter,如:
  366. * array(
  367. * Filter::HTMLSPECIALCHARS,
  368. * Filter::STRIP_TAGS,
  369. * );
  370. * 3) 多个filter,并且某些filter另外指定参数,如:
  371. * array(
  372. * array(
  373. * Filter::HTMLSPECIALCHARS => ENT_QUOTES,
  374. * ),
  375. * array(
  376. * Filter::STRIP_TAGS => "<a>",
  377. * ),
  378. * Filter::STRIP_SELECTED_TAGS,
  379. * );
  380. *
  381. * @throws ParamsException "无效的过滤方法filter"
  382. * @return string
  383. */
  384. public function get($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  385. if (!isset($_GET[$name])) {
  386. return false;
  387. }
  388. $val = $_GET[$name];
  389. if (is_null($filters)) {
  390. return $val;
  391. }
  392. if (!is_array($filters)) {
  393. $filters = array($filters);
  394. }
  395. return self::filter($val, $filters);
  396. }
  397. /**
  398. *
  399. * get的别名方法
  400. * @param string $name
  401. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  402. * @throws ParamsException "无效的过滤方法filter"
  403. * @return string
  404. */
  405. public function g($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  406. return self::get($name, $filters);
  407. }
  408. /**
  409. *
  410. * 获取 $_POST 里指定key $name 的值,同时可以指定 $filters 过滤方法处理值
  411. *
  412. * 用法:
  413. * 1、对值不做任何处理:Request::getInstance()->post('content', null);
  414. * 2、对值做html转义处理:Request::getInstance()->post('name');
  415. *
  416. * @param string $name
  417. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  418. * @throws ParamsException "无效的过滤方法filter"
  419. * @return string
  420. */
  421. public function post($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  422. if (!isset($_POST[$name])) {
  423. return false;
  424. }
  425. $val = $_POST[$name];
  426. if (is_null($filters)) {
  427. return $val;
  428. }
  429. if (!is_array($filters)) {
  430. $filters = array($filters);
  431. }
  432. return self::filter($val, $filters);
  433. }
  434. /**
  435. *
  436. * post的别名方法
  437. * @param string $name
  438. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  439. * @throws ParamsException "无效的过滤方法filter"
  440. * @return string
  441. */
  442. public function p($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  443. return self::post($name, $filters);
  444. }
  445. /**
  446. *
  447. * 获取 $_REQUEST 里指定key $name 的值,同时可以指定 $filters 过滤方法处理值
  448. * !! 因为与类同名的方法会被认为是构造函数,所以这个方法名加个小字符 !!
  449. *
  450. * 用法:
  451. * 1、对值不做任何处理:Request::getInstance()->requestV('content', null);
  452. * 2、对值做html转义处理:Request::getInstance()->requestV('name');
  453. *
  454. * @param string $name
  455. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  456. * @throws ParamsException "无效的过滤方法filter"
  457. * @return string
  458. */
  459. public function requestV($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  460. if (!isset($_REQUEST[$name])) {
  461. return false;
  462. }
  463. $val = $_REQUEST[$name];
  464. if (is_null($filters)) {
  465. return $val;
  466. }
  467. if (!is_array($filters)) {
  468. $filters = array($filters);
  469. }
  470. return self::filter($val, $filters);
  471. }
  472. /**
  473. *
  474. * requestV的别名方法
  475. * @param string $name
  476. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  477. * @throws ParamsException "无效的过滤方法filter"
  478. * @return string
  479. */
  480. public function r($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  481. return self::requestV($name, $filters);
  482. }
  483. /**
  484. *
  485. * 获取 $_COOKIE 里指定key $name 的值,同时可以指定 $filters 过滤方法处理值
  486. *
  487. * 用法:
  488. * 1、对值不做任何处理:Request::getInstance()->cookie('content', null);
  489. * 2、对值做html转义处理:Request::getInstance()->cookie('name');
  490. *
  491. * @param string $name
  492. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  493. * @throws ParamsException "无效的过滤方法filter"
  494. * @return string | false
  495. */
  496. public function cookie($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  497. if (!isset($_COOKIE[$name])) {
  498. return false;
  499. }
  500. $val = $_COOKIE[$name];
  501. if (is_null($filters)) {
  502. return $val;
  503. }
  504. if (!is_array($filters)) {
  505. $filters = array($filters);
  506. }
  507. return self::filter($val, $filters);
  508. }
  509. /**
  510. *
  511. * cookie的别名方法
  512. * @param string $name
  513. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  514. * @throws ParamsException "无效的过滤方法filter"
  515. * @return string | false
  516. */
  517. public function c($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  518. return self::cookie($name, $filters);
  519. }
  520. /**
  521. *
  522. * 获取当前请求参数里指定key $name 的值,同时可以指定 $filters 过滤方法处理值
  523. *
  524. * 用法:
  525. * 1、对值不做任何处理:Request::getInstance()->param('content', null);
  526. * 2、对值做html转义处理:Request::getInstance()->param('name');
  527. *
  528. * @param string $name
  529. * @param mixed $filters 默认使用html转义过滤。当值为null里,对值不做任何过滤。
  530. * @throws ParamsException "无效的过滤方法filter"
  531. * @return string | false
  532. */
  533. public function param($name, $filters = array(Filter::HTMLSPECIALCHARS, Filter::TRIM)) {
  534. if (!isset($this->params[$name])) {
  535. return false;
  536. }
  537. $val = $this->params[$name];
  538. if (is_null($filters)) {
  539. return $val;
  540. }
  541. if (!is_array($filters)) {
  542. $filters = array($filters);
  543. }
  544. return self::filter($val, $filters);
  545. }
  546. /**
  547. *
  548. * 使用用户指定的 过滤方法,过滤值 $val
  549. * @param string $val
  550. * @param array $filters 过滤方法相关信息
  551. * @throws ParamsException "无效的过滤方法filter"
  552. * @return string
  553. */
  554. private function filter($val, array $filters) {
  555. foreach ($filters as $filter) {
  556. $params = array($val);
  557. if (is_array($filter)) {
  558. list($filter_name, $filter_options) = each($filter);
  559. } else {
  560. $filter_name = $filter;
  561. $filter_options = null;
  562. }
  563. if (!Filter::isValid($filter_name)) {
  564. throw new ParamsException("无效的过滤方法filter");
  565. }
  566. $val = call_user_func(array('KIF\String\Filter', $filter_name), $val, $filter_options);
  567. }
  568. return $val;
  569. }
  570. /**
  571. * 是否处于命令行下
  572. * @return Boolean
  573. */
  574. static public function isCLI() {
  575. if (php_sapi_name() == "cli"//PHP 4 >= 4.0.1, PHP 5 support php_sapi_name function
  576. || empty($_SERVER['PHP_SELF'])//If PHP is running as a command-line processor this variable contains the script name since PHP 4.3.0. Previously it was not available.
  577. ) {
  578. return true;
  579. } else {
  580. return false;
  581. }
  582. }
  583. /**
  584. * 是否类unix系统
  585. * @return Boolean
  586. */
  587. static public function isUnixLike() {
  588. $os = strtolower(PHP_OS);
  589. if (in_array($os, array('linux', 'freebsd', 'unix', 'netbsd'))) {
  590. return true;
  591. }
  592. return false;
  593. }
  594. /**
  595. *
  596. * 分发请求,调用Controller以及对应的action
  597. */
  598. public function dispatch() {
  599. $params = $this->params;
  600. $controllerName = self::getController($params);
  601. if (!class_exists($controllerName)) {
  602. throw new Exception("controller: {$controllerName} not exists!");
  603. }
  604. $action = self::getAction($params);
  605. $controller = new $controllerName();
  606. $controller->setAction($action);
  607. $controller->run();
  608. if (method_exists($controller, 'display')) {
  609. $controller->display();
  610. }
  611. }
  612. public function getController() {
  613. $c = self::param('c');
  614. $c = trim($c, '_');
  615. $arr_class_path = array_map(function ($tmpV) {
  616. return ucfirst($tmpV);
  617. }, explode('_', $c));
  618. $c = join('\\', $arr_class_path);
  619. $NS = Config::getInstance()->get('Namespace');
  620. $controller = "{$NS}\Controller\\{$c}";
  621. return $controller;
  622. }
  623. public function getAction(array $params = null) {
  624. $action = self::param('a');
  625. return $action;
  626. }
  627. }