Пакетный скрипт для замены коротких открытых тегов PHP на ‹? Php

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

change "<?" into "<?php"

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

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

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

<?//
<?/*

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

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

Может я ошибаюсь.
А может это может быть один лайнер?


person Polypheme    schedule 26.03.2009    source источник
comment
Ваш скрипт обрабатывает ‹? = (Эквивалент‹? Php echo)?   -  person Andrew Hedges    schedule 26.03.2009
comment
Нет (насколько я помню), но я думаю, было бы неплохо принять во внимание этот синтаксис, чтобы получить решение, полезное для всех.   -  person Polypheme    schedule 26.03.2009


Ответы (13)


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

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

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

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

ИЗМЕНИТЬ 1: организатор ринга был так любезен с укажите его.

ИЗМЕНИТЬ 2: в системах с short_open_tag выключено в php.ini, <?, <% и <?=, сценарий замены не распознает. чтобы скрипт работал в таких системах, включите short_open_tag через опцию командной строки:

php -d short_open_tag=On short_open_tag_replacement_script.php

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

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

person ax.    schedule 26.03.2009
comment
Вы определенно правы здесь. Мне нужно это проверить. (Хотя я должен сказать, что с трудом представляю, где я хотел бы эхо ‹?, В любом случае не добавляя php) - person Polypheme; 26.03.2009
comment
@Polypheme: ‹? Xml version = 1.0 encoding = UTF-8?› - person Piskvor left the building; 26.03.2009
comment
@Piskvor: да, вы правы, но я позабочусь об этом в регулярном выражении, которое использую. Хорошо, мое замечание в скобках было всего лишь предположением. И я предполагаю, что примерно в 100% случаев my ситуация со строкой не будет проблемой. Тем не менее, маршрут токенов все еще лучше / чище. - person Polypheme; 26.03.2009
comment
Хотя этот процесс, возможно, является лучшей альтернативой использованию регулярного выражения, обратите внимание, что он не работает в системе с отключенными короткими тегами, поскольку токенизатор подчиняется настройкам в php.ini для коротких тегов. - person ringmaster; 30.10.2009
comment
@ringmaster: с отключенными короткими тегами в php.ini вы просто делаете ini_set('short_open_tag', 1) перед вызовом токенизатора, не так ли? - person ax.; 31.10.2009
comment
@ringmaster: ты прав: с ini_set не работает. подумав об этом, это имеет смысл, поскольку этот параметр используется на ранней стадии, на этапе синтаксического анализа, до того, как какой-либо код, включая ini_set, когда-либо будет выполнен. Я думал, что это сработает, потому что это задокументировано как PHP_INI_ALL - очевидно, это ошибка (документации). однако есть способ обойти это: просто установите short_open_tag на On / 1 с помощью параметра командной строки, например: php -d short_open_tag = On test.php, тогда он применяется перед состоянием синтаксического анализа, и ваш сценарий замены тегов работает и в системах с отключенными короткими тегами. - person ax.; 09.11.2009
comment
реализация оставлена ​​в качестве упражнения для читателя :) хотя это интересный вопрос ... на самом деле он не решает никаких проблем .. - person levhita; 04.03.2014
comment
@levhita, пытаясь решить упражнение самостоятельно, делает вас лучше, потому что вы понимаете. просто копирование результатов чужой работы из поиска Google не работает. а также жалобы и отрицательные голоса не являются подсказкой, которая может помочь вам самим себе. - person ax.; 04.03.2014
comment
@ax Боюсь, это место, где можно найти ответы, а не больше вопросов ... хотя здесь есть люди, которые просто узнают, что некоторые из нас занимались этим более десяти лет, и им просто нужно заставить все работать. Все, что вы сказали, абсолютно верно, и я рекомендую себя, когда я преподаю в своем местном университете, просто не подходит для наиболее распространенного пользовательского случая пользователя stackoverflow. - person levhita; 09.04.2014

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

$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;

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

person Community    schedule 30.10.2009
comment
см. мой последний комментарий к пакету stackoverflow.com/questions/684587/, чтобы узнать, как заставить его работать в системах с short_open_tag = Off. - person ax.; 09.11.2009

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

Исправить тогда несложно:

$ php-cs-fixer fix <path> --rules=full_opening_tag,no_short_echo_tag --diff --dry-run

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

Установить php-cs-fixer так же просто, как

$ composer global require friendsofphp/php-cs-fixer

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

person hakre    schedule 06.11.2016
comment
В последней версии php-cs-fixer используется следующий синтаксис: php-cs-fixer fix --rules=full_opening_tag --diff --dry-run . - person marcovtwout; 13.06.2018
comment
Это лучший ответ, особенно если вы используете github.com/squizlabs/PHP_CodeSniffer в качестве линтера для хранения Ваш проект чист на долгий срок. - person btomw; 26.06.2020

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

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

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

К этому

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

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

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

person danorton    schedule 25.10.2010
comment
Обновлено. Спасибо за предупреждение. - person danorton; 04.04.2012
comment
Ссылка снова мертва. Не возражаете обновить его / поместить сценарий в какое-нибудь стабильное место? - person MDCore; 01.12.2013
comment
проблема в том, что этот скрипт не обрабатывает полный каталог, что и было задано вопросом ... и действительно, зачем вам вообще нужен скрипт для этого. - person Brett Thomas; 17.08.2016
comment
Для обработки всех файлов в текущем каталоге вы можете использовать php php_replace_short_tags.php --overwrite * (это перезаписывает файлы), и если вы хотите, чтобы это было рекурсивно, это решение может помочь: github.com/danorton/php_replace_short_tags/issues/4 - person Sebastian; 08.11.2018
comment
<?= не является коротким открытым тегом и не является устаревшим; таким образом не будет удален - person zanderwar; 07.05.2020

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

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

#!/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 $! $@ ");
    open my $input, '<', $file . '.orig'
      or Carp::croak("Read error with $file.orig $! $@");

    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, $! $@");
    close $output or Carp::carp(" Close error with $file  , $! $@");

    unlink $file . '.orig';
}

Но обратите внимание, я не тестировал это ни на каком реальном коде, так что это могло произойти «Взрыв».

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

person Kent Fredric    schedule 26.03.2009
comment
ммм, это не сделает мой сайт нечетким, если у меня есть встроенные коды вроде ‹? = $ printme;?› ??? - person lock; 26.03.2009
comment
Спасибо, Кент Фредрик, это дает мне представление о том, как связать результаты поиска и команду sed. Но боюсь, что мы еще не достигли цели. - person Polypheme; 26.03.2009
comment
Вероятно, вам удастся использовать функцию glob() вместо File :: Find :: Rule. Он должен делать то же самое на меньшем пространстве. - person Chris Lutz; 26.03.2009
comment
Я мог бы использовать glob, но glob может делать странные вещи, когда в именах файлов есть пробелы. В наши дни для Modern Perl рекомендуется использовать File :: Find :: Rule, насколько я могу понять, это кратко и содержательно (не говоря уже о фильтрах каталогов;)) - person Kent Fredric; 26.03.2009
comment
[P.s. Я попытался применить здесь свои знания о передовых методах, чтобы сделать код хорошим, легким для понимания и легким в сопровождении, в отличие от игры в гольф:)] - person Kent Fredric; 26.03.2009
comment
Я не могу представить, чтобы многие каталоги заканчивались на .php. Обычно я не называю файлы (особенно программные) пробелами, но я понимаю, что это серьезная проблема. - person Chris Lutz; 26.03.2009
comment
Да, этот новый скрипт кажется лучше, хотя он конвертирует ‹? Xml в‹? Phpxml, поэтому я по-прежнему предпочитаю свое регулярное выражение: $ line = ~ s / ‹\? (\ S | \ n | \ t | [^ a-zA -Z]) / ‹? Php $ 1 / г; - person Polypheme; 26.03.2009
comment
Ну да, я утверждал, что вы не можете быть уверены, что он делает правильные вещи без анализатора FSM. Я полностью осознаю трудности со струнами. - person Kent Fredric; 26.03.2009
comment
Кроме того, мой случай был адаптирован так, что он будет обрабатывать строки xml внутри php, предполагая, что они смежные. - person Kent Fredric; 26.03.2009
comment
Пока что мои тесты с вашим сценарием положительные. Даже в сложных случаях. - person Polypheme; 27.03.2009

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

<\?(?!(php|=|xml))(\s|\t|\n)
person Thiago Belem    schedule 27.01.2010

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

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

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

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

person ActionJackson    schedule 11.12.2011
comment
Я использовал: php -d short_open_tag=On ~/scripts/replace_short_tags.php --overwrite *.php в каталоге со всеми проблемными скриптами .. - person Grizly; 09.01.2015

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

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

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

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

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

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

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

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

person CubicleSoft    schedule 26.04.2019

Страницы 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" ?>'; ?>
person vartec    schedule 26.03.2009
comment
Конечно. Регулярное выражение, которое я предложил в своем вопросе, позаботится об этом. У Кента Федрича также есть рабочее регулярное выражение. И топор тоже должен подойти. - person Polypheme; 26.03.2009

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

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

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

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

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

person Bjørn Børresen    schedule 26.11.2013

У меня была такая же проблема при обновлении версии php.

Использовать это:

find . -iname "\*.ph\*" -type f -print0 |xargs -0 sed -i -e 's/<? /<?php /g' -e 's/<?\/\//<?php \/\//g' -e 's/<?\/\*/<?php \/\*/g' -e 's/<?\=/<?php echo/g'

Это преобразует ‹? в ‹? php,‹? // в ‹? php //,‹? / в ‹? php /

для любого файла .php или .phtml

Кредиты: https://coderwall.com/p/cnm0_w/replace-php-short-open-tags-with-full-form-in-all-php-files-using-one-command

person user2662006    schedule 26.06.2020

person    schedule
comment
Спасибо за четкие объяснения, я обязательно воспользуюсь этим для решения некоторых других проблем! - person Polypheme; 26.03.2009

person    schedule
comment
Если возвращение - настоящая боль, вам нужен надлежащий контроль версий. Не должно быть. - person derobert; 26.03.2009
comment
Это то, что я сделал, совершил git, тогда я хотел бы использовать скрипт. (Кейт выполнила свою работу, как вы сказали, он поддерживает поиск в файлах, а затем заменяет регулярное выражение по одному файлу за раз) - person Polypheme; 26.03.2009
comment
@derobert - Верно. В то время у меня их не было. Теперь у меня настоящая зависимость от SVN. - person Paulo; 26.03.2009