Précédent   Forum du club des développeurs et IT Pro > PHP > Langage > Fonctions
Fonctions Forum d'entraide sur les fonctions PHP. Avant de poster -> FAQ fonctions et Sources diverses
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 29/07/2009, 18h25   #1
gomodo
Membre régulier
 
Inscription : mai 2007
Messages : 181
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 181
Points : 82
Points : 82
Par défaut Analyser un fichier PHP avec token_get_all

Bonjour à tous.

Contexte :

Je souhaite utiliser la fonction token_get_all : Cette fonction éclate un code source php en multiple "jeton" identifiant le type d'élément php utilisé.

Mon problème:

Mais bien sur cette fonction marche correctement uniquement si on lui passe en paramètre du code php... et uniquement du code php. Or je veux analyser un fichier PHP, même lorsque celui-ci contient de l'HTML mélangé avec des parties en PHP...

Je souhaite donc parser un fichier PHP, et en extraire les parties uniquement PHP (si possible en identifiant les lignes) pour utiliser token_get_all : grosso modo ce que fait tidy en HTML (nettoyer et manipuler les documents HTML, et les traiter sous forme de balises hiérarchisées.)..
..mais en PHP (repérer les blocs php) !

Connaissez-vous une fonction ou une extension qui ferait cela ?

Merci aux experts (et à leur mémoire ).
gomodo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2009, 19h39   #2
micetf
Membre chevronné
 
Avatar de micetf
 
Homme Fred
Professeur des Ecoles
Inscription : mai 2009
Messages : 503
Détails du profil
Informations personnelles :
Nom : Homme Fred
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Professeur des Ecoles
Secteur : Enseignement

Informations forums :
Inscription : mai 2009
Messages : 503
Points : 727
Points : 727
Peut-être qu'une fonction de ce type suffirait ?
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
function extrairePHP($source,$destination) {
	$string=file_get_contents($source);
 
	preg_match_all('/(<\?php)(.*?)(\?>)/s',$string,$result);
 
	$codePhp='<?php ';
	foreach ($result[2] as $bloc) {
		$codePhp .= $bloc."\n";
	}
	$codePhp .= ' ?>';
 
	file_put_contents($destination,$codePhp);
}
Fred
micetf est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2009, 20h08   #3
gomodo
Membre régulier
 
Inscription : mai 2007
Messages : 181
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 181
Points : 82
Points : 82
Merci,
mais je cherche une solution plus carré, qui marcherait à tous les coups.
Ce que je veux dire c'est que ta solution ne marcherais pas par exemple avec un php qui contiendrait :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type='text/javascript'>
function mafonctionjavascript()
{
// commentaire avec un malencontreux <%
}
</script>
</head>
<body onload="mafonctionjavascript('un autre malencontreux <%');" >
<?php
 $message= "un autre malencontreux <%";
 echo $message;
?>
</body>
</html>
Bref, au lieu de ré-inventer la poudre (au risque de faire du code foireux), je chercher un outil qui ferais déjà ça proprement (et ca serait étonnant que ça n'existe pas).
gomodo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2009, 20h52   #4
micetf
Membre chevronné
 
Avatar de micetf
 
Homme Fred
Professeur des Ecoles
Inscription : mai 2009
Messages : 503
Détails du profil
Informations personnelles :
Nom : Homme Fred
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Professeur des Ecoles
Secteur : Enseignement

Informations forums :
Inscription : mai 2009
Messages : 503
Points : 727
Points : 727
Je ne peux garantir ma solution,
je l'ai d'ailleurs modifiée pour le cas d'une dernière balise non fermée.
Néanmoins,
pour l'exemple que tu donnes,
elle fonctionne parfaitement.
Je donne donc le code modifié :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
function extrairePHP($source,$destination) {
	$string=file_get_contents($source);
 
	preg_match_all('/(<\?php)(.*?)(\?>|$)/s',$string,$result);
 
	$codePhp='<?php ';
	foreach ($result[2] as $bloc) {
		$codePhp .= $bloc;
	}
	$codePhp .= ' ?>';
 
	file_put_contents($destination,$codePhp);
}
On ne sait jamais,
je n'ai peut-être pas réinventé la poudre,
et l'outil que tu cherches n'existe peut-être pas.
Après tout, ce n'est qu'une expression régulière qui fait tout le travail.

Fred
micetf est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2009, 21h54   #5
gomodo
Membre régulier
 
Inscription : mai 2007
Messages : 181
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 181
Points : 82
Points : 82
Merci Fred pour l'attention que tu porte à mon problême,

Quand je parlais de ré-inventer la poudre ou de code foireux, je ne parlais pas de toi mais de moi ("je"). D'autre part, les limites d'une simple expression rationnelle ne me convienne pas, même dans ta seconde version modifiée. Mon exemple était a l'évidence pas assez clair, je te présente (moi aussi ) une seconde version de mon exemple qui montre les limites de l'expression rationnelle:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Document sans nom</title>
<script type='text/javascript'>
function mafonctionjavascript()
{
//  <% Ceci n'est pas du php %>
}
</script>
</head>
<body onload="mafonctionjavascript('<% Ceci n'est pas du php %>');" >
<?php
 $message= "<?php Ceci n'est pas du php ?>";
 echo $message;
?>
</body>
</html>
Extraire correctement toute les balises implique de passer par l'equivalent d'un parser (mais à la sauce HTML-PHP.. pas en XML),
et il me parait étrange qu'il n'existe pas d'outils déjà fait..
..je continue donc de chercher !
gomodo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2009, 22h42   #6
micetf
Membre chevronné
 
Avatar de micetf
 
Homme Fred
Professeur des Ecoles
Inscription : mai 2009
Messages : 503
Détails du profil
Informations personnelles :
Nom : Homme Fred
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Professeur des Ecoles
Secteur : Enseignement

Informations forums :
Inscription : mai 2009
Messages : 503
Points : 727
Points : 727
Citation:
D'autre part, les limites d'une simple expression rationnelle ne me conviennent pas, même dans ta seconde version modifiée.
OK !
Ce n'est pas grave.
Mais comme je suis têtu,
je propose une dernière mouture
qui ne se laisse pas piéger par ton dernier exemple.
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
function extrairePHP($source,$destination) {
	$string=file_get_contents($source);
 
	preg_match_all('/(<\?php)(((<\?php.*?\?>)|.)*?)(\?>|$)/s',$string,$result);
 
	$codePhp='<?php ';
	foreach ($result[2] as $bloc) {
		$codePhp .= $bloc;
	}
	$codePhp .= ' ?>';
 
	file_put_contents($destination,$codePhp);
}
avant de te souhaiter bonne chance dans ta recherche.
Fred
micetf est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/07/2009, 23h16   #7
gomodo
Membre régulier
 
Inscription : mai 2007
Messages : 181
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 181
Points : 82
Points : 82
Pour le developpement être têtu est une qualité..
.. même si ton dernier code que j'ai testé retourne ceci :

Code :
1
2
3
 
<?php 
 $message= "<?php Ceci n'est pas du php  ?>
Alors que le résultat attendu est :

Code :
1
2
3
4
5
 
<?php
 $message= "<?php Ceci n'est pas du php ?>";
 echo $message;
?>
Je sais, je suis perfectionniste..
..mais c'est aussi une qualité dans le developpement .

Merci Fred.
gomodo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/07/2009, 08h33   #8
micetf
Membre chevronné
 
Avatar de micetf
 
Homme Fred
Professeur des Ecoles
Inscription : mai 2009
Messages : 503
Détails du profil
Informations personnelles :
Nom : Homme Fred
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Professeur des Ecoles
Secteur : Enseignement

Informations forums :
Inscription : mai 2009
Messages : 503
Points : 727
Points : 727
Que neni !
Refais le test,
mais ma dernière (3ème) version renvoie bien :
Citation:
<?php
$message= "<?php Ceci n'est pas du php ?>";
echo $message;
?>
Fred
micetf est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/07/2009, 11h35   #9
gomodo
Membre régulier
 
Inscription : mai 2007
Messages : 181
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 181
Points : 82
Points : 82
Autant pour moi Fred..
.. par contre cet exemple ne fonctionne pas

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type='text/javascript'>
function mafonctionjavascript()
{
//  <% Ceci n'est pas du php %>
}
</script>
</head>
<body onload='mafonctionjavascript('<?php Ceci est du php ?>');' >
<?php
/*
Ceci est une fin de balise ?> dans un commentaire
*/
 $message= "<?php Ceci n'est pas du php ?>";
 echo $message;
?>
</body>
</html>
car il retourne :
Code :
1
2
3
4
 
<?php  Ceci est du php 
/*
Ceci est une fin de balise  Ceci n'est pas du php  ?>
(Je suis aussi un peu joueur )

A part de la bidouille, personne n'a d'idée sur l'existence d'une fonction ou d'une extension qui extrairerais la partie PHP (idéalement qui permettrait d'identifier la ligne correspondante du fichier original)?
gomodo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/08/2009, 18h41   #10
gomodo
Membre régulier
 
Inscription : mai 2007
Messages : 181
Détails du profil
Informations forums :
Inscription : mai 2007
Messages : 181
Points : 82
Points : 82
Attention à l'utilisation de get_token_all () - (Constaté sur WAMP, PHP 5.3.0)

1: les numéros de ligne bug

Depuis PHP 5.2.2 token_get_all () doit retourner le nombre de ligne dans l'élément 2 ..
.. mais par exemple (5.3.0 sur WAMP), il fonctionne parfaitement avec du code PHP (sans HMTL mélangé), mais si vous avez des T_INLINE_HTML détecté par token_get_all (), parfois, vous trouverez les numéros de ligne décalé (ligne suivante) ...

2: bug des messages d'alertes qui peuvent avoir un impact sur les boucles

Attention l'analyse de code PHP non complet (ex: code php ligne par ligne):
par exemple, si une balise de commentaire n'est pas fermé token_get_all (), les boucles peuvent être impacté par cet avertissement:
Warning: Unterminated commentaire ligne de départ

Ce problème ne semble pas se produire dans CLI mod (php en ligne de commande), mais seulement sur le Web mod.

En attendant plus de stabilité, utiliser token_get_all () seulement sur du code PHP complet (avec les balise d'ouverture et de fermeture PHP incluse) :
  1. Tout d'abord extraire entièrement du code PHP (avec php et à proximité tag),
  2. Utilisation token_get_all () sur le code PHP pur.

3: Pourquoi n'y at-il pas la fonction d'extraire du code PHP (extrait de HTML, nous avons Tidy ..) ?

En attendant, je propose donc ma fonction.
Attention elle prend pas en charge:
- les anciennes notations : <? ?> Et <% %>
- Heredoc syntaxe
- Nowdoc syntaxe (depuis PHP 5.3.0)

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
 
function extract_php_blocks($arg_path)
{
	$dbg=false;
	if(!is_file($arg_path)) exit ("extract_php_blocks() : ".$arg_path." file not found");
	$handle = @fopen($arg_path, "r");
	if ($handle) {
		$bloc = array();
		$php_bloc_number=0; //fisrt bloc = 0
		$line_number=1; // first row number  = 1
		$multiline_php_code="";
		$double_increment=false;
		$in_php_code=false;
		$in_single_quoted=false;
		$in_double_quoted=false;
		$in_comment_multi_line=false;
		$in_comment_single_line=false;
		while (!feof($handle)) {
			$line_mixed_code= fgets($handle, 4096);
			$nb_char=strlen($line_mixed_code);
			$i_inline=0;
			while($i_inline<$nb_char)
			{// scanning line
				if(!$in_php_code)
				{// searching php open tag : with strpos
					if($dbg) echo "\n".$line_number."---- OUT PHP ----\n".substr($line_mixed_code,$i_inline);
					$pos_open_tag = strpos(substr($line_mixed_code,$i_inline) ,'<?php');
					if ($pos_open_tag !== false)
					{
						$i_inline+=$pos_open_tag;
						$bloc[$php_bloc_number]=array("start_line" => $line_number,"start_pos" => $i_inline,"end_line" => null,"end_pos" => null,"code" => null);
						if($dbg) echo "\n".$line_number."-".$i_inline."\n";
						$in_php_code=true;
					}
				}// end  searching php open tag
				else
				{// searching php close tag : char by char
					$multiline_php_code.=$line_mixed_code[$i_inline];
					if($double_increment){$i_inline++;$multiline_php_code.=$line_mixed_code[$i_inline];$double_increment=false;	}
					if($dbg) echo "\n".$line_number."---- IN PHP ----\n".substr($line_mixed_code,$i_inline);
					if($dbg&&$in_comment_single_line) echo "\n [in_comment_single_line] \n";
 
					// specification in http://fr.php.net/manual/fr/language.types.string.php
					if($in_comment_multi_line)
					{// search ending sequence
						if($dbg) echo "\n [in_comment_multi_line] \n";
						if (($line_mixed_code[$i_inline]=='*')&&(($i_inline+1)<$nb_char)&&($line_mixed_code[$i_inline+1]=='/')){$in_comment_multi_line=false;;$double_increment=true;}
					}
					elseif($in_single_quoted)
					{// search ending sequence 
						if($dbg) echo "\n [in_single_quoted] \n";
						if (($line_mixed_code[$i_inline]=='\\')&&(($i_inline+1)<$nb_char)&&(
						($line_mixed_code[($i_inline+1)]=='\'')||($line_mixed_code[$i_inline+1]=='\\')
						))$double_increment=true;
						elseif ($line_mixed_code[$i_inline]=='\'') $in_single_quoted=false;
					}
					elseif($in_double_quoted)
					{// search ending sequence
						if($dbg) echo "\n [in_double_quoted] \n";
						if (($line_mixed_code[$i_inline]=='\\')&&(($i_inline+1)<$nb_char)&&(
						($line_mixed_code[($i_inline+1)]=='\'')||($line_mixed_code[$i_inline+1]=='\\')
						||($line_mixed_code[$i_inline+1]=='n')||($line_mixed_code[$i_inline+1]=='r')
						||($line_mixed_code[$i_inline+1]=='t')||($line_mixed_code[$i_inline+1]=='v')
						||($line_mixed_code[$i_inline+1]=='f')||($line_mixed_code[$i_inline+1]=='$')
						||($line_mixed_code[$i_inline+1]=='"')
						))$double_increment=true;
						elseif ($line_mixed_code[$i_inline]=='"') $in_double_quoted=false;					
					}
					elseif ((($i_inline+1)<$nb_char)&&($line_mixed_code[$i_inline]=='?')&&($line_mixed_code[($i_inline+1)]=='>')) {
						$bloc[$php_bloc_number]["end_line"] = $line_number ;
						$bloc[$php_bloc_number]["end_pos"] = $i_inline+2;
						$bloc[$php_bloc_number]["code"] = '<'.$multiline_php_code.'>';
						// reset in_php_code values
						$multiline_php_code="";
						$php_bloc_number++;
						$in_php_code=false;
						$in_comment_single_line=false;
						$double_increment=true;
					}
					elseif((!$in_comment_multi_line)&&!$in_comment_single_line)
					{// not in comment
						if ($line_mixed_code[$i_inline]=='\'') $in_single_quoted=true;
						elseif ($line_mixed_code[$i_inline]=='"') $in_double_quoted=true;
						elseif ($line_mixed_code[$i_inline]=='#') $in_comment_single_line=true;
						elseif (($i_inline+1)<$nb_char)
						{// next char exist
							if($dbg) echo "\n [found char+1] \n".substr($line_mixed_code,$i_inline);
							if (($line_mixed_code[$i_inline]=='/')&&($line_mixed_code[($i_inline+1)]=='*')) {$in_comment_multi_line=true;;$double_increment=true;}
							elseif (($line_mixed_code[$i_inline]=='/')&&($line_mixed_code[($i_inline+1)]=='/')) {$in_comment_single_line=true;;$double_increment=true;}
						}// end next char exist
					}//end :  not in comment
 
				}// end  searching php close tag
				$i_inline++;
			}// end scanning line
			$line_number++;
			if($dbg) echo "\n [newline] \n";
			$in_comment_single_line=false;
		}
		fclose($handle);
	}
	return $bloc;
}
 
function view_php_blocks(&$list_php_bloc)
{
	if(!is_array($list_php_bloc)) return false;
	foreach($list_php_bloc as $key => $value)
	{
		$multiline_php_code.="\nBloc ".$key." (line ".$value["start_line"]." at char ".$value["start_pos"]." - line ".$value["end_line"]." at char ".$value["end_pos"].") :\n".$value["code"]."\n";
	}
	return $multiline_php_code;
}
gomodo est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 21h59.


 
 
 
 
Partenaires

Hébergement Web