AbstractRequest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. <?php
  2. /**
  3. *
  4. * Cube Framework $Id$ yBFfD3HYGqz60Alvkn4pAoBfcZDVbd5mpjgAc+NCHSc=
  5. *
  6. * @link http://codecu.be/framework
  7. * @copyright Copyright (c) 2017 CodeCube SRL
  8. * @license http://codecu.be/framework/license Commercial License
  9. *
  10. * @version 1.9 [rev.1.9.01]
  11. */
  12. /**
  13. * abstract request class
  14. * all request classes should extend this class or at a minimum implement the request interface
  15. */
  16. namespace Cube\Controller\Request;
  17. abstract class AbstractRequest implements RequestInterface
  18. {
  19. const URI_DELIMITER = '/';
  20. const METHOD_POST = 'POST';
  21. const METHOD_GET = 'GET';
  22. /**
  23. *
  24. * formatted request uri
  25. *
  26. * @var string
  27. */
  28. protected $_requestUri;
  29. /**
  30. *
  31. * the base URL of the application (from the request uri)
  32. *
  33. * @var string
  34. */
  35. protected $_baseUrl = null;
  36. /**
  37. *
  38. * base path of the application (the location on the server)
  39. *
  40. * @var string
  41. */
  42. protected $_basePath;
  43. /**
  44. *
  45. * the module requested (optional)
  46. *
  47. * @var string
  48. */
  49. protected $_module;
  50. /**
  51. *
  52. * the controller requested
  53. *
  54. * @var string
  55. */
  56. protected $_controller;
  57. /**
  58. *
  59. * the action requested
  60. *
  61. * @var string
  62. */
  63. protected $_action;
  64. /**
  65. *
  66. * query string in key => value pairs
  67. *
  68. * @var array
  69. */
  70. protected $_params = array();
  71. /**
  72. *
  73. * request dispatched flag
  74. *
  75. * @var bool
  76. */
  77. protected $_dispatched;
  78. /**
  79. *
  80. * class constructor
  81. *
  82. * the constructor will initialize the base path and the formatted request uri
  83. */
  84. public function __construct()
  85. {
  86. $this->setBasePath()
  87. ->setRequestUri();
  88. $this->setRequestParams();
  89. }
  90. /**
  91. *
  92. * get the formatted request uri, set if its not already set
  93. *
  94. * @return string
  95. */
  96. public function getRequestUri()
  97. {
  98. if (empty($this->_requestUri)) {
  99. $this->setRequestUri();
  100. }
  101. return $this->_requestUri;
  102. }
  103. /**
  104. *
  105. * set the request uri and format it so that it can be used by the router
  106. * (remove the base url of the application from the uri and remove any GET variables as well)
  107. *
  108. * @param string $requestUri
  109. *
  110. * @return $this
  111. */
  112. public function setRequestUri($requestUri = null)
  113. {
  114. if ($requestUri === null) {
  115. // we can retrieve more ways if needed
  116. // we replace the first occurrence of the base url (used if installing the app in a sub-domain)
  117. if (array_key_exists('REQUEST_URI', $_SERVER)) {
  118. $uri = explode('?', $_SERVER['REQUEST_URI']);
  119. $baseUrl = $this->getBaseUrl();
  120. if ($baseUrl) {
  121. $requestUri = str_ireplace('//', '/',
  122. @preg_replace($this->getBaseUrl() . self::URI_DELIMITER, '', $uri[0], 1));
  123. }
  124. else {
  125. $requestUri = $uri[0];
  126. }
  127. }
  128. }
  129. $this->_requestUri = $requestUri;
  130. return $this;
  131. }
  132. /**
  133. *
  134. * get the base url of the application
  135. *
  136. * @param bool $forceDelimiter
  137. *
  138. * @return string
  139. */
  140. public function getBaseUrl($forceDelimiter = false)
  141. {
  142. if ($this->_baseUrl === null) {
  143. if (array_key_exists('SCRIPT_NAME', $_SERVER)) {
  144. $baseUrl = rtrim(
  145. dirname($_SERVER['SCRIPT_NAME']), self::URI_DELIMITER);
  146. $this->setBaseUrl($baseUrl);
  147. }
  148. }
  149. if ($forceDelimiter === true && empty($this->_baseUrl)) {
  150. return self::URI_DELIMITER;
  151. }
  152. return $this->_baseUrl;
  153. }
  154. /**
  155. *
  156. * set the base url of the application
  157. *
  158. * @param string $baseUrl
  159. *
  160. * @return $this
  161. */
  162. public function setBaseUrl($baseUrl)
  163. {
  164. $this->_baseUrl = $this->filterInput($baseUrl);
  165. return $this;
  166. }
  167. /**
  168. *
  169. * set the base path of the application
  170. * the base path is the actual location of the application on the server
  171. *
  172. * @return string
  173. */
  174. public function getBasePath()
  175. {
  176. if (empty($this->_basePath)) {
  177. $this->setBasePath();
  178. }
  179. return $this->_basePath;
  180. }
  181. /**
  182. *
  183. * set the base path of the application
  184. *
  185. * @param string $basePath
  186. *
  187. * @return $this
  188. */
  189. public function setBasePath($basePath = null)
  190. {
  191. if ($basePath === null) {
  192. if (array_key_exists('SCRIPT_FILENAME', $_SERVER)) {
  193. $basePath = dirname($_SERVER['SCRIPT_FILENAME']);
  194. }
  195. }
  196. $this->_basePath = $basePath;
  197. return $this;
  198. }
  199. /**
  200. *
  201. * get one or all variables from the $_GET super-global
  202. * the order will be: first routed variables, then variables in the query string
  203. *
  204. * @param string $name
  205. * @param mixed $default Default value to use if key not found
  206. *
  207. * @return mixed Returns null if key does not exist
  208. */
  209. public function getQuery($name = null, $default = null)
  210. {
  211. if ($name === null) {
  212. $get = $this->filterInput($_GET);
  213. $parts = array();
  214. if (isset($_SERVER['QUERY_STRING'])) {
  215. $parts = array_filter(explode('&', $_SERVER['QUERY_STRING']), 'strlen');
  216. }
  217. $vars = array();
  218. foreach ((array)$parts as $part) {
  219. $data = explode('=', $part);
  220. $key = (isset($data[0])) ? urlencode($data[0]) : '';
  221. $val = (isset($data[1])) ? urlencode($data[1]) : '';
  222. $vars[(string)$this->filterInput($key)] = $this->filterInput($val);
  223. }
  224. $get = array_diff_key($get, $vars);
  225. return array_merge($get, $vars);
  226. }
  227. if (isset($_GET[$name])) {
  228. return $this->filterInput($_GET[$name]);
  229. }
  230. return $default;
  231. }
  232. /**
  233. *
  234. * add variables that have been passed through the url address
  235. *
  236. * @param array $data
  237. * @param string|null $value
  238. *
  239. * @return $this
  240. */
  241. public function setQuery($data, $value = null)
  242. {
  243. if (($value === null) && is_array($data)) {
  244. foreach ($data as $key => $value) {
  245. $this->setQuery($key, $value);
  246. }
  247. return $this;
  248. }
  249. $_GET[(string)$data] = $value;
  250. return $this;
  251. }
  252. /**
  253. *
  254. * set request params
  255. *
  256. * @return $this
  257. */
  258. public function setRequestParams()
  259. {
  260. if (count($_POST) > 0) {
  261. $this->setParams($this->filterInput($_POST));
  262. }
  263. if (count($_GET) > 0) {
  264. $this->setParams($this->filterInput($_GET));
  265. }
  266. return $this;
  267. }
  268. /**
  269. *
  270. * get the request params
  271. *
  272. * @param array $skip array of parameters to skip
  273. *
  274. * @return array
  275. */
  276. public function getParams(array $skip = null)
  277. {
  278. if ($skip !== null) {
  279. $params = $this->_params;
  280. foreach ($skip as $key) {
  281. unset($params[$key]);
  282. }
  283. return $params;
  284. }
  285. return $this->_params;
  286. }
  287. /**
  288. *
  289. * set multiple request params
  290. *
  291. * @param array $params
  292. *
  293. * @return $this
  294. */
  295. public function setParams(array $params = null)
  296. {
  297. if (empty($this->_params)) {
  298. $params = array_merge($_GET, $_POST, (array)$params);
  299. }
  300. foreach ((array)$params as $key => $value) {
  301. $this->setParam($key, $value);
  302. }
  303. return $this;
  304. }
  305. /**
  306. *
  307. * clear request params
  308. *
  309. * @return $this
  310. */
  311. public function clearParams()
  312. {
  313. $this->_params = array();
  314. return $this;
  315. }
  316. /**
  317. *
  318. * clear a single request variable
  319. *
  320. * @param string $key the key of the variable
  321. *
  322. * @return $this
  323. */
  324. public function clearParam($key)
  325. {
  326. if (isset($this->_params[$key])) {
  327. unset($this->_params[$key]);
  328. }
  329. return $this;
  330. }
  331. /**
  332. *
  333. * returns the value of a variable from a request
  334. *
  335. * @param string $key the name of the variable
  336. * @param mixed $default a default value in case the variable is not set
  337. *
  338. * @return string return the formatted value of the variable
  339. */
  340. public function getParam($key, $default = null)
  341. {
  342. if (isset($this->_params[$key])) {
  343. return $this->filterInput($this->_params[$key]);
  344. }
  345. return $default;
  346. }
  347. /**
  348. *
  349. * set the value of a request param
  350. *
  351. * @param string $key
  352. * @param string $value
  353. *
  354. * @return $this
  355. */
  356. public function setParam($key, $value)
  357. {
  358. if (($value === null) && isset($this->_params[$key])) {
  359. unset($this->_params[$key]);
  360. }
  361. else if ($value !== null && $key === preg_replace("/[^a-zA-Z0-9_-]/", '', $key)) {
  362. $this->_params[$key] = $this->filterInput($value);
  363. }
  364. return $this;
  365. }
  366. /**
  367. *
  368. * check if a post request has been made
  369. *
  370. * @return bool
  371. */
  372. public function isPost()
  373. {
  374. if (stristr($_SERVER['REQUEST_METHOD'], self::METHOD_POST)) {
  375. return true;
  376. }
  377. return false;
  378. }
  379. /**
  380. *
  381. * check if a get request has been made
  382. *
  383. * @return bool
  384. */
  385. public function isGet()
  386. {
  387. if (stristr($_SERVER['REQUEST_METHOD'], self::METHOD_GET)) {
  388. return true;
  389. }
  390. return false;
  391. }
  392. /**
  393. *
  394. * get the module from the routed request
  395. *
  396. * @return string
  397. */
  398. public function getModule()
  399. {
  400. return $this->_module;
  401. }
  402. /**
  403. *
  404. * clear request method
  405. *
  406. * @return $this
  407. */
  408. public function clearRequestMethod()
  409. {
  410. $_SERVER['REQUEST_METHOD'] = '';
  411. return $this;
  412. }
  413. /**
  414. *
  415. * set the name of the module for the routed request (all module names start with a capital letter)
  416. *
  417. * @param string $module
  418. *
  419. * @return $this
  420. */
  421. public function setModule($module)
  422. {
  423. $this->_module = $this->normalize($module);
  424. return $this;
  425. }
  426. /**
  427. *
  428. * get the name of the routed action controller
  429. *
  430. * @return string
  431. */
  432. public function getController()
  433. {
  434. return $this->_controller;
  435. }
  436. /**
  437. *
  438. * set the name of the action controller for the routed request (all module names start with a capital letter)
  439. *
  440. * @param string $controller
  441. *
  442. * @return $this
  443. */
  444. public function setController($controller)
  445. {
  446. $this->_controller = $this->normalize($controller);
  447. return $this;
  448. }
  449. /**
  450. *
  451. * get the name of the routed controller action
  452. *
  453. * @return string
  454. */
  455. public function getAction()
  456. {
  457. return $this->_action;
  458. }
  459. /**
  460. *
  461. * set the name of the action from the routed request, in the following formats:
  462. * hello-world-today => HelloWorldToday
  463. * hello_world-today => HelloworldToday
  464. * heLlO => Hello
  465. * helloWorld => Helloworld
  466. *
  467. * @param string $action
  468. *
  469. * @return $this
  470. */
  471. public function setAction($action)
  472. {
  473. $this->_action = $this->normalize($action);
  474. return $this;
  475. }
  476. /**
  477. *
  478. * get dispatched status
  479. *
  480. * @return bool
  481. */
  482. public function isDispatched()
  483. {
  484. return (bool)$this->_dispatched;
  485. }
  486. /**
  487. *
  488. * set dispatched status
  489. *
  490. * @param bool $dispatched
  491. */
  492. public function setDispatched($dispatched)
  493. {
  494. $this->_dispatched = (bool)$dispatched;
  495. }
  496. /**
  497. *
  498. * remove special characters method, recursive in case of arrays
  499. * it cleans both keys and values in a request
  500. *
  501. * @param string|array $input
  502. *
  503. * @return mixed
  504. */
  505. public function filterInput($input)
  506. {
  507. $output = null;
  508. if (is_array($input)) {
  509. foreach ($input as $key => $value) {
  510. $key = preg_replace("/[^a-zA-Z0-9_-]/", '', $key);
  511. $output[$key] = $this->filterInput($value);
  512. }
  513. if (!is_array($output)) {
  514. $output = (array)$output;
  515. }
  516. }
  517. else {
  518. $output = trim(str_ireplace(
  519. array("'", '"', '<', '>'), array('&#039;', '&quot;', '&lt;', '&gt;'),
  520. stripslashes(rawurldecode($input))));
  521. }
  522. return $output;
  523. }
  524. /**
  525. *
  526. * match an uri string to the request uri variable
  527. *
  528. * @param string $uri
  529. * @param bool $equal checks for equal strings only
  530. *
  531. * @return bool
  532. */
  533. public function matchRequestUri($uri, $equal = true)
  534. {
  535. $uri = trim($uri, self::URI_DELIMITER);
  536. $requestUri = trim($this->getRequestUri(), self::URI_DELIMITER);
  537. if ($equal === true && strcmp($uri, $requestUri) === 0) {
  538. return true;
  539. }
  540. else if ($equal !== true && stristr($requestUri, $uri)) {
  541. return true;
  542. }
  543. return false;
  544. }
  545. /**
  546. *
  547. * normalize url parts for modules/controllers/actions in order for them to be parsable by the router
  548. *
  549. * - will first convert the input to lowercase
  550. * - will remove any non alpha-numeric and '-' characters from the value
  551. * - will convert '-' to camel cased and will capitalize the first letter of the string
  552. *
  553. * Examples:
  554. * hello-world-today => HelloWorldToday
  555. * hello_world-today => HelloworldToday
  556. * heLlO => Hello
  557. * helloWorld => Helloworld
  558. *
  559. * if reverse is set to true, we convert a router router parsable string into a url string
  560. *
  561. * @param string $input
  562. * @param bool $reverse
  563. *
  564. * @return string
  565. */
  566. public function normalize($input, $reverse = false)
  567. {
  568. if ($reverse) {
  569. return strtolower(
  570. preg_replace("/([a-z])([A-Z])/", '$1-$2', $input));
  571. }
  572. else {
  573. $input = str_replace('-', ' ', strtolower(
  574. preg_replace("/[^a-zA-Z0-9\_\-]/", '', $input)));
  575. return str_replace(' ', '', ucwords($input));
  576. }
  577. }
  578. }