source: spip-zone/_plugins_/saisies/trunk/inc/saisies_afficher_si_commun.php @ 117794

Last change on this file since 117794 was 117794, checked in by maieul@…, 6 weeks ago

verif des tests conditionnelles en PHP : si une champ a une valeur null, considérer cela comme une string vide

File size: 6.7 KB
Line 
1<?php
2
3/**
4 * Gestion de l'affichage conditionnelle des saisies.
5 * Partie commun js/php
6 *
7 * @package SPIP\Saisies\Afficher_si_commun
8 **/
9
10
11/**
12 * Reçoit une condition
13 * la parse pour trouver champs/opérateurs/valeurs etc.
14 * @param string $condition
15 * @return array tableau d'analyse (resultat d'un preg_match_all) montrant sous condition par sous condition l'analyse en champ/opérateur/valeur etc.
16**/
17function saisies_parser_condition_afficher_si($condition) {
18        $regexp =
19          "(?<negation>!?)" // négation éventuelle
20                . "(?:@(?<champ>.+?)@)" // @champ_@
21                . "(" // partie operateur + valeur (optionnelle) : debut
22                . "(?:\s*?)" // espaces éventuels après
23                . "(?<operateur>==|!=|IN|!IN|>=|>|<=|<)" // opérateur
24                . "(?:\s*?)" // espaces éventuels après
25                . "((?<guillemet>\"|')(?<valeur>.*?)(\k<guillemet>)|(?<valeur_numerique>\d+))" // valeur (string) ou valeur_numérique (int)
26                . ")?" // partie operateur + valeur (optionnelle) : fin
27                . '|(?<booleen>false|true)';//accepter false/true brut
28        $regexp = "#$regexp#";
29        preg_match_all($regexp, $condition, $tests, PREG_SET_ORDER);
30        return $tests;
31}
32
33/**
34 * Retourne le résultat de l'évaluation d'un plugin actif
35 * @param string $champ (sans les @@)
36 * @param string $negation ! si on doit nier
37 * @return bool '' ('' si jamais on ne teste pas un plugin)
38**/
39function saisies_afficher_si_evaluer_plugin($champ, $negation = '') {
40        if (preg_match_all('#plugin:(.*)#', $champ, $matches, PREG_SET_ORDER)) {
41                foreach ($matches as $plugin) {
42                        $plugin_a_tester = $plugin[1];
43                        if ($negation) {
44                                $actif = !test_plugin_actif($plugin_a_tester);
45                        } else {
46                                $actif = test_plugin_actif($plugin_a_tester);
47                        }
48                }
49        }       else {
50                $actif = '';
51        }
52        return $actif;
53}
54
55
56/**
57 * Teste une condition d'afficher_si
58 * @param string|array champ le champ à tester. Cela peut être :
59 *      - un string
60 *      - un tableau
61 *      - un tableau sérializé
62 * @param string $operateur : l'opérateur:
63 * @param string $valeur la valeur à tester pour un IN. Par exemple "23" ou encore "23", "25"
64 * @param string $negation y-a-t-il un négation avant le test ? '!' si oui
65 * @return bool false / true selon la condition
66**/
67function saisies_tester_condition_afficher_si($champ, $operateur=null, $valeur=null, $negation = '') {
68        // Si operateur null => on test juste qu'un champ est cochée / validé
69        if ($operateur === null and $valeur === null) {
70                if ($negation) {
71                        return !(isset($champ) and $champ);
72                }
73                else {
74                        return isset($champ) and $champ;
75                }
76        }
77
78        if (is_null($champ)) {
79                $champ = '';
80        }
81        // Dans tous les cas, enlever les guillemets qui sont au sein de valeur
82        //Si champ est de type string, tenter d'unserializer
83        $tenter_unserialize = @unserialize($champ);
84        if ($tenter_unserialize)  {
85                $champ = $tenter_unserialize;
86        }
87
88        //Et maintenant appeler les sous fonctions qui vont bien
89        if (is_string($champ)) {
90                $retour = saisies_tester_condition_afficher_si_string($champ, $operateur, $valeur);
91        } elseif (is_array($champ)) {
92                $retour = saisies_tester_condition_afficher_si_array($champ, $operateur, $valeur);
93        } else {
94                $retour = false;
95        }
96        if ($negation) {
97                return !$retour;
98        } else {
99                return $retour;
100        }
101}
102
103/**
104 * Teste un condition d'afficher_si lorsque la valeur envoyée par le formulaire est une chaîne
105 * @param string champ le champ à tester.
106 * @param string $operateur : l'opérateur:
107 * @param string|int $valeur la valeur à tester pour un IN. Par exemple "23" ou encore "23, 25", 23
108 * @return bool false / true selon la condition
109**/
110function saisies_tester_condition_afficher_si_string($champ, $operateur, $valeur) {
111        if ($operateur == "==") {
112                return $champ == $valeur;
113        } elseif ($operateur == "!=") {
114                return $champ != $valeur;
115        } elseif ($operateur == '<') {
116                return $champ < $valeur;
117        } elseif ($operateur == '<=') {
118                return $champ <= $valeur;
119        } elseif ($operateur == '>') {
120                return $champ > $valeur;
121        } elseif ($operateur == '>=') {
122                return $champ >= $valeur;
123        } else {//Si mauvaise operateur -> on annule
124                return false;
125        }
126}
127
128/**
129 * Teste un condition d'afficher_si lorsque la valeur postée est  un tableau
130 * @param array champ le champ à tester.
131 * @param string $operateur : l'opérateur:
132 * @param string $valeur la valeur à tester pour un IN. Par exemple "23" ou encore "23", "25"
133 * @return bool false / true selon la condition
134**/
135function saisies_tester_condition_afficher_si_array($champ, $operateur, $valeur) {
136        $valeur = explode(',', $valeur);
137        $intersection = array_intersect($champ, $valeur);
138        if ($operateur == "==" or $operateur == "IN") {
139                return count($intersection) > 0;
140        } else {
141                return count($intersection) == 0;
142        }
143        return false;
144}
145
146/**
147 * Retourne la valeur d'une config, si nécessaire
148 * @param string $champ le "champ" a tester : config:xxx ou un vrai champ
149 * @return string
150**/
151function saisies_afficher_si_get_valeur_config($champ) {
152        $valeur = '';
153        if (preg_match("#config:(.*)#", $champ, $config)) {
154                $config_a_tester = str_replace(":", "/", $config[1]);
155                $valeur = lire_config($config_a_tester);
156        }
157        return $valeur;
158}
159
160/** Vérifie qu'une condition est sécurisée
161 * IE : ne permet pas d'executer n'importe quel code arbitraire.
162 * @param string $condition
163 * @param array $tests tableau des tests parsés
164 * @return bool true si secure / false sinon
165 **/
166function saisies_afficher_si_secure($condition, $tests=array()) {
167        $condition_original = $condition;
168        $hors_test = array('||','&&','!','(',')','true','false');
169        foreach ($tests as $test) {
170                $condition = str_replace($test[0], '', $condition);
171        }
172        foreach ($hors_test as $hors) {
173                $condition = str_replace($hors, '', $condition);
174        }
175        $condition = trim($condition);
176        if ($condition) {// il reste quelque chose > c'est le mal
177                spip_log("Afficher_si incorrect. $condition_original non sécurisée", "saisies"._LOG_CRITIQUE);
178                return false;
179        } else {
180                return true;
181        }
182}
183
184/** Vérifie qu'une condition respecte la syntaxe formelle
185 * @param string $condition
186 * @param array $tests liste des tests simples
187* @return bool
188**/
189function saisies_afficher_si_verifier_syntaxe($condition, $tests=array()) {
190        if ($tests and saisies_afficher_si_secure($condition, $tests)) {//Si cela passe la sécurité, faisons des tests complémentaires
191                // parenthèses équilibrées
192                if (substr_count($condition,'(') != substr_count($condition,')')) {
193                        return false;
194                }
195                // pas de && ou de || qui traine sans rien à gauche ni à droite
196                $condition = " $condition ";
197                $condition_pour_sous_test = str_replace('||','$', $condition);
198                $condition_pour_sous_test = str_replace('&&','$', $condition_pour_sous_test);
199                $liste_sous_tests = explode('$', $condition_pour_sous_test);
200                $liste_sous_tests = array_map('trim', $liste_sous_tests);
201                if ($liste_sous_tests != array_filter($liste_sous_tests)) {
202                        return false;
203                }
204
205                return true;
206        }
207        return false;
208
209}
Note: See TracBrowser for help on using the repository browser.