Forum Programmation.php graphe des liaisons entre fichiers

Posté par (page perso) .
Tags :
0
19
août
2004
Bonjour !

J'ai un "site" en php d'une soixantaine de pages, avec plein de variables et d'inclusions de fichiers.

J'aimerais me faire un graph qui me permette de savoir quel page appelle quelle page, quels variables sont définis où, etc.

Savez vous s'il existe déjà une petite appli permettant ça (je ne tiens pas forcément à ce que l'appli établissent les liens elle-mêmes. Je peux très bien rentrer toutes les informations à la main. C'est juste que sur PC, c'est plus facile pour modifier le graph lors de l'évolution de certaines pages...) ?
  • # Dox

    Posté par (page perso) . Évalué à 2.

    Tout dépends de ce que tu veux,
    s'il s'agit de savoir quel URL appel quelle URL, aucune idée.
    Sinon tu peux utiliser doxygen pour savoir quel fichier inclus quel fichier.
    Cerise sur le gateau, Dox te permet avec Dot de coder toi meme tes propres graphs, donc si tu veux coder a la main quelle URL mene a quelle URL c'est possible.
  • # Une solution

    Posté par . Évalué à 1.

    J'ai trouvé ton problème intéressant et j'ai pondu un petit programme en python (php2dot) qui génère un graphe des relations d'inclusion entre fichiers php d'une hiérarchie de répertoires.

    La subtilité, pour éviter de pourrir le graphe, c'est de regrouper en un même noeud les fichiers qui ont les mêmes inclusions.

    Sinon une limitation fondamentale du programme c'est qu'il attend des fichiers aux noms distincts ; lever cette limitation demanderait pas mal d'efforts supplémentaires... moi je m'arrête là.
    • [^] # php2dot

      Posté par . Évalué à 2.

      #!/usr/bin/python
      # -*- coding: iso-8859-1 -*-
      #
      # Copyright (C) 2004 Nicolas Girard < bobert at dlfp dot org >
      #
      # This program is free software; you can redistribute it and/or modify
      # it under the terms of the GNU General Public License as published by
      # the Free Software Foundation; either version 2, or (at your option)
      # any later version.
      #
      # This program is distributed in the hope that it will be useful,
      # but WITHOUT ANY WARRANTY; without even the implied warranty of
      # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      # GNU General Public License for more details.
      #
      # You should have received a copy of the GNU General Public License
      # along with this program; if not, write to the Free Software
      # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
      import os,sys,re
      from os.path import join
      from itertools import ifilter
      from sets import Set
      
      class Finder:
          """Parcourt une hiérarchie de répertoires à partir de startDirectory"""
          def __init__(self,startDirectory):
              self.walker = os.walk(startDirectory)
          def walk(self):
              while 1:
                  root, dirs, files = self.walker.next()
                  for file in files:
                      yield (root,file)
          def phpFiles(self):
              isPhp = lambda (r,f):f.endswith('.php') or f.endswith('.php3')
              return ifilter(isPhp,self.walk())
              
      def find(dir):
          return Finder(dir)
          
      class PhpFile:
          include = re.compile(".*include\s*\(['\"](\S+)['\"]\)\s*;")
          def __init__(self,dir,name):
              (self.dir,self.name)=(dir,name)
          def includes(self):
              f=open(join(self.dir,self.name),'r')
              lines=f.readlines()
              f.close()
              for line in lines:
                  if PhpFile.include.match(line):
                      yield PhpFile.include.match(line).group(1).split('/')[-1]
              
      class Node:
          def __init__(self,name,labels=[],children=Set()):
              (self.name,self.labels,self.children,self.nodes)=(name,labels,children,None)
          def mergeWith(self,node):
              self.labels+=node.labels
          def label(self):
              return "\\n".join(self.labels)
          def edges(self):
              return "\n".join(map(lambda child,s=self:"%s -> %s"%(s.name,child.name),self.children))
          def __eq__(self,other):
              return self.name==other.name
          def __str__(self):
              return "%s [label=\"%s\"]\n%s"%(self.name,self.label(),self.edges())
          def rank(self):
              """calcule le nombre de parents du noeud"""
              return sum(map(lambda o,s=self,:s in o.children,self.nodes))
          def isExcluded(self):
              return self.rank()==0 and len(self.children)==0
              
      class Graph:
          def __init__(self,ranksep=2,nodesep=0.5,minlen=1.5,concentrate=True,nodes=[]):
              self.nodes=nodes
              self.head="""
      digraph Schema {
        node[shape=box];
        concentrate=%s;
        ranksep=%f;
        nodesep=%f;
        edge[minlen=%f];\n"""%(concentrate,ranksep,nodesep,minlen)
              self.foot="}\n"
          def append(self,node):
              node.nodes=self.nodes
              self.nodes.append(node)
          def __getitem__(self,nodeName):
              res=filter(lambda node,n=nodeName:node.name==n,self.nodes)
              if len(res)==1:
                  return res[0]
              else:
                  return None
          def checkChildren(self):
              """On supprime les fichiers inclus ne correspondant pas à un fichier trouvé
              et les doublons"""
              for node in self.nodes:
                  node.children = filter(lambda ch,fath=node:ch and fath!=ch,
                    map(lambda c,s=self:self[c],node.children))
          def removeExcluded(self):
              """supprime les noeuds exclus du graphe"""
              for excluded in filter(Node.isExcluded,self.nodes):
                  self.nodes.remove(excluded)
          def clusterize(self):
              """Regroupe les fichers non-inclus par d'autres, et incluant les mêmes fichiers"""
              nodes = filter(lambda n:n.rank()==0,self.nodes)
              for node in nodes:
                  (node.clustered,node.removed)=(False,False)
              for node in nodes:
                  ch = node.children[:]
                  for other in nodes:
                      if other == node or other.clustered or other.removed:
                          continue
                      if ch==other.children:
                          node.mergeWith(other)
                          node.clustered=True
                          other.removed=True
              for node in filter(lambda n:n.removed,nodes):
                  self.nodes.remove(node)
          def __str__(self):
              for i in range(len(self.nodes)):
                  self.nodes[i].name="node%d"%i
              return self.head+"\n".join(map(str,self.nodes))+self.foot                    
              
                  
      usage="""
      php2dot - Génère un script dot des relations d'inclusion entre fichiers PHP
           
      Syntaxe: php2dot startDir
          
        startDir : répertoire de recherche des fichiers PHP.
                   La recherche est récursive.
                   
      Synopsis:
        php2dot startDir > graph.dot
        dot -Tpng -ograph.png graph.dot
        
      Limitation:
        Les noms des fichiers PHP trouvés doivent être distincts
        
      """
              
      if __name__=="__main__":
          if len(sys.argv)==1:
              print usage
              sys.exit(0)
          startDir=sys.argv[1]
          graph = Graph()
          for (dir,name) in find(startDir).phpFiles():
              phpFile = PhpFile(dir,name)
              if not graph[name]:
                  graph.append(Node(name,[name],phpFile.includes()))
          graph.checkChildren()
          graph.removeExcluded()
          graph.clusterize()
          print graph
      
  • # php

    Posté par . Évalué à 1.

    PHP te fournit un truc pas mal en la fonction debug_backtrace.

    print_r ( debug_backtrace ( ) ) ;

    Tu peux aussi regarder du coté des paquet PEAR de deboguage, ça foisonne.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.