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: namespace Simpletools\Mvc;
39:
40: 41: 42:
43: class Router extends \Simpletools\Mvc\Common
44: {
45:
46: const NOSLASH_NOINDEX = 1;
47: const SLASH_NOINDEX = 2;
48: const NOSLASH_INDEX = 3;
49: const SLASH_INDEX = 4;
50:
51: private $_duplicate_content = 0;
52:
53:
54: protected $_appDir = '';
55: protected $_forwarded = false;
56: protected $_params = '';
57: protected $_autoRender = true;
58: protected $_errorCode = false;
59: protected $_error = null;
60: protected $_classes = array();
61: protected $_404_error_header = true;
62: protected $_enableRouterHooks = false;
63:
64:
65: private static $_instance = null;
66: protected $_shifts_params = false;
67:
68:
69: protected $_objects = false;
70:
71:
72: protected $_routingNamespaces = array();
73: protected $_activeRoutingNamespace = '';
74: protected $_activeRoutingNamespaceUrlPath = '';
75:
76: private $_settings = array(
77: 'defaultController' => 'index',
78: 'defaultAction' => 'index',
79: 'uri_app_position' => 0,
80: 'redirect_missing_location_to_default' => false,
81: '404_error_header' => true,
82: 'overrideController' => false,
83: 'overrideAction' => 'index'
84: );
85:
86:
87: protected $_view = '';
88: protected $_view_enabled = true;
89:
90: public function __construct(array $settings=null)
91: {
92: if(
93: (isset($settings['applicationDir']) && is_dir($settings['applicationDir']))
94: OR
95: (isset($settings['application_dir']) && is_dir($settings['application_dir']))
96: )
97: {
98: $vext = isset($settings['view_extension']) ? $settings['view_extension'] : 'phtml';
99: $this->_appDir = isset($settings['applicationDir']) ? rtrim($settings['applicationDir'],'/') : rtrim($settings['application_dir'],'/');
100: $this->_view = new \Simpletools\Mvc\View($vext);
101: $this->_settings['uri_app_position'] = isset($settings['uri_app_position']) ? (integer) $settings['uri_app_position'] : 0;
102: $this->_settings['redirect_missing_location_to_default'] = isset($settings['redirect_missing_location_to_default']) ? (boolean) $settings['redirect_missing_location_to_default'] : false;
103: $this->_settings['use_subdomain'] = isset($settings['use_subdomain']) ? $settings['use_subdomain'] : false;
104:
105: $this->_settings['overrideController'] = isset($settings['overrideController']) ? $settings['overrideController'] : false;
106: $this->_settings['overrideAction'] = isset($settings['overrideAction']) ? $settings['overrideAction'] : $this->_settings['overrideAction'];
107:
108: $this->_404_error_header = isset($settings['404_error_header']) ? (boolean) $settings['404_error_header'] : true;
109: $this->_duplicate_content = isset($settings['duplicate_content']) ? (int) $settings['duplicate_content'] : 0;
110:
111: $this->_routingHooks = isset($settings['routingHooks']) ? (bool) $settings['routingHooks'] : false;
112:
113: if(isset($settings['routingNamespaces']))
114: {
115: $this->registerRoutingNamespaces($settings['routingNamespaces']);
116: }
117:
118: if(isset($settings['customRoutes']))
119: {
120: $this->_customRoutes = array();
121: $this->_addCustomRoutes($settings['customRoutes']);
122: }
123:
124: $this->_params = $this->getParams(true);
125:
126: $this->_view->setParams($this->_params,$this->_shifts_params);
127:
128: new \Simpletools\Mvc\Model($this->_appDir,$this->_activeRoutingNamespace);
129: }
130: else
131: {
132: trigger_error("<br />You must to specify correct directory to application folder as an argument of SimpleMVC object constructor to be able to use SimpleMVC framework<br />", E_USER_ERROR);
133: }
134: }
135:
136: protected $_customRoutes = false;
137: protected $_activeCustomRouteArgs = false;
138: protected $_httpMethods = array(
139: "OPTIONS" => "OPTIONS",
140: "GET" => "GET",
141: "HEAD" => "HEAD",
142: "POST" => "POST",
143: "PUT" => "PUT",
144: "DELETE" => "DELETE",
145: "TRACE" => "TRACE",
146: "CONNECT" => "CONNECT",
147: );
148:
149: protected function _addCustomRoutes($routes,$method='ANY')
150: {
151: foreach($routes as $route=>$invoke)
152: {
153: $httpMethod = isset($this->_httpMethods[$route]) ? $this->_httpMethods[$route] : false;
154:
155: if($httpMethod)
156: {
157: $this->_addCustomRoutes($invoke,$httpMethod);
158: }
159: else
160: {
161: $this->_customRoutes[$method][$route] = $this->_parseCustomRoutes($route,$invoke);
162: }
163: }
164: }
165:
166: 167: 168: 169: 170: 171: 172: 173: 174: 175:
176: protected function _parseCustomRoutes($path,$invoke)
177: {
178: preg_match_all('/\{(.*?)\}/', $path, $matches);
179:
180: if(isset($matches[0]))
181: {
182: $path = str_replace(array('\*','\^','\?'),array('.*','^','?'),preg_quote($path,'/'));
183: $map = array();
184: foreach($matches[0] as $index => $match)
185: {
186: $path = str_replace(preg_quote($match),'([A-Za-z0-9\-_]*)',$path);
187: $map[] = $matches[1][$index];
188: }
189: }
190:
191: return array(
192: 'pattern' => '/'.$path.'$/',
193: 'map' => $map,
194: 'invoke' => $invoke
195: );
196: }
197:
198: public function registerRoutingNamespaces($namespaces)
199: {
200: foreach($namespaces as $namespace)
201: {
202: $namespace = str_replace('/','\\',$namespace);
203: $namespace = explode('\\',$namespace);
204:
205: $_namespace = array();
206: foreach($namespace as $n)
207: {
208: $_namespace[] = self::getCorrectControllerName($n);
209: }
210:
211: $this->_routingNamespaces[implode('\\',$_namespace)] = 1;
212: }
213: }
214:
215: public function getActiveRoutingNamespaceDir()
216: {
217: return str_replace('\\',DIRECTORY_SEPARATOR,$this->_activeRoutingNamespace);
218: }
219:
220: public function getActiveRoutingNamespaceUrlPath()
221: {
222: return '/'.$this->_activeRoutingNamespaceUrlPath;
223: }
224:
225: public function getActiveRoutingNamespace($useDirectorySeparator=false)
226: {
227: return $this->_activeRoutingNamespace;
228: }
229:
230: public static function &getInstance(array $settings=null)
231: {
232: if (empty(self::$_instance))
233: self::$_instance = new \Simpletools\Mvc\Router($settings);
234:
235: return self::$_instance;
236: }
237:
238: public static function &settings(array $settings)
239: {
240: if(empty(self::$_instance))
241: self::$_instance = new \Simpletools\Mvc\Router($settings);
242:
243: return self::$_instance;
244: }
245:
246:
247: public function registerObject($objectName,&$object)
248: {
249: $this->registerViewObject($objectName,$object);
250: }
251:
252: public function registerViewObject($objectName,&$object)
253: {
254: $this->_objects[$objectName] = &$object;
255: $this->_view->registerObject($objectName,$object);
256: }
257:
258: public static function &run($dir_emulate=false)
259: {
260: self::getInstance()->dispatch($dir_emulate);
261: return self::$_instance;
262: }
263:
264:
265: public function &dispatch($dir_emulate=false)
266: {
267: if($this->_routingHooks)
268: {
269: \Simpletools\Mvc\RoutingHook::setEnv(array(
270: 'routingNamespace' => $this->_activeRoutingNamespace,
271: 'router' => &$this
272: ));
273:
274: \Simpletools\Mvc\RoutingHook::fire('dispatchStart');
275: }
276:
277: 278: 279:
280: if(
281: isset($this->_settings['use_subdomain']) &&
282: isset($this->_settings['use_subdomain']['controller']) &&
283: isset($this->_settings['use_subdomain']['action'])
284: )
285: {
286: $subdomain = $this->_getSubdomain();
287: if($subdomain)
288: {
289: $old_action = $this->getParam('action');
290: $old_controller = $this->getParam('controller');
291:
292: $this->setParam('controller',$this->_settings['use_subdomain']['controller']);
293: $this->setParam('action',$this->_settings['use_subdomain']['action']);
294: $this->setParam('subdomain',$subdomain);
295: $this->setParam('old_controller',$old_controller);
296: $this->setParam('old_action',$old_action);
297: }
298: }
299:
300: $param = 2;
301:
302: if(
303: ($dir_emulate === true) && '/' != substr($_SERVER['REQUEST_URI'],-1) &&
304: ($this->getParam_($param) === null)
305: )
306: {
307: $this->redirect($_SERVER['REQUEST_URI'],true);
308: }
309:
310: if(!$this->_settings['overrideController'])
311: $this->forwardDispatch($this->getParam('controller'),$this->getParam('action'));
312: else
313: {
314: if(strtolower($this->_settings['overrideController'])==strtolower($this->getParam('controller')))
315: $this->forwardDispatch($this->_settings['overrideController'],'self.reference');
316: else
317: $this->forwardDispatch($this->_settings['overrideController'],$this->_settings['overrideAction']);
318: }
319:
320: return $this;
321: }
322:
323: public function disable404OnError()
324: {
325: $this->_404_error_header = false;
326: }
327:
328: public function enable404OnError()
329: {
330: $this->_404_error_header = true;
331: }
332:
333: public function error($errorCode='v404')
334: {
335: $this->_autoRender = true;
336: if($this->_404_error_header) header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
337: $this->_errorCode = $errorCode;
338:
339: $namespace = $this->_activeRoutingNamespace;
340: $path = (!$namespace) ? '' : str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/';
341: $path = $this->_appDir. '/controllers/'.$path.'ErrorController.php';
342:
343: $className = $namespace.'\ErrorController';
344:
345: if($namespace && !($_c = realpath($path)))
346: {
347: $namespace = '';
348: $path = $this->_appDir.'/controllers/ErrorController.php';
349: if(!($_c = realpath($path)))
350: {
351: trigger_error("<u>SimpleMVC ERROR</u> - Missing ErrorController.php", E_USER_ERROR);
352: }
353: else
354: {
355: $className = 'ErrorController';
356: }
357: }
358: elseif(!$namespace)
359: {
360: $className = 'ErrorController';
361: $path = $this->_appDir.'/controllers/ErrorController.php';
362:
363: if(!($_c = realpath($path)))
364: {
365: trigger_error("<u>SimpleMVC ERROR</u> - Missing ErrorController.php", E_USER_ERROR);
366: }
367: }
368:
369: $this->forward('Error','error');
370: }
371:
372: private function &_getEnv()
373: {
374: $env = new \StdClass();
375: $env->appDir = &$this->_appDir;
376: $env->view = &$this->_view;
377: $env->autoRender = &$this->_autoRender;
378: $env->forwarded = &$this->_forwarded;
379: $env->params = &$this->_params;
380: $env->objects = &$this->_objects;
381: $env->errorCode = &$this->_errorCode;
382: $env->shifts_params = &$this->_shifts_params;
383: $env->classes = &$this->_classes;
384: $env->current_controller = &$this->_current_controller;
385: $env->_404_error_header = &$this->_404_error_header;
386: $env->view_enabled = &$this->_view_enabled;
387: $env->_routingHooks = &$this->_routingHooks;
388:
389: $env->routingNamespaces = &$this->_routingNamespaces;
390: $env->activeRoutingNamespace = &$this->_activeRoutingNamespace;
391: $env->activeRoutingNamespaceUrlPath = &$this->_activeRoutingNamespaceUrlPath;
392:
393: return $env;
394: }
395:
396: private function _callReflectionMethod($controller, $methodName, array $args = array())
397: {
398: $reflection = new \ReflectionMethod($controller, $methodName);
399:
400: $pass = array();
401: foreach($reflection->getParameters() as $param)
402: {
403: $name = $param->getName();
404: if(isset($args[$name]))
405: {
406: $pass[] = $args[$name];
407: }
408: else
409: {
410: try
411: {
412: $pass[] = $param->getDefaultValue();
413: }
414: catch(\Exception $e)
415: {
416: $pass[] = null;
417: }
418: }
419: }
420:
421: return $reflection->invokeArgs($controller, $pass);
422: }
423:
424: private function forwardDispatch($controller,$action,$params=false)
425: {
426: $controller = self::getCorrectControllerName($controller);
427: $action = self::getCorrectActionName($action);
428:
429: $namespace = $this->_activeRoutingNamespace;
430:
431: $path = (!$namespace) ? $controller.'Controller.php' : str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$controller.'Controller.php';
432: $path = $this->_appDir.'/controllers/'.$path;
433:
434: if(($_c = realpath($path)))
435: {
436: require_once($_c);
437: $className = (!$namespace) ? $controller.'Controller' : $namespace."\\".$controller.'Controller';
438:
439: if(class_exists($className))
440: {
441: $this->_current_controller = $controller;
442:
443: $this->_classes[$className] = new $className($this->_getEnv());
444:
445: if($this->_routingHooks)
446: {
447: \Simpletools\Mvc\RoutingHook::fire('beforeControllerInit',array('controller'=>$controller,'action'=>$action));
448: }
449:
450: if(is_callable(array($this->_classes[$className],'init')))
451: {
452: $this->_classes[$className]->init();
453: }
454:
455: if($this->_routingHooks)
456: {
457: \Simpletools\Mvc\RoutingHook::fire('afterControllerInit',array('controller'=>$controller,'action'=>$action));
458: }
459:
460: if(!$this->_forwarded && $this->_autoRender)
461: {
462: $actionMethod = $action.'Action';
463: $this->_forwarded = true;
464:
465: if(is_callable(array($this->_classes[$className],$actionMethod)))
466: {
467: if($this->_routingHooks)
468: {
469: \Simpletools\Mvc\RoutingHook::fire('beforeControllerAction',array('controller'=>$controller,'action'=>$action));
470: }
471:
472: if($this->_activeCustomRouteArgs)
473: {
474: $this->_callReflectionMethod($this->_classes[$className],$actionMethod,$this->_activeCustomRouteArgs);
475: }
476: else
477: {
478: $this->_classes[$className]->$actionMethod();
479: }
480:
481: if($this->_routingHooks)
482: {
483: \Simpletools\Mvc\RoutingHook::fire('afterControllerAction',array('controller'=>$controller,'action'=>$action));
484: }
485: }
486: else
487: {
488: if($this->_routingHooks)
489: {
490: \Simpletools\Mvc\RoutingHook::fire('missingControllerActionError',array('controller'=>$controller,'action'=>$action));
491: }
492:
493: if($this->_autoRender) $this->error('a404');
494: }
495: }
496:
497: }
498: else
499: {
500: if($this->_routingHooks)
501: {
502: \Simpletools\Mvc\RoutingHook::fire('missingControllerError',array('controller'=>$controller,'action'=>$action));
503: }
504:
505: $this->error('c405');
506: }
507:
508: if($this->_autoRender)
509: {
510: $this->_render($controller,$action);
511: }
512: }
513: else
514: {
515: if($this->_routingHooks)
516: {
517: \Simpletools\Mvc\RoutingHook::fire('missingControllerError',array('controller'=>$controller,'action'=>$action));
518: }
519:
520: $this->error('c404');
521: }
522:
523: if($this->_routingHooks)
524: {
525: \Simpletools\Mvc\RoutingHook::fire('dispatchEnd');
526: }
527: }
528:
529: public function forward($controller,$action=null,$params=false)
530: {
531: $this->_autoRender = true;
532:
533: if($controller == 'error' || $action == 'error')
534: $this->_errorCode = 'custom error';
535:
536: $_c = false;
537:
538: $namespace = $this->_activeRoutingNamespace;
539: $orgController = $controller;
540:
541: $n = substr($controller,0,1);
542: if($n=='\\' OR $n == '/')
543: {
544: $controller = trim(str_replace('/','\\',$controller),'\\');
545: $_path = explode('\\',$controller);
546: $controller = array_pop($_path);
547: $namespace = implode('\\',$_path);
548: }
549:
550: $className = (!$namespace) ? $controller.'Controller' : $namespace."\\".$controller.'Controller';
551:
552: if($namespace && strtolower($controller) == 'error')
553: {
554: $path = str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$controller.'Controller.php';
555: $path = $this->_appDir.'/controllers/'.$path;
556:
557: if(
558: !isset($this->_classes[$className]) &&
559: !($_c = realpath($path))
560: )
561: {
562: $namespace = '';
563: $className = $controller.'Controller';
564: }
565: }
566:
567: $path = (!$namespace) ? $controller.'Controller.php' : str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$controller.'Controller.php';
568: $path = $this->_appDir.'/controllers/'.$path;
569:
570: if(
571: isset($this->_classes[$className]) ||
572: ($_c = realpath($path))
573: )
574: {
575: if(!isset($this->_classes[$className]) && $_c)
576: {
577: require($_c);
578: }
579:
580: if(class_exists($className))
581: {
582: if(!isset($this->_classes[$className]))
583: {
584: $this->_classes[$className] = new $className($this->_getEnv());
585: $this->_forwarded = false;
586: }
587:
588: if(is_callable(array($this->_classes[$className],'init')) && !$this->_forwarded)
589: {
590: if($this->_current_controller != $controller)
591: {
592: $this->_classes[$className]->init();
593: $this->_current_controller = $controller;
594: }
595: $this->_forwarded = true;
596: }
597:
598: if($this->_autoRender)
599: {
600: $actionMethod = $action.'Action';
601:
602: if(is_callable(array($this->_classes[$className],$actionMethod)))
603: {
604: $this->_classes[$className]->$actionMethod();
605: }
606: elseif($className!='ErrorController')
607: {
608: return $this->error('a404');
609: }
610: elseif($actionMethod=='errorAction')
611: {
612: throw new \Exception("Missing errorAction() under ErrorController", 1);
613: }
614: else
615: {
616: throw new \Exception("Missing correct error handling structure", 1);
617: }
618: }
619:
620: if($this->_autoRender)
621: {
622: $this->_render($orgController,$action);
623: }
624:
625: }
626: else
627: {
628: $this->error('c405');
629: }
630: }
631: else
632: {
633: $this->error('c404');
634: }
635:
636: }
637:
638:
639: public function enableView()
640: {
641: $this->_view_enabled = true;
642: }
643:
644: public function disableView()
645: {
646: $this->_view_enabled = false;
647: }
648:
649: protected function _render($controller,$view=null)
650: {
651: if(!$this->_view_enabled) return;
652:
653:
654: $namespace = $this->_activeRoutingNamespace;
655:
656: if($this->_routingHooks)
657: {
658: \Simpletools\Mvc\RoutingHook::fire('beforeRenderView',array('controller'=>$controller,'view'=>$view));
659: }
660:
661: $n = substr($controller,0,1);
662: if($n=='\\' OR $n == '/')
663: {
664: $controller = trim(str_replace('/','\\',$controller),'\\');
665: $_path = explode('\\',$controller);
666: $controller = array_pop($_path);
667: $namespace = implode('\\',$_path);
668: }
669:
670: if($namespace)
671: {
672: $namespacePath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace)."/";
673:
674: if(strtolower($view) == 'error')
675: {
676: $path = $this->_appDir.'/views/'.$namespacePath.$controller.'/'.$view.'.'.$this->_view->getViewExt();
677:
678: if(!realpath($path))
679: {
680: $namespacePath = '';
681: }
682: }
683: }
684: else
685: {
686: $namespacePath = '';
687: }
688:
689: $v = realpath($this->_appDir.'/views/'.$namespacePath.$controller.'/'.$view.'.'.$this->_view->getViewExt());
690:
691: if($v)
692: {
693: $this->_autoRender = false;
694: $this->_view->render($v);
695:
696: if($this->_routingHooks)
697: {
698: \Simpletools\Mvc\RoutingHook::fire('afterRenderView',array('controller'=>$controller,'view'=>$view));
699: }
700: }
701: else
702: {
703: if($view != 'error')
704: {
705: if($this->_routingHooks)
706: {
707: \Simpletools\Mvc\RoutingHook::fire('missingViewError',array('controller'=>$controller,'view'=>$view));
708: }
709:
710: $this->error('v404');
711: }
712: else
713: {
714: if($this->_routingHooks)
715: {
716: \Simpletools\Mvc\RoutingHook::fire('missingViewError',array('controller'=>$controller,'view'=>$view));
717: }
718:
719: trigger_error("<u>SimpleMVC ERROR</u> - There is a missing Error View.", E_USER_ERROR);
720: exit;
721: }
722: }
723: }
724:
725: protected function _getSubdomain()
726: {
727: $domain = $_SERVER['SERVER_NAME'];
728: $sub = trim(str_ireplace($this->_settings['use_subdomain']['domain'],'',$domain),'.');
729:
730: if(strtolower($sub) == 'www' || '')
731: return null;
732:
733: return $sub;
734: }
735:
736: public function isController($controller)
737: {
738: $controller = self::getCorrectControllerName($controller);
739: $className = $controller.'Controller';
740:
741: return (isset($this->_classes[$className]) || realpath($this->_appDir.'/controllers/'.$controller.'Controller.php'));
742: }
743:
744: public function getParams($fix_duplicate_content=false)
745: {
746: $_params = array();
747:
748:
749: $SERVER_REQUEST_URI = isset($_SERVER['REQUEST_URI']) ? parse_url('http://simpletools.php'.$_SERVER['REQUEST_URI'],PHP_URL_PATH) : null;
750:
751: if(($p = stripos($SERVER_REQUEST_URI,'#')) !== false)
752: $SERVER_REQUEST_URI = substr($SERVER_REQUEST_URI,0,$p);
753:
754: $params = explode('/',rtrim(substr($SERVER_REQUEST_URI,1),'/'));
755:
756:
757: foreach($params as $index => $param)
758: {
759:
760: $params[$index] = $param = filter_var(urldecode($param),FILTER_SANITIZE_STRING,array('flags'=>FILTER_FLAG_STRIP_HIGH));
761: }
762:
763: if(count($this->_routingNamespaces))
764: {
765: $params_ = array();
766: foreach($params as $param)
767: {
768: $params_[] = self::getCorrectControllerName($param);
769: }
770:
771: $length = count($params);
772: while($length)
773: {
774: $key = implode('\\',array_slice($params_,0,$length));
775: if(isset($this->_routingNamespaces[$key]))
776: {
777: $this->_activeRoutingNamespace = $key;
778:
779: $this->_activeRoutingNamespaceUrlPath = implode('/',array_slice($params,0,$length));
780: $params = array_slice($params,$length);
781:
782: break;
783: }
784:
785: $length--;
786: }
787:
788: unset($params_);
789: }
790:
791: if($this->_settings['uri_app_position'] > 0)
792: {
793: for($i=0; $i<$this->_settings['uri_app_position']; $i++)
794: {
795: $this->_shifts_params[] = array_shift($params);
796: }
797: }
798:
799: if($this->_customRoutes)
800: {
801: $METHOD = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
802:
803: $routes = isset($this->_customRoutes[$METHOD]) ? $this->_customRoutes[$METHOD] : array();
804: $routes = isset($this->_customRoutes['ANY']) ? array_merge($this->_customRoutes['ANY'],$routes) : $routes;
805:
806: foreach($routes as $route)
807: {
808: if(preg_match($route['pattern'], $SERVER_REQUEST_URI, $matches))
809: {
810: $invoke = explode('@',$route['invoke']);
811:
812: $invoke[0] = str_replace('Controller','',$invoke[0]);
813: $invoke[1] = isset($invoke[1]) ? str_replace('Action','',$invoke[1]) : null;
814:
815: $controller = implode('-',preg_split('/(?<=\\w)(?=[A-Z])/', $invoke[0]));
816:
817: $_params['associative']['controller'] = $controller;
818: $_params['associative']['action'] = isset($invoke[1]) ? $invoke[1] : $this->_settings['defaultAction'];
819:
820: array_shift($matches);
821:
822: foreach($matches as $i=>$m)
823: {
824: if(!isset($route['map'][$i])) continue;
825:
826: $this->_activeCustomRouteArgs[$route['map'][$i]] = $m;
827: }
828:
829: return $_params;
830: }
831: }
832: }
833:
834: if(count($params))
835: {
836: $index = count($params)-1;
837: if(($position = strpos($params[$index],'?')) !== false)
838: {
839: $params[$index] = substr($params[$index],0,$position);
840: if($params[$index] == '') $params[$index] = null;
841: }
842:
843: $controllerKey = 0; $actionKey = 1;
844:
845: $_params['associative']['controller'] = null;
846: $_params['associative']['action'] = null;
847:
848: foreach($params as $key => $val)
849: {
850: $_params['number'][$key] = $val;
851:
852: if($key == $controllerKey)
853: {
854: if($val != null) $_params['associative']['controller'] = $val;
855: }
856: else if($key == $actionKey)
857: {
858: if($val != null) $_params['associative']['action'] = $val;
859: }
860: else
861: {
862: if(!($key%2))
863: {
864: $prev_key = $val;
865: $_params['associative'][$val] = '';
866: unset($val);
867: continue;
868: }
869: else
870: {
871: if(isset($prev_key)) $_params['associative'][$prev_key] = $val;
872: }
873: }
874: }
875: }
876:
877: if($fix_duplicate_content)
878: $this->_fixDuplicateContent($_params,$SERVER_REQUEST_URI);
879:
880: if(!isset($_params['associative']['action']))
881: {
882: $_params['associative']['action'] = $this->_settings['defaultAction'];
883: }
884:
885: if(!isset($_params['associative']['controller']))
886: {
887: $_params['associative']['controller'] = $this->_settings['defaultController'];
888: }
889:
890: return $_params;
891: }
892:
893: private function _fixDuplicateContent($_params,$uri_path)
894: {
895: $GET = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
896:
897: switch($this->_duplicate_content)
898: {
899:
900: case 1:
901: {
902: if(
903: (!isset($_params['associative']['action']) && $_params['associative']['controller'] == $this->_settings['defaultController']) OR
904: (count($_params['associative']) == 2 && $_params['associative']['controller'] == $this->_settings['defaultController'] && $_params['associative']['action'] == $this->_settings['defaultAction'])
905: ){
906: $this->redirect('/',false,false,301,$GET);
907: }
908: else if(count($_params['associative']) == 2 && $_params['associative']['action'] == $this->_settings['defaultAction']) {
909: $this->redirect('/'.$_params['associative']['controller'],false,false,301,$GET);
910: }
911: else if(strlen($uri_path) > 1 && substr($uri_path,-1) == '/'){
912: $this->redirect($_params['associative'],false,false,301,$GET);
913: }
914:
915: break;
916: }
917:
918:
919: case 2:
920: {
921: if(
922: (!isset($_params['associative']['action']) && $_params['associative']['controller'] == $this->_settings['defaultController']) OR
923: (count($_params['associative']) == 2 && $_params['associative']['controller'] == $this->_settings['defaultController'] && $_params['associative']['action'] == $this->_settings['defaultAction'])
924: ){
925: $this->redirect('/',false,false,301,$GET);
926: }
927: else if(count($_params['associative']) == 2 && $_params['associative']['action'] == $this->_settings['defaultAction']) {
928: $this->redirect('/'.$_params['associative']['controller'].'/',false,false,301,$GET);
929: }
930: else if(strlen($uri_path) > 1 && substr($uri_path,-1) != '/'){
931: $this->redirect($_params['associative'],true,false,301,$GET);
932: }
933:
934: break;
935: }
936:
937:
938: case 3:
939: {
940: if(!isset($_params['associative']['controller'])){
941: $this->redirect('/index/index',false,false,301,$GET);
942: }
943: else if(!isset($_params['associative']['action'])){
944: $this->redirect('/'.$_params['associative']['controller'].'/index',false,false,301,$GET);
945: }
946: else if(strlen($uri_path) > 1 && substr($uri_path,-1) == '/'){
947: $this->redirect($_params['associative'],false,false,301,$GET);
948: }
949:
950: break;
951: }
952:
953:
954: case 4:
955: {
956: if(!isset($_params['associative']['controller'])){
957: $this->redirect('/index/index/',false,false,301,$GET);
958: }
959: else if(!isset($_params['associative']['action'])){
960: $this->redirect('/'.$_params['associative']['controller'].'/index/',false,false,301,$GET);
961: }
962: else if(strlen($uri_path) > 1 && substr($uri_path,-1) != '/'){
963: $this->redirect($_params['associative'],true,false,301,$GET);
964: }
965:
966: break;
967: }
968: }
969: }
970:
971: public function setParam($id,$value)
972: {
973: $this->_params['associative'][$id] = $value;
974: }
975:
976: public function getDisplayedParam($id)
977: {
978: $params = $this->getParams();
979: return isset($params['associative'][$id]) ? (string) $params['associative'][$id] : null;
980: }
981:
982: public function getDisplayedParam_($id)
983: {
984: $params = $this->getParams();
985: return isset($params['number'][$id]) ? (string) $params['number'][$id] : null;
986: }
987:
988: public function url(Array $urls, $slashEnd=false, $https=false, $absolute=false)
989: {
990: return $this->_view->url($urls, $absolute, $https, $slashEnd);
991: }
992:
993: public function isError404()
994: {
995: if($this->_errorCode !== false) return true;
996: else return false;
997: }
998:
999: public function setViewProperty($key,$value)
1000: {
1001: $this->_view->{$key} = $value;
1002: }
1003:
1004: public function __destruct()
1005: {
1006: if($this->_routingHooks)
1007: {
1008: \Simpletools\Mvc\RoutingHook::fire('routerDestruct');
1009: }
1010: }
1011: }
1012:
1013: ?>