Есть ли инструмент, который будет разрешать и жестко кодировать каждый включенный файл скрипта PHP? - PullRequest
2 голосов
/ 13 февраля 2010

Мне нужен инструмент, если он существует или вы можете написать менее чем за 5 минут (не хотите тратить время впустую).

Инструмент, о котором идет речь, будет разрешать include, require, include_once и require_once в сценарии PHP и фактически рекурсивно кодировать его содержимое.

Это необходимо для доставки сценариев 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 ?>, а не в комментариях и в строках. Небольшая цель также состоит в том, чтобы иметь возможность обнаруживать dirname(__FILE__)."" в директиве include и фактически соблюдать ее.

Ответы [ 2 ]

2 голосов
/ 14 февраля 2010

Интересная проблема, но она не может быть решена без подробных знаний времени выполнения. Условные включения было бы почти невозможно определить, но если вы сделаете достаточно простых предположений, возможно, будет достаточно чего-то подобного:

<?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'); }
  • Он не проверяет бесконечно рекурсивные включения
  • Он не знает о путях включения
  • и т.д ...

Но даже в таком примитивном состоянии это все еще может быть полезно.

0 голосов
/ 13 февраля 2010

Вы можете использовать встроенную функцию 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 выведет список фактически запущенного скрипта.

Если это ДОЛЖНО быть автономным инструментом, а не выпадением, вы можете прочитать исходный файл, добавить этот код в виде текста, а затем оценить все это (возможно, опасно).

...