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

发布于 2024-08-21 19:46:09 字数 1754 浏览 6 评论 0原文

我需要一个工具,如果它存在或者你可以在 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

我对脚本做了简单的修改。当我开始自己编写该工具时,我发现我在原始脚本中犯了一个错误。为了完成最少的工作量,包含的文件必须包含在开始和结束标记之外 ()

生成的脚本示例已被修改,但尚未经过测试。

编辑 2

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

我开始编写脚本,并正在读取文件以不智能地解析它们,使其仅包含在 标签中,而不是在注释或字符串中。一个小目标是还能够检测 include 指令中的 dirname(__FILE__)."" 并真正遵守它。

I would need a tool, if it exists or if you can write in under 5 mins (don't want to waste anyone's time).

The tool in question would resolve the includes, requires, include_once and require_once in a PHP script and actually harcode the contents of then, recursively.

This would be needed to ship PHP scripts in one big file that actually use code and resources from multiple included files.

I know that PHP is not the best tool for CLI scripts, but as I'm the most pro-efficient at it, I use it to write some personal or semi-personal tools. I don't want un-helpful answers or comments that tell me to use something else than PHP or learn something else.

The idea of that approach is to be able to have a single file that would represent everything needed to put it in my personal ~/.bin/ directory and let it live there as a completely functional and self-contained script. I know I could set include paths in the script to something that would honor the XDG data directories standards or anything else, but I wanted to try that approach.

Anyway, I ask there because I don't want to re-invent the wheel and all my searches gave nothing, but if I don't have any insight here, I will continue in the way I was going to and actually write a tool that will resolve the includes and requires.

Thanks for any help!

P.S.: I forgot to include examples and don't want to rephrase the message:
Those two files
mainfile.php

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

resource.php

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

Would be "compiled" as (comments added for clarity)

<?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();
?>

The script does not have to output explicit comments, but it could be nice if it did.

Thanks again for any help!

EDIT 1

I made a simple modification to the script. As I have begun writing the tool myself, I have seen a mistake I made in the original script. The included file would have, to do the least amount of work, to be enclosed out of start and end tags (<?php ?>)

The resulting script example has been modified in consequence, but it has not been tested.

EDIT 2

The script does not actually need to do heavy-duty parsing of the PHP script as in run-time accurate parsing. Simple includes only have to be treated (like include('file.php');).

I started working on my script and am reading the file to unintelligently parse them to include only when in <?php ?> tags, not in comments nor in strings. A small goal is to also be able to detect dirname(__FILE__)."" in an include directive and actually honor it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

会傲 2024-08-28 19:46:09

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

<?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);
  }
?>

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

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

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

An interesting problem, but one that's not really solvable without detailed runtime knowledge. Conditional includes would be nearly impossible to determine, but if you make enough simple assumptions, perhaps something like this will suffice:

<?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);
  }
?>

There are many caveats to the above code, some of which can be worked around. (I leave that as an exercise for somebody else.) To name a few:

  • It doesn't honor <?php ?> blocks, so it will match inside HTML
  • It doesn't know about any PHP rules, so it will match inside PHP comments
  • It cannot handle variable includes (e.g., include $foo;)
  • It may introduce scope errors. (e.g., if (true) include('foo.php'); should be if (true) { include('foo.php'); }
  • It doesn't check for infinitely recursive includes
  • It doesn't know about include paths
  • etc...

But even in such a primitive state, it may still be useful.

千秋岁 2024-08-28 19:46:09

您可以使用内置函数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 也会列出实际运行的脚本。

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

You could use the built in function get_included_files which returns an array of, you guessed it, all the included files.

Here's an example, you'd drop this code at the END of mainfile.php and then run mainfile.php.

  $includes = get_included_files();

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

A few things to note:

  • any include which is actually not processed (ie. an include inside a function) will not be dumped into the final file. Only includes which have actually run.
  • This will also have a around each file but you can have multiple blocks like that with no issues inside a single text file.
  • This WILL include anything included within another include.
  • Yes, get_included_files will list the script actually running as well.

If this HAD to be a stand-alone tool instead of a drop in, you could read the inital file in, add this code in as text, then eval the entire thing (possibly dangerous).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文