Amerabbcode -valider un bbcode (ou autre)-

Description

Bonjour à tous !

Cette classe est inspirée du code de Malalam (voir http://www.phpcs.com/code.aspx?ID=30110) qui permettait de corriger une chaîne contenant du BBCode. Mais cette classe ne fonctionnait pas entièrement. J'ai voulu corrigé le problème mais j'ai vite arrêté car je me suis cassé les dents sur ce script auquel je ne comprennais pas grand chose XD

J'ai donc entièrement reprogrammé cette classe pour obtenir ce résultat.

Si vous avez des remarques ou des améliorations à me proposer, je suis à votre écoute ;-)

Source / Exemple :


<?php
// Classe AmeraBBCode
// Auteur : Obimo (Site Web "www.audayls.123.fr")
// Classe basée sur la classe "verif_bb"  de "Malalam" ("http://www.phpcs.com/code.aspx?ID=30110")

define('FILETAGS', 'filetags.xml');

class AmeraBBCode {
	private $string = '';
	private static $tags;
	private $temp = array();

	public function __construct($string) {
		if (!isset(self::$tags)) $this->initialisetags();
		$this->string = (string) $string;
	}

	private function checktags() {
		$this->temp = $this->sortposition($this->temp, 'pos', 'asc');
		$i = -1;
		$open = array();
		while (isset($this->temp[++$i])) {
			if ($this->temp[$i]['delete'] === FALSE) {
				if ($this->temp[$i]['open'] === TRUE) {
					if (!isset($open[$this->temp[$i]['type']])) $open[$this->temp[$i]['type']] = array(0 => $i, 1 => $this->temp[$i]['type']);
					else {
						$j = $i;
						while (isset($this->temp[++$j]) AND ($this->temp[$j]['delete'] === TRUE OR $this->temp[$j]['open'] === TRUE OR $this->temp[$j]['type'] !== $this->temp[$i]['type']));
						$this->temp[$i]['delete'] = TRUE;
						$this->temp[$j]['delete'] = TRUE;
					}
				}
				else {
					$temp = end($open);
					if ($temp === FALSE OR $this->temp[$i]['type'] !== $temp[1]) {
						$j = $i;
						while (isset($this->temp[++$j])) $this->temp[$j]['newpos'] -= $this->temp[$i]['strlen'];
						$end = end($this->temp);
						$this->temp[$i]['newpos'] = $end['newpos']+$end['strlen'];
						$this->temp[] = $this->temp[$i];
						unset($this->temp[$i]);
					}
					else unset($open[$temp[1]]);
				}
			}
		}
	}

	public function correction() {
		$this->searchtags();
		$this->checktags();
		$this->emptytags();
		$this->save();
	}
	
	private function emptytags() {
		$this->temp = $this->sortposition($this->temp, 'newpos', 'asc');
		$i = -1;
		$close = array();
		$open = array();
		while (isset($this->temp[++$i])) {
			$endclose = end($close);
			$endopen = end($open);
			if ($this->temp[$i]['delete'] === FALSE) {
				if ($this->temp[$i]['open'] === TRUE) {
					if ($this->temp[$i]['newpos'] === $endclose[2] AND $this->temp[$i]['tag'] === $this->temp[$endclose[3]]['tag']) {
						$this->temp[$i]['delete'] = TRUE;
						$this->temp[$endclose[0]]['delete'] = TRUE;
					}
					else $open[$this->temp[$i]['type']] = array(0 => $i, 1 => $this->temp[$i]['type'], 2 => $this->temp[$i]['newpos']+$this->temp[$i]['strlen']);
					unset($close[$endclose[1]]);
				}
				else {
					if ($this->temp[$i]['newpos'] === $endopen[2]) {
						$this->temp[$i]['delete'] = TRUE;
						$this->temp[$endopen[0]]['delete'] = TRUE;
					}
					else $close[$this->temp[$i]['type']] = array(0 => $i, 1 => $this->temp[$i]['type'], 2 => $this->temp[$i]['newpos']+$this->temp[$i]['strlen'], 3 => $endopen[0]);
					unset($open[$endopen[1]]);
				}
			}
			else {
				if ($endclose !== FALSE) $close[$endclose[1]][2] += $this->temp[$i]['strlen'];
				if ($endopen !== FALSE) $open[$endopen[1]][2] += $this->temp[$i]['strlen'];
			}
		}
	}

	private function initialisetags() {
		if (!is_file(FILETAGS)) throw new Exception('Le fichier tags de AmeraBBCode est introuvable.');
		clearstatcache();
		$xml = simplexml_load_file(FILETAGS);
		if ($xml === FALSE) throw new Exception('Erreur dans le fichier de tags de AmeraBBCode.');
		$i = -1;
		while (isset($xml->tag[++$i])) {
			if ((string) $xml->tag[$i]->code === 'TRUE') $code = TRUE;
			else $code = FALSE;
			if ((string) $xml->tag[$i]->delete === 'TRUE') $delete = TRUE;
			else $delete = FALSE;
			if ((string) $xml->tag[$i]->regex === 'TRUE') {
				$regex = TRUE;
				$xml->tag[$i]->open = preg_replace(array('`^\[`', '`\]$`'), array('\[', '\]'), (string) $xml->tag[$i]->open);
			}
			else $regex = FALSE;
			self::$tags[] = array('open' => (string) $xml->tag[$i]->open, 'close' => (string) $xml->tag[$i]->close, 'code' => FALSE, 'delete' => $delete, 'regex' => $regex);
		}
	}

	private function save() {
		$tempdesc = $this->sortposition($this->temp, 'pos', 'desc');
		$i = -1;
		while (isset($tempdesc[++$i])) $this->string = substr_replace($this->string, '', $tempdesc[$i]['pos'], $tempdesc[$i]['strlen']);
		$i = -1;
		$temp = 0;
		while (isset($this->temp[++$i])) {
			if ($this->temp[$i]['delete'] === TRUE) $temp += $this->temp[$i]['strlen'];
			else $this->string = substr_replace($this->string, $this->temp[$i]['tag'], $this->temp[$i]['newpos']-$temp, 0);
		}
	}

	private function searchtags() {
		$i = -1;
		while (isset(self::$tags[++$i])) {
			$countopen = 0;
			$countclose = 0;
			$open = array();
			$close = array();
			if (self::$tags[$i]['regex'] === TRUE) {
				preg_match_all('`'.self::$tags[$i]['open'].'`', $this->string, $temp);
				$j =  -1;
				$pos = -1;
				while (isset($temp[0][++$j])) {
					$pos = strpos($this->string, $temp[0][$j], $pos+1);
					$open[] = array('delete' => self::$tags[$i]['delete'], 'newpos' => $pos, 'open' => TRUE, 'pos' => $pos, 'strlen' => strlen($temp[0][$j]), 'tag' => $temp[0][$j], 'type' => $i);
					$countopen++;
				}
			}
			else {
				$pos = -1;
				$strlen = strlen(self::$tags[$i]['open']);
				do {
				    $pos = strpos($this->string, self::$tags[$i]['open'], $pos+1);
					if ($pos !== FALSE) {
						$open[] = array('delete' => self::$tags[$i]['delete'], 'newpos' => $pos, 'open' => TRUE, 'pos' => $pos, 'strlen' => $strlen, 'tag' => self::$tags[$i]['open'], 'type' => $i);
						$countopen++;
					}
				} while ($pos !== FALSE);
			}
			$pos = -1;
			$strlen = strlen(self::$tags[$i]['close']);
			do {
				$pos = strpos($this->string, self::$tags[$i]['close'], $pos+1);
				if ($pos !== FALSE) {
					$close[] = array('delete' => self::$tags[$i]['delete'], 'newpos' => $pos, 'pos' => $pos, 'open' => FALSE, 'strlen' => $strlen, 'tag' => self::$tags[$i]['close'], 'type' => $i);
					$countclose++;
				}
			} while ($pos !== FALSE);
			$j = -1;
			while (isset($close[++$j]) AND isset($open[0]) AND $close[$j]['pos'] < $open[0]['pos']) {
				$close[$j]['delete'] = TRUE;
				$countclose--;
			}
			while ($countclose !== $countopen) {
				if ($countclose > $countopen) {
					$close[$countclose-1]['delete'] = TRUE;
					$countclose--;
				}
				else {
					$open[$countopen-1]['delete'] = TRUE;
					$countopen--;
				}
			}
			$this->temp = array_merge($this->temp, $open, $close);
		}
	}

	public function showstring() {
		return $this->string;
	}

	private function sortposition($array, $by, $order) {
		$endval = end($array);
		$vals = array_keys($endval);
		foreach ($vals as $init){
			$keyname = $init;
			$$keyname = array();
		}
		foreach ($array as $key => $row) {
			foreach ($vals as $names){
				$keyname = $names;
				$test = array();
				$test[$key] = $row[$names];
				$$keyname = array_merge((array) $$keyname,(array) $test);
			}
		}
		if ($order === 'asc') array_multisort($$by,SORT_ASC, SORT_NUMERIC,$array);
		else array_multisort($$by,SORT_DESC, SORT_NUMERIC,$array);
		return $array;
	}

}

try {
	$string = '[url="http://www.google.com"][b][url="http://www.google.fr"]/i/b/i/b[code="php"]Code !/code/u/b[b]Salut/b[b][i][i][b]bonjour/url/i/b/b[b]/i/url';
	$time = microtime(TRUE);
	$AmeraBBCode = new AmeraBBCode($string);
	$AmeraBBCode->correction();
	echo 'Chaîne d\'origine : ',$string,"<br />\n";
	echo 'Chaîne corrigée : ',$AmeraBBCode->showstring();
}
catch (Exception $e) {
	die ($e->getmessage());
}

?>

Conclusion :


La prochaine mise à jour ajoutera la prise en compte des balises "code" (les balises encadrées par ces balises ne seront pas analysées).

Codes Sources

A voir également

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.

Du même auteur (audayls)