[PLUGINS] ~maj globale
[lhc/web/www.git] / www / plugins / saisies / inc / saisies.php
index 53853ef..ad7a3e8 100644 (file)
-<?php\r
-\r
-/**\r
- * Gestion de l'affichage des saisies\r
- *\r
- * @package SPIP\Saisies\Saisies\r
-**/\r
-\r
-// Sécurité\r
-if (!defined('_ECRIRE_INC_VERSION')) return;\r
-\r
-/*\r
- * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies\r
- *\r
- * saisies_lister_par_nom()\r
- * saisies_lister_champs()\r
- * saisies_lister_valeurs_defaut()\r
- * saisies_charger_champs()\r
- * saisies_chercher()\r
- * saisies_supprimer()\r
- * saisies_inserer()\r
- * saisies_deplacer()\r
- * saisies_modifier()\r
- * saisies_verifier()\r
- * saisies_comparer()\r
- * saisies_generer_html()\r
- * saisies_generer_vue()\r
- * saisies_generer_nom()\r
- * saisies_inserer_html()\r
- * saisies_lister_disponibles()\r
- * saisies_autonomes()\r
- */\r
-\r
-// Différentes méthodes pour trouver les saisies\r
-include_spip('inc/saisies_lister');\r
-\r
-// Différentes méthodes pour manipuler une liste de saisies\r
-include_spip('inc/saisies_manipuler');\r
-\r
-// Les outils pour afficher les saisies et leur vue\r
-include_spip('inc/saisies_afficher');\r
-\r
-/**\r
- * Cherche la description des saisies d'un formulaire CVT dont on donne le nom\r
- *\r
- * @param string $form Nom du formulaire dont on cherche les saisies\r
- * @param array $args Tableau d'arguments du formulaire\r
- * @return array Retourne les saisies du formulaire sinon false\r
- */\r
-function saisies_chercher_formulaire($form, $args){\r
-       if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)\r
-               and $saisies = call_user_func_array($fonction_saisies, $args)\r
-               and is_array($saisies)\r
-               // On passe les saisies dans un pipeline normé comme pour CVT\r
-               and $saisies = pipeline(\r
-                       'formulaire_saisies',\r
-                       array(\r
-                               'args' => array('form' => $form, 'args' => $args),\r
-                               'data' => $saisies\r
-                       )\r
-               )\r
-               // Si c'est toujours un tableau après le pipeline\r
-               and is_array($saisies)\r
-       ){\r
-               return $saisies;\r
-       }\r
-       else{\r
-               return false;\r
-       }\r
-}\r
-\r
-/**\r
- * Cherche une saisie par son id, son nom ou son chemin et renvoie soit la saisie, soit son chemin\r
- *\r
- * @param array $saisies Un tableau décrivant les saisies\r
- * @param unknown_type $id_ou_nom_ou_chemin L'identifiant ou le nom de la saisie à chercher ou le chemin sous forme d'une liste de clés\r
- * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin\r
- * @return array Retourne soit la saisie, soit son chemin, soit null\r
- */\r
-function saisies_chercher($saisies, $id_ou_nom_ou_chemin, $retourner_chemin=false){\r
-\r
-       if (is_array($saisies) and $id_ou_nom_ou_chemin){\r
-               if (is_string($id_ou_nom_ou_chemin)){\r
-                       $nom = $id_ou_nom_ou_chemin;\r
-                       // identifiant ? premier caractere @\r
-                       $id = ($nom[0] == '@');\r
-\r
-                       foreach($saisies as $cle => $saisie){\r
-                               $chemin = array($cle);\r
-                               // notre saisie est la bonne ?\r
-                               if ($nom == ($id ? $saisie['identifiant'] : $saisie['options']['nom'])) {\r
-                                       return $retourner_chemin ? $chemin : $saisie;\r
-                               // sinon a telle des enfants ? et si c'est le cas, cherchons dedans\r
-                               } elseif (isset($saisie['saisies']) and is_array($saisie['saisies']) and $saisie['saisies']\r
-                                       and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))) {\r
-                                               return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;\r
-                               }\r
-\r
-                       }\r
-               }\r
-               elseif (is_array($id_ou_nom_ou_chemin)){\r
-                       $chemin = $id_ou_nom_ou_chemin;\r
-                       $saisie = $saisies;\r
-                       // On vérifie l'existence quand même\r
-                       foreach ($chemin as $cle){\r
-                               if (isset($saisie[$cle])) $saisie = $saisie[$cle];\r
-                               else return null;\r
-                       }\r
-                       // Si c'est une vraie saisie\r
-                       if ($saisie['saisie'] and $saisie['options']['nom'])\r
-                               return $retourner_chemin ? $chemin : $saisie;\r
-               }\r
-       }\r
-       \r
-       return null;\r
-}\r
-\r
-/**\r
- * Génère un nom unique pour un champ d'un formulaire donné\r
- *\r
- * @param array $formulaire\r
- *     Le formulaire à analyser \r
- * @param string $type_saisie\r
- *     Le type de champ dont on veut un identifiant \r
- * @return string\r
- *     Un nom unique par rapport aux autres champs du formulaire\r
- */\r
-function saisies_generer_nom($formulaire, $type_saisie){\r
-       $champs = saisies_lister_champs($formulaire);\r
-       \r
-       // Tant que type_numero existe, on incrémente le compteur\r
-       $compteur = 1;\r
-       while (array_search($type_saisie.'_'.$compteur, $champs) !== false)\r
-               $compteur++;\r
-       \r
-       // On a alors un compteur unique pour ce formulaire\r
-       return $type_saisie.'_'.$compteur;\r
-}\r
-\r
-/**\r
- * Crée un identifiant Unique\r
- * pour toutes les saisies donnees qui n'en ont pas \r
- *\r
- * @param Array $saisies Tableau de saisies\r
- * @param Bool $regenerer Régénère un nouvel identifiant pour toutes les saisies ?\r
- * @return Array Tableau de saisies complété des identifiants\r
- */\r
-function saisies_identifier($saisies, $regenerer = false) {\r
-       if (!is_array($saisies)) {\r
-               return array();\r
-       }\r
-       foreach ($saisies as $k => $saisie) {\r
-               $saisies[$k] = saisie_identifier($saisie, $regenerer);\r
-       }\r
-       return $saisies;\r
-}\r
-\r
-/**\r
- * Crée un identifiant Unique\r
- * pour la saisie donnee si elle n'en a pas\r
- * (et pour ses sous saisies éventuels)\r
- *\r
- * @param Array $saisie Tableau d'une saisie\r
- * @param Bool $regenerer Régénère un nouvel identifiant pour la saisie ?\r
- * @return Array Tableau de la saisie complété de l'identifiant\r
-**/\r
-function saisie_identifier($saisie, $regenerer = false) {\r
-       if (!isset($saisie['identifiant']) OR !$saisie['identifiant']) {\r
-               $saisie['identifiant'] = uniqid('@');\r
-       } elseif ($regenerer) {\r
-               $saisie['identifiant'] = uniqid('@');\r
-       }\r
-       if (isset($saisie['saisies']) AND is_array($saisie['saisies'])) {\r
-               $saisie['saisies'] = saisies_identifier($saisie['saisies'], $regenerer);\r
-       }\r
-       return $saisie;\r
-}\r
-\r
-/**\r
- * Vérifier tout un formulaire tel que décrit avec les Saisies\r
- *\r
- * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies\r
- * @param bool $saisies_masquees_nulles Si TRUE, les saisies masquées selon afficher_si ne seront pas verifiées, leur valeur étant forcée a NULL. Cette valeur NULL est transmise à traiter (via set_request).\r
- * @return array Retourne un tableau d'erreurs\r
- */\r
-function saisies_verifier($formulaire, $saisies_masquees_nulles=true){\r
-       include_spip('inc/verifier');\r
-       $erreurs = array();\r
-       $verif_fonction = charger_fonction('verifier','inc',true);\r
-\r
-       if ($saisies_masquees_nulles)\r
-               $formulaire = saisies_verifier_afficher_si($formulaire);\r
-       \r
-       $saisies = saisies_lister_par_nom($formulaire);\r
-       foreach ($saisies as $saisie){\r
-               $obligatoire = isset($saisie['options']['obligatoire']) ? $saisie['options']['obligatoire'] : '';\r
-               $champ = $saisie['options']['nom'];\r
-               $file = ($saisie['saisie'] == 'input' and isset($saisie['options']['type']) and $saisie['options']['type'] == 'file');\r
-               $verifier = isset($saisie['verifier']) ? $saisie['verifier'] : false;\r
-\r
-               // Si le nom du champ est un tableau indexé, il faut parser !\r
-               if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)){\r
-                       $valeur = _request($separe[1]);\r
-                       preg_match_all('/\[([\w]+)\]/', $separe[2], $index);\r
-                       // On va chercher au fond du tableau\r
-                       foreach($index[1] as $cle){\r
-                               $valeur = isset($valeur[$cle]) ? $valeur[$cle] : null;\r
-                       }\r
-               }\r
-               // Sinon la valeur est juste celle du nom\r
-               else\r
-                       $valeur = _request($champ);\r
-               \r
-               // Pour la saisie "destinataires" il faut filtrer si jamais on a mis un premier choix vide\r
-               if ($saisie['saisie'] == 'destinataires') {\r
-                       $valeur = array_filter($valeur);\r
-               }\r
-               \r
-               // On regarde d'abord si le champ est obligatoire\r
-               if ($obligatoire\r
-                       and $obligatoire != 'non'\r
-                       and (\r
-                               ($file and !$_FILES[$champ]['name'])\r
-                               or (!$file and (\r
-                                       is_null($valeur)\r
-                                       or (is_string($valeur) and trim($valeur) == '')\r
-                                       or (is_array($valeur) and count($valeur) == 0)\r
-                               ))\r
-                       )\r
-               ) {\r
-                       $erreurs[$champ] =\r
-                               (isset($saisie['options']['erreur_obligatoire']) and $saisie['options']['erreur_obligatoire'])\r
-                               ? $saisie['options']['erreur_obligatoire']\r
-                               : _T('info_obligatoire');\r
-               }\r
-\r
-               // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif\r
-               if ((!isset($erreurs[$champ]) or !$erreurs[$champ]) and is_array($verifier) and $verif_fonction){\r
-                       $normaliser = null;\r
-                       // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur\r
-                       $options = isset($verifier['options']) ? $verifier['options'] : array();\r
-                       if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $options, $normaliser)) {\r
-                               $erreurs[$champ] = $erreur_eventuelle;\r
-                       // S'il n'y a pas d'erreur et que la variable de normalisation a été remplie, on l'injecte dans le POST\r
-                       } elseif (!is_null($normaliser)) {\r
-                               set_request($champ, $normaliser);\r
-                       }\r
-               }\r
-       }\r
-       \r
-       return $erreurs;\r
-}\r
-\r
-/**\r
- * Applatie une description tabulaire\r
- * @param string $tab Le tableau à aplatir\r
- * @return $nouveau_tab\r
- */\r
-function saisies_aplatir_tableau($tab){\r
-       $nouveau_tab = array();\r
-       foreach($tab as $entree=>$contenu){\r
-               if (is_array($contenu)) {\r
-                       foreach ($contenu as $cle => $valeur) {\r
-                               $nouveau_tab[$cle] = $valeur;\r
-                       }\r
-               } else {\r
-                       $nouveau_tab[$entree] = $contenu;\r
-               }\r
-       }\r
-       return $nouveau_tab;\r
-}\r
-\r
-/**\r
- * Applatie une description chaînée, en supprimant les sous-groupes.\r
- * @param string $chaine La chaîne à aplatir\r
- * @return $chaine\r
- */\r
-function saisies_aplatir_chaine($chaine){\r
-       return trim(preg_replace("#(?:^|\n)(\*(?:.*)|/\*)\n#i","\n",$chaine));\r
-}\r
-\r
-/**\r
- * Transforme une chaine en tableau avec comme principe :\r
- * \r
- * - une ligne devient une case\r
- * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur\r
- * - si la ligne commence par * alors on commence un sous-tableau\r
- * - si la ligne est égale à /*, alors on fini le sous-tableau\r
- * \r
- * @param string $chaine Une chaine à transformer\r
- * @param string $separateur Séparateur utilisé\r
- * @return array Retourne un tableau PHP\r
- */\r
-function saisies_chaine2tableau($chaine, $separateur="\n"){\r
-       if ($chaine and is_string($chaine)){\r
-               $tableau = array();\r
-               $soustab = False;\r
-               // On découpe d'abord en lignes\r
-               $lignes = explode($separateur, $chaine);\r
-               foreach ($lignes as $i=>$ligne){\r
-                       $ligne = trim(trim($ligne), '|');\r
-                       // Si ce n'est pas une ligne sans rien\r
-                       if ($ligne !== ''){\r
-                               // si ca commence par * c'est qu'on va faire un sous tableau\r
-                               if (strpos($ligne,"*")===0) {\r
-                                       $soustab=True;\r
-                                       $soustab_cle    = _T_ou_typo(substr($ligne,1), 'multi');\r
-                                       if (!isset($tableau[$soustab_cle])){\r
-                                               $tableau[$soustab_cle] = array();\r
-                                       }\r
-                               }\r
-                               elseif ($ligne=="/*") {//si on finit sous tableau\r
-                                       $soustab=False;\r
-                               }\r
-                               else{//sinon c'est une entrée normale\r
-                               // Si on trouve un découpage dans la ligne on fait cle|valeur\r
-                                       if (strpos($ligne, '|') !== false) {\r
-                                               list($cle,$valeur) = explode('|', $ligne, 2);\r
-                                               // permettre les traductions de valeurs au passage\r
-                                               if ($soustab == True){\r
-                                                       $tableau[$soustab_cle][$cle] = _T_ou_typo($valeur, 'multi');\r
-                                               } else {\r
-                                                       $tableau[$cle] = _T_ou_typo($valeur, 'multi');\r
-                                               }\r
-                                       }\r
-                               // Sinon on génère la clé\r
-                                       else{\r
-                                               if ($soustab == True) {\r
-                                                       $tableau[$soustab_cle][$i] = _T_ou_typo($ligne,'multi');\r
-                                               } else {\r
-                                                       $tableau[$i] = _T_ou_typo($ligne,'multi');\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               return $tableau;\r
-       }\r
-       // Si c'est déjà un tableau on lui applique _T_ou_typo (qui fonctionne de manière récursive avant de le renvoyer\r
-       elseif (is_array($chaine)){\r
-               return _T_ou_typo($chaine, 'multi');\r
-       } else {\r
-               return array();\r
-       }\r
-}\r
-\r
-/**\r
- * Transforme un tableau en chaine de caractères avec comme principe :\r
- * \r
- * - une case de vient une ligne de la chaine\r
- * - chaque ligne est générée avec la forme cle|valeur\r
- * - si une entrée du tableau est elle même un tableau, on met une ligne de la forme *clef\r
- * - pour marquer que l'on quitte un sous-tableau, on met une ligne commencant par /*, sauf si on bascule dans un autre sous-tableau.\r
- *\r
- * @param array $tableau Tableau à transformer\r
- * @return string Texte représentant les données du tableau\r
- */\r
-function saisies_tableau2chaine($tableau){\r
-       if ($tableau and is_array($tableau)){\r
-               $chaine = '';\r
-               $avant_est_tableau = False;\r
-               foreach($tableau as $cle=>$valeur){\r
-                       if (is_array($valeur)){\r
-                               $avant_est_tableau = True;\r
-                               $ligne=trim("*$cle");\r
-                               $chaine .= "$ligne\n";\r
-                               $chaine .= saisies_tableau2chaine($valeur)."\n";\r
-                               }\r
-                       else{   \r
-                               if ($avant_est_tableau == True){\r
-                                               $avant_est_tableau = False;\r
-                                               $chaine.="/*\n";\r
-                                       }\r
-                               $ligne = trim("$cle|$valeur");\r
-                               $chaine .= "$ligne\n";\r
-                       }\r
-               }\r
-               $chaine = trim($chaine);\r
-       \r
-               return $chaine;\r
-       }\r
-       // Si c'est déjà une chaine on la renvoie telle quelle\r
-       elseif (is_string($tableau)){\r
-               return $tableau;\r
-       }\r
-       else{\r
-               return '';\r
-       }\r
-}\r
-\r
-\r
-\r
-\r
-/**\r
- * Transforme une valeur en tableau d'élements si ce n'est pas déjà le cas\r
- *\r
- * @param mixed $valeur\r
- * @return array Tableau de valeurs\r
-**/\r
-function saisies_valeur2tableau($valeur) {\r
-       if (is_array($valeur)) {\r
-               return $valeur;\r
-       }\r
-\r
-       if (!strlen($valeur)) {\r
-               return array();\r
-       }\r
-\r
-       $t = saisies_chaine2tableau($valeur);\r
-       if (count($t) > 1) {\r
-               return $t;\r
-       }\r
-\r
-       // qu'une seule valeur, c'est qu'elle a peut etre un separateur a virgule\r
-       // et a donc une cle est 0 dans ce cas la d'ailleurs\r
-       if (isset($t[0])) {\r
-               $t = saisies_chaine2tableau($t[0], ',');\r
-       }\r
-\r
-       return $t;\r
-}\r
-\r
-\r
-/**\r
- * Pour les saisies multiples (type checkbox) proposant un choix alternatif,\r
- * retrouve à partir des data de choix proposés\r
- * et des valeurs des choix enregistrés\r
- * le texte enregistré pour le choix alternatif.\r
- *\r
- * @param array $data\r
- * @param array $valeur\r
- * @return string choix_alternatif\r
-**/\r
-function saisies_trouver_choix_alternatif($data,$valeur) {\r
-       if (!is_array($valeur)) {\r
-               $valeur = saisies_chaine2tableau($valeur) ;\r
-       }\r
-       if (!is_array($data)) {\r
-               $data = saisies_chaine2tableau($data) ;\r
-       }\r
-       $choix_theorique = array_keys($data);\r
-       $choix_alternatif = array_values(array_diff($valeur,$choix_theorique));\r
-       return $choix_alternatif[0];//on suppose que personne ne s'est amusé à proposer deux choix alternatifs\r
-}\r
-\r
-/**\r
- * Génère une page d'aide listant toutes les saisies et leurs options\r
- *\r
- * Retourne le résultat du squelette `inclure/saisies_aide` auquel\r
- * on a transmis toutes les saisies connues.\r
- * \r
- * @return string Code HTML\r
- */\r
-function saisies_generer_aide(){\r
-       // On a déjà la liste par saisie\r
-       $saisies = saisies_lister_disponibles();\r
-\r
-       // On construit une liste par options\r
-       $options = array();\r
-       foreach ($saisies as $type_saisie=>$saisie){\r
-               $options_saisie = saisies_lister_par_nom($saisie['options'], false);\r
-               foreach ($options_saisie as $nom=>$option){\r
-                       // Si l'option n'existe pas encore\r
-                       if (!isset($options[$nom])){\r
-                               $options[$nom] = _T_ou_typo($option['options']);\r
-                       }\r
-                       // On ajoute toujours par qui c'est utilisé\r
-                       $options[$nom]['utilisee_par'][] = $type_saisie;\r
-               }\r
-               ksort($options_saisie);\r
-               $saisies[$type_saisie]['options'] = $options_saisie;\r
-       }\r
-       ksort($options);\r
-\r
-       return recuperer_fond(\r
-               'inclure/saisies_aide',\r
-               array(\r
-                       'saisies' => $saisies,\r
-                       'options' => $options\r
-               )\r
-       );\r
-}\r
-\r
-/**\r
- * Le tableau de saisies a-t-il une option afficher_si ?\r
- *\r
- * @param array $saisies Un tableau de saisies\r
- * @return boolean\r
- */\r
-\r
-function saisies_afficher_si($saisies) {\r
-       $saisies = saisies_lister_par_nom($saisies,true);\r
-       // Dès qu'il y a au moins une option afficher_si, on l'active\r
-       foreach ($saisies as $saisie) {\r
-               if (isset($saisie['options']['afficher_si']))\r
-                       return true;\r
-       }\r
-       return false;\r
-}\r
-\r
-\r
-/**\r
- * Le tableau de saisies a-t-il une option afficher_si_remplissage ?\r
- *\r
- * @param array $saisies Un tableau de saisies\r
- * @return boolean\r
- */\r
-function saisies_afficher_si_remplissage($saisies) {\r
-       $saisies = saisies_lister_par_nom($saisies,true);\r
-       // Dès qu'il y a au moins une option afficher_si_remplissage, on l'active\r
-       foreach ($saisies as $saisie) {\r
-               if (isset($saisie['options']['afficher_si_remplissage']))\r
-                       return true;\r
-       }\r
-       return false;\r
-}\r
-\r
+<?php
+
+/**
+ * Gestion de l'affichage des saisies
+ *
+ * @package SPIP\Saisies\Saisies
+**/
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
+
+/*
+ * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies
+ *
+ * saisies_lister_par_nom()
+ * saisies_lister_champs()
+ * saisies_lister_valeurs_defaut()
+ * saisies_charger_champs()
+ * saisies_chercher()
+ * saisies_supprimer()
+ * saisies_inserer()
+ * saisies_deplacer()
+ * saisies_modifier()
+ * saisies_verifier()
+ * saisies_comparer()
+ * saisies_generer_html()
+ * saisies_generer_vue()
+ * saisies_generer_nom()
+ * saisies_inserer_html()
+ * saisies_lister_disponibles()
+ * saisies_autonomes()
+ */
+
+// Différentes méthodes pour trouver les saisies
+include_spip('inc/saisies_lister');
+
+// Différentes méthodes pour manipuler une liste de saisies
+include_spip('inc/saisies_manipuler');
+
+// Les outils pour afficher les saisies et leur vue
+include_spip('inc/saisies_afficher');
+
+/**
+ * Cherche la description des saisies d'un formulaire CVT dont on donne le nom
+ *
+ * @param string $form Nom du formulaire dont on cherche les saisies
+ * @param array $args Tableau d'arguments du formulaire
+ * @return array Retourne les saisies du formulaire sinon false
+ */
+function saisies_chercher_formulaire($form, $args) {
+       if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)
+               and $saisies = call_user_func_array($fonction_saisies, $args)
+               and is_array($saisies)
+               // On passe les saisies dans un pipeline normé comme pour CVT
+               and $saisies = pipeline(
+                       'formulaire_saisies',
+                       array(
+                               'args' => array('form' => $form, 'args' => $args),
+                               'data' => $saisies
+                       )
+               )
+               // Si c'est toujours un tableau après le pipeline
+               and is_array($saisies)
+       ) {
+               return $saisies;
+       } else {
+               return false;
+       }
+}
+
+/**
+ * Cherche une saisie par son id, son nom ou son chemin et renvoie soit la saisie, soit son chemin
+ *
+ * @param array $saisies Un tableau décrivant les saisies
+ * @param unknown_type $id_ou_nom_ou_chemin L'identifiant ou le nom de la saisie à chercher ou le chemin sous forme d'une liste de clés
+ * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin
+ * @return array Retourne soit la saisie, soit son chemin, soit null
+ */
+function saisies_chercher($saisies, $id_ou_nom_ou_chemin, $retourner_chemin = false) {
+       if (is_array($saisies) and $id_ou_nom_ou_chemin) {
+               if (is_string($id_ou_nom_ou_chemin)) {
+                       $nom = $id_ou_nom_ou_chemin;
+                       // identifiant ? premier caractere @
+                       $id = ($nom[0] == '@');
+
+                       foreach ($saisies as $cle => $saisie) {
+                               $chemin = array($cle);
+                               // notre saisie est la bonne ?
+                               if ($nom == ($id ? $saisie['identifiant'] : $saisie['options']['nom'])) {
+                                       return $retourner_chemin ? $chemin : $saisie;
+                               // sinon a telle des enfants ? et si c'est le cas, cherchons dedans
+                               } elseif (isset($saisie['saisies']) and is_array($saisie['saisies']) and $saisie['saisies']
+                                       and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))) {
+                                               return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;
+                               }
+                       }
+               } elseif (is_array($id_ou_nom_ou_chemin)) {
+                       $chemin = $id_ou_nom_ou_chemin;
+                       $saisie = $saisies;
+                       // On vérifie l'existence quand même
+                       foreach ($chemin as $cle) {
+                               if (isset($saisie[$cle])) {
+                                       $saisie = $saisie[$cle];
+                               } else {
+                                       return null;
+                               }
+                       }
+                       // Si c'est une vraie saisie
+                       if ($saisie['saisie'] and $saisie['options']['nom']) {
+                               return $retourner_chemin ? $chemin : $saisie;
+                       }
+               }
+       }
+
+       return null;
+}
+
+/**
+ * Génère un nom unique pour un champ d'un formulaire donné
+ *
+ * @param array $formulaire
+ *     Le formulaire à analyser
+ * @param string $type_saisie
+ *     Le type de champ dont on veut un identifiant
+ * @return string
+ *     Un nom unique par rapport aux autres champs du formulaire
+ */
+function saisies_generer_nom($formulaire, $type_saisie) {
+       $champs = saisies_lister_champs($formulaire);
+
+       // Tant que type_numero existe, on incrémente le compteur
+       $compteur = 1;
+       while (array_search($type_saisie.'_'.$compteur, $champs) !== false) {
+               $compteur++;
+       }
+
+       // On a alors un compteur unique pour ce formulaire
+       return $type_saisie.'_'.$compteur;
+}
+
+/**
+ * Crée un identifiant Unique
+ * pour toutes les saisies donnees qui n'en ont pas
+ *
+ * @param Array $saisies Tableau de saisies
+ * @param Bool $regenerer Régénère un nouvel identifiant pour toutes les saisies ?
+ * @return Array Tableau de saisies complété des identifiants
+ */
+function saisies_identifier($saisies, $regenerer = false) {
+       if (!is_array($saisies)) {
+               return array();
+       }
+       foreach ($saisies as $k => $saisie) {
+               $saisies[$k] = saisie_identifier($saisie, $regenerer);
+       }
+       return $saisies;
+}
+
+/**
+ * Crée un identifiant Unique
+ * pour la saisie donnee si elle n'en a pas
+ * (et pour ses sous saisies éventuels)
+ *
+ * @param Array $saisie Tableau d'une saisie
+ * @param Bool $regenerer Régénère un nouvel identifiant pour la saisie ?
+ * @return Array Tableau de la saisie complété de l'identifiant
+**/
+function saisie_identifier($saisie, $regenerer = false) {
+       if (!isset($saisie['identifiant']) or !$saisie['identifiant']) {
+               $saisie['identifiant'] = uniqid('@');
+       } elseif ($regenerer) {
+               $saisie['identifiant'] = uniqid('@');
+       }
+       if (isset($saisie['saisies']) and is_array($saisie['saisies'])) {
+               $saisie['saisies'] = saisies_identifier($saisie['saisies'], $regenerer);
+       }
+       return $saisie;
+}
+
+/**
+ * Vérifier tout un formulaire tel que décrit avec les Saisies
+ *
+ * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies
+ * @param bool $saisies_masquees_nulles Si TRUE, les saisies masquées selon afficher_si ne seront pas verifiées, leur valeur étant forcée a NULL. Cette valeur NULL est transmise à traiter (via set_request).
+ * @return array Retourne un tableau d'erreurs
+ */
+function saisies_verifier($formulaire, $saisies_masquees_nulles = true) {
+       include_spip('inc/verifier');
+       $erreurs = array();
+       $verif_fonction = charger_fonction('verifier', 'inc', true);
+
+       if ($saisies_masquees_nulles) {
+               $formulaire = saisies_verifier_afficher_si($formulaire);
+       }
+
+       $saisies = saisies_lister_par_nom($formulaire);
+       foreach ($saisies as $saisie) {
+               $obligatoire = isset($saisie['options']['obligatoire']) ? $saisie['options']['obligatoire'] : '';
+               $champ = $saisie['options']['nom'];
+               $file = ($saisie['saisie'] == 'input' and isset($saisie['options']['type']) and $saisie['options']['type'] == 'file');
+               $verifier = isset($saisie['verifier']) ? $saisie['verifier'] : false;
+
+               // Si le nom du champ est un tableau indexé, il faut parser !
+               if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)) {
+                       $valeur = _request($separe[1]);
+                       preg_match_all('/\[([\w]+)\]/', $separe[2], $index);
+                       // On va chercher au fond du tableau
+                       foreach ($index[1] as $cle) {
+                               $valeur = isset($valeur[$cle]) ? $valeur[$cle] : null;
+                       }
+               } else {
+                       // Sinon la valeur est juste celle du nom
+                       $valeur = _request($champ);
+               }
+
+               // Pour la saisie "destinataires" il faut filtrer si jamais on a mis un premier choix vide
+               if ($saisie['saisie'] == 'destinataires') {
+                       $valeur = array_filter($valeur);
+               }
+
+               // On regarde d'abord si le champ est obligatoire
+               if ($obligatoire
+                       and $obligatoire != 'non'
+                       and (
+                               ($file and !$_FILES[$champ]['name'])
+                               or (!$file and (
+                                       is_null($valeur)
+                                       or (is_string($valeur) and trim($valeur) == '')
+                                       or (is_array($valeur) and count($valeur) == 0)
+                               ))
+                       )
+               ) {
+                       $erreurs[$champ] =
+                               (isset($saisie['options']['erreur_obligatoire']) and $saisie['options']['erreur_obligatoire'])
+                               ? $saisie['options']['erreur_obligatoire']
+                               : _T('info_obligatoire');
+               }
+
+               // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif
+               if ((!isset($erreurs[$champ]) or !$erreurs[$champ]) and is_array($verifier) and $verif_fonction) {
+                       $normaliser = null;
+                       // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur
+                       $options = isset($verifier['options']) ? $verifier['options'] : array();
+                       if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $options, $normaliser)) {
+                               $erreurs[$champ] = $erreur_eventuelle;
+                       // S'il n'y a pas d'erreur et que la variable de normalisation a été remplie, on l'injecte dans le POST
+                       } elseif (!is_null($normaliser)) {
+                               set_request($champ, $normaliser);
+                       }
+               }
+       }
+
+       return $erreurs;
+}
+
+/**
+ * Applatie une description tabulaire
+ * @param string $tab Le tableau à aplatir
+ * @return $nouveau_tab
+ */
+function saisies_aplatir_tableau($tab) {
+       $nouveau_tab = array();
+       foreach ($tab as $entree => $contenu) {
+               if (is_array($contenu)) {
+                       foreach ($contenu as $cle => $valeur) {
+                               $nouveau_tab[$cle] = $valeur;
+                       }
+               } else {
+                       $nouveau_tab[$entree] = $contenu;
+               }
+       }
+       return $nouveau_tab;
+}
+
+/**
+ * Applatie une description chaînée, en supprimant les sous-groupes.
+ * @param string $chaine La chaîne à aplatir
+ * @return $chaine
+ */
+function saisies_aplatir_chaine($chaine) {
+       return trim(preg_replace("#(?:^|\n)(\*(?:.*)|/\*)\n#i", "\n", $chaine));
+}
+
+/**
+ * Transforme une chaine en tableau avec comme principe :
+ *
+ * - une ligne devient une case
+ * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur
+ * - si la ligne commence par * alors on commence un sous-tableau
+ * - si la ligne est égale à /*, alors on fini le sous-tableau
+ *
+ * @param string $chaine Une chaine à transformer
+ * @param string $separateur Séparateur utilisé
+ * @return array Retourne un tableau PHP
+ */
+function saisies_chaine2tableau($chaine, $separateur = "\n") {
+       if ($chaine and is_string($chaine)) {
+               $tableau = array();
+               $soustab = false;
+               // On découpe d'abord en lignes
+               $lignes = explode($separateur, $chaine);
+               foreach ($lignes as $i => $ligne) {
+                       $ligne = trim(trim($ligne), '|');
+                       // Si ce n'est pas une ligne sans rien
+                       if ($ligne !== '') {
+                               // si ca commence par * c'est qu'on va faire un sous tableau
+                               if (strpos($ligne, '*') === 0) {
+                                       $soustab=true;
+                                       $soustab_cle = _T_ou_typo(substr($ligne, 1), 'multi');
+                                       if (!isset($tableau[$soustab_cle])) {
+                                               $tableau[$soustab_cle] = array();
+                                       }
+                               } elseif ($ligne == '/*') {//si on finit sous tableau
+                                       $soustab=false;
+                               } else {
+                                       //sinon c'est une entrée normale
+                                       // Si on trouve un découpage dans la ligne on fait cle|valeur
+                                       if (strpos($ligne, '|') !== false) {
+                                               list($cle,$valeur) = explode('|', $ligne, 2);
+                                               // permettre les traductions de valeurs au passage
+                                               if ($soustab == true) {
+                                                       $tableau[$soustab_cle][$cle] = _T_ou_typo($valeur, 'multi');
+                                               } else {
+                                                       $tableau[$cle] = _T_ou_typo($valeur, 'multi');
+                                               }
+                                       } else {
+                                               // Sinon on génère la clé
+                                               if ($soustab == true) {
+                                                       $tableau[$soustab_cle][$i] = _T_ou_typo($ligne, 'multi');
+                                               } else {
+                                                       $tableau[$i] = _T_ou_typo($ligne, 'multi');
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return $tableau;
+       } elseif (is_array($chaine)) {
+               // Si c'est déjà un tableau on lui applique _T_ou_typo (qui fonctionne de manière récursive avant de le renvoyer
+               return _T_ou_typo($chaine, 'multi');
+       } else {
+               return array();
+       }
+}
+
+/**
+ * Transforme un tableau en chaine de caractères avec comme principe :
+ *
+ * - une case de vient une ligne de la chaine
+ * - chaque ligne est générée avec la forme cle|valeur
+ * - si une entrée du tableau est elle même un tableau, on met une ligne de la forme *clef
+ * - pour marquer que l'on quitte un sous-tableau, on met une ligne commencant par /*, sauf si on bascule dans un autre sous-tableau.
+ *
+ * @param array $tableau Tableau à transformer
+ * @return string Texte représentant les données du tableau
+ */
+function saisies_tableau2chaine($tableau) {
+       if ($tableau and is_array($tableau)) {
+               $chaine = '';
+               $avant_est_tableau = false;
+               foreach ($tableau as $cle => $valeur) {
+                       if (is_array($valeur)) {
+                               $avant_est_tableau = true;
+                               $ligne=trim("*$cle");
+                               $chaine .= "$ligne\n";
+                               $chaine .= saisies_tableau2chaine($valeur)."\n";
+                       } else {
+                               if ($avant_est_tableau == true) {
+                                       $avant_est_tableau = false;
+                                       $chaine.="/*\n";
+                               }
+                               $ligne = trim("$cle|$valeur");
+                               $chaine .= "$ligne\n";
+                       }
+               }
+               $chaine = trim($chaine);
+
+               return $chaine;
+       } elseif (is_string($tableau)) {
+               // Si c'est déjà une chaine on la renvoie telle quelle
+               return $tableau;
+       } else {
+               return '';
+       }
+}
+
+/**
+ * Transforme une valeur en tableau d'élements si ce n'est pas déjà le cas
+ *
+ * @param mixed $valeur
+ * @return array Tableau de valeurs
+**/
+function saisies_valeur2tableau($valeur) {
+       if (is_array($valeur)) {
+               return $valeur;
+       }
+
+       if (!strlen($valeur)) {
+               return array();
+       }
+
+       $t = saisies_chaine2tableau($valeur);
+       if (count($t) > 1) {
+               return $t;
+       }
+
+       // qu'une seule valeur, c'est qu'elle a peut etre un separateur a virgule
+       // et a donc une cle est 0 dans ce cas la d'ailleurs
+       if (isset($t[0])) {
+               $t = saisies_chaine2tableau($t[0], ',');
+       }
+
+       return $t;
+}
+
+/**
+ * Pour les saisies multiples (type checkbox) proposant un choix alternatif,
+ * retrouve à partir des data de choix proposés
+ * et des valeurs des choix enregistrés
+ * le texte enregistré pour le choix alternatif.
+ *
+ * @param array $data
+ * @param array $valeur
+ * @return string choix_alternatif
+**/
+function saisies_trouver_choix_alternatif($data, $valeur) {
+       if (!is_array($valeur)) {
+               $valeur = saisies_chaine2tableau($valeur) ;
+       }
+       if (!is_array($data)) {
+               $data = saisies_chaine2tableau($data) ;
+       }
+       $choix_theorique = array_keys($data);
+       $choix_alternatif = array_values(array_diff($valeur, $choix_theorique));
+       return $choix_alternatif[0];//on suppose que personne ne s'est amusé à proposer deux choix alternatifs
+}
+
+/**
+ * Génère une page d'aide listant toutes les saisies et leurs options
+ *
+ * Retourne le résultat du squelette `inclure/saisies_aide` auquel
+ * on a transmis toutes les saisies connues.
+ *
+ * @return string Code HTML
+ */
+function saisies_generer_aide() {
+       // On a déjà la liste par saisie
+       $saisies = saisies_lister_disponibles();
+
+       // On construit une liste par options
+       $options = array();
+       foreach ($saisies as $type_saisie => $saisie) {
+               $options_saisie = saisies_lister_par_nom($saisie['options'], false);
+               foreach ($options_saisie as $nom => $option) {
+                       // Si l'option n'existe pas encore
+                       if (!isset($options[$nom])) {
+                               $options[$nom] = _T_ou_typo($option['options']);
+                       }
+                       // On ajoute toujours par qui c'est utilisé
+                       $options[$nom]['utilisee_par'][] = $type_saisie;
+               }
+               ksort($options_saisie);
+               $saisies[$type_saisie]['options'] = $options_saisie;
+       }
+       ksort($options);
+
+       return recuperer_fond(
+               'inclure/saisies_aide',
+               array(
+                       'saisies' => $saisies,
+                       'options' => $options
+               )
+       );
+}
+
+/**
+ * Le tableau de saisies a-t-il une option afficher_si ?
+ *
+ * @param array $saisies Un tableau de saisies
+ * @return boolean
+ */
+
+function saisies_afficher_si($saisies) {
+       $saisies = saisies_lister_par_nom($saisies, true);
+       // Dès qu'il y a au moins une option afficher_si, on l'active
+       foreach ($saisies as $saisie) {
+               if (isset($saisie['options']['afficher_si'])) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+
+/**
+ * Le tableau de saisies a-t-il une option afficher_si_remplissage ?
+ *
+ * @param array $saisies Un tableau de saisies
+ * @return boolean
+ */
+function saisies_afficher_si_remplissage($saisies) {
+       $saisies = saisies_lister_par_nom($saisies, true);
+       // Dès qu'il y a au moins une option afficher_si_remplissage, on l'active
+       foreach ($saisies as $saisie) {
+               if (isset($saisie['options']['afficher_si_remplissage'])) {
+                       return true;
+               }
+       }
+       return false;
+}