1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
22:
23: App::uses('Router', 'Routing');
24: App::uses('CakeRequest', 'Network');
25: App::uses('CakeResponse', 'Network');
26: App::uses('Controller', 'Controller');
27: App::uses('Scaffold', 'Controller');
28: App::uses('View', 'View');
29: App::uses('Debugger', 'Utility');
30:
31: 32: 33: 34: 35: 36: 37:
38: class Dispatcher {
39:
40: 41: 42: 43: 44:
45: public function __construct($base = false) {
46: if ($base !== false) {
47: Configure::write('App.base', $base);
48: }
49: }
50:
51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69:
70: public function dispatch(CakeRequest $request, CakeResponse $response, $additionalParams = array()) {
71: if ($this->asset($request->url, $response) || $this->cached($request->here())) {
72: return;
73: }
74:
75: Router::setRequestInfo($request);
76: $request = $this->parseParams($request, $additionalParams);
77: $controller = $this->_getController($request, $response);
78:
79: if (!($controller instanceof Controller)) {
80: throw new MissingControllerException(array(
81: 'class' => Inflector::camelize($request->params['controller']) . 'Controller',
82: 'plugin' => empty($request->params['plugin']) ? null : Inflector::camelize($request->params['plugin'])
83: ));
84: }
85:
86: return $this->_invoke($controller, $request, $response);
87: }
88:
89: 90: 91: 92: 93: 94: 95: 96: 97: 98:
99: protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) {
100: $controller->constructClasses();
101: $controller->startupProcess();
102:
103: $render = true;
104: $result = $controller->invokeAction($request);
105: if ($result instanceof CakeResponse) {
106: $render = false;
107: $response = $result;
108: }
109:
110: if ($render && $controller->autoRender) {
111: $response = $controller->render();
112: } elseif ($response->body() === null) {
113: $response->body($result);
114: }
115: $controller->shutdownProcess();
116:
117: if (isset($request->params['return'])) {
118: return $response->body();
119: }
120: $response->send();
121: }
122:
123: 124: 125: 126: 127: 128: 129: 130: 131:
132: public function parseParams(CakeRequest $request, $additionalParams = array()) {
133: if (count(Router::$routes) == 0) {
134: $namedExpressions = Router::getNamedExpressions();
135: extract($namedExpressions);
136: $this->_loadRoutes();
137: }
138:
139: $params = Router::parse($request->url);
140: $request->addParams($params);
141:
142: if (!empty($additionalParams)) {
143: $request->addParams($additionalParams);
144: }
145: return $request;
146: }
147:
148: 149: 150: 151: 152: 153: 154:
155: protected function _getController($request, $response) {
156: $ctrlClass = $this->_loadController($request);
157: if (!$ctrlClass) {
158: return false;
159: }
160: $reflection = new ReflectionClass($ctrlClass);
161: if ($reflection->isAbstract() || $reflection->isInterface()) {
162: return false;
163: }
164: return $reflection->newInstance($request, $response);
165: }
166:
167: 168: 169: 170: 171: 172:
173: protected function _loadController($request) {
174: $pluginName = $pluginPath = $controller = null;
175: if (!empty($request->params['plugin'])) {
176: $pluginName = $controller = Inflector::camelize($request->params['plugin']);
177: $pluginPath = $pluginName . '.';
178: }
179: if (!empty($request->params['controller'])) {
180: $controller = Inflector::camelize($request->params['controller']);
181: }
182: if ($pluginPath . $controller) {
183: $class = $controller . 'Controller';
184: App::uses('AppController', 'Controller');
185: App::uses($pluginName . 'AppController', $pluginPath . 'Controller');
186: App::uses($class, $pluginPath . 'Controller');
187: if (class_exists($class)) {
188: return $class;
189: }
190: }
191: return false;
192: }
193:
194: 195: 196: 197: 198:
199: protected function _loadRoutes() {
200: include APP . 'Config' . DS . 'routes.php';
201: }
202:
203: 204: 205: 206: 207: 208:
209: public function cached($path) {
210: if (Configure::read('Cache.check') === true) {
211: if ($path == '/') {
212: $path = 'home';
213: }
214: $path = strtolower(Inflector::slug($path));
215:
216: $filename = CACHE . 'views' . DS . $path . '.php';
217:
218: if (!file_exists($filename)) {
219: $filename = CACHE . 'views' . DS . $path . '_index.php';
220: }
221:
222: if (file_exists($filename)) {
223: App::uses('ThemeView', 'View');
224:
225: $controller = null;
226: $view = new ThemeView($controller);
227: return $view->renderCache($filename, microtime(true));
228: }
229: }
230: return false;
231: }
232:
233: 234: 235: 236: 237: 238: 239:
240: public function asset($url, CakeResponse $response) {
241: if (strpos($url, '..') !== false || strpos($url, '.') === false) {
242: return false;
243: }
244: $filters = Configure::read('Asset.filter');
245: $isCss = (
246: strpos($url, 'ccss/') === 0 ||
247: preg_match('#^(theme/([^/]+)/ccss/)|(([^/]+)(?<!css)/ccss)/#i', $url)
248: );
249: $isJs = (
250: strpos($url, 'cjs/') === 0 ||
251: preg_match('#^/((theme/[^/]+)/cjs/)|(([^/]+)(?<!js)/cjs)/#i', $url)
252: );
253: if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) {
254: $response->statusCode(404);
255: $response->send();
256: return true;
257: } elseif ($isCss) {
258: include WWW_ROOT . DS . $filters['css'];
259: return true;
260: } elseif ($isJs) {
261: include WWW_ROOT . DS . $filters['js'];
262: return true;
263: }
264: $pathSegments = explode('.', $url);
265: $ext = array_pop($pathSegments);
266: $parts = explode('/', $url);
267: $assetFile = null;
268:
269: if ($parts[0] === 'theme') {
270: $themeName = $parts[1];
271: unset($parts[0], $parts[1]);
272: $fileFragment = urldecode(implode(DS, $parts));
273: $path = App::themePath($themeName) . 'webroot' . DS;
274: if (file_exists($path . $fileFragment)) {
275: $assetFile = $path . $fileFragment;
276: }
277: } else {
278: $plugin = Inflector::camelize($parts[0]);
279: if (CakePlugin::loaded($plugin)) {
280: unset($parts[0]);
281: $fileFragment = urldecode(implode(DS, $parts));
282: $pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS;
283: if (file_exists($pluginWebroot . $fileFragment)) {
284: $assetFile = $pluginWebroot . $fileFragment;
285: }
286: }
287: }
288:
289: if ($assetFile !== null) {
290: $this->_deliverAsset($response, $assetFile, $ext);
291: return true;
292: }
293: return false;
294: }
295:
296: 297: 298: 299: 300: 301: 302: 303:
304: protected function _deliverAsset(CakeResponse $response, $assetFile, $ext) {
305: ob_start();
306: $compressionEnabled = Configure::read('Asset.compress') && $response->compress();
307: if ($response->type($ext) == $ext) {
308: $contentType = 'application/octet-stream';
309: $agent = env('HTTP_USER_AGENT');
310: if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
311: $contentType = 'application/octetstream';
312: }
313: $response->type($contentType);
314: }
315: if (!$compressionEnabled) {
316: $response->header('Content-Length', filesize($assetFile));
317: }
318: $response->cache(filemtime($assetFile));
319: $response->send();
320: ob_clean();
321: if ($ext === 'css' || $ext === 'js') {
322: include($assetFile);
323: } else {
324: readfile($assetFile);
325: }
326:
327: if ($compressionEnabled) {
328: ob_end_flush();
329: }
330: }
331: }
332: