00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 if (!class_exists('Object')) {
00032 App::import('Core', 'Object');
00033 }
00034
00035
00036
00037
00038
00039
00040 class Router extends Object {
00041
00042
00043
00044
00045
00046
00047 var $routes = array();
00048
00049
00050
00051
00052
00053
00054 var $__admin = null;
00055
00056
00057
00058
00059
00060
00061 var $__prefixes = array();
00062
00063
00064
00065
00066
00067
00068 var $__parseExtensions = false;
00069
00070
00071
00072
00073
00074
00075 var $__validExtensions = null;
00076
00077
00078
00079
00080
00081
00082 var $__named = array(
00083 'Action' => 'index|show|add|create|edit|update|remove|del|delete|view|item',
00084 'Year' => '[12][0-9]{3}',
00085 'Month' => '0[1-9]|1[012]',
00086 'Day' => '0[1-9]|[12][0-9]|3[01]',
00087 'ID' => '[0-9]+',
00088 'UUID' => '[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}'
00089 );
00090
00091
00092
00093
00094
00095
00096 var $named = array(
00097 'default' => array('page', 'fields', 'order', 'limit', 'recursive', 'sort', 'direction', 'step'),
00098 'greedy' => true,
00099 'separator' => ':',
00100 'rules' => false,
00101 );
00102
00103
00104
00105
00106
00107
00108 var $__currentRoute = array();
00109
00110
00111
00112
00113
00114
00115 var $__headerMap = array(
00116 'type' => 'content_type',
00117 'method' => 'request_method',
00118 'server' => 'server_name'
00119 );
00120
00121
00122
00123
00124
00125
00126 var $__resourceMap = array(
00127 array('action' => 'index', 'method' => 'GET', 'id' => false),
00128 array('action' => 'view', 'method' => 'GET', 'id' => true),
00129 array('action' => 'add', 'method' => 'POST', 'id' => false),
00130 array('action' => 'edit', 'method' => 'PUT', 'id' => true),
00131 array('action' => 'delete', 'method' => 'DELETE', 'id' => true),
00132 array('action' => 'edit', 'method' => 'POST', 'id' => true)
00133 );
00134
00135
00136
00137
00138
00139
00140 var $__resourceMapped = array();
00141
00142
00143
00144
00145
00146
00147 var $__params = array();
00148
00149
00150
00151
00152
00153
00154 var $__paths = array();
00155
00156
00157
00158
00159
00160
00161 var $__defaultsMapped = false;
00162
00163
00164
00165
00166
00167
00168
00169 function &getInstance() {
00170 static $instance = array();
00171
00172 if (!$instance) {
00173 $instance[0] =& new Router();
00174 $instance[0]->__admin = Configure::read('Routing.admin');
00175 }
00176 return $instance[0];
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186 function getNamedExpressions() {
00187 $_this =& Router::getInstance();
00188 return $_this->__named;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 function connect($route, $default = array(), $params = array()) {
00202 $_this =& Router::getInstance();
00203
00204 if (!isset($default['action'])) {
00205 $default['action'] = 'index';
00206 }
00207 if (isset($default[$_this->__admin])) {
00208 $default['prefix'] = $_this->__admin;
00209 }
00210 if (isset($default['prefix'])) {
00211 $_this->__prefixes[] = $default['prefix'];
00212 $_this->__prefixes = array_keys(array_flip($_this->__prefixes));
00213 }
00214 $_this->routes[] = array($route, $default, $params);
00215 return $_this->routes;
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 function connectNamed($named, $options = array()) {
00245 $_this =& Router::getInstance();
00246
00247 if (isset($options['argSeparator'])) {
00248 $_this->named['separator'] = $options['argSeparator'];
00249 unset($options['argSeparator']);
00250 }
00251
00252 if ($named === true || $named === false) {
00253 $options = array_merge(array('default' => $named, 'reset' => true, 'greedy' => $named), $options);
00254 $named = array();
00255 }
00256 $options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options);
00257
00258 if ($options['reset'] == true || $_this->named['rules'] === false) {
00259 $_this->named['rules'] = array();
00260 }
00261
00262 if ($options['default']) {
00263 $named = array_merge($named, $_this->named['default']);
00264 }
00265
00266 foreach ($named as $key => $val) {
00267 if (is_numeric($key)) {
00268 $_this->named['rules'][$val] = true;
00269 } else {
00270 $_this->named['rules'][$key] = $val;
00271 }
00272 }
00273 $_this->named['greedy'] = $options['greedy'];
00274 return $_this->named;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 function mapResources($controller, $options = array()) {
00292 $_this =& Router::getInstance();
00293 $options = array_merge(array('prefix' => '/', 'id' => $_this->__named['ID'] . '|' . $_this->__named['UUID']), $options);
00294 $prefix = $options['prefix'];
00295
00296 foreach ((array)$controller as $ctlName) {
00297 $urlName = Inflector::underscore($ctlName);
00298
00299 foreach ($_this->__resourceMap as $params) {
00300 extract($params);
00301 $url = $prefix . $urlName . (($id) ? '/:id' : '');
00302
00303 Router::connect($url,
00304 array('controller' => $urlName, 'action' => $action, '[method]' => $params['method']),
00305 array('id' => $options['id'], 'pass' => array('id'))
00306 );
00307 }
00308 $_this->__resourceMapped[] = $urlName;
00309 }
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 function writeRoute($route, $default, $params) {
00323 if (empty($route) || ($route === '/')) {
00324 return array('/^[\/]*$/', array());
00325 }
00326 $names = array();
00327 $elements = explode('/', $route);
00328
00329 foreach ($elements as $element) {
00330 if (empty($element)) {
00331 continue;
00332 }
00333 $q = null;
00334 $element = trim($element);
00335 $namedParam = strpos($element, ':') !== false;
00336
00337 if ($namedParam && preg_match('/^:([^:]+)$/', $element, $r)) {
00338 if (isset($params[$r[1]])) {
00339 if ($r[1] != 'plugin' && array_key_exists($r[1], $default)) {
00340 $q = '?';
00341 }
00342 $parsed[] = '(?:/(' . $params[$r[1]] . ')' . $q . ')' . $q;
00343 } else {
00344 $parsed[] = '(?:/([^\/]+))?';
00345 }
00346 $names[] = $r[1];
00347 } elseif ($element === '*') {
00348 $parsed[] = '(?:/(.*))?';
00349 } else if ($namedParam && preg_match_all('/(?!\\\\):([a-z_0-9]+)/i', $element, $matches)) {
00350 $matchCount = count($matches[1]);
00351
00352 foreach ($matches[1] as $i => $name) {
00353 $pos = strpos($element, ':' . $name);
00354 $before = substr($element, 0, $pos);
00355 $element = substr($element, $pos + strlen($name) + 1);
00356 $after = null;
00357
00358 if ($i + 1 === $matchCount && $element) {
00359 $after = preg_quote($element);
00360 }
00361
00362 if ($i === 0) {
00363 $before = '/' . $before;
00364 }
00365 $before = preg_quote($before, '#');
00366
00367 if (isset($params[$name])) {
00368 if (isset($default[$name]) && $name != 'plugin') {
00369 $q = '?';
00370 }
00371 $parsed[] = '(?:' . $before . '(' . $params[$name] . ')' . $q . $after . ')' . $q;
00372 } else {
00373 $parsed[] = '(?:' . $before . '([^\/]+)' . $after . ')?';
00374 }
00375 $names[] = $name;
00376 }
00377 } else {
00378 $parsed[] = '/' . $element;
00379 }
00380 }
00381 return array('#^' . join('', $parsed) . '[\/]*$#', $names);
00382 }
00383
00384
00385
00386
00387
00388
00389
00390 function prefixes() {
00391 $_this =& Router::getInstance();
00392 return $_this->__prefixes;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403 function parse($url) {
00404 $_this =& Router::getInstance();
00405 if (!$_this->__defaultsMapped) {
00406 $_this->__connectDefaultRoutes();
00407 }
00408 $out = array('pass' => array(), 'named' => array());
00409 $r = $ext = null;
00410
00411 if (ini_get('magic_quotes_gpc') === '1') {
00412 $url = stripslashes_deep($url);
00413 }
00414
00415 if ($url && strpos($url, '/') !== 0) {
00416 $url = '/' . $url;
00417 }
00418 if (strpos($url, '?') !== false) {
00419 $url = substr($url, 0, strpos($url, '?'));
00420 }
00421 extract($_this->__parseExtension($url));
00422
00423 foreach ($_this->routes as $i => $route) {
00424 if (count($route) === 3) {
00425 $route = $_this->compile($i);
00426 }
00427
00428 if (($r = $_this->__matchRoute($route, $url)) !== false) {
00429 $_this->__currentRoute[] = $route;
00430 list($route, $regexp, $names, $defaults, $params) = $route;
00431 $argOptions = array();
00432
00433 if (array_key_exists('named', $params)) {
00434 $argOptions['named'] = $params['named'];
00435 unset($params['named']);
00436 }
00437 if (array_key_exists('greedy', $params)) {
00438 $argOptions['greedy'] = $params['greedy'];
00439 unset($params['greedy']);
00440 }
00441 array_shift($r);
00442
00443 foreach ($names as $name) {
00444 $out[$name] = null;
00445 }
00446 if (is_array($defaults)) {
00447 foreach ($defaults as $name => $value) {
00448 if (preg_match('#[a-zA-Z_\-]#i', $name)) {
00449 $out[$name] = $value;
00450 } else {
00451 $out['pass'][] = $value;
00452 }
00453 }
00454 }
00455
00456 foreach ($r as $key => $found) {
00457 if (empty($found) && $found != 0) {
00458 continue;
00459 }
00460
00461 if (isset($names[$key])) {
00462 $out[$names[$key]] = $_this->stripEscape($found);
00463 } else {
00464 $argOptions['context'] = array('action' => $out['action'], 'controller' => $out['controller']);
00465 extract($_this->getArgs($found, $argOptions));
00466 $out['pass'] = array_merge($out['pass'], $pass);
00467 $out['named'] = $named;
00468 }
00469 }
00470
00471 if (isset($params['pass'])) {
00472 for ($j = count($params['pass']) - 1; $j > -1; $j--) {
00473 if (isset($out[$params['pass'][$j]])) {
00474 array_unshift($out['pass'], $out[$params['pass'][$j]]);
00475 }
00476 }
00477 }
00478 break;
00479 }
00480 }
00481
00482 if (!empty($ext)) {
00483 $out['url']['ext'] = $ext;
00484 }
00485 return $out;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495 function __matchRoute($route, $url) {
00496 list($route, $regexp, $names, $defaults) = $route;
00497
00498 if (!preg_match($regexp, $url, $r)) {
00499 return false;
00500 } else {
00501 foreach ($defaults as $key => $val) {
00502 if ($key{0} === '[' && preg_match('/^\[(\w+)\]$/', $key, $header)) {
00503 if (isset($this->__headerMap[$header[1]])) {
00504 $header = $this->__headerMap[$header[1]];
00505 } else {
00506 $header = 'http_' . $header[1];
00507 }
00508
00509 $val = (array)$val;
00510 $h = false;
00511
00512 foreach ($val as $v) {
00513 if (env(strtoupper($header)) === $v) {
00514 $h = true;
00515 }
00516 }
00517 if (!$h) {
00518 return false;
00519 }
00520 }
00521 }
00522 }
00523 return $r;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533 function compile($i) {
00534 $route = $this->routes[$i];
00535
00536 list($pattern, $names) = $this->writeRoute($route[0], $route[1], $route[2]);
00537 $this->routes[$i] = array(
00538 $route[0], $pattern, $names,
00539 array_merge(array('plugin' => null, 'controller' => null), (array)$route[1]),
00540 $route[2]
00541 );
00542 return $this->routes[$i];
00543 }
00544
00545
00546
00547
00548
00549
00550
00551 function __parseExtension($url) {
00552 $ext = null;
00553
00554 if ($this->__parseExtensions) {
00555 if (preg_match('/\.[0-9a-zA-Z]*$/', $url, $match) === 1) {
00556 $match = substr($match[0], 1);
00557 if (empty($this->__validExtensions)) {
00558 $url = substr($url, 0, strpos($url, '.' . $match));
00559 $ext = $match;
00560 } else {
00561 foreach ($this->__validExtensions as $name) {
00562 if (strcasecmp($name, $match) === 0) {
00563 $url = substr($url, 0, strpos($url, '.' . $name));
00564 $ext = $match;
00565 }
00566 }
00567 }
00568 }
00569 if (empty($ext)) {
00570 $ext = 'html';
00571 }
00572 }
00573 return compact('ext', 'url');
00574 }
00575
00576
00577
00578
00579
00580
00581
00582 function __connectDefaultRoutes() {
00583 if ($this->__defaultsMapped) {
00584 return;
00585 }
00586
00587 if ($this->__admin) {
00588 $params = array('prefix' => $this->__admin, $this->__admin => true);
00589 }
00590
00591 if ($plugins = Configure::listObjects('plugin')) {
00592 foreach ($plugins as $key => $value) {
00593 $plugins[$key] = Inflector::underscore($value);
00594 }
00595
00596 $match = array('plugin' => implode('|', $plugins));
00597 $this->connect('/:plugin/:controller/:action
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 function setRequestInfo($params) {
00626 $_this =& Router::getInstance();
00627 $defaults = array('plugin' => null, 'controller' => null, 'action' => null);
00628 $params[0] = array_merge($defaults, (array)$params[0]);
00629 $params[1] = array_merge($defaults, (array)$params[1]);
00630 list($_this->__params[], $_this->__paths[]) = $params;
00631
00632 if (count($_this->__paths)) {
00633 if (isset($_this->__paths[0]['namedArgs'])) {
00634 foreach ($_this->__paths[0]['namedArgs'] as $arg => $value) {
00635 $_this->named['rules'][$arg] = true;
00636 }
00637 }
00638 }
00639 }
00640
00641
00642
00643
00644
00645
00646
00647
00648 function getParams($current = false) {
00649 $_this =& Router::getInstance();
00650 if ($current) {
00651 return $_this->__params[count($_this->__params) - 1];
00652 }
00653 if (isset($_this->__params[0])) {
00654 return $_this->__params[0];
00655 }
00656 return array();
00657 }
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 function getParam($name = 'controller', $current = false) {
00668 $params = Router::getParams($current);
00669 if (isset($params[$name])) {
00670 return $params[$name];
00671 }
00672 return null;
00673 }
00674
00675
00676
00677
00678
00679
00680
00681
00682 function getPaths($current = false) {
00683 $_this =& Router::getInstance();
00684 if ($current) {
00685 return $_this->__paths[count($_this->__paths) - 1];
00686 }
00687 if (!isset($_this->__paths[0])) {
00688 return array('base' => null);
00689 }
00690 return $_this->__paths[0];
00691 }
00692
00693
00694
00695
00696
00697
00698
00699 function reload() {
00700 $_this =& Router::getInstance();
00701 foreach (get_class_vars('Router') as $key => $val) {
00702 $_this->{$key} = $val;
00703 }
00704 $_this->__admin = Configure::read('Routing.admin');
00705 }
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 function promote($which = null) {
00716 $_this =& Router::getInstance();
00717 if ($which === null) {
00718 $which = count($_this->routes) - 1;
00719 }
00720 if (!isset($_this->routes[$which])) {
00721 return false;
00722 }
00723 $route = $_this->routes[$which];
00724 unset($_this->routes[$which]);
00725 array_unshift($_this->routes, $route);
00726 return true;
00727 }
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 function url($url = null, $full = false) {
00751 $_this =& Router::getInstance();
00752 $defaults = $params = array('plugin' => null, 'controller' => null, 'action' => 'index');
00753
00754 if (is_bool($full)) {
00755 $escape = false;
00756 } else {
00757 extract(array_merge(array('escape' => false, 'full' => false), $full));
00758 }
00759
00760 if (!empty($_this->__params)) {
00761 if (isset($this) && !isset($this->params['requested'])) {
00762 $params = $_this->__params[0];
00763 } else {
00764 $params = end($_this->__params);
00765 }
00766 }
00767 $path = array('base' => null);
00768
00769 if (!empty($_this->__paths)) {
00770 if (isset($this) && !isset($this->params['requested'])) {
00771 $path = $_this->__paths[0];
00772 } else {
00773 $path = end($_this->__paths);
00774 }
00775 }
00776 $base = $path['base'];
00777 $extension = $output = $mapped = $q = $frag = null;
00778
00779 if (is_array($url)) {
00780 if (isset($url['base']) && $url['base'] === false) {
00781 $base = null;
00782 unset($url['base']);
00783 }
00784 if (isset($url['full_base']) && $url['full_base'] === true) {
00785 $full = true;
00786 unset($url['full_base']);
00787 }
00788 if (isset($url['?'])) {
00789 $q = $url['?'];
00790 unset($url['?']);
00791 }
00792 if (isset($url['#'])) {
00793 $frag = '#' . urlencode($url['#']);
00794 unset($url['#']);
00795 }
00796 if (empty($url['action'])) {
00797 if (empty($url['controller']) || $params['controller'] === $url['controller']) {
00798 $url['action'] = $params['action'];
00799 } else {
00800 $url['action'] = 'index';
00801 }
00802 }
00803 if ($_this->__admin) {
00804 if (!isset($url[$_this->__admin]) && !empty($params[$_this->__admin])) {
00805 $url[$_this->__admin] = true;
00806 } elseif ($_this->__admin && isset($url[$_this->__admin]) && !$url[$_this->__admin]) {
00807 unset($url[$_this->__admin]);
00808 }
00809 }
00810 $plugin = false;
00811
00812 if (array_key_exists('plugin', $url)) {
00813 $plugin = $url['plugin'];
00814 }
00815
00816 $url = array_merge(array('controller' => $params['controller'], 'plugin' => $params['plugin']), Set::filter($url, true));
00817
00818 if ($plugin !== false) {
00819 $url['plugin'] = $plugin;
00820 }
00821
00822 if (isset($url['ext'])) {
00823 $extension = '.' . $url['ext'];
00824 unset($url['ext']);
00825 }
00826 $match = false;
00827
00828 foreach ($_this->routes as $i => $route) {
00829 if (count($route) === 3) {
00830 $route = $_this->compile($i);
00831 }
00832 $originalUrl = $url;
00833
00834 if (isset($route[4]['persist'], $_this->__params[0])) {
00835 $url = array_merge(array_intersect_key($params, Set::combine($route[4]['persist'], '/')), $url);
00836 }
00837 if ($match = $_this->mapRouteElements($route, $url)) {
00838 $output = trim($match, '/');
00839 $url = array();
00840 break;
00841 }
00842 $url = $originalUrl;
00843 }
00844
00845 $named = $args = array();
00846 $skip = array(
00847 'bare', 'action', 'controller', 'plugin', 'ext', '?', '#', 'prefix', $_this->__admin
00848 );
00849
00850 $keys = array_values(array_diff(array_keys($url), $skip));
00851 $count = count($keys);
00852
00853 // Remove this once parsed URL parameters can be inserted into 'pass'
00854 for ($i = 0; $i < $count; $i++) {
00855 if ($i === 0 && is_numeric($keys[$i]) && in_array('id', $keys)) {
00856 $args[0] = $url[$keys[$i]];
00857 } elseif (is_numeric($keys[$i]) || $keys[$i] === 'id') {
00858 $args[] = $url[$keys[$i]];
00859 } else {
00860 $named[$keys[$i]] = $url[$keys[$i]];
00861 }
00862 }
00863
00864 if ($match === false) {
00865 list($args, $named) = array(Set::filter($args, true), Set::filter($named));
00866 if (!empty($url[$_this->__admin])) {
00867 $url['action'] = str_replace($_this->__admin . '_', '', $url['action']);
00868 }
00869
00870 if (empty($named) && empty($args) && (!isset($url['action']) || $url['action'] === 'index')) {
00871 $url['action'] = null;
00872 }
00873
00874 $urlOut = Set::filter(array($url['controller'], $url['action']));
00875
00876 if (isset($url['plugin']) && $url['plugin'] != $url['controller']) {
00877 array_unshift($urlOut, $url['plugin']);
00878 }
00879
00880 if ($_this->__admin && isset($url[$_this->__admin])) {
00881 array_unshift($urlOut, $_this->__admin);
00882 }
00883 $output = join('/', $urlOut) . '/';
00884 }
00885
00886 if (!empty($args)) {
00887 $args = join('/', $args);
00888 if ($output{strlen($output) - 1} != '/') {
00889 $args = '/'. $args;
00890 }
00891 $output .= $args;
00892 }
00893
00894 if (!empty($named)) {
00895 foreach ($named as $name => $value) {
00896 $output .= '/' . $name . $_this->named['separator'] . $value;
00897 }
00898 }
00899 $output = str_replace('//', '/', $base . '/' . $output);
00900 } else {
00901 if (((strpos($url, '://')) || (strpos($url, 'javascript:') === 0) || (strpos($url, 'mailto:') === 0)) || (!strncmp($url, '#', 1))) {
00902 return $url;
00903 }
00904 if (empty($url)) {
00905 if (!isset($path['here'])) {
00906 $path['here'] = '/';
00907 }
00908 $output = $path['here'];
00909 } elseif (substr($url, 0, 1) === '/') {
00910 $output = $base . $url;
00911 } else {
00912 $output = $base . '/';
00913 if ($_this->__admin && isset($params[$_this->__admin])) {
00914 $output .= $_this->__admin . '/';
00915 }
00916 if (!empty($params['plugin']) && $params['plugin'] !== $params['controller']) {
00917 $output .= Inflector::underscore($params['plugin']) . '/';
00918 }
00919 $output .= Inflector::underscore($params['controller']) . '/' . $url;
00920 }
00921 $output = str_replace('//', '/', $output);
00922 }
00923 if ($full && defined('FULL_BASE_URL')) {
00924 $output = FULL_BASE_URL . $output;
00925 }
00926 if (!empty($extension) && substr($output, -1) === '/') {
00927 $output = substr($output, 0, -1);
00928 }
00929
00930 return $output . $extension . $_this->queryString($q, array(), $escape) . $frag;
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941 function mapRouteElements($route, $url) {
00942 if (isset($route[3]['prefix'])) {
00943 $prefix = $route[3]['prefix'];
00944 unset($route[3]['prefix']);
00945 }
00946
00947 $pass = array();
00948 $defaults = $route[3];
00949 $routeParams = $route[2];
00950 $params = Set::diff($url, $defaults);
00951 $urlInv = array_combine(array_values($url), array_keys($url));
00952
00953 $i = 0;
00954 while (isset($defaults[$i])) {
00955 if (isset($urlInv[$defaults[$i]])) {
00956 if (!in_array($defaults[$i], $url) && is_int($urlInv[$defaults[$i]])) {
00957 return false;
00958 }
00959 unset($urlInv[$defaults[$i]], $defaults[$i]);
00960 } else {
00961 return false;
00962 }
00963 $i++;
00964 }
00965
00966 foreach ($params as $key => $value) {
00967 if (is_int($key)) {
00968 $pass[] = $value;
00969 unset($params[$key]);
00970 }
00971 }
00972 list($named, $params) = Router::getNamedElements($params);
00973
00974 if (!strpos($route[0], '*') && (!empty($pass) || !empty($named))) {
00975 return false;
00976 }
00977
00978 $urlKeys = array_keys($url);
00979 $paramsKeys = array_keys($params);
00980 $defaultsKeys = array_keys($defaults);
00981
00982 if (!empty($params)) {
00983 if (array_diff($paramsKeys, $routeParams) != array()) {
00984 return false;
00985 }
00986 $required = array_values(array_diff($routeParams, $urlKeys));
00987 $reqCount = count($required);
00988
00989 for ($i = 0; $i < $reqCount; $i++) {
00990 if (array_key_exists($required[$i], $defaults) && $defaults[$required[$i]] === null) {
00991 unset($required[$i]);
00992 }
00993 }
00994 }
00995 $isFilled = true;
00996
00997 if (!empty($routeParams)) {
00998 $filled = array_intersect_key($url, array_combine($routeParams, array_keys($routeParams)));
00999 $isFilled = (array_diff($routeParams, array_keys($filled)) === array());
01000 if (!$isFilled && empty($params)) {
01001 return false;
01002 }
01003 }
01004
01005 if (empty($params)) {
01006 return Router::__mapRoute($route, array_merge($url, compact('pass', 'named', 'prefix')));
01007 } elseif (!empty($routeParams) && !empty($route[3])) {
01008
01009 if (!empty($required)) {
01010 return false;
01011 }
01012 foreach ($params as $key => $val) {
01013 if ((!isset($url[$key]) || $url[$key] != $val) || (!isset($defaults[$key]) || $defaults[$key] != $val) && !in_array($key, $routeParams)) {
01014 if (!isset($defaults[$key])) {
01015 continue;
01016 }
01017 return false;
01018 }
01019 }
01020 } else {
01021 if (empty($required) && $defaults['plugin'] === $url['plugin'] && $defaults['controller'] === $url['controller'] && $defaults['action'] === $url['action']) {
01022 return Router::__mapRoute($route, array_merge($url, compact('pass', 'named', 'prefix')));
01023 }
01024 return false;
01025 }
01026
01027 if (!empty($route[4])) {
01028 foreach ($route[4] as $key => $reg) {
01029 if (array_key_exists($key, $url) && !preg_match('#' . $reg . '#', $url[$key])) {
01030 return false;
01031 }
01032 }
01033 }
01034 return Router::__mapRoute($route, array_merge($filled, compact('pass', 'named', 'prefix')));
01035 }
01036
01037
01038
01039
01040
01041
01042
01043
01044 function __mapRoute($route, $params = array()) {
01045 if (isset($params['plugin']) && isset($params['controller']) && $params['plugin'] === $params['controller']) {
01046 unset($params['controller']);
01047 }
01048
01049 if (isset($params['prefix']) && isset($params['action'])) {
01050 $params['action'] = str_replace($params['prefix'] . '_', '', $params['action']);
01051 unset($params['prefix']);
01052 }
01053
01054 if (isset($params['pass']) && is_array($params['pass'])) {
01055 $params['pass'] = implode('/', Set::filter($params['pass'], true));
01056 } elseif (!isset($params['pass'])) {
01057 $params['pass'] = '';
01058 }
01059
01060 if (isset($params['named'])) {
01061 if (is_array($params['named'])) {
01062 $count = count($params['named']);
01063 $keys = array_keys($params['named']);
01064 $named = array();
01065
01066 for ($i = 0; $i < $count; $i++) {
01067 $named[] = $keys[$i] . $this->named['separator'] . $params['named'][$keys[$i]];
01068 }
01069 $params['named'] = join('/', $named);
01070 }
01071 $params['pass'] = str_replace('//', '/', $params['pass'] . '/' . $params['named']);
01072 }
01073 $out = $route[0];
01074
01075 foreach ($route[2] as $key) {
01076 $string = null;
01077 if (isset($params[$key])) {
01078 $string = $params[$key];
01079 unset($params[$key]);
01080 } elseif (strpos($out, $key) != strlen($out) - strlen($key)) {
01081 $key = $key . '/';
01082 }
01083 $out = str_replace(':' . $key, $string, $out);
01084 }
01085
01086 if (strpos($route[0], '*')) {
01087 $out = str_replace('*', $params['pass'], $out);
01088 }
01089
01090 return $out;
01091 }
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 function getNamedElements($params, $controller = null, $action = null) {
01103 $_this =& Router::getInstance();
01104 $named = array();
01105
01106 foreach ($params as $param => $val) {
01107 if (isset($_this->named['rules'][$param])) {
01108 $rule = $_this->named['rules'][$param];
01109 if (Router::matchNamed($param, $val, $rule, compact('controller', 'action'))) {
01110 $named[$param] = $val;
01111 unset($params[$param]);
01112 }
01113 }
01114 }
01115 return array($named, $params);
01116 }
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128 function matchNamed($param, $val, $rule, $context = array()) {
01129 if ($rule === true || $rule === false) {
01130 return $rule;
01131 }
01132 if (is_string($rule)) {
01133 $rule = array('match' => $rule);
01134 }
01135 if (!is_array($rule)) {
01136 return false;
01137 }
01138
01139 $controllerMatches = !isset($rule['controller'], $context['controller']) || in_array($context['controller'], (array)$rule['controller']);
01140 if (!$controllerMatches) {
01141 return false;
01142 }
01143 $actionMatches = !isset($rule['action'], $context['action']) || in_array($context['action'], (array)$rule['action']);
01144 if (!$actionMatches) {
01145 return false;
01146 }
01147 $valueMatches = !isset($rule['match']) || preg_match(sprintf('/%s/', $rule['match']), $val);
01148 return $valueMatches;
01149 }
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160 function queryString($q, $extra = array(), $escape = false) {
01161 if (empty($q) && empty($extra)) {
01162 return null;
01163 }
01164 $join = '&';
01165 if ($escape === true) {
01166 $join = '&';
01167 }
01168 $out = '';
01169
01170 if (is_array($q)) {
01171 $q = array_merge($extra, $q);
01172 } else {
01173 $out = $q;
01174 $q = $extra;
01175 }
01176 $out .= http_build_query($q, null, $join);
01177 if (isset($out[0]) && $out[0] != '?') {
01178 $out = '?' . $out;
01179 }
01180 return $out;
01181 }
01182
01183
01184
01185
01186
01187
01188
01189 function normalize($url = '/') {
01190 if (is_array($url)) {
01191 $url = Router::url($url);
01192 } elseif (preg_match('/^[a-z\-]+:\/\//', $url)) {
01193 return $url;
01194 }
01195 $paths = Router::getPaths();
01196
01197 if (!empty($paths['base']) && stristr($url, $paths['base'])) {
01198 $url = preg_replace('/^' . preg_quote($paths['base'], '/') . '/', '', $url, 1);
01199 }
01200 $url = '/' . $url;
01201
01202 while (strpos($url, '//') !== false) {
01203 $url = str_replace('//', '/', $url);
01204 }
01205 $url = preg_replace('/(?:(\/$))/', '', $url);
01206
01207 if (empty($url)) {
01208 return '/';
01209 }
01210 return $url;
01211 }
01212
01213
01214
01215
01216
01217
01218
01219 function requestRoute() {
01220 $_this =& Router::getInstance();
01221 return $_this->__currentRoute[0];
01222 }
01223
01224
01225
01226
01227
01228
01229
01230 function currentRoute() {
01231 $_this =& Router::getInstance();
01232 return $_this->__currentRoute[count($_this->__currentRoute) - 1];
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243 function stripPlugin($base, $plugin = null) {
01244 if ($plugin != null) {
01245 $base = preg_replace('/(?:' . $plugin . ')/', '', $base);
01246 $base = str_replace('//', '', $base);
01247 $pos1 = strrpos($base, '/');
01248 $char = strlen($base) - 1;
01249
01250 if ($pos1 === $char) {
01251 $base = substr($base, 0, $char);
01252 }
01253 }
01254 return $base;
01255 }
01256
01257
01258
01259
01260
01261
01262
01263
01264 function stripEscape($param) {
01265 $_this =& Router::getInstance();
01266 if (!is_array($param) || empty($param)) {
01267 if (is_bool($param)) {
01268 return $param;
01269 }
01270
01271 return preg_replace('/^(?:[\\t ]*(?:-!)+)/', '', $param);
01272 }
01273
01274 foreach ($param as $key => $value) {
01275 if (is_string($value)) {
01276 $return[$key] = preg_replace('/^(?:[\\t ]*(?:-!)+)/', '', $value);
01277 } else {
01278 foreach ($value as $array => $string) {
01279 $return[$key][$array] = $_this->stripEscape($string);
01280 }
01281 }
01282 }
01283 return $return;
01284 }
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301 function parseExtensions() {
01302 $_this =& Router::getInstance();
01303 $_this->__parseExtensions = true;
01304 if (func_num_args() > 0) {
01305 $_this->__validExtensions = func_get_args();
01306 }
01307 }
01308
01309
01310
01311
01312
01313
01314
01315
01316 function getArgs($args, $options = array()) {
01317 $_this =& Router::getInstance();
01318 $pass = $named = array();
01319 $args = explode('/', $args);
01320
01321 $greedy = $_this->named['greedy'];
01322 if (isset($options['greedy'])) {
01323 $greedy = $options['greedy'];
01324 }
01325 $context = array();
01326 if (isset($options['context'])) {
01327 $context = $options['context'];
01328 }
01329 $rules = $_this->named['rules'];
01330 if (isset($options['named'])) {
01331 $greedy = isset($options['greedy']) && $options['greedy'] === true;
01332 foreach ((array)$options['named'] as $key => $val) {
01333 if (is_numeric($key)) {
01334 $rules[$val] = true;
01335 continue;
01336 }
01337 $rules[$key] = $val;
01338 }
01339 }
01340
01341 foreach ($args as $param) {
01342 if (empty($param) && $param !== '0' && $param !== 0) {
01343 continue;
01344 }
01345 $param = $_this->stripEscape($param);
01346
01347 $separatorIsPresent = strpos($param, $_this->named['separator']) !== false;
01348 if ((!isset($options['named']) || !empty($options['named'])) && $separatorIsPresent) {
01349 list($key, $val) = explode($_this->named['separator'], $param, 2);
01350 $hasRule = isset($rules[$key]);
01351 $passIt = (!$hasRule && !$greedy) || ($hasRule && !Router::matchNamed($key, $val, $rules[$key], $context));
01352 if ($passIt) {
01353 $pass[] = $param;
01354 } else {
01355 $named[$key] = $val;
01356 }
01357 } else {
01358 $pass[] = $param;
01359 }
01360 }
01361 return compact('pass', 'named');
01362 }
01363 }
01364 ?>