G->RAW->id; // affiche $_GET['id'] sans modification * echo $Input->P->HTML->truc; // affiche $_POST['truc'] pour une utilisation dans une balise html (htmlentities) * echo $Input->C->SQL->login; // affiche $_COOKIE['login'] pour une utilisation dans une requete sql (mysql_real_escape_string) * echo $Input->F->RAW->nomFichier; // affiche $FILES['nomFichier']; sans modification * echo $Input->G->ISSET->id; // affiche TRUE si $_GET['id'] existe, FALSE sinon * echo $Input->HTML($variableLocale); * * Ajouter des types ou des formats : * - Créer une classe fille qui étend de "In" * - Enregistrer les nouveaux types / formats dans la méthode "register" comme c'est le cas pour les types et formats prédéfinis de In * - Appeler parent::register(); en haut de register() * - Créer les méthodes correspondants aux nouveaux formats dans la classe fille. * * Parametrage : * In::setThrowException(FALSE); // Renverra NULL au lieu d'une exception en cas de mauvaise utilisation ou de variable inexistante. * In::setCharset('...'); // Permet de spécifier un charset pour la methode htmlentities * * Attention a ce comportement lié au cache : * $Input = In::getInstance(); * echo $Input->G->RAW->id; // affiche $_GET['id'] * $_GET['id'] = 'nouvelle Valeur'; * echo $Input->G->RAW->id; // affiche l'ANCIENNE valeur de $_GET['id'] car la variable est présente en cache ! * echo $Input->G->HTML->id; // affiche la NOUVELLE valeur de $_GET['id'] car la variable n'a jamais été demandée pour le format HTML ! * $_GET['machin'] = 'valeur'; * echo $Input->G->RAW->machin; // affiche $_GET['machin'] car la valeur n'a jamais été demandé précédemment, donc le cache est vide. * * Historique * 1.4 * Réécriture complète. Suppression des classes internes. * Ajout de la possibilité d'enregistrer de nouveaux types et de nouveaux formats * Ajout du format URL et Base64 * 1.3 * Correction d'un bug dans la gestion des magic_quotes_gpc pour toutes les variables * Correction d'un bug dans la gestion des magic_quotes_gpc pour les variables locales * 1.2 * Ajout du charset pour htmlentities * Ajout de ENT_QUOTES * 1.1 * Ajout de la possibilite de formater des variables locales * * @author Fladnag * @date 29/12/2007 * @review 15/02/2009 1.3 * @review 12/03/2011 1.4 * @version 1.4 * @require PHP 5.3.0 */ /* NE PAS UTILISER DIRECTEMENT CETTE CLASSE */ abstract class _InBase { // l'exception levée en cas de variable inconnue const EX_UNDEFINED_VARIABLE=1; // l'exception levée en cas d'appel a un format inconnu const EX_UNDEFINED_FORMAT=2; // l'exception levée en cas d'appel a un tableau inconnu const EX_UNDEFINED_TYPE=3; protected static $mpBaseInstances = array(); // Tableau d'instances: en cas de classes filles, on peux avoir autant de singleton que de classes filles protected static $mpTypeInstances = array(); // Instances de Type protected static $mpFormatInstances = array(); // Instances de Format private static $mpThrowException = TRUE; // Parametrage de l'exception en cas de variable inexistante private static $mpIsMagicQuotesGPC = NULL; // Indique si l'option magic_quotes_gpc est activee dans php.ini private static $mpCharset = NULL; // Charset par defaut protected static $mpTypeList = array(); // Liste des Type enregistrés protected static $mpFormatList = array(); // Liste des Format enregistrés private $mpType = NULL; // Le type courant de l'instance private $mpFormat = NULL; // Le format courant de l'instance /***************** PRIVATE FUNCTIONS ***************/ private static function getRegisteredType($pType) { if (static::isExistType($pType)) { return static::$mpTypeList[$pType]; } static::throwException("Le type [$pType] n'est pas enregistré.", static::EX_UNDEFINED_TYPE); return NULL; } private static function getRegisteredFormat($pFormat) { if (static::isExistFormat($pFormat)) { return static::$mpFormatList[$pFormat]; } static::throwException("Le format [$pFormat] n'est pas enregistré.", static::EX_UNDEFINED_FORMAT); return NULL; } private static function isExistType($pType) { return isset(static::$mpTypeList[$pType]); } private static function isExistFormat($pFormat) { return isset(static::$mpFormatList[$pFormat]); } /** * @description Lève un message d'exception si on utilise les exceptions */ private static function throwException($pMessage, $pTypeException) { if (self::haveToThrowException()) { throw new Exception($pMessage, $pTypeException); } } /** * @description Renvoi la variable formatée. */ private function _getVariable($pVariable) { $aSource=static::getRegisteredType($this->mpType); if (!is_array($aSource)) { global ${$aSource}; // les tableaux superglobaux ne sont pas visibles car leur nom est construit dynamiquement. Le mot clé "global" est donc nécessaire. $aSource=${$aSource}; } if ($this->mpFormat === "ISSET") { $this->$pVariable = isset($aSource[$pVariable]); return $this->$pVariable; } if (!isset($aSource[$pVariable])) { static::throwException("La variable [$pVariable] n'est pas définie dans le tableau [\$".$this->mpType.']', static::EX_UNDEFINED_VARIABLE); return NULL; } $aVariable = $aSource[$pVariable]; $aFunction=static::getRegisteredFormat($this->mpFormat); if (is_scalar($aVariable)) { if (static::getMagicQuotesGPC()) { $aVariable=stripslashes($aVariable); } $this->$pVariable = forward_static_call($aFunction, $aVariable); } elseif (is_array($aVariable)) { if (static::getMagicQuotesGPC()) { $aVariable=array_map($aVariable, 'stripslashes'); } $this->$pVariable = array_map($aFunction, $aVariable); } return $this->$pVariable; } /** * @description Renvoi une instance de Format */ private function _getFormat($pFormat) { $this->$pFormat = static::getFormatInstance($this->mpType, $pFormat); return $this->$pFormat; } /** * @description Renvoi une instance de Type */ private function _getType($pType) { if (static::isExistType($pType)) { $this->$pType = static::getTypeInstance($pType); } else { static::throwException("Le type [$pType] n'existe pas.", static::EX_UNDEFINED_TYPE); } return $this->$pType; } /** * @description Renvoi l'instance du singleton de type */ final private static function getTypeInstance($pType) { if (!isset(static::$mpTypeInstances[$pType])) { static::$mpTypeInstances[$pType] = new static($pType); } return static::$mpTypeInstances[$pType]; } /** * @description Renvoi l'instance du singleton de type / format */ final private static function getFormatInstance($pType, $pFormat) { $aKey = $pType.'/'.$pFormat; if (!isset(static::$mpFormatInstances[$aKey])) { static::$mpFormatInstances[$aKey] = new static($pType,$pFormat); } return static::$mpFormatInstances[$aKey]; } private function __construct() { if (func_num_args() > 0) { call_user_func_array(array($this, __METHOD__.func_num_args()), func_get_args()); } else { static::register(); } } /** * @description Construit une instance de Type */ private function __construct1($pType) { $this->mpType = $pType; } /** * @description Construit une instance de Format */ private final function __construct2($pType, $pFormat) { $this->mpType = $pType; $this->mpFormat = $pFormat; } /********** PROTECTED FUNCTIONS **********/ /** * @description Enregistre un nouveau type dans le singleton * @param $pName Le nom du type * @param $pSource Le nom du tableau global sous forme de String (sans le caractère $, par exemple "_GET" pour "$_GET") */ protected static function registerType($pName, $pSource) { static::$mpTypeList[$pName]=$pSource; } /** * @description Enregistre un nouveau format dans le singleton * @param $pName Le nom du format * @param $pFunction Le nom de la fonction. S'il s'agit d'une fonction de classe, utiliser un tableau de la forme array(NomDeLaClasse,NomDeLaMethodeStatique) */ protected static function registerFormat($pName, $pFunction) { static::$mpFormatList[$pName]=$pFunction; } /********** PUBLIC FUNCTIONS **********/ /** * @description Permet de parametrer le charset à utiliser pour le format HTML (htmlentities) */ public static function setCharset($pCharset) { self::$mpCharset = $pCharset; } /** * @description Renvoi le charset utilisé */ public static function getCharset() { return self::$mpCharset; } /** * @description Permet de parametrer le comportement de la classe en cas d'exception */ public static function setThrowException($pValue) { self::$mpThrowException = (boolean)$pValue; } /** * @description Renvoi TRUE si on doit lever une exception en cas d'erreur. FALSE sinon */ public static function haveToThrowException() { return self::$mpThrowException; } /** * @description Indique si le MagicQuotesGPC est activé ou non */ public static function getMagicQuotesGPC() { if (self::$mpIsMagicQuotesGPC === NULL) { self::$mpIsMagicQuotesGPC=(get_magic_quotes_gpc()==1); } return self::$mpIsMagicQuotesGPC; } /** * @description Renvoi l'instance du singleton */ final public static function getInstance() { $aIndex=get_called_class(); // permet de récupérer le nom de la classe fille. if (!isset(static::$mpBaseInstances[$aIndex])) { static::$mpBaseInstances[$aIndex] = new static(); } return static::$mpBaseInstances[$aIndex]; } /** * @description Renvoi l'objet demandé et l'ajoute a la classe pour un accès plus rapide ensuite s'il existe. */ public function __get($pVar) { if (isset($this->mpFormat)) { return static::_getVariable($pVar); } elseif (isset($this->mpType)) { return static::_getFormat($pVar); } else { return static::_getType($pVar); } } /** * @description Lève une exception indiquant que le format demandé n'existe pas. */ public function __call($pFormat, $pArgs) { static::throwException("Le format [$pFormat] n'existe pas.", static::EX_UNDEFINED_FORMAT); return NULL; } /** * @description La méthode a implémenter pour enregistrer les types / format par défaut. * Ne pas oublier d'appeller parent::register() si on étend la classe ! */ abstract protected function register(); } class In extends _InBase { /** * @description Constructeur par defaut. Enregistrement des types et formats par défaut. */ protected function register() { //parent::register(); // Ne pas oublier de faire cet appel dans la classe fille si on étend la classe static::registerType('G', '_GET'); static::registerType('P', '_POST'); static::registertype('F', '_FILES'); static::registerType('C', '_COOKIE'); static::registerFormat('HTML', array(get_class($this),'HTML')); static::registerFormat('URL', array(get_class($this),'URL')); static::registerFormat('SQL', array(get_class($this),'SQL')); static::registerFormat('RAW', array(get_class($this),'RAW')); static::registerFormat('B64', array(get_class($this),'B64')); static::registerFormat('ISSET', ''); // enregistré en interne. Nécessaire pour enregister le format quand même. } /** * @description Implementation du format HTML */ public static function HTML($pVariable) { return htmlentities($pVariable, ENT_QUOTES, static::getCharset()); } /** * @description Implementation du format B64 (base64) */ public static function B64($pVariable) { return base64_encode($pVariable); } /** * @description Implementation du format URL */ public static function URL($pVariable) { return urlencode($pVariable); } /** * @description Implementation du format SQL */ public static function SQL($pVariable) { return mysql_real_escape_string($pVariable); } /** * @description Implementation du format RAW */ public static function RAW($pVariable) { return $pVariable; } } /**** Tests Part **** header('Content-Type : text/html; charset=utf-8;'); echo '
';

mysql_connect('localhost', 'root', '');

$a='a\'a"a/a\aaa$a';
$_GET['id']=$a;

$Tests=array(
	'$In=In::getInstance();',
	'In::setCharset("utf-8");',
	'In::setThrowException(FALSE);',
	'$_GET[id] pour HTML' => array('$In->G->HTML->id', 'a'a"a/a\a<b>a</b>a$a'),
	'$_GET[id] pour SQL' => array('$In->G->SQL->id', 'a\\\'a\\"a/a\\\aaa$a'),
	'$_GET[id] pour URL' => array('$In->G->URL->id', 'a%27a%22a%2Fa%5Ca%3Cb%3Ea%3C%2Fb%3Ea%24a'),
	'$_GET[id] pour Base64' => array('$In->G->B64->id', 'YSdhImEvYVxhPGI+YTwvYj5hJGE='),
	'Local var pour HTML' => array('$In->HTML(\''.str_replace("'", "\\'", $a).'\')', 'a'a"a/a\a<b>a</b>a$a'),
	'$_GET[non_exist] pour RAW' => array('$In->G->RAW->non_exist', NULL),
	'In::setThrowException(TRUE);',
	'$_GET[non_exist] pour RAW avec Exception' => array('$In->G->RAW->non_exist', In::EX_UNDEFINED_VARIABLE),
	'Isset FALSE'=>array('$In->G->ISSET->nexistepas', FALSE),
	'Isset TRUE'=>array('$In->G->ISSET->id', TRUE),
	'Type inconnu avec Exception' => array('$In->R->HTML(1)', In::EX_UNDEFINED_TYPE),
	'Format inconnu avec Exception' => array('$In->TRUC(1)', In::EX_UNDEFINED_FORMAT),
	'class In2 extends In {
		public function register() {
			parent::register();
			static::registerType("R", "_T");
			static::registerFormat("HTML2", array(get_class($this), "HTML2"));
		}

		public static function HTML2($arg) {
			return "<".$arg.">";
		}
	}',
	'global $_T;',
	'$_T=array("AA"=>"aa", "BB"=>"bb");',
	'$In2=In2::getInstance();',
	'Classe Fille : Ajout du type R et du format HTML2'=>array('$In2->R->HTML2->AA', '<aa>'),
	'Classe Fille : Type R et format natif HTML'=>array('$In2->R->HTML->BB', 'bb'),
	'Classe Fille : Format sur variable locale'=>array('$In2->HTML2("machin")', '<machin>'),
	'$_POST["id"]="truc";',
	'Test Cache 1' => array('$In->P->RAW->id', 'truc'),
	'$_POST["id"]="machin";',
	'Test Cache 2' => array('$In->P->RAW->id', 'truc'),
	'Test Cache 3' => array('$In->P->HTML->id', 'machin'),
	'$_GET["tab"]=array("", "");',
	'Class Fille : Test tableau avec HTML' => array('$In2->G->HTML->tab', array('<u>', '<a>')),
	'Class Fille : Test tableau avec HTML2' => array('$In2->G->HTML2->tab', array('<>', '<>')),
);

$mem=array(memory_get_peak_usage(true), memory_get_usage(true));

function runTests($pTests) {
	$aNumTest=1;
	$nbOK=0;
	$nbKO=0;
	foreach($pTests as $aTestName=>$aTest) {
		if (is_numeric($aTestName)) {
			eval($aTest);
		} else {
			echo 'Test n°'.($aNumTest++).': '.$aTestName;
			//echo $In->$value[0][0]->$value[0][1]->$value[0][2];
			$isExceptionExpected=(is_numeric($aTest[1]));
			try {
				//var_dump($aTest[0]);
				eval('$aResult = '.$aTest[0].';');
				if (!$isExceptionExpected) {
					if (assert($aResult === $aTest[1])) {
						echo ' : OK';
						$nbOK++;
					} else {
						echo ' : KO : '.htmlspecialchars($aTest[1]).'] expected. ['.htmlspecialchars($aResult).'] obtained';
						$nbKO++;
					}
				} else {
					echo ' : KO : Exception '.htmlspecialchars($aTest[1]).' expected';
					$nbKO++;
				}
			} catch (Exception $ex) {
				if ($isExceptionExpected) {
					if (assert($ex->getCode() === $aTest[1])) {
						echo ' : OK';
						$nbOK++;
					} else {
						echo ' : KO : '.htmlspecialchars($aTest[1]).'] expected. ['.htmlspecialchars($ex->getCode()).'] obtained';
						$nbKO++;
					}
				} else {
					echo ' : KO : '.$ex->getMessage().'
['.htmlspecialchars($aTest[1]).'] expected. ['.htmlspecialchars($aResult).'] obtained'; $nbKO++; } } echo '
'; } } echo 'Nombre de tests OK : '.$nbOK.'
'; echo 'Nombre de tests KO : '.$nbKO.'

'; echo 'Dump pour empreinte mémoire :
'; ob_start(); var_dump($In); var_dump($In2); $out=ob_get_contents(); ob_end_clean(); echo htmlentities($out); } runTests($Tests); echo 'Memoire allouée max : '.(memory_get_peak_usage(true)-$mem[0]).' octets
'; echo 'Memoire allouée : '.(memory_get_usage(true)-$mem[1]).' octets
'; ******/ ?>