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