Valider 413ca3cc rédigé par cerdic's avatar cerdic
Parcourir les fichiers

Fix/refactoring query_echappe_textes() qui ne detectait parfois pas...

Fix/refactoring query_echappe_textes() qui ne detectait parfois pas completement et correctement les chaines
On robustifie la fonction avec controle en amont et en aval, en preferant ne rien faire si on a un doute plutot que de risquer de casser la requete sql.
On en profite pour rendre encore moins plausible la presence des sequences d'echappement dans la chaine
Et on modernise le code dans query_reinjecte_textes() en utilisant un argument splat

On modifie aussi l'usage dans req/mysql en privilegiant de garder la requete initiale intacte si il n'y a rien a faire dessus
parent 1baec0c9
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+35 −36
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -399,10 +399,29 @@ function _q($a) {
 * @param string $query
 * @return array
 */
function query_echappe_textes($query) {
	static $codeEchappements = ["''" => "\x1@##@\x1", "\'" => "\x2@##@\x2", '\\"' => "\x3@##@\x3"];
	$query = str_replace(array_keys($codeEchappements), array_values($codeEchappements), $query);
	if (preg_match_all("/((['])[^']*(\\2))|(([\"])[^\"]*(\\5))/S", $query, $textes)) {
function query_echappe_textes($query, $uniqid=null) {
	static $codeEchappements = null;
	if (is_null($codeEchappements)) {
		if (is_null($uniqid)) {
			$uniqid = uniqid();
		}
		$uniqid = substr(md5($uniqid), 0, 4);
		$codeEchappements = ["\\\\" => "\x1@#{$uniqid}#@\x1", "\\'" => "\x2@#{$uniqid}#@\x2", '\\"' => "\x3@#{$uniqid}#@\x3"];
	}
	if ($query === null) {
		return $codeEchappements;
	}

	// si la query contient deja des codes d'echappement on va s'emmeler les pinceaux et donc on ne touche a rien
	// ce n'est pas un cas legitime
	foreach ($codeEchappements as $codeEchappement) {
		if (strpos($query, $codeEchappement) !== false) {
			return [$query, []];
		}
	}

	$query_echappees = str_replace(array_keys($codeEchappements), array_values($codeEchappements), $query);
	if (preg_match_all("/((['])[^']*(\\2))|(([\"])[^\"]*(\\5))/S", $query_echappees, $textes)) {
		$textes = reset($textes); // indice 0 du match
		switch (count($textes)) {
			case 0:
@@ -429,12 +448,18 @@ function query_echappe_textes($query) {
				$replace = explode(',', $replace);
				break;
		}
		$query = str_replace($textes, $replace, $query);
		$query_echappees = str_replace($textes, $replace, $query_echappees);
	} else {
		$textes = [];
	}

	return [$query, $textes];
	// si il reste des quotes simples ou doubles, c'est qu'on s'est emmelles les pinceaux
	// dans le doute on ne touche a rien
	if (strpbrk($query_echappees, "'\"") !== false) {
		return [$query, []];
	}

	return [$query_echappees, $textes];
}

/**
@@ -448,36 +473,10 @@ function query_echappe_textes($query) {
 * @return string
 */
function query_reinjecte_textes($query, $textes) {
	static $codeEchappements = ["''" => "\x1@##@\x1", "\'" => "\x2@##@\x2", '\\"' => "\x3@##@\x3"];
	# debug de la substitution
	#if (($c1=substr_count($query,"%"))!=($c2=count($textes))){
	#	spip_log("$c1 ::". $query,"tradquery"._LOG_ERREUR);
	#	spip_log("$c2 ::". var_export($textes,1),"tradquery"._LOG_ERREUR);
	#	spip_log("ini ::". $qi,"tradquery"._LOG_ERREUR);
	#}
	switch (count($textes)) {
		case 0:
			break;
		case 1:
			$query = sprintf($query, $textes[0]);
			break;
		case 2:
			$query = sprintf($query, $textes[0], $textes[1]);
			break;
		case 3:
			$query = sprintf($query, $textes[0], $textes[1], $textes[2]);
			break;
		case 4:
			$query = sprintf($query, $textes[0], $textes[1], $textes[2], $textes[3]);
			break;
		case 5:
			$query = sprintf($query, $textes[0], $textes[1], $textes[2], $textes[3], $textes[4]);
			break;
		default:
			array_unshift($textes, $query);
			$query = call_user_func_array('sprintf', $textes);
			break;
	}
	// recuperer les codes echappements
	$codeEchappements = query_echappe_textes(null);

	$query = sprintf($query, ...$textes);

	$query = str_replace(array_values($codeEchappements), array_keys($codeEchappements), $query);

+4 −4
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -540,11 +540,11 @@ function _mysql_traite_query($query, $db = '', $prefixe = '') {
		// il faut alors echapper les chaine avant de le faire, pour ne pas risquer de
		// modifier une requete qui est en fait juste du texte dans un champ
		if (stripos($suite, 'SELECT') !== false) {
			list($suite, $textes) = query_echappe_textes($suite);
			if (preg_match('/^(.*?)([(]\s*SELECT\b.*)$/si', $suite, $r)) {
				$suite = $r[1] . _mysql_traite_query($r[2], $db, $prefixe);
			list($suite_echap, $textes) = query_echappe_textes($suite);
			if (preg_match('/^(.*?)([(]\s*SELECT\b.*)$/si', $suite_echap, $r)) {
				$suite_echap = $r[1] . _mysql_traite_query($r[2], $db, $prefixe);
				$suite = query_reinjecte_textes($suite_echap, $textes);
			}
			$suite = query_reinjecte_textes($suite, $textes);
		}
	}
	$r = preg_replace(_SQL_PREFIXE_TABLE_MYSQL, '\1' . $pref, $query) . $suite;