PageRenderTime 59ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/cake/dispatcher.php

https://github.com/hardsshah/bookmarks
PHP | 683 lines | 481 code | 40 blank | 162 comment | 146 complexity | 398f10e91ed800be3e67bc1682780024 MD5 | raw file
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * Dispatcher takes the URL information, parses it for paramters and
  5. * tells the involved controllers what to do.
  6. *
  7. * This is the heart of Cake's operation.
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
  12. * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  13. *
  14. * Licensed under The MIT License
  15. * Redistributions of files must retain the above copyright notice.
  16. *
  17. * @filesource
  18. * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
  19. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  20. * @package cake
  21. * @subpackage cake.cake
  22. * @since CakePHP(tm) v 0.2.9
  23. * @version $Revision$
  24. * @modifiedby $LastChangedBy$
  25. * @lastmodified $Date$
  26. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  27. */
  28. /**
  29. * List of helpers to include
  30. */
  31. App::import('Core', array('Router', 'Controller'));
  32. /**
  33. * Dispatcher translates URLs to controller-action-paramter triads.
  34. *
  35. * Dispatches the request, creating appropriate models and controllers.
  36. *
  37. * @package cake
  38. * @subpackage cake.cake
  39. */
  40. class Dispatcher extends Object {
  41. /**
  42. * Base URL
  43. *
  44. * @var string
  45. * @access public
  46. */
  47. var $base = false;
  48. /**
  49. * webroot path
  50. *
  51. * @var string
  52. * @access public
  53. */
  54. var $webroot = '/';
  55. /**
  56. * Current URL
  57. *
  58. * @var string
  59. * @access public
  60. */
  61. var $here = false;
  62. /**
  63. * Admin route (if on it)
  64. *
  65. * @var string
  66. * @access public
  67. */
  68. var $admin = false;
  69. /**
  70. * Plugin being served (if any)
  71. *
  72. * @var string
  73. * @access public
  74. */
  75. var $plugin = null;
  76. /**
  77. * the params for this request
  78. *
  79. * @var string
  80. * @access public
  81. */
  82. var $params = null;
  83. /**
  84. * Constructor.
  85. */
  86. function __construct($url = null, $base = false) {
  87. if ($base !== false) {
  88. Configure::write('App.base', $base);
  89. }
  90. if ($url !== null) {
  91. return $this->dispatch($url);
  92. }
  93. }
  94. /**
  95. * Dispatches and invokes given URL, handing over control to the involved controllers, and then renders the results (if autoRender is set).
  96. *
  97. * If no controller of given name can be found, invoke() shows error messages in
  98. * the form of Missing Controllers information. It does the same with Actions (methods of Controllers are called
  99. * Actions).
  100. *
  101. * @param string $url URL information to work on
  102. * @param array $additionalParams Settings array ("bare", "return") which is melded with the GET and POST params
  103. * @return boolean Success
  104. * @access public
  105. */
  106. function dispatch($url = null, $additionalParams = array()) {
  107. if ($this->base === false) {
  108. $this->base = $this->baseUrl();
  109. }
  110. if (is_array($url)) {
  111. $url = $this->__extractParams($url, $additionalParams);
  112. } else {
  113. if ($url) {
  114. $_GET['url'] = $url;
  115. }
  116. $url = $this->getUrl();
  117. $this->params = array_merge($this->parseParams($url), $additionalParams);
  118. }
  119. $this->here = $this->base . '/' . $url;
  120. if ($this->cached($url)) {
  121. $this->_stop();
  122. }
  123. $controller =& $this->__getController();
  124. if (!is_object($controller)) {
  125. Router::setRequestInfo(array($this->params, array('base' => $this->base, 'webroot' => $this->webroot)));
  126. return $this->cakeError('missingController', array(array(
  127. 'className' => Inflector::camelize($this->params['controller']) . 'Controller',
  128. 'webroot' => $this->webroot,
  129. 'url' => $url,
  130. 'base' => $this->base
  131. )));
  132. }
  133. $privateAction = (bool)(strpos($this->params['action'], '_', 0) === 0);
  134. $prefixes = Router::prefixes();
  135. if (!empty($prefixes)) {
  136. if (isset($this->params['prefix'])) {
  137. $this->params['action'] = $this->params['prefix'] . '_' . $this->params['action'];
  138. } elseif (strpos($this->params['action'], '_') !== false && !$privateAction) {
  139. list($prefix, $action) = explode('_', $this->params['action']);
  140. $privateAction = in_array($prefix, $prefixes);
  141. }
  142. }
  143. Router::setRequestInfo(array(
  144. $this->params, array('base' => $this->base, 'here' => $this->here, 'webroot' => $this->webroot)
  145. ));
  146. if ($privateAction) {
  147. return $this->cakeError('privateAction', array(array(
  148. 'className' => Inflector::camelize($this->params['controller'] . "Controller"),
  149. 'action' => $this->params['action'],
  150. 'webroot' => $this->webroot,
  151. 'url' => $url,
  152. 'base' => $this->base
  153. )));
  154. }
  155. $controller->base = $this->base;
  156. $controller->here = $this->here;
  157. $controller->webroot = $this->webroot;
  158. $controller->plugin = $this->plugin;
  159. $controller->params =& $this->params;
  160. $controller->action =& $this->params['action'];
  161. $controller->passedArgs = array_merge($this->params['pass'], $this->params['named']);
  162. if (!empty($this->params['data'])) {
  163. $controller->data =& $this->params['data'];
  164. } else {
  165. $controller->data = null;
  166. }
  167. if (array_key_exists('return', $this->params) && $this->params['return'] == 1) {
  168. $controller->autoRender = false;
  169. }
  170. if (!empty($this->params['bare'])) {
  171. $controller->autoLayout = false;
  172. }
  173. if (array_key_exists('layout', $this->params)) {
  174. if (empty($this->params['layout'])) {
  175. $controller->autoLayout = false;
  176. } else {
  177. $controller->layout = $this->params['layout'];
  178. }
  179. }
  180. if (isset($this->params['viewPath'])) {
  181. $controller->viewPath = $this->params['viewPath'];
  182. }
  183. return $this->_invoke($controller, $this->params);
  184. }
  185. /**
  186. * Invokes given controller's render action if autoRender option is set. Otherwise the
  187. * contents of the operation are returned as a string.
  188. *
  189. * @param object $controller Controller to invoke
  190. * @param array $params Parameters with at least the 'action' to invoke
  191. * @param boolean $missingAction Set to true if missing action should be rendered, false otherwise
  192. * @return string Output as sent by controller
  193. * @access protected
  194. */
  195. function _invoke(&$controller, $params) {
  196. $controller->constructClasses();
  197. $controller->Component->initialize($controller);
  198. $controller->beforeFilter();
  199. $controller->Component->startup($controller);
  200. $methods = array_flip($controller->methods);
  201. if (!isset($methods[strtolower($params['action'])])) {
  202. if ($controller->scaffold !== false) {
  203. App::import('Core', 'Scaffold');
  204. return new Scaffold($controller, $params);
  205. }
  206. return $this->cakeError('missingAction', array(array(
  207. 'className' => Inflector::camelize($params['controller']."Controller"),
  208. 'action' => $params['action'],
  209. 'webroot' => $this->webroot,
  210. 'url' => $this->here,
  211. 'base' => $this->base
  212. )));
  213. }
  214. $output = $controller->dispatchMethod($params['action'], $params['pass']);
  215. if ($controller->autoRender) {
  216. $controller->output = $controller->render();
  217. } elseif (empty($controller->output)) {
  218. $controller->output = $output;
  219. }
  220. $controller->Component->shutdown($controller);
  221. $controller->afterFilter();
  222. if (isset($params['return'])) {
  223. return $controller->output;
  224. }
  225. echo($controller->output);
  226. }
  227. /**
  228. * Sets the params when $url is passed as an array to Object::requestAction();
  229. *
  230. * @param array $url
  231. * @param array $additionalParams
  232. * @return string $url
  233. * @access private
  234. */
  235. function __extractParams($url, $additionalParams = array()) {
  236. $defaults = array('pass' => array(), 'named' => array(), 'form' => array());
  237. $this->params = array_merge($defaults, $url, $additionalParams);
  238. return Router::url($url);
  239. }
  240. /**
  241. * Returns array of GET and POST parameters. GET parameters are taken from given URL.
  242. *
  243. * @param string $fromUrl URL to mine for parameter information.
  244. * @return array Parameters found in POST and GET.
  245. * @access public
  246. */
  247. function parseParams($fromUrl) {
  248. $params = array();
  249. if (isset($_POST)) {
  250. $params['form'] = $_POST;
  251. if (ini_get('magic_quotes_gpc') === '1') {
  252. $params['form'] = stripslashes_deep($params['form']);
  253. }
  254. if (env('HTTP_X_HTTP_METHOD_OVERRIDE')) {
  255. $params['form']['_method'] = env('HTTP_X_HTTP_METHOD_OVERRIDE');
  256. }
  257. if (isset($params['form']['_method'])) {
  258. if (isset($_SERVER) && !empty($_SERVER)) {
  259. $_SERVER['REQUEST_METHOD'] = $params['form']['_method'];
  260. } else {
  261. $_ENV['REQUEST_METHOD'] = $params['form']['_method'];
  262. }
  263. unset($params['form']['_method']);
  264. }
  265. }
  266. $namedExpressions = Router::getNamedExpressions();
  267. extract($namedExpressions);
  268. include CONFIGS . 'routes.php';
  269. $params = array_merge(Router::parse($fromUrl), $params);
  270. if (strlen($params['action']) === 0) {
  271. $params['action'] = 'index';
  272. }
  273. if (isset($params['form']['data'])) {
  274. $params['data'] = Router::stripEscape($params['form']['data']);
  275. unset($params['form']['data']);
  276. }
  277. if (isset($_GET)) {
  278. if (ini_get('magic_quotes_gpc') === '1') {
  279. $url = stripslashes_deep($_GET);
  280. } else {
  281. $url = $_GET;
  282. }
  283. if (isset($params['url'])) {
  284. $params['url'] = array_merge($params['url'], $url);
  285. } else {
  286. $params['url'] = $url;
  287. }
  288. }
  289. foreach ($_FILES as $name => $data) {
  290. if ($name != 'data') {
  291. $params['form'][$name] = $data;
  292. }
  293. }
  294. if (isset($_FILES['data'])) {
  295. foreach ($_FILES['data'] as $key => $data) {
  296. foreach ($data as $model => $fields) {
  297. foreach ($fields as $field => $value) {
  298. if (is_array($value)) {
  299. foreach ($value as $k => $v) {
  300. $params['data'][$model][$field][$k][$key] = $v;
  301. }
  302. } else {
  303. $params['data'][$model][$field][$key] = $value;
  304. }
  305. }
  306. }
  307. }
  308. }
  309. return $params;
  310. }
  311. /**
  312. * Returns a base URL and sets the proper webroot
  313. *
  314. * @return string Base URL
  315. * @access public
  316. */
  317. function baseUrl() {
  318. $dir = $webroot = null;
  319. $config = Configure::read('App');
  320. extract($config);
  321. if (!$base) {
  322. $base = $this->base;
  323. }
  324. if ($base !== false) {
  325. $this->webroot = $base . '/';
  326. return $this->base = $base;
  327. }
  328. if (!$baseUrl) {
  329. $base = dirname(env('PHP_SELF'));
  330. if ($webroot === 'webroot' && $webroot === basename($base)) {
  331. $base = dirname($base);
  332. }
  333. if ($dir === 'app' && $dir === basename($base)) {
  334. $base = dirname($base);
  335. }
  336. if ($base === DS || $base === '.') {
  337. $base = '';
  338. }
  339. $this->webroot = $base .'/';
  340. return $base;
  341. }
  342. $file = null;
  343. if ($baseUrl) {
  344. $file = '/' . basename($baseUrl);
  345. $base = dirname($baseUrl);
  346. if ($base === DS || $base === '.') {
  347. $base = '';
  348. }
  349. $this->webroot = $base .'/';
  350. if (strpos($this->webroot, $dir) === false) {
  351. $this->webroot .= $dir . '/' ;
  352. }
  353. if (strpos($this->webroot, $webroot) === false) {
  354. $this->webroot .= $webroot . '/';
  355. }
  356. return $base . $file;
  357. }
  358. return false;
  359. }
  360. /**
  361. * Restructure params in case we're serving a plugin.
  362. *
  363. * @param array $params Array on where to re-set 'controller', 'action', and 'pass' indexes
  364. * @param boolean $reverse
  365. * @return array Restructured array
  366. * @access protected
  367. */
  368. function _restructureParams($params, $reverse = false) {
  369. if ($reverse === true) {
  370. extract(Router::getArgs($params['action']));
  371. $params = array_merge($params, array(
  372. 'controller'=> $params['plugin'],
  373. 'action'=> $params['controller'],
  374. 'pass' => array_merge($pass, $params['pass']),
  375. 'named' => array_merge($named, $params['named'])
  376. ));
  377. $this->plugin = $params['plugin'];
  378. } else {
  379. $params['plugin'] = $params['controller'];
  380. $params['controller'] = $params['action'];
  381. if (isset($params['pass'][0])) {
  382. $params['action'] = $params['pass'][0];
  383. array_shift($params['pass']);
  384. } else {
  385. $params['action'] = null;
  386. }
  387. }
  388. return $params;
  389. }
  390. /**
  391. * Get controller to use, either plugin controller or application controller
  392. *
  393. * @param array $params Array of parameters
  394. * @return mixed name of controller if not loaded, or object if loaded
  395. * @access private
  396. */
  397. function &__getController($params = null) {
  398. if (!is_array($params)) {
  399. $original = $params = $this->params;
  400. }
  401. $controller = false;
  402. $ctrlClass = $this->__loadController($params);
  403. if (!$ctrlClass) {
  404. if (!isset($params['plugin'])) {
  405. $params = $this->_restructureParams($params);
  406. } else {
  407. if (empty($original['pass']) && $original['action'] == 'index') {
  408. $params['action'] = null;
  409. }
  410. $params = $this->_restructureParams($params, true);
  411. }
  412. $ctrlClass = $this->__loadController($params);
  413. if (!$ctrlClass) {
  414. $this->params = $original;
  415. return $controller;
  416. }
  417. } else {
  418. $params = $this->params;
  419. }
  420. $name = $ctrlClass;
  421. $ctrlClass = $ctrlClass . 'Controller';
  422. if (class_exists($ctrlClass)) {
  423. if (strtolower(get_parent_class($ctrlClass)) === strtolower($name . 'AppController') && empty($params['plugin'])) {
  424. $params = $this->_restructureParams($params);
  425. $params = $this->_restructureParams($params, true);
  426. }
  427. $this->params = $params;
  428. $controller =& new $ctrlClass();
  429. }
  430. return $controller;
  431. }
  432. /**
  433. * Load controller and return controller class
  434. *
  435. * @param array $params Array of parameters
  436. * @return string|bool Name of controller class name
  437. * @access private
  438. */
  439. function __loadController($params) {
  440. $pluginName = $pluginPath = $controller = null;
  441. if (!empty($params['plugin'])) {
  442. $this->plugin = $params['plugin'];
  443. $pluginName = Inflector::camelize($params['plugin']);
  444. $pluginPath = $pluginName . '.';
  445. $this->params['controller'] = $this->plugin;
  446. $controller = $pluginName;
  447. }
  448. if (!empty($params['controller'])) {
  449. $this->params['controller'] = $params['controller'];
  450. $controller = Inflector::camelize($params['controller']);
  451. }
  452. if ($pluginPath . $controller) {
  453. if (App::import('Controller', $pluginPath . $controller)) {
  454. return $controller;
  455. }
  456. }
  457. return false;
  458. }
  459. /**
  460. * Returns the REQUEST_URI from the server environment, or, failing that,
  461. * constructs a new one, using the PHP_SELF constant and other variables.
  462. *
  463. * @return string URI
  464. * @access public
  465. */
  466. function uri() {
  467. foreach (array('HTTP_X_REWRITE_URL', 'REQUEST_URI', 'argv') as $var) {
  468. if ($uri = env($var)) {
  469. if ($var == 'argv') {
  470. $uri = $uri[0];
  471. }
  472. break;
  473. }
  474. }
  475. $base = preg_replace('/^\//', '', '' . Configure::read('App.baseUrl'));
  476. if ($base) {
  477. $uri = preg_replace('/^(?:\/)?(?:' . preg_quote($base, '/') . ')?(?:url=)?/', '', $uri);
  478. }
  479. if (PHP_SAPI == 'isapi') {
  480. $uri = preg_replace('/^(?:\/)?(?:\/)?(?:\?)?(?:url=)?/', '', $uri);
  481. }
  482. if (!empty($uri)) {
  483. if (key($_GET) && strpos(key($_GET), '?') !== false) {
  484. unset($_GET[key($_GET)]);
  485. }
  486. $uri = preg_split('/\?/', $uri, 2);
  487. if (isset($uri[1])) {
  488. parse_str($uri[1], $_GET);
  489. }
  490. $uri = $uri[0];
  491. } elseif (empty($uri) && is_string(env('QUERY_STRING'))) {
  492. $uri = env('QUERY_STRING');
  493. }
  494. if (strpos($uri, 'index.php') !== false) {
  495. list(, $uri) = explode('index.php', $uri, 2);
  496. }
  497. if (empty($uri) || $uri == '/' || $uri == '//') {
  498. return '';
  499. }
  500. return str_replace('//', '/', '/' . $uri);
  501. }
  502. /**
  503. * Returns and sets the $_GET[url] derived from the REQUEST_URI
  504. *
  505. * @param string $uri Request URI
  506. * @param string $base Base path
  507. * @return string URL
  508. * @access public
  509. */
  510. function getUrl($uri = null, $base = null) {
  511. if (empty($_GET['url'])) {
  512. if ($uri == null) {
  513. $uri = $this->uri();
  514. }
  515. if ($base == null) {
  516. $base = $this->base;
  517. }
  518. $url = null;
  519. $tmpUri = preg_replace('/^(?:\?)?(?:\/)?/', '', $uri);
  520. $baseDir = preg_replace('/^\//', '', dirname($base)) . '/';
  521. if ($tmpUri === '/' || $tmpUri == $baseDir || $tmpUri == $base) {
  522. $url = $_GET['url'] = '/';
  523. } else {
  524. if ($base && strpos($uri, $base) !== false) {
  525. $elements = explode($base, $uri);
  526. } elseif (preg_match('/^[\/\?\/|\/\?|\?\/]/', $uri)) {
  527. $elements = array(1 => preg_replace('/^[\/\?\/|\/\?|\?\/]/', '', $uri));
  528. } else {
  529. $elements = array();
  530. }
  531. if (!empty($elements[1])) {
  532. $_GET['url'] = $elements[1];
  533. $url = $elements[1];
  534. } else {
  535. $url = $_GET['url'] = '/';
  536. }
  537. if (strpos($url, '/') === 0 && $url != '/') {
  538. $url = $_GET['url'] = substr($url, 1);
  539. }
  540. }
  541. } else {
  542. $url = $_GET['url'];
  543. }
  544. if ($url{0} == '/') {
  545. $url = substr($url, 1);
  546. }
  547. return $url;
  548. }
  549. /**
  550. * Outputs cached dispatch for js, css, img, view cache
  551. *
  552. * @param string $url Requested URL
  553. * @access public
  554. */
  555. function cached($url) {
  556. if (strpos($url, 'css/') !== false || strpos($url, 'js/') !== false || strpos($url, 'img/') !== false) {
  557. if (strpos($url, 'ccss/') === 0) {
  558. include WWW_ROOT . DS . Configure::read('Asset.filter.css');
  559. $this->_stop();
  560. } elseif (strpos($url, 'cjs/') === 0) {
  561. include WWW_ROOT . DS . Configure::read('Asset.filter.js');
  562. $this->_stop();
  563. }
  564. $isAsset = false;
  565. $assets = array('js' => 'text/javascript', 'css' => 'text/css', 'gif' => 'image/gif', 'jpg' => 'image/jpeg', 'png' => 'image/png');
  566. $ext = array_pop(explode('.', $url));
  567. foreach ($assets as $type => $contentType) {
  568. if ($type === $ext) {
  569. if ($type === 'css' || $type === 'js') {
  570. $pos = strpos($url, $type . '/');
  571. } else {
  572. $pos = strpos($url, 'img/');
  573. }
  574. $isAsset = true;
  575. break;
  576. }
  577. }
  578. if ($isAsset === true) {
  579. $ob = @ini_get("zlib.output_compression") !== '1' && extension_loaded("zlib") && (strpos(env('HTTP_ACCEPT_ENCODING'), 'gzip') !== false);
  580. if ($ob && Configure::read('Asset.compress')) {
  581. ob_start();
  582. ob_start('ob_gzhandler');
  583. }
  584. $assetFile = null;
  585. $paths = array();
  586. if ($pos > 0) {
  587. $plugin = substr($url, 0, $pos - 1);
  588. $url = str_replace($plugin . '/', '', $url);
  589. $pluginPaths = Configure::read('pluginPaths');
  590. $count = count($pluginPaths);
  591. for ($i = 0; $i < $count; $i++) {
  592. $paths[] = $pluginPaths[$i] . $plugin . DS . 'vendors' . DS;
  593. }
  594. }
  595. $paths = array_merge($paths, Configure::read('vendorPaths'));
  596. foreach ($paths as $path) {
  597. if (is_file($path . $url) && file_exists($path . $url)) {
  598. $assetFile = $path . $url;
  599. break;
  600. }
  601. }
  602. if ($assetFile !== null) {
  603. $fileModified = filemtime($assetFile);
  604. header("Date: " . date("D, j M Y G:i:s ", $fileModified) . 'GMT');
  605. header('Content-type: ' . $assets[$type]);
  606. header("Expires: " . gmdate("D, j M Y H:i:s", time() + DAY) . " GMT");
  607. header("Cache-Control: cache");
  608. header("Pragma: cache");
  609. if ($type === 'css' || $type === 'js') {
  610. include($assetFile);
  611. } else {
  612. readfile($assetFile);
  613. }
  614. if (Configure::read('Asset.compress')) {
  615. ob_end_flush();
  616. }
  617. return true;
  618. }
  619. }
  620. }
  621. if (Configure::read('Cache.check') === true) {
  622. $path = $this->here;
  623. if ($this->here == '/') {
  624. $path = 'home';
  625. }
  626. $path = strtolower(Inflector::slug($path));
  627. $filename = CACHE . 'views' . DS . $path . '.php';
  628. if (!file_exists($filename)) {
  629. $filename = CACHE . 'views' . DS . $path . '_index.php';
  630. }
  631. if (file_exists($filename)) {
  632. if (!class_exists('View')) {
  633. App::import('Core', 'View');
  634. }
  635. $controller = null;
  636. $view =& new View($controller, false);
  637. return $view->renderCache($filename, getMicrotime());
  638. }
  639. }
  640. return false;
  641. }
  642. }
  643. ?>