Completed
Push — master ( 1a3b2f...b50fb4 )
by cam
09:59
created

ValidateurXML::debutElement()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 8
nop 3
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
/***************************************************************************\
4
 *  SPIP, Systeme de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright (c) 2001-2018                                                *
7
 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8
 *                                                                         *
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
\***************************************************************************/
12
13
if (!defined('_ECRIRE_INC_VERSION')) {
14
	return;
15
}
16
17
/**
18
 * Validateur XML en deux passes, fondé sur SAX pour la première
19
 *
20
 * @note
21
 *     Faudrait faire deux classes car pour la première passe
22
 *     on a les memes methodes et variables que l'indenteur
23
 **/
24
class ValidateurXML {
25
26
	// http://code.spip.net/@validerElement
27
	public function validerElement($phraseur, $name, $attrs) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
28
		if (!($p = isset($this->dtc->elements[$name]))) {
29
			if ($p = strpos($name, ':')) {
30
				$name = substr($name, $p + 1);
31
				$p = isset($this->dtc->elements[$name]);
32
			}
33
			if (!$p) {
34
				coordonnees_erreur($this, " <b>$name</b>&nbsp;: "
35
					. _T('zxml_inconnu_balise'));
36
37
				return;
38
			}
39
		}
40
		// controler les filles illegitimes, ca suffit 
41
		$depth = $this->depth;
42
		$ouvrant = $this->ouvrant;
43
		#spip_log("trouve $name apres " . $ouvrant[$depth]);
44
		if (isset($ouvrant[$depth])) {
45
			if (preg_match('/^\s*(\w+)/', $ouvrant[$depth], $r)) {
46
				$pere = $r[1];
47
				#spip_log("pere $pere");
48
				if (isset($this->dtc->elements[$pere])) {
49
					$fils = $this->dtc->elements[$pere];
50
					#spip_log("rejeton $name fils " . @join(',',$fils));
51
					if (!($p = @in_array($name, $fils))) {
52 View Code Duplication
						if ($p = strpos($name, ':')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
53
							$p = substr($name, $p + 1);
54
							$p = @in_array($p, $fils);
55
						}
56
					}
57
					if (!$p) {
58
						$bons_peres = @join('</b>, <b>', $this->dtc->peres[$name]);
59
						coordonnees_erreur($this, " <b>$name</b> "
60
							. _T('zxml_non_fils')
61
							. ' <b>'
62
							. $pere
63
							. '</b>'
64
							. (!$bons_peres ? ''
65
								: ('<p style="font-size: 80%"> ' . _T('zxml_mais_de') . ' <b>' . $bons_peres . '</b></p>')));
66
					} elseif ($this->dtc->regles[$pere][0] == '/') {
67
						$frat = substr($depth, 2);
68
						if (!isset($this->fratrie[$frat])) {
69
							$this->fratrie[$frat] = '';
70
						}
71
						$this->fratrie[$frat] .= "$name ";
72
					}
73
				}
74
			}
75
		}
76
		// Init de la suite des balises a memoriser si regle difficile
77
		if ($this->dtc->regles[$name] and $this->dtc->regles[$name][0] == '/') {
78
			$this->fratrie[$depth] = '';
79
		}
80
		if (isset($this->dtc->attributs[$name])) {
81
			foreach ($this->dtc->attributs[$name] as $n => $v) {
82
				if (($v[1] == '#REQUIRED') and (!isset($attrs[$n]))) {
83
					coordonnees_erreur($this, " <b>$n</b>"
84
						. '&nbsp;:&nbsp;'
85
						. _T('zxml_obligatoire_attribut')
86
						. " <b>$name</b>");
87
				}
88
			}
89
		}
90
	}
91
92
	// http://code.spip.net/@validerAttribut
93
	public function validerAttribut($phraseur, $name, $val, $bal) {
94
		// Si la balise est inconnue, eviter d'insister
95
		if (!isset($this->dtc->attributs[$bal])) {
96
			return;
97
		}
98
99
		$a = $this->dtc->attributs[$bal];
100
		if (!isset($a[$name])) {
101
			$bons = join(', ', array_keys($a));
102
			if ($bons) {
103
				$bons = " title=' " .
104
					_T('zxml_connus_attributs') .
105
					'&nbsp;: ' .
106
					$bons .
107
					"'";
108
			}
109
			$bons .= " style='font-weight: bold'";
110
			coordonnees_erreur($this, " <b>$name</b> "
111
				. _T('zxml_inconnu_attribut') . ' ' . _T('zxml_de')
112
				. " <a$bons>$bal</a> ("
113
				. _T('zxml_survoler')
114
				. ")");
115
		} else {
116
			$type = $a[$name][0];
117
			if (!preg_match('/^\w+$/', $type)) {
118
				$this->valider_motif($phraseur, $name, $val, $bal, $type);
119
			} else {
120
				if (method_exists($this, $f = 'validerAttribut_' . $type)) {
121
					$this->$f($phraseur, $name, $val, $bal);
122
				}
123
			}
124
			#		else spip_log("$type type d'attribut inconnu");
125
		}
126
	}
127
128
	public function validerAttribut_NMTOKEN($phraseur, $name, $val, $bal) {
129
		$this->valider_motif($phraseur, $name, $val, $bal, _REGEXP_NMTOKEN);
130
	}
131
132
	public function validerAttribut_NMTOKENS($phraseur, $name, $val, $bal) {
133
		$this->valider_motif($phraseur, $name, $val, $bal, _REGEXP_NMTOKENS);
134
	}
135
136
	// http://code.spip.net/@validerAttribut_ID
137
	public function validerAttribut_ID($phraseur, $name, $val, $bal) {
138
		if (isset($this->ids[$val])) {
139
			list($l, $c) = $this->ids[$val];
140
			coordonnees_erreur($this, " <p><b>$val</b> "
141
				. _T('zxml_valeur_attribut')
142
				. " <b>$name</b> "
143
				. _T('zxml_de')
144
				. " <b>$bal</b> "
145
				. _T('zxml_vu')
146
				. " (L$l,C$c)");
147
		} else {
148
			$this->valider_motif($phraseur, $name, $val, $bal, _REGEXP_ID);
149
			$this->ids[$val] = array(xml_get_current_line_number($phraseur), xml_get_current_column_number($phraseur));
150
		}
151
	}
152
153
	// http://code.spip.net/@validerAttribut_IDREF
154
	public function validerAttribut_IDREF($phraseur, $name, $val, $bal) {
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $bal is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
155
		$this->idrefs[] = array($val, xml_get_current_line_number($phraseur), xml_get_current_column_number($phraseur));
156
	}
157
158
	// http://code.spip.net/@validerAttribut_IDREFS
159
	public function validerAttribut_IDREFS($phraseur, $name, $val, $bal) {
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $bal is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
160
		$this->idrefss[] = array($val, xml_get_current_line_number($phraseur), xml_get_current_column_number($phraseur));
161
	}
162
163
	// http://code.spip.net/@valider_motif
164
	public function valider_motif($phraseur, $name, $val, $bal, $motif) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
		if (!preg_match($motif, $val)) {
166
			coordonnees_erreur($this, "<b>$val</b> "
167
				. _T('zxml_valeur_attribut')
168
				. " <b>$name</b> "
169
				. _T('zxml_de')
170
				. " <b>$bal</b> "
171
				. _T('zxml_non_conforme')
172
				. "</p><p>"
173
				. "<b>" . $motif . "</b>");
174
		}
175
	}
176
177
	// http://code.spip.net/@valider_idref
178
	public function valider_idref($nom, $ligne, $col) {
179
		if (!isset($this->ids[$nom])) {
180
			$this->err[] = array(" <p><b>$nom</b> " . _T('zxml_inconnu_id'), $ligne, $col);
181
		}
182
	}
183
184
	// http://code.spip.net/@valider_passe2
185
	public function valider_passe2() {
186
		if (!$this->err) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->err of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
187
			foreach ($this->idrefs as $idref) {
188
				list($nom, $ligne, $col) = $idref;
189
				$this->valider_idref($nom, $ligne, $col);
190
			}
191
			foreach ($this->idrefss as $idref) {
192
				list($noms, $ligne, $col) = $idref;
193
				foreach (preg_split('/\s+/', $noms) as $nom) {
194
					$this->valider_idref($nom, $ligne, $col);
195
				}
196
			}
197
		}
198
	}
199
200
	// http://code.spip.net/@debutElement
201
	public function debutElement($phraseur, $name, $attrs) {
202
		if ($this->dtc->elements) {
203
			$this->validerElement($phraseur, $name, $attrs);
204
		}
205
206
		if ($f = $this->process['debut']) {
207
			$f($this, $name, $attrs);
208
		}
209
		$depth = $this->depth;
210
		$this->debuts[$depth] = strlen($this->res);
211
		foreach ($attrs as $k => $v) {
212
			$this->validerAttribut($phraseur, $k, $v, $name);
213
		}
214
	}
215
216
	// http://code.spip.net/@finElement
217
	public function finElement($phraseur, $name) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
218
		$depth = $this->depth;
219
		$contenu = $this->contenu;
220
221
		$n = strlen($this->res);
222
		$c = strlen(trim($contenu[$depth]));
223
		$k = $this->debuts[$depth];
224
225
		$regle = isset($this->dtc->regles[$name]) ? $this->dtc->regles[$name] : false;
226
		$vide = ($regle == 'EMPTY');
227
		// controler que les balises devant etre vides le sont 
228
		if ($vide) {
229
			if ($n <> ($k + $c)) {
230
				coordonnees_erreur($this, " <p><b>$name</b> " . _T('zxml_nonvide_balise'));
231
			}
232
			// pour les regles PCDATA ou iteration de disjonction, tout est fait
233
		} elseif ($regle and ($regle != '*')) {
234
			if ($regle == '+') {
235
				// iteration de disjonction non vide: 1 balise au -
236
				if ($n == $k) {
237
					coordonnees_erreur($this, "<p>\n<b>$name</b> "
238
						. _T('zxml_vide_balise'));
239
				}
240
			} else {
241
				$f = isset($this->fratrie[substr($depth, 2)]) ? $this->fratrie[substr($depth, 2)] : null;
242
				if (is_null($f) or !preg_match($regle, $f)) {
243
					coordonnees_erreur($this,
244
						" <p>\n<b>$name</b> "
245
						. _T('zxml_succession_fils_incorrecte')
246
						. '&nbsp;: <b>'
247
						. $f
248
						. '</b>');
249
				}
250
			}
251
252
		}
253
		if ($f = $this->process['fin']) {
254
			$f($this, $name, $vide);
255
		}
256
	}
257
258
	// http://code.spip.net/@textElement
259
	public function textElement($phraseur, $data) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
260
		if (trim($data)) {
261
			$d = $this->depth;
262
			$d = $this->ouvrant[$d];
263
			preg_match('/^\s*(\S+)/', $d, $m);
264
			if (isset($this->dtc->pcdata[$m[1]]) and ($this->dtc->pcdata[$m[1]])) {
265
				coordonnees_erreur($this, " <p><b>" . $m[1] . "</b> "
266
					. _T('zxml_nonvide_balise') // message a affiner
267
				);
268
			}
269
		}
270
		if ($f = $this->process['text']) {
271
			$f($this, $data);
272
		}
273
	}
274
275
	public function piElement($phraseur, $target, $data) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
276
		if ($f = $this->process['pi']) {
277
			$f($this, $target, $data);
278
		}
279
	}
280
281
	// Denonciation des entitees XML inconnues
282
	// Pour contourner le bug de conception de SAX qui ne signale pas si elles
283
	// sont dans un attribut, les  entites les plus frequentes ont ete
284
	// transcodees au prealable  (sauf & < > " que SAX traite correctement).
285
	// On ne les verra donc pas passer a cette etape, contrairement a ce que 
286
	// le source de la page laisse legitimement supposer. 
287
288
	// http://code.spip.net/@defautElement
289
	public function defaultElement($phraseur, $data) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
290
		if (!preg_match('/^<!--/', $data)
291
			and (preg_match_all('/&([^;]*)?/', $data, $r, PREG_SET_ORDER))
292
		) {
293
			foreach ($r as $m) {
294
				list($t, $e) = $m;
0 ignored issues
show
Unused Code introduced by
The assignment to $t is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
295
				if (!isset($this->dtc->entites[$e])) {
296
					coordonnees_erreur($this, " <b>$e</b> "
297
						. _T('zxml_inconnu_entite')
298
						. ' '
299
					);
300
				}
301
			}
302
		}
303
		if (isset($this->process['default']) and ($f = $this->process['default'])) {
304
			$f($this, $data);
305
		}
306
	}
307
308
	// http://code.spip.net/@phraserTout
309
	public function phraserTout($phraseur, $data) {
0 ignored issues
show
Unused Code introduced by
The parameter $phraseur is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
310
		xml_parsestring($this, $data);
311
312
		if (!$this->dtc or preg_match(',^' . _MESSAGE_DOCTYPE . ',', $data)) {
313
			$this->err[] = array('DOCTYPE ?', 0, 0);
314
		} else {
315
			$this->valider_passe2($this);
0 ignored issues
show
Unused Code introduced by
The call to ValidateurXML::valider_passe2() has too many arguments starting with $this.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
316
		}
317
	}
318
319
	/**
320
	 * Constructeur
321
	 *
322
	 * @param array $process ?
323
	 **/
324
	public function __construct($process = array()) {
325
		if (is_array($process)) {
326
			$this->process = $process;
327
		}
328
	}
329
330
	public $ids = array();
331
	public $idrefs = array();
332
	public $idrefss = array();
333
	public $debuts = array();
334
	public $fratrie = array();
335
336
	public $dtc = null;
337
	public $sax = null;
338
	public $depth = "";
339
	public $entete = '';
340
	public $page = '';
341
	public $res = "";
342
	public $err = array();
343
	public $contenu = array();
344
	public $ouvrant = array();
345
	public $reperes = array();
346
	public $process = array(
347
		'debut' => 'xml_debutElement',
348
		'fin' => 'xml_finElement',
349
		'text' => 'xml_textElement',
350
		'pi' => 'xml_piElement',
351
		'default' => 'xml_defaultElement'
352
	);
353
}
354
355
356
/**
357
 * Retourne une structure ValidateurXML, dont le champ "err" est un tableau
358
 * ayant comme entrees des sous-tableaux [message, ligne, colonne]
359
 *
360
 **/
361
function xml_valider_dist($page, $apply = false, $process = false, $doctype = '', $charset = null) {
362
	$f = new ValidateurXML($process);
363
	$sax = charger_fonction('sax', 'xml');
364
365
	return $sax($page, $apply, $f, $doctype, $charset);
366
}
367