Accueil > > > DÉBOGAGE D'UN CODE PHP (SUIVIT DES VARIABLES)
DÉBOGAGE D'UN CODE PHP (SUIVIT DES VARIABLES)
Information sur la source
Description
* La classe originalcompo\Debug est une classe PHP5 d'aide au débogage de code PHP permettant l'affichage du contenu de variables PHP, mais aussi de la définition d'une classe à partir d'une de ses instances (utilisation de la reflexion).
* Sa particularité est que l'affichage se fait sur une fenêtre HTML à part, qui est créée sur le serveur (qui contient le script à déboguer).
* Avantage: sur une page web, l'affichage de celui-ci n'est pas polué, les valeurs sont toujours visibles (plus de problème avec la mise en page css au moment ou on écrit la trace...)
* Il y a deux versions possibles:
* chaque page html est tracée indépendemment: toto.php --> toto.php.Debug.html
* une trace unique cumulant les traces: toto.php, tata.php --> trace.html
Ce code a été écrit dans un but pratique (aider au débogage de PHP) mais aussi didactique:
* il existe deux méthodes pour sauver la trace dans un seul fichier: en travaillant à partir d'une sauvegarde XML ou d'une sauvegarde de l'objet sérialisé;
* il existe deux méthodes dans la version XML: en travaillant avec DOM ou avec l'objet SimpleXMLElement
A chaque fois, l'utilisation de l'une ou l'autre des méthodes amène au même résultat. Cela m'a juste permis de tester plusieurs manières de faire !
Les explications du code sont incluses dans celui-ci
Source
- <?php
- namespace originalcompo;
- /** -----------------------------------------------------------------------------------------------
- Ce code a été écrit dans un but pratique (aider au débogage de PHP) mais aussi didactique:
- - il existe deux méthodes pour sauver la trace dans un seul fichier: en travaillant à partir d'une
- sauvegarde XML ou d'une sauvegarde de l'objet sérialisé;
- - il existe deux méthodes dans la version XML: en travaillant avec DOM ou avec l'objet
- SimpleXMLElement
- A chaque fois, l'utilisation de l'une ou l'autre des méthodes amène au même résultat.
- Cela m'a juste permis de tester plusieurs manière de faire !
- ---------------------------------------------------------------------------------------------------
- La classe Debug est une classe d'aide au débugage de code PHP permettant l'affichage de variables
- PHP intermédiaires.
- Sa particularité est que l'affichage se fait sur une fenêtre HTML à part, qui est créée sur le
- serveur (où se trouve ce script).
- Avantages: si on travaille sur une page web, l'affichage de celui-ci n'est pas polué, les valeurs
- sont toujours visibles (plus de problème avec la mise en page css au moment ou on écrit la trace...)
- Il y a deux versions possibles:
- - chaque page html est tracée indépendemment: toto.php --> toto.php.Debug.html
- - une trace unique cumulant les traces: toto.php, tata.php --> trace.html
- ---------------------------------------------------------------------------------------------------
- 2010/08/14 :
- - Pas d'écriture dans le fichier si $updateTrace est à false
- - Possibilité d'afficher la structure d'une classe à partir d'une instance de celle-ci
-
- 2010/08/15 :
- - Affichage de la classe parente ainsi que des interfaces utilisées
- - Interdiction du clonage
- - Notation HEREDOC
-
- 2010/08/16 :
- - Rajout d'un espace de nom
- (la classe ocDEBUG a été renommé en Debug, plus standard, l'espace de nom permettant de garantir
- l'unicité de la classe)
-
- 2010/08/17 :
- - Corrections de l'interprétation des span dans certains cas (fonction "describe_variable")
-
- 2010/08/19 :
- - Possibilité de générer les traces de plusieurs fichiers php dans un seul fichier
- (refresh y compris) via la sauvegarde dans un fichier xml des résultats intermédiaires
-
- 2010/08/24 :
- - rajout de deux liens: Clear (pour vider la trace) et Refresh (équivalent au F5 du navigateur)
- - Possibilité de générer les traces de plusieurs fichiers php dans un seul fichier
- (refresh y compris) via la sauvegarde de l'objet serialisé
- */
-
- /** -----------------------------------------------------------------------------------------------
- Le fait de définir un espace de nom fait que les classes/fonctions/constantes sont recherchées dans
- cet espace.
- - Pour les fonctions et constantes, PHP va aller les chercher dans l'espace global s'il ne peut les
- trouver dans l'espace de noms courant.
- - Les noms de classes sont toujours résolus avec l'espace de noms courant.
- Il faut donc ici préciser que les classes ReflectionClass et ReflectionMethod sont dans l'espace de
- nom global "\".
- On peut le faire en utilisant directement l'espace de nom lors de l'utilisation de la classe...
- exemple: $reflectMethod = new \ReflectionMethod($className, $fct->name);
- ...ou bien en utilisant un alias comme cela est fait dans le code ("use")
- */
- use \ReflectionClass as ReflectionClass, // \a\b\c as c; équivalent à \a\b\c;
- \ReflectionMethod,
- \SimpleXMLElement,
- \DomDocument, \DomXPath;
-
- class Debug {
- const ONETRACE_XML = 'trace.xml'; // nom du fichier de sortie si trace unique
- const ONETRACE_SER = 'trace.ser'; // nom du fichier de sortie si trace unique
- const ONETRACE_HTML = 'trace.html'; // nom du fichier de sortie si trace unique
- const EXT = '.Debug.html'; // extension du fichier de sortie si "une trace par fichier"
- const ENCODING = 'ISO-8859-1'; // const ENCODING = 'UTF-8';
-
- private $BEGIN; // "constante"
- private $END; // "constante"
- private $END_XML_SER; // "constante"
- private $nbRaccourcis = 0;
- private $trace = array();
- private $inittrace = array(); // sert au chargement de la page
-
- // Il est possible d'afficher l'heure d'écriture des variables
- public $withTime = false;
-
- // voir SaveToXML() :
- public $checksymbols = true;
-
- private $original4xml = array();
- private $_replace4xml = array();
- private $oldchar4xml;
- private $newchar4xml;
-
- // ----------------------------------------------------------------------------------------------
-
- private $updateTrace = true;
-
- public function get_UpdateTrace() {
- return $this->updateTrace;
- }
-
- public function set_UpdateTrace($new) {
- if ($new != $this->updateTrace) {
- $this->updateTrace = $new;
-
- if ($this->updateTrace) $this->update_debughtml();
- }
- }
-
- /** ---------------------------------------------------------------------------------------------
- Il y a 2 types d'informations qui ont un affichage particulier: les objets et les tableaux.
- Ces informations pouvant occuper beaucoup de place, pour faciliter/alléger le parcours de la
- page de débugage, on peut choisir de réduire ou développer ces informations, directement sur
- la page HTML, en appuyant respectivement sur le "-" ou le "+" qui apparait à côté de ce type
- de variables.
- - si un '+' est affiché, l'information est minimisé
- - si un '-' est affiché, toute l'information est affichée
-
- La propriété collapsed permet de choisir l'affichage par défaut au démarrage: true pour tout
- réduire, false pour tout afficher
-
- NOTES: la fonctionnalité réduire/développer est gérée via javascript.
- Des chaines de caractères sont générées par PHP et passées en paramètre d'une fonction javascript.
- Le javascript pouvant être interprété différemment selon les navigateurs, il est cnseillé de
- laisser $collapsed à true par défaut, certains d'entre eux pouvant ne pas réussir à interpréter
- certaines variables complexes.
- Par exemple: si $f est une instance de la classe de débugage, le script généré pour
- réduire/développer le code associée à $f->print_variable($f) fonctionne bien sur Mozilla Firefox
- mais pas sur IE8.
- ($f contient des propriétés chaines de caractère avec code HTML et fonctions javascript!)
- */
- public $collapsed = false;
-
- /** ---------------------------------------------------------------------------------------------
- Si on choisit XML pour gérer la trace unique
- Debug::getInstance('XML');
- ici, on décide si on utilise DOM ou SimpleXMLElement pour générer le XML
- (choix transparent puisque sans conséquence sur le résultat)
- */
- private $DOM = false;
- //private $DOM = true;
-
- /** ---------------------------------------------------------------------------------------------
- Définition des constantes :
- Le code CSS et JS était initialement externalisé dans 2 fichiers, mais on a alors un problème
- d'accès à définir si les différents fichiers à débuguer ne se trouvent pas sous le même chemin
- (répertoire). Ces codes sont donc directement inclus dans le fichier de trace généré.
- */
- public function init_const()
- {
- $JS =
- <<<JS
- <SCRIPT type='text/javascript' language='JavaScript1.2'>
- function dhtml_Click(INFO, VARIABLE, NUMERO)
- {
- INFO_ID = "INFO"+NUMERO.toString();
- PLUS_ID = "PLUS"+NUMERO.toString();
- if (document.getElementById(PLUS_ID).innerHTML == "+") {
- document.getElementById(PLUS_ID).innerHTML = "-";
- document.getElementById(INFO_ID).innerHTML = VARIABLE
- +"<br /><table><tr><td><PRE>"+INFO+"</PRE></td></tr></table>";
- }
- else {
- document.getElementById(PLUS_ID).innerHTML = "+";
- document.getElementById(INFO_ID).innerHTML = VARIABLE;
- }
- }
- </SCRIPT>
- JS;
-
- $CSS =
- <<<CSS
- <style type="text/css">
-
- TABLE, BODY { color: #0000a0; background-color: #ffffff;
- font-family:sans-serif, arial, times, helvetica; font-size: 10pt;}
-
- A:after {content: " "; }
- A:before {content: " "; }
- A:link {text-decoration: none; color: #FF0000; font-weight:bold; font-size:14pt;}
- A:visited {text-decoration: none; color: #FF0000; font-weight:bold; font-size:14pt;}
- A:active {text-decoration: none; color: #FF0000; font-weight:bold; font-size:14pt;}
- A:hover {text-decoration: none; color: #339900; font-weight:bold; font-size:14pt;}
-
- .changeFile { background-color: yellow; color: #FF0000; text-align: center; }
- .property { color : #0000a0; }
- .methodname { color : #0000a0; }
- .methodparam { color: green; }
- .titre {color: #FF0000;}
- .infoplus {color: black;}
- .constant {color: gray; }
- PRE { font-size: 8pt; }
- .italic { font-style: italic; }
-
- TABLE { width:90%; margin-left:1.9pt; border: none; border-collapse:collapse; }
- TH, TD { border:solid red 1.0pt; padding:0cm 5.4pt 0cm 5.4pt; }
- .TABLE { width:100%; text-align:center;} // margin-left: auto; margin-right: auto; width : 50%
-
- </style>
- CSS;
-
- $this->BEGIN =
- <<<BEGIN
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <HTML>
- <HEAD>
- <TITLE>DEBUG</TITLE>
- <meta name='author' content='OriginalCompo' />
- <meta name='owner' content='Jean-Pierre Aguado' />
- <meta name='Debug unit for PHP 5' content='Debug unit for PHP 5' />
- <meta name='keywords' content='PHP5, Debug' />
- <META http-equiv="Cache-Control" content="no-cache">
- <META http-equiv="Pragma" content="no-cache">
- <META http-equiv="Expires" content="0">
-
- {$JS}
-
- {$CSS}
- </HEAD>
- <BODY>
- BEGIN;
-
- $this->END_XML_SER =
- <<<END_XMLSER
- <a name="here"></a>
- <table class=TABLE><tr>
- <td width=50%><a target="_self" href="reload.php">Refresh</a></td>
- <td width=50%><a target="_self" href="clear.php">Clear</a></td>
- </tr></table>
- </BODY>
- </HTML>
- END_XMLSER;
-
- $this->END =
- <<<END
- </BODY>
- </HTML>
- END;
-
- $newXMLLine = chr(10);
- $this->original4xml = array('<' , '>' , '&' );
- $this->_replace4xml = array($newXMLLine.'{i,n,f', 's,u,p}', $newXMLLine.'{e,t]');
- $this->oldchar4xml = ',';
- $this->newchar4xml = ';';
- }
-
- // ----------------------------------------------------------------------------------------------
-
- private $xmlfile = '';
- private $serfile = '';
- private $onefile = '';
-
- // ----------------------------------------------------------------------------------------------
-
- static public function getPath()
- {
- $d = new Debug();
- $reflectClass = new ReflectionClass($d);
- unset($d);
- return dirname($reflectClass->getFileName());
- }
-
- // ----------------------------------------------------------------------------------------------
-
- private function setFiles($mode = '')
- {
- if ($mode=='')
- {
- $this->xmlfile = '';
- $this->serfile = '';
- $this->onefile = '';
- }
- else
- {
- $chemin = Debug::getPath();
-
- if ($mode=='XML')
- {
- $this->onefile = $chemin.'/'.Debug::ONETRACE_HTML;
- $this->serfile = '';
- $this->xmlfile = $chemin.'/'.Debug::ONETRACE_XML;
- }
- elseif ($mode='SER')
- {
- $this->onefile = $chemin.'/'.Debug::ONETRACE_HTML;
- $this->serfile = $chemin.'/'.Debug::ONETRACE_SER;
- $this->xmlfile = '';
- }
- }
- }
-
- /** ---------------------------------------------------------------------------------------------
- Clear efface les traces cumulatives (dans le cas d'une trace unique)
- */
-
- public function clear()
- {
- $this->trace = array(); // on efface le tableau
- $this->inittrace = array(); // on efface le tableau
- $this->nbRaccourcis=0;
- $this->update_debughtml(true);
- }
-
- /** =============================================================================================
- Une seule instante de Debug peut exister à la fois.
- Le design pattern SINGLETON est utilisé dans cet objectif
- Pour travailler sur l'instance de Debug à partir de plusieurs scripts PHP, il faut donc chercher
- l'instance dans chaque script (avec l'espace de nom) ...
- $instanceDebug = originalcompo\Debug::getInstance();
- ... et travailler sur $instanceDebug
- */
- private static $_singleton;
-
- private function __construct()
- {
- $this->init_const();
- }
-
- /** ---------------------------------------------------------------------------------------------
- Il y a 3 appels possibles de getInstance
- Debug::getInstance();
- --> chaque trace est générée dans un fichier indépendant.
- Ex: si la page web toto.php est en cours de débogage, alors la trace sera sur
- toto.php.debug.html
- Debug::getInstance('SER');
- --> les traces sont toutes générées dans un unique fichier trace.html se trouvant au même endroit
- que ce fichier (contenant la classe originalcompo\Debug
- Pour cela, un cache contenant la classe serialisée est stockée sur le disque dur
- Debug::getInstance('XML');
- --> les traces sont toutes générées dans un unique fichier trace.html se trouvant au même endroit
- que ce fichier (contenant la classe originalcompo\Debug
- Pour cela, un cache au format XML contenant une partie du code HTML de la page trace.html est
- stokée sur le disque dur
-
- Note: il n'y a aucune différence à l'exécution entre getInstance('SER') et getInstance('XML').
- Par contre il est IMPERATIF de TOUJOURS garder le même choix.
- Si vous utilisez 'SER' dans un fichier, puis 'XML' pour déboguer un autre, vous n'obtiendrez pas
- le résultat désiré...
- */
- public static function getInstance($mode = '') // XML, SER,
- {
- if (is_null(self::$_singleton))
- {
- if ($mode=='')
- {
- self::$_singleton = new Debug();
- self::$_singleton->setFiles();
- }
- else
- {
- $chemin = Debug::getPath();
-
- if ($mode == 'SER')
- {
- self::$_singleton = self::unserializeMe();
- self::$_singleton->setFiles('SER');
- }
- elseif ($mode == 'XML')
- {
- self::$_singleton = new Debug();
- self::$_singleton->setFiles('XML');
-
- try {
- self::$_singleton->LoadXML();
- }
- catch (Exception $e) {
- }
- }
-
- self::$_singleton->trace[] = '<p class=changeFile>'
- .date("Y/m/d H:i:s : ", time())
- .$_SERVER['PHP_SELF']
- .'</p>';
- }
- }
-
- return self::$_singleton;
- }
-
- private function __clone()
- {
- // Lorsqu'un objet est cloné, PHP 5 effectue une copie superficielle
- // de toutes les propriétés de l'objet. Toutes les propriétés qui
- // sont des références à d'autres variables demeureront des références.
- }
-
- /** ---------------------------------------------------------------------------------------------
- */
- private function serializeMe()
- {
- $s = serialize(Debug::getInstance());
- file_put_contents($this->serfile, $s);
- }
-
- // ..............................................................................................
-
- private static function unserializeMe()
- {
- $fichier = Debug::getPath() . '/' . Debug::ONETRACE_SER;
-
- return (file_exists($fichier) ? unserialize(file_get_contents($fichier)) : new Debug());
- }
-
- // ==============================================================================================
-
- private function describe_variable($titre, $toprint)
- {
- // Le titre est inclus dans une balise qui doit être interprétée, alors que la valeur doit être
- // affichée en brut (balises html non interprétées)
- $paramTitre = ($titre=='') ? '?' : htmlentities($titre, ENT_QUOTES, Debug::ENCODING, true);
-
- if (isset($toprint))
- {
- $titre_begin = '<span class=titre>';
- $titre_end = '</span>';
-
- if ($titre=='') {
- $titre_begin = $titre_begin.'<span class=italic>';
- $titre_end = '</span>'.$titre_end;
- }
-
- if (is_object($toprint) || is_array($toprint))
- {
- // Mise en place d'un lien javascript pour déclencher la fonction réduire/développer ...
- // '<a href="JavaScript: dhtml_Click($param2_a_js, $param1_a_js); ...'
- // ... et de (l'équivalent) à l'appel automatique de ce lien au démarrage
- // '<script language="JavaScript"> dhtml_Click($param2_js, $param1_js); ...'
-
- // $param1_(a_)js, $param2_(a_)js vont générer des chaines de caractères qui ne doivent
- // pas avoir de retour à la ligne, sinon le code javascript ne fonctionnera pas
- $rc = array(chr(13).chr(10), chr(10));
- $br = array('<br />', '<br />');
-
- $nb = ++$this->nbRaccourcis;
-
- $param1_js = $paramTitre;
- $param1_a_js = htmlspecialchars($paramTitre, ENT_QUOTES, Debug::ENCODING, true);
-
- $param1_js = str_replace($rc, $br, $param1_js );
- $param1_a_js = str_replace($rc, $br, $param1_a_js);
-
- $infoplus = is_object($toprint) ? ' (class ' .get_class($toprint).')'
- : ' (array ' .count($toprint).' elements)';
-
- $param1_js = '\''.$titre_begin.$param1_js .$titre_end.' <span class=infoplus>'.$infoplus.'</span>\'';
- $param1_a_js = '\''.$titre_begin.$param1_a_js.$titre_end.' <span class=infoplus>'.$infoplus.'</span>\'';
-
- // GESTION DU DETAIL (partie qui sera visible si -, invisible si +)
- $paramDetails = var_export($toprint, TRUE);
- $paramDetails = htmlentities($paramDetails, ENT_QUOTES, Debug::ENCODING, true);
-
- $param2_js = $paramDetails;
- $param2_a_js = htmlspecialchars($paramDetails, ENT_QUOTES, Debug::ENCODING, true);
-
- $param2_js = '\''.str_replace($rc, $br, $param2_js ).'\'';
- $param2_a_js = '\''.str_replace($rc, $br, $param2_a_js).'\'';
-
- // création de la balise avec appel du js
- $ret = '<a class=local href="JavaScript: dhtml_Click('.$param2_a_js.', '.$param1_a_js.', '.$nb.')">'
- .'<span id=PLUS'.$nb.'>'.($this->collapsed ? "-" : "+").'</span></a>'
- .'<span id=INFO'.$nb.'></span>'.PHP_EOL;
-
- // création et stockage de l'appel direct du js
- $this->inittrace[] = 'dhtml_Click('.$param2_js.', '.$param1_js.', '.$nb.');';
- }
- else {
- if (is_bool($toprint))
- $ret = $titre_begin.$paramTitre.' (bool) = '.$titre_end.($toprint==true ? 'true' : 'false');
- elseif (is_string($toprint))
- $ret = $titre_begin.$paramTitre.' = '.$titre_end
- .(htmlentities($toprint, ENT_QUOTES, Debug::ENCODING, false));
- else // numérique
- $ret = $titre_begin.$paramTitre.' = '.$titre_end.$toprint;
- }
- }
- else
- {
- $ret = $paramTitre.' variable unset !';
- }
-
- if ($this->withTime) $ret = date("H:i:s . ", time()).$ret;
-
- return $ret;
- }
-
- /** .............................................................................................
- Fonction à utiliser pour tracer une variable $name représente un commentaire à associer à la
- variable (en général, rappeler son nom !)
- */
- public function print_variable($name, $toprint)
- {
- $this->trace[] = $this->describe_variable($name, $toprint);
- $this->update_debughtml();
- }
-
- /** .............................................................................................
- Fonction à utiliser pour regrouper la trace de plusieurs variables
- Exemple d'utilisation:
- - print_variables('Etape 1', array('$a', '$b', '$c propriété x'), array($a, $b, $c->x));
- */
- public function print_variables($comment, array $names, array $variables)
- {
- $error = (!is_array($variables)) || (!is_array($names)) || (count($variables)==0);
-
- if (!$error) $error = count($variables)!=count($names);
-
- if ($error)
- $ret = '<span class=constant>Error calling : '.__METHOD__.'<br>File : '.__FILE__.'<br>Line : '.__LINE__.'</span>';
- else {
- $param2_js = '';
- $nb = ++$this->nbRaccourcis;
-
- for ($i=0; $i <count($variables); $i++)
- {
- $arg = $variables[$i];
- $tab = $this->describe_variable($names[$i], $arg);
- $param2_js .= '<li>'.$tab.'</li>';
- }
-
- $ret = '<span class=titre>'
- .htmlentities($comment, ENT_QUOTES, Debug::ENCODING, true)
- .' : </span> '
- .'<table><tr><td><PRE><ul>'.$param2_js.'</ul></PRE></td></tr></table><br />'.PHP_EOL;
- }
-
- $this->trace[] = $ret;
- $this->update_debughtml();
- }
-
- /** ---------------------------------------------------------------------------------------------
- Fonction à utiliser pour afficher un commentaire
- */
- public function print_constant($toprint)
- {
- $this->trace[] = htmlentities('<span class=constant>'
- .($this->withTime ? date("H:i:s : ", time()) : '')
- .$toprint.'</span>'
- , ENT_QUOTES, Debug::ENCODING, true);
- $this->update_debughtml();
- }
-
- /** ---------------------------------------------------------------------------------------------
- Possibilité d'afficher la structure d'une classe à partir d'une instance de celle-ci
- */
- public function reflexion($toAnalyse)
- {
- if (is_object($toAnalyse))
- {
- $reflectClass = new ReflectionClass($toAnalyse);
- $className = $reflectClass->getName(); // get_class($toAnalyse);
- $reflectParentClass = $reflectClass->getParentClass();
- $heriteDe = $reflectParentClass != null ? ' extends '.$reflectParentClass->getName() : '';
-
- $lesInterfaces = $reflectClass->getInterfaceNames();
- $interfaces = count($lesInterfaces)==0 ? '' : ' implements '.implode(', ', $lesInterfaces);
-
- $info_class = '<span class=titre>class '.$className.'</span>'.$heriteDe.$interfaces.'<br />'.PHP_EOL
- .$reflectClass->getFileName().'<br />'.PHP_EOL
- .'Lines: '.$reflectClass->getStartLine(). ' - ' .$reflectClass->getEndLine().'<br />'.PHP_EOL;
-
- $lesMethodes = $reflectClass->getMethods();
- $functions = array();
-
- foreach($lesMethodes as $fct) {
- $c = '';
- $reflectMethod = new ReflectionMethod($className, $fct->name);
-
- if ($reflectMethod->IsPublic())
- $c = 'public ';
- elseif ($reflectMethod->IsPrivate())
- $c = 'private ';
- elseif ($reflectMethod->IsProtected())
- $c = 'protected ';
-
- if ($reflectMethod->IsStatic()) $c = 'static '.$c;
- if ($reflectMethod->IsAbstract()) $c = 'abstract '.$c;
- if ($reflectMethod->IsFinal()) $c = 'final '.$c;
-
- $c = $c.'<span class=methodname>'.$fct->name.'</span>';
-
- if ($reflectMethod->getNumberOfParameters()==0)
- $c .= '()';
- else
- {
- $params = $reflectMethod->getParameters();
- $args = array();
- $i = 0;
- $c = $c . '(';
-
- foreach ($params as $param) {
- $arg = '';
- $parametre = '<span class=methodparam>'.$param->getName().'</span>';
-
- if ($param->isPassedByReference()) $arg = '&';
-
- if ($param->isOptional()) {
- if ($param->isArray())
- $arg .= '[$' .$parametre. ' (array) ]';
- else{
- $val = $param->getDefaultValue();
- $arg = '[$' .$parametre. ' = ' .($val==null ? 'null' : $val). ']';
- }
- }
- else
- $arg .= '$'.$parametre;
-
- $args[] = $arg;
- }
-
- $c .= implode(', ', $args) . ')';
- }
-
- $functions[] = $c;
- }
-
- $info_methods = implode('<br />'.PHP_EOL, $functions);
- $lesProprietes = $reflectClass->getProperties();
- $proprietes = array();
-
- foreach($lesProprietes as $pro) {
- $c = '';
-
- if ($pro->IsPublic())
- $c = 'public ';
- elseif ($pro->IsPrivate())
- $c = 'private ';
- elseif ($pro->IsProtected())
- $c = 'protected ';
-
- if ($pro->IsStatic()) $c = 'static '.$c;
-
- $c .= '$<span class=property>'.$pro->name.'</span>';
-
- $proprietes[] = $c;
- }
-
- $info_properties = implode('<br />'.PHP_EOL, $proprietes);
-
- $lesConstantes = $reflectClass->getConstants();
- $constants = array();
-
- foreach($lesConstantes as $key=>$value)
- $constants[] = '<span class=property>'.$key.'</span> = '.htmlspecialchars($value, ENT_QUOTES, Debug::ENCODING, true);
-
- $info_constants = implode('<br />'.PHP_EOL, $constants);
- $this->print_constant($info_class.'<hr /><span class=infoplus>Methods :</span><br/>'
- .$info_methods.'<hr /><span class=infoplus>Properties :</span><br/>'
- .$info_properties.'<hr /><span class=infoplus>Constants :</span><br/>'
- .$info_constants.'<hr />');
- }
- else {
- $this->print_constant('<span class=infoplus>Error:</span> The variable tested is not an instance of a class<br>'.PHP_EOL);
- }
- }
-
- /** ---------------------------------------------------------------------------------------------
- Fonction écrivant le fichier de débugage
- */
-
- private function update_debughtml($all = false)
- {
- if (!$this->updateTrace) return;
-
- if ($this->xmlfile == '' && $this->serfile == '')
- $nom = basename($_SERVER['PHP_SELF'].Debug::EXT);
- else {
- if ($all || $this->xmlfile != '') {
- $this->SaveToXml();
- $nom = $this->onefile;
- }
-
- if ($all || $this->serfile != '') {
- $this->serializeMe();
- $nom = $this->onefile;
- }
- }
-
- $resultat = fopen($nom, 'w+');
-
- if (!$resultat) {
- echo '<p>DEBUG IMPOSSIBLE</p>'.PHP_EOL;
- exit;
- }
- else
- {
- fputs($resultat, $this->BEGIN);
- fputs($resultat, PHP_EOL.'<ul>'.PHP_EOL);
- $inf_ETlt = '<'; //$inf_ETlt2 = '&lt;';
-
- for ($i=0; $i < count($this->trace); $i++) {
- $trace = $this->trace[$i];
-
- if (substr($trace, 0, strlen($inf_ETlt))==$inf_ETlt){
- $trace = html_entity_decode($trace, ENT_QUOTES, Debug::ENCODING);
- }
-
- fputs($resultat, '<li>'.$trace.'</li>'); // .PHP_EOL
- }
-
- fputs($resultat, '</ul>'.PHP_EOL);
-
- fputs($resultat, PHP_EOL.'<script language="JavaScript">'.PHP_EOL.PHP_EOL);
-
- for ($i=0; $i < count($this->inittrace); $i++) {
- $trace = $this->inittrace[$i];
-
- if (substr($trace, 0, strlen($inf_ETlt))==$inf_ETlt){
- $trace = html_entity_decode($trace, ENT_QUOTES, Debug::ENCODING);
- }
-
- fputs($resultat, $trace.PHP_EOL.PHP_EOL);
- }
-
- fputs($resultat, '</script>'.PHP_EOL);
-
- fputs($resultat, (($this->xmlfile == '') && ($this->serfile == '')) ? $this->END : $this->END_XML_SER);
- fclose($resultat);
- }
- }
-
- /** ---------------------------------------------------------------------------------------------
- Afin de garder plusieurs traces successives dans un même fichier (après changement de page ou
- bien rechargement d'une même page), un fichier XML peut être utilisé.
-
- /* STRUCTURE DU FICHIER XML UTILISE
- <?xml version="1.0"?>
- <rootelement>
- <param symbol="<">
- <equivalent>{i;n;f</equivalent>
- </param>
-
- <trace position="1">
- <print>...</print>
- </trace>
- ...
- <inittrace position="1">
- <print>...</print>
- </inittrace>
- ...
- </rootelement>
- */
-
- /** ---------------------------------------------------------------------------------------------
- SaveToXML(): sauvegarde les infos permettant de re-générer le fichier html de trace.
- Le but est de remplacer les balises perturbantes pour XML par des balises personnelles neutres
- (qui ne seront pas interprétées par XML ou HTML)
- Pour cela, il faut remplacer les caractères < > et & par des chaines de caractères de notre choix
- AVANT de construire le fichier XML, et faire l'inverse lorsqu'on récupère le XML.
- Ces chaines de correspondances pouvant se retrouver dans le texte à afficher, il faut vérifier si
- elles n'y sont pas et en choisir éventuellement une autre.
- Ex: '<' est remplacé par '{i;n;f', mais si '{i;n;f' est trouvé, on utilisera '{i;n;f1', sinon
- '{i;n;f2' etc...
- La vérification est activée par défaut mais peut être désactivée ($checksymbols = false;)
-
- Détail: Si '{i;n;f' est une chaine de codage stockée dans une propriété de l'instance $f de la
- classe Debug, $f->print_variable('$f', $f) va devoir utiliser '{i;n;f1' pour générer
- le XML. Lors d'un deuxième appel, ce sera '{i;n;f2'...
- C'est dans l'unique but (!!) d'utiliser la classe originalcompo\Debug avec elle même
- sans modifier inutilement la chaine de remplacement que celle-ci n'est pas stockée telle
- qu'elle dans la classe.
- La propriété $_replace4xml contient la valeur '{i,n,f', mais la chaine de remplacement
- est recalculée en '{i;n;f'. De même pour les autres valeurs 's,u,p}' et '{e,t]'
- */
- public function SaveToXML()
- {
- $xmlBEGIN = '<?xml version="1.0" encoding="'.Debug::ENCODING.'"?><rootelement>';
- $xmlEND = '</rootelement>';
-
- // Création d'un document XML "vide"
- $xmltext = $xmlBEGIN.$xmlEND;
-
- // Construction du tableau $replace4xml des chaines de substitutions à < > &
- // (basé sur $_replace4xml)
- $replace4xml = str_replace($this->oldchar4xml, $this->newchar4xml, $this->_replace4xml);
- $r = $replace4xml;
- $i=0;
-
- // Parcours de toutes les chaines qu'il va falloir modifier, et vérification
- // que les chaines de remplacement ne sont pas déjà présentes dans ces chaines
- if ($this->checksymbols)
- do
- {
- $retester = false;
-
- foreach($this->trace as $trace)
- {
- foreach ($replace4xml as $ri)
- {
- $retester = !(stripos($trace, $ri) === false);
-
- if ($retester) break 2;
- }
- }
-
- if (!$retester) {
- foreach($this->inittrace as $trace)
- {
- foreach ($replace4xml as $ri)
- {
- $retester = !(stripos($trace, $ri) === false);
-
- if ($retester) break 2;
- }
- }
- }
-
- if ($retester) {
- $i++;
-
- for ($j = 0; $j<count($r); $j++)
- $replace4xml[$j] = $r[$j].$i;
- }
- }
- while($retester);
-
- $this->DOM ? $this->DOM_SaveXML ($xmltext, $replace4xml)
- : $this->simple_SaveXML($xmltext, $replace4xml);
- }
-
- // --------------------------------------------------------------------------
-
- public function simple_SaveXML($xmltext, $replace4xml)
- {
- $XMLelements = new SimpleXMLElement($xmltext, NULL, false);
- //
-
- for ($i=0; $i<count($replace4xml); $i++) {
- $newXMLelement = $XMLelements->addChild('param');
- $newXMLelement->addAttribute('symbol', $this->original4xml[$i]);
- $newXMLelement->addChild('equivalent', $replace4xml[$i]);
- //
- //
- }
-
- foreach($this->trace as $trace) {
- $i++;
- $trace = str_replace($this->original4xml, $replace4xml, $trace);
-
- $newXMLelement = $XMLelements->addChild('trace');
- $newXMLelement->addAttribute('position', $i);
- $newXMLelement->addChild('print', $trace);
- //
- //
- }
-
- $i=0;
-
- foreach($this->inittrace as $inittrace) {
- $i++;
- $inittrace = str_replace($this->original4xml, $replace4xml, $inittrace);
-
- $newXMLelement = $XMLelements->addChild('inittrace');
- $newXMLelement->addAttribute('position', $i);
- $newXMLelement->addChild('print', $inittrace);
- //
- //
- }
-
- $resultat = fopen($this->xmlfile, 'w+');
- fputs($resultat, $XMLelements->asXML());
- fclose($resultat);
- }
-
- // --------------------------------------------------------------------------
-
- public function DOM_SaveXML($xmltext, $replace4xml)
- {
- $XMLelements = new DomDocument();
- $XMLelements->loadXML($xmltext);
-
- for ($i=0; $i<count($replace4xml); $i++) {
- $newXMLelement = $XMLelements->createElement('param');
- $newXMLelement2 = $XMLelements->createElement('equivalent', $replace4xml[$i]);
- $newXMLelement->SetAttribute('symbol', $this->original4xml[$i]);
- $newXMLelement->appendChild($newXMLelement2);
- $XMLelements->documentElement->appendChild($newXMLelement);
- }
-
- foreach($this->trace as $trace) {
- $i++;
- $trace = str_replace($this->original4xml, $replace4xml, $trace);
-
- $newXMLelement = $XMLelements->createElement('trace');
- $newXMLelement->SetAttribute('position', $i);
- $newXMLelement2 = $XMLelements->createElement('print', $trace);
- $newXMLelement->appendChild($newXMLelement2);
- $XMLelements->documentElement->appendChild($newXMLelement);
- }
-
- $i=0;
-
- foreach($this->inittrace as $inittrace) {
- $i++;
- $inittrace = str_replace($this->original4xml, $replace4xml, $inittrace);
-
- $newXMLelement = $XMLelements->createElement('inittrace');
- $newXMLelement->SetAttribute('position', $i);
- $newXMLelement2 = $XMLelements->createElement('print', $inittrace);
- $newXMLelement->appendChild($newXMLelement2);
- $XMLelements->documentElement->appendChild($newXMLelement);
- }
-
- $XMLelements->save($this->xmlfile);
- //
- //
- }
-
- // ==============================================================================================
-
- public function LoadXML()
- {
- if (!file_exists($this->xmlfile)) return;
-
- $this->trace = array(); //array_splice($this->trace, 0); // on efface le tableau
- $this->inittrace = array(); // on efface le tableau
- $this->nbRaccourcis=0;
-
- $this->DOM ? $this->DOM_LoadXML()
- : $this->simple_LoadXML();
- }
-
- // ----------------------------------------------------------------------------------------------
-
- function simple_LoadXML()
- {
- $replace4xml = array();
- $XMLelements = new SimpleXMLElement($this->xmlfile, NULL, true); // true : path, false : string
- //
- // ALTERNATIVES
- // 1) $xmlstr = file_get_contents($xmlfile);
- // $XMLelements = simplexml_load_string($xmlstr);
- // 2) $XMLelements = simplexml_load_file($xmlfile);
- // 3) $xmlstr = file_get_contents($xmlfile);
- // $XMLelements = new SimpleXMLElement($xmlstr);
-
- $results = $XMLelements->xpath('/rootelement/param');
- //
-
- foreach ($results as $noeud)
- {
- $position = '';
-
- foreach ($noeud->attributes() as $attr)
- if ($attr->getName()=='symbol') $position = $attr;
-
- if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
-
- foreach ($noeud->children() as $subnoeud)
- {
- if ($subnoeud->getName()=='equivalent') {
- for ($i=0; $i<count($this->original4xml); $i++)
- {
- if ($this->original4xml[$i]==$attr)
- {
- $replace4xml[$i] = $subnoeud;
- break;
- }
- }
- }
- }
- }
-
- $results = $XMLelements->xpath('/rootelement/trace');
- foreach ($results as $noeud)
- {
- $position = -1;
-
- foreach ($noeud->attributes() as $attr)
- if ($attr->getName()=='position') $position = $attr;
-
- if ($position==-1) throw new Exception('Mauvaise structure du fichier XML');
-
- foreach ($noeud->children() as $subnoeud)
- {
- if ($subnoeud->getName()=='print') {
- $this->trace[] = str_replace($replace4xml, $this->original4xml, $subnoeud);
- $this->nbRaccourcis++;
- }
- }
- }
-
- $results = $XMLelements->xpath('/rootelement/inittrace');
- foreach ($results as $noeud)
- {
- $position = -1;
-
- foreach ($noeud->attributes() as $attr)
- if ($attr->getName()=='position') $position = $attr;
-
- if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
-
- foreach ($noeud->children() as $subnoeud)
- {
- if ($subnoeud->getName()=='print') {
- $this->inittrace[] = str_replace($replace4xml, $this->original4xml, $subnoeud);
- $this->nbRaccourcis++;
- }
- }
- }
- }
-
- // ----------------------------------------------------------------------------------------------
- // Fonctions DOM interressantes: (file, string)
- // DomDocument::loadHtmlFile() , DomDocument::loadHTML()
- // DomDocument::save() ,
- // DomDocument:saveHTMLFile() , DomDocument::saveHTML(), DomDocument::saveXML()
-
- /* RAPPEL : STRUCTURE DU FICHIER XML UTILISE
- <?xml version="1.0"?>
- <rootelement>
- <param symbol="<">
- <equivalent>{i;n;f</equivalent>
- </param>
-
- <trace position="1">
- <print>...</print>
- </trace>
- ...
- <inittrace position="1">
- <print>...</print>
- </inittrace>
- ...
- </rootelement>
- */
-
- // ----------------------------------------------------------------------------------------------
-
- public function DOM_LoadXML()
- {
- $replace4xml = array();
- $XMLelements = new DomDocument();
- $XMLelements->load($this->xmlfile);
- // ALTERNATIVES
- // 1) $XMLelements = new DomDocument();
- // $XMLelements->C
- //
- //
- //
-
- $xpath = new DomXPath($XMLelements);
- $results = $xpath->query('//rootelement/param');
-
- foreach ($results as $noeud)
- {
- $position = '';
-
- foreach ($noeud->attributes as $attr)
- if ($attr->nodeName=='symbol') $position = $attr->nodeValue;
-
- if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
-
- foreach ($noeud->childNodes as $subnoeud)
- {
- if ($subnoeud->nodeName=='equivalent') {
- for ($i=0; $i<count($this->original4xml); $i++)
- {
- if ($this->original4xml[$i]==$attr->nodeValue)
- {
- $replace4xml[$i] = $subnoeud->nodeValue;
- break;
- }
- }
- }
- }
- }
-
- $results = $xpath->query('//rootelement/trace');
- foreach ($results as $noeud)
- {
- $position = -1;
-
- foreach ($noeud->attributes as $attr)
- if ($attr->nodeName=='position') $position = $attr->nodeValue;
-
- if ($position==-1) throw new Exception('Mauvaise structure du fichier XML');
-
- foreach ($noeud->childNodes as $subnoeud)
- {
- if ($subnoeud->nodeName=='print') {
- $this->trace[] = str_replace($replace4xml, $this->original4xml, $subnoeud->nodeValue);
- $this->nbRaccourcis++;
- }
- }
- }
-
- $results = $xpath->query('//rootelement/inittrace');
- foreach ($results as $noeud)
- {
- $position = -1;
-
- foreach ($noeud->attributes as $attr)
- if ($attr->nodeName=='position') $position = $attr->nodeValue;
-
- if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
-
- foreach ($noeud->childNodes as $subnoeud)
- {
- if ($subnoeud->nodeName=='print') {
- $this->inittrace[] = str_replace($replace4xml, $this->original4xml, $subnoeud->nodeValue);
- $this->nbRaccourcis++;
- }
- }
- }
- }
-
- // ================================================================================================
- }
-
- ?>
<?php
namespace originalcompo;
/** -----------------------------------------------------------------------------------------------
Ce code a été écrit dans un but pratique (aider au débogage de PHP) mais aussi didactique:
- il existe deux méthodes pour sauver la trace dans un seul fichier: en travaillant à partir d'une
sauvegarde XML ou d'une sauvegarde de l'objet sérialisé;
- il existe deux méthodes dans la version XML: en travaillant avec DOM ou avec l'objet
SimpleXMLElement
A chaque fois, l'utilisation de l'une ou l'autre des méthodes amène au même résultat.
Cela m'a juste permis de tester plusieurs manière de faire !
---------------------------------------------------------------------------------------------------
La classe Debug est une classe d'aide au débugage de code PHP permettant l'affichage de variables
PHP intermédiaires.
Sa particularité est que l'affichage se fait sur une fenêtre HTML à part, qui est créée sur le
serveur (où se trouve ce script).
Avantages: si on travaille sur une page web, l'affichage de celui-ci n'est pas polué, les valeurs
sont toujours visibles (plus de problème avec la mise en page css au moment ou on écrit la trace...)
Il y a deux versions possibles:
- chaque page html est tracée indépendemment: toto.php --> toto.php.Debug.html
- une trace unique cumulant les traces: toto.php, tata.php --> trace.html
---------------------------------------------------------------------------------------------------
2010/08/14 :
- Pas d'écriture dans le fichier si $updateTrace est à false
- Possibilité d'afficher la structure d'une classe à partir d'une instance de celle-ci
2010/08/15 :
- Affichage de la classe parente ainsi que des interfaces utilisées
- Interdiction du clonage
- Notation HEREDOC
2010/08/16 :
- Rajout d'un espace de nom
(la classe ocDEBUG a été renommé en Debug, plus standard, l'espace de nom permettant de garantir
l'unicité de la classe)
2010/08/17 :
- Corrections de l'interprétation des span dans certains cas (fonction "describe_variable")
2010/08/19 :
- Possibilité de générer les traces de plusieurs fichiers php dans un seul fichier
(refresh y compris) via la sauvegarde dans un fichier xml des résultats intermédiaires
2010/08/24 :
- rajout de deux liens: Clear (pour vider la trace) et Refresh (équivalent au F5 du navigateur)
- Possibilité de générer les traces de plusieurs fichiers php dans un seul fichier
(refresh y compris) via la sauvegarde de l'objet serialisé
*/
/** -----------------------------------------------------------------------------------------------
Le fait de définir un espace de nom fait que les classes/fonctions/constantes sont recherchées dans
cet espace.
- Pour les fonctions et constantes, PHP va aller les chercher dans l'espace global s'il ne peut les
trouver dans l'espace de noms courant.
- Les noms de classes sont toujours résolus avec l'espace de noms courant.
Il faut donc ici préciser que les classes ReflectionClass et ReflectionMethod sont dans l'espace de
nom global "\".
On peut le faire en utilisant directement l'espace de nom lors de l'utilisation de la classe...
exemple: $reflectMethod = new \ReflectionMethod($className, $fct->name);
...ou bien en utilisant un alias comme cela est fait dans le code ("use")
*/
use \ReflectionClass as ReflectionClass, // \a\b\c as c; équivalent à \a\b\c;
\ReflectionMethod,
\SimpleXMLElement,
\DomDocument, \DomXPath;
class Debug {
const ONETRACE_XML = 'trace.xml'; // nom du fichier de sortie si trace unique
const ONETRACE_SER = 'trace.ser'; // nom du fichier de sortie si trace unique
const ONETRACE_HTML = 'trace.html'; // nom du fichier de sortie si trace unique
const EXT = '.Debug.html'; // extension du fichier de sortie si "une trace par fichier"
const ENCODING = 'ISO-8859-1'; // const ENCODING = 'UTF-8';
private $BEGIN; // "constante"
private $END; // "constante"
private $END_XML_SER; // "constante"
private $nbRaccourcis = 0;
private $trace = array();
private $inittrace = array(); // sert au chargement de la page
// Il est possible d'afficher l'heure d'écriture des variables
public $withTime = false;
// voir SaveToXML() :
public $checksymbols = true;
private $original4xml = array();
private $_replace4xml = array();
private $oldchar4xml;
private $newchar4xml;
// ----------------------------------------------------------------------------------------------
private $updateTrace = true;
public function get_UpdateTrace() {
return $this->updateTrace;
}
public function set_UpdateTrace($new) {
if ($new != $this->updateTrace) {
$this->updateTrace = $new;
if ($this->updateTrace) $this->update_debughtml();
}
}
/** ---------------------------------------------------------------------------------------------
Il y a 2 types d'informations qui ont un affichage particulier: les objets et les tableaux.
Ces informations pouvant occuper beaucoup de place, pour faciliter/alléger le parcours de la
page de débugage, on peut choisir de réduire ou développer ces informations, directement sur
la page HTML, en appuyant respectivement sur le "-" ou le "+" qui apparait à côté de ce type
de variables.
- si un '+' est affiché, l'information est minimisé
- si un '-' est affiché, toute l'information est affichée
La propriété collapsed permet de choisir l'affichage par défaut au démarrage: true pour tout
réduire, false pour tout afficher
NOTES: la fonctionnalité réduire/développer est gérée via javascript.
Des chaines de caractères sont générées par PHP et passées en paramètre d'une fonction javascript.
Le javascript pouvant être interprété différemment selon les navigateurs, il est cnseillé de
laisser $collapsed à true par défaut, certains d'entre eux pouvant ne pas réussir à interpréter
certaines variables complexes.
Par exemple: si $f est une instance de la classe de débugage, le script généré pour
réduire/développer le code associée à $f->print_variable($f) fonctionne bien sur Mozilla Firefox
mais pas sur IE8.
($f contient des propriétés chaines de caractère avec code HTML et fonctions javascript!)
*/
public $collapsed = false;
/** ---------------------------------------------------------------------------------------------
Si on choisit XML pour gérer la trace unique
Debug::getInstance('XML');
ici, on décide si on utilise DOM ou SimpleXMLElement pour générer le XML
(choix transparent puisque sans conséquence sur le résultat)
*/
private $DOM = false;
//private $DOM = true;
/** ---------------------------------------------------------------------------------------------
Définition des constantes :
Le code CSS et JS était initialement externalisé dans 2 fichiers, mais on a alors un problème
d'accès à définir si les différents fichiers à débuguer ne se trouvent pas sous le même chemin
(répertoire). Ces codes sont donc directement inclus dans le fichier de trace généré.
*/
public function init_const()
{
$JS =
<<<JS
<SCRIPT type='text/javascript' language='JavaScript1.2'>
function dhtml_Click(INFO, VARIABLE, NUMERO)
{
INFO_ID = "INFO"+NUMERO.toString();
PLUS_ID = "PLUS"+NUMERO.toString();
if (document.getElementById(PLUS_ID).innerHTML == "+") {
document.getElementById(PLUS_ID).innerHTML = "-";
document.getElementById(INFO_ID).innerHTML = VARIABLE
+"<br /><table><tr><td><PRE>"+INFO+"</PRE></td></tr></table>";
}
else {
document.getElementById(PLUS_ID).innerHTML = "+";
document.getElementById(INFO_ID).innerHTML = VARIABLE;
}
}
</SCRIPT>
JS;
$CSS =
<<<CSS
<style type="text/css">
TABLE, BODY { color: #0000a0; background-color: #ffffff;
font-family:sans-serif, arial, times, helvetica; font-size: 10pt;}
A:after {content: " "; }
A:before {content: " "; }
A:link {text-decoration: none; color: #FF0000; font-weight:bold; font-size:14pt;}
A:visited {text-decoration: none; color: #FF0000; font-weight:bold; font-size:14pt;}
A:active {text-decoration: none; color: #FF0000; font-weight:bold; font-size:14pt;}
A:hover {text-decoration: none; color: #339900; font-weight:bold; font-size:14pt;}
.changeFile { background-color: yellow; color: #FF0000; text-align: center; }
.property { color : #0000a0; }
.methodname { color : #0000a0; }
.methodparam { color: green; }
.titre {color: #FF0000;}
.infoplus {color: black;}
.constant {color: gray; }
PRE { font-size: 8pt; }
.italic { font-style: italic; }
TABLE { width:90%; margin-left:1.9pt; border: none; border-collapse:collapse; }
TH, TD { border:solid red 1.0pt; padding:0cm 5.4pt 0cm 5.4pt; }
.TABLE { width:100%; text-align:center;} // margin-left: auto; margin-right: auto; width : 50%
</style>
CSS;
$this->BEGIN =
<<<BEGIN
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>DEBUG</TITLE>
<meta name='author' content='OriginalCompo' />
<meta name='owner' content='Jean-Pierre Aguado' />
<meta name='Debug unit for PHP 5' content='Debug unit for PHP 5' />
<meta name='keywords' content='PHP5, Debug' />
<META http-equiv="Cache-Control" content="no-cache">
<META http-equiv="Pragma" content="no-cache">
<META http-equiv="Expires" content="0">
{$JS}
{$CSS}
</HEAD>
<BODY>
BEGIN;
$this->END_XML_SER =
<<<END_XMLSER
<a name="here"></a>
<table class=TABLE><tr>
<td width=50%><a target="_self" href="reload.php">Refresh</a></td>
<td width=50%><a target="_self" href="clear.php">Clear</a></td>
</tr></table>
</BODY>
</HTML>
END_XMLSER;
$this->END =
<<<END
</BODY>
</HTML>
END;
$newXMLLine = chr(10);
$this->original4xml = array('<' , '>' , '&' );
$this->_replace4xml = array($newXMLLine.'{i,n,f', 's,u,p}', $newXMLLine.'{e,t]');
$this->oldchar4xml = ',';
$this->newchar4xml = ';';
}
// ----------------------------------------------------------------------------------------------
private $xmlfile = '';
private $serfile = '';
private $onefile = '';
// ----------------------------------------------------------------------------------------------
static public function getPath()
{
$d = new Debug();
$reflectClass = new ReflectionClass($d);
unset($d);
return dirname($reflectClass->getFileName());
}
// ----------------------------------------------------------------------------------------------
private function setFiles($mode = '')
{
if ($mode=='')
{
$this->xmlfile = '';
$this->serfile = '';
$this->onefile = '';
}
else
{
$chemin = Debug::getPath();
if ($mode=='XML')
{
$this->onefile = $chemin.'/'.Debug::ONETRACE_HTML;
$this->serfile = '';
$this->xmlfile = $chemin.'/'.Debug::ONETRACE_XML;
}
elseif ($mode='SER')
{
$this->onefile = $chemin.'/'.Debug::ONETRACE_HTML;
$this->serfile = $chemin.'/'.Debug::ONETRACE_SER;
$this->xmlfile = '';
}
}
}
/** ---------------------------------------------------------------------------------------------
Clear efface les traces cumulatives (dans le cas d'une trace unique)
*/
public function clear()
{
$this->trace = array(); // on efface le tableau
$this->inittrace = array(); // on efface le tableau
$this->nbRaccourcis=0;
$this->update_debughtml(true);
}
/** =============================================================================================
Une seule instante de Debug peut exister à la fois.
Le design pattern SINGLETON est utilisé dans cet objectif
Pour travailler sur l'instance de Debug à partir de plusieurs scripts PHP, il faut donc chercher
l'instance dans chaque script (avec l'espace de nom) ...
$instanceDebug = originalcompo\Debug::getInstance();
... et travailler sur $instanceDebug
*/
private static $_singleton;
private function __construct()
{
$this->init_const();
}
/** ---------------------------------------------------------------------------------------------
Il y a 3 appels possibles de getInstance
Debug::getInstance();
--> chaque trace est générée dans un fichier indépendant.
Ex: si la page web toto.php est en cours de débogage, alors la trace sera sur
toto.php.debug.html
Debug::getInstance('SER');
--> les traces sont toutes générées dans un unique fichier trace.html se trouvant au même endroit
que ce fichier (contenant la classe originalcompo\Debug
Pour cela, un cache contenant la classe serialisée est stockée sur le disque dur
Debug::getInstance('XML');
--> les traces sont toutes générées dans un unique fichier trace.html se trouvant au même endroit
que ce fichier (contenant la classe originalcompo\Debug
Pour cela, un cache au format XML contenant une partie du code HTML de la page trace.html est
stokée sur le disque dur
Note: il n'y a aucune différence à l'exécution entre getInstance('SER') et getInstance('XML').
Par contre il est IMPERATIF de TOUJOURS garder le même choix.
Si vous utilisez 'SER' dans un fichier, puis 'XML' pour déboguer un autre, vous n'obtiendrez pas
le résultat désiré...
*/
public static function getInstance($mode = '') // XML, SER,
{
if (is_null(self::$_singleton))
{
if ($mode=='')
{
self::$_singleton = new Debug();
self::$_singleton->setFiles();
}
else
{
$chemin = Debug::getPath();
if ($mode == 'SER')
{
self::$_singleton = self::unserializeMe();
self::$_singleton->setFiles('SER');
}
elseif ($mode == 'XML')
{
self::$_singleton = new Debug();
self::$_singleton->setFiles('XML');
try {
self::$_singleton->LoadXML();
}
catch (Exception $e) {
}
}
self::$_singleton->trace[] = '<p class=changeFile>'
.date("Y/m/d H:i:s : ", time())
.$_SERVER['PHP_SELF']
.'</p>';
}
}
return self::$_singleton;
}
private function __clone()
{
// Lorsqu'un objet est cloné, PHP 5 effectue une copie superficielle
// de toutes les propriétés de l'objet. Toutes les propriétés qui
// sont des références à d'autres variables demeureront des références.
}
/** ---------------------------------------------------------------------------------------------
*/
private function serializeMe()
{
$s = serialize(Debug::getInstance());
file_put_contents($this->serfile, $s);
}
// ..............................................................................................
private static function unserializeMe()
{
$fichier = Debug::getPath() . '/' . Debug::ONETRACE_SER;
return (file_exists($fichier) ? unserialize(file_get_contents($fichier)) : new Debug());
}
// ==============================================================================================
private function describe_variable($titre, $toprint)
{
// Le titre est inclus dans une balise qui doit être interprétée, alors que la valeur doit être
// affichée en brut (balises html non interprétées)
$paramTitre = ($titre=='') ? '?' : htmlentities($titre, ENT_QUOTES, Debug::ENCODING, true);
if (isset($toprint))
{
$titre_begin = '<span class=titre>';
$titre_end = '</span>';
if ($titre=='') {
$titre_begin = $titre_begin.'<span class=italic>';
$titre_end = '</span>'.$titre_end;
}
if (is_object($toprint) || is_array($toprint))
{
// Mise en place d'un lien javascript pour déclencher la fonction réduire/développer ...
// '<a href="JavaScript: dhtml_Click($param2_a_js, $param1_a_js); ...'
// ... et de (l'équivalent) à l'appel automatique de ce lien au démarrage
// '<script language="JavaScript"> dhtml_Click($param2_js, $param1_js); ...'
// $param1_(a_)js, $param2_(a_)js vont générer des chaines de caractères qui ne doivent
// pas avoir de retour à la ligne, sinon le code javascript ne fonctionnera pas
$rc = array(chr(13).chr(10), chr(10));
$br = array('<br />', '<br />');
$nb = ++$this->nbRaccourcis;
$param1_js = $paramTitre;
$param1_a_js = htmlspecialchars($paramTitre, ENT_QUOTES, Debug::ENCODING, true);
$param1_js = str_replace($rc, $br, $param1_js );
$param1_a_js = str_replace($rc, $br, $param1_a_js);
$infoplus = is_object($toprint) ? ' (class ' .get_class($toprint).')'
: ' (array ' .count($toprint).' elements)';
$param1_js = '\''.$titre_begin.$param1_js .$titre_end.' <span class=infoplus>'.$infoplus.'</span>\'';
$param1_a_js = '\''.$titre_begin.$param1_a_js.$titre_end.' <span class=infoplus>'.$infoplus.'</span>\'';
// GESTION DU DETAIL (partie qui sera visible si -, invisible si +)
$paramDetails = var_export($toprint, TRUE);
$paramDetails = htmlentities($paramDetails, ENT_QUOTES, Debug::ENCODING, true);
$param2_js = $paramDetails;
$param2_a_js = htmlspecialchars($paramDetails, ENT_QUOTES, Debug::ENCODING, true);
$param2_js = '\''.str_replace($rc, $br, $param2_js ).'\'';
$param2_a_js = '\''.str_replace($rc, $br, $param2_a_js).'\'';
// création de la balise avec appel du js
$ret = '<a class=local href="JavaScript: dhtml_Click('.$param2_a_js.', '.$param1_a_js.', '.$nb.')">'
.'<span id=PLUS'.$nb.'>'.($this->collapsed ? "-" : "+").'</span></a>'
.'<span id=INFO'.$nb.'></span>'.PHP_EOL;
// création et stockage de l'appel direct du js
$this->inittrace[] = 'dhtml_Click('.$param2_js.', '.$param1_js.', '.$nb.');';
}
else {
if (is_bool($toprint))
$ret = $titre_begin.$paramTitre.' (bool) = '.$titre_end.($toprint==true ? 'true' : 'false');
elseif (is_string($toprint))
$ret = $titre_begin.$paramTitre.' = '.$titre_end
.(htmlentities($toprint, ENT_QUOTES, Debug::ENCODING, false));
else // numérique
$ret = $titre_begin.$paramTitre.' = '.$titre_end.$toprint;
}
}
else
{
$ret = $paramTitre.' variable unset !';
}
if ($this->withTime) $ret = date("H:i:s . ", time()).$ret;
return $ret;
}
/** .............................................................................................
Fonction à utiliser pour tracer une variable $name représente un commentaire à associer à la
variable (en général, rappeler son nom !)
*/
public function print_variable($name, $toprint)
{
$this->trace[] = $this->describe_variable($name, $toprint);
$this->update_debughtml();
}
/** .............................................................................................
Fonction à utiliser pour regrouper la trace de plusieurs variables
Exemple d'utilisation:
- print_variables('Etape 1', array('$a', '$b', '$c propriété x'), array($a, $b, $c->x));
*/
public function print_variables($comment, array $names, array $variables)
{
$error = (!is_array($variables)) || (!is_array($names)) || (count($variables)==0);
if (!$error) $error = count($variables)!=count($names);
if ($error)
$ret = '<span class=constant>Error calling : '.__METHOD__.'<br>File : '.__FILE__.'<br>Line : '.__LINE__.'</span>';
else {
$param2_js = '';
$nb = ++$this->nbRaccourcis;
for ($i=0; $i <count($variables); $i++)
{
$arg = $variables[$i];
$tab = $this->describe_variable($names[$i], $arg);
$param2_js .= '<li>'.$tab.'</li>';
}
$ret = '<span class=titre>'
.htmlentities($comment, ENT_QUOTES, Debug::ENCODING, true)
.' : </span> '
.'<table><tr><td><PRE><ul>'.$param2_js.'</ul></PRE></td></tr></table><br />'.PHP_EOL;
}
$this->trace[] = $ret;
$this->update_debughtml();
}
/** ---------------------------------------------------------------------------------------------
Fonction à utiliser pour afficher un commentaire
*/
public function print_constant($toprint)
{
$this->trace[] = htmlentities('<span class=constant>'
.($this->withTime ? date("H:i:s : ", time()) : '')
.$toprint.'</span>'
, ENT_QUOTES, Debug::ENCODING, true);
$this->update_debughtml();
}
/** ---------------------------------------------------------------------------------------------
Possibilité d'afficher la structure d'une classe à partir d'une instance de celle-ci
*/
public function reflexion($toAnalyse)
{
if (is_object($toAnalyse))
{
$reflectClass = new ReflectionClass($toAnalyse);
$className = $reflectClass->getName(); // get_class($toAnalyse);
$reflectParentClass = $reflectClass->getParentClass();
$heriteDe = $reflectParentClass != null ? ' extends '.$reflectParentClass->getName() : '';
$lesInterfaces = $reflectClass->getInterfaceNames();
$interfaces = count($lesInterfaces)==0 ? '' : ' implements '.implode(', ', $lesInterfaces);
$info_class = '<span class=titre>class '.$className.'</span>'.$heriteDe.$interfaces.'<br />'.PHP_EOL
.$reflectClass->getFileName().'<br />'.PHP_EOL
.'Lines: '.$reflectClass->getStartLine(). ' - ' .$reflectClass->getEndLine().'<br />'.PHP_EOL;
$lesMethodes = $reflectClass->getMethods();
$functions = array();
foreach($lesMethodes as $fct) {
$c = '';
$reflectMethod = new ReflectionMethod($className, $fct->name);
if ($reflectMethod->IsPublic())
$c = 'public ';
elseif ($reflectMethod->IsPrivate())
$c = 'private ';
elseif ($reflectMethod->IsProtected())
$c = 'protected ';
if ($reflectMethod->IsStatic()) $c = 'static '.$c;
if ($reflectMethod->IsAbstract()) $c = 'abstract '.$c;
if ($reflectMethod->IsFinal()) $c = 'final '.$c;
$c = $c.'<span class=methodname>'.$fct->name.'</span>';
if ($reflectMethod->getNumberOfParameters()==0)
$c .= '()';
else
{
$params = $reflectMethod->getParameters();
$args = array();
$i = 0;
$c = $c . '(';
foreach ($params as $param) {
$arg = '';
$parametre = '<span class=methodparam>'.$param->getName().'</span>';
if ($param->isPassedByReference()) $arg = '&';
if ($param->isOptional()) {
if ($param->isArray())
$arg .= '[$' .$parametre. ' (array) ]';
else{
$val = $param->getDefaultValue();
$arg = '[$' .$parametre. ' = ' .($val==null ? 'null' : $val). ']';
}
}
else
$arg .= '$'.$parametre;
$args[] = $arg;
}
$c .= implode(', ', $args) . ')';
}
$functions[] = $c;
}
$info_methods = implode('<br />'.PHP_EOL, $functions);
$lesProprietes = $reflectClass->getProperties();
$proprietes = array();
foreach($lesProprietes as $pro) {
$c = '';
if ($pro->IsPublic())
$c = 'public ';
elseif ($pro->IsPrivate())
$c = 'private ';
elseif ($pro->IsProtected())
$c = 'protected ';
if ($pro->IsStatic()) $c = 'static '.$c;
$c .= '$<span class=property>'.$pro->name.'</span>';
$proprietes[] = $c;
}
$info_properties = implode('<br />'.PHP_EOL, $proprietes);
$lesConstantes = $reflectClass->getConstants();
$constants = array();
foreach($lesConstantes as $key=>$value)
$constants[] = '<span class=property>'.$key.'</span> = '.htmlspecialchars($value, ENT_QUOTES, Debug::ENCODING, true);
$info_constants = implode('<br />'.PHP_EOL, $constants);
$this->print_constant($info_class.'<hr /><span class=infoplus>Methods :</span><br/>'
.$info_methods.'<hr /><span class=infoplus>Properties :</span><br/>'
.$info_properties.'<hr /><span class=infoplus>Constants :</span><br/>'
.$info_constants.'<hr />');
}
else {
$this->print_constant('<span class=infoplus>Error:</span> The variable tested is not an instance of a class<br>'.PHP_EOL);
}
}
/** ---------------------------------------------------------------------------------------------
Fonction écrivant le fichier de débugage
*/
private function update_debughtml($all = false)
{
if (!$this->updateTrace) return;
if ($this->xmlfile == '' && $this->serfile == '')
$nom = basename($_SERVER['PHP_SELF'].Debug::EXT);
else {
if ($all || $this->xmlfile != '') {
$this->SaveToXml();
$nom = $this->onefile;
}
if ($all || $this->serfile != '') {
$this->serializeMe();
$nom = $this->onefile;
}
}
$resultat = fopen($nom, 'w+');
if (!$resultat) {
echo '<p>DEBUG IMPOSSIBLE</p>'.PHP_EOL;
exit;
}
else
{
fputs($resultat, $this->BEGIN);
fputs($resultat, PHP_EOL.'<ul>'.PHP_EOL);
$inf_ETlt = '<'; //$inf_ETlt2 = '&lt;';
for ($i=0; $i < count($this->trace); $i++) {
$trace = $this->trace[$i];
if (substr($trace, 0, strlen($inf_ETlt))==$inf_ETlt){
$trace = html_entity_decode($trace, ENT_QUOTES, Debug::ENCODING);
}
fputs($resultat, '<li>'.$trace.'</li>'); // .PHP_EOL
}
fputs($resultat, '</ul>'.PHP_EOL);
fputs($resultat, PHP_EOL.'<script language="JavaScript">'.PHP_EOL.PHP_EOL);
for ($i=0; $i < count($this->inittrace); $i++) {
$trace = $this->inittrace[$i];
if (substr($trace, 0, strlen($inf_ETlt))==$inf_ETlt){
$trace = html_entity_decode($trace, ENT_QUOTES, Debug::ENCODING);
}
fputs($resultat, $trace.PHP_EOL.PHP_EOL);
}
fputs($resultat, '</script>'.PHP_EOL);
fputs($resultat, (($this->xmlfile == '') && ($this->serfile == '')) ? $this->END : $this->END_XML_SER);
fclose($resultat);
}
}
/** ---------------------------------------------------------------------------------------------
Afin de garder plusieurs traces successives dans un même fichier (après changement de page ou
bien rechargement d'une même page), un fichier XML peut être utilisé.
/* STRUCTURE DU FICHIER XML UTILISE
<?xml version="1.0"?>
<rootelement>
<param symbol="<">
<equivalent>{i;n;f</equivalent>
</param>
<trace position="1">
<print>...</print>
</trace>
...
<inittrace position="1">
<print>...</print>
</inittrace>
...
</rootelement>
*/
/** ---------------------------------------------------------------------------------------------
SaveToXML(): sauvegarde les infos permettant de re-générer le fichier html de trace.
Le but est de remplacer les balises perturbantes pour XML par des balises personnelles neutres
(qui ne seront pas interprétées par XML ou HTML)
Pour cela, il faut remplacer les caractères < > et & par des chaines de caractères de notre choix
AVANT de construire le fichier XML, et faire l'inverse lorsqu'on récupère le XML.
Ces chaines de correspondances pouvant se retrouver dans le texte à afficher, il faut vérifier si
elles n'y sont pas et en choisir éventuellement une autre.
Ex: '<' est remplacé par '{i;n;f', mais si '{i;n;f' est trouvé, on utilisera '{i;n;f1', sinon
'{i;n;f2' etc...
La vérification est activée par défaut mais peut être désactivée ($checksymbols = false;)
Détail: Si '{i;n;f' est une chaine de codage stockée dans une propriété de l'instance $f de la
classe Debug, $f->print_variable('$f', $f) va devoir utiliser '{i;n;f1' pour générer
le XML. Lors d'un deuxième appel, ce sera '{i;n;f2'...
C'est dans l'unique but (!!) d'utiliser la classe originalcompo\Debug avec elle même
sans modifier inutilement la chaine de remplacement que celle-ci n'est pas stockée telle
qu'elle dans la classe.
La propriété $_replace4xml contient la valeur '{i,n,f', mais la chaine de remplacement
est recalculée en '{i;n;f'. De même pour les autres valeurs 's,u,p}' et '{e,t]'
*/
public function SaveToXML()
{
$xmlBEGIN = '<?xml version="1.0" encoding="'.Debug::ENCODING.'"?><rootelement>';
$xmlEND = '</rootelement>';
// Création d'un document XML "vide"
$xmltext = $xmlBEGIN.$xmlEND;
// Construction du tableau $replace4xml des chaines de substitutions à < > &
// (basé sur $_replace4xml)
$replace4xml = str_replace($this->oldchar4xml, $this->newchar4xml, $this->_replace4xml);
$r = $replace4xml;
$i=0;
// Parcours de toutes les chaines qu'il va falloir modifier, et vérification
// que les chaines de remplacement ne sont pas déjà présentes dans ces chaines
if ($this->checksymbols)
do
{
$retester = false;
foreach($this->trace as $trace)
{
foreach ($replace4xml as $ri)
{
$retester = !(stripos($trace, $ri) === false);
if ($retester) break 2;
}
}
if (!$retester) {
foreach($this->inittrace as $trace)
{
foreach ($replace4xml as $ri)
{
$retester = !(stripos($trace, $ri) === false);
if ($retester) break 2;
}
}
}
if ($retester) {
$i++;
for ($j = 0; $j<count($r); $j++)
$replace4xml[$j] = $r[$j].$i;
}
}
while($retester);
$this->DOM ? $this->DOM_SaveXML ($xmltext, $replace4xml)
: $this->simple_SaveXML($xmltext, $replace4xml);
}
// --------------------------------------------------------------------------
public function simple_SaveXML($xmltext, $replace4xml)
{
$XMLelements = new SimpleXMLElement($xmltext, NULL, false);
//
for ($i=0; $i<count($replace4xml); $i++) {
$newXMLelement = $XMLelements->addChild('param');
$newXMLelement->addAttribute('symbol', $this->original4xml[$i]);
$newXMLelement->addChild('equivalent', $replace4xml[$i]);
//
//
}
foreach($this->trace as $trace) {
$i++;
$trace = str_replace($this->original4xml, $replace4xml, $trace);
$newXMLelement = $XMLelements->addChild('trace');
$newXMLelement->addAttribute('position', $i);
$newXMLelement->addChild('print', $trace);
//
//
}
$i=0;
foreach($this->inittrace as $inittrace) {
$i++;
$inittrace = str_replace($this->original4xml, $replace4xml, $inittrace);
$newXMLelement = $XMLelements->addChild('inittrace');
$newXMLelement->addAttribute('position', $i);
$newXMLelement->addChild('print', $inittrace);
//
//
}
$resultat = fopen($this->xmlfile, 'w+');
fputs($resultat, $XMLelements->asXML());
fclose($resultat);
}
// --------------------------------------------------------------------------
public function DOM_SaveXML($xmltext, $replace4xml)
{
$XMLelements = new DomDocument();
$XMLelements->loadXML($xmltext);
for ($i=0; $i<count($replace4xml); $i++) {
$newXMLelement = $XMLelements->createElement('param');
$newXMLelement2 = $XMLelements->createElement('equivalent', $replace4xml[$i]);
$newXMLelement->SetAttribute('symbol', $this->original4xml[$i]);
$newXMLelement->appendChild($newXMLelement2);
$XMLelements->documentElement->appendChild($newXMLelement);
}
foreach($this->trace as $trace) {
$i++;
$trace = str_replace($this->original4xml, $replace4xml, $trace);
$newXMLelement = $XMLelements->createElement('trace');
$newXMLelement->SetAttribute('position', $i);
$newXMLelement2 = $XMLelements->createElement('print', $trace);
$newXMLelement->appendChild($newXMLelement2);
$XMLelements->documentElement->appendChild($newXMLelement);
}
$i=0;
foreach($this->inittrace as $inittrace) {
$i++;
$inittrace = str_replace($this->original4xml, $replace4xml, $inittrace);
$newXMLelement = $XMLelements->createElement('inittrace');
$newXMLelement->SetAttribute('position', $i);
$newXMLelement2 = $XMLelements->createElement('print', $inittrace);
$newXMLelement->appendChild($newXMLelement2);
$XMLelements->documentElement->appendChild($newXMLelement);
}
$XMLelements->save($this->xmlfile);
//
//
}
// ==============================================================================================
public function LoadXML()
{
if (!file_exists($this->xmlfile)) return;
$this->trace = array(); //array_splice($this->trace, 0); // on efface le tableau
$this->inittrace = array(); // on efface le tableau
$this->nbRaccourcis=0;
$this->DOM ? $this->DOM_LoadXML()
: $this->simple_LoadXML();
}
// ----------------------------------------------------------------------------------------------
function simple_LoadXML()
{
$replace4xml = array();
$XMLelements = new SimpleXMLElement($this->xmlfile, NULL, true); // true : path, false : string
//
// ALTERNATIVES
// 1) $xmlstr = file_get_contents($xmlfile);
// $XMLelements = simplexml_load_string($xmlstr);
// 2) $XMLelements = simplexml_load_file($xmlfile);
// 3) $xmlstr = file_get_contents($xmlfile);
// $XMLelements = new SimpleXMLElement($xmlstr);
$results = $XMLelements->xpath('/rootelement/param');
//
foreach ($results as $noeud)
{
$position = '';
foreach ($noeud->attributes() as $attr)
if ($attr->getName()=='symbol') $position = $attr;
if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
foreach ($noeud->children() as $subnoeud)
{
if ($subnoeud->getName()=='equivalent') {
for ($i=0; $i<count($this->original4xml); $i++)
{
if ($this->original4xml[$i]==$attr)
{
$replace4xml[$i] = $subnoeud;
break;
}
}
}
}
}
$results = $XMLelements->xpath('/rootelement/trace');
foreach ($results as $noeud)
{
$position = -1;
foreach ($noeud->attributes() as $attr)
if ($attr->getName()=='position') $position = $attr;
if ($position==-1) throw new Exception('Mauvaise structure du fichier XML');
foreach ($noeud->children() as $subnoeud)
{
if ($subnoeud->getName()=='print') {
$this->trace[] = str_replace($replace4xml, $this->original4xml, $subnoeud);
$this->nbRaccourcis++;
}
}
}
$results = $XMLelements->xpath('/rootelement/inittrace');
foreach ($results as $noeud)
{
$position = -1;
foreach ($noeud->attributes() as $attr)
if ($attr->getName()=='position') $position = $attr;
if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
foreach ($noeud->children() as $subnoeud)
{
if ($subnoeud->getName()=='print') {
$this->inittrace[] = str_replace($replace4xml, $this->original4xml, $subnoeud);
$this->nbRaccourcis++;
}
}
}
}
// ----------------------------------------------------------------------------------------------
// Fonctions DOM interressantes: (file, string)
// DomDocument::loadHtmlFile() , DomDocument::loadHTML()
// DomDocument::save() ,
// DomDocument:saveHTMLFile() , DomDocument::saveHTML(), DomDocument::saveXML()
/* RAPPEL : STRUCTURE DU FICHIER XML UTILISE
<?xml version="1.0"?>
<rootelement>
<param symbol="<">
<equivalent>{i;n;f</equivalent>
</param>
<trace position="1">
<print>...</print>
</trace>
...
<inittrace position="1">
<print>...</print>
</inittrace>
...
</rootelement>
*/
// ----------------------------------------------------------------------------------------------
public function DOM_LoadXML()
{
$replace4xml = array();
$XMLelements = new DomDocument();
$XMLelements->load($this->xmlfile);
// ALTERNATIVES
// 1) $XMLelements = new DomDocument();
// $XMLelements->C
//
//
//
$xpath = new DomXPath($XMLelements);
$results = $xpath->query('//rootelement/param');
foreach ($results as $noeud)
{
$position = '';
foreach ($noeud->attributes as $attr)
if ($attr->nodeName=='symbol') $position = $attr->nodeValue;
if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
foreach ($noeud->childNodes as $subnoeud)
{
if ($subnoeud->nodeName=='equivalent') {
for ($i=0; $i<count($this->original4xml); $i++)
{
if ($this->original4xml[$i]==$attr->nodeValue)
{
$replace4xml[$i] = $subnoeud->nodeValue;
break;
}
}
}
}
}
$results = $xpath->query('//rootelement/trace');
foreach ($results as $noeud)
{
$position = -1;
foreach ($noeud->attributes as $attr)
if ($attr->nodeName=='position') $position = $attr->nodeValue;
if ($position==-1) throw new Exception('Mauvaise structure du fichier XML');
foreach ($noeud->childNodes as $subnoeud)
{
if ($subnoeud->nodeName=='print') {
$this->trace[] = str_replace($replace4xml, $this->original4xml, $subnoeud->nodeValue);
$this->nbRaccourcis++;
}
}
}
$results = $xpath->query('//rootelement/inittrace');
foreach ($results as $noeud)
{
$position = -1;
foreach ($noeud->attributes as $attr)
if ($attr->nodeName=='position') $position = $attr->nodeValue;
if ($position=='') throw new Exception('Mauvaise structure du fichier XML');
foreach ($noeud->childNodes as $subnoeud)
{
if ($subnoeud->nodeName=='print') {
$this->inittrace[] = str_replace($replace4xml, $this->original4xml, $subnoeud->nodeValue);
$this->nbRaccourcis++;
}
}
}
}
// ================================================================================================
}
?>
Conclusion
Toutes les explications se trouvent dans le code php (fichier source)
Le sources se trouvent aussi sur un de mes sites web:
http://mywebdev.free.fr (section PHP)
Fichier Zip
Historique
- 12 août 2010 14:18:25 :
- explications supplémentaires (pas de modif su source)
- 14 août 2010 19:28:44 :
- Nouvelle méthode permettant d'afficher la définition d'une classe à partir d'une de ses instances (utilisation de la "reflexion").
exemple d'utilisation :
$instance_ocDEBUG->reflexion($instance_une_classe);
- 15 août 2010 09:34:44 :
- - Interdiction du clonage
- Utilisation de l'écriture HEREDOC
- Reflection() affiche maintenant le nom de la classe parente ainsi que les interfaces utilisées
- 25 août 2010 13:25:07 :
- Possibilité de garder toutes les traces venant de plusieurs pages html dans un seul fichier
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Probleme avec serialize et unserialize [ par matou82 ]
J'ai un objet que je serialize et passe en paramètre dans l'url d'un popup.Dans ce popup je le unserialize. Il s'agit d'un objet possédant une fonctio
probleme de class [ par damien174 ]
bonjour, je voudrai créer une classe pour dessiné des graphet j'ai un petit soucis, lorsque j'appelle la fonction init_graph ca marche mais
passage de tableau en url [ par eddie5150 ]
Salut à tous,J'aimerai passer en url un tableau, et le récupérer avec un $_GET.J'ai essayé addslashes(urlencode(serialize($tab))), ou encore urlencode
Trace du Telnet [ par A_Script ]
Bonjour j'ai besoin de sauvgarder une trace de ce que je fais sous l'interface telnet (les commandes et les reponses) , est ce que c'est possible de
DomXML, TextNode tronqué ... [ par JoJo738 ]
Helo tout le monde :pJe suis depuis ce matin sur une class de log, et je rencontre un petit problème ...Je veux enregistrer la Trace de mon erreur ...
$_SESSION perte de données [ par ciberrique ]
Bonjour, lorsque je veux mettre des objets en session avec la fonction serialize cela fonctionne mais si j'actualise ma page alors les données de l'ob
reflexion construction de base de donnée pour annuaire hôtels et restaurants [ par math567 ]
J'ai besoin d'un coup de pouce !!! Je m'explique, j'ai une table "t_etablissement" contenant plusieurs champs "id,nom,adresse,..." et pour chaque étab
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|