Skip to content
Extraits de code Groupes Projets
utils.php 103 ko
Newer Older
	}
	if (!is_array($taches)) {
		$taches = $taches_old;
	} // compat anciens appels
	// si taches a inserer en base et base inaccessible, laisser tomber
	// sinon on ne verifie pas la connexion tout de suite, car si ca se trouve
	// queue_sleep_time_to_next_job() dira qu'il n'y a rien a faire
	// et on evite d'ouvrir une connexion pour rien (utilisation de _DIRECT_CRON_FORCE dans mes_options.php)
	if ($taches and count($taches) and !spip_connect()) {
		return false;
	}
	spip_log("cron !", 'jq' . _LOG_DEBUG);
	if ($genie = charger_fonction('genie', 'inc', true)) {
/**
 * Ajout d'une tache dans la file d'attente
 *
amemo's avatar
amemo a validé
 *     Le nom de la fonction PHP qui doit être appelée.
amemo's avatar
amemo a validé
 *     Une description humainement compréhensible de ce que fait la tâche
 *     (essentiellement pour l’affichage dans la page de suivi de l’espace privé)
amemo's avatar
amemo a validé
 *     Facultatif, vide par défaut : les arguments qui seront passés à la fonction, sous forme de tableau PHP
amemo's avatar
amemo a validé
 *     Facultatif, vide par défaut : nom du fichier à inclure, via `include_spip($file)`
 *     exemple : `'inc/mail'` : il ne faut pas indiquer .php
 *     Si le nom finit par un '/' alors on considère que c’est un répertoire et SPIP fera un `charger_fonction($function, $file)`
amemo's avatar
amemo a validé
 *     Facultatif, `false` par défaut
 *
 *     - si `true` la tâche ne sera pas ajoutée si elle existe déjà en file d’attente avec la même fonction et les mêmes arguments.
 *     - si `function_only` la tâche ne sera pas ajoutée si elle existe déjà en file d’attente avec la même fonction indépendamment de ses arguments
amemo's avatar
amemo a validé
 *     Facultatif, `0` par défaut : indique la date sous forme de timestamp à laquelle la tâche doit être programmée.
 *     Si `0` ou une date passée, la tâche sera exécutée aussitôt que possible (en général en fin hit, en asynchrone).
amemo's avatar
amemo a validé
 *     Facultatif, `0` par défaut : indique un niveau de priorité entre -10 et +10.
 *     Les tâches sont exécutées par ordre de priorité décroissante, une fois leur date d’exécution passée. La priorité est surtout utilisée quand une tâche cron indique qu’elle n’a pas fini et doit être relancée : dans ce cas SPIP réduit sa priorité pour être sûr que celle tâche ne monopolise pas la file d’attente.
amemo's avatar
amemo a validé
 *     Le numéro de travail ajouté ou `0` si aucun travail n’a été ajouté.
function job_queue_add(
	$function,
	$description,
	$arguments = array(),
	$file = '',
	$no_duplicate = false,
	$time = 0,
	$priority = 0
) {
	return queue_add_job($function, $description, $arguments, $file, $no_duplicate, $time, $priority);
}

/**
 * Supprimer une tache de la file d'attente
 * @param int $id_job
 *  id of jonb to delete
 * @return bool
 */
	return queue_remove_job($id_job);
}

/**
 * Associer une tache a un/des objets de SPIP
 *     can be a simple array('objet'=>'article', 'id_objet'=>23)
 *     or an array of simple array to link multiples objet in one time
function job_queue_link($id_job, $objets) {
}


/**
 * Renvoyer le temps de repos restant jusqu'au prochain job
 * @staticvar int $queue_next_job_time
marcimat's avatar
marcimat a validé
 * @see queue_set_next_job_time()
 * @param int|bool $force
 *    Utilisée par `queue_set_next_job_time()` pour mettre à jour la valeur :
marcimat's avatar
marcimat a validé
 *    - si `true`, force la relecture depuis le fichier
 *    - si int, affecte la static directement avec la valeur
marcimat's avatar
marcimat a validé
 *
 *  - `0` si un job est à traiter
 *  - `null` si la queue n'est pas encore initialisée
function queue_sleep_time_to_next_job($force = null) {
	static $queue_next_job_time = -1;
		$queue_next_job_time = $force;
		if (!defined('_JQ_NEXT_JOB_TIME_FILENAME')) {
			define('_JQ_NEXT_JOB_TIME_FILENAME', _DIR_TMP . "job_queue_next.txt");
		}
		// utiliser un cache memoire si dispo
		if (function_exists("cache_get") and defined('_MEMOIZE_MEMORY') and _MEMOIZE_MEMORY) {
			$queue_next_job_time = cache_get(_JQ_NEXT_JOB_TIME_FILENAME);
			if (lire_fichier(_JQ_NEXT_JOB_TIME_FILENAME, $contenu)) {
				$queue_next_job_time = intval($contenu);
		$_SERVER['REQUEST_TIME'] = time();
	return $queue_next_job_time - $_SERVER['REQUEST_TIME'];
marcimat's avatar
marcimat a validé
/**
 * Transformation XML des `&` en `&`
 * 
 * @pipeline post_typo
 * @param string $u
 * @return string
 */
function quote_amp($u) {
	return preg_replace(
Fil's avatar
Fil a validé
		"/&(?![a-z]{0,4}\w{2,3};|#x?[0-9a-f]{2,6};)/i",

/**
 * Produit une balise `<script>` valide
 *
 * @example
 *     ```
 *     echo http_script('alert("ok");');
 *     echo http_script('','js/jquery.js');
 *     ```
 * @param string $script
 *     Code source du script
 * @param string $src
 *     Permet de faire appel à un fichier javascript distant
 * @param string $noscript
 *     Contenu de la balise  `<noscript>`
 * @return string
 *     Balise HTML `<script>` et son contenu
function http_script($script, $src = '', $noscript = '') {
	static $done = array();
		$done[$src] = true;
		$src = find_in_path($src, _JAVASCRIPT);
		$script = ("/*<![CDATA[*/\n" .
			preg_replace(',</([^>]*)>,', '<\/\1>', $script) .
			"/*]]>*/");
	}
	if ($noscript) {
		$noscript = "<noscript>\n\t$noscript\n</noscript>\n";
		? "<script type='text/javascript'$src>$script</script>$noscript"
		: '';

/**
 * Sécurise du texte à écrire dans du PHP ou du Javascript.
 * Transforme n'importe quel texte en une chaîne utilisable
 * en PHP ou Javascript en toute sécurité, à l'intérieur d'apostrophes
 * simples (`'` uniquement ; pas `"`)
 *
 * Utile particulièrement en filtre dans un squelettes
 * pour écrire un contenu dans une variable JS ou PHP.
 *
 * Échappe les apostrophes (') du contenu transmis.
 *
 * @link http://www.spip.net/4281
 * @example
 *     PHP dans un squelette
 *     ```
 *     $x = '[(#TEXTE|texte_script)]';
 *     ```
 *
 *     JS dans un squelette (transmettre une chaîne de langue)
 *     ```
 *     $x = '<:afficher_calendrier|texte_script:>';
 *     ```
 *
 * @filtre
 * @param string $texte
 *     Texte à échapper
 * @return string
 *     Texte échappé
function texte_script($texte) {
	return str_replace('\'', '\\\'', str_replace('\\', '\\\\', $texte));
}


/**
 * Gestion des chemins (ou path) de recherche de fichiers par SPIP
 *
amemo's avatar
amemo a validé
 * Empile de nouveaux chemins (à la suite de ceux déjà présents, mais avant
 * le répertoire `squelettes` ou les dossiers squelettes), si un répertoire
 * (ou liste de répertoires séparés par `:`) lui est passé en paramètre.
 *
 * Ainsi, si l'argument est de la forme `dir1:dir2:dir3`, ces 3 chemins sont placés
amemo's avatar
amemo a validé
 * en tête du path, dans cet ordre (hormis `squelettes` & la globale
 * `$dossier_squelette` si définie qui resteront devant)
 * Retourne dans tous les cas la liste des chemins.
 *
 * @note
 *     Cette fonction est appelée à plusieurs endroits et crée une liste
 *     de chemins finale à peu près de la sorte :
 *     - dossiers squelettes (si globale précisée)
 *     - squelettes/
 *     - plugins (en fonction de leurs dépendances) : ceux qui dépendent
 *       d'un plugin sont devant eux (ils peuvent surcharger leurs fichiers)
 *     - racine du site
 *     - squelettes-dist/
 *     - prive/
 *     - ecrire/
 * @param string $dir_path
 *     - Répertoire(s) à empiler au path
 *     - '' provoque un recalcul des chemins.
 * @return array
 *     Liste des chemins, par ordre de priorité.
 **/
function _chemin($dir_path = null) {
	static $path_base = null;
	static $path_full = null;
	if ($path_base == null) {
Fil's avatar
Fil a validé
		// Chemin standard depuis l'espace public
		$path = defined('_SPIP_PATH') ? _SPIP_PATH :
			_DIR_RACINE . ':' .
			_DIR_RACINE . 'squelettes-dist/:' .
			_DIR_RACINE . 'prive/:' .
Fil's avatar
Fil a validé
		// Ajouter squelettes/
		if (@is_dir(_DIR_RACINE . 'squelettes')) {
			$path = _DIR_RACINE . 'squelettes/:' . $path;
		}
Fil's avatar
Fil a validé
		foreach (explode(':', $path) as $dir) {
Fil's avatar
Fil a validé
				$dir .= "/";
			$path_base[] = $dir;
		}
		$path_full = $path_base;
		// Et le(s) dossier(s) des squelettes nommes
		if (strlen($GLOBALS['dossier_squelettes'])) {
			foreach (array_reverse(explode(':', $GLOBALS['dossier_squelettes'])) as $d) {
				array_unshift($path_full, ($d[0] == '/' ? '' : _DIR_RACINE) . $d . '/');
		$GLOBALS['path_sig'] = md5(serialize($path_full));
		if (reset($path_base) == _DIR_RACINE . 'squelettes/') {
		}
		$dirs = array_reverse(explode(':', $dir_path));
		foreach ($dirs as $dir_path) {
			#if ($dir_path{0}!='/')
			#	$dir_path = $dir_path;
			if (substr($dir_path, -1) != '/') {
				$dir_path .= "/";
			}
			if (!in_array($dir_path, $path_base)) {
				array_unshift($path_base, $dir_path);
			}
		}
		if (strlen($tete)) {
			array_unshift($path_base, $tete);
		}
Fil's avatar
Fil a validé
	}
	$path_full = $path_base;
	// Et le(s) dossier(s) des squelettes nommes
	if (strlen($GLOBALS['dossier_squelettes'])) {
		foreach (array_reverse(explode(':', $GLOBALS['dossier_squelettes'])) as $d) {
marcimat's avatar
marcimat a validé
			array_unshift($path_full, ((isset($d[0]) and $d[0] == '/') ? '' : _DIR_RACINE) . $d . '/');
	$GLOBALS['path_sig'] = md5(serialize($path_full));
/**
 * Retourne la liste des chemins connus de SPIP, dans l'ordre de priorité
 *
 * Recalcule la liste si le nom ou liste de dossier squelettes a changé.
 *
 * @uses _chemin()
 * @return array Liste de chemins
function creer_chemin() {
	$path_a = _chemin();
	static $c = '';
	// on calcule le chemin si le dossier skel a change
	if ($c != $GLOBALS['dossier_squelettes']) {
		// assurer le non plantage lors de la montee de version :
		$c = $GLOBALS['dossier_squelettes'];
		$path_a = _chemin(''); // forcer un recalcul du chemin
	}
	static $themes = null;
cerdic's avatar
cerdic a validé
		// si pas encore definie
denisb's avatar
denisb a validé
			define('_SPIP_THEME_PRIVE', 'spip');
		$themes = array(_SPIP_THEME_PRIVE);
		// lors d'une installation neuve, prefs n'est pas definie.
		if (isset($GLOBALS['visiteur_session']['prefs'])) {
			$prefs = $GLOBALS['visiteur_session']['prefs'];
cerdic's avatar
cerdic a validé
			$prefs = unserialize($GLOBALS['visiteur_session']['prefs']);
cerdic's avatar
cerdic a validé
		if (
			((isset($prefs['theme']) and $theme = $prefs['theme'])
				or (isset($GLOBALS['theme_prive_defaut']) and $theme = $GLOBALS['theme_prive_defaut']))
			and $theme != _SPIP_THEME_PRIVE
		) {
			array_unshift($themes, $theme);
		} // placer le theme choisi en tete
cerdic's avatar
cerdic a validé
	}
	return $themes;
cerdic's avatar
cerdic a validé
}

function find_in_theme($file, $subdir = '', $include = false) {
	static $themefiles = array();
	if (isset($themefiles["$subdir$file"])) {
		return $themefiles["$subdir$file"];
	}
	// on peut fournir une icone generique -xx.svg qui fera le job dans toutes les tailles, et qui est prioritaire sur le png
	// si il y a un .svg a la bonne taille (-16.svg) a cote, on l'utilise en remplacement du -16.png
	if (preg_match(',-(\d+)[.](png|gif|svg)$,', $file, $m)
	  and $file_svg_generique = substr($file,0, -strlen($m[0])) . "-xx.svg"
		and $f = find_in_theme("$file_svg_generique")) {
		if ($fsize = substr($f,0,-6) . $m[1] . ".svg" and file_exists($fsize)) {
			return $themefiles["$subdir$file"] = $fsize;
		}
		else {
			return $themefiles["$subdir$file"] = $f;
		}
	$themes = lister_themes_prives();
	foreach ($themes as $theme) {
		if ($f = find_in_path($file, "prive/themes/$theme/$subdir", $include)) {
			return $themefiles["$subdir$file"] = $f;
cerdic's avatar
cerdic a validé
	}
	spip_log("$file introuvable dans le theme prive " . reset($themes), 'theme');

	return $themefiles["$subdir$file"] = "";
cerdic's avatar
cerdic a validé
}
marcimat's avatar
marcimat a validé

/**
 * Cherche une image dans les dossiers d'images
 *
 * Cherche en priorité dans les thèmes d'image (prive/themes/X/images)
 * et si la fonction n'en trouve pas, gère le renommage des icones (ex: 'supprimer' => 'del')
 * de facon temporaire le temps de la migration, et cherche de nouveau.
 *
 * Si l'image n'est toujours pas trouvée, on la cherche dans les chemins,
 * dans le répertoire défini par la constante `_NOM_IMG_PACK`
marcimat's avatar
marcimat a validé
 *
 * @see find_in_theme()
 * @see inc_icone_renommer_dist()
marcimat's avatar
marcimat a validé
 * @param string $icone
 *     Nom de l'icone cherchée
 * @return string
 *     Chemin complet de l'icone depuis la racine si l'icone est trouée,
 *     sinon chaîne vide.
	static $icone_renommer;
	// gerer le cas d'un double appel en evitant de refaire le travail inutilement
	if (strpos($icone, "/") !== false and file_exists($icone)) {
	// si c'est un nom d'image complet (article-24.png) essayer de le renvoyer direct
	if (preg_match(',[.](png|gif|jpg|svg)$,', $icone) and $f = find_in_theme("images/$icone")) {
	// sinon passer par le module de renommage
	if (is_null($icone_renommer)) {
		$icone_renommer = charger_fonction('icone_renommer', 'inc', true);
	}
	if ($icone_renommer) {
		list($icone, $fonction) = $icone_renommer($icone, "");
		if (file_exists($icone)) {
cerdic's avatar
cerdic a validé
			return $icone;
cerdic's avatar
cerdic a validé
	}
//
// chercher un fichier $file dans le SPIP_PATH
// si on donne un sous-repertoire en 2e arg optionnel, il FAUT le / final
// si 3e arg vrai, on inclut si ce n'est fait.
$GLOBALS['path_sig'] = '';
cerdic's avatar
cerdic a validé
$GLOBALS['path_files'] = null;
Fil's avatar
Fil a validé

/**
 * Recherche un fichier dans les chemins de SPIP (squelettes, plugins, core)
 *
 * Retournera le premier fichier trouvé (ayant la plus haute priorité donc),
 * suivant l'ordre des chemins connus de SPIP.
 *
 * @uses creer_chemin() Pour la liste des chemins.
 * @example
 *     ```
 *     $f = find_in_path('css/perso.css');
 *     $f = find_in_path('perso.css', 'css');
 *     ```
 * @param string $file
 *     Fichier recherché
 * @param string $dirname
 *     Répertoire éventuel de recherche (est aussi extrait automatiquement de $file)
 * @param bool|string $include
 *     - false : ne fait rien de plus
 *     - true : inclut le fichier (include_once)
 *     - 'require' : idem, mais tue le script avec une erreur si le fichier n'est pas trouvé.
 * @return string|bool
 *     - string : chemin du fichier trouvé
 *     - false : fichier introuvable
 **/
function find_in_path($file, $dirname = '', $include = false) {
	static $dirs = array();
	static $inc = array(); # cf http://trac.rezo.net/trac/spip/changeset/14743
	static $c = '';

	// on calcule le chemin si le dossier skel a change
	if ($c != $GLOBALS['dossier_squelettes']) {
		// assurer le non plantage lors de la montee de version :
		$c = $GLOBALS['dossier_squelettes'];
		creer_chemin(); // forcer un recalcul du chemin et la mise a jour de path_sig
	}

	if (isset($GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file])) {
		if (!$GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file]) {
cerdic's avatar
cerdic a validé
			return false;
			include_once _ROOT_CWD . $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file];
cerdic's avatar
cerdic a validé
			$inc[$dirname][$file] = $inc[''][$dirname . $file] = true;
		}
		return $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file];
esj's avatar
esj a validé
	if ($a !== false) {
		$dirname .= substr($file, 0, ++$a);
		$file = substr($file, $a);
	foreach (creer_chemin() as $dir) {
		if (!isset($dirs[$a = $dir . $dirname])) {
			$dirs[$a] = (is_dir(_ROOT_CWD . $a) || !$a);
		}
cerdic's avatar
cerdic a validé
			if (file_exists(_ROOT_CWD . ($a .= $file))) {
cerdic's avatar
cerdic a validé
					include_once _ROOT_CWD . $a;
					$inc[$dirname][$file] = $inc[''][$dirname . $file] = true;
				}
					// si le chemin n'a pas encore ete charge, ne pas lever le flag, ne pas cacher
				return $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file] = $GLOBALS['path_files'][$GLOBALS['path_sig']][''][$dirname . $file] = $a;
esj's avatar
esj a validé
		}
		spip_log("include_spip $dirname$file non trouve");
			echo '<pre>',
			"<strong>Erreur Fatale</strong><br />";
			if (function_exists('debug_print_backtrace')) {
				echo debug_print_backtrace();
			echo '</pre>';
			die("Erreur interne: ne peut inclure $dirname$file");
		}
	}
cerdic's avatar
cerdic a validé

		// si le chemin n'a pas encore ete charge, ne pas lever le flag, ne pas cacher
		if (is_null($GLOBALS['path_files'])) {
			return false;
		}
	return $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file] = $GLOBALS['path_files'][$GLOBALS['path_sig']][''][$dirname . $file] = false;
cerdic's avatar
cerdic a validé
}

cerdic's avatar
cerdic a validé
	$GLOBALS['path_files'] = array();
	spip_unlink(_CACHE_CHEMIN);
}
	// charger le path des plugins
		include_once(_CACHE_PLUGINS_PATH);
	}
cerdic's avatar
cerdic a validé
	$GLOBALS['path_files'] = array();
	// si le visiteur est admin,
	// on ne recharge pas le cache pour forcer sa mise a jour
cerdic's avatar
cerdic a validé
		// la session n'est pas encore chargee a ce moment, on ne peut donc pas s'y fier
		//AND (!isset($GLOBALS['visiteur_session']['statut']) OR $GLOBALS['visiteur_session']['statut']!='0minirezo')
cerdic's avatar
cerdic a validé
		// utiliser le cookie est un pis aller qui marche 'en general'
		// on blinde par un second test au moment de la lecture de la session
		// !isset($_COOKIE[$GLOBALS['cookie_prefix'].'_admin'])
cerdic's avatar
cerdic a validé
		// et en ignorant ce cache en cas de recalcul explicite
		// on essaye de lire directement sans verrou pour aller plus vite
		if ($contenu = spip_file_get_contents(_CACHE_CHEMIN)) {
			// mais si semble corrompu on relit avec un verrou
			if (!$GLOBALS['path_files'] = unserialize($contenu)) {
				lire_fichier(_CACHE_CHEMIN, $contenu);
				if (!$GLOBALS['path_files'] = unserialize($contenu)) {
cerdic's avatar
cerdic a validé
	}
cerdic's avatar
cerdic a validé
	if (defined('_SAUVER_CHEMIN')
	) {
		ecrire_fichier(_CACHE_CHEMIN, serialize($GLOBALS['path_files']));
	}
cerdic's avatar
cerdic a validé
/**
 * Trouve tous les fichiers du path correspondants à un pattern
 * Pour un nom de fichier donné, ne retourne que le premier qui sera trouvé
 * par un `find_in_path()`
cerdic's avatar
cerdic a validé
 *
 * @api
marcimat's avatar
marcimat a validé
 * @uses creer_chemin()
 * @uses preg_files()
cerdic's avatar
cerdic a validé
 * @param string $dir
 * @param string $pattern
 * @param bool $recurs
 * @return array
 */
function find_all_in_path($dir, $pattern, $recurs = false) {
	$liste_fichiers = array();
	// cas borderline si dans mes_options on appelle redirige_par_entete qui utilise _T et charge un fichier de langue
	// on a pas encore inclus flock.php
	if (!function_exists('preg_files')) {
		include_once _ROOT_RESTREINT . 'inc/flock.php';
	}

	foreach (creer_chemin() as $d) {
			$liste = preg_files($f, $pattern, $maxfiles - count($liste_fichiers), $recurs === true ? array() : $recurs);
				$nom = basename($chemin);
				// ne prendre que les fichiers pas deja trouves
				// car find_in_path prend le premier qu'il trouve,
				// les autres sont donc masques
					$liste_fichiers[$nom] = $chemin;
marcimat's avatar
marcimat a validé
/**
 * Prédicat sur les scripts de ecrire qui n'authentifient pas par cookie
 * et beneficient d'une exception
 *
marcimat's avatar
marcimat a validé
 * @param string $nom
marcimat's avatar
marcimat a validé
 * @return bool
 */
function autoriser_sans_cookie($nom, $strict = false) {
	static $autsanscookie = array('install', 'base_repair');

	if (in_array($nom, $autsanscookie)) {
		if (test_espace_prive()){
			include_spip('base/connect_sql');
			if (!$strict or !spip_connect()){
				return true;
			}
		}
	}
	return false;
 * Fonction codant et décodant les URLs des objets SQL mis en page par SPIP
 * @api
 * @param string $id
 *   numero de la cle primaire si nombre, URL a decoder si pas numerique
 * @param string $entite
 *   surnom de la table SQL (donne acces au nom de cle primaire)
 * @param string $args
 *   query_string a placer apres cle=$id&....
 * @param string $ancre
 *   ancre a mettre a la fin de l'URL a produire
 * @param bool|string $public
 *   produire l'URL publique ou privee (par defaut: selon espace)
 *   si string : serveur de base de donnee (nom du connect)
 * @param string $type
 *   fichier dans le repertoire ecrire/urls determinant l'apparence
 * @return string|array
 *   url codee ou fonction de decodage
 *   array : derogatoire, la fonction d'url retourne (objet,id_objet) utilises par nettoyer_raccourcis_typo() pour generer un lien titre
 *           (cas des raccourcis personalises [->spip20] : il faut implementer une fonction generer_url_spip et une fonction generer_url_ecrire_spip)
 */
function generer_url_entite($id = '', $entite = '', $args = '', $ancre = '', $public = null, $type = null) {
	if ($public === null) {
		$public = !test_espace_prive();
	}
cerdic's avatar
cerdic a validé
	$entite = objet_type($entite); // cas particulier d'appels sur objet/id_objet...
		if (!$entite) {
			return '';
		}
		if (!function_exists('generer_url_ecrire_objet')) {
			include_spip('inc/urls');
		}
		$res = generer_url_ecrire_objet($entite, $id, $args, $ancre, false);
		if ($type === null) {
			$type = (isset($GLOBALS['type_urls']))
				? $GLOBALS['type_urls'] // pour surcharge via fichier d'options
				: ((isset($GLOBALS['meta']['type_urls'])) // sinon la config url_etendues
					? ($GLOBALS['meta']['type_urls']) : "page"); // sinon type "page" par défaut

		$f = charger_fonction($type, 'urls', true);
		// se rabattre sur les urls page si les urls perso non dispo
		if (!$f) {
			$f = charger_fonction('page', 'urls', true);
		}

		// si $entite='', on veut la fonction de passage URL ==> id
		// sinon on veut effectuer le passage id ==> URL

		// mais d'abord il faut tester le cas des urls sur une
		// base distante
		if (is_string($public)

		$res = $f(intval($id), $entite, $args, $ancre, $public);

	// Sinon c'est un raccourci ou compat SPIP < 2
	if (!function_exists($f = 'generer_url_' . $entite)) {
	if ($f) {
		$url = $f($id, $args, $ancre);
			$url .= strstr($url, '?')
	// On a ete gentil mais la ....
	spip_log("generer_url_entite: entite $entite ($f) inconnue $type $public");
function generer_url_ecrire_entite_edit($id, $entite, $args = '', $ancre = '') {
	$exec = objet_info($entite, 'url_edit');
	$url = generer_url_ecrire($exec, $args);
	if (intval($id)) {
		$url = parametre_url($url, id_table_objet($entite), $id);
	} else {
		$url = parametre_url($url, 'new', 'oui');
	}
	if ($ancre) {
		$url = ancre_url($url, $ancre);
	}

// http://code.spip.net/@urls_connect_dist
function urls_connect_dist($i, &$entite, $args = '', $ancre = '', $public = null) {
	include_spip('base/connect_sql');
	return _DIR_RACINE . get_spip_script('./')
	. "?" . _SPIP_PAGE . "=$entite&$id_type=$i&connect=$public"
	. (!$args ? '' : "&$args")
	. (!$ancre ? '' : "#$ancre");
/**
 * Transformer les caractères utf8 d'une URL (farsi par exemple) selon la RFC 1738
 *
 * @param string $url
 * @return string
 */
function urlencode_1738($url) {
	if (preg_match(',[^\x00-\x7E],sS', $url)) {
		for ($i = 0; $i < strlen($url); $i++) {
			if (ord($a = $url[$i]) > 127) {
// http://code.spip.net/@generer_url_entite_absolue
function generer_url_entite_absolue($id = '', $entite = '', $args = '', $ancre = '', $connect = null) {
	if (!$connect) {
		$connect = true;
	}
	$h = generer_url_entite($id, $entite, $args, $ancre, $connect);
esj's avatar
esj a validé
	if (!preg_match(',^\w+:,', $h)) {
		include_spip('inc/filtres_mini');
		$h = url_absolue($h);
esj's avatar
esj a validé
	}

/**
 * Tester qu'une variable d'environnement est active
 * Sur certains serveurs, la valeur 'Off' tient lieu de false dans certaines
 * variables d'environnement comme `$_SERVER['HTTPS']` ou `ini_get('display_errors')`
 *
 * @param string|bool $truc
 *     La valeur de la variable d'environnement
 * @return bool
 *     true si la valeur est considérée active ; false sinon.
function test_valeur_serveur($truc) {
	return (strtolower($truc) !== 'off');

//
// Fonctions de fabrication des URL des scripts de Spip
//
amemo's avatar
amemo a validé
 * Calcule l'url de base du site
 *
 * Calcule l'URL de base du site, en priorité sans se fier à la méta (adresse_site) qui
 * peut être fausse (sites avec plusieurs noms d’hôtes, déplacements, erreurs).
 * En dernier recours, lorsqu'on ne trouve rien, on utilise adresse_site comme fallback.
amemo's avatar
amemo a validé
 * @note
 *     La globale `$profondeur_url` doit être initialisée de manière à
 *     indiquer le nombre de sous-répertoires de l'url courante par rapport à la
 *     racine de SPIP : par exemple, sur ecrire/ elle vaut 1, sur sedna/ 1, et à
 *     la racine 0. Sur url/perso/ elle vaut 2
amemo's avatar
amemo a validé
 *    - si non renseignée : retourne l'url pour la profondeur $GLOBALS['profondeur_url']
 *    - si int : indique que l'on veut l'url pour la profondeur indiquée
 *    - si bool : retourne le tableau static complet
 *    - si array : réinitialise le tableau static complet avec la valeur fournie
function url_de_base($profondeur = null) {
Fil's avatar
Fil a validé
	static $url = array();
	if (is_array($profondeur)) {
		return $url = $profondeur;
	}
	if ($profondeur === false) {
		return $url;
	}
	if (is_null($profondeur)) {
		$profondeur = $GLOBALS['profondeur_url'];
	}
	if (
		isset($_SERVER["SCRIPT_URI"])
		and substr($_SERVER["SCRIPT_URI"], 0, 5) == 'https'
	) {
		$http = 'https';
	} elseif (
		isset($_SERVER['HTTPS'])
		and test_valeur_serveur($_SERVER['HTTPS'])
	) {
		$http = 'https';
	}

	// note : HTTP_HOST contient le :port si necessaire
	$host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
	// si on n'a pas trouvé d'hôte du tout, en dernier recours on utilise adresse_site comme fallback
	if (is_null($host) and isset($GLOBALS['meta']['adresse_site'])) {
		$host = $GLOBALS['meta']['adresse_site'];
		if ($scheme = parse_url($host, PHP_URL_SCHEME)) {
			$http = $scheme;
			$host = str_replace("{$scheme}://", '', $host);
	}
	if (isset($_SERVER['SERVER_PORT'])
		and $port = $_SERVER['SERVER_PORT']
		and strpos($host, ":") == false
	) {
		if (!defined('_PORT_HTTP_STANDARD')) {
			define('_PORT_HTTP_STANDARD', '80');
		}
		if (!defined('_PORT_HTTPS_STANDARD')) {
			define('_PORT_HTTPS_STANDARD', '443');
		}
		if ($http == "http" and !in_array($port, explode(',', _PORT_HTTP_STANDARD))) {
			$host .= ":$port";
		}
		if ($http == "https" and !in_array($port, explode(',', _PORT_HTTPS_STANDARD))) {
			$host .= ":$port";
cerdic's avatar
cerdic a validé
		if (isset($_SERVER['REQUEST_URI'])) {
			$GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
		} else {
			$GLOBALS['REQUEST_URI'] = (php_sapi_name() !== 'cli') ? $_SERVER['PHP_SELF'] : '';
			if (!empty($_SERVER['QUERY_STRING'])
			) {
				$GLOBALS['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
			}
cerdic's avatar
cerdic a validé
		}
Fil's avatar
Fil a validé
	}
	$url[$profondeur] = url_de_($http, $host, $GLOBALS['REQUEST_URI'], $profondeur);
/**
 * fonction testable de construction d'une url appelee par url_de_base()
 * @param string $http
 * @param string $host
 * @param string $request
 * @param int $prof
 * @return string
 */
function url_de_($http, $host, $request, $prof = 0) {
	$prof = max($prof, 0);
	# supprimer la chaine de GET
	list($myself) = explode('?', $myself);
	// vieux mode HTTP qui envoie après le nom de la methode l'URL compléte
	// protocole, "://", nom du serveur avant le path dans _SERVER["REQUEST_URI"]
	if (strpos($myself,'://') !== false) {
		$myself = explode('://',$myself);
		array_shift($myself);
		$myself = implode('://',$myself);
		$myself = explode('/',$myself);
		array_shift($myself);
		$myself = implode('/',$myself);
	}
	$url = join('/', array_slice(explode('/', $myself), 0, -1 - $prof)) . '/';

	$url = $http . '://' . rtrim($host, '/') . '/' . ltrim($url, '/');
Fil's avatar
Fil a validé

esj's avatar
esj a validé
// Pour une redirection, la liste des arguments doit etre separee par "&"
// Pour du code XHTML, ca doit etre &amp;
// Bravo au W3C qui n'a pas ete capable de nous eviter ca
// faute de separer proprement langage et meta-langage
// Attention, X?y=z et "X/?y=z" sont completement differents!
// http://httpd.apache.org/docs/2.0/mod/mod_dir.html
/**
 * Crée une URL vers un script de l'espace privé
 *
 * @example
 *     ```
 *     generer_url_ecrire('admin_plugin')