1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:
48: class FrontController {
49: 50: 51: 52: 53: 54:
55: private $queryString;
56:
57: 58: 59: 60: 61: 62:
63: private $pageController;
64:
65: 66: 67: 68: 69: 70:
71: private $encryptedQuery = false;
72:
73: 74: 75: 76: 77: 78:
79: private $controllerAlias = array();
80:
81: 82: 83: 84: 85: 86: 87:
88: private $filters = array();
89:
90: 91: 92: 93: 94: 95:
96: private $currentAlias;
97:
98: 99: 100: 101: 102: 103:
104: private static $logger = null;
105:
106: 107: 108: 109: 110: 111:
112: public function __construct() {
113: self::$logger = new Logger('FrontController');
114:
115: self::$logger->debug('>>__construct()');
116:
117: global $config;
118:
119: self::$logger->debug('Requested URL is ['.$_SERVER['REQUEST_URI'].']');
120:
121:
122: if (isset($_GET['act'])) {
123: self::$logger->debug('Processing direct request to the front controller');
124: $this->pageController = $_GET['act'];
125:
126: }elseif($config->get('app.use.mod.rewrite') && !isset($_GET['tk'])) {
127: self::$logger->debug('Processing a mod_rewrite request');
128: $this->handleModRewriteRequests();
129:
130: }else{
131: if (!isset($_GET['tk'])) {
132: self::$logger->warn('No controller action set for the front controller, URL is ['.$_SERVER['REQUEST_URI'].']');
133: throw new ResourceNotFoundException('The file that you have requested cannot be found!');
134: }else{
135: self::$logger->debug('Processing a direct request to the front controller with an encrypted token param');
136: $this->setEncrypt(true);
137: try {
138: $this->decodeQuery();
139: $this->populateGetVars();
140: if(isset($_GET['act']))
141: $this->pageController = $_GET['act'];
142: else
143: throw new SecurityException('No act param provided in the secure token!');
144: }catch (SecurityException $e) {
145: self::$logger->error('Error while attempting to decode a secure token in the FrontController: '.$e->getMessage());
146: throw new ResourceNotFoundException('The file that you have requested cannot be found!');
147: }
148: }
149: }
150:
151: self::$logger->debug('<<__construct');
152: }
153:
154: 155: 156: 157: 158: 159:
160: public function setEncrypt($encryptedQuery) {
161: $this->encryptedQuery = $encryptedQuery;
162: }
163:
164: 165: 166: 167: 168: 169:
170: private function populateGetVars() {
171:
172: $pairs = explode('&', $this->queryString);
173:
174: foreach($pairs as $pair) {
175: $keyValue = explode('=', $pair);
176: if(count($keyValue) == 2) {
177: $_GET[$keyValue[0]] = $keyValue[1];
178: $_REQUEST[$keyValue[0]] = $keyValue[1];
179: }
180: }
181: }
182:
183: 184: 185: 186: 187: 188: 189:
190: public static function generateSecureURL($params) {
191: global $config;
192:
193: if($config->get('app.use.mod.rewrite'))
194: return $config->get('app.url').'tk/'.FrontController::encodeQuery($params);
195: else
196: return $config->get('app.url').'?tk='.FrontController::encodeQuery($params);
197: }
198:
199: 200: 201: 202: 203: 204: 205:
206: public static function encodeQuery($queryString) {
207: global $config;
208:
209: $td = mcrypt_module_open ('tripledes', '', 'ecb', '');
210: $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
211: mcrypt_generic_init ($td, $config->get('security.query.string.key'), $iv);
212: $encryptedData = mcrypt_generic ($td, $queryString);
213: mcrypt_generic_deinit ($td);
214: mcrypt_module_close ($td);
215:
216: $return = base64_encode($encryptedData);
217:
218: $return = strtr($return, '+/', '-_');
219:
220: return $return;
221: }
222:
223: 224: 225: 226: 227: 228:
229: private function decodeQuery() {
230: global $config;
231:
232: if (!isset($_GET['tk'])) {
233: throw new SecurityException('No token provided for the front controller!');
234: }else{
235: $td = mcrypt_module_open('tripledes', '', 'ecb', '');
236: $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
237:
238: $token = strtr($_GET['tk'], '-_', '+/');
239: $token = base64_decode($token);
240: $this->queryString = trim(mcrypt_decrypt('tripledes', $config->get('security.query.string.key'), $token, 'ecb', $iv));
241: }
242: }
243:
244: 245: 246: 247: 248: 249:
250: public static function decodeQueryParams($tk) {
251: global $config;
252:
253: $td = mcrypt_module_open('tripledes', '', 'ecb', '');
254: $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
255:
256: $token = strtr($tk, '-_', '+/');
257: $token = base64_decode($token);
258: $params = trim(mcrypt_decrypt('tripledes', $config->get('security.query.string.key'), $token, 'ecb', $iv));
259:
260: return $params;
261: }
262:
263: 264: 265: 266: 267: 268:
269: public static function getDecodeQueryParams($tk) {
270: global $config;
271:
272: $td = mcrypt_module_open('tripledes', '', 'ecb', '');
273: $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
274:
275: $token = strtr($tk, '-_', '+/');
276: $token = base64_decode($token);
277: $params = trim(mcrypt_decrypt('tripledes', $config->get('security.query.string.key'), $token, 'ecb', $iv));
278:
279: $pairs = explode('&', $params);
280:
281: $parameters = array();
282:
283: foreach($pairs as $pair) {
284: $split = explode('=', $pair);
285: $parameters[$split[0]] = $split[1];
286: }
287:
288: return $parameters;
289: }
290:
291: 292: 293: 294: 295: 296: 297:
298: public function loadController($allowRedirects = true) {
299: global $config;
300:
301: if($allowRedirects && $config->get('app.check.installed') && $this->pageController != 'Install' && $this->pageController != 'Login') {
302: if(!AlphaDAO::isInstalled()) {
303: self::$logger->info('Invoking the Install controller as the system DB is not installed...');
304: $url = FrontController::generateSecureURL('act=Install');
305: self::$logger->info('Redirecting to ['.$url.']');
306: header('Location: '.$url);
307: exit;
308: }
309: }
310:
311:
312: foreach ($this->filters as $filter)
313: $filter->process();
314:
315: if($allowRedirects) {
316:
317: if($config->get('app.force.front.controller') && $this->hasAlias($this->pageController)) {
318:
319: if(empty($this->currentAlias)) {
320:
321: header('HTTP/1.1 301 Moved Permanently');
322:
323:
324: if (count($_GET) > 1) {
325: $keys = array_keys($_GET);
326: $param = $_GET[$keys[1]];
327:
328: if($keys[1] == 'title')
329: $param = str_replace(' ','_',$param);
330:
331: $URL = $config->get('app.url').'/'.$this->getControllerAlias($this->pageController).'/'.
332: $this->getControllerParam($this->pageController).$param;
333: }else{
334: $URL = $config->get('app.url').'/'.$this->getControllerAlias($this->pageController);
335: }
336:
337: header('Location: '.$URL);
338: exit;
339: }
340: }
341: }
342:
343: try {
344: AlphaController::loadControllerDef($this->pageController);
345: $pageController = new $this->pageController();
346:
347: if(!empty($_POST)) {
348: $pageController->doPOST($_REQUEST);
349: }else{
350: $pageController->doGET($_GET);
351: }
352: }catch (LibraryNotInstalledException $e) {
353: self::$logger->warn($e->getMessage()."\nStacktrace:\n".$e->getTraceAsString()."\nRequest params:\n".var_export($_REQUEST, true)."\nRequested resource:\n".$_SERVER['REQUEST_URI']);
354: throw new LibraryNotInstalledException($e->getMessage());
355: }catch (ResourceNotAllowedException $e) {
356: self::$logger->warn($e->getMessage()."\nStacktrace:\n".$e->getTraceAsString()."\nRequest params:\n".var_export($_REQUEST, true)."\nRequested resource:\n".$_SERVER['REQUEST_URI']);
357: throw new ResourceNotAllowedException($e->getMessage());
358: }catch (ResourceNotFoundException $e) {
359: self::$logger->warn($e->getMessage()."\nStacktrace:\n".$e->getTraceAsString()."\nRequest params:\n".var_export($_REQUEST, true)."\nRequested resource:\n".$_SERVER['REQUEST_URI']);
360: throw new ResourceNotFoundException($e->getMessage());
361: }catch (IllegalArguementException $e) {
362: self::$logger->warn($e->getMessage()."\nStacktrace:\n".$e->getTraceAsString()."\nRequest params:\n".var_export($_REQUEST, true)."\nRequested resource:\n".$_SERVER['REQUEST_URI']);
363:
364: if($config->get('security.client.temp.blacklist.filter.enabled')) {
365: if(isset($_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['REMOTE_ADDR']) && isset($_SERVER['REQUEST_URI'])) {
366: $request = new BadRequestObject();
367: $request->set('client', $_SERVER['HTTP_USER_AGENT']);
368: $request->set('IP', $_SERVER['REMOTE_ADDR']);
369: $request->set('requestedResource', $_SERVER['REQUEST_URI']);
370: $request->save();
371: }
372: }
373:
374: throw new ResourceNotFoundException('The file that you have requested cannot be found!');
375: }catch (AlphaException $e) {
376: self::$logger->warn($e->getMessage()."\nStacktrace:\n".$e->getTraceAsString()."\nRequest params:\n".var_export($_REQUEST, true)."\nRequested resource:\n".$_SERVER['REQUEST_URI']);
377:
378: if($config->get('security.client.temp.blacklist.filter.enabled')) {
379: if(isset($_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['REMOTE_ADDR']) && isset($_SERVER['REQUEST_URI'])) {
380: $request = new BadRequestObject();
381: $request->set('client', $_SERVER['HTTP_USER_AGENT']);
382: $request->set('IP', $_SERVER['REMOTE_ADDR']);
383: $request->set('requestedResource', $_SERVER['REQUEST_URI']);
384: $request->save();
385: }
386: }
387:
388: throw new ResourceNotFoundException('The file that you have requested cannot be found!');
389: }
390: }
391:
392: 393: 394: 395: 396: 397: 398: 399: 400:
401: public function registerAlias($controller, $alias, $param=null) {
402: $this->controllerAlias[$alias] = $controller;
403: if(isset($param))
404: $this->controllerAlias[$alias.'_param'] = $param;
405:
406:
407: $this->handleModRewriteRequests();
408: }
409:
410: 411: 412: 413: 414: 415: 416:
417: public function checkAlias($alias) {
418: if(array_key_exists($alias, $this->controllerAlias))
419: return true;
420: else
421: return false;
422: }
423:
424: 425: 426: 427: 428: 429: 430:
431: public function hasAlias($controller) {
432: if(in_array($controller, $this->controllerAlias))
433: return true;
434: else
435: return false;
436: }
437:
438: 439: 440: 441: 442: 443: 444:
445: public function getAliasController($alias) {
446: if(array_key_exists($alias, $this->controllerAlias))
447: return $this->controllerAlias[$alias];
448: }
449:
450: 451: 452: 453: 454: 455: 456:
457: public function getControllerAlias($controller) {
458: if(in_array($controller, $this->controllerAlias)) {
459: $keys = array_keys($this->controllerAlias, $controller);
460:
461: return $keys[0];
462: }
463: }
464:
465: 466: 467: 468: 469: 470: 471:
472: public function getAliasParam($alias) {
473: if(array_key_exists($alias.'_param', $this->controllerAlias))
474: return $this->controllerAlias[$alias.'_param'];
475: else
476: return '';
477: }
478:
479: 480: 481: 482: 483: 484: 485:
486: public function getControllerParam($controller) {
487: $alias = $this->getControllerAlias($controller);
488: if(array_key_exists($alias.'_param', $this->controllerAlias))
489: return $this->controllerAlias[$alias.'_param'];
490: else
491: return '';
492: }
493:
494: 495: 496: 497: 498: 499: 500: 501: 502:
503: private static function multipleExplode($string, $delimiters = array()){
504:
505: $mainDelim=$delimiters[count($delimiters)-1];
506:
507: array_pop($delimiters);
508:
509: foreach($delimiters as $delimiter) {
510: $string = str_replace($delimiter, $mainDelim, $string);
511: }
512:
513: $result = explode($mainDelim, $string);
514:
515: return $result;
516: }
517:
518: 519: 520: 521: 522:
523: private function handleModRewriteRequests() {
524: self::$logger->debug('>>handleModRewriteRequests');
525: global $config;
526:
527:
528: $request = str_replace($config->get('app.url'), '', 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
529: self::$logger->debug('$request is ['.$request.']');
530: $params = self::multipleExplode($request, array('/','?','&'));
531: self::$logger->debug('$params are ['.var_export($params, true).']');
532:
533: try {
534:
535: if(empty($this->currentAlias) && !empty($params[0]))
536: $this->currentAlias = $params[0];
537:
538:
539: AlphaController::loadControllerDef($params[0]);
540: self::$logger->debug('Page controller name set on the request URL is ['.$params[0].']');
541: $this->pageController = $params[0];
542: }catch (IllegalArguementException $iae) {
543:
544: self::$logger->debug('The supplied controller alias is ['.$this->currentAlias.']');
545:
546:
547: if($this->checkAlias($this->currentAlias)) {
548: $this->pageController = $this->getAliasController($this->currentAlias);
549: self::$logger->debug('Page controller name obtained from the URL alias is ['.$this->pageController.']');
550:
551: if(isset($params[1])) {
552: if(!empty($_POST))
553: $_REQUEST[$this->getAliasParam($this->currentAlias)] = $params[1];
554: else
555: $_GET[$this->getAliasParam($this->currentAlias)] = $params[1];
556: }
557: }
558: }
559:
560: self::$logger->debug('$params are ['.var_export($params, true).']');
561: self::$logger->debug('currentAlias is ['.$this->currentAlias.']');
562:
563:
564: if($this->currentAlias == 'tk') {
565: self::$logger->debug('Setting the GET vars for a mod_rewrite request with a tk param');
566: $this->setEncrypt(true);
567: $this->queryString = FrontController::decodeQueryParams($params[1]);
568: $_GET['tk'] = $params[1];
569: $this->populateGetVars();
570: $this->pageController = $_GET['act'];
571: }else{
572: $count = count($params);
573:
574: for($i = 1; $i < $count; $i+=2) {
575: if(isset($params[$i+1])) {
576: if(!empty($_POST))
577: $_REQUEST[$params[$i]] = $params[$i+1];
578: else
579: $_GET[$params[$i]] = $params[$i+1];
580: }
581: }
582: }
583:
584: self::$logger->debug('$_GET is ['.var_export($_GET, true).']');
585: self::$logger->debug('<<handleModRewriteRequests');
586: }
587:
588: 589: 590: 591: 592: 593:
594: public function getPageController() {
595: return $this->pageController;
596: }
597:
598: 599: 600: 601: 602: 603: 604:
605: public function registerFilter($filterObject) {
606: if($filterObject instanceof AlphaFilterInterface)
607: array_push($this->filters, $filterObject);
608: else
609: throw new IllegalArguementException('Supplied filter object is not a valid AlphaFilterInterface instance!');
610: }
611:
612: 613: 614: 615: 616: 617:
618: public function getFilters() {
619: return $this->filters;
620: }
621: }
622:
623: ?>