PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/libs/controller/components/request_handler.php

https://github.com/rogerwu99/randomizr
PHP | 741 lines | 386 code | 35 blank | 320 comment | 103 complexity | 80ce7a127225083a162c9223e3e6f368 MD5 | raw file
Possible License(s): MIT, LGPL-3.0
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * Request object for handling alternative HTTP requests
  5. *
  6. * Alternative HTTP requests can come from wireless units like mobile phones, palmtop computers,
  7. * and the like. These units have no use for Ajax requests, and this Component can tell how Cake
  8. * should respond to the different needs of a handheld computer and a desktop machine.
  9. *
  10. * CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
  11. * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  12. *
  13. * Licensed under The MIT License
  14. * Redistributions of files must retain the above copyright notice.
  15. *
  16. * @filesource
  17. * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  18. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  19. * @package cake
  20. * @subpackage cake.cake.libs.controller.components
  21. * @since CakePHP(tm) v 0.10.4.1076
  22. * @version $Revision$
  23. * @modifiedby $LastChangedBy$
  24. * @lastmodified $Date$
  25. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  26. */
  27. if (!defined('REQUEST_MOBILE_UA')) {
  28. define('REQUEST_MOBILE_UA', '(iPhone|MIDP|AvantGo|BlackBerry|J2ME|Opera Mini|DoCoMo|NetFront|Nokia|PalmOS|PalmSource|portalmmm|Plucker|ReqwirelessWeb|SonyEricsson|Symbian|UP\.Browser|Windows CE|Xiino)');
  29. }
  30. /**
  31. * Request object for handling HTTP requests
  32. *
  33. * @package cake
  34. * @subpackage cake.cake.libs.controller.components
  35. *
  36. */
  37. class RequestHandlerComponent extends Object {
  38. /**
  39. * The layout that will be switched to for Ajax requests
  40. *
  41. * @var string
  42. * @access public
  43. * @see RequestHandler::setAjax()
  44. */
  45. var $ajaxLayout = 'ajax';
  46. /**
  47. * Determines whether or not callbacks will be fired on this component
  48. *
  49. * @var boolean
  50. * @access public
  51. */
  52. var $enabled = true;
  53. /**
  54. * Holds the content-type of the response that is set when using
  55. * RequestHandler::respondAs()
  56. *
  57. * @var string
  58. * @access private
  59. */
  60. var $__responseTypeSet = null;
  61. /**
  62. * Holds the copy of Controller::$params
  63. *
  64. * @var array
  65. * @access public
  66. */
  67. var $params = array();
  68. /**
  69. * Friendly content-type mappings used to set response types and determine
  70. * request types. Can be modified with RequestHandler::setContent()
  71. *
  72. * @var array
  73. * @access private
  74. * @see RequestHandlerComponent::setContent
  75. */
  76. var $__requestContent = array(
  77. 'javascript' => 'text/javascript',
  78. 'js' => 'text/javascript',
  79. 'json' => 'application/json',
  80. 'css' => 'text/css',
  81. 'html' => array('text/html', '*/*'),
  82. 'text' => 'text/plain',
  83. 'txt' => 'text/plain',
  84. 'csv' => array('application/vnd.ms-excel', 'text/plain'),
  85. 'form' => 'application/x-www-form-urlencoded',
  86. 'file' => 'multipart/form-data',
  87. 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'),
  88. 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml',
  89. 'xml' => array('application/xml', 'text/xml'),
  90. 'rss' => 'application/rss+xml',
  91. 'atom' => 'application/atom+xml',
  92. 'amf' => 'application/x-amf',
  93. 'wap' => array(
  94. 'text/vnd.wap.wml',
  95. 'text/vnd.wap.wmlscript',
  96. 'image/vnd.wap.wbmp'
  97. ),
  98. 'wml' => 'text/vnd.wap.wml',
  99. 'wmlscript' => 'text/vnd.wap.wmlscript',
  100. 'wbmp' => 'image/vnd.wap.wbmp',
  101. 'pdf' => 'application/pdf',
  102. 'zip' => 'application/x-zip',
  103. 'tar' => 'application/x-tar'
  104. );
  105. /**
  106. * Content-types accepted by the client. If extension parsing is enabled in the
  107. * Router, and an extension is detected, the corresponding content-type will be
  108. * used as the overriding primary content-type accepted.
  109. *
  110. * @var array
  111. * @access private
  112. * @see Router::parseExtensions()
  113. */
  114. var $__acceptTypes = array();
  115. /**
  116. * The template to use when rendering the given content type.
  117. *
  118. * @var string
  119. * @access private
  120. */
  121. var $__renderType = null;
  122. /**
  123. * Contains the file extension parsed out by the Router
  124. *
  125. * @var string
  126. * @access public
  127. * @see Router::parseExtensions()
  128. */
  129. var $ext = null;
  130. /**
  131. * Flag set when MIME types have been initialized
  132. *
  133. * @var boolean
  134. * @access private
  135. * @see RequestHandler::__initializeTypes()
  136. */
  137. var $__typesInitialized = false;
  138. /**
  139. * Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
  140. *
  141. */
  142. function __construct() {
  143. $this->__acceptTypes = explode(',', env('HTTP_ACCEPT'));
  144. foreach ($this->__acceptTypes as $i => $type) {
  145. if (strpos($type, ';')) {
  146. $type = explode(';', $type);
  147. $this->__acceptTypes[$i] = $type[0];
  148. }
  149. }
  150. parent::__construct();
  151. }
  152. /**
  153. * Initializes the component, gets a reference to Controller::$parameters, and
  154. * checks to see if a file extension has been parsed by the Router. If yes, the
  155. * corresponding content-type is pushed onto the list of accepted content-types
  156. * as the first item.
  157. *
  158. * @param object $controller A reference to the controller
  159. * @return void
  160. * @see Router::parseExtensions()
  161. * @access public
  162. */
  163. function initialize(&$controller) {
  164. if (isset($controller->params['url']['ext'])) {
  165. $this->ext = $controller->params['url']['ext'];
  166. }
  167. }
  168. /**
  169. * The startup method of the RequestHandler enables several automatic behaviors
  170. * related to the detection of certain properties of the HTTP request, including:
  171. *
  172. * - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header)
  173. * - If Router::parseExtensions() is enabled, the layout and template type are
  174. * switched based on the parsed extension. For example, if controller/action.xml
  175. * is requested, the view path becomes <i>app/views/controller/xml/action.ctp</i>.
  176. * - If a helper with the same name as the extension exists, it is added to the controller.
  177. * - If the extension is of a type that RequestHandler understands, it will set that
  178. * Content-type in the response header.
  179. * - If the XML data is POSTed, the data is parsed into an XML object, which is assigned
  180. * to the $data property of the controller, which can then be saved to a model object.
  181. *
  182. * @param object $controller A reference to the controller
  183. * @return void
  184. * @access public
  185. */
  186. function startup(&$controller) {
  187. if (!$this->enabled) {
  188. return;
  189. }
  190. $this->__initializeTypes();
  191. $controller->params['isAjax'] = $this->isAjax();
  192. $isRecognized = (
  193. !in_array($this->ext, array('html', 'htm')) &&
  194. in_array($this->ext, array_keys($this->__requestContent))
  195. );
  196. if (!empty($this->ext) && $isRecognized) {
  197. $this->renderAs($controller, $this->ext);
  198. } elseif ($this->isAjax()) {
  199. $this->renderAs($controller, 'ajax');
  200. }
  201. if ($this->requestedWith('xml')) {
  202. if (!class_exists('XmlNode')) {
  203. App::import('Core', 'Xml');
  204. }
  205. $xml = new Xml(trim(file_get_contents('php://input')));
  206. if (is_object($xml->child('data')) && count($xml->children) == 1) {
  207. $controller->data = $xml->child('data');
  208. } else {
  209. $controller->data = $xml;
  210. }
  211. }
  212. }
  213. /**
  214. * Handles (fakes) redirects for Ajax requests using requestAction()
  215. *
  216. * @param object $controller A reference to the controller
  217. * @param mixed $url A string or array containing the redirect location
  218. * @access public
  219. */
  220. function beforeRedirect(&$controller, $url) {
  221. if (!$this->isAjax()) {
  222. return;
  223. }
  224. foreach ($_POST as $key => $val) {
  225. unset($_POST[$key]);
  226. }
  227. echo $this->requestAction($url, array('return'));
  228. $this->_stop();
  229. }
  230. /**
  231. * Returns true if the current HTTP request is Ajax, false otherwise
  232. *
  233. * @return boolean True if call is Ajax
  234. * @access public
  235. */
  236. function isAjax() {
  237. return env('HTTP_X_REQUESTED_WITH') === "XMLHttpRequest";
  238. }
  239. /**
  240. * Returns true if the current HTTP request is coming from a Flash-based client
  241. *
  242. * @return boolean True if call is from Flash
  243. * @access public
  244. */
  245. function isFlash() {
  246. return (preg_match('/^(Shockwave|Adobe) Flash/', env('HTTP_USER_AGENT')) == 1);
  247. }
  248. /**
  249. * Returns true if the current request is over HTTPS, false otherwise.
  250. *
  251. * @return bool True if call is over HTTPS
  252. * @access public
  253. */
  254. function isSSL() {
  255. return env('HTTPS');
  256. }
  257. /**
  258. * Returns true if the current call accepts an XML response, false otherwise
  259. *
  260. * @return boolean True if client accepts an XML response
  261. * @access public
  262. */
  263. function isXml() {
  264. return $this->prefers('xml');
  265. }
  266. /**
  267. * Returns true if the current call accepts an RSS response, false otherwise
  268. *
  269. * @return boolean True if client accepts an RSS response
  270. * @access public
  271. */
  272. function isRss() {
  273. return $this->prefers('rss');
  274. }
  275. /**
  276. * Returns true if the current call accepts an Atom response, false otherwise
  277. *
  278. * @return boolean True if client accepts an RSS response
  279. * @access public
  280. */
  281. function isAtom() {
  282. return $this->prefers('atom');
  283. }
  284. /**
  285. * Returns true if user agent string matches a mobile web browser, or if the
  286. * client accepts WAP content.
  287. *
  288. * @return boolean True if user agent is a mobile web browser
  289. * @access public
  290. */
  291. function isMobile() {
  292. preg_match('/' . REQUEST_MOBILE_UA . '/i', env('HTTP_USER_AGENT'), $match);
  293. if (!empty($match) || $this->accepts('wap')) {
  294. return true;
  295. }
  296. return false;
  297. }
  298. /**
  299. * Returns true if the client accepts WAP content
  300. *
  301. * @return bool
  302. * @access public
  303. */
  304. function isWap() {
  305. return $this->prefers('wap');
  306. }
  307. /**
  308. * Returns true if the current call a POST request
  309. *
  310. * @return boolean True if call is a POST
  311. * @access public
  312. */
  313. function isPost() {
  314. return (strtolower(env('REQUEST_METHOD')) == 'post');
  315. }
  316. /**
  317. * Returns true if the current call a PUT request
  318. *
  319. * @return boolean True if call is a PUT
  320. * @access public
  321. */
  322. function isPut() {
  323. return (strtolower(env('REQUEST_METHOD')) == 'put');
  324. }
  325. /**
  326. * Returns true if the current call a GET request
  327. *
  328. * @return boolean True if call is a GET
  329. * @access public
  330. */
  331. function isGet() {
  332. return (strtolower(env('REQUEST_METHOD')) == 'get');
  333. }
  334. /**
  335. * Returns true if the current call a DELETE request
  336. *
  337. * @return boolean True if call is a DELETE
  338. * @access public
  339. */
  340. function isDelete() {
  341. return (strtolower(env('REQUEST_METHOD')) == 'delete');
  342. }
  343. /**
  344. * Gets Prototype version if call is Ajax, otherwise empty string.
  345. * The Prototype library sets a special "Prototype version" HTTP header.
  346. *
  347. * @return string Prototype version of component making Ajax call
  348. * @access public
  349. */
  350. function getAjaxVersion() {
  351. if (env('HTTP_X_PROTOTYPE_VERSION') != null) {
  352. return env('HTTP_X_PROTOTYPE_VERSION');
  353. }
  354. return false;
  355. }
  356. /**
  357. * Adds/sets the Content-type(s) for the given name. This method allows
  358. * content-types to be mapped to friendly aliases (or extensions), which allows
  359. * RequestHandler to automatically respond to requests of that type in the
  360. * startup method.
  361. *
  362. * @param string $name The name of the Content-type, i.e. "html", "xml", "css"
  363. * @param mixed $type The Content-type or array of Content-types assigned to the name,
  364. * i.e. "text/html", or "application/xml"
  365. * @return void
  366. * @access public
  367. */
  368. function setContent($name, $type = null) {
  369. if (is_array($name)) {
  370. $this->__requestContent = array_merge($this->__requestContent, $name);
  371. return;
  372. }
  373. $this->__requestContent[$name] = $type;
  374. }
  375. /**
  376. * Gets the server name from which this request was referred
  377. *
  378. * @return string Server address
  379. * @access public
  380. */
  381. function getReferrer() {
  382. if (env('HTTP_HOST') != null) {
  383. $sessHost = env('HTTP_HOST');
  384. }
  385. if (env('HTTP_X_FORWARDED_HOST') != null) {
  386. $sessHost = env('HTTP_X_FORWARDED_HOST');
  387. }
  388. return trim(preg_replace('/(?:\:.*)/', '', $sessHost));
  389. }
  390. /**
  391. * Gets remote client IP
  392. *
  393. * @return string Client IP address
  394. * @access public
  395. */
  396. function getClientIP($safe = true) {
  397. if (!$safe && env('HTTP_X_FORWARDED_FOR') != null) {
  398. $ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR'));
  399. } else {
  400. if (env('HTTP_CLIENT_IP') != null) {
  401. $ipaddr = env('HTTP_CLIENT_IP');
  402. } else {
  403. $ipaddr = env('REMOTE_ADDR');
  404. }
  405. }
  406. if (env('HTTP_CLIENTADDRESS') != null) {
  407. $tmpipaddr = env('HTTP_CLIENTADDRESS');
  408. if (!empty($tmpipaddr)) {
  409. $ipaddr = preg_replace('/(?:,.*)/', '', $tmpipaddr);
  410. }
  411. }
  412. return trim($ipaddr);
  413. }
  414. /**
  415. * Determines which content types the client accepts. Acceptance is based on
  416. * the file extension parsed by the Router (if present), and by the HTTP_ACCEPT
  417. * header.
  418. *
  419. * @param mixed $type Can be null (or no parameter), a string type name, or an
  420. * array of types
  421. * @return mixed If null or no parameter is passed, returns an array of content
  422. * types the client accepts. If a string is passed, returns true
  423. * if the client accepts it. If an array is passed, returns true
  424. * if the client accepts one or more elements in the array.
  425. * @access public
  426. * @see RequestHandlerComponent::setContent()
  427. */
  428. function accepts($type = null) {
  429. $this->__initializeTypes();
  430. if ($type == null) {
  431. return $this->mapType($this->__acceptTypes);
  432. } elseif (is_array($type)) {
  433. foreach ($type as $t) {
  434. if ($this->accepts($t) == true) {
  435. return true;
  436. }
  437. }
  438. return false;
  439. } elseif (is_string($type)) {
  440. if (!isset($this->__requestContent[$type])) {
  441. return false;
  442. }
  443. $content = $this->__requestContent[$type];
  444. if (is_array($content)) {
  445. foreach ($content as $c) {
  446. if (in_array($c, $this->__acceptTypes)) {
  447. return true;
  448. }
  449. }
  450. } else {
  451. if (in_array($content, $this->__acceptTypes)) {
  452. return true;
  453. }
  454. }
  455. }
  456. }
  457. /**
  458. * Determines the content type of the data the client has sent (i.e. in a POST request)
  459. *
  460. * @param mixed $type Can be null (or no parameter), a string type name, or an array of types
  461. * @return mixed
  462. * @access public
  463. */
  464. function requestedWith($type = null) {
  465. if (!$this->isPost() && !$this->isPut()) {
  466. return null;
  467. }
  468. list($contentType) = explode(';', env('CONTENT_TYPE'));
  469. if ($type == null) {
  470. return $this->mapType($contentType);
  471. } elseif (is_array($type)) {
  472. foreach ($type as $t) {
  473. if ($this->requestedWith($t)) {
  474. return $this->mapType($t);
  475. }
  476. }
  477. return false;
  478. } elseif (is_string($type)) {
  479. return ($type == $this->mapType($contentType));
  480. }
  481. }
  482. /**
  483. * Determines which content-types the client prefers. If no parameters are given,
  484. * the content-type that the client most likely prefers is returned. If $type is
  485. * an array, the first item in the array that the client accepts is returned.
  486. * Preference is determined primarily by the file extension parsed by the Router
  487. * if provided, and secondarily by the list of content-types provided in
  488. * HTTP_ACCEPT.
  489. *
  490. * @param mixed $type An optional array of 'friendly' content-type names, i.e.
  491. * 'html', 'xml', 'js', etc.
  492. * @return mixed If $type is null or not provided, the first content-type in the
  493. * list, based on preference, is returned.
  494. * @access public
  495. * @see RequestHandlerComponent::setContent()
  496. */
  497. function prefers($type = null) {
  498. $this->__initializeTypes();
  499. $accept = $this->accepts();
  500. if ($type == null) {
  501. if (empty($this->ext)) {
  502. if (is_array($accept)) {
  503. return $accept[0];
  504. }
  505. return $accept;
  506. }
  507. return $this->ext;
  508. }
  509. $types = $type;
  510. if (is_string($type)) {
  511. $types = array($type);
  512. }
  513. if (count($types) === 1) {
  514. if (!empty($this->ext)) {
  515. return ($types[0] == $this->ext);
  516. }
  517. return ($types[0] == $accept[0]);
  518. }
  519. $accepts = array();
  520. foreach ($types as $type) {
  521. if (in_array($type, $accept)) {
  522. $accepts[] = $type;
  523. }
  524. }
  525. if (count($accepts) === 0) {
  526. return false;
  527. } elseif (count($types) === 1) {
  528. return ($types[0] === $accepts[0]);
  529. } elseif (count($accepts) === 1) {
  530. return $accepts[0];
  531. }
  532. $acceptedTypes = array();
  533. foreach ($this->__acceptTypes as $type) {
  534. $acceptedTypes[] = $this->mapType($type);
  535. }
  536. $accepts = array_intersect($acceptedTypes, $accepts);
  537. return $accepts[0];
  538. }
  539. /**
  540. * Sets the layout and template paths for the content type defined by $type.
  541. *
  542. * @param object $controller A reference to a controller object
  543. * @param string $type Type of response to send (e.g: 'ajax')
  544. * @return void
  545. * @access public
  546. * @see RequestHandlerComponent::setContent()
  547. * @see RequestHandlerComponent::respondAs()
  548. */
  549. function renderAs(&$controller, $type) {
  550. $this->__initializeTypes();
  551. $options = array('charset' => 'UTF-8');
  552. if (Configure::read('App.encoding') !== null) {
  553. $options = array('charset' => Configure::read('App.encoding'));
  554. }
  555. if ($type == 'ajax') {
  556. $controller->layout = $this->ajaxLayout;
  557. return $this->respondAs('html', $options);
  558. }
  559. $controller->ext = '.ctp';
  560. if (empty($this->__renderType)) {
  561. $controller->viewPath .= '/' . $type;
  562. } else {
  563. $remove = preg_replace("/(?:\/{$this->__renderType})$/", '/' . $type, $controller->viewPath);
  564. $controller->viewPath = $remove;
  565. }
  566. $this->__renderType = $type;
  567. $controller->layoutPath = $type;
  568. if (isset($this->__requestContent[$type])) {
  569. $this->respondAs($type, $options);
  570. }
  571. $helper = ucfirst($type);
  572. $isAdded = (
  573. in_array($helper, $controller->helpers) ||
  574. array_key_exists($helper, $controller->helpers)
  575. );
  576. if (!$isAdded) {
  577. if (App::import('Helper', $helper)) {
  578. $controller->helpers[] = $helper;
  579. }
  580. }
  581. }
  582. /**
  583. * Sets the response header based on type map index name. If DEBUG is greater than 2, the header
  584. * is not set.
  585. *
  586. * @param mixed $type Friendly type name, i.e. 'html' or 'xml', or a full content-type,
  587. * like 'application/x-shockwave'.
  588. * @param array $options If $type is a friendly type name that is associated with
  589. * more than one type of content, $index is used to select which content-type to use.
  590. *
  591. * @return boolean Returns false if the friendly type name given in $type does
  592. * not exist in the type map, or if the Content-type header has
  593. * already been set by this method.
  594. * @access public
  595. * @see RequestHandlerComponent::setContent()
  596. */
  597. function respondAs($type, $options = array()) {
  598. $this->__initializeTypes();
  599. if ($this->__responseTypeSet != null) {
  600. return false;
  601. }
  602. if (!array_key_exists($type, $this->__requestContent) && strpos($type, '/') === false) {
  603. return false;
  604. }
  605. $defaults = array('index' => 0, 'charset' => null, 'attachment' => false);
  606. $options = array_merge($defaults, $options);
  607. if (strpos($type, '/') === false && isset($this->__requestContent[$type])) {
  608. $cType = null;
  609. if (is_array($this->__requestContent[$type]) && isset($this->__requestContent[$type][$options['index']])) {
  610. $cType = $this->__requestContent[$type][$options['index']];
  611. } elseif (is_array($this->__requestContent[$type]) && isset($this->__requestContent[$type][0])) {
  612. $cType = $this->__requestContent[$type][0];
  613. } elseif (isset($this->__requestContent[$type])) {
  614. $cType = $this->__requestContent[$type];
  615. } else {
  616. return false;
  617. }
  618. if (is_array($cType)) {
  619. if ($this->prefers($cType)) {
  620. $cType = $this->prefers($cType);
  621. } else {
  622. $cType = $cType[0];
  623. }
  624. }
  625. } else {
  626. $cType = $type;
  627. }
  628. if ($cType != null) {
  629. $header = 'Content-type: ' . $cType;
  630. if (!empty($options['charset'])) {
  631. $header .= '; charset=' . $options['charset'];
  632. }
  633. if (!empty($options['attachment'])) {
  634. header("Content-Disposition: attachment; filename=\"{$options['attachment']}\"");
  635. }
  636. if (Configure::read() < 2 && !defined('CAKEPHP_SHELL')) {
  637. @header($header);
  638. }
  639. $this->__responseTypeSet = $cType;
  640. return true;
  641. }
  642. return false;
  643. }
  644. /**
  645. * Returns the current response type (Content-type header), or null if none has been set
  646. *
  647. * @return mixed A string content type alias, or raw content type if no alias map exists,
  648. * otherwise null
  649. * @access public
  650. */
  651. function responseType() {
  652. if ($this->__responseTypeSet == null) {
  653. return null;
  654. }
  655. return $this->mapType($this->__responseTypeSet);
  656. }
  657. /**
  658. * Maps a content-type back to an alias
  659. *
  660. * @param mixed $type Content type
  661. * @return mixed Alias
  662. * @access public
  663. */
  664. function mapType($ctype) {
  665. if (is_array($ctype)) {
  666. $out = array();
  667. foreach ($ctype as $t) {
  668. $out[] = $this->mapType($t);
  669. }
  670. return $out;
  671. } else {
  672. $keys = array_keys($this->__requestContent);
  673. $count = count($keys);
  674. for ($i = 0; $i < $count; $i++) {
  675. $name = $keys[$i];
  676. $type = $this->__requestContent[$name];
  677. if (is_array($type) && in_array($ctype, $type)) {
  678. return $name;
  679. } elseif (!is_array($type) && $type == $ctype) {
  680. return $name;
  681. }
  682. }
  683. return $ctype;
  684. }
  685. }
  686. /**
  687. * Initializes MIME types
  688. *
  689. * @return void
  690. * @access private
  691. */
  692. function __initializeTypes() {
  693. if ($this->__typesInitialized) {
  694. return;
  695. }
  696. if (isset($this->__requestContent[$this->ext])) {
  697. $content = $this->__requestContent[$this->ext];
  698. if (is_array($content)) {
  699. $content = $content[0];
  700. }
  701. array_unshift($this->__acceptTypes, $content);
  702. }
  703. $this->__typesInitialized = true;
  704. }
  705. }
  706. ?>