2

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

有问题的工具将解决 PHP 脚本中的 include、requires、include_once 和 require_once,并实际上递归地对 then 的内容进行编码。

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

知道PHP 不是 CLI 脚本的最佳工具,但由于我最擅长使用它,所以我用它来编写一些个人或半个人工具。我不想要那些告诉我使用 PHP 以外的东西或学习其他东西的无用答案或评论

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

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

谢谢你的帮助!

PS:我忘记包含示例并且不想改写消息:这两个文件
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 ?>标签中包含它们,而不是在注释中或字符串中。一个小目标是也能够dirname(__FILE__).""在包含指令中检测并实际尊重它。

4

2 回答 2

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'); }
  • 它不检查无限递归包含
  • 它不知道包含路径
  • ETC...

但即使在如此原始的状态下,它可能仍然有用。

于 2010-02-14T01:35:28.527 回答
0

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

这是一个示例,您可以将此代码放在 mainfile.php 的末尾,然后运行 ​​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也会列出实际运行的脚本。

如果这个必须是一个独立的工具而不是一个插件,你可以读入初始文件,将此代码作为文本添加,然后评估整个事情(可能很危险)。

于 2010-02-13T14:56:19.300 回答