CakeRequest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. <?php
  2. /**
  3. * CakeRequest
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @since CakePHP(tm) v 2.0
  16. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  17. */
  18. App::uses('Set', 'Utility');
  19. /**
  20. * A class that helps wrap Request information and particulars about a single request.
  21. * Provides methods commonly used to introspect on the request headers and request body.
  22. *
  23. * Has both an Array and Object interface. You can access framework parameters using indexes:
  24. *
  25. * `$request['controller']` or `$request->controller`.
  26. *
  27. * @package cake.libs
  28. */
  29. class CakeRequest implements ArrayAccess {
  30. /**
  31. * Array of parameters parsed from the url.
  32. *
  33. * @var array
  34. */
  35. public $params = array();
  36. /**
  37. * Array of POST data. Will contain form data as well as uploaded files.
  38. * Will only contain data from inputs that start with 'data'. So
  39. * `<input name="some_input" />` will not end up in data. However,
  40. * `<input name="data[something]" />`
  41. *
  42. * @var array
  43. */
  44. public $data = array();
  45. /**
  46. * Array of querystring arguments
  47. *
  48. * @var array
  49. */
  50. public $query = array();
  51. /**
  52. * The url string used for the request.
  53. *
  54. * @var string
  55. */
  56. public $url;
  57. /**
  58. * Base url path.
  59. *
  60. * @var string
  61. */
  62. public $base = false;
  63. /**
  64. * webroot path segment for the request.
  65. *
  66. * @var string
  67. */
  68. public $webroot = '/';
  69. /**
  70. * The full address to the current request
  71. *
  72. * @var string
  73. */
  74. public $here = null;
  75. /**
  76. * The built in detectors used with `is()` can be modified with `addDetector()`.
  77. *
  78. * There are several ways to specify a detector, see CakeRequest::addDetector() for the
  79. * various formats and ways to define detectors.
  80. *
  81. * @var array
  82. */
  83. protected $_detectors = array(
  84. 'get' => array('env' => 'REQUEST_METHOD', 'value' => 'GET'),
  85. 'post' => array('env' => 'REQUEST_METHOD', 'value' => 'POST'),
  86. 'put' => array('env' => 'REQUEST_METHOD', 'value' => 'PUT'),
  87. 'delete' => array('env' => 'REQUEST_METHOD', 'value' => 'DELETE'),
  88. 'head' => array('env' => 'REQUEST_METHOD', 'value' => 'HEAD'),
  89. 'options' => array('env' => 'REQUEST_METHOD', 'value' => 'OPTIONS'),
  90. 'ssl' => array('env' => 'HTTPS', 'value' => 1),
  91. 'ajax' => array('env' => 'HTTP_X_REQUESTED_WITH', 'value' => 'XMLHttpRequest'),
  92. 'flash' => array('env' => 'HTTP_USER_AGENT', 'pattern' => '/^(Shockwave|Adobe) Flash/'),
  93. 'mobile' => array('env' => 'HTTP_USER_AGENT', 'options' => array(
  94. 'Android', 'AvantGo', 'BlackBerry', 'DoCoMo', 'Fennec', 'iPod', 'iPhone',
  95. 'J2ME', 'MIDP', 'NetFront', 'Nokia', 'Opera Mini', 'PalmOS', 'PalmSource',
  96. 'portalmmm', 'Plucker', 'ReqwirelessWeb', 'SonyEricsson', 'Symbian', 'UP\\.Browser',
  97. 'webOS', 'Windows CE', 'Xiino'
  98. ))
  99. );
  100. /**
  101. * Constructor
  102. *
  103. * @param string $url Trimmed url string to use. Should not contain the application base path.
  104. * @param boolean $parseEnvironment Set to false to not auto parse the environment. ie. GET, POST and FILES.
  105. * @return void
  106. */
  107. public function __construct($url = null, $parseEnvironment = true) {
  108. $this->_base();
  109. if (empty($url)) {
  110. $url = $this->_url();
  111. }
  112. if ($url[0] == '/') {
  113. $url = substr($url, 1);
  114. }
  115. $this->url = $url;
  116. if ($parseEnvironment) {
  117. $this->_processPost();
  118. $this->_processGet();
  119. $this->_processFiles();
  120. }
  121. $this->here = $this->base . '/' . $this->url;
  122. }
  123. /**
  124. * process the post data and set what is there into the object.
  125. *
  126. * @return void
  127. */
  128. protected function _processPost() {
  129. $this->params['form'] = $_POST;
  130. if (ini_get('magic_quotes_gpc') === '1') {
  131. $this->params['form'] = stripslashes_deep($this->params['form']);
  132. }
  133. if (env('HTTP_X_HTTP_METHOD_OVERRIDE')) {
  134. $this->params['form']['_method'] = env('HTTP_X_HTTP_METHOD_OVERRIDE');
  135. }
  136. if (isset($this->params['form']['_method'])) {
  137. if (!empty($_SERVER)) {
  138. $_SERVER['REQUEST_METHOD'] = $this->params['form']['_method'];
  139. } else {
  140. $_ENV['REQUEST_METHOD'] = $this->params['form']['_method'];
  141. }
  142. unset($this->params['form']['_method']);
  143. }
  144. if (isset($this->params['form']['data'])) {
  145. $this->data = $this->params['form']['data'];
  146. unset($this->params['form']['data']);
  147. }
  148. }
  149. /**
  150. * Process the GET parameters and move things into the object.
  151. *
  152. * @return void
  153. */
  154. protected function _processGet() {
  155. if (ini_get('magic_quotes_gpc') === '1') {
  156. $query = stripslashes_deep($_GET);
  157. } else {
  158. $query = $_GET;
  159. }
  160. if (strpos($this->url, '?') !== false) {
  161. list(, $querystr) = explode('?', $this->url);
  162. parse_str($querystr, $queryArgs);
  163. $query += $queryArgs;
  164. }
  165. if (isset($this->params['url'])) {
  166. $query = array_merge($this->params['url'], $query);
  167. }
  168. $this->query = $query;
  169. }
  170. /**
  171. * Get the request uri. Looks in PATH_INFO first, as this is the exact value we need prepared
  172. * by PHP. Following that, REQUEST_URI, PHP_SELF, HTTP_X_REWRITE_URL and argv are checked in that order.
  173. * Each of these server variables have the base path, and query strings stripped off
  174. *
  175. * @return string URI The CakePHP request path that is being accessed.
  176. */
  177. protected function _url() {
  178. if (!empty($_SERVER['PATH_INFO'])) {
  179. return $_SERVER['PATH_INFO'];
  180. } elseif (isset($_SERVER['REQUEST_URI'])) {
  181. $uri = $_SERVER['REQUEST_URI'];
  182. } elseif (isset($_SERVER['PHP_SELF']) && isset($_SERVER['SCRIPT_NAME'])) {
  183. $uri = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['PHP_SELF']);
  184. } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
  185. $uri = $_SERVER['HTTP_X_REWRITE_URL'];
  186. } elseif ($var = env('argv')) {
  187. $uri = $var[0];
  188. }
  189. $base = $this->base;
  190. if (strlen($base) > 0 && strpos($uri, $base) === 0) {
  191. $uri = substr($uri, strlen($base));
  192. }
  193. if (strpos($uri, '?') !== false) {
  194. $uri = parse_url($uri, PHP_URL_PATH);
  195. }
  196. if (empty($uri) || $uri == '/' || $uri == '//') {
  197. return '/';
  198. }
  199. return $uri;
  200. }
  201. /**
  202. * Returns a base URL and sets the proper webroot
  203. *
  204. * @return string Base URL
  205. */
  206. protected function _base() {
  207. $dir = $webroot = null;
  208. $config = Configure::read('App');
  209. extract($config);
  210. if (empty($base)) {
  211. $base = $this->base;
  212. }
  213. if ($base !== false) {
  214. $this->webroot = $base . '/';
  215. return $this->base = $base;
  216. }
  217. if (!$baseUrl) {
  218. $base = dirname(env('SCRIPT_NAME'));
  219. if ($webroot === 'webroot' && $webroot === basename($base)) {
  220. $base = dirname($base);
  221. }
  222. if ($dir === 'app' && $dir === basename($base)) {
  223. $base = dirname($base);
  224. }
  225. if ($base === DS || $base === '.') {
  226. $base = '';
  227. }
  228. $this->webroot = $base .'/';
  229. return $this->base = $base;
  230. }
  231. $file = '/' . basename($baseUrl);
  232. $base = dirname($baseUrl);
  233. if ($base === DS || $base === '.') {
  234. $base = '';
  235. }
  236. $this->webroot = $base . '/';
  237. $docRoot = env('DOCUMENT_ROOT');
  238. $docRootContainsWebroot = strpos($docRoot, $dir . '/' . $webroot);
  239. if (!empty($base) || !$docRootContainsWebroot) {
  240. if (strpos($this->webroot, $dir) === false) {
  241. $this->webroot .= $dir . '/' ;
  242. }
  243. if (strpos($this->webroot, $webroot) === false) {
  244. $this->webroot .= $webroot . '/';
  245. }
  246. }
  247. return $this->base = $base . $file;
  248. }
  249. /**
  250. * Process $_FILES and move things into the object.
  251. *
  252. * @return void
  253. */
  254. protected function _processFiles() {
  255. if (isset($_FILES) && is_array($_FILES)) {
  256. foreach ($_FILES as $name => $data) {
  257. if ($name != 'data') {
  258. $this->params['form'][$name] = $data;
  259. }
  260. }
  261. }
  262. if (isset($_FILES['data'])) {
  263. foreach ($_FILES['data'] as $key => $data) {
  264. foreach ($data as $model => $fields) {
  265. if (is_array($fields)) {
  266. foreach ($fields as $field => $value) {
  267. if (is_array($value)) {
  268. foreach ($value as $k => $v) {
  269. $this->data[$model][$field][$k][$key] = $v;
  270. }
  271. } else {
  272. $this->data[$model][$field][$key] = $value;
  273. }
  274. }
  275. } else {
  276. $this->data[$model][$key] = $fields;
  277. }
  278. }
  279. }
  280. }
  281. }
  282. /**
  283. * Get the IP the client is using, or says they are using.
  284. *
  285. * @param boolean $safe Use safe = false when you think the user might manipulate their HTTP_CLIENT_IP
  286. * header. Setting $safe = false will will also look at HTTP_X_FORWARDED_FOR
  287. * @return string The client IP.
  288. */
  289. public function clientIp($safe = true) {
  290. if (!$safe && env('HTTP_X_FORWARDED_FOR') != null) {
  291. $ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR'));
  292. } else {
  293. if (env('HTTP_CLIENT_IP') != null) {
  294. $ipaddr = env('HTTP_CLIENT_IP');
  295. } else {
  296. $ipaddr = env('REMOTE_ADDR');
  297. }
  298. }
  299. if (env('HTTP_CLIENTADDRESS') != null) {
  300. $tmpipaddr = env('HTTP_CLIENTADDRESS');
  301. if (!empty($tmpipaddr)) {
  302. $ipaddr = preg_replace('/(?:,.*)/', '', $tmpipaddr);
  303. }
  304. }
  305. return trim($ipaddr);
  306. }
  307. /**
  308. * Returns the referer that referred this request.
  309. *
  310. * @param boolean $local Attempt to return a local address. Local addresses do not contain hostnames.
  311. * @return string The referring address for this request.
  312. */
  313. public function referer($local = false) {
  314. $ref = env('HTTP_REFERER');
  315. $forwarded = env('HTTP_X_FORWARDED_HOST');
  316. if ($forwarded) {
  317. $ref = $forwarded;
  318. }
  319. $base = '';
  320. if (defined('FULL_BASE_URL')) {
  321. $base = FULL_BASE_URL . $this->webroot;
  322. }
  323. if (!empty($ref) && !empty($base)) {
  324. if ($local && strpos($ref, $base) === 0) {
  325. $ref = substr($ref, strlen($base));
  326. if ($ref[0] != '/') {
  327. $ref = '/' . $ref;
  328. }
  329. return $ref;
  330. } elseif (!$local) {
  331. return $ref;
  332. }
  333. }
  334. return '/';
  335. }
  336. /**
  337. * Missing method handler, handles wrapping older style isAjax() type methods
  338. *
  339. * @param string $name The method called
  340. * @param array $params Array of parameters for the method call
  341. * @return mixed
  342. * @throws BadMethodCallException when an invalid method is called.
  343. */
  344. public function __call($name, $params) {
  345. if (strpos($name, 'is') === 0) {
  346. $type = strtolower(substr($name, 2));
  347. return $this->is($type);
  348. }
  349. throw new CakeException(__('Method %s does not exist', $name));
  350. }
  351. /**
  352. * Magic get method allows access to parsed routing parameters directly on the object.
  353. *
  354. * Allows access to `$this->params['controller']` via `$this->controller`
  355. *
  356. * @param string $name The property being accessed.
  357. * @return mixed Either the value of the parameter or null.
  358. */
  359. public function __get($name) {
  360. if (isset($this->params[$name])) {
  361. return $this->params[$name];
  362. }
  363. return null;
  364. }
  365. /**
  366. * Check whether or not a Request is a certain type. Uses the built in detection rules
  367. * as well as additional rules defined with CakeRequest::addDetector(). Any detector can be called
  368. * as `is($type)` or `is$Type()`.
  369. *
  370. * @param string $type The type of request you want to check.
  371. * @return boolean Whether or not the request is the type you are checking.
  372. */
  373. public function is($type) {
  374. $type = strtolower($type);
  375. if (!isset($this->_detectors[$type])) {
  376. return false;
  377. }
  378. $detect = $this->_detectors[$type];
  379. if (isset($detect['env'])) {
  380. if (isset($detect['value'])) {
  381. return env($detect['env']) == $detect['value'];
  382. }
  383. if (isset($detect['pattern'])) {
  384. return (bool)preg_match($detect['pattern'], env($detect['env']));
  385. }
  386. if (isset($detect['options'])) {
  387. $pattern = '/' . implode('|', $detect['options']) . '/i';
  388. return (bool)preg_match($pattern, env($detect['env']));
  389. }
  390. }
  391. if (isset($detect['callback']) && is_callable($detect['callback'])) {
  392. return call_user_func($detect['callback'], $this);
  393. }
  394. return false;
  395. }
  396. /**
  397. * Add a new detector to the list of detectors that a request can use.
  398. * There are several different formats and types of detectors that can be set.
  399. *
  400. * ### Environment value comparison
  401. *
  402. * An environment value comparison, compares a value fetched from `env()` to a known value
  403. * the environment value is equality checked against the provided value.
  404. *
  405. * e.g `addDetector('post', array('env' => 'REQUEST_METHOD', 'value' => 'POST'))`
  406. *
  407. * ### Pattern value comparison
  408. *
  409. * Pattern value comparison allows you to compare a value fetched from `env()` to a regular expression.
  410. *
  411. * e.g `addDetector('iphone', array('env' => 'HTTP_USER_AGENT', 'pattern' => '/iPhone/i'));`
  412. *
  413. * ### Option based comparison
  414. *
  415. * Option based comparisons use a list of options to create a regular expression. Subsequent calls
  416. * to add an already defined options detector will merge the options.
  417. *
  418. * e.g `addDetector('mobile', array('env' => 'HTTP_USER_AGENT', 'options' => array('Fennec')));`
  419. *
  420. * ### Callback detectors
  421. *
  422. * Callback detectors allow you to provide a 'callback' type to handle the check. The callback will
  423. * recieve the request object as its only parameter.
  424. *
  425. * e.g `addDetector('custom', array('callback' => array('SomeClass', 'somemethod')));`
  426. *
  427. * @param string $name The name of the detector.
  428. * @param array $options The options for the detector definition. See above.
  429. * @return void
  430. */
  431. public function addDetector($name, $options) {
  432. if (isset($this->_detectors[$name]) && isset($options['options'])) {
  433. $options = Set::merge($this->_detectors[$name], $options);
  434. }
  435. $this->_detectors[$name] = $options;
  436. }
  437. /**
  438. * Add parameters to the request's parsed parameter set. This will overwrite any existing parameters.
  439. * This modifies the parameters available through `$request->params`.
  440. *
  441. * @param array $params Array of parameters to merge in
  442. * @return The current object, you can chain this method.
  443. */
  444. public function addParams($params) {
  445. $this->params = array_merge($this->params, $params);
  446. return $this;
  447. }
  448. /**
  449. * Add paths to the requests' paths vars. This will overwrite any existing paths.
  450. * Provides an easy way to modify, here, webroot and base.
  451. *
  452. * @param array $paths Array of paths to merge in
  453. * @return the current object, you can chain this method.
  454. */
  455. public function addPaths($paths) {
  456. foreach (array('webroot', 'here', 'base') as $element) {
  457. if (isset($paths[$element])) {
  458. $this->{$element} = $paths[$element];
  459. }
  460. }
  461. return $this;
  462. }
  463. /**
  464. * Get the value of the current requests url. Will include named parameters and querystring arguments.
  465. *
  466. * @param boolean $base Include the base path, set to false to trim the base path off.
  467. * @return string the current request url including query string args.
  468. */
  469. public function here($base = true) {
  470. $url = $this->here;
  471. if (!empty($this->query)) {
  472. $url .= '?' . http_build_query($this->query);
  473. }
  474. if (!$base) {
  475. $url = preg_replace('/^' . preg_quote($this->base, '/') . '/', '', $url, 1);
  476. }
  477. return $url;
  478. }
  479. /**
  480. * Read an HTTP header from the Request information.
  481. *
  482. * @param string $name Name of the header you want.
  483. * @return mixed Either false on no header being set or the value of the header.
  484. */
  485. public static function header($name) {
  486. $name = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
  487. if (!empty($_SERVER[$name])) {
  488. return $_SERVER[$name];
  489. }
  490. return false;
  491. }
  492. /**
  493. * Get the HTTP method used for this request.
  494. *
  495. * @return string The name of the HTTP method used.
  496. */
  497. public function method() {
  498. return env('REQUEST_METHOD');
  499. }
  500. /**
  501. * Get the host that the request was handled on.
  502. *
  503. * @return void
  504. */
  505. public function host() {
  506. return env('HTTP_HOST');
  507. }
  508. /**
  509. * Get the domain name and include $tldLength segments of the tld.
  510. *
  511. * @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld.
  512. * While `example.co.uk` contains 2.
  513. * @return string Domain name without subdomains.
  514. */
  515. public function domain($tldLength = 1) {
  516. $segments = explode('.', $this->host());
  517. $domain = array_slice($segments, -1 * ($tldLength + 1));
  518. return implode('.', $domain);
  519. }
  520. /**
  521. * Get the subdomains for a host.
  522. *
  523. * @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld.
  524. * While `example.co.uk` contains 2.
  525. * @return array of subdomains.
  526. */
  527. public function subdomains($tldLength = 1) {
  528. $segments = explode('.', $this->host());
  529. return array_slice($segments, 0, -1 * ($tldLength + 1));
  530. }
  531. /**
  532. * Find out which content types the client accepts or check if they accept a
  533. * particular type of content.
  534. *
  535. * #### Get all types:
  536. *
  537. * `$this->request->accepts();`
  538. *
  539. * #### Check for a single type:
  540. *
  541. * `$this->request->accepts('json');`
  542. *
  543. * @param string $type The content type to check for. Leave null to get all types a client accepts.
  544. * @return mixed Either an array of all the types the client accepts or a boolean if they accept the
  545. * provided type.
  546. */
  547. public function accepts($type = null) {
  548. $acceptTypes = explode(',', $this->header('accept'));
  549. foreach ($acceptTypes as $i => $accepted) {
  550. if (strpos($accepted, ';') !== false) {
  551. list($accepted, $prefValue) = explode(';', $accepted);
  552. $acceptTypes[$i] = $accepted;
  553. }
  554. }
  555. if ($type === null) {
  556. return $acceptTypes;
  557. }
  558. return in_array($type, $acceptTypes);
  559. }
  560. /**
  561. * Get the lanaguages accepted by the client, or check if a specific language is accepted.
  562. *
  563. * Get the list of accepted languages:
  564. *
  565. * {{{ CakeRequest::acceptLanguage(); }}}
  566. *
  567. * Check if a specific language is accepted:
  568. *
  569. * {{{ CakeRequest::acceptLanguage('es-es'); }}}
  570. *
  571. * @param string $language The language to test.
  572. * @return If a $language is provided, a boolean. Otherwise the array of accepted languages.
  573. */
  574. public static function acceptLanguage($language = null) {
  575. $accepts = preg_split('/[;,]/', self::header('Accept-Language'));
  576. foreach ($accepts as &$accept) {
  577. $accept = strtolower($accept);
  578. if (strpos($accept, '_') !== false) {
  579. $accept = str_replace('_', '-', $accept);
  580. }
  581. }
  582. if ($language === null) {
  583. return $accepts;
  584. }
  585. return in_array($language, $accepts);
  586. }
  587. /**
  588. * Provides a read/write accessor for `$this->data`. Allows you
  589. * to use a syntax similar to `CakeSession` for reading post data.
  590. *
  591. * ## Reading values.
  592. *
  593. * `$request->data('Post.title');`
  594. *
  595. * When reading values you will get `null` for keys/values that do not exist.
  596. *
  597. * ## Writing values
  598. *
  599. * `$request->data('Post.title', 'New post!');`
  600. *
  601. * You can write to any value, even paths/keys that do not exist, and the arrays
  602. * will be created for you.
  603. *
  604. * @param string $name Dot separated name of the value to read/write
  605. * @param mixed $value Value to write to the data array.
  606. * @return mixed Either the value being read, or this so you can chain consecutive writes.
  607. */
  608. public function data($name) {
  609. $args = func_get_args();
  610. if (count($args) == 2) {
  611. $this->data = Set::insert($this->data, $name, $args[1]);
  612. return $this;
  613. }
  614. return Set::classicExtract($this->data, $name);
  615. }
  616. /**
  617. * Array access read implementation
  618. *
  619. * @param string $name Name of the key being accessed.
  620. * @return mixed
  621. */
  622. public function offsetGet($name) {
  623. if (isset($this->params[$name])) {
  624. return $this->params[$name];
  625. }
  626. if ($name == 'url') {
  627. return $this->query;
  628. }
  629. if ($name == 'data') {
  630. return $this->data;
  631. }
  632. return null;
  633. }
  634. /**
  635. * Array access write implementation
  636. *
  637. * @param string $name Name of the key being written
  638. * @param mixed $value The value being written.
  639. * @return void
  640. */
  641. public function offsetSet($name, $value) {
  642. $this->params[$name] = $value;
  643. }
  644. /**
  645. * Array access isset() implementation
  646. *
  647. * @param string $name thing to check.
  648. * @return boolean
  649. */
  650. public function offsetExists($name) {
  651. return isset($this->params[$name]);
  652. }
  653. /**
  654. * Array access unset() implementation
  655. *
  656. * @param $name Name to unset.
  657. * @return void
  658. */
  659. public function offsetUnset($name) {
  660. unset($this->params[$name]);
  661. }
  662. }