dispatcher.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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-2007, Cake Software Foundation, Inc.
  13. * 1785 E. Sahara Avenue, Suite 490-204
  14. * Las Vegas, Nevada 89104
  15. *
  16. * Licensed under The MIT License
  17. * Redistributions of files must retain the above copyright notice.
  18. *
  19. * @filesource
  20. * @copyright Copyright 2005-2007, Cake Software Foundation, Inc.
  21. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  22. * @package cake
  23. * @subpackage cake.cake
  24. * @since CakePHP(tm) v 0.2.9
  25. * @version $Revision$
  26. * @modifiedby $LastChangedBy$
  27. * @lastmodified $Date$
  28. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  29. */
  30. /**
  31. * List of helpers to include
  32. */
  33. uses('router', DS.'controller'.DS.'controller');
  34. /**
  35. * Dispatcher translates URLs to controller-action-paramter triads.
  36. *
  37. * Dispatches the request, creating appropriate models and controllers.
  38. *
  39. * @package cake
  40. * @subpackage cake.cake
  41. */
  42. class Dispatcher extends Object {
  43. /**
  44. * Base URL
  45. * @var string
  46. */
  47. var $base = false;
  48. /**
  49. * Current URL
  50. * @var string
  51. */
  52. var $here = false;
  53. /**
  54. * @var string
  55. */
  56. var $admin = false;
  57. /**
  58. * @var string
  59. */
  60. var $webservices = null;
  61. /**
  62. * @var string
  63. */
  64. var $plugin = null;
  65. /**
  66. * Constructor.
  67. */
  68. function __construct() {
  69. parent::__construct();
  70. }
  71. /**
  72. * Dispatches and invokes given URL, handing over control to the involved controllers, and then renders the results (if autoRender is set).
  73. *
  74. * If no controller of given name can be found, invoke() shows error messages in
  75. * the form of Missing Controllers information. It does the same with Actions (methods of Controllers are called
  76. * Actions).
  77. *
  78. * @param string $url URL information to work on.
  79. * @param array $additionalParams Settings array ("bare", "return"),
  80. * which is melded with the GET and POST params.
  81. * @return boolean Success
  82. */
  83. function dispatch($url, $additionalParams = array()) {
  84. $params = array_merge($this->parseParams($url), $additionalParams);
  85. $missingController = false;
  86. $missingAction = false;
  87. $missingView = false;
  88. $privateAction = false;
  89. $this->base = $this->baseUrl();
  90. if (empty($params['controller'])) {
  91. $missingController = true;
  92. } else {
  93. $ctrlName = Inflector::camelize($params['controller']);
  94. $ctrlClass = $ctrlName.'Controller';
  95. if (!loadController($ctrlName)) {
  96. $pluginName = Inflector::camelize($params['action']);
  97. if (!loadPluginController(Inflector::underscore($ctrlName), $pluginName)) {
  98. if(preg_match('/([\\.]+)/', $ctrlName)) {
  99. Router::setRequestInfo(array($params, array('base' => $this->base, 'webroot' => $this->webroot)));
  100. return $this->cakeError('error404',
  101. array(array('url' => strtolower($ctrlName),
  102. 'message' => 'Was not found on this server',
  103. 'base' => $this->base)));
  104. } elseif(!class_exists($ctrlClass)) {
  105. $missingController = true;
  106. } else {
  107. $params['plugin'] = null;
  108. $this->plugin = null;
  109. }
  110. } else {
  111. $params['plugin'] = Inflector::underscore($ctrlName);
  112. }
  113. } else {
  114. $params['plugin'] = null;
  115. $this->plugin = null;
  116. }
  117. }
  118. if(isset($params['plugin'])) {
  119. $plugin = $params['plugin'];
  120. $pluginName = Inflector::camelize($params['action']);
  121. $pluginClass = $pluginName.'Controller';
  122. $ctrlClass = $pluginClass;
  123. $oldAction = $params['action'];
  124. $params = $this->_restructureParams($params);
  125. $this->plugin = $plugin;
  126. loadPluginModels($plugin);
  127. $this->base = $this->base.'/'.Inflector::underscore($ctrlName);
  128. if(empty($params['controller']) || !class_exists($pluginClass)) {
  129. $params['controller'] = Inflector::underscore($ctrlName);
  130. $ctrlClass = $ctrlName.'Controller';
  131. if (!is_null($params['action'])) {
  132. array_unshift($params['pass'], $params['action']);
  133. }
  134. $params['action'] = $oldAction;
  135. }
  136. }
  137. if (empty($params['action'])) {
  138. $params['action'] = 'index';
  139. }
  140. if(defined('CAKE_ADMIN')) {
  141. if(isset($params[CAKE_ADMIN])) {
  142. $this->admin = '/'.CAKE_ADMIN ;
  143. $url = preg_replace('/'.CAKE_ADMIN.'\//', '', $url);
  144. $params['action'] = CAKE_ADMIN.'_'.$params['action'];
  145. } elseif (strpos($params['action'], CAKE_ADMIN) === 0) {
  146. $privateAction = true;
  147. }
  148. }
  149. $base = Router::stripPlugin($this->base, $this->plugin);
  150. if(defined('BASE_URL')) {
  151. $this->here = $base . $this->admin . $url;
  152. } else {
  153. $this->here = $base . $this->admin . '/' . $url;
  154. }
  155. if ($missingController) {
  156. Router::setRequestInfo(array($params, array('base' => $this->base, 'webroot' => $this->webroot)));
  157. return $this->cakeError('missingController', array(
  158. array(
  159. 'className' => Inflector::camelize($params['controller']."Controller"),
  160. 'webroot' => $this->webroot,
  161. 'url' => $url,
  162. 'base' => $this->base
  163. )
  164. ));
  165. } else {
  166. $controller =& new $ctrlClass();
  167. }
  168. $classMethods = get_class_methods($controller);
  169. $classVars = get_object_vars($controller);
  170. if((in_array($params['action'], $classMethods) || in_array(strtolower($params['action']), $classMethods)) && strpos($params['action'], '_', 0) === 0) {
  171. $privateAction = true;
  172. }
  173. if(!in_array($params['action'], $classMethods) && !in_array(strtolower($params['action']), $classMethods)) {
  174. $missingAction = true;
  175. }
  176. if (in_array(strtolower($params['action']), array(
  177. 'tostring', 'requestaction', 'log', 'cakeerror', 'constructclasses', 'redirect', 'set', 'setaction',
  178. 'validate', 'validateerrors', 'render', 'referer', 'flash', 'flashout', 'generatefieldnames',
  179. 'postconditions', 'cleanupfields', 'beforefilter', 'beforerender', 'afterfilter', 'disablecache', 'paginate'))) {
  180. $missingAction = true;
  181. }
  182. if(in_array('return', array_keys($params)) && $params['return'] == 1) {
  183. $controller->autoRender = false;
  184. }
  185. $controller->base = $this->base;
  186. $controller->here = $this->here;
  187. $controller->webroot = $this->webroot;
  188. $controller->params = $params;
  189. $controller->action = $params['action'];
  190. if (!empty($controller->params['data'])) {
  191. $controller->data =& $controller->params['data'];
  192. } else {
  193. $controller->data = null;
  194. }
  195. $namedArgs = array();
  196. if (is_array($controller->namedArgs)) {
  197. if(array_key_exists($params['action'], $controller->namedArgs)) {
  198. $namedArgs = $controller->namedArgs[$params['action']];
  199. } else {
  200. $namedArgs = $controller->namedArgs;
  201. }
  202. $controller->namedArgs = true;
  203. }
  204. if (!empty($controller->params['pass'])) {
  205. $controller->passed_args =& $controller->params['pass'];
  206. $controller->passedArgs =& $controller->params['pass'];
  207. if ($controller->namedArgs === true) {
  208. $controller->namedArgs = array();
  209. $c = count($controller->passedArgs);
  210. for ($i = 0; $i <= $c; $i++) {
  211. if (isset($controller->passedArgs[$i]) && strpos($controller->passedArgs[$i], $controller->argSeparator) !== false) {
  212. list($argKey, $argVal) = explode($controller->argSeparator, $controller->passedArgs[$i]);
  213. if(empty($namedArgs) || (!empty($namedArgs) && in_array($argKey, array_keys($namedArgs)))) {
  214. $controller->passedArgs[$argKey] = $argVal;
  215. $controller->namedArgs[$argKey] = $argVal;
  216. unset($controller->passedArgs[$i]);
  217. unset($params['pass'][$i]);
  218. }
  219. } else if($controller->argSeparator === '/') {
  220. $ii = $i + 1;
  221. if(isset($controller->passedArgs[$i]) && isset($controller->passedArgs[$ii])) {
  222. $argKey = $controller->passedArgs[$i];
  223. $argVal = $controller->passedArgs[$ii];
  224. if(empty($namedArgs) || (!empty($namedArgs) && in_array($argKey, array_keys($namedArgs)))) {
  225. $controller->passedArgs[$argKey] = $argVal;
  226. $controller->namedArgs[$argKey] = $argVal;
  227. unset($controller->passedArgs[$i], $controller->passedArgs[$ii]);
  228. unset($params['pass'][$i], $params['pass'][$ii]);
  229. }
  230. }
  231. }
  232. }
  233. $controller->passedArgs = am($namedArgs, $controller->passedArgs);
  234. $controller->namedArgs = am($namedArgs, $controller->namedArgs);
  235. }
  236. } else {
  237. $controller->passed_args = null;
  238. $controller->passedArgs = null;
  239. /* set default namedArgs if they exist*/
  240. if ($controller->namedArgs === true) {
  241. $controller->passedArgs = array();
  242. $controller->namedArgs = array();
  243. $controller->passedArgs = am($namedArgs, $controller->passedArgs);
  244. $controller->namedArgs = am($namedArgs, $controller->namedArgs);
  245. }
  246. }
  247. if (!empty($params['bare'])) {
  248. $controller->autoLayout = !$params['bare'];
  249. }
  250. $controller->webservices = $params['webservices'];
  251. $controller->plugin = $this->plugin;
  252. if (isset($params['viewPath'])) {
  253. $controller->viewPath = $params['viewPath'];
  254. }
  255. if (isset($params['layout'])) {
  256. if ($params['layout'] === '') {
  257. $controller->autoLayout = false;
  258. } else {
  259. $controller->layout = $params['layout'];
  260. }
  261. }
  262. foreach(array('components', 'helpers') as $var) {
  263. if (isset($params[$var]) && !empty($params[$var]) && is_array($controller->{$var})) {
  264. $diff = array_diff($params[$var], $controller->{$var});
  265. $controller->{$var} = array_merge($controller->{$var}, $diff);
  266. }
  267. }
  268. if(!is_null($controller->webservices)) {
  269. array_push($controller->components, $controller->webservices);
  270. array_push($controller->helpers, $controller->webservices);
  271. $component =& new Component($controller);
  272. }
  273. Router::setRequestInfo(array($params, array('base' => $this->base, 'here' => $this->here, 'webroot' => $this->webroot, 'passedArgs' => $controller->passedArgs, 'argSeparator' => $controller->argSeparator, 'namedArgs' => $controller->namedArgs, 'webservices' => $controller->webservices)));
  274. $controller->_initComponents();
  275. $controller->constructClasses();
  276. if ($missingAction && !in_array('scaffold', array_keys($classVars))){
  277. $this->start($controller);
  278. return $this->cakeError('missingAction', array(
  279. array(
  280. 'className' => Inflector::camelize($params['controller']."Controller"),
  281. 'action' => $params['action'],
  282. 'webroot' => $this->webroot,
  283. 'url' => $url,
  284. 'base' => $this->base
  285. )
  286. ));
  287. }
  288. if ($privateAction) {
  289. $this->start($controller);
  290. return $this->cakeError('privateAction', array(
  291. array(
  292. 'className' => Inflector::camelize($params['controller']."Controller"),
  293. 'action' => $params['action'],
  294. 'webroot' => $this->webroot,
  295. 'url' => $url,
  296. 'base' => $this->base
  297. )
  298. ));
  299. }
  300. return $this->_invoke($controller, $params, $missingAction);
  301. }
  302. /**
  303. * Invokes given controller's render action if autoRender option is set. Otherwise the contents of the operation are returned as a string.
  304. *
  305. * @param object $controller
  306. * @param array $params
  307. * @param boolean $missingAction
  308. * @return string
  309. */
  310. function _invoke (&$controller, $params, $missingAction = false) {
  311. $this->start($controller);
  312. $classVars = get_object_vars($controller);
  313. if ($missingAction && in_array('scaffold', array_keys($classVars))) {
  314. uses('controller'. DS . 'scaffold');
  315. return new Scaffold($controller, $params);
  316. } else {
  317. $output = call_user_func_array(array(&$controller, $params['action']), empty($params['pass'])? null: $params['pass']);
  318. }
  319. if ($controller->autoRender) {
  320. $output = $controller->render();
  321. }
  322. $controller->output =& $output;
  323. foreach($controller->components as $c) {
  324. $path = preg_split('/\/|\./', $c);
  325. $c = $path[count($path) - 1];
  326. if (isset($controller->{$c}) && is_object($controller->{$c}) && is_callable(array($controller->{$c}, 'shutdown'))) {
  327. if (!array_key_exists('enabled', get_object_vars($controller->{$c})) || $controller->{$c}->enabled == true) {
  328. $controller->{$c}->shutdown($controller);
  329. }
  330. }
  331. }
  332. $controller->afterFilter();
  333. return $controller->output;
  334. }
  335. /**
  336. * Starts up a controller
  337. *
  338. * @param object $controller
  339. */
  340. function start(&$controller) {
  341. if (!empty($controller->beforeFilter)) {
  342. if(is_array($controller->beforeFilter)) {
  343. foreach($controller->beforeFilter as $filter) {
  344. if(is_callable(array($controller,$filter)) && $filter != 'beforeFilter') {
  345. $controller->$filter();
  346. }
  347. }
  348. } else {
  349. if(is_callable(array($controller, $controller->beforeFilter)) && $controller->beforeFilter != 'beforeFilter') {
  350. $controller->{$controller->beforeFilter}();
  351. }
  352. }
  353. }
  354. $controller->beforeFilter();
  355. foreach($controller->components as $c) {
  356. $path = preg_split('/\/|\./', $c);
  357. $c = $path[count($path) - 1];
  358. if (isset($controller->{$c}) && is_object($controller->{$c}) && is_callable(array($controller->{$c}, 'startup'))) {
  359. if (!array_key_exists('enabled', get_object_vars($controller->{$c})) || $controller->{$c}->enabled == true) {
  360. $controller->{$c}->startup($controller);
  361. }
  362. }
  363. }
  364. }
  365. /**
  366. * Returns array of GET and POST parameters. GET parameters are taken from given URL.
  367. *
  368. * @param string $from_url URL to mine for parameter information.
  369. * @return array Parameters found in POST and GET.
  370. */
  371. function parseParams($from_url) {
  372. $Route = Router::getInstance();
  373. extract(Router::getNamedExpressions());
  374. include CONFIGS.'routes.php';
  375. $params = Router::parse($from_url);
  376. if (ini_get('magic_quotes_gpc') == 1) {
  377. if(!empty($_POST)) {
  378. $params['form'] = stripslashes_deep($_POST);
  379. }
  380. } else {
  381. $params['form'] = $_POST;
  382. }
  383. if (isset($params['form']['data'])) {
  384. $params['data'] = $params['form']['data'];
  385. unset($params['form']['data']);
  386. }
  387. if (isset($_GET)) {
  388. if (ini_get('magic_quotes_gpc') == 1) {
  389. $url = stripslashes_deep($_GET);
  390. } else {
  391. $url = $_GET;
  392. }
  393. if (isset($params['url'])) {
  394. $params['url'] = am($params['url'], $url);
  395. } else {
  396. $params['url'] = $url;
  397. }
  398. }
  399. foreach ($_FILES as $name => $data) {
  400. if ($name != 'data') {
  401. $params['form'][$name] = $data;
  402. }
  403. }
  404. if (isset($_FILES['data'])) {
  405. foreach ($_FILES['data'] as $key => $data) {
  406. foreach ($data as $model => $fields) {
  407. foreach ($fields as $field => $value) {
  408. $params['data'][$model][$field][$key] = $value;
  409. }
  410. }
  411. }
  412. }
  413. $params['bare'] = empty($params['ajax'])? (empty($params['bare'])? 0: 1): 1;
  414. $params['webservices'] = empty($params['webservices']) ? null : $params['webservices'];
  415. return $params;
  416. }
  417. /**
  418. * Returns a base URL.
  419. *
  420. * @return string Base URL
  421. */
  422. function baseUrl() {
  423. $htaccess = null;
  424. $base = $this->admin;
  425. $this->webroot = '';
  426. if (defined('BASE_URL')) {
  427. $base = BASE_URL.$this->admin;
  428. }
  429. $docRoot = env('DOCUMENT_ROOT');
  430. $scriptName = env('PHP_SELF');
  431. $r = null;
  432. $appDirName = str_replace('/','\/',preg_quote(APP_DIR));
  433. $webrootDirName = str_replace('/', '\/', preg_quote(WEBROOT_DIR));
  434. if (preg_match('/'.$appDirName.'\\'.DS.$webrootDirName.'/', $docRoot)) {
  435. $this->webroot = '/';
  436. if (preg_match('/^(.*)\/index\.php$/', $scriptName, $r)) {
  437. if(!empty($r[1])) {
  438. return $base.$r[1];
  439. }
  440. }
  441. } else {
  442. if (defined('BASE_URL')) {
  443. $webroot = setUri();
  444. $htaccess = preg_replace('/(?:'.APP_DIR.'\\/(.*)|index\\.php(.*))/i', '', $webroot).APP_DIR.'/'.$webrootDirName.'/';
  445. }
  446. if (preg_match('/^(.*)\\/'.$appDirName.'\\/'.$webrootDirName.'\\/index\\.php$/', $scriptName, $regs)) {
  447. if(APP_DIR === 'app') {
  448. $appDir = null;
  449. } else {
  450. $appDir = '/'.APP_DIR;
  451. }
  452. !empty($htaccess)? $this->webroot = $htaccess : $this->webroot = $regs[1].$appDir.'/';
  453. return $base.$regs[1].$appDir;
  454. } elseif (preg_match('/^(.*)\\/'.$webrootDirName.'([^\/i]*)|index\\\.php$/', $scriptName, $regs)) {
  455. !empty($htaccess)? $this->webroot = $htaccess : $this->webroot = $regs[0].'/';
  456. return $base.$regs[0];
  457. } else {
  458. !empty($htaccess)? $this->webroot = $htaccess : $this->webroot = '/';
  459. return $base;
  460. }
  461. }
  462. return $base;
  463. }
  464. /**
  465. * Enter description here...
  466. *
  467. * @param unknown_type $params
  468. * @return unknown
  469. */
  470. function _restructureParams($params) {
  471. $params['controller'] = $params['action'];
  472. if(isset($params['pass'][0])) {
  473. $params['action'] = $params['pass'][0];
  474. array_shift($params['pass']);
  475. } else {
  476. $params['action'] = null;
  477. }
  478. return $params;
  479. }
  480. }
  481. ?>