public function compile($aSelector) { global $gJCoord; $sourceFile = $aSelector->getPath(); $cachefile = $aSelector->getCompiledFilePath(); // lecture du fichier xml $xml = simplexml_load_file($sourceFile); if (!$xml) { return false; } /* <urls> <classicentrypoint name="index" default="true"> <url pathinfo="/test/:mois/:annee" module="" action=""> <param name="mois" escape="true" regexp="\d{4}"/> <param name="annee" escape="false" /> <static name="bla" value="cequejeveux" /> </url> <url handler="" module="" action="" /> </classicentrypoint> </urls> génère dans un fichier propre à chaque entrypoint : $PARSE_URL = array($isDefault , $infoparser,$infoparser... ) où $isDefault : indique si c'est un point d'entrée par défaut, et donc si le parser ne trouve rien, si il ignore ou fait une erreur $infoparser = array('module','action','selecteur handler') ou $infoparser = array( 'module','action', 'regexp_pathinfo', array('annee','mois'), // tableau des valeurs dynamiques, classées par ordre croissant array(true, false), // tableau des valeurs escapes array('bla'=>'cequejeveux' ) // tableau des valeurs statiques ) génère dans un fichier commun à tous : $CREATE_URL = array( 'news~show@classic' => array(0,'entrypoint', https true/false, 'selecteur handler') ou array(1,'entrypoint', https true/false, array('annee','mois','jour','id','titre'), // liste des paramètres de l'url à prendre en compte array(true, false..), // valeur des escapes "/news/%1/%2/%3/%4-%5", // forme de l'url array('bla'=>'cequejeveux' ) // tableau des valeurs statiques, pour comparer quand il y a plusieurs urls vers la même action ) quand il y a plusieurs urls vers la même action, il y a plutôt un tableau contenant plusieurs tableaux du type précédent array( 4, array(1,...), array(1,...)...) ou array(2,'entrypoint', https true/false); pour les clés du type "@request" array(3,'entrypoint', https true/false); pour les clés du type "module~@request" */ $typeparam = array('string' => '([^\\/]+)', 'char' => '([^\\/])', 'letter' => '(\\w)', 'number' => '(\\d+)', 'int' => '(\\d+)', 'integer' => '(\\d+)', 'digit' => '(\\d)', 'date' => '([0-2]\\d{3}\\-(?:0[1-9]|1[0-2])\\-(?:[0-2][1-9]|3[0-1]))', 'year' => '([0-2]\\d{3})', 'month' => '(0[1-9]|1[0-2])', 'day' => '([0-2][1-9]|[1-2]0|3[0-1])'); $createUrlInfos = array(); $createUrlContent = "<?php \n"; $defaultEntrypoints = array(); foreach ($xml->children() as $name => $tag) { if (!preg_match("/^(.*)entrypoint\$/", $name, $m)) { //TODO : erreur continue; } $requestType = $m[1]; $entryPoint = (string) $tag['name']; $isDefault = isset($tag['default']) ? (string) $tag['default'] == 'true' : false; $isHttps = isset($tag['https']) ? (string) $tag['https'] == 'true' : false; $generatedentrypoint = $entryPoint; if (isset($tag['noentrypoint']) && (string) $tag['noentrypoint'] == 'true') { $generatedentrypoint = ''; } $parseInfos = array($isDefault); // si c'est le point d'entrée par défaut pour le type de requet indiqué // alors on indique une regle supplementaire que matcherons // toutes les urls qui ne correspondent pas aux autres rêgles if ($isDefault) { $createUrlInfos['@' . $requestType] = array(2, $entryPoint, $isHttps); } $parseContent = "<?php \n"; foreach ($tag->url as $url) { $module = (string) $url['module']; if (isset($url['https'])) { $urlhttps = (string) $url['https'] == 'true'; } else { $urlhttps = $isHttps; } if (isset($url['noentrypoint']) && (string) $url['noentrypoint'] == 'true') { $urlep = ''; } else { $urlep = $generatedentrypoint; } // dans le cas d'un point d'entrée qui n'est pas celui par défaut pour le type de requete indiqué // si il y a juste un module indiqué alors on sait que toutes les actions // concernant ce module passeront par ce point d'entrée. if (!$isDefault && !isset($url['action']) && !isset($url['handler'])) { $parseInfos[] = array($module, '', '/.*/', array(), array(), array(), false); $createUrlInfos[$module . '~*@' . $requestType] = array(3, $urlep, $urlhttps); continue; } $action = (string) $url['action']; if (strpos($action, ':') === false) { $action = 'default:' . $action; } if (isset($url['actionoverride'])) { $actionOverride = preg_split("/[\\s,]+/", (string) $url['actionoverride']); foreach ($actionOverride as &$each) { if (strpos($each, ':') === false) { $each = 'default:' . $each; } } } else { $actionOverride = false; } // si il y a un handler indiqué, on sait alors que pour le module et action indiqué // il faut passer par cette classe handler pour le parsing et la creation de l'url if (isset($url['handler'])) { $class = (string) $url['handler']; // il faut absolument un nom de module dans le selecteur, car lors de l'analyse de l'url // dans le request, il n'y a pas de module connu dans le context (normal...) $p = strpos($class, '~'); if ($p === false) { $selclass = $module . '~' . $class; } elseif ($p == 0) { $selclass = $module . $class; } else { $selclass = $class; } $s = new jSelectorUrlHandler($selclass); if (!isset($url['action'])) { $action = '*'; } $createUrlContent .= "include_once('" . $s->getPath() . "');\n"; $parseInfos[] = array($module, $action, $selclass, $actionOverride); $createUrlInfos[$module . '~' . $action . '@' . $requestType] = array(0, $urlep, $urlhttps, $selclass); if ($actionOverride) { foreach ($actionOverride as $ao) { $createUrlInfos[$module . '~' . $ao . '@' . $requestType] = array(0, $urlep, $urlhttps, $selclass); } } continue; } $listparam = array(); $escapes = array(); if (isset($url['pathinfo'])) { $path = (string) $url['pathinfo']; $regexppath = $path; if (preg_match_all("/\\:([a-zA-Z_]+)/", $path, $m, PREG_PATTERN_ORDER)) { $listparam = $m[1]; foreach ($url->param as $var) { $nom = (string) $var['name']; $k = array_search($nom, $listparam); if ($k === false) { // TODO error continue; } if (isset($var['escape'])) { $escapes[$k] = (string) $var['escape'] == 'true'; } else { $escapes[$k] = false; } if (isset($var['type'])) { if (isset($typeparam[(string) $var['type']])) { $regexp = $typeparam[(string) $var['type']]; } else { $regexp = '([^\\/]+)'; } } else { if (isset($var['regexp'])) { $regexp = '(' . (string) $var['regexp'] . ')'; } else { $regexp = '([^\\/]+)'; } } $regexppath = str_replace(':' . $nom, $regexp, $regexppath); } foreach ($listparam as $k => $name) { if (isset($escapes[$k])) { continue; } $escapes[$k] = false; $regexppath = str_replace(':' . $name, '([^\\/]+)', $regexppath); } } } else { $regexppath = '.*'; $path = ''; } if (isset($url['optionalTrailingSlash']) && $url['optionalTrailingSlash'] == 'true') { if (substr($regexppath, -1) == '/') { $regexppath .= '?'; } else { $regexppath .= '\\/?'; } } $liststatics = array(); foreach ($url->static as $var) { $liststatics[(string) $var['name']] = (string) $var['value']; } $parseInfos[] = array($module, $action, '!^' . $regexppath . '$!', $listparam, $escapes, $liststatics, $actionOverride); $cuisel = $module . '~' . $action . '@' . $requestType; $arr = array(1, $urlep, $urlhttps, $listparam, $escapes, $path, false, $liststatics); if (isset($createUrlInfos[$cuisel])) { if ($createUrlInfos[$cuisel][0] == 4) { $createUrlInfos[$cuisel][] = $arr; } else { $createUrlInfos[$cuisel] = array(4, $createUrlInfos[$cuisel], $arr); } } else { $createUrlInfos[$cuisel] = $arr; } if ($actionOverride) { foreach ($actionOverride as $ao) { $cuisel = $module . '~' . $ao . '@' . $requestType; $arr = array(1, $urlep, $urlhttps, $listparam, $escapes, $path, true, $liststatics); if (isset($createUrlInfos[$cuisel])) { if ($createUrlInfos[$cuisel][0] == 4) { $createUrlInfos[$cuisel][] = $arr; } else { $createUrlInfos[$cuisel] = array(4, $createUrlInfos[$cuisel], $arr); } } else { $createUrlInfos[$cuisel] = $arr; } } } } $parseContent .= '$GLOBALS[\'SIGNIFICANT_PARSEURL\'][\'' . rawurlencode($entryPoint) . '\'] = ' . var_export($parseInfos, true) . ";\n?>"; jFile::write(JELIX_APP_TEMP_PATH . 'compiled/urlsig/' . $aSelector->file . '.' . rawurlencode($entryPoint) . '.entrypoint.php', $parseContent); } $createUrlContent .= '$GLOBALS[\'SIGNIFICANT_CREATEURL\'] =' . var_export($createUrlInfos, true) . ";\n?>"; jFile::write(JELIX_APP_TEMP_PATH . 'compiled/urlsig/' . $aSelector->file . '.creationinfos.php', $createUrlContent); return true; }
/** * * @param string $scriptNamePath /path/index.php * @param string $pathinfo the path info part of the url (part between script name and query) * @param array $params url parameters (query part e.g. $_REQUEST) * @param boolean $isHttps says if the given url is asked with https or not * @return jUrlAction */ protected function _parse($scriptNamePath, $pathinfo, $params, $isHttps) { $urlact = null; $isDefault = false; $url = new jUrl($scriptNamePath, $params, $pathinfo); foreach ($this->dataParseUrl as $k => $infoparsing) { // the first element indicates if the entry point is a default entry point or not if ($k == 0) { $isDefault = $infoparsing; continue; } if (count($infoparsing) < 7) { // an handler will parse the request URI list($module, $action, $reg, $selectorHandler, $secondariesActions, $needHttps) = $infoparsing; $url2 = clone $url; if ($reg != '') { if (preg_match($reg, $pathinfo, $m)) { $url2->pathInfo = isset($m[1]) ? $m[1] : '/'; } else { continue; } } $s = new jSelectorUrlHandler($selectorHandler); include_once $s->getPath(); $c = $s->className . 'UrlsHandler'; $handler = new $c(); $url2->params['module'] = $module; // if the action parameter exists in the current url // and if it is one of secondaries actions, then we keep it // else we take the action indicated in the url mapping if ($secondariesActions && isset($params['action'])) { if (strpos($params['action'], ':') === false) { $params['action'] = 'default:' . $params['action']; } if (in_array($params['action'], $secondariesActions)) { // action peut avoir été écrasé par une itération précédente $url2->params['action'] = $params['action']; } else { $url2->params['action'] = $action; } } else { $url2->params['action'] = $action; } // appel au handler if ($urlact = $handler->parse($url2)) { break; } } elseif (preg_match($infoparsing[2], $pathinfo, $matches)) { /* we have this array array( 0=>'module', 1=>'action', 2=>'regexp_pathinfo', 3=>array('year','month'), // list of dynamic value included in the url, // alphabetical ascendant order 4=>array(0, 1..), // list of integer which indicates for each // dynamic value: 0: urlencode, 1:urlencode except '/', 2:escape, 4: lang, 8: locale 5=>array('bla'=>'whatIWant' ), // list of static values 6=>false or array('secondaries','actions') */ list($module, $action, $reg, $dynamicValues, $escapes, $staticValues, $secondariesActions, $needHttps) = $infoparsing; if (isset($params['module']) && $params['module'] !== $module) { continue; } if ($module != '') { $params['module'] = $module; } // if the action parameter exists in the current url // and if it is one of secondaries actions, then we keep it // else we take the action indicated in the url mapping if ($secondariesActions && isset($params['action'])) { if (strpos($params['action'], ':') === false) { $params['action'] = 'default:' . $params['action']; } if (!in_array($params['action'], $secondariesActions) && $action != '') { $params['action'] = $action; } } else { if ($action != '') { $params['action'] = $action; } } // let's merge static parameters if ($staticValues) { foreach ($staticValues as $n => $v) { if (!empty($v) && $v[0] == '$') { // special statique value $typeStatic = $v[1]; $v = substr($v, 2); if ($typeStatic == 'l') { jApp::config()->locale = jLocale::langToLocale($v); } else { if ($typeStatic == 'L') { jApp::config()->locale = $v; } } } $params[$n] = $v; } } // now let's read dynamic parameters if (count($matches)) { array_shift($matches); foreach ($dynamicValues as $k => $name) { if (isset($matches[$k])) { if ($escapes[$k] & 2) { $params[$name] = jUrl::unescape($matches[$k]); } else { $params[$name] = $matches[$k]; if ($escapes[$k] & 4) { $v = $matches[$k]; if (preg_match('/^\\w{2,3}$/', $v, $m)) { jApp::config()->locale = jLocale::langToLocale($v); } else { jApp::config()->locale = $v; $params[$name] = substr($v, 0, strpos('_')); } } else { if ($escapes[$k] & 8) { $v = $matches[$k]; if (preg_match('/^\\w{2,3}$/', $v, $m)) { jApp::config()->locale = $params[$name] = jLocale::langToLocale($v); } else { jApp::config()->locale = $v; } } } } } } } $urlact = new jUrlAction($params); break; } } if (!$urlact) { if ($isDefault && $pathinfo == '') { // if we didn't find the url in the mapping, and if this is the default // entry point, then we do anything $urlact = new jUrlAction($params); } else { try { $urlact = jUrl::get(jApp::config()->urlengine['notfoundAct'], array(), jUrl::JURLACTION); } catch (Exception $e) { $urlact = new jUrlAction(array('module' => 'jelix', 'action' => 'error:notfound')); } } } else { if ($needHttps && !$isHttps) { // the url is declared for HTTPS, but the request does not come from HTTPS // -> 404 not found $urlact = new jUrlAction(array('module' => 'jelix', 'action' => 'error:notfound')); } } return $urlact; }
/** * @param significantUrlInfoParsing $u * @param simpleXmlElement $url */ protected function newHandler($u, $url, $pathinfo = '') { $class = (string) $url['handler']; // we must have a module name in the selector, because, during the parsing of // the url in the request process, we are not still in a module context $p = strpos($class, '~'); if ($p === false) { $selclass = $u->module . '~' . $class; } elseif ($p == 0) { $selclass = $u->module . $class; } else { $selclass = $class; } $s = new jSelectorUrlHandler($selclass); if (!isset($url['action'])) { $u->action = '*'; } $regexp = ''; if (isset($url['pathinfo'])) { $pathinfo .= '/' . trim((string) $url['pathinfo'], '/'); } if ($pathinfo != '/') { $regexp = '!^' . preg_quote($pathinfo, '!') . '(/.*)?$!'; } $this->createUrlContentInc .= "include_once('" . $s->getPath() . "');\n"; $this->parseInfos[] = array($u->module, $u->action, $regexp, $selclass, $u->actionOverride, $this->checkHttps && $u->isHttps); $this->createUrlInfos[$u->getFullSel()] = array(0, $u->entryPointUrl, $u->isHttps, $selclass, $pathinfo); if ($u->actionOverride) { foreach ($u->actionOverride as $ao) { $u->action = $ao; $this->createUrlInfos[$u->getFullSel()] = array(0, $u->entryPointUrl, $u->isHttps, $selclass, $pathinfo); } } }
protected function _parse($scriptNamePath, $pathinfo, $params, $isHttps) { $urlact = null; $isDefault = false; $url = new jUrl($scriptNamePath, $params, $pathinfo); foreach ($this->dataParseUrl as $k => $infoparsing) { if ($k == 0) { $isDefault = $infoparsing; continue; } if (count($infoparsing) < 7) { list($module, $action, $reg, $selectorHandler, $secondariesActions, $needHttps) = $infoparsing; $url2 = clone $url; if ($reg != '') { if (preg_match($reg, $pathinfo, $m)) { $url2->pathInfo = isset($m[1]) ? $m[1] : '/'; } else { continue; } } $s = new jSelectorUrlHandler($selectorHandler); include_once $s->getPath(); $c = $s->className . 'UrlsHandler'; $handler = new $c(); $url2->params['module'] = $module; if ($secondariesActions && isset($params['action'])) { if (strpos($params['action'], ':') === false) { $params['action'] = 'default:' . $params['action']; } if (in_array($params['action'], $secondariesActions)) { $url2->params['action'] = $params['action']; } else { $url2->params['action'] = $action; } } else { $url2->params['action'] = $action; } if ($urlact = $handler->parse($url2)) { break; } } elseif (preg_match($infoparsing[2], $pathinfo, $matches)) { list($module, $action, $reg, $dynamicValues, $escapes, $staticValues, $secondariesActions, $needHttps) = $infoparsing; if (isset($params['module']) && $params['module'] !== $module) { continue; } if ($module != '') { $params['module'] = $module; } if ($secondariesActions && isset($params['action'])) { if (strpos($params['action'], ':') === false) { $params['action'] = 'default:' . $params['action']; } if (!in_array($params['action'], $secondariesActions) && $action != '') { $params['action'] = $action; } } else { if ($action != '') { $params['action'] = $action; } } if ($staticValues) { foreach ($staticValues as $n => $v) { if ($v[0] == '$') { $typeStatic = $v[1]; $v = substr($v, 2); if ($typeStatic == 'l') { jApp::config()->locale = jLocale::langToLocale($v); } else { if ($typeStatic == 'L') { jApp::config()->locale = $v; } } } $params[$n] = $v; } } if (count($matches)) { array_shift($matches); foreach ($dynamicValues as $k => $name) { if (isset($matches[$k])) { if ($escapes[$k] & 2) { $params[$name] = jUrl::unescape($matches[$k]); } else { $params[$name] = $matches[$k]; if ($escapes[$k] & 4) { $v = $matches[$k]; if (preg_match('/^\\w{2,3}$/', $v, $m)) { jApp::config()->locale = jLocale::langToLocale($v); } else { jApp::config()->locale = $v; $params[$name] = substr($v, 0, strpos('_')); } } else { if ($escapes[$k] & 8) { $v = $matches[$k]; if (preg_match('/^\\w{2,3}$/', $v, $m)) { jApp::config()->locale = $params[$name] = jLocale::langToLocale($v); } else { jApp::config()->locale = $v; } } } } } } } $urlact = new jUrlAction($params); break; } } if (!$urlact) { if ($isDefault && $pathinfo == '') { $urlact = new jUrlAction($params); } else { try { $urlact = jUrl::get(jApp::config()->urlengine['notfoundAct'], array(), jUrl::JURLACTION); } catch (Exception $e) { $urlact = new jUrlAction(array('module' => 'jelix', 'action' => 'error:notfound')); } } } else { if ($needHttps && !$isHttps) { $urlact = new jUrlAction(array('module' => 'jelix', 'action' => 'error:notfound')); } } return $urlact; }