是否有任何工具可以解析和硬编码PHP脚本的每个包含文件?

时间:2010-02-13 14:26:48

标签: php include resolve

我需要一个工具,如果它存在或者你可以写不到5分钟(不想浪费任何人的时间)。

有问题的工具将解析PHP脚本中的includes,requires,include_once和require_once,并实际上以递归方式对其内容进行编码。

这需要将PHP脚本发送到一个大文件中,该文件实际上使用来自多个包含文件的代码和资源。

知道 PHP不是CLI脚本的最佳工具,但由于我是最有效率的,我用它来编写一些个人或半个人工具。 我不希望无用的答案或评论告诉我使用除PHP以外的其他内容或了解其他内容

这种方法的想法是能够拥有一个单独的文件,代表将其放入我的个人~/.bin/目录所需的所有内容,并让它作为一个功能齐全且自包含的脚本存在。我知道我可以在脚本中设置包含路径,以符合XDG数据目录标准或其他任何东西,但我想尝试这种方法。

无论如何,我问那里因为我不想重新发明轮子而且我的所有搜索都没有给出任何东西,但是如果我在这里没有任何见解,我会继续按照我去的方式进行编写一个可以解决包含和要求的工具。

感谢您的帮助!

P.S。:我忘记包含示例,并且不想重述消息: 那两个文件
mainfile.php

<?php
    include('resource.php');
    include_once('resource.php');
    echo returnBeef();
?>

resource.php

<?php
    function returnBeef() {
        return "The beef!";
    }
?>

将“编译”为(为了清晰起见而添加注释)

<?php

    /* begin of include('resource.php'); */?><?php
    function returnBeef() {
        return "The beef!";
    }
    ?><?php /* end of include('resource.php); */
    /*
    NOT INCLUDED BECAUSE resource.php WAS PREVIOUSLY INCLUDED 
    include_once('resource.php'); 
    */
    echo returnBeef();
?>

脚本不必输出显式注释,但如果确实如此,则可能很好。

再次感谢您的帮助!

编辑1

  

我对脚本做了一个简单的修改。当我自己开始编写该工具时,我看到我在原始脚本中犯了一个错误。包含的文件最少量工作将包含在开始和结束标记之外(<?php ?>

     

结果脚本示例已被修改,但尚未经过测试。

编辑2

该脚本实际上不需要像运行时准确的解析那样对PHP脚本进行繁重的解析。简单包含只需要处理(如include('file.php');)。

我开始处理我的脚本并且正在阅读文件以便无情地解析它们,以便仅在<?php ?>标记中包含,而不是在注释或字符串中。一个小目标是还能够在include指令中检测dirname(__FILE__).""并实际遵守它。

2 个答案:

答案 0 :(得分:2)

一个有趣的问题,但如果没有详细的运行时知识,这个问题就无法解决。条件包含几乎不可能确定,但​​如果你做了足够简单的假设,也许这样的东西就足够了:

<?php
  # import.php 
  #
  # Usage:
  # php import.php basefile.php
  if (!isset($argv[1])) die("Invalid usage.\n");

  $included_files = array();

  echo import_file($argv[1])."\n";

  function import_file($filename)
  {
    global $included_files;

    # this could fail because the file doesn't exist, or
    # if the include path contains a run time variable
    # like include($foo);
    $file = @file_get_contents($filename);
    if ($file === false) die("Error: Unable to open $filename\n");

    # trimming whitespace so that the str_replace() at the end of 
    # this routine works. however, this could cause minor problems if
    # the whitespace is considered significant
    $file = trim($file);

    # look for require/include statements. Note that this looks
    # everywhere, including non-PHP portions and comments!
    if (!preg_match_all('!((require|include)(_once)?)\\s*\\(?\\s*(\'|")(.+)\\4\\s*\\)?\\s*;!U', $file, $matches, PREG_SET_ORDER |  PREG_OFFSET_CAPTURE ))
    {
      # nothing found, so return file contents as-is
      return $file;
    }

    $new_file = "";
    $i = 0;
    foreach ($matches as $match)
    {
      # append the plain PHP code up to the include statement 
      $new_file .= substr($file, $i, $match[0][1] - $i);

      # make sure to honor "include once" files
      if ($match[3][0] != "_once" || !isset($included_files[$match[5][0]]))
      {
         # include this file
         $included_files[$match[5][0]] = true;
         $new_file .= ' ?>'.import_file($match[5][0]).'<?php ';
      }

      # update the index pointer to where the next plain chunk starts
      $i = $match[0][1] + strlen($match[0][0]);
    }

    # append the remainder of the source PHP code
    $new_file .= substr($file, $i);

    return str_replace('?><?php', '', $new_file);
  }
?>

上面的代码有很多警告,其中一些可以解决。 (我将其留作其他人的练习。)仅举几例:

  • 它不支持<?php ?>块,因此它将匹配HTML内部
  • 它不知道任何PHP规则,因此它将匹配PHP内部评论
  • 它无法处理变量包含(例如include $foo;
  • 可能会引入范围错误。 (例如,if (true) include('foo.php');应为if (true) { include('foo.php'); }
  • 它不会检查无限递归包含
  • 它不知道包含路径
  • 等...

但即使在这种原始状态下,它仍然可能有用。

答案 1 :(得分:0)

您可以使用内置函数get_included_files,它返回所有包含文件的数组,您猜对了。

以下是一个示例,您将此代码放在mainfile.php的END处,然后运行mainfile.php。

  $includes = get_included_files();

  $all = "";
  foreach($includes as $filename) {
    $all .= file_get_contents($filename);
  }
  file_put_contents('all.php',$all);

有几点需要注意:

  • 任何实际未处理的包含(即函数内的包含)都不会被转储到最终文件中。只包括实际运行的那些。
  • 这也将包含每个文件,但您可以拥有多个这样的块,在单个文本文件中没有任何问题。
  • 这将包括另一个包含的内容。
  • 是的,get_included_files将列出实际运行的脚本。

如果这个HAD是一个独立的工具而不是插入,你可以阅读inital文件,将这段代码添加为文本,然后评估整个事情(可能是危险的)。