Подтвердить что ты не робот

Пакет script для замены коротких открытых тегов PHP <? Php

У меня есть большая коллекция php файлов, написанных на протяжении многих лет, и мне нужно правильно заменить все короткие открытые теги на правильные явные открытые теги.

change "<?" into "<?php"

Я думаю, что это регулярное выражение будет правильно выбирать их:

<\?(\s|\n|\t|[^a-zA-Z])

который заботится о таких случаях, как

<?//
<?/*

но я не уверен, как обрабатывать дерево всей папки и обнаруживать расширение .php файла и применять регулярное выражение и сохранять файл после его изменения.

У меня такое чувство, что это может быть довольно просто, если вы освоите правильные инструменты. (В руководстве sed есть интересный взлом: 4.3 Пример/Переименовать файлы в нижний регистр).

Возможно, я ошибаюсь.
Или, может быть, это может быть oneliner?

4b9b3361

Ответ 1

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

<?
$bla = '?> now what? <?';

безопаснее использовать процессор, который знает о структуре языка. для html это будет xml-процессор; для php, встроенное расширение токенизатора. он имеет T_OPEN_TAG токен парсера, который соответствует <?php, <? или <% и T_OPEN_TAG_WITH_ECHO, который соответствует <?= или <%=. для замены всех коротких открытых тегов вы найдете все эти маркеры и замените T_OPEN_TAG на <?php и T_OPEN_TAG_WITH_ECHO на <?php echo.

реализация остается в качестве упражнения для читателя:)

РЕДАКТИРОВАТЬ 1: ringmaster был настолько добр, чтобы предоставить один.

EDIT 2: в системах с short_open_tag отключен в php.ini, <?, <%, а <?= не будет распознаваться заменой script. чтобы сделать работу script на таких системах, включите short_open_tag через параметр командной строки:

php -d short_open_tag=On short_open_tag_replacement_script.php

p.s. справочная страница для token_get_all() и googleing для творческих комбинаций токенизатора, token_get_all и имен токенов парсера могут помочь.

p.p.s. см. также Regex для анализа содержимого define(), возможно? здесь на SO

Ответ 2

Если вы используете опцию токенизатора, это может быть полезно:

$content = file_get_contents($file);
$tokens = token_get_all($content);
$output = '';

foreach($tokens as $token) {
 if(is_array($token)) {
  list($index, $code, $line) = $token;
  switch($index) {
   case T_OPEN_TAG_WITH_ECHO:
    $output .= '<?php echo ';
    break;
   case T_OPEN_TAG:
    $output .= '<?php ';
    break;
   default:
    $output .= $code;
    break;
  }

 }
 else {
  $output .= $token;
 }
}
return $output;

Обратите внимание, что токенизатор не будет правильно маркировать короткие теги, если короткие теги не включены. То есть вы не можете запустить этот код в системе, где короткие теги не работают. Вы должны запустить его в другом месте, чтобы преобразовать код.

Ответ 3

Это утилита, которую я написал, которая преобразует источник PHP, который содержит короткие открытые теги и заменяет их длинными тегами.

то есть. он преобразует код следующим образом:

  <?= $var1 ?>
  <? printf("%u changes\n",$changes) ?>

Для этого

  <?php echo $var1 ?>
  <?php printf("%u changes\n",$changes) ?>

Параметр - skip-echo-tags заставит его пропускать теги <? = и заменять теги <?.

Он написан как PHP-CLI script и нуждается в файле CLI php.ini, который должен быть установлен для разрешения коротких коротких открытых тегов. Это значение по умолчанию для PHP 5.3.0 и более ранних версий, но оно может не всегда оставаться таким. (script просто ничего не изменит, если параметр не включен.)

Ответ 4

Проблема решена как фиксатор в инструменте php-cs-fixer, который может быть легко установлен и который протестирован и поддерживается.

Фиксирование тогда легко:

$ php-cs-fixer fix --fixers=short_tag --diff --dry-run <path>

Просто замените <path> на путь к каталогу или файлу, который вы хотите изменить. Приведенная команда должна сначала просмотреть параметры (--dry-run и --diff).

Установка выполняется так же просто, как

$ composer global require friendsofphp/php-cs-fixer

если у вас есть композитор, установленный с каталогом глобального каталога композитора в вашем пути (рекомендуется).

Ответ 5

Мой предыдущий ответ, который я только что написал с помощью sed wont work, sed слишком слаб для такого рода вещей IMO.

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

#!/usr/bin/perl 

use strict;
use warnings;

use File::Find::Rule;
use Carp;

my @files = File::Find::Rule->file()->name('*.php')->in('/tmp/foo/bar');

for my $file (@files) {
    rename $file, $file . '.orig';
    open my $output, '>', $file or Carp::croak("Write Error with $file $! [email protected] ");
    open my $input, '<', $file . '.orig'
      or Carp::croak("Read error with $file.orig $! [email protected]");

    while ( my $line = <$input> ) {
        # Replace <?= with <?php echo 
        $line =~ s/<\?=/<?php echo /g;

        # Replace <? ashded  with <?php ashed

        $line =~ s/<\?(?!php|xml)/<?php /g;
        print $output $line;
    }

    close $input  or Carp::carp(" Close error with $file.orig, $! [email protected]");
    close $output or Carp::carp(" Close error with $file  , $! [email protected]");

    unlink $file . '.orig';
}

Но заметьте, я не тестировал это на каком-либо реальном коде, поэтому он мог пойти "Bang".

Я бы порекомендовал вам, что ваш код был изменен (подождите, его уже отредактировано, правильно?.. правильно?) и запустите тестовый пакет (не говорите мне, что у вас нет тестов!) на измененном коде, потому что вы не можете быть уверены в том, что он делает правильные вещи без полноценного парсера FSM.

Ответ 6

Я собираюсь упорядочить ваше регулярное выражение для целей этого в том, что может работать лучше, но я могу ошибаться, так как я не тестировал его ни на одном реальном коде.

Скажем, вы сидите в базовом каталоге вашего кода, вы можете начать с:

find . -iname "*.php" -print0

Это даст вам все .php файлы, разделенные символами NULL, что необходимо, если у любого из них есть пробелы.

find . -iname "*.php" -print0 | xargs -0 -I{} sed -n 's/\(<\?\)\([^a-zA-Z]\)/\1php\2/gp' '{}'

Это должно сделать вам большую часть пути. Он найдет все файлы, затем для каждого из них запустит sed, чтобы заменить код. Однако без тега -i (используется ниже) это фактически не коснется ваших файлов, оно просто отправит ваш код на ваш терминал. Параметр -n подавляет нормальный вывод, а p после того, как часть регулярного выражения сообщает ему, чтобы печатались только строки, которые изменились.

Хорошо, если ваши результаты выглядят правильно, то вы делаете большой шаг, который заменяет файлы на месте. Вы должны обязательно создать резервную копию всех своих файлов, прежде чем пытаться это сделать.

find . -iname "*.php" -print0 | xargs -0 -I{} sed -i 's/\(<\?\)\([^a-zA-Z]\)/\1php\2/g' '{}'

Это должно сделать работу. К сожалению, у меня нет файлов PHP, лежащих вокруг, которые используют этот синтаксис, поэтому вы сами можете понять это, но, надеюсь, механика, когда все будет сделано, немного понятнее:

  • Захватите все файлы с помощью "find"
  • Отправьте этот список файлов на "xargs" (который выполняет некоторую команду по файлам по одному за раз
  • Используйте "sed" и синтаксис /to -change/changed/', чтобы использовать вашу магию регулярных выражений!

Ответ 7

Что моя версия RegExp:

<\?(?!(php|=|xml))(\s|\t|\n)

Ответ 8

Я использовал danorton script почти для 2000 файлов, и он работал как шарм

Я положил его script в файл с именем "fixtags.php" и использовал следующий linux-1 liner для решения проблемы:

find . -iname "*.php" | xargs php fixtags.php --overwrite

Единственная проблема, с которой я столкнулся, - это когда он столкнулся с файлом размером 0 байт.

Ответ 9

Мне пришлось пройти через это раньше, и я нашел, что это лучше всего сделать поэтапно. Плохой script, пытающийся поймать все это может испортить много файлов.

Я использовал Coda (или любой другой веб-редактор), чтобы выполнить простую поиск и замену на очень конкретные строки.

Например, начиная с "

Это может показаться немного более утомительным, но я был уверен, что что-то не запуталось где-то, о чем я не знал. Возвращение - настоящая боль.

Ответ 10

Типично для страниц XML/XHTML включать следующий код:

<?php echo '<?xml version="1.0" encoding="UTF-8" ?>'; ?>

Конечно, это не должно меняться ни к:

<?phpphp echo '<?phpxml version="1.0" encoding="UTF-8" ?>'; ?>

ни

<?php echo '<?phpxml version="1.0" encoding="UTF-8" ?>'; ?>

Ответ 11

К сожалению, автоматические решения могут не работать. Моя рекомендация:

1) Используйте grep, чтобы найти все короткие теги:

grep -rn "<?[^p]" *

2) Пройдите через каждый файл и строку и исправьте вручную

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

Ответ 12

Здесь один perl-вкладыш:

perl -pi -w -e 's/\<\?/\<\?php/g;' *php

Используйте управление версиями для выполнения и решите сохранить изменения или нет.

Ответ 13

PHP 7.4 официально отвергает короткие открытые теги, а PHP 8 полностью их удаляет, поэтому этот вопрос о SO станет несколько популярным, поскольку люди будут искать решения для преобразования унаследованных кодовых баз.

Как уже отмечалось в других ответах, sed не охватывает все варианты использования. Предлагаемый PHP-CS-Fixer full_opening_tag очень похож на свое поведение и не охватывает все варианты использования. Кроме того, по крайней мере один инструмент, который я нашел, такой как один ответ от danorton, в настоящее время работает только при включенных коротких открытых тегах, которые, если вы обновили до PHP 8 через обновление ОС, вы не сможете легко откатиться до 7.x для запуска такого инструменты. Предостережение Emptor очень применимо ко всем этим подходам.

Я написал инструмент, который не зависит от существования коротких открытых тегов (т.е. он работает с PHP 8), не использует регулярные выражения (т.е. он использует token_get_all()), а также избегает коротких открытых тегов (например, <?xml) и другие сценарии без тегов (например, строки PHP, содержащие теги).

https://github.com/cubiclesoft/php-short-open-tag-finder/

Режим по умолчанию, в котором работает инструмент, просто находит ссылки и отображает их. Файлы не изменены.

В режиме -ask, который в настоящее время является единственным режимом, который изменяет файлы, инструмент спрашивает, можно ли заменить каждый набор ссылок для каждого файла отдельно. То есть, если существует 500 файлов с 2 000 ссылок на короткие открытые теги, он будет запрашивать только 500 раз.

Даже с группировкой на уровне файлов инструмент, возможно, слишком осторожен в своем подходе к внесению изменений. Но мы говорим о возможном изменении тысяч файлов в системе за один день. Я не думаю, что полная автоматизация является правильным ответом здесь. Мне потребовалось всего несколько часов, чтобы внимательно изучить каждое изменение, охватывающее несколько тысяч файлов во всех системах, которыми я управляю с помощью инструмента.

У меня довольно большой опыт использования token_get_all() а также написания парсеров токенов.