Valider un bbcode (ou autre) = html correct

Soyez le premier à donner votre avis sur cette source.

Snippet vu 5 151 fois - Téléchargée 29 fois

Contenu du snippet

Ce petit script verifie simplement qu'un texte contenant un bbcode soit valide : qu'il y ait bien des balises ouvrantes et fermantes, et pas n'importe comment.
Ainsi, lorsque ce code sera parse er remplace par son equivalent html, il n'y aura pas de probleme de html crade (enfin, tout depend par quoi vous remplacez, evidemment ;-) )
Donc, voila ce que le code fait :
- detruit toute balise orpheline (balise ouvrante seule, balise fermante seule, balise fermante AVANT une balise ouvrante...)
- verifie que l'encapsulation est correcte. Sinon, la corrige. Exemple : [b][i] bla /b/i va devenir [b][i] bla /i/b (et ca, ca a ete complique ;-) )

Source / Exemple :


<?php
class verif_bb {
	
	//variables membres
	var $startTags;
	var $endTags;
	var $texte;
	var $startArr;
	var $endArr;
	
	//constructeur de la classe. Verifie que les parametres passes soient corrects. Accepte tableaux de meme taille ou chaines pour les tags, et une chaine uniquement pour le texte. Les tags ouvrants et leurs equivalents fermants DOIVENT avoir la meme clef dans leur tableau respectif.
	function verif_bb ($start, $end, &$chaine) {
		if (!is_string ($start) && !is_array ($start))
			die ('le parametre $start n\'est pas une chaine ou un tableau.');
		if (!is_string ($end) && !is_array ($end))
			die ('le parametre $end n\'est pas une chaine ou un tableau.');
		if (count ($start) != count ($end))
			die ('$start et $end ne sont pas de meme taille.');
		if (!is_string ($chaine))
			die ('le parametre $chaine n\'est pas une chaine.');
			
		$this -> startTags = $start;
		$this -> endTags = $end;
		$this -> texte = &$chaine;
		
		$this -> verif_integrite ();
	}
	
	//appelle les differentes methodes
	function verif_integrite () {
		$this -> strip_starting_end_tags ();
		$this -> strip_no_end_start ();
		if (is_array ($this -> startTags)) 
			$this -> verif_encaps();
	}
	
 //methode verifiant s'il y a des end tags avant leur equivalent start tag. Dans ce cas, on les vire!
	function strip_starting_end_tags () {
		//si on a un tableau de tags
		if (is_array ($this -> startTags)) {
			foreach ($this -> startTags as $clef => $val) {
				$endPos = strpos ($this -> texte, $this ->endTags[$clef]);
				$startPos = strpos ($this -> texte, $val);
				while ($endPos !== false && ($endPos < $startPos || $startPos === false)) {
					$this -> texte = substr_replace ($this -> texte, '', $endPos, strlen ($this -> endTags[$clef]));
					$endPos = strpos ($this -> texte, $this -> endTags[$clef]);
				}
			}
		}
		// si on a juste une chaine avec un tag
		else {
			$endPos = strpos ($this -> texte, $this -> endTags);
			$startPos = strpos ($this -> texte, $this -> startTags);
			while ($endPos !== false && ($endPos < $startPos || $startPos === false)) {
				$this -> texte = substr_replace ($this -> texte, '', $endPos, strlen ($this -> endTags));
				$endPos = strpos ($this -> texte, $this -> endTags);
			}
		}
	}
	
	//methode verifiant s'il y a en fin de texte des start tags sans end tags. dans ce cas, on les vire!
	function strip_no_end_start () {
		$this -> texte = strrev ($this -> texte);
		//si on a un tableau de tags
		if (is_array ($this -> startTags)) {
			foreach ($this -> startTags as $clef => $val) {
				$val =strrev ($val);
				$endPos = strpos ($this -> texte, strrev ($this -> endTags[$clef]));
				$startPos = strpos ($this -> texte, $val);
				while ($startPos !== false && ($endPos > $startPos || $endPos === false)) {
					$this -> texte = substr_replace ($this -> texte, '', $startPos, strlen ($val));
					$startPos = strpos ($this -> texte, $val);
				}
			}
		}
		// si on a juste une chaine avec un tag
		else {
			$endPos = strpos ($this -> texte, strrev ($this ->endTags));
			$startPos = strpos ($this -> texte, strrev ($this -> startTags));
			while ($startPos !== false && ($endPos > $startPos || $endPos === false)) {
				$this -> texte = substr_replace ($this -> texte, '', $startPos, strlen ($this -> startTags));
				$startPos = strpos ($this -> texte, strrev ($this ->startTags));
			}
		}
	$this -> texte = strrev($this -> texte);
	}
	
	//methode verifiant et corrigeant l'encapsulation des tags
	function verif_encaps () {
		if (isset ($this -> startArr))
			unset ($this -> startArr);
		if (isset ($this -> endArr))
			unset ($this -> endArr);
		foreach ($this -> startTags as $startVal) {
			$offset = 0;
			while (strpos ($this -> texte, $startVal, $offset) !== false) {
				$startPosTab = strpos ($this -> texte, $startVal, $offset);
				$this -> startArr[][$startVal] = $startPosTab;
				$offset = $startPosTab + strlen ($startVal);
			}
		}
		foreach ($this -> endTags as $clefVal => $endVal) {
			$offset = 0;
			$revTxt = strrev ($this -> texte);
			$revVal = strrev ($endVal);
			while (strpos ($revTxt, $revVal, $offset) !== false) {
				$endPosTab = strpos ($revTxt, $revVal, $offset);
				$this -> endArr[][$endVal]= strlen ($this -> texte) - $endPosTab -strlen ($endVal);
				$offset = $endPosTab + strlen ($endVal);
			}
		}

		$cpt = count ($this -> startArr);
		$iCpt = 0;
		while ($iCpt < $cpt) {
			$jCpt = $iCpt + 1;
			 while ($jCpt < $cpt) {
				foreach ($this -> startArr[$iCpt] as $clef => $val) {
					foreach ($this -> startArr[$jCpt] as $clef2 => $val2) {
						if ($clef  != $clef2) {
							$startPos = $val;
							$endPos = $this -> endArr[$iCpt][$this -> endTags[array_search($clef, $this -> startTags)]];
							$startPos2 = $val2;
							$endPos2 = $this -> endArr[$jCpt][$this -> endTags[array_search($clef2, $this -> startTags)]];
							if (($startPos < $startPos2 && $endPos < $endPos2) || ($startPos > $startPos2 && $endPos > $endPos2)) {
								$tagRep1 = $this -> endTags[array_search($clef, $this -> startTags)];
								$tagRep2 = $this -> endTags[array_search($clef2, $this -> startTags)];
								$len1 = strlen ($tagRep1);
								$len2 = strlen ($tagRep2);
								if ($len1 < $len2 && $endPos > $endPos2) {
									$endPos = $endPos - ($len2 - $len1);
									$this -> texte = str_pad ($this -> texte, $len2 - $len1);
								}
								if ($len1 > $len2 && $endPos > $endPos2) {
									$endPos = $endPos + ($len1 - $len2);
									$this -> texte = str_pad ($this -> texte, $len1 - $len2);
								}
								$this -> texte = substr_replace ($this -> texte, $tagRep1, $endPos2, $len2);
								$this -> texte = substr_replace ($this -> texte, $tagRep2, $endPos, $len1);
								$this -> verif_encaps ();
							}
						}
					}
				}
				$jCpt ++;
			}
			$iCpt ++;
		}
	}
	
}

// tests
$txt = '/url/i/b/b[b][i][b]bonjour/i/b/b[b]';
$txt2 = '[i][url][b] test /i/url/b';
$arrStart = array ('[b]', '[i]', '[url]');
$arrEnd = array ('/b', '/i', '/url');

$txttxt = '/b[b]bonjour/b[b][b]';
$txtStart = '[b]';
$txtEnd = '/b';

echo '<br> Avant : ', $txt, '<br/>';
$parser = new verif_bb($arrStart, $arrEnd, $txt);
echo '<br> Apres : ', $txt, '<br/>';

echo '<br> Avant : ', $txt2, '<br/>';
$parser = new verif_bb ($arrStart, $arrEnd, $txt2);
echo '<br> Apres : ', $txt2, '<br/>';

echo '<br> Avant : ', $txttxt, '<br/>';
$parser = new verif_bb ($txtStart, $txtEnd, $txttxt);
echo '<br> Apres : ', $txttxt, '<br/>';

?>

Conclusion :


Je n'ai pas tout a fait fini, je veux verifier que l'imbrication soit correcte, et faire la meme chose avec du html. Mais je n'ai plus le temps ce soir! Je mettrai a jour.

A voir également

Ajouter un commentaire Commentaires
Messages postés
31
Date d'inscription
vendredi 18 février 2005
Statut
Membre
Dernière intervention
25 avril 2006

je dirais que ça les prend en compte, mais que ça ne les corrige pas.
l'utilisateur devra corriger et progresser tout seul (à mon avis mieux vaut ça que le traitement buggé des forums en phpBB, où je trouve régulièrement des fermetures de balises innoportunes en fin de message. j'ai pas creusé le sujet non plus)
bref, soit ton balisage est correct, et il sera transcrit en html, soit il n'est pas correct et il restera tel quel.

à la rigueur tu peux tester le reste des balises [xxx] et/ou /yyy en fin de traitement et les mettre en blink dans la prévisualisation

un exemple de rendu
[b]penche[u]souligneépais[b]
->
penche<gras>[u]souligneepais</gras>

bon le blink je sais pas s'il faut l'implémenter
;-)

j'attends avec impatience le décodage de la regex. merci !

(ps : désolé pour l'erreur [i] devient et pas bien entendu !)
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
22
Pour l'explication, on verra demain (désolé de faiure si court, mais bon, c'est le soir ;-) Je vis, le soir lol).
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
22
Hello,

non, ça ne prend pas en compte les mauvaises imbrications, justement. Ni les oublis de fermeture, ou d'ouverture, etc.
Messages postés
31
Date d'inscription
vendredi 18 février 2005
Statut
Membre
Dernière intervention
25 avril 2006

c'est pas de moi, mais cela ne suffit-il pas ?
$chaine = preg_replace('#\ (.+?)\ #si','$1',$chaine);
$chaine = preg_replace('#\(.+?)\#si','$1',$chaine);
etc.. etc...

avec une prévisualisation, si l'utilisateur oublie de fermer une balise il s'en rendra compte lui même, et progressera tout seul.

au moins c'est pas l'usine à gaz !
(au passage si kkun peut m'expliquer cette expression rationnelle, j'ai pas réussi à trouver de référence complète sur les regex.
pour le moment je lis contient ''.$var.'' quelque part dans la chaine et remplace par '[em]'.$var.'/em'.
le # du début veut certainement dire "n'importe ou" mais le #si de la fin... hum hum je vois pas

merci d'avance
Messages postés
10840
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
22
Finalement, je n'ai pas termuiné cette partie précise ;-)
Jamais eu le temps, et c'est lourd...je n'ai jamais vraiment trouver de solution parfaitement fiable (je parle de la gestion de l'imbrication des balises).
Le reste fonctionne.
Afficher les 18 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.