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