3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
14 * Utilitaires indispensables autour du serveur Http.
16 * @package SPIP\Core\Utilitaires
19 if (!defined('_ECRIRE_INC_VERSION')) {
25 * Cherche une fonction surchargeable et en retourne le nom exact,
26 * après avoir chargé le fichier la contenant si nécessaire.
28 * Charge un fichier (suivant les chemins connus) et retourne si elle existe
29 * le nom de la fonction homonyme `$dir_$nom`, ou suffixé `$dir_$nom_dist`
31 * Peut être appelé plusieurs fois, donc optimisé.
34 * @uses include_spip() Pour charger le fichier
37 * $envoyer_mail = charger_fonction('envoyer_mail', 'inc');
38 * $envoyer_mail($email, $sujet, $texte);
42 * Nom de la fonction (et du fichier)
43 * @param string $dossier
44 * Nom du dossier conteneur
45 * @param bool $continue
46 * true pour ne pas râler si la fonction n'est pas trouvée
48 * Nom de la fonction, ou false.
50 function charger_fonction($nom, $dossier = 'exec', $continue = false) {
51 static $echecs = array();
53 if (strlen($dossier) and substr($dossier, -1) != '/') {
56 $f = str_replace('/', '_', $dossier) . $nom;
58 if (function_exists($f)) {
61 if (function_exists($g = $f . '_dist')) {
65 if (isset($echecs[$f])) {
68 // Sinon charger le fichier de declaration si plausible
70 if (!preg_match(',^\w+$,', $f)) {
73 } //appel interne, on passe
74 include_spip('inc/minipres');
79 // passer en minuscules (cf les balises de formulaires)
80 // et inclure le fichier
81 if (!$inc = include_spip($dossier . ($d = strtolower($nom)))
82 // si le fichier truc/machin/nom.php n'existe pas,
83 // la fonction peut etre definie dans truc/machin.php qui regroupe plusieurs petites fonctions
84 and strlen(dirname($dossier)) and dirname($dossier) != '.'
86 include_spip(substr($dossier, 0, -1));
88 if (function_exists($f)) {
91 if (function_exists($g)) {
96 return $echecs[$f] = false;
99 // Echec : message d'erreur
100 spip_log("fonction $nom ($f ou $g) indisponible" .
101 ($inc ?
"" : " (fichier $d absent de $dossier)"));
103 include_spip('inc/minipres');
104 echo minipres(_T('forum_titre_erreur'),
105 _T('fichier_introuvable', array('fichier' => '<b>' . spip_htmlentities($d) . '</b>')),
106 array('all_inline'=>true,'status'=>404));
111 * Inclusion unique avec verification d'existence du fichier + log en crash sinon
113 * @param string $file
116 function include_once_check($file) {
117 if (file_exists($file)) {
122 $crash = (isset($GLOBALS['meta']['message_crash_plugins']) ?
unserialize($GLOBALS['meta']['message_crash_plugins']) : '');
123 $crash = ($crash ?
$crash : array());
124 $crash[$file] = true;
125 ecrire_meta('message_crash_plugins', serialize($crash));
132 * Inclut un fichier PHP (en le cherchant dans les chemins)
135 * @uses find_in_path()
138 * include_spip('inc/texte');
142 * Nom du fichier (sans l'extension)
143 * @param bool $include
144 * - true pour inclure le fichier,
145 * - false ne fait que le chercher
146 * @return string|bool
147 * - false : fichier introuvable
148 * - string : chemin du fichier trouvé
150 function include_spip($f, $include = true) {
151 return find_in_path($f . '.php', '', $include);
155 * Requiert un fichier PHP (en le cherchant dans les chemins)
157 * @uses find_in_path()
158 * @see include_spip()
161 * require_spip('inc/texte');
165 * Nom du fichier (sans l'extension)
166 * @return string|bool
167 * - false : fichier introuvable
168 * - string : chemin du fichier trouvé
170 function require_spip($f) {
171 return find_in_path($f . '.php', '', 'required');
175 * Exécute une fonction (appellée par un pipeline) avec la donnée transmise.
177 * Un pipeline est lie a une action et une valeur
178 * chaque element du pipeline est autorise a modifier la valeur
179 * le pipeline execute les elements disponibles pour cette action,
180 * les uns apres les autres, et retourne la valeur finale
182 * Cf. compose_filtres dans references.php, qui est la
183 * version compilee de cette fonctionnalite
184 * appel unitaire d'une fonction du pipeline
185 * utilisee dans le script pipeline precompile
187 * on passe $val par reference pour limiter les allocations memoire
189 * @param string $fonc
190 * Nom de la fonction appelée par le pipeline
191 * @param string|array $val
192 * Les paramètres du pipeline, son environnement
193 * @return string|array $val
194 * Les paramètres du pipeline modifiés
196 function minipipe($fonc, &$val) {
198 if (function_exists($fonc)) {
199 $val = call_user_func($fonc, $val);
202 if (preg_match("/^(\w*)::(\w*)$/S", $fonc, $regs)
203 and $methode = array($regs[1], $regs[2])
204 and is_callable($methode)
206 $val = call_user_func($methode, $val);
208 spip_log("Erreur - '$fonc' non definie !");
216 * Appel d’un pipeline
218 * Exécute le pipeline souhaité, éventuellement avec des données initiales.
219 * Chaque plugin qui a demandé à voir ce pipeline vera sa fonction spécifique appelée.
220 * Les fonctions (des plugins) appelées peuvent modifier à leur guise le contenu.
222 * Deux types de retours. Si `$val` est un tableau de 2 éléments, avec une clé `data`
223 * on retourne uniquement ce contenu (`$val['data']`) sinon on retourne tout `$val`.
227 * Appel du pipeline `pre_insertion`
229 * $champs = pipeline('pre_insertion', array(
230 * 'args' => array('table' => 'spip_articles'),
235 * @param string $action
237 * @param null|string|array $val
238 * Données à l’entrée du pipeline
242 function pipeline($action, $val = null) {
245 // chargement initial des fonctions mises en cache, ou generation du cache
247 if (!($ok = @is_readable
($charger = _CACHE_PIPELINES
))) {
248 include_spip('inc/plugin');
249 // generer les fichiers php precompiles
250 // de chargement des plugins et des pipelines
251 actualise_plugins_actifs();
252 if (!($ok = @is_readable
($charger))) {
253 spip_log("fichier $charger pas cree");
258 include_once $charger;
262 // appliquer notre fonction si elle existe
263 $fonc = 'execute_pipeline_' . strtolower($action);
264 if (function_exists($fonc)) {
268 spip_log("fonction $fonc absente : pipeline desactive", _LOG_ERREUR
);
271 // si le flux est une table avec 2 cle args&data
272 // on ne ressort du pipe que les donnees dans 'data'
273 // array_key_exists pour php 4.1.0
276 and (array_key_exists('data', $val))
285 * Enregistrement des événements
287 * Signature : `spip_log(message[,niveau|type|type.niveau])`
289 * Le niveau de log par défaut est la valeur de la constante `_LOG_INFO`
291 * Les différents niveaux possibles sont :
293 * - `_LOG_HS` : écrira 'HS' au début de la ligne logguée
294 * - `_LOG_ALERTE_ROUGE` : 'ALERTE'
295 * - `_LOG_CRITIQUE` : 'CRITIQUE'
296 * - `_LOG_ERREUR` : 'ERREUR'
297 * - `_LOG_AVERTISSEMENT` : 'WARNING'
298 * - `_LOG_INFO_IMPORTANTE` : '!INFO'
299 * - `_LOG_INFO` : 'info'
300 * - `_LOG_DEBUG` : 'debug'
305 * spip_log($message, 'recherche')
306 * spip_log($message, _LOG_DEBUG)
307 * spip_log($message, 'recherche.'._LOG_DEBUG)
311 * @link http://programmer.spip.net/spip_log
312 * @uses inc_log_dist()
314 * @param string $message
316 * @param string|int $name
318 * - int indique le niveau de log, tel que `_LOG_DEBUG`
319 * - string indique le type de log
320 * - `string.int` indique les 2 éléments.
321 * Cette dernière notation est controversée mais le 3ème
322 * paramètre est planté pour cause de compatibilité ascendante.
324 function spip_log($message = null, $name = null) {
325 static $pre = array();
327 preg_match('/^([a-z_]*)\.?(\d)?$/iS', (string)$name, $regs);
328 if (!isset($regs[1]) or !$logname = $regs[1]) {
331 if (!isset($regs[2]) or !$niveau = $regs[2]) {
335 if ($niveau <= (defined('_LOG_FILTRE_GRAVITE') ? _LOG_FILTRE_GRAVITE
: _LOG_INFO_IMPORTANTE
)) {
339 _LOG_ALERTE_ROUGE
=> 'ALERTE:',
340 _LOG_CRITIQUE
=> 'CRITIQUE:',
341 _LOG_ERREUR
=> 'ERREUR:',
342 _LOG_AVERTISSEMENT
=> 'WARNING:',
343 _LOG_INFO_IMPORTANTE
=> '!INFO:',
344 _LOG_INFO
=> 'info:',
345 _LOG_DEBUG
=> 'debug:'
347 $log = charger_fonction('log', 'inc');
349 if (!is_string($message)) {
350 $message = print_r($message, true);
352 $log($pre[$niveau] . ' ' . $message, $logname);
357 * Enregistrement des journaux
359 * @uses inc_journal_dist()
360 * @param string $phrase Texte du journal
361 * @param array $opt Tableau d'options
363 function journal($phrase, $opt = array()) {
364 $journal = charger_fonction('journal', 'inc');
365 $journal($phrase, $opt);
370 * Renvoie le `$_GET` ou le `$_POST` émis par l'utilisateur
371 * ou pioché dans un tableau transmis
376 * @param bool|array $c
377 * Tableau transmis (sinon cherche dans GET ou POST)
379 * - null si la clé n'a pas été trouvée
380 * - la valeur de la clé sinon.
382 function _request($var, $c = false) {
385 return isset($c[$var]) ?
$c[$var] : null;
388 if (isset($_GET[$var])) {
390 } elseif (isset($_POST[$var])) {
396 // Si on est en ajax et en POST tout a ete encode
397 // via encodeURIComponent, il faut donc repasser
398 // dans le charset local...
401 and isset($GLOBALS['meta']['charset'])
402 and $GLOBALS['meta']['charset'] != 'utf-8'
404 // check rapide mais pas fiable
405 and preg_match(',[\x80-\xFF],', $a)
407 and include_spip('inc/charsets')
410 return importer_charset($a, 'utf-8');
418 * Affecte une valeur à une clé (pour usage avec `_request()`)
420 * @see _request() Pour obtenir la valeur
421 * @note Attention au cas ou l'on fait `set_request('truc', NULL);`
423 * @param string $var Nom de la clé
424 * @param string $val Valeur à affecter
425 * @param bool|array $c Tableu de données (sinon utilise `$_GET` et `$_POST`)
427 * - array $c complété si un $c est transmis,
430 function set_request($var, $val = null, $c = false) {
446 return false; # n'affecte pas $c
451 * Tester si une URL est absolue
453 * On est sur le web, on exclut certains protocoles,
454 * notamment 'file://', 'php://' et d'autres…
459 function tester_url_absolue($url) {
461 if (preg_match(";^([a-z]{3,7}:)?//;Uims", $url, $m)) {
464 and $p = strtolower(rtrim($m[1], ':'))
465 and in_array($p, array('file', 'php', 'zlib', 'glob', 'phar', 'ssh2', 'rar', 'ogg', 'expect', 'zip'))
475 * Prend une URL et lui ajoute/retire un paramètre
478 * @link http://www.spip.net/4255
481 * [(#SELF|parametre_url{suite,18})] (ajout)
482 * [(#SELF|parametre_url{suite,''})] (supprime)
483 * [(#SELF|parametre_url{suite[],1})] (tableaux valeurs multiples)
486 * @param string $url URL
487 * @param string $c Nom du paramètre
488 * @param string|array|null $v Valeur du paramètre
489 * @param string $sep Séparateur entre les paramètres
492 function parametre_url($url, $c, $v = null, $sep = '&') {
493 // requete erronnee : plusieurs variable dans $c et aucun $v
494 if (strpos($c, "|") !== false and is_null($v)) {
499 if (preg_match(',^([^#]*)(#.*)$,', $url, $r)) {
507 $url = preg_split(',[?]|&|&,', $url);
510 $a = array_shift($url);
515 $regexp = ',^(' . str_replace('[]', '\[\]', $c) . '[[]?[]]?)(=.*)?$,';
516 $ajouts = array_flip(explode('|', $c));
517 $u = is_array($v) ?
$v : rawurlencode($v);
518 $testv = (is_array($v) ?
count($v) : strlen($v));
520 // lire les variables et agir
521 foreach ($url as $n => $val) {
522 if (preg_match($regexp, urldecode($val), $r)) {
523 $r = array_pad($r, 3, null);
525 // c'est un tableau, on memorise les valeurs
526 if (substr($r[1], -2) == "[]") {
530 $v_read[] = $r[2] ?
substr($r[2], 1) : '';
531 } // c'est un scalaire, on retourne direct
533 return $r[2] ?
substr($r[2], 1) : '';
539 // Ajout. Pour une variable, remplacer au meme endroit,
540 // pour un tableau ce sera fait dans la prochaine boucle
541 elseif (substr($r[1], -2) != '[]') {
542 $url[$n] = $r[1] . '=' . $u;
543 unset($ajouts[$r[1]]);
545 // Pour les tableaux on laisse tomber les valeurs de
546 // départ, on remplira à l'étape suivante
553 // traiter les parametres pas encore trouves
555 and $args = func_get_args()
556 and count($args) == 2
558 return $v_read; // rien trouve ou un tableau
560 foreach ($ajouts as $k => $n) {
562 $url[] = $k . '=' . $u;
564 $id = (substr($k, -2) == '[]') ?
$k : ($k . "[]");
566 $url[] = $id . '=' . (is_array($w) ?
'Array' : $w);
572 // eliminer les vides
573 $url = array_filter($url);
575 // recomposer l'adresse
577 $a .= '?' . join($sep, $url);
584 * Ajoute (ou retire) une ancre sur une URL
586 * L’ancre est nettoyée : on translitère, vire les non alphanum du début,
587 * et on remplace ceux à l'interieur ou au bout par `-`
590 * - `$url = ancre_url($url, 'navigation'); // => mettra l’ancre #navigation
591 * - `$url = ancre_url($url, ''); // => enlèvera une éventuelle ancre
592 * @uses translitteration()
594 * @param string $ancre
597 function ancre_url($url, $ancre) {
599 if (preg_match(',^([^#]*)(#.*)$,', $url, $r)) {
602 if (preg_match('/[^-_a-zA-Z0-9]+/S', $ancre)) {
603 if (!function_exists('translitteration')) {
604 include_spip('inc/charsets');
606 $ancre = preg_replace(
607 array('/^[^-_a-zA-Z0-9]+/', '/[^-_a-zA-Z0-9]/'),
609 translitteration($ancre)
612 return $url . (strlen($ancre) ?
'#' . $ancre : '');
616 * Pour le nom du cache, les `types_urls` et `self`
618 * @param string|null $reset
621 function nettoyer_uri($reset = null) {
622 static $done = false;
624 if (!is_null($reset)) {
625 return $propre = $reset;
631 return $propre = nettoyer_uri_var($GLOBALS['REQUEST_URI']);
635 * Nettoie une request_uri des paramètres var_xxx
636 * @param $request_uri
639 function nettoyer_uri_var($request_uri) {
640 $uri1 = $request_uri;
643 $uri1 = preg_replace(',([?&])(PHPSESSID|(var_[^=&]*))=[^&]*(&|$),i',
645 } while ($uri <> $uri1);
646 return preg_replace(',[?&]$,', '', $uri1);
651 * Donner l'URL de base d'un lien vers "soi-meme", modulo les trucs inutiles
654 * Style des esperluettes
659 function self($amp = '&', $root = false) {
660 $url = nettoyer_uri();
663 // si pas de profondeur on peut tronquer
664 $GLOBALS['profondeur_url'] < (_DIR_RESTREINT ?
1 : 2)
665 // sinon c'est OK si _SET_HTML_BASE a ete force a false
666 or (defined('_SET_HTML_BASE') and !_SET_HTML_BASE
))
668 $url = preg_replace(',^[^?]*/,', '', $url);
670 // ajouter le cas echeant les variables _POST['id_...']
671 foreach ($_POST as $v => $c) {
672 if (substr($v, 0, 3) == 'id_') {
673 $url = parametre_url($url, $v, $c, '&');
677 // supprimer les variables sans interet
678 if (test_espace_prive()) {
679 $url = preg_replace(',([?&])('
681 . 'changer_lang|var_lang|action)=[^&]*,i', '\1', $url);
682 $url = preg_replace(',([?&])[&]+,', '\1', $url);
683 $url = preg_replace(',[&]$,', '\1', $url);
687 include_spip('inc/filtres_mini');
688 $url = spip_htmlspecialchars($url);
690 $url = str_replace(array("'", '"', '<', '[', ']', ':'), array('%27', '%22', '%3C', '%5B', '%5D', '%3A'), $url);
693 if ($amp != '&') {
694 $url = str_replace('&', $amp, $url);
697 // Si ca demarre par ? ou vide, donner './'
698 $url = preg_replace(',^([?].*)?$,', './\1', $url);
705 * Indique si on est dans l'espace prive
708 * true si c'est le cas, false sinon.
710 function test_espace_prive() {
711 return defined('_ESPACE_PRIVE') ? _ESPACE_PRIVE
: false;
715 * Vérifie la présence d'un plugin actif, identifié par son préfixe
717 * @param string $plugin
720 function test_plugin_actif($plugin) {
721 return ($plugin and defined('_DIR_PLUGIN_' . strtoupper($plugin))) ?
true : false;
725 * Traduction des textes de SPIP
727 * Traduit une clé de traduction en l'obtenant dans les fichiers de langues.
730 * @uses inc_traduire_dist()
734 * _T('bouton_enregistrer')
735 * _T('medias:image_tourner_droite')
736 * _T('medias:erreurs', array('nb'=>3))
737 * _T("email_sujet", array('spip_lang'=>$lang_usager))
740 * @param string $texte
743 * Couples (variable => valeur) pour passer des variables à la chaîne traduite. la variable spip_lang permet de forcer la langue
744 * @param array $options
745 * - string class : nom d'une classe a ajouter sur un span pour encapsuler la chaine
746 * - bool force : forcer un retour meme si la chaine n'a pas de traduction
747 * - bool sanitize : nettoyer le html suspect dans les arguments
751 function _T($texte, $args = array(), $options = array()) {
752 static $traduire = false;
753 $o = array('class' => '', 'force' => true, 'sanitize' => true);
755 // support de l'ancien argument $class
756 if (is_string($options)) {
757 $options = array('class' => $options);
759 $o = array_merge($o, $options);
763 $traduire = charger_fonction('traduire', 'inc');
764 include_spip('inc/lang');
767 // On peut passer explicitement la langue dans le tableau
768 // On utilise le même nom de variable que la globale
769 if (isset($args['spip_lang'])) {
770 $lang = $args['spip_lang'];
771 // On l'enleve pour ne pas le passer au remplacement
772 unset($args['spip_lang']);
773 } // Sinon on prend la langue du contexte
775 $lang = $GLOBALS['spip_lang'];
777 $text = $traduire($texte, $lang);
779 if (!strlen($text)) {
786 // pour les chaines non traduites, assurer un service minimum
787 if (!$GLOBALS['test_i18n'] and (_request('var_mode') != 'traduction')) {
788 $text = str_replace('_', ' ',
789 (($n = strpos($text, ':')) === false ?
$texte :
790 substr($texte, $n +
1)));
796 return _L($text, $args, $o);
802 * Remplace les variables `@...@` par leur valeur dans une chaîne de langue.
804 * Cette fonction est également appelée dans le code source de SPIP quand une
805 * chaîne n'est pas encore dans les fichiers de langue.
810 * _L('Texte avec @nb@ ...', array('nb'=>3)
813 * @param string $text
816 * Couples (variable => valeur) à transformer dans le texte
817 * @param array $options
818 * - string class : nom d'une classe a ajouter sur un span pour encapsuler la chaine
819 * - bool sanitize : nettoyer le html suspect dans les arguments
823 function _L($text, $args = array(), $options = array()) {
825 $defaut_options = array(
829 // support de l'ancien argument $class
830 if ($options and is_string($options)) {
831 $options = array('class' => $options);
833 if (is_array($options)) {
834 $options +
= $defaut_options;
836 $options = $defaut_options;
839 if (is_array($args)) {
840 if (!function_exists('interdire_scripts')) {
841 include_spip('inc/texte');
843 if (!function_exists('echapper_html_suspect')) {
844 include_spip('inc/texte_mini');
846 foreach ($args as $name => $value) {
847 if ($options['sanitize']) {
848 $value = echapper_html_suspect($value);
849 $value = interdire_scripts($value, -1);
851 if (!empty($options['class'])) {
852 $value = "<span class='".$options['class']."'>$value</span>";
854 $t = str_replace("@$name@", $value, $text);
860 // Si des variables n'ont pas ete inserees, le signaler
861 // (chaines de langues pas a jour)
863 spip_log("$f: variables inutilisees " . join(', ', array_keys($args)), _LOG_DEBUG
);
867 if (($GLOBALS['test_i18n'] or (_request('var_mode') == 'traduction')) and is_null($options['class'])) {
868 return "<span class=debug-traduction-erreur>$text</span>";
876 * Retourne un joli chemin de répertoire
878 * Pour afficher `ecrire/action/` au lieu de `action/` dans les messages
879 * ou `tmp/` au lieu de `../tmp/`
881 * @param stirng $rep Chemin d’un répertoire
884 function joli_repertoire($rep) {
885 $a = substr($rep, 0, 1);
886 if ($a <> '.' and $a <> '/') {
887 $rep = (_DIR_RESTREINT ?
'' : _DIR_RESTREINT_ABS
) . $rep;
889 $rep = preg_replace(',(^\.\.\/),', '', $rep);
896 * Débute ou arrête un chronomètre et retourne sa valeur
898 * On exécute 2 fois la fonction, la première fois pour démarrer le chrono,
899 * la seconde fois pour l’arrêter et récupérer la valeur
903 * spip_timer('papoter');
905 * $duree = spip_timer('papoter');
911 * - false : retour en texte humainement lisible
912 * - true : retour en millisecondes
913 * @return float|int|string|void
915 function spip_timer($t = 'rien', $raw = false) {
919 // microtime peut contenir les microsecondes et le temps
920 $b = explode(' ', $b);
921 if (count($b) == 2) {
925 if (!isset($time[$t])) {
928 $p = ($a +
$b - $time[$t]) * 1000;
937 $s = sprintf("%d ", $x = floor($p / 1000));
941 return $s . sprintf($s ?
"%07.3f ms" : "%.3f ms", $p);
946 // Renvoie False si un fichier n'est pas plus vieux que $duree secondes,
947 // sinon renvoie True et le date sauf si ca n'est pas souhaite
948 // http://code.spip.net/@spip_touch
949 function spip_touch($fichier, $duree = 0, $touch = true) {
952 if ((@$f = filemtime($fichier)) and ($f >= time() - $duree)) {
956 if ($touch !== false) {
957 if (!@touch
($fichier)) {
958 spip_unlink($fichier);
961 @chmod
($fichier, _SPIP_CHMOD
& ~
0111);
969 * Action qui déclenche une tache de fond
971 * @see queue_affichage_cron()
972 * @see action_super_cron_dist()
975 function action_cron() {
976 include_spip('inc/headers');
977 http_status(204); // No Content
978 header("Connection: close");
979 define('_DIRECT_CRON_FORCE', true);
984 * Exécution des tâches de fond
986 * @uses inc_genie_dist()
988 * @param array $taches
990 * @param array $taches_old
991 * Tâches forcées, pour compat avec ancienne syntaxe
993 * True si la tache a pu être effectuée
995 function cron($taches = array(), $taches_old = array()) {
996 // si pas en mode cron force, laisser tomber.
997 if (!defined('_DIRECT_CRON_FORCE')) {
1000 if (!is_array($taches)) {
1001 $taches = $taches_old;
1002 } // compat anciens appels
1003 // si taches a inserer en base et base inaccessible, laisser tomber
1004 // sinon on ne verifie pas la connexion tout de suite, car si ca se trouve
1005 // queue_sleep_time_to_next_job() dira qu'il n'y a rien a faire
1006 // et on evite d'ouvrir une connexion pour rien (utilisation de _DIRECT_CRON_FORCE dans mes_options.php)
1007 if ($taches and count($taches) and !spip_connect()) {
1010 spip_log("cron !", 'jq' . _LOG_DEBUG
);
1011 if ($genie = charger_fonction('genie', 'inc', true)) {
1012 return $genie($taches);
1019 * Ajout d'une tache dans la file d'attente
1021 * @param string $function
1022 * Le nom de la fonction PHP qui doit être appelée.
1023 * @param string $description
1024 * Une description humainement compréhensible de ce que fait la tâche
1025 * (essentiellement pour l’affichage dans la page de suivi de l’espace privé)
1026 * @param array $arguments
1027 * Facultatif, vide par défaut : les arguments qui seront passés à la fonction, sous forme de tableau PHP
1028 * @param string $file
1029 * Facultatif, vide par défaut : nom du fichier à inclure, via `include_spip($file)`
1030 * exemple : `'inc/mail'` : il ne faut pas indiquer .php
1031 * Si le nom finit par un '/' alors on considère que c’est un répertoire et SPIP fera un `charger_fonction($function, $file)`
1032 * @param bool $no_duplicate
1033 * Facultatif, `false` par défaut
1035 * - 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.
1036 * - 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
1038 * Facultatif, `0` par défaut : indique la date sous forme de timestamp à laquelle la tâche doit être programmée.
1039 * 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).
1040 * @param int $priority
1041 * Facultatif, `0` par défaut : indique un niveau de priorité entre -10 et +10.
1042 * 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.
1044 * Le numéro de travail ajouté ou `0` si aucun travail n’a été ajouté.
1046 function job_queue_add(
1049 $arguments = array(),
1051 $no_duplicate = false,
1055 include_spip('inc/queue');
1057 return queue_add_job($function, $description, $arguments, $file, $no_duplicate, $time, $priority);
1061 * Supprimer une tache de la file d'attente
1063 * @param int $id_job
1064 * id of jonb to delete
1067 function job_queue_remove($id_job) {
1068 include_spip('inc/queue');
1070 return queue_remove_job($id_job);
1074 * Associer une tache a un/des objets de SPIP
1076 * @param int $id_job
1078 * @param array $objets
1079 * can be a simple array('objet'=>'article', 'id_objet'=>23)
1080 * or an array of simple array to link multiples objet in one time
1082 function job_queue_link($id_job, $objets) {
1083 include_spip('inc/queue');
1085 return queue_link_job($id_job, $objets);
1090 * Renvoyer le temps de repos restant jusqu'au prochain job
1092 * @staticvar int $queue_next_job_time
1093 * @see queue_set_next_job_time()
1094 * @param int|bool $force
1095 * Utilisée par `queue_set_next_job_time()` pour mettre à jour la valeur :
1097 * - si `true`, force la relecture depuis le fichier
1098 * - si int, affecte la static directement avec la valeur
1101 * - `0` si un job est à traiter
1102 * - `null` si la queue n'est pas encore initialisée
1104 function queue_sleep_time_to_next_job($force = null) {
1105 static $queue_next_job_time = -1;
1106 if ($force === true) {
1107 $queue_next_job_time = -1;
1109 $queue_next_job_time = $force;
1112 if ($queue_next_job_time == -1) {
1113 if (!defined('_JQ_NEXT_JOB_TIME_FILENAME')) {
1114 define('_JQ_NEXT_JOB_TIME_FILENAME', _DIR_TMP
. "job_queue_next.txt");
1116 // utiliser un cache memoire si dispo
1117 if (function_exists("cache_get") and defined('_MEMOIZE_MEMORY') and _MEMOIZE_MEMORY
) {
1118 $queue_next_job_time = cache_get(_JQ_NEXT_JOB_TIME_FILENAME
);
1120 $queue_next_job_time = null;
1121 if (lire_fichier(_JQ_NEXT_JOB_TIME_FILENAME
, $contenu)) {
1122 $queue_next_job_time = intval($contenu);
1127 if (is_null($queue_next_job_time)) {
1130 if (!$_SERVER['REQUEST_TIME']) {
1131 $_SERVER['REQUEST_TIME'] = time();
1134 return $queue_next_job_time - $_SERVER['REQUEST_TIME'];
1139 * Transformation XML des `&` en `&`
1141 * @pipeline post_typo
1145 function quote_amp($u) {
1146 return preg_replace(
1147 "/&(?![a-z]{0,4}\w{2,3};|#x?[0-9a-f]{2,6};)/i",
1153 * Produit une balise `<script>` valide
1157 * echo http_script('alert("ok");');
1158 * echo http_script('','js/jquery.js');
1161 * @param string $script
1162 * Code source du script
1163 * @param string $src
1164 * Permet de faire appel à un fichier javascript distant
1165 * @param string $noscript
1166 * Contenu de la balise `<noscript>`
1168 * Balise HTML `<script>` et son contenu
1170 function http_script($script, $src = '', $noscript = '') {
1171 static $done = array();
1173 if ($src && !isset($done[$src])) {
1175 $src = find_in_path($src, _JAVASCRIPT
);
1176 $src = " src='$src'";
1181 $script = ("/*<![CDATA[*/\n" .
1182 preg_replace(',</([^>]*)>,', '<\/\1>', $script) .
1186 $noscript = "<noscript>\n\t$noscript\n</noscript>\n";
1189 return ($src or $script or $noscript)
1190 ?
"<script type='text/javascript'$src>$script</script>$noscript"
1196 * Sécurise du texte à écrire dans du PHP ou du Javascript.
1198 * Transforme n'importe quel texte en une chaîne utilisable
1199 * en PHP ou Javascript en toute sécurité, à l'intérieur d'apostrophes
1200 * simples (`'` uniquement ; pas `"`)
1202 * Utile particulièrement en filtre dans un squelettes
1203 * pour écrire un contenu dans une variable JS ou PHP.
1205 * Échappe les apostrophes (') du contenu transmis.
1207 * @link http://www.spip.net/4281
1209 * PHP dans un squelette
1211 * $x = '[(#TEXTE|texte_script)]';
1214 * JS dans un squelette (transmettre une chaîne de langue)
1216 * $x = '<:afficher_calendrier|texte_script:>';
1220 * @param string $texte
1225 function texte_script($texte) {
1226 return str_replace('\'', '\\\'', str_replace('\\', '\\\\', $texte));
1231 * Gestion des chemins (ou path) de recherche de fichiers par SPIP
1233 * Empile de nouveaux chemins (à la suite de ceux déjà présents, mais avant
1234 * le répertoire `squelettes` ou les dossiers squelettes), si un répertoire
1235 * (ou liste de répertoires séparés par `:`) lui est passé en paramètre.
1237 * Ainsi, si l'argument est de la forme `dir1:dir2:dir3`, ces 3 chemins sont placés
1238 * en tête du path, dans cet ordre (hormis `squelettes` & la globale
1239 * `$dossier_squelette` si définie qui resteront devant)
1241 * Retourne dans tous les cas la liste des chemins.
1244 * Cette fonction est appelée à plusieurs endroits et crée une liste
1245 * de chemins finale à peu près de la sorte :
1247 * - dossiers squelettes (si globale précisée)
1249 * - plugins (en fonction de leurs dépendances) : ceux qui dépendent
1250 * d'un plugin sont devant eux (ils peuvent surcharger leurs fichiers)
1252 * - squelettes-dist/
1256 * @param string $dir_path
1257 * - Répertoire(s) à empiler au path
1258 * - '' provoque un recalcul des chemins.
1260 * Liste des chemins, par ordre de priorité.
1262 function _chemin($dir_path = null) {
1263 static $path_base = null;
1264 static $path_full = null;
1265 if ($path_base == null) {
1266 // Chemin standard depuis l'espace public
1267 $path = defined('_SPIP_PATH') ? _SPIP_PATH
:
1269 _DIR_RACINE
. 'squelettes-dist/:' .
1270 _DIR_RACINE
. 'prive/:' .
1272 // Ajouter squelettes/
1273 if (@is_dir
(_DIR_RACINE
. 'squelettes')) {
1274 $path = _DIR_RACINE
. 'squelettes/:' . $path;
1276 foreach (explode(':', $path) as $dir) {
1277 if (strlen($dir) and substr($dir, -1) != '/') {
1280 $path_base[] = $dir;
1282 $path_full = $path_base;
1283 // Et le(s) dossier(s) des squelettes nommes
1284 if (strlen($GLOBALS['dossier_squelettes'])) {
1285 foreach (array_reverse(explode(':', $GLOBALS['dossier_squelettes'])) as $d) {
1286 array_unshift($path_full, ($d[0] == '/' ?
'' : _DIR_RACINE
) . $d . '/');
1289 $GLOBALS['path_sig'] = md5(serialize($path_full));
1291 if ($dir_path === null) {
1295 if (strlen($dir_path)) {
1297 if (reset($path_base) == _DIR_RACINE
. 'squelettes/') {
1298 $tete = array_shift($path_base);
1300 $dirs = array_reverse(explode(':', $dir_path));
1301 foreach ($dirs as $dir_path) {
1302 #if ($dir_path{0}!='/')
1303 # $dir_path = $dir_path;
1304 if (substr($dir_path, -1) != '/') {
1307 if (!in_array($dir_path, $path_base)) {
1308 array_unshift($path_base, $dir_path);
1311 if (strlen($tete)) {
1312 array_unshift($path_base, $tete);
1315 $path_full = $path_base;
1316 // Et le(s) dossier(s) des squelettes nommes
1317 if (strlen($GLOBALS['dossier_squelettes'])) {
1318 foreach (array_reverse(explode(':', $GLOBALS['dossier_squelettes'])) as $d) {
1319 array_unshift($path_full, ((isset($d[0]) and $d[0] == '/') ?
'' : _DIR_RACINE
) . $d . '/');
1323 $GLOBALS['path_sig'] = md5(serialize($path_full));
1329 * Retourne la liste des chemins connus de SPIP, dans l'ordre de priorité
1331 * Recalcule la liste si le nom ou liste de dossier squelettes a changé.
1335 * @return array Liste de chemins
1337 function creer_chemin() {
1338 $path_a = _chemin();
1341 // on calcule le chemin si le dossier skel a change
1342 if ($c != $GLOBALS['dossier_squelettes']) {
1343 // assurer le non plantage lors de la montee de version :
1344 $c = $GLOBALS['dossier_squelettes'];
1345 $path_a = _chemin(''); // forcer un recalcul du chemin
1352 function lister_themes_prives() {
1353 static $themes = null;
1354 if (is_null($themes)) {
1355 // si pas encore definie
1356 if (!defined('_SPIP_THEME_PRIVE')) {
1357 define('_SPIP_THEME_PRIVE', 'spip');
1359 $themes = array(_SPIP_THEME_PRIVE
);
1360 // lors d'une installation neuve, prefs n'est pas definie.
1361 if (isset($GLOBALS['visiteur_session']['prefs'])) {
1362 $prefs = $GLOBALS['visiteur_session']['prefs'];
1366 if (is_string($prefs)) {
1367 $prefs = unserialize($GLOBALS['visiteur_session']['prefs']);
1370 ((isset($prefs['theme']) and $theme = $prefs['theme'])
1371 or (isset($GLOBALS['theme_prive_defaut']) and $theme = $GLOBALS['theme_prive_defaut']))
1372 and $theme != _SPIP_THEME_PRIVE
1374 array_unshift($themes, $theme);
1375 } // placer le theme choisi en tete
1381 function find_in_theme($file, $subdir = '', $include = false) {
1382 static $themefiles = array();
1383 if (isset($themefiles["$subdir$file"])) {
1384 return $themefiles["$subdir$file"];
1386 $themes = lister_themes_prives();
1387 foreach ($themes as $theme) {
1388 if ($f = find_in_path($file, "prive/themes/$theme/$subdir", $include)) {
1389 return $themefiles["$subdir$file"] = $f;
1392 spip_log("$file introuvable dans le theme prive " . reset($themes), 'theme');
1394 return $themefiles["$subdir$file"] = "";
1399 * Cherche une image dans les dossiers d'images
1401 * Cherche en priorité dans les thèmes d'image (prive/themes/X/images)
1402 * et si la fonction n'en trouve pas, gère le renommage des icones (ex: 'supprimer' => 'del')
1403 * de facon temporaire le temps de la migration, et cherche de nouveau.
1405 * Si l'image n'est toujours pas trouvée, on la cherche dans les chemins,
1406 * dans le répertoire défini par la constante `_NOM_IMG_PACK`
1408 * @see find_in_theme()
1409 * @see inc_icone_renommer_dist()
1411 * @param string $icone
1412 * Nom de l'icone cherchée
1414 * Chemin complet de l'icone depuis la racine si l'icone est trouée,
1415 * sinon chaîne vide.
1417 function chemin_image($icone) {
1418 static $icone_renommer;
1419 // gerer le cas d'un double appel en evitant de refaire le travail inutilement
1420 if (strpos($icone, "/") !== false and file_exists($icone)) {
1424 // si c'est un nom d'image complet (article-24.png) essayer de le renvoyer direct
1425 if (preg_match(',[.](png|gif|jpg)$,', $icone) and $f = find_in_theme("images/$icone")) {
1428 // sinon passer par le module de renommage
1429 if (is_null($icone_renommer)) {
1430 $icone_renommer = charger_fonction('icone_renommer', 'inc', true);
1432 if ($icone_renommer) {
1433 list($icone, $fonction) = $icone_renommer($icone, "");
1434 if (file_exists($icone)) {
1439 return find_in_path($icone, _NOM_IMG_PACK
);
1443 // chercher un fichier $file dans le SPIP_PATH
1444 // si on donne un sous-repertoire en 2e arg optionnel, il FAUT le / final
1445 // si 3e arg vrai, on inclut si ce n'est fait.
1446 $GLOBALS['path_sig'] = '';
1447 $GLOBALS['path_files'] = null;
1450 * Recherche un fichier dans les chemins de SPIP (squelettes, plugins, core)
1452 * Retournera le premier fichier trouvé (ayant la plus haute priorité donc),
1453 * suivant l'ordre des chemins connus de SPIP.
1456 * @see charger_fonction()
1457 * @uses creer_chemin() Pour la liste des chemins.
1460 * $f = find_in_path('css/perso.css');
1461 * $f = find_in_path('perso.css', 'css');
1464 * @param string $file
1466 * @param string $dirname
1467 * Répertoire éventuel de recherche (est aussi extrait automatiquement de $file)
1468 * @param bool|string $include
1469 * - false : ne fait rien de plus
1470 * - true : inclut le fichier (include_once)
1471 * - 'require' : idem, mais tue le script avec une erreur si le fichier n'est pas trouvé.
1472 * @return string|bool
1473 * - string : chemin du fichier trouvé
1474 * - false : fichier introuvable
1476 function find_in_path($file, $dirname = '', $include = false) {
1477 static $dirs = array();
1478 static $inc = array(); # cf http://trac.rezo.net/trac/spip/changeset/14743
1481 // on calcule le chemin si le dossier skel a change
1482 if ($c != $GLOBALS['dossier_squelettes']) {
1483 // assurer le non plantage lors de la montee de version :
1484 $c = $GLOBALS['dossier_squelettes'];
1485 creer_chemin(); // forcer un recalcul du chemin et la mise a jour de path_sig
1488 if (isset($GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file])) {
1489 if (!$GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file]) {
1492 if ($include and !isset($inc[$dirname][$file])) {
1493 include_once _ROOT_CWD
. $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file];
1494 $inc[$dirname][$file] = $inc[''][$dirname . $file] = true;
1497 return $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file];
1500 $a = strrpos($file, '/');
1502 $dirname .= substr($file, 0, ++
$a);
1503 $file = substr($file, $a);
1506 foreach (creer_chemin() as $dir) {
1507 if (!isset($dirs[$a = $dir . $dirname])) {
1508 $dirs[$a] = (is_dir(_ROOT_CWD
. $a) ||
!$a);
1511 if (file_exists(_ROOT_CWD
. ($a .= $file))) {
1512 if ($include and !isset($inc[$dirname][$file])) {
1513 include_once _ROOT_CWD
. $a;
1514 $inc[$dirname][$file] = $inc[''][$dirname . $file] = true;
1516 if (!defined('_SAUVER_CHEMIN')) {
1517 // si le chemin n'a pas encore ete charge, ne pas lever le flag, ne pas cacher
1518 if (is_null($GLOBALS['path_files'])) {
1521 define('_SAUVER_CHEMIN', true);
1524 return $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file] = $GLOBALS['path_files'][$GLOBALS['path_sig']][''][$dirname . $file] = $a;
1530 spip_log("include_spip $dirname$file non trouve");
1531 if ($include === 'required') {
1533 "<strong>Erreur Fatale</strong><br />";
1534 if (function_exists('debug_print_backtrace')) {
1535 echo debug_print_backtrace();
1538 die("Erreur interne: ne peut inclure $dirname$file");
1542 if (!defined('_SAUVER_CHEMIN')) {
1543 // si le chemin n'a pas encore ete charge, ne pas lever le flag, ne pas cacher
1544 if (is_null($GLOBALS['path_files'])) {
1547 define('_SAUVER_CHEMIN', true);
1550 return $GLOBALS['path_files'][$GLOBALS['path_sig']][$dirname][$file] = $GLOBALS['path_files'][$GLOBALS['path_sig']][''][$dirname . $file] = false;
1553 function clear_path_cache() {
1554 $GLOBALS['path_files'] = array();
1555 spip_unlink(_CACHE_CHEMIN
);
1558 function load_path_cache() {
1559 // charger le path des plugins
1560 if (@is_readable
(_CACHE_PLUGINS_PATH
)) {
1561 include_once(_CACHE_PLUGINS_PATH
);
1563 $GLOBALS['path_files'] = array();
1564 // si le visiteur est admin,
1565 // on ne recharge pas le cache pour forcer sa mise a jour
1567 // la session n'est pas encore chargee a ce moment, on ne peut donc pas s'y fier
1568 //AND (!isset($GLOBALS['visiteur_session']['statut']) OR $GLOBALS['visiteur_session']['statut']!='0minirezo')
1569 // utiliser le cookie est un pis aller qui marche 'en general'
1570 // on blinde par un second test au moment de la lecture de la session
1571 // !isset($_COOKIE[$GLOBALS['cookie_prefix'].'_admin'])
1572 // et en ignorant ce cache en cas de recalcul explicite
1573 !_request('var_mode')
1575 // on essaye de lire directement sans verrou pour aller plus vite
1576 if ($contenu = spip_file_get_contents(_CACHE_CHEMIN
)) {
1577 // mais si semble corrompu on relit avec un verrou
1578 if (!$GLOBALS['path_files'] = unserialize($contenu)) {
1579 lire_fichier(_CACHE_CHEMIN
, $contenu);
1580 if (!$GLOBALS['path_files'] = unserialize($contenu)) {
1581 $GLOBALS['path_files'] = array();
1588 function save_path_cache() {
1589 if (defined('_SAUVER_CHEMIN')
1592 ecrire_fichier(_CACHE_CHEMIN
, serialize($GLOBALS['path_files']));
1598 * Trouve tous les fichiers du path correspondants à un pattern
1600 * Pour un nom de fichier donné, ne retourne que le premier qui sera trouvé
1601 * par un `find_in_path()`
1604 * @uses creer_chemin()
1605 * @uses preg_files()
1607 * @param string $dir
1608 * @param string $pattern
1609 * @param bool $recurs
1612 function find_all_in_path($dir, $pattern, $recurs = false) {
1613 $liste_fichiers = array();
1616 // cas borderline si dans mes_options on appelle redirige_par_entete qui utilise _T et charge un fichier de langue
1617 // on a pas encore inclus flock.php
1618 if (!function_exists('preg_files')) {
1619 include_once _ROOT_RESTREINT
. 'inc/flock.php';
1622 // Parcourir le chemin
1623 foreach (creer_chemin() as $d) {
1626 $liste = preg_files($f, $pattern, $maxfiles - count($liste_fichiers), $recurs === true ?
array() : $recurs);
1627 foreach ($liste as $chemin) {
1628 $nom = basename($chemin);
1629 // ne prendre que les fichiers pas deja trouves
1630 // car find_in_path prend le premier qu'il trouve,
1631 // les autres sont donc masques
1632 if (!isset($liste_fichiers[$nom])) {
1633 $liste_fichiers[$nom] = $chemin;
1639 return $liste_fichiers;
1643 * Prédicat sur les scripts de ecrire qui n'authentifient pas par cookie
1644 * @param string $nom
1647 function autoriser_sans_cookie($nom) {
1648 static $autsanscookie = array('install', 'base_repair');
1649 $nom = preg_replace('/.php[3]?$/', '', basename($nom));
1651 return in_array($nom, $autsanscookie);
1655 * Fonction codant et décodant les URLs des objets SQL mis en page par SPIP
1659 * numero de la cle primaire si nombre, URL a decoder si pas numerique
1660 * @param string $entite
1661 * surnom de la table SQL (donne acces au nom de cle primaire)
1662 * @param string $args
1663 * query_string a placer apres cle=$id&....
1664 * @param string $ancre
1665 * ancre a mettre a la fin de l'URL a produire
1666 * @param bool|string $public
1667 * produire l'URL publique ou privee (par defaut: selon espace)
1668 * si string : serveur de base de donnee (nom du connect)
1669 * @param string $type
1670 * fichier dans le repertoire ecrire/urls determinant l'apparence
1671 * @return string|array
1672 * url codee ou fonction de decodage
1673 * array : derogatoire, la fonction d'url retourne (objet,id_objet) utilises par nettoyer_raccourcis_typo() pour generer un lien titre
1674 * (cas des raccourcis personalises [->spip20] : il faut implementer une fonction generer_url_spip et une fonction generer_url_ecrire_spip)
1676 function generer_url_entite($id = '', $entite = '', $args = '', $ancre = '', $public = null, $type = null) {
1677 if ($public === null) {
1678 $public = !test_espace_prive();
1680 $entite = objet_type($entite); // cas particulier d'appels sur objet/id_objet...
1686 if (!function_exists('generer_url_ecrire_objet')) {
1687 include_spip('inc/urls');
1689 $res = generer_url_ecrire_objet($entite, $id, $args, $ancre, false);
1691 if ($type === null) {
1692 $type = (isset($GLOBALS['type_urls']))
1693 ?
$GLOBALS['type_urls'] // pour surcharge via fichier d'options
1694 : ((isset($GLOBALS['meta']['type_urls'])) // sinon la config url_etendues
1695 ?
($GLOBALS['meta']['type_urls']) : "page"); // sinon type "page" par défaut
1698 $f = charger_fonction($type, 'urls', true);
1699 // se rabattre sur les urls page si les urls perso non dispo
1701 $f = charger_fonction('page', 'urls', true);
1704 // si $entite='', on veut la fonction de passage URL ==> id
1705 // sinon on veut effectuer le passage id ==> URL
1710 // mais d'abord il faut tester le cas des urls sur une
1712 if (is_string($public)
1713 and $g = charger_fonction('connect', 'urls', true)
1718 $res = $f(intval($id), $entite, $args, $ancre, $public);
1724 // Sinon c'est un raccourci ou compat SPIP < 2
1725 if (!function_exists($f = 'generer_url_' . $entite)) {
1726 if (!function_exists($f .= '_dist')) {
1731 $url = $f($id, $args, $ancre);
1732 if (strlen($args)) {
1733 $url .= strstr($url, '?')
1740 // On a ete gentil mais la ....
1741 spip_log("generer_url_entite: entite $entite ($f) inconnue $type $public");
1746 function generer_url_ecrire_entite_edit($id, $entite, $args = '', $ancre = '') {
1747 $exec = objet_info($entite, 'url_edit');
1748 $url = generer_url_ecrire($exec, $args);
1750 $url = parametre_url($url, id_table_objet($entite), $id);
1752 $url = parametre_url($url, 'new', 'oui');
1755 $url = ancre_url($url, $ancre);
1761 // http://code.spip.net/@urls_connect_dist
1762 function urls_connect_dist($i, &$entite, $args = '', $ancre = '', $public = null) {
1763 include_spip('base/connect_sql');
1764 $id_type = id_table_objet($entite, $public);
1766 return _DIR_RACINE
. get_spip_script('./')
1767 . "?" . _SPIP_PAGE
. "=$entite&$id_type=$i&connect=$public"
1768 . (!$args ?
'' : "&$args")
1769 . (!$ancre ?
'' : "#$ancre");
1774 * Transformer les caractères utf8 d'une URL (farsi par exemple) selon la RFC 1738
1776 * @param string $url
1779 function urlencode_1738($url) {
1780 if (preg_match(',[^\x00-\x7E],sS', $url)) {
1782 for ($i = 0; $i < strlen($url); $i++
) {
1783 if (ord($a = $url[$i]) > 127) {
1784 $a = rawurlencode($a);
1791 return quote_amp($url);
1794 // http://code.spip.net/@generer_url_entite_absolue
1795 function generer_url_entite_absolue($id = '', $entite = '', $args = '', $ancre = '', $connect = null) {
1799 $h = generer_url_entite($id, $entite, $args, $ancre, $connect);
1800 if (!preg_match(',^\w+:,', $h)) {
1801 include_spip('inc/filtres_mini');
1802 $h = url_absolue($h);
1810 * Tester qu'une variable d'environnement est active
1812 * Sur certains serveurs, la valeur 'Off' tient lieu de false dans certaines
1813 * variables d'environnement comme $_SERVER[HTTPS] ou ini_get(register_globals)
1815 * @param string|bool $truc
1816 * La valeur de la variable d'environnement
1818 * true si la valeur est considérée active ; false sinon.
1820 function test_valeur_serveur($truc) {
1825 return (strtolower($truc) !== 'off');
1829 // Fonctions de fabrication des URL des scripts de Spip
1832 * Calcule l'url de base du site
1834 * Calcule l'URL de base du site, en priorité sans se fier à la méta (adresse_site) qui
1835 * peut être fausse (sites avec plusieurs noms d’hôtes, déplacements, erreurs).
1836 * En dernier recours, lorsqu'on ne trouve rien, on utilise adresse_site comme fallback.
1839 * La globale `$profondeur_url` doit être initialisée de manière à
1840 * indiquer le nombre de sous-répertoires de l'url courante par rapport à la
1841 * racine de SPIP : par exemple, sur ecrire/ elle vaut 1, sur sedna/ 1, et à
1842 * la racine 0. Sur url/perso/ elle vaut 2
1844 * @param int|boo|array $profondeur
1845 * - si non renseignée : retourne l'url pour la profondeur $GLOBALS['profondeur_url']
1846 * - si int : indique que l'on veut l'url pour la profondeur indiquée
1847 * - si bool : retourne le tableau static complet
1848 * - si array : réinitialise le tableau static complet avec la valeur fournie
1849 * @return string|array
1851 function url_de_base($profondeur = null) {
1853 static $url = array();
1854 if (is_array($profondeur)) {
1855 return $url = $profondeur;
1857 if ($profondeur === false) {
1861 if (is_null($profondeur)) {
1862 $profondeur = $GLOBALS['profondeur_url'];
1865 if (isset($url[$profondeur])) {
1866 return $url[$profondeur];
1872 isset($_SERVER["SCRIPT_URI"])
1873 and substr($_SERVER["SCRIPT_URI"], 0, 5) == 'https'
1877 isset($_SERVER['HTTPS'])
1878 and test_valeur_serveur($_SERVER['HTTPS'])
1883 // note : HTTP_HOST contient le :port si necessaire
1884 $host = isset($_SERVER['HTTP_HOST']) ?
$_SERVER['HTTP_HOST'] : null;
1885 // si on n'a pas trouvé d'hôte du tout, en dernier recours on utilise adresse_site comme fallback
1886 if (is_null($host) and isset($GLOBALS['meta']['adresse_site'])) {
1887 $host = $GLOBALS['meta']['adresse_site'];
1888 if ($scheme = parse_url($host, PHP_URL_SCHEME
)) {
1890 $host = str_replace("{$scheme}://", '', $host);
1893 if (isset($_SERVER['SERVER_PORT'])
1894 and $port = $_SERVER['SERVER_PORT']
1895 and strpos($host, ":") == false
1897 if (!defined('_PORT_HTTP_STANDARD')) {
1898 define('_PORT_HTTP_STANDARD', '80');
1900 if (!defined('_PORT_HTTPS_STANDARD')) {
1901 define('_PORT_HTTPS_STANDARD', '443');
1903 if ($http == "http" and !in_array($port, explode(',', _PORT_HTTP_STANDARD
))) {
1906 if ($http == "https" and !in_array($port, explode(',', _PORT_HTTPS_STANDARD
))) {
1911 if (!$GLOBALS['REQUEST_URI']) {
1912 if (isset($_SERVER['REQUEST_URI'])) {
1913 $GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
1915 $GLOBALS['REQUEST_URI'] = (php_sapi_name() !== 'cli') ?
$_SERVER['PHP_SELF'] : '';
1916 if (!empty($_SERVER['QUERY_STRING'])
1917 and !strpos($_SERVER['REQUEST_URI'], '?')
1919 $GLOBALS['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
1924 $url[$profondeur] = url_de_($http, $host, $GLOBALS['REQUEST_URI'], $profondeur);
1926 return $url[$profondeur];
1930 * fonction testable de construction d'une url appelee par url_de_base()
1932 * @param string $http
1933 * @param string $host
1934 * @param string $request
1938 function url_de_($http, $host, $request, $prof = 0) {
1939 $prof = max($prof, 0);
1941 $myself = ltrim($request, '/');
1942 # supprimer la chaine de GET
1943 list($myself) = explode('?', $myself);
1944 // vieux mode HTTP qui envoie après le nom de la methode l'URL compléte
1945 // protocole, "://", nom du serveur avant le path dans _SERVER["REQUEST_URI"]
1946 if (strpos($myself,'://') !== false) {
1947 $myself = explode('://',$myself);
1948 array_shift($myself);
1949 $myself = implode('://',$myself);
1950 $myself = explode('/',$myself);
1951 array_shift($myself);
1952 $myself = implode('/',$myself);
1954 $url = join('/', array_slice(explode('/', $myself), 0, -1 - $prof)) . '/';
1956 $url = $http . '://' . rtrim($host, '/') . '/' . ltrim($url, '/');
1962 // Pour une redirection, la liste des arguments doit etre separee par "&"
1963 // Pour du code XHTML, ca doit etre &
1964 // Bravo au W3C qui n'a pas ete capable de nous eviter ca
1965 // faute de separer proprement langage et meta-langage
1967 // Attention, X?y=z et "X/?y=z" sont completement differents!
1968 // http://httpd.apache.org/docs/2.0/mod/mod_dir.html
1971 * Crée une URL vers un script de l'espace privé
1975 * generer_url_ecrire('admin_plugin')
1978 * @param string $script
1979 * Nom de la page privée (xx dans exec=xx)
1980 * @param string $args
1981 * Arguments à transmettre, tel que `arg1=yy&arg2=zz`
1982 * @param bool $no_entities
1983 * Si false : transforme les `&` en `&`
1984 * @param bool|string $rel
1987 * - false : l’URL sera complète et contiendra l’URL du site
1988 * - true : l’URL sera relavive.
1989 * - string : on transmet l'url à la fonction
1990 * @return string URL
1992 function generer_url_ecrire($script = '', $args = "", $no_entities = false, $rel = false) {
1994 $rel = url_de_base() . _DIR_RESTREINT_ABS
. _SPIP_ECRIRE_SCRIPT
;
1996 if (!is_string($rel)) {
1997 $rel = _DIR_RESTREINT ? _DIR_RESTREINT
:
1998 ('./' . _SPIP_ECRIRE_SCRIPT
);
2002 list($script, $ancre) = array_pad(explode('#', $script), 2, null);
2003 if ($script and ($script <> 'accueil' or $rel)) {
2004 $args = "?exec=$script" . (!$args ?
'' : "&$args");
2012 return $rel . ($no_entities ?
$args : str_replace('&', '&', $args));
2016 * Permet d'ajouter lien vers une page privée à un paramètre d'url (déprécié)
2020 * $h = generer_url_ecrire('article', "id_article=$id_article&redirect=" . generer_url_retour('articles'));
2022 * $h = generer_url_ecrire('article');
2023 * $h = parametre_url($h, 'id_article', $id_article);
2024 * $h = parametre_url($h, 'redirect', generer_url_ecrire('articles'));
2027 * @deprecated Utiliser parametre_url() et generer_url_ecrire()
2028 * @see parametre_url()
2029 * @see generer_url_ecrire()
2031 * @param string $script
2032 * @param string $args
2035 function generer_url_retour($script, $args = "") {
2036 return rawurlencode(generer_url_ecrire($script, $args, true, true));
2040 // Adresse des scripts publics (a passer dans inc-urls...)
2045 * Retourne le nom du fichier d'exécution de SPIP
2049 * Detecter le fichier de base, a la racine, comme etant spip.php ou ''
2050 * dans le cas de '', un $default = './' peut servir (comme dans urls/page.php)
2052 * @param string $default
2055 * Nom du fichier (constante _SPIP_SCRIPT), sinon nom par défaut
2057 function get_spip_script($default = '') {
2058 # cas define('_SPIP_SCRIPT', '');
2060 return _SPIP_SCRIPT
;
2067 * Crée une URL vers une page publique de SPIP
2071 * generer_url_public("rubrique","id_rubrique=$id_rubrique")
2074 * @param string $script
2076 * @param string|array $args
2077 * Arguments à transmettre a l'URL,
2078 * soit sous la forme d'un string tel que `arg1=yy&arg2=zz`
2079 * soit sous la forme d'un array tel que array( `arg1` => `yy`, `arg2` => `zz` )
2080 * @param bool $no_entities
2081 * Si false : transforme les `&` en `&`
2085 * - false : l’URL sera complète et contiendra l’URL du site
2086 * - true : l’URL sera relavive.
2087 * @param string $action
2088 * - Fichier d'exécution public (spip.php par défaut)
2089 * @return string URL
2091 function generer_url_public($script = '', $args = "", $no_entities = false, $rel = true, $action = '') {
2092 // si le script est une action (spip_pass, spip_inscription),
2093 // standardiser vers la nouvelle API
2096 $action = get_spip_script();
2099 $action = parametre_url($action, _SPIP_PAGE
, $script, '&');
2103 if (is_array($args)) {
2105 foreach ($args as $k => $v) {
2106 $r .= '&' . $k . '=' . $v;
2108 $args = substr($r, 1);
2111 (strpos($action, '?') !== false ?
'&' : '?') . $args;
2113 if (!$no_entities) {
2114 $action = quote_amp($action);
2117 // ne pas generer une url avec /./?page= en cas d'url absolue et de _SPIP_SCRIPT vide
2118 return ($rel ? _DIR_RACINE
. $action : rtrim(url_de_base(), '/') . preg_replace(",^/[.]/,", "/", "/$action"));
2121 // http://code.spip.net/@generer_url_prive
2122 function generer_url_prive($script, $args = "", $no_entities = false) {
2124 return generer_url_public($script, $args, $no_entities, false, _DIR_RESTREINT_ABS
. 'prive.php');
2127 // Pour les formulaires en methode POST,
2128 // mettre le nom du script a la fois en input-hidden et dans le champ action:
2129 // 1) on peut ainsi memoriser le signet comme si c'etait un GET
2130 // 2) ca suit http://en.wikipedia.org/wiki/Representational_State_Transfer
2133 * Retourne un formulaire (POST par défaut) vers un script exec
2134 * de l’interface privée
2136 * @param string $script
2137 * Nom de la page exec
2138 * @param string $corps
2139 * Contenu du formulaire
2140 * @param string $atts
2141 * Si présent, remplace les arguments par défaut (method=post) par ceux indiqués
2142 * @param string $submit
2143 * Si indiqué, un bouton de soumission est créé avec texte sa valeur.
2145 * Code HTML du formulaire
2147 function generer_form_ecrire($script, $corps, $atts = '', $submit = '') {
2149 $script1 = explode('&', $script);
2150 $script1 = reset($script1);
2152 return "<form action='"
2153 . ($script ?
generer_url_ecrire($script) : '')
2155 . ($atts ?
$atts : " method='post'")
2157 . "<input type='hidden' name='exec' value='$script1' />"
2160 ("<div style='text-align: " . $GLOBALS['spip_lang_right'] . "'><input class='fondo' type='submit' value=\"" . entites_html($submit) . "\" /></div>"))
2161 . "</div></form>\n";
2165 * Générer un formulaire pour lancer une action vers $script
2167 * Attention, JS/Ajax n'aime pas le melange de param GET/POST
2168 * On n'applique pas la recommandation ci-dessus pour les scripts publics
2169 * qui ne sont pas destines a etre mis en signets
2171 * @param string $script
2172 * @param string $corps
2173 * @param string $atts
2174 * @param bool $public
2177 function generer_form_action($script, $corps, $atts = '', $public = false) {
2178 // si l'on est dans l'espace prive, on garde dans l'url
2179 // l'exec a l'origine de l'action, qui permet de savoir si il est necessaire
2180 // ou non de proceder a l'authentification (cas typique de l'install par exemple)
2181 $h = (_DIR_RACINE
and !$public)
2182 ?
generer_url_ecrire(_request('exec'))
2183 : generer_url_public();
2185 return "\n<form action='" .
2191 "\n<input type='hidden' name='action' value='$script' />" .
2199 * @param string $script
2200 * Nom du script à exécuter
2201 * @param string $args
2202 * Arguments à transmettre a l'URL sous la forme `arg1=yy&arg2=zz`
2203 * @param bool $no_entities
2204 * Si false : transforme les & en &
2205 * @param boolean $public
2206 * URL relative ? false : l’URL sera complète et contiendra l’URL du site.
2207 * true : l’URL sera relative.
2211 function generer_url_action($script, $args = "", $no_entities = false, $public = false) {
2212 // si l'on est dans l'espace prive, on garde dans l'url
2213 // l'exec a l'origine de l'action, qui permet de savoir si il est necessaire
2214 // ou non de proceder a l'authentification (cas typique de l'install par exemple)
2215 $url = (_DIR_RACINE
and !$public)
2216 ?
generer_url_ecrire(_request('exec'))
2217 : generer_url_public('', '', false, false);
2218 $url = parametre_url($url, 'action', $script);
2220 $url .= quote_amp('&' . $args);
2224 $url = str_replace('&', '&', $url);
2232 * Fonction d'initialisation groupée pour compatibilité ascendante
2234 * @param string $pi Répertoire permanent inaccessible
2235 * @param string $pa Répertoire permanent accessible
2236 * @param string $ti Répertoire temporaire inaccessible
2237 * @param string $ta Répertoire temporaire accessible
2239 function spip_initialisation($pi = null, $pa = null, $ti = null, $ta = null) {
2240 spip_initialisation_core($pi, $pa, $ti, $ta);
2241 spip_initialisation_suite();
2245 * Fonction d'initialisation, appellée dans inc_version ou mes_options
2247 * Elle définit les répertoires et fichiers non partageables
2248 * et indique dans $test_dirs ceux devant être accessibles en écriture
2249 * mais ne touche pas à cette variable si elle est déjà définie
2250 * afin que mes_options.php puisse en spécifier d'autres.
2252 * Elle définit ensuite les noms des fichiers et les droits.
2253 * Puis simule un register_global=on sécurisé.
2255 * @param string $pi Répertoire permanent inaccessible
2256 * @param string $pa Répertoire permanent accessible
2257 * @param string $ti Répertoire temporaire inaccessible
2258 * @param string $ta Répertoire temporaire accessible
2260 function spip_initialisation_core($pi = null, $pa = null, $ti = null, $ta = null) {
2261 static $too_late = 0;
2266 // Declaration des repertoires
2268 // le nom du repertoire plugins/ activables/desactivables
2269 if (!defined('_DIR_PLUGINS')) {
2270 define('_DIR_PLUGINS', _DIR_RACINE
. "plugins/");
2273 // le nom du repertoire des extensions/ permanentes du core, toujours actives
2274 if (!defined('_DIR_PLUGINS_DIST')) {
2275 define('_DIR_PLUGINS_DIST', _DIR_RACINE
. "plugins-dist/");
2278 // le nom du repertoire des librairies
2279 if (!defined('_DIR_LIB')) {
2280 define('_DIR_LIB', _DIR_RACINE
. "lib/");
2283 if (!defined('_DIR_IMG')) {
2284 define('_DIR_IMG', $pa);
2286 if (!defined('_DIR_LOGOS')) {
2287 define('_DIR_LOGOS', $pa);
2289 if (!defined('_DIR_IMG_ICONES')) {
2290 define('_DIR_IMG_ICONES', _DIR_LOGOS
. "icones/");
2293 if (!defined('_DIR_DUMP')) {
2294 define('_DIR_DUMP', $ti . "dump/");
2296 if (!defined('_DIR_SESSIONS')) {
2297 define('_DIR_SESSIONS', $ti . "sessions/");
2299 if (!defined('_DIR_TRANSFERT')) {
2300 define('_DIR_TRANSFERT', $ti . "upload/");
2302 if (!defined('_DIR_CACHE')) {
2303 define('_DIR_CACHE', $ti . "cache/");
2305 if (!defined('_DIR_CACHE_XML')) {
2306 define('_DIR_CACHE_XML', _DIR_CACHE
. "xml/");
2308 if (!defined('_DIR_SKELS')) {
2309 define('_DIR_SKELS', _DIR_CACHE
. "skel/");
2311 if (!defined('_DIR_AIDE')) {
2312 define('_DIR_AIDE', _DIR_CACHE
. "aide/");
2314 if (!defined('_DIR_TMP')) {
2315 define('_DIR_TMP', $ti);
2318 if (!defined('_DIR_VAR')) {
2319 define('_DIR_VAR', $ta);
2322 if (!defined('_DIR_ETC')) {
2323 define('_DIR_ETC', $pi);
2325 if (!defined('_DIR_CONNECT')) {
2326 define('_DIR_CONNECT', $pi);
2328 if (!defined('_DIR_CHMOD')) {
2329 define('_DIR_CHMOD', $pi);
2332 if (!isset($GLOBALS['test_dirs']))
2333 // Pas $pi car il est bon de le mettre hors ecriture apres intstall
2334 // il sera rajoute automatiquement si besoin a l'etape 2 de l'install
2336 $GLOBALS['test_dirs'] = array($pa, $ti, $ta);
2339 // Declaration des fichiers
2341 if (!defined('_CACHE_PLUGINS_PATH')) {
2342 define('_CACHE_PLUGINS_PATH', _DIR_CACHE
. "charger_plugins_chemins.php");
2344 if (!defined('_CACHE_PLUGINS_OPT')) {
2345 define('_CACHE_PLUGINS_OPT', _DIR_CACHE
. "charger_plugins_options.php");
2347 if (!defined('_CACHE_PLUGINS_FCT')) {
2348 define('_CACHE_PLUGINS_FCT', _DIR_CACHE
. "charger_plugins_fonctions.php");
2350 if (!defined('_CACHE_PIPELINES')) {
2351 define('_CACHE_PIPELINES', _DIR_CACHE
. "charger_pipelines.php");
2353 if (!defined('_CACHE_CHEMIN')) {
2354 define('_CACHE_CHEMIN', _DIR_CACHE
. "chemin.txt");
2357 # attention .php obligatoire pour ecrire_fichier_securise
2358 if (!defined('_FILE_META')) {
2359 define('_FILE_META', $ti . 'meta_cache.php');
2361 if (!defined('_DIR_LOG')) {
2362 define('_DIR_LOG', _DIR_TMP
. 'log/');
2364 if (!defined('_FILE_LOG')) {
2365 define('_FILE_LOG', 'spip');
2367 if (!defined('_FILE_LOG_SUFFIX')) {
2368 define('_FILE_LOG_SUFFIX', '.log');
2371 // Le fichier de connexion a la base de donnees
2372 // tient compte des anciennes versions (inc_connect...)
2373 if (!defined('_FILE_CONNECT_INS')) {
2374 define('_FILE_CONNECT_INS', 'connect');
2376 if (!defined('_FILE_CONNECT')) {
2377 define('_FILE_CONNECT',
2378 (@is_readable
($f = _DIR_CONNECT
. _FILE_CONNECT_INS
. '.php') ?
$f
2379 : (@is_readable
($f = _DIR_RESTREINT
. 'inc_connect.php') ?
$f
2383 // Le fichier de reglages des droits
2384 if (!defined('_FILE_CHMOD_INS')) {
2385 define('_FILE_CHMOD_INS', 'chmod');
2387 if (!defined('_FILE_CHMOD')) {
2388 define('_FILE_CHMOD',
2389 (@is_readable
($f = _DIR_CHMOD
. _FILE_CHMOD_INS
. '.php') ?
$f
2393 if (!defined('_FILE_LDAP')) {
2394 define('_FILE_LDAP', 'ldap.php');
2397 if (!defined('_FILE_TMP_SUFFIX')) {
2398 define('_FILE_TMP_SUFFIX', '.tmp.php');
2400 if (!defined('_FILE_CONNECT_TMP')) {
2401 define('_FILE_CONNECT_TMP', _DIR_CONNECT
. _FILE_CONNECT_INS
. _FILE_TMP_SUFFIX
);
2403 if (!defined('_FILE_CHMOD_TMP')) {
2404 define('_FILE_CHMOD_TMP', _DIR_CHMOD
. _FILE_CHMOD_INS
. _FILE_TMP_SUFFIX
);
2407 // Definition des droits d'acces en ecriture
2408 if (!defined('_SPIP_CHMOD') and _FILE_CHMOD
) {
2409 include_once _FILE_CHMOD
;
2412 // Se mefier des fichiers mal remplis!
2413 if (!defined('_SPIP_CHMOD')) {
2414 define('_SPIP_CHMOD', 0777);
2417 if (!defined('_DEFAULT_CHARSET')) {
2418 /** Le charset par défaut lors de l'installation */
2419 define('_DEFAULT_CHARSET', 'utf-8');
2421 if (!defined('_ROOT_PLUGINS')) {
2422 define('_ROOT_PLUGINS', _ROOT_RACINE
. "plugins/");
2424 if (!defined('_ROOT_PLUGINS_DIST')) {
2425 define('_ROOT_PLUGINS_DIST', _ROOT_RACINE
. "plugins-dist/");
2427 if (!defined('_ROOT_PLUGINS_SUPPL') && defined('_DIR_PLUGINS_SUPPL') && _DIR_PLUGINS_SUPPL
) {
2428 define('_ROOT_PLUGINS_SUPPL', _ROOT_RACINE
. str_replace(_DIR_RACINE
, '', _DIR_PLUGINS_SUPPL
));
2431 // La taille des Log
2432 if (!defined('_MAX_LOG')) {
2433 define('_MAX_LOG', 100);
2436 // Sommes-nous dans l'empire du Mal ?
2437 // (ou sous le signe du Pingouin, ascendant GNU ?)
2438 if (isset($_SERVER['SERVER_SOFTWARE']) and strpos($_SERVER['SERVER_SOFTWARE'], '(Win') !== false) {
2439 if (!defined('_OS_SERVEUR')) {
2440 define('_OS_SERVEUR', 'windows');
2442 if (!defined('_SPIP_LOCK_MODE')) {
2443 define('_SPIP_LOCK_MODE', 1);
2444 } // utiliser le flock php
2446 if (!defined('_OS_SERVEUR')) {
2447 define('_OS_SERVEUR', '');
2449 if (!defined('_SPIP_LOCK_MODE')) {
2450 define('_SPIP_LOCK_MODE', 1);
2451 } // utiliser le flock php
2452 #if (!defined('_SPIP_LOCK_MODE')) define('_SPIP_LOCK_MODE',2); // utiliser le nfslock de spip mais link() est tres souvent interdite
2455 // Langue par defaut
2456 if (!defined('_LANGUE_PAR_DEFAUT')) {
2457 define('_LANGUE_PAR_DEFAUT', 'fr');
2461 // Module de lecture/ecriture/suppression de fichiers utilisant flock()
2462 // (non surchargeable en l'etat ; attention si on utilise include_spip()
2463 // pour le rendre surchargeable, on va provoquer un reecriture
2464 // systematique du noyau ou une baisse de perfs => a etudier)
2465 include_once _ROOT_RESTREINT
. 'inc/flock.php';
2467 // charger tout de suite le path et son cache
2470 // *********** traiter les variables ************
2476 // Ne pas se faire manger par un bug php qui accepte ?GLOBALS[truc]=toto
2477 if (isset($_REQUEST['GLOBALS'])) {
2480 // nettoyer les magic quotes \' et les caracteres nuls %00
2481 spip_desinfecte($_GET);
2482 spip_desinfecte($_POST);
2483 spip_desinfecte($_COOKIE);
2484 spip_desinfecte($_REQUEST);
2486 // Si les variables sont passees en global par le serveur,
2487 // il faut faire quelques verifications de base
2488 // Todo: test à supprimer lorsque version PHP minimum >= 5.4.
2489 $avertir_register_globals = false;
2490 if (test_valeur_serveur(@ini_get
('register_globals'))) {
2491 // ne pas desinfecter les globales en profondeur car elle contient aussi les
2492 // precedentes, qui seraient desinfectees 2 fois.
2493 spip_desinfecte($GLOBALS, false);
2495 if (include_spip('inc/php3')) {
2496 spip_register_globals(true);
2499 $avertir_register_globals = true;
2502 // appliquer le cookie_prefix
2503 if ($GLOBALS['cookie_prefix'] != 'spip') {
2504 include_spip('inc/cookie');
2505 recuperer_cookies_spip($GLOBALS['cookie_prefix']);
2509 // Capacites php (en fonction de la version)
2511 $GLOBALS['flag_ob'] = (function_exists("ob_start")
2512 && function_exists("ini_get")
2513 && !strstr(@ini_get
('disable_functions'), 'ob_'));
2514 $GLOBALS['flag_sapi_name'] = function_exists("php_sapi_name");
2515 $GLOBALS['flag_get_cfg_var'] = (@get_cfg_var
('error_reporting') != "");
2516 $GLOBALS['flag_upload'] = (!$GLOBALS['flag_get_cfg_var'] ||
2517 (get_cfg_var('upload_max_filesize') > 0));
2520 // Compatibilite avec serveurs ne fournissant pas $REQUEST_URI
2521 if (isset($_SERVER['REQUEST_URI'])) {
2522 $GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
2524 $GLOBALS['REQUEST_URI'] = (php_sapi_name() !== 'cli') ?
$_SERVER['PHP_SELF'] : '';
2525 if (!empty($_SERVER['QUERY_STRING'])
2526 and !strpos($_SERVER['REQUEST_URI'], '?')
2528 $GLOBALS['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
2532 // Duree de validite de l'alea pour les cookies et ce qui s'ensuit.
2533 if (!defined('_RENOUVELLE_ALEA')) {
2534 define('_RENOUVELLE_ALEA', 12 * 3600);
2536 if (!defined('_DUREE_COOKIE_ADMIN')) {
2537 define('_DUREE_COOKIE_ADMIN', 14 * 24 * 3600);
2540 // charger les meta si possible et renouveller l'alea au besoin
2541 // charge aussi effacer_meta et ecrire_meta
2542 $inc_meta = charger_fonction('meta', 'inc');
2545 // on a pas pu le faire plus tot
2546 if ($avertir_register_globals) {
2547 avertir_auteurs("register_globals",
2548 _L("Problème de sécurité : register_globals=on; dans php.ini à corriger."));
2551 // nombre de repertoires depuis la racine
2552 // on compare a l'adresse de spip.php : $_SERVER["SCRIPT_NAME"]
2553 // ou a defaut celle donnee en meta ; (mais si celle-ci est fausse
2554 // le calcul est faux)
2555 if (!_DIR_RESTREINT
) {
2556 $GLOBALS['profondeur_url'] = 1;
2558 $uri = isset($_SERVER['REQUEST_URI']) ?
explode('?', $_SERVER['REQUEST_URI']) : '';
2559 $uri_ref = $_SERVER["SCRIPT_NAME"];
2561 // si on est appele avec un autre ti, on est sans doute en mutu
2562 // si jamais c'est de la mutu avec sous rep, on est perdu si on se fie
2563 // a spip.php qui est a la racine du spip, et vue qu'on sait pas se reperer
2564 // s'en remettre a l'adresse du site. alea jacta est.
2565 or $ti !== _NOM_TEMPORAIRES_INACCESSIBLES
2568 if (isset($GLOBALS['meta']['adresse_site'])) {
2569 $uri_ref = parse_url($GLOBALS['meta']['adresse_site']);
2570 $uri_ref = (isset($uri_ref['path']) ?
$uri_ref['path'] : '') . '/';
2575 if (!$uri or !$uri_ref) {
2576 $GLOBALS['profondeur_url'] = 0;
2578 $GLOBALS['profondeur_url'] = max(0,
2579 substr_count($uri[0], '/')
2580 - substr_count($uri_ref, '/'));
2583 // s'il y a un cookie ou PHP_AUTH, initialiser visiteur_session
2584 if (_FILE_CONNECT
) {
2585 if (verifier_visiteur() == '0minirezo'
2586 // si c'est un admin sans cookie admin, il faut ignorer le cache chemin !
2587 and !isset($_COOKIE['spip_admin'])
2596 * Complements d'initialisation non critiques pouvant etre realises
2600 function spip_initialisation_suite() {
2601 static $too_late = 0;
2606 // taille mini des login
2607 if (!defined('_LOGIN_TROP_COURT')) {
2608 define('_LOGIN_TROP_COURT', 4);
2611 // la taille maxi des logos (0 : pas de limite) (pas de define par defaut, ce n'est pas utile)
2612 #if (!defined('_LOGO_MAX_SIZE')) define('_LOGO_MAX_SIZE', 0); # poids en ko
2613 #if (!defined('_LOGO_MAX_WIDTH')) define('_LOGO_MAX_WIDTH', 0); # largeur en pixels
2614 #if (!defined('_LOGO_MAX_HEIGHT')) define('_LOGO_MAX_HEIGHT', 0); # hauteur en pixels
2616 // la taille maxi des images (0 : pas de limite) (pas de define par defaut, ce n'est pas utile)
2617 #if (!defined('_DOC_MAX_SIZE')) define('_DOC_MAX_SIZE', 0); # poids en ko
2618 #if (!defined('_IMG_MAX_SIZE')) define('_IMG_MAX_SIZE', 0); # poids en ko
2619 #if (!defined('_IMG_MAX_WIDTH')) define('_IMG_MAX_WIDTH', 0); # largeur en pixels
2620 #if (!defined('_IMG_MAX_HEIGHT')) define('_IMG_MAX_HEIGHT', 0); # hauteur en pixels
2622 if (!defined('_PASS_LONGUEUR_MINI')) {
2623 define('_PASS_LONGUEUR_MINI', 6);
2627 // Qualite des images calculees automatiquement. C'est un nombre entre 0 et 100, meme pour imagick (on ramene a 0..1 par la suite)
2628 if (!defined('_IMG_QUALITE')) {
2629 define('_IMG_QUALITE', 85);
2630 } # valeur par defaut
2631 if (!defined('_IMG_GD_QUALITE')) {
2632 define('_IMG_GD_QUALITE', _IMG_QUALITE
);
2633 } # surcharge pour la lib GD
2634 if (!defined('_IMG_CONVERT_QUALITE')) {
2635 define('_IMG_CONVERT_QUALITE', _IMG_QUALITE
);
2636 } # surcharge pour imagick en ligne de commande
2637 // Historiquement la valeur pour imagick semble differente. Si ca n'est pas necessaire, il serait preferable de garder _IMG_QUALITE
2638 if (!defined('_IMG_IMAGICK_QUALITE')) {
2639 define('_IMG_IMAGICK_QUALITE', 75);
2640 } # surcharge pour imagick en PHP
2642 if (!defined('_COPIE_LOCALE_MAX_SIZE')) {
2643 define('_COPIE_LOCALE_MAX_SIZE', 33554432);
2646 // qq chaines standard
2647 if (!defined('_ACCESS_FILE_NAME')) {
2648 define('_ACCESS_FILE_NAME', '.htaccess');
2650 if (!defined('_AUTH_USER_FILE')) {
2651 define('_AUTH_USER_FILE', '.htpasswd');
2653 if (!defined('_SPIP_DUMP')) {
2654 define('_SPIP_DUMP', 'dump@nom_site@@stamp@.xml');
2656 if (!defined('_CACHE_RUBRIQUES')) {
2657 /** Fichier cache pour le navigateur de rubrique du bandeau */
2658 define('_CACHE_RUBRIQUES', _DIR_TMP
. 'menu-rubriques-cache.txt');
2660 if (!defined('_CACHE_RUBRIQUES_MAX')) {
2661 /** Nombre maxi de rubriques enfants affichées pour chaque rubrique du navigateur de rubrique du bandeau */
2662 define('_CACHE_RUBRIQUES_MAX', 500);
2665 if (!defined('_EXTENSION_SQUELETTES')) {
2666 define('_EXTENSION_SQUELETTES', 'html');
2669 if (!defined('_DOCTYPE_ECRIRE')) {
2670 define('_DOCTYPE_ECRIRE',
2671 // "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>\n");
2672 //"<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>\n");
2673 //"<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>\n");
2674 // "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.1 //EN' 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>\n");
2675 "<!DOCTYPE html>\n");
2677 if (!defined('_DOCTYPE_AIDE')) {
2678 define('_DOCTYPE_AIDE',
2679 "<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Frameset//EN' 'http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd'>");
2682 /** L'adresse de base du site ; on peut mettre '' si la racine est gerée par
2683 * le script de l'espace public, alias index.php */
2684 if (!defined('_SPIP_SCRIPT')) {
2685 define('_SPIP_SCRIPT', 'spip.php');
2687 /** Argument page, personalisable en cas de conflit avec un autre script */
2688 if (!defined('_SPIP_PAGE')) {
2689 define('_SPIP_PAGE', 'page');
2692 // le script de l'espace prive
2693 // Mettre a "index.php" si DirectoryIndex ne le fait pas ou pb connexes:
2694 // les anciens IIS n'acceptent pas les POST sur ecrire/ (#419)
2695 // meme pb sur thttpd cf. http://forum.spip.net/fr_184153.html
2696 if (!defined('_SPIP_ECRIRE_SCRIPT')) {
2697 define('_SPIP_ECRIRE_SCRIPT', (empty($_SERVER['SERVER_SOFTWARE']) ?
'' :
2698 preg_match(',IIS|thttpd,', $_SERVER['SERVER_SOFTWARE']) ?
2703 if (!defined('_SPIP_AJAX')) {
2704 define('_SPIP_AJAX', ((!isset($_COOKIE['spip_accepte_ajax']))
2706 : (($_COOKIE['spip_accepte_ajax'] != -1) ?
1 : 0)));
2709 // La requete est-elle en ajax ?
2710 if (!defined('_AJAX')) {
2712 (isset($_SERVER['HTTP_X_REQUESTED_WITH']) # ajax jQuery
2713 or !empty($_REQUEST['var_ajax_redir']) # redirection 302 apres ajax jQuery
2714 or !empty($_REQUEST['var_ajaxcharset']) # compat ascendante pour plugins
2715 or !empty($_REQUEST['var_ajax']) # forms ajax & inclure ajax de spip
2717 and empty($_REQUEST['var_noajax']) # horrible exception, car c'est pas parce que la requete est ajax jquery qu'il faut tuer tous les formulaires ajax qu'elle contient
2721 # nombre de pixels maxi pour calcul de la vignette avec gd
2722 # au dela de 5500000 on considere que php n'est pas limite en memoire pour cette operation
2723 # les configurations limitees en memoire ont un seuil plutot vers 1MPixel
2724 if (!defined('_IMG_GD_MAX_PIXELS')) {
2725 define('_IMG_GD_MAX_PIXELS',
2726 (isset($GLOBALS['meta']['max_taille_vignettes']) and $GLOBALS['meta']['max_taille_vignettes'])
2727 ?
$GLOBALS['meta']['max_taille_vignettes']
2731 if (!defined('_MEMORY_LIMIT_MIN')) {
2732 define('_MEMORY_LIMIT_MIN', 16);
2734 // si on est dans l'espace prive et si le besoin est superieur a 8Mo (qui est vraiment le standard)
2735 // on verifie que la memoire est suffisante pour le compactage css+js pour eviter la page blanche
2736 // il y aura d'autres problemes et l'utilisateur n'ira pas tres loin, mais ce sera plus comprehensible qu'une page blanche
2737 if (test_espace_prive() and _MEMORY_LIMIT_MIN
> 8) {
2738 if ($memory = trim(ini_get('memory_limit')) and $memory != -1) {
2739 $unit = strtolower(substr($memory, -1));
2740 $memory = substr($memory, 0, -1);
2742 // Le modifieur 'G' est disponible depuis PHP 5.1.0
2750 if ($memory < _MEMORY_LIMIT_MIN
* 1024 * 1024) {
2751 @ini_set
('memory_limit', $m = _MEMORY_LIMIT_MIN
. 'M');
2752 if (trim(ini_get('memory_limit')) != $m) {
2753 if (!defined('_INTERDIRE_COMPACTE_HEAD_ECRIRE')) {
2754 define('_INTERDIRE_COMPACTE_HEAD_ECRIRE', true);
2755 } // evite une page blanche car on ne saura pas calculer la css dans ce hit
2759 if (!defined('_INTERDIRE_COMPACTE_HEAD_ECRIRE')) {
2760 define('_INTERDIRE_COMPACTE_HEAD_ECRIRE', true);
2762 } // evite une page blanche car on ne saura pas calculer la css dans ce hit
2764 // Protocoles a normaliser dans les chaines de langues
2765 if (!defined('_PROTOCOLES_STD')) {
2766 define('_PROTOCOLES_STD', 'http|https|ftp|mailto|webcal');
2773 * Repérer les variables d'URL spéciales `var_mode` qui conditionnent
2774 * la validité du cache ou certains affichages spéciaux.
2776 * Le paramètre d'URL `var_mode` permet de
2777 * modifier la pérennité du cache, recalculer des urls
2778 * ou d'autres petit caches (trouver_table, css et js compactes ...),
2779 * d'afficher un écran de débug ou des traductions non réalisées.
2781 * En fonction de ces paramètres dans l'URL appelante, on définit
2782 * da constante `_VAR_MODE` qui servira ensuite à SPIP.
2784 * Le paramètre `var_mode` accepte ces valeurs :
2786 * - `calcul` : force un calcul du cache de la page (sans forcément recompiler les squelettes)
2787 * - `recalcul` : force un calcul du cache de la page en recompilant au préabable les squelettes
2788 * - `inclure` : modifie l'affichage en ajoutant visuellement le nom de toutes les inclusions qu'elle contient
2789 * - `debug` : modifie l'affichage activant le mode "debug"
2790 * - `preview` : modifie l'affichage en ajoutant aux boucles les éléments prévisualisables
2791 * - `traduction` : modifie l'affichage en affichant des informations sur les chaînes de langues utilisées
2792 * - `urls` : permet de recalculer les URLs des objets appelés dans la page par les balises `#URL_xx`
2793 * - `images` : permet de recalculer les filtres d'images utilisés dans la page
2795 * En dehors des modes `calcul` et `recalcul`, une autorisation 'previsualiser' ou 'debug' est testée.
2798 * Il éxiste également le paramètre `var_profile` qui modifie l'affichage pour incruster
2799 * le nombre de requêtes SQL utilisées dans la page, qui peut se compléter avec le paramètre
2800 * ` var_mode` (calcul ou recalcul).
2802 function init_var_mode() {
2803 static $done = false;
2806 if (isset($_GET['var_mode'])) {
2807 $var_mode = explode(',', $_GET['var_mode']);
2808 // tout le monde peut calcul/recalcul
2809 if (!defined('_VAR_MODE')) {
2810 if (in_array('recalcul', $var_mode)) {
2811 define('_VAR_MODE', 'recalcul');
2812 } elseif (in_array('calcul', $var_mode)) {
2813 define('_VAR_MODE', 'calcul');
2816 $var_mode = array_diff($var_mode, array('calcul', 'recalcul'));
2818 include_spip('inc/autoriser');
2819 // autoriser preview si preview seulement, et sinon autoriser debug
2821 ($_GET['var_mode'] == 'preview')
2825 if (in_array('traduction', $var_mode)) {
2826 // forcer le calcul pour passer dans traduire
2827 if (!defined('_VAR_MODE')) {
2828 define('_VAR_MODE', 'calcul');
2830 // et ne pas enregistrer de cache pour ne pas trainer les surlignages sur d'autres pages
2831 if (!defined('_VAR_NOCACHE')) {
2832 define('_VAR_NOCACHE', true);
2834 $var_mode = array_diff($var_mode, array('traduction'));
2836 if (in_array('preview', $var_mode)) {
2837 // basculer sur les criteres de preview dans les boucles
2838 if (!defined('_VAR_PREVIEW')) {
2839 define('_VAR_PREVIEW', true);
2842 if (!defined('_VAR_MODE')) {
2843 define('_VAR_MODE', 'calcul');
2845 // et ne pas enregistrer de cache
2846 if (!defined('_VAR_NOCACHE')) {
2847 define('_VAR_NOCACHE', true);
2849 $var_mode = array_diff($var_mode, array('preview'));
2851 if (in_array('inclure', $var_mode)) {
2852 // forcer le compilo et ignorer les caches existants
2853 if (!defined('_VAR_MODE')) {
2854 define('_VAR_MODE', 'calcul');
2856 if (!defined('_VAR_INCLURE')) {
2857 define('_VAR_INCLURE', true);
2859 // et ne pas enregistrer de cache
2860 if (!defined('_VAR_NOCACHE')) {
2861 define('_VAR_NOCACHE', true);
2863 $var_mode = array_diff($var_mode, array('inclure'));
2865 if (in_array('urls', $var_mode)) {
2866 // forcer le compilo et ignorer les caches existants
2867 if (!defined('_VAR_MODE')) {
2868 define('_VAR_MODE', 'calcul');
2870 if (!defined('_VAR_URLS')) {
2871 define('_VAR_URLS', true);
2873 $var_mode = array_diff($var_mode, array('urls'));
2875 if (in_array('images', $var_mode)) {
2876 // forcer le compilo et ignorer les caches existants
2877 if (!defined('_VAR_MODE')) {
2878 define('_VAR_MODE', 'calcul');
2880 // indiquer qu'on doit recalculer les images
2881 if (!defined('_VAR_IMAGES')) {
2882 define('_VAR_IMAGES', true);
2884 $var_mode = array_diff($var_mode, array('images'));
2886 if (in_array('debug', $var_mode)) {
2887 if (!defined('_VAR_MODE')) {
2888 define('_VAR_MODE', 'debug');
2890 // et ne pas enregistrer de cache
2891 if (!defined('_VAR_NOCACHE')) {
2892 define('_VAR_NOCACHE', true);
2894 $var_mode = array_diff($var_mode, array('debug'));
2896 if (count($var_mode) and !defined('_VAR_MODE')) {
2897 define('_VAR_MODE', reset($var_mode));
2899 if (isset($GLOBALS['visiteur_session']['nom'])) {
2900 spip_log($GLOBALS['visiteur_session']['nom']
2905 // si on n'est pas connecte on se redirige
2906 if (!$GLOBALS['visiteur_session']) {
2907 include_spip('inc/headers');
2908 redirige_par_entete(generer_url_public('login',
2909 'url=' . rawurlencode(
2910 parametre_url(self(), 'var_mode', $_GET['var_mode'], '&')
2917 if (!defined('_VAR_MODE')) {
2919 * Indique le mode de calcul ou d'affichage de la page.
2920 * @see init_var_mode()
2922 define('_VAR_MODE', false);
2928 // Annuler les magic quotes \' sur GET POST COOKIE et GLOBALS ;
2929 // supprimer aussi les eventuels caracteres nuls %00, qui peuvent tromper
2930 // la commande is_readable('chemin/vers/fichier/interdit%00truc_normal')
2931 // http://code.spip.net/@spip_desinfecte
2932 function spip_desinfecte(&$t, $deep = true) {
2933 static $magic_quotes;
2934 if (!isset($magic_quotes)) {
2935 $magic_quotes = @get_magic_quotes_gpc
();
2938 foreach ($t as $key => $val) {
2939 if (is_string($t[$key])) {
2940 if ($magic_quotes) {
2941 $t[$key] = stripslashes($t[$key]);
2943 $t[$key] = str_replace(chr(0), '-', $t[$key]);
2944 } // traiter aussi les "texte_plus" de article_edit
2946 if ($deep and is_array($t[$key]) and $key !== 'GLOBALS') {
2947 spip_desinfecte($t[$key], $deep);
2953 // retourne le statut du visiteur s'il s'annonce
2955 // http://code.spip.net/@verifier_visiteur
2956 function verifier_visiteur() {
2957 // Rq: pour que cette fonction marche depuis mes_options
2958 // il faut forcer l'init si ce n'est fait
2959 // mais on risque de perturber des plugins en initialisant trop tot
2960 // certaines constantes
2961 @spip_initialisation_core
(
2962 (_DIR_RACINE
. _NOM_PERMANENTS_INACCESSIBLES
),
2963 (_DIR_RACINE
. _NOM_PERMANENTS_ACCESSIBLES
),
2964 (_DIR_RACINE
. _NOM_TEMPORAIRES_INACCESSIBLES
),
2965 (_DIR_RACINE
. _NOM_TEMPORAIRES_ACCESSIBLES
)
2968 // Demarrer une session NON AUTHENTIFIEE si on donne son nom
2969 // dans un formulaire sans login (ex: #FORMULAIRE_FORUM)
2970 // Attention on separe bien session_nom et nom, pour eviter
2971 // les melanges entre donnees SQL et variables plus aleatoires
2972 $variables_session = array('session_nom', 'session_email');
2973 foreach ($variables_session as $var) {
2974 if (_request($var) !== null) {
2980 #@spip_initialisation_suite();
2981 $session = charger_fonction('session', 'inc');
2983 include_spip('inc/texte');
2984 foreach ($variables_session as $var) {
2985 if (($a = _request($var)) !== null) {
2986 $GLOBALS['visiteur_session'][$var] = safehtml($a);
2989 if (!isset($GLOBALS['visiteur_session']['id_auteur'])) {
2990 $GLOBALS['visiteur_session']['id_auteur'] = 0;
2992 $session($GLOBALS['visiteur_session']);
2997 $h = (isset($_SERVER['PHP_AUTH_USER']) and !$GLOBALS['ignore_auth_http']);
2998 if ($h or isset($_COOKIE['spip_session']) or isset($_COOKIE[$GLOBALS['cookie_prefix'] . '_session'])) {
3000 $session = charger_fonction('session', 'inc');
3002 return $GLOBALS['visiteur_session']['statut'];
3004 if ($h and isset($_SERVER['PHP_AUTH_PW'])) {
3005 include_spip('inc/auth');
3006 $h = lire_php_auth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
3009 $GLOBALS['visiteur_session'] = $h;
3011 return $GLOBALS['visiteur_session']['statut'];
3015 // au moins son navigateur nous dit la langue preferee de cet inconnu
3016 include_spip('inc/lang');
3017 utiliser_langue_visiteur();
3024 * Sélectionne la langue donnée en argument et mémorise la courante
3026 * Restaure l'ancienne langue si appellée sans argument.
3029 * On pourrait économiser l'empilement en cas de non changemnt
3030 * et lui faire retourner `False` pour prevenir l'appelant
3031 * Le noyau de Spip sait le faire, mais pour assurer la compatibilité
3032 * cette fonction retourne toujours non `False`
3034 * @uses changer_langue()
3035 * @param null|string $lang
3036 * - string : Langue à appliquer,
3037 * - null : Pour restituer la dernière langue mémorisée.
3039 * - string Langue utilisée.
3041 function lang_select($lang = null) {
3042 static $pile_langues = array();
3043 if (!function_exists('changer_langue')) {
3044 include_spip('inc/lang');
3046 if ($lang === null) {
3047 $lang = array_pop($pile_langues);
3049 array_push($pile_langues, $GLOBALS['spip_lang']);
3051 if (isset($GLOBALS['spip_lang']) and $lang == $GLOBALS['spip_lang']) {
3054 changer_langue($lang);
3060 * Renvoie une chaîne qui identifie la session courante
3062 * Permet de savoir si on peut utiliser un cache enregistré pour cette session.
3063 * Cette chaîne est courte (8 cars) pour pouvoir être utilisée dans un nom
3066 * @pipeline_appel definir_session
3068 * @param bool $force
3070 * Identifiant de la session
3072 function spip_session($force = false) {
3074 if ($force or !isset($session)) {
3075 $s = pipeline('definir_session',
3076 $GLOBALS['visiteur_session']
3077 ?
serialize($GLOBALS['visiteur_session'])
3078 . '_' . @$_COOKIE['spip_session']
3081 $session = $s ?
substr(md5($s), 0, 8) : '';
3084 #spip_log('session: '.$session);
3090 * Retourne un lien vers une aide
3092 * Aide, aussi depuis l'espace privé à présent.
3093 * Surchargeable mais pas d'erreur fatale si indisponible.
3095 * @param string $aide
3096 * Cle d'identification de l'aide desiree
3097 * @param bool $distante
3098 * Generer une url locale (par defaut)
3099 * ou une url distante [directement sur spip.net]
3101 * Lien sur une icone d'aide
3103 function aider($aide = '', $distante = false) {
3104 $aider = charger_fonction('aide', 'inc', true);
3106 return $aider ?
$aider($aide, '', array(), $distante) : '';
3110 * Page `exec=info` : retourne le contenu de la fonction php `phpinfo()`
3112 * Si l’utiliseur est un webmestre.
3114 function exec_info_dist() {
3116 include_spip('inc/autoriser');
3117 if (autoriser('webmestre')) {
3120 include_spip('inc/filtres');
3121 sinon_interdire_acces();
3126 * Génère une erreur de squelette
3128 * Génère une erreur de squelette qui sera bien visible par un
3129 * administrateur authentifié lors d'une visite de la page en erreur
3131 * @param bool|string|array $message
3132 * - Message d'erreur (string|array)
3133 * - false pour retourner le texte des messages d'erreurs
3134 * - vide pour afficher les messages d'erreurs
3135 * @param string|array|object $lieu
3136 * Lieu d'origine de l'erreur
3137 * @return null|string
3138 * - Rien dans la plupart des cas
3139 * - string si $message à false.
3141 function erreur_squelette($message = '', $lieu = '') {
3142 $debusquer = charger_fonction('debusquer', 'public');
3143 if (is_array($lieu)) {
3144 include_spip('public/compiler');
3145 $lieu = reconstruire_contexte_compil($lieu);
3148 return $debusquer($message, $lieu);
3152 * Calcule un squelette avec un contexte et retourne son contenu
3154 * La fonction de base de SPIP : un squelette + un contexte => une page.
3155 * $fond peut etre un nom de squelette, ou une liste de squelette au format array.
3156 * Dans ce dernier cas, les squelettes sont tous evalues et mis bout a bout
3157 * $options permet de selectionner les options suivantes :
3159 * - trim => true (valeur par defaut) permet de ne rien renvoyer si le fond ne produit que des espaces ;
3160 * - raw => true permet de recuperer la strucure $page complete avec entetes et invalideurs
3161 * pour chaque $fond fourni.
3164 * @param string /array $fond
3165 * - Le ou les squelettes à utiliser, sans l'extension, {@example prive/liste/auteurs}
3166 * - Le fichier sera retrouvé dans la liste des chemins connus de SPIP (squelettes, plugins, spip)
3167 * @param array $contexte
3168 * - Informations de contexte envoyées au squelette, {@example array('id_rubrique' => 8)}
3169 * - La langue est transmise automatiquement (sauf option étoile).
3170 * @param array $options
3171 * Options complémentaires :
3173 * - trim : applique un trim sur le résultat (true par défaut)
3174 * - raw : retourne un tableau d'information sur le squelette (false par défaut)
3175 * - etoile : ne pas transmettre la langue au contexte automatiquement (false par défaut),
3176 * équivalent de INCLURE*
3177 * - ajax : gere les liens internes du squelette en ajax (équivalent du paramètre {ajax})
3178 * @param string $connect
3179 * Non du connecteur de bdd a utiliser
3180 * @return string|array
3181 * - Contenu du squelette calculé
3182 * - ou tableau d'information sur le squelette.
3184 function recuperer_fond($fond, $contexte = array(), $options = array(), $connect = '') {
3185 if (!function_exists('evaluer_fond')) {
3186 include_spip('public/assembler');
3188 // assurer la compat avec l'ancienne syntaxe
3189 // (trim etait le 3eme argument, par defaut a true)
3190 if (!is_array($options)) {
3191 $options = array('trim' => $options);
3193 if (!isset($options['trim'])) {
3194 $options['trim'] = true;
3197 if (isset($contexte['connect'])) {
3198 $connect = $contexte['connect'];
3199 unset($contexte['connect']);
3205 if (!isset($options['etoile']) or !$options['etoile']) {
3206 // Si on a inclus sans fixer le critere de lang, on prend la langue courante
3207 if (!isset($contexte['lang'])) {
3208 $contexte['lang'] = $GLOBALS['spip_lang'];
3211 if ($contexte['lang'] != $GLOBALS['meta']['langue_site']) {
3212 $lang_select = lang_select($contexte['lang']);
3216 if (!isset($GLOBALS['_INC_PUBLIC'])) {
3217 $GLOBALS['_INC_PUBLIC'] = 0;
3220 $GLOBALS['_INC_PUBLIC']++
;
3223 foreach (is_array($fond) ?
$fond : array($fond) as $f) {
3224 $page = evaluer_fond($f, $contexte, $connect);
3226 $c = isset($options['compil']) ?
$options['compil'] : '';
3227 $a = array('fichier' => $fond);
3228 $erreur = _T('info_erreur_squelette2', $a); // squelette introuvable
3229 erreur_squelette($erreur, $c);
3230 // eviter des erreurs strictes ensuite sur $page['cle'] en PHP >= 5.4
3231 $page = array('texte' => '', 'erreur' => $erreur);
3234 $page = pipeline('recuperer_fond', array(
3235 'args' => array('fond' => $f, 'contexte' => $contexte, 'options' => $options, 'connect' => $connect),
3238 if (isset($options['ajax']) and $options['ajax']) {
3239 if (!function_exists('encoder_contexte_ajax')) {
3240 include_spip('inc/filtres');
3242 $page['texte'] = encoder_contexte_ajax(
3245 array('fond' => $f),
3246 ($connect ?
array('connect' => $connect) : array())
3254 if (isset($options['raw']) and $options['raw']) {
3257 $texte .= $options['trim'] ?
rtrim($page['texte']) : $page['texte'];
3261 $GLOBALS['_INC_PUBLIC']--;
3266 if (isset($options['raw']) and $options['raw']) {
3267 return is_array($fond) ?
$pages : reset($pages);
3269 return $options['trim'] ?
ltrim($texte) : $texte;
3274 * Trouve un squelette dans le repertoire modeles/
3279 function trouve_modele($nom) {
3280 return trouver_fond($nom, 'modeles/');
3284 * Trouver un squelette dans le chemin
3285 * on peut specifier un sous-dossier dans $dir
3286 * si $pathinfo est a true, retourne un tableau avec
3287 * les composantes du fichier trouve
3288 * + le chemin complet sans son extension dans fond
3290 * @param string $nom
3291 * @param string $dir
3292 * @param bool $pathinfo
3293 * @return array|string
3295 function trouver_fond($nom, $dir = '', $pathinfo = false) {
3296 $f = find_in_path($nom . '.' . _EXTENSION_SQUELETTES
, $dir ?
rtrim($dir, '/') . '/' : '');
3300 // renvoyer un tableau detaille si $pathinfo==true
3302 if (!isset($p['extension']) or !$p['extension']) {
3303 $p['extension'] = _EXTENSION_SQUELETTES
;
3305 if (!isset($p['extension']) or !$p['filename']) {
3306 $p['filename'] = ($p['basename'] ?
substr($p['basename'], 0, -strlen($p['extension']) - 1) : '');
3308 $p['fond'] = ($f ?
substr($f, 0, -strlen($p['extension']) - 1) : '');
3314 * Teste, pour un nom de page de l'espace privé, s'il est possible
3315 * de générer son contenu.
3317 * Dans ce cas, on retourne la fonction d'exécution correspondante à utiliser
3318 * (du répertoire `ecrire/exec`). Deux cas particuliers et prioritaires :
3319 * `fond` ou `fond_monobloc` sont retournés si des squelettes existent.
3321 * - `fond` : pour des squelettes de `prive/squelettes/contenu`
3322 * ou pour des objets éditoriaux dont les suqelettes seront échaffaudés
3323 * - `fond_monobloc` (compatibilité avec SPIP 2.1) : pour des squelettes de `prive/exec`
3325 * @param string $nom
3328 * Nom de l'exec, sinon chaîne vide.
3330 function tester_url_ecrire($nom) {
3331 static $exec = array();
3332 if (isset($exec[$nom])) {
3335 // tester si c'est une page en squelette
3336 if (trouver_fond($nom, 'prive/squelettes/contenu/')) {
3337 return $exec[$nom] = 'fond';
3338 } // compat skels orthogonaux version precedente
3339 elseif (trouver_fond($nom, 'prive/exec/')) {
3340 return $exec[$nom] = 'fond_monobloc';
3341 } // echafaudage d'un fond !
3342 elseif (include_spip('public/styliser_par_z') and z_echafaudable($nom)) {
3343 return $exec[$nom] = 'fond';
3345 // attention, il ne faut pas inclure l'exec ici
3346 // car sinon #URL_ECRIRE provoque des inclusions
3347 // et des define intrusifs potentiels
3348 return $exec[$nom] = ((find_in_path("{$nom}.php", 'exec/') or charger_fonction($nom, 'exec', true)) ?
$nom : '');
3353 * Tente de charger dynamiquement une extension PHP
3357 * $ok = charger_php_extension('sqlite');
3359 * @uses inc_charger_php_extension_dist() Si la librairie n'est pas déjà charchée
3361 * @param string $module Nom du module à charger
3362 * @return bool true si le module est chargé
3364 function charger_php_extension($module) {
3365 if (extension_loaded($module)) {
3368 $charger_php_extension = charger_fonction('charger_php_extension', 'inc');
3370 return $charger_php_extension($module);
3376 * Indique si le code HTML5 est permis sur le site public
3379 * true si et seulement si la configuration autorise le code HTML5 sur le site public
3381 function html5_permis() {
3382 return (isset($GLOBALS['meta']['version_html_max'])
3383 and ('html5' == $GLOBALS['meta']['version_html_max']));
3387 * Bloc de compatibilite : quasiment tous les plugins utilisent ces fonctions
3388 * desormais depreciees ; plutot que d'obliger tout le monde a charger
3389 * vieilles_defs, on va assumer l'histoire de ces 3 fonctions ubiquitaires
3393 * lire_meta : fonction dépréciée
3395 * @deprecated Utiliser `$GLOBALS['meta'][$nom]` ou `lire_config('nom')`
3396 * @see lire_config()
3397 * @param string $nom Clé de meta à lire
3398 * @return mixed Valeur de la meta.
3400 function lire_meta($nom) {
3401 return isset($GLOBALS['meta'][$nom]) ?
$GLOBALS['meta'][$nom] : null;
3406 * ecrire_metas : fonction dépréciée
3410 function ecrire_metas() { }
3413 * Retourne une ligne d'un résultat de requête mysql (déprécié)
3416 * @deprecated Utiliser sql_fetch()
3417 * @param Ressource $r Ressource mysql
3418 * @param int|null $t Type de retour
3419 * @return array|void|bool Tableau de la ligne SQL
3421 function spip_fetch_array($r, $t = null) {
3424 return sql_fetch($r);
3427 if ($t == 'SPIP_NUM') {
3430 if ($t == 'SPIP_BOTH') {
3433 if ($t == 'SPIP_ASSOC') {
3436 spip_log("appel deprecie de spip_fetch_array(..., $t)", 'vieilles_defs');
3438 return mysqli_fetch_array($r, $t);
3444 * Poser une alerte qui sera affiche aux auteurs de bon statut ('' = tous)
3445 * au prochain passage dans l'espace prive
3446 * chaque alerte doit avoir un nom pour eviter duplication a chaque hit
3447 * les alertes affichees une fois sont effacees
3449 * @param string $nom
3450 * @param string $message
3451 * @param string $statut
3453 function avertir_auteurs($nom, $message, $statut = '') {
3454 $alertes = $GLOBALS['meta']['message_alertes_auteurs'];
3456 or !is_array($alertes = unserialize($alertes))
3461 if (!isset($alertes[$statut])) {
3462 $alertes[$statut] = array();
3464 $alertes[$statut][$nom] = $message;
3465 ecrire_meta("message_alertes_auteurs", serialize($alertes));
3468 if (PHP_VERSION_ID
< 50500) {
3469 if (!function_exists('array_column')) {
3471 * Returns the values from a single column of the input array, identified by
3474 * Optionally, you may provide an $indexKey to index the values in the returned
3475 * array by the values from the $indexKey column in the input array.
3477 * @link http://php.net/manual/fr/function.array-column.php
3478 * @link https://github.com/ramsey/array_column/blob/master/src/array_column.php
3479 * @copyright Copyright (c) Ben Ramsey (http://benramsey.com)
3480 * @license http://opensource.org/licenses/MIT MIT
3482 * @param array $input A multi-dimensional array (record set) from which to pull
3483 * a column of values.
3484 * @param mixed $columnKey The column of values to return. This value may be the
3485 * integer key of the column you wish to retrieve, or it
3486 * may be the string key name for an associative array.
3487 * @param mixed $indexKey (Optional.) The column to use as the index/keys for
3488 * the returned array. This value may be the integer key
3489 * of the column, or it may be the string key name.
3492 function array_column($input = null, $columnKey = null, $indexKey = null)
3494 // Using func_get_args() in order to check for proper number of
3495 // parameters and trigger errors exactly as the built-in array_column()
3497 $argc = func_num_args();
3498 $params = func_get_args();
3501 trigger_error("array_column() expects at least 2 parameters, {$argc} given", E_USER_WARNING
);
3505 if (!is_array($params[0])) {
3507 'array_column() expects parameter 1 to be array, ' . gettype($params[0]) . ' given',
3513 if (!is_int($params[1])
3514 && !is_float($params[1])
3515 && !is_string($params[1])
3516 && $params[1] !== null
3517 && !(is_object($params[1]) && method_exists($params[1], '__toString'))
3519 trigger_error('array_column(): The column key should be either a string or an integer', E_USER_WARNING
);
3523 if (isset($params[2])
3524 && !is_int($params[2])
3525 && !is_float($params[2])
3526 && !is_string($params[2])
3527 && !(is_object($params[2]) && method_exists($params[2], '__toString'))
3529 trigger_error('array_column(): The index key should be either a string or an integer', E_USER_WARNING
);
3533 $paramsInput = $params[0];
3534 $paramsColumnKey = ($params[1] !== null) ?
(string) $params[1] : null;
3536 $paramsIndexKey = null;
3537 if (isset($params[2])) {
3538 if (is_float($params[2]) ||
is_int($params[2])) {
3539 $paramsIndexKey = (int) $params[2];
3541 $paramsIndexKey = (string) $params[2];
3545 $resultArray = array();
3547 foreach ($paramsInput as $row) {
3548 $key = $value = null;
3549 $keySet = $valueSet = false;
3551 if ($paramsIndexKey !== null && array_key_exists($paramsIndexKey, $row)) {
3553 $key = (string) $row[$paramsIndexKey];
3556 if ($paramsColumnKey === null) {
3559 } elseif (is_array($row) && array_key_exists($paramsColumnKey, $row)) {
3561 $value = $row[$paramsColumnKey];
3566 $resultArray[$key] = $value;
3568 $resultArray[] = $value;
3574 return $resultArray;