diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index ff3c7de7b7add62e29ebec4b4184f7e6c7eb2ef5..c4ecc08bc953bb8ea06b9b0b49886bb114fcd2a5 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -746,9 +746,10 @@ function autoriser_sans_cookie($nom)
 // $entite = surnom de la table SQL (donne acces au nom de cle primaire)
 // $args = query_string a placer apres cle=$id&....
 // $ancre = ancre a mettre a la fin de l'URL a produire
-// $prive = vrai s'il faut produire l'URL d'edition, celle de lecture sinon
+// $public = produire l'URL publique ou privee (par defaut: selon espace)
 // $type = fichier dans le repertoire ecrire/urls determinant l'apparence
-
+// @return string : url codee
+// @return string : fonction de decodage
 // http://doc.spip.org/@generer_url_entite
 function generer_url_entite($id='', $entite='', $args='', $ancre='', $public=NULL, $type=NULL)
 {
@@ -775,11 +776,12 @@ function generer_url_entite($id='', $entite='', $args='', $ancre='', $public=NUL
 				?  $GLOBALS['meta']['type_urls']
 				:  $GLOBALS['type_urls']; // pour SPIP <2
 			}
+
 			$f = charger_fonction($type, 'urls', true); 
 		// si $entite='', on veut la fonction de passage URL ==> id
 			if (!$entite) return $f; 
 		// sinon on veut effectuer le passage id ==> URL
-			$res = !$f ? '' : $f($id, $entite, $args, $ancre);
+			$res = !$f ? '' : $f(intval($id), $entite, $args, $ancre);
 		}
 	}
 	if ($res) return $res;
diff --git a/ecrire/public/assembler.php b/ecrire/public/assembler.php
index d3a144630eb59e30e923a9a82f9ea0b5c572df97..bee18cf69a82c84232b7f4c7128cd15878d8a17b 100644
--- a/ecrire/public/assembler.php
+++ b/ecrire/public/assembler.php
@@ -75,18 +75,35 @@ function assembler($fond, $connect='') {
 			$contexte = $page['contexte'];
 		}
 		// ATTENTION, gestion des URLs transformee par le htaccess
+		// $renommer = 'urls_propres_dist';
+		// renvoie array($contexte, $fond, $url_redirect)
+		// Compat ascendante si le retour est null:
 		// 1. $contexte est global car cette fonction le modifie.
 		// 2. $fond est passe par reference, pour la meme raison
-		// Bref,  les URL dites propres ont une implementation sale.
-		// Interdit de nettoyer, faut assumer l'histoire.
 		// et calculer la page
 		else {
 			$renommer = generer_url_entite();
-			if ($renommer)
-				$renommer(nettoyer_uri(), $fond);
+			if ($renommer) {
+				$url = nettoyer_uri();
+				$a = $renommer($url, $fond);
+				if (is_array($a)) {
+					list($ncontexte, $nfond, $url_redirect) = $a;
+					if (isset($url_redirect)
+					AND $url !== $url_redirect) {
+						spip_log("Redirige $url vers $url_redirect");
+						include_spip('inc/headers');
+						http_status(301);
+						redirige_par_entete($url_redirect);
+					}
+					if (isset($nfond))
+						$fond = $nfond;
+					if (isset($ncontexte))
+						$contexte = $ncontexte;
+				}
+			}
 			elseif (function_exists('recuperer_parametres_url'))
 				// compatibilite <= 1.9.2
-				recuperer_parametres_url($fond,  nettoyer_uri());
+				recuperer_parametres_url($fond, nettoyer_uri());
 			$parametrer = charger_fonction('parametrer', 'public');
 			$page = $parametrer($fond, $GLOBALS['contexte'], $chemin_cache, $connect);
 
diff --git a/ecrire/urls/arbo.php b/ecrire/urls/arbo.php
index e4135fa3c25b11221918023db232963073deb41a..4a35a5462be3bdd5c22ea0547460523d0e9422b6 100644
--- a/ecrire/urls/arbo.php
+++ b/ecrire/urls/arbo.php
@@ -403,10 +403,9 @@ function _generer_url_arbo($type, $id, $args='', $ancre='') {
 }
 
 
+// @return array([contexte],[fond],[url_redirect]) : url decodee
 // http://doc.spip.org/@urls_arbo_dist
-function urls_arbo_dist($i, &$entite, $args='', $ancre='') {
-	global $contexte;
-
+function urls_arbo_dist($i, $entite, $args='', $ancre='') {
 	if (is_numeric($i))
 		return _generer_url_arbo($entite, $i, $args, $ancre);
 
@@ -415,41 +414,33 @@ function urls_arbo_dist($i, &$entite, $args='', $ancre='') {
 		$entite = 'type_urls';
 	}
 
+	$contexte = $GLOBALS['contexte']; // recuperer aussi les &debut_xx
 	$url = $i;
 	$id_objet = $type = 0;
+	$url_redirect = null;
 
 	// Migration depuis anciennes URLs ?
-	if (
-		// traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23
-	  $GLOBALS['profondeur_url']<=0
-	  AND $_SERVER['REQUEST_METHOD'] != 'POST') {
+	// traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23
+	if ($GLOBALS['profondeur_url']<=0
+	AND $_SERVER['REQUEST_METHOD'] != 'POST') {
+		// Decoder l'url html, page ou standard
 		if (preg_match(
-		',(^|/)(article|breve|rubrique|mot|auteur|site)(\.php3?|[0-9]+(\.html)?)'
-		.'([?&].*)?$,', $url, $regs)
-		) {
-			$type = $regs[2];
-			$id_table_objet = id_table_objet($type);
-			$id_objet = intval(_request($id_table_objet));
-		}
-
-		/* Compatibilite urls-page */
-		else if (preg_match(
-		',[?/&](article|breve|rubrique|mot|auteur|site)[=]?([0-9]+),',
+		',(^|id_|[?])(article|breve|rubrique|mot|auteur|site|syndic)=?(\d+),iS',
 		$url, $regs)) {
-			$type = $regs[1];
-			$id_objet = $regs[2];
+			$type = preg_replace(',s$,', '', table_objet($regs[2]));
+			$_id = id_table_objet($regs[2]);
+			$id_objet = $regs[3];
 		}
 	}
 	if ($id_objet) {
 		$url_propre = generer_url_entite($id_objet, $type, $args, $ancre);
+		$contexte = array($_id => $id_objet);
 		if (strlen($url_propre)
 		AND !strstr($url,$url_propre)) {
-			include_spip('inc/headers');
-			http_status(301);
-			// recuperer les arguments supplementaires (&debut_xxx=...)
 			$reste = preg_replace('/^&/','?',
 				preg_replace("/[?&]$id_table_objet=$id_objet/",'',$regs[5]));
-			redirige_par_entete("$url_propre$reste");
+			$url_redirect = "$url_propre$reste";
+			return array($contexte, $type, $url_redirect);
 		}
 	}
 	/* Fin compatibilite anciennes urls */
@@ -501,28 +492,21 @@ function urls_arbo_dist($i, &$entite, $args='', $ancre='') {
 			// Compatibilite avec les anciens marqueurs d'URL propres
 			// Tester l'entree telle quelle (avec 'url_libre' des sites ont pu avoir des entrees avec marqueurs dans la table spip_urls)
 			if (is_null($type)
-			  OR !$row=sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote("$typesyn/$url_propre")))) {
-			  if (!is_null($type))
+			OR !$row=sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote("$typesyn/$url_propre")))) {
+				if (!is_null($type))
 					array_push($url_arbo,$type);
 				$row = sql_fetsel('id_objet, type, date', 'spip_urls',array('url='.sql_quote($url_propre)));
 			}
 			if ($row) {
 				$type = $row['type'];
-		
-				// Redirection 301 si l'url est vieux
-				/*if ($recent = sql_fetsel('url, date', 'spip_urls',
-				'type='.sql_quote($row['type']).' AND id_objet='.sql_quote($row['id_objet'])
-				.' AND date>'.sql_quote($row['date']), '', 'date DESC', 1)) {
-					spip_log('Redirige '.$url_propre.' vers '.$recent['url']);
-					include_spip('inc/headers');
-					redirige_par_entete($recent['url']);
-				}*/
-		
 				$col_id = id_table_objet($type);
+				$contexte[$col_id] = $row['id_objet'];
+				$entite = $row['type'];
+
 				if (!isset($contexte[$col_id])) // n'affecter que la premiere fois un parent de type id_rubrique
 					$contexte[$col_id] = $row['id_objet'];
-				if (!$entite 
-					OR !in_array($type,$types_parents))
+				if (!$entite
+				OR !in_array($type,$types_parents))
 					$entite = $type;
 	
 				if ($p = url_arbo_parent($type))
@@ -532,18 +516,16 @@ function urls_arbo_dist($i, &$entite, $args='', $ancre='') {
 				// un segment est inconnu
 				if ($entite=='type_urls') {
 					// on genere une 404 comme il faut si on ne sait pas ou aller
-					include_spip('inc/headers');
-					http_status('404');
-					$entite = '404';
+					return array(array(),'404');
 				}
-				return;
+				return; // ?
 			}
 		}
 
 		// gerer le retour depuis des urls propres
 		if ($entite=='type_urls' AND $GLOBALS['profondeur_url']<=0){
 			$urls_anciennes = charger_fonction('propres','urls');
-			$urls_anciennes($url_propre,$entite);
+			return $urls_anciennes($url_propre,$entite);
 		}
 	}
 	if ($entite=='type_urls') {
@@ -555,6 +537,8 @@ function urls_arbo_dist($i, &$entite, $args='', $ancre='') {
 		}
 	}
 	define('_SET_HTML_BASE',1);
+
+	return array($contexte, $entite);
 }
 
 ?>
diff --git a/ecrire/urls/html.php b/ecrire/urls/html.php
index 64239a9d2a6fdfadfabce7b0854c08e96e45f1f6..3a3bc28edf56e11cc507cb34c1cac051ba9b8714 100644
--- a/ecrire/urls/html.php
+++ b/ecrire/urls/html.php
@@ -51,18 +51,28 @@ function _generer_url_html($type, $id, $args='', $ancre='') {
 
 // retrouver les parametres d'une URL dite "html"
 // http://doc.spip.org/@urls_html_dist
-function urls_html_dist($i, &$entite, $args='', $ancre='') {
-	global $contexte;
+function urls_html_dist($i, $entite, $args='', $ancre='') {
+	$contexte = $GLOBALS['contexte']; // recuperer aussi les &debut_xx
 
 	if (is_numeric($i))
 		return _generer_url_html($entite, $i, $args, $ancre);
 
 	// traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23
 	if ($GLOBALS['profondeur_url']>0 AND $entite=='sommaire'){
-		$entite = '404';
+		return array(array(),'404');
 	}
 	$url = $i;
 
+	// Decoder l'url html, page ou standard
+	if (preg_match(
+	',(^|id_|[?])(article|breve|rubrique|mot|auteur|site|syndic)=?(\d+),iS',
+	$url, $regs)) {
+		$type = preg_replace(',s$,', '', table_objet($regs[2]));
+		$_id = id_table_objet($regs[2]);
+		$contexte[$_id] = $id = $regs[3];
+		return array($contexte, $type);
+	}
+
 	/*
 	 * Le bloc qui suit sert a faciliter les transitions depuis
 	 * le mode 'urls-propres' vers les modes 'urls-standard' et 'url-html'
@@ -71,17 +81,20 @@ function urls_html_dist($i, &$entite, $args='', $ancre='') {
 	 */
 	// Si on est revenu en mode html, mais c'est une ancienne url_propre
 	// on ne redirige pas, on assume le nouveau contexte (si possible)
-	$url_propre = isset($_SERVER['REDIRECT_url_propre']) ?
-		$_SERVER['REDIRECT_url_propre'] :
-		(isset($_ENV['url_propre']) ?
-			$_ENV['url_propre'] :
-			'');
-	if ($url_propre AND preg_match(',^(article|breve|rubrique|mot|auteur|site|type_urls|404)$,', $entite)) {
+	$url_propre = isset($url)
+		? $url
+		: (isset($_SERVER['REDIRECT_url_propre'])
+			? $_SERVER['REDIRECT_url_propre']
+			: (isset($_ENV['url_propre'])
+				? $_ENV['url_propre']
+				: ''
+				));
+	if ($url_propre) {
 		if ($GLOBALS['profondeur_url']<=0)
 			$urls_anciennes = charger_fonction('propres','urls');
 		else
 			$urls_anciennes = charger_fonction('arbo','urls');
-		$urls_anciennes($url_propre,$entite);
+		return $urls_anciennes($url_propre,$entite);
 	}
 	/* Fin du bloc compatibilite url-propres */
 }
diff --git a/ecrire/urls/page.php b/ecrire/urls/page.php
index 9c46b2ca44edfc441fc4b67c8bdc844fb95206b6..0575f2a873f3ef291edea34344ae57eb349dd0a6 100644
--- a/ecrire/urls/page.php
+++ b/ecrire/urls/page.php
@@ -47,69 +47,51 @@ function _generer_url_page($type,$id, $args='', $ancre='') {
 // http://doc.spip.org/@urls_page_dist
 function urls_page_dist($i, &$entite, $args='', $ancre='')
 {
-	global $contexte;
+	$contexte = $GLOBALS['contexte']; // recuperer aussi les &debut_xx
 
 	if (is_numeric($i))
 		return _generer_url_page($entite, $i, $args, $ancre);
 
-	$url = $i;
 	// traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23
 	if ($GLOBALS['profondeur_url']>0 AND $entite=='sommaire'){
-		$entite = '404';
+		return array(array(),'404');
 	}
+	$url = $i;
 
-	// Ce bloc gere les urls page et la compatibilite avec les "urls standard"
-	if ($entite=='sommaire'){
-		if (preg_match(
-		',^[^?]*[?/](article|rubrique|breve|mot|site|auteur)(?:\.php3?)?.*?([0-9]+),',
-		$url, $regs)) {
-			$entite = $regs[1];
-			if ($regs[1] == 'site') {
-				if (!isset($contexte['id_syndic']))
-					$contexte['id_syndic'] = $regs[2];
-			} else {
-				if (!isset($contexte['id_'.$entite]))
-					$contexte['id_'.$entite] = $regs[2];
-			}
-	
-			return;
-		}
-		/* Compatibilite urls-page avec formulaire en get !!! */
-		else if (preg_match(
-			',[?/&](article|breve|rubrique|mot|auteur|site)[=]?([0-9]+),',
-			$url, $regs)) {
-			$entite = $regs[1];
-			if ($regs[1] == 'site') {
-				if (!isset($contexte['id_syndic']))
-					$contexte['id_syndic'] = $regs[2];
-			} else {
-				if (!isset($contexte['id_'.$entite]))
-					$contexte['id_'.$entite] = $regs[2];
-			}
-			return;
-		}
-		/* Fin compatibilite urls-page */
+	// Decoder l'url html, page ou standard
+	if (preg_match(
+	',(^|id_|[?])(article|breve|rubrique|mot|auteur|site|syndic)=?(\d+),iS',
+	$url, $regs)) {
+		$type = preg_replace(',s$,', '', table_objet($regs[2]));
+		$_id = id_table_objet($regs[2]);
+		$contexte[$_id] = $id = $regs[3];
+		return array($contexte, $type);
 	}
 
-
 	/*
 	 * Le bloc qui suit sert a faciliter les transitions depuis
-	 * le mode 'urls-propres' vers les modes 'urls-standard/page' et 'url-html'
+	 * le mode 'urls-propres' vers les modes 'urls-standard' et 'url-html'
 	 * Il est inutile de le recopier si vous personnalisez vos URLs
 	 * et votre .htaccess
 	 */
-	// Si on est revenu en mode page, mais c'est une ancienne url_propre
+	// Si on est revenu en mode html, mais c'est une ancienne url_propre
 	// on ne redirige pas, on assume le nouveau contexte (si possible)
-	if (
-		 (isset($_SERVER['REDIRECT_url_propre']) AND $url_propre = $_SERVER['REDIRECT_url_propre'])
-	OR (isset($_ENV['url_propre']) AND $url_propre = $_ENV['url_propre'])
-	AND preg_match(',^(article|breve|rubrique|mot|auteur|site|type_urls|404)$,', $entite)) {
+	$url_propre = isset($url)
+		? $url
+		: (isset($_SERVER['REDIRECT_url_propre'])
+			? $_SERVER['REDIRECT_url_propre']
+			: (isset($_ENV['url_propre'])
+				? $_ENV['url_propre']
+				: ''
+				));
+	if ($url_propre) {
 		if ($GLOBALS['profondeur_url']<=0)
 			$urls_anciennes = charger_fonction('propres','urls');
 		else
 			$urls_anciennes = charger_fonction('arbo','urls');
-		$urls_anciennes($url_propre,$entite);
+		return $urls_anciennes($url_propre,$entite);
 	}
 	/* Fin du bloc compatibilite url-propres */
 }
+
 ?>
diff --git a/ecrire/urls/propres.php b/ecrire/urls/propres.php
index 0f9880ce95780dd3bbfd7fea2a954ac0f9d842e2..d17da1c758e5fcc36f999222933d2fb0224f0c57 100644
--- a/ecrire/urls/propres.php
+++ b/ecrire/urls/propres.php
@@ -321,48 +321,55 @@ function _generer_url_propre($type, $id, $args='', $ancre='') {
 
 // retrouve le fond et les parametres d'une URL propre
 // ou produit une URL propre si on donne un parametre
+// @return array([contexte],[fond],[url_redirect]) : url decodee
 // http://doc.spip.org/@urls_propres_dist
-function urls_propres_dist($i, &$entite, $args='', $ancre='') {
-	global $contexte;
+function urls_propres_dist($i, $entite, $args='', $ancre='') {
 
 	if (is_numeric($i))
 		return _generer_url_propre($entite, $i, $args, $ancre);
 
 	$url = $i;
 	$id_objet = $type = 0;
+	$url_redirect = null;
+	$contexte = $GLOBALS['contexte']; // recuperer aussi les &debut_xx
 
 	// Migration depuis anciennes URLs ?
-	if (
-		// traiter les injections du type domaine.org/spip.php/cestnimportequoi/ou/encore/plus/rubrique23
-	  $GLOBALS['profondeur_url']<=0
-	  AND $_SERVER['REQUEST_METHOD'] != 'POST') {
+	// traiter les injections domain.tld/spip.php/n/importe/quoi/rubrique23
+	if ($GLOBALS['profondeur_url']<=0
+	AND $_SERVER['REQUEST_METHOD'] != 'POST') {
+		// Decoder l'url html, page ou standard
 		if (preg_match(
-		',(^|/)(article|breve|rubrique|mot|auteur|site)(\.php3?|[0-9]+(\.html)?)'
-		.'([?&].*)?$,', $url, $regs)
-		) {
-			$type = $regs[2];
-			$id_table_objet = id_table_objet($type);
-			$id_objet = intval(_request($id_table_objet));
-		}
-
-		/* Compatibilite urls-page */
-		else if (preg_match(
-		',[?/&](article|breve|rubrique|mot|auteur|site)[=]?([0-9]+),',
+		',(^|id_|[?])(article|breve|rubrique|mot|auteur|site|syndic)=?(\d+),iS',
 		$url, $regs)) {
-			$type = $regs[1];
-			$id_objet = $regs[2];
+			$type = preg_replace(',s$,', '', table_objet($regs[2]));
+			$_id = id_table_objet($regs[2]);
+			$id_objet = $regs[3];
 		}
 	}
 	if ($id_objet) {
 		$url_propre = generer_url_entite($id_objet, $type, $args, $ancre);
+		$contexte = array($_id => $id_objet);
+		if (strlen($url_propre)
+		AND !strstr($url,$url_propre)) {
+			$reste = preg_replace('/^&/','?',
+				preg_replace("/[?&]$id_table_objet=$id_objet/",'',$regs[5]));
+			$url_redirect = "$url_propre$reste";
+			return array($contexte, $type, $url_redirect);
+		}
+	}
+	/* Fin compatibilite anciennes urls */
+
+	if ($id_objet) {
+		$url_propre = generer_url_entite($id_objet, $type, $args, $ancre);
+		$contexte = array($id_table_objet => $id_objet);
 		if (strlen($url_propre)
 		AND !strstr($url,$url_propre)) {
 			include_spip('inc/headers');
-			http_status(301);
 			// recuperer les arguments supplementaires (&debut_xxx=...)
 			$reste = preg_replace('/^&/','?',
 				preg_replace("/[?&]$id_table_objet=$id_objet/",'',$regs[5]));
-			redirige_par_entete("$url_propre$reste");
+			$url_redirect = "$url_propre$reste";
+			return array($contexte, $type, $url_redirect);
 		}
 	}
 	/* Fin compatibilite anciennes urls */
@@ -394,8 +401,7 @@ function urls_propres_dist($i, &$entite, $args='', $ancre='') {
 	// mais si url arbo ne trouve pas, on veut une 404 par securite
 	if ($GLOBALS['profondeur_url']>0){
 		$urls_anciennes = charger_fonction('arbo','urls');
-		$urls_anciennes($url_propre,$entite);
-		return;
+		return $urls_anciennes($url_propre,$entite);
 	}
 	
 	include_spip('base/abstract_sql'); // chercher dans la table des URLS
@@ -414,8 +420,11 @@ function urls_propres_dist($i, &$entite, $args='', $ancre='') {
 
 	if ($row) {
 		$type = $row['type'];
+		$col_id = id_table_objet($type);
+		$contexte[$col_id] = $row['id_objet'];
+		$entite = $row['type'];
 
-		// Redirection 301 si l'url est vieux
+		// Si l'url est vieux, donner le nouveau
 		if ($recent = sql_fetsel('url, date', 'spip_urls',
 		'type='.sql_quote($row['type']).' AND id_objet='.sql_quote($row['id_objet'])
 		.' AND date>'.sql_quote($row['date']), '', 'date DESC', 1)) {
@@ -426,15 +435,8 @@ function urls_propres_dist($i, &$entite, $args='', $ancre='') {
 				$marqueur2 = $marqueur[$type.'2']; // fin '-+'
 			} else
 				$marqueur1 = $marqueur2 = '';
-			$recent = $marqueur1 . $recent['url'] . $marqueur2;
-			spip_log('Redirige '.$url_propre.' vers '.$recent);
-			include_spip('inc/headers');
-			redirige_par_entete($recent);
+			$url_redirect = $marqueur1 . $recent['url'] . $marqueur2;
 		}
-
-		$col_id = id_table_objet($type);
-		$contexte[$col_id] = $row['id_objet'];
-		$entite = $row['type'];
 	}
 
 	if ($entite=='type_urls') {
@@ -445,5 +447,8 @@ function urls_propres_dist($i, &$entite, $args='', $ancre='') {
 			$contexte['erreur'] = ''; // qu'afficher ici ?  l'url n'existe pas... on ne sait plus dire de quel type d'objet il s'agit
 		}
 	}
+
+	return array($contexte, $entite, $url_redirect);
 }
+
 ?>