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

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

tester systématiquement la syntaxe des conditions avant d'essayer de les transformer en js/php + accepter les conditions false / true

File size: 6.6 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        // Dans tous les cas, enlever les guillemets qui sont au sein de valeur
78        //Si champ est de type string, tenter d'unserializer
79        $tenter_unserialize = @unserialize($champ);
80        if ($tenter_unserialize)  {
81                $champ = $tenter_unserialize;
82        }
83
84        //Et maintenant appeler les sous fonctions qui vont bien
85        if (is_string($champ)) {
86                $retour = saisies_tester_condition_afficher_si_string($champ, $operateur, $valeur);
87        } elseif (is_array($champ)) {
88                $retour = saisies_tester_condition_afficher_si_array($champ, $operateur, $valeur);
89        } else {
90                $retour = false;
91        }
92        if ($negation) {
93                return !$retour;
94        } else {
95                return $retour;
96        }
97}
98
99/**
100 * Teste un condition d'afficher_si lorsque la valeur envoyée par le formulaire est une chaîne
101 * @param string champ le champ à tester.
102 * @param string $operateur : l'opérateur:
103 * @param string|int $valeur la valeur à tester pour un IN. Par exemple "23" ou encore "23, 25", 23
104 * @return bool false / true selon la condition
105**/
106function saisies_tester_condition_afficher_si_string($champ, $operateur, $valeur) {
107        if ($operateur == "==") {
108                return $champ == $valeur;
109        } elseif ($operateur == "!=") {
110                return $champ != $valeur;
111        } elseif ($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        } else {//Si mauvaise operateur -> on annule
120                return false;
121        }
122}
123
124/**
125 * Teste un condition d'afficher_si lorsque la valeur postée est  un tableau
126 * @param array champ le champ à tester.
127 * @param string $operateur : l'opérateur:
128 * @param string $valeur la valeur à tester pour un IN. Par exemple "23" ou encore "23", "25"
129 * @return bool false / true selon la condition
130**/
131function saisies_tester_condition_afficher_si_array($champ, $operateur, $valeur) {
132        $valeur = explode(',', $valeur);
133        $intersection = array_intersect($champ, $valeur);
134        if ($operateur == "==" or $operateur == "IN") {
135                return count($intersection) > 0;
136        } else {
137                return count($intersection) == 0;
138        }
139        return false;
140}
141
142/**
143 * Retourne la valeur d'une config, si nécessaire
144 * @param string $champ le "champ" a tester : config:xxx ou un vrai champ
145 * @return string
146**/
147function saisies_afficher_si_get_valeur_config($champ) {
148        $valeur = '';
149        if (preg_match("#config:(.*)#", $champ, $config)) {
150                $config_a_tester = str_replace(":", "/", $config[1]);
151                $valeur = lire_config($config_a_tester);
152        }
153        return $valeur;
154}
155
156/** Vérifie qu'une condition est sécurisée
157 * IE : ne permet pas d'executer n'importe quel code arbitraire.
158 * @param string $condition
159 * @param array $tests tableau des tests parsés
160 * @return bool true si secure / false sinon
161 **/
162function saisies_afficher_si_secure($condition, $tests=array()) {
163        $condition_original = $condition;
164        $hors_test = array('||','&&','!','(',')','true','false');
165        foreach ($tests as $test) {
166                $condition = str_replace($test[0], '', $condition);
167        }
168        foreach ($hors_test as $hors) {
169                $condition = str_replace($hors, '', $condition);
170        }
171        $condition = trim($condition);
172        if ($condition) {// il reste quelque chose > c'est le mal
173                spip_log("Afficher_si incorrect. $condition_original non sécurisée", "saisies"._LOG_CRITIQUE);
174                return false;
175        } else {
176                return true;
177        }
178}
179
180/** Vérifie qu'une condition respecte la syntaxe formelle
181 * @param string $condition
182 * @param array $tests liste des tests simples
183* @return bool
184**/
185function saisies_afficher_si_verifier_syntaxe($condition, $tests=array()) {
186        if ($tests and saisies_afficher_si_secure($condition, $tests)) {//Si cela passe la sécurité, faisons des tests complémentaires
187                // parenthèses équilibrées
188                if (substr_count($condition,'(') != substr_count($condition,')')) {
189                        return false;
190                }
191                // pas de && ou de || qui traine sans rien à gauche ni à droite
192                $condition = " $condition ";
193                $condition_pour_sous_test = str_replace('||','$', $condition);
194                $condition_pour_sous_test = str_replace('&&','$', $condition_pour_sous_test);
195                $liste_sous_tests = explode('$', $condition_pour_sous_test);
196                $liste_sous_tests = array_map('trim', $liste_sous_tests);
197                if ($liste_sous_tests != array_filter($liste_sous_tests)) {
198                        return false;
199                }
200
201                return true;
202        }
203        return false;
204
205}
Note: See TracBrowser for help on using the repository browser.