20

多年来,我收集了大量的 php 文件,我需要将所有简短的打开标签正确地替换为正确的显式打开标签。

change "<?" into "<?php"

我认为这个正则表达式会正确选择它们:

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

它处理像这样的情况

<?//
<?/*

但我不确定如何处理整个文件夹树并检测 .php 文件扩展名并应用正则表达式并在文件更改后保存文件。

我觉得如果你掌握了正确的工具,这会非常简单。(在 sed 手册中有一个有趣的技巧:4.3 Example/Rename files to lower case)。

也许我错了。
或者也许这可能是一个单线器?


将文本字段的委托属性连接到 IB 中的视图控制器(应该是该视图的文件所有者)。还要在视图控制器标头中注意您符合协议。

或者您可以在视图控制器的 viewDidLoad 方法中将 texfield.delegate 属性设置为 self。

4

13 回答 13

16

不要使用正则表达式来解析形式语言——你总是会遇到你没有预料到的草垛。喜欢:

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

使用了解语言结构的处理器更安全。对于 html,那将是一个 xml 处理器;对于 php,内置分词器扩展。它有T_OPEN_TAG解析器标记,它匹配<?php, <?or <%, and T_OPEN_TAG_WITH_ECHO, 匹配<?=or <%=。要替换所有简短​​的开放标签,您需要找到所有这些标记并替换T_OPEN_TAG<?php和。T_OPEN_TAG_WITH_ECHO<?php echo

该实现留给读者作为练习:)

编辑 1:ringmaster 非常好心地提供了一个

编辑 2:在, ,short_open_tag中关闭的系统上,替换脚本无法识别。要使脚本在此类系统上运行,请通过命令行选项启用:php.ini<?<%<?=short_open_tag

php -d short_open_tag=On short_open_tag_replacement_script.php

ps token_get_all() 的手册页和谷歌搜索tokenizertoken_get_all和解析器令牌名称的创造性组合可能会有所帮助。

pps 另请参阅正则表达式来解析 define() 内容,可能吗?在这里

于 2009-03-26T06:51:39.767 回答
14

如果您使用标记器选项,这可能会有所帮助:

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

请注意,如果未启用短标签,则标记器将无法正确标记短标签。也就是说,您不能在短标签不起作用的系统上运行此代码。您必须在其他地方运行它才能转换代码。

于 2009-10-30T00:44:03.870 回答
9

该问题已作为工具中的修复程序得到解决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 目录的作曲家(推荐)。

于 2016-11-06T13:36:30.410 回答
4

这是我编写的一个实用程序,它可以转换包含短开放标签的 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 及更早版本的默认设置,但可能并不总是如此。(如果未启用该设置,脚本将不会更改任何内容。)

于 2010-10-25T17:31:39.077 回答
3

我之前的回答我只是用 sed 覆盖了,它不起作用,sed 对于这种事情 IMO 来说太弱了。

因此,我编写了一个 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 解析器,就不能确定它会做正确的事。

于 2009-03-26T05:17:14.830 回答
3

那是我的 RegExp 版本:

<\?(?!(php|=|xml))(\s|\t|\n)
于 2010-01-27T03:47:36.187 回答
1

为此,我将简化您的正则表达式,使其效果更好,但我可能错了,因为我没有在任何真实代码上对其进行测试。

假设您坐在代码的基本目录中,您可以从以下内容开始:

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 文件,因此您只能从这里弄清楚,但希望现在完成工作的机制更加清晰:

  1. 使用“查找”获取所有文件
  2. 将该文件列表发送到“xargs”(一次对文件执行一些命令
  3. 使用 "sed" 和语法 's/to-change/changed/' 让你的正则表达式魔法发挥作用!
于 2009-03-26T06:54:43.970 回答
1

我在将近 2000 个文件上使用了 danorton 脚本,它就像一个魅力

我将他的脚本放入一个名为“fixtags.php”的文件中,并使用以下 linux 1 liner 来解决问题:

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

我遇到的唯一问题是当它遇到一个大小为零字节的文件时。

于 2011-12-11T17:59:45.823 回答
1

PHP 7.4 正式弃用了短开放标签,而 PHP 8 完全删除了它们,所以随着人们寻找转换遗留代码库的解决方案,关于 SO 的这个问题将会变得有些流行。

正如其他答案已经指出的那样, sed 并不涵盖所有用例。建议的full_opening_tagPHP-CS-Fixer 的行为与 sed 非常相似,也没有涵盖所有用例。此外,我发现的至少一个工具,例如 danorton 的一个答案,目前仅在启用短打开标签时才有效,如果您通过操作系统升级升级到 PHP 8,则无法轻松回滚到 7.x 来运行此类工具。警告 Emptor 非常适用于所有这些方法。

我写了一个工具,它不依赖于短打开标签的存在(即它适用于 PHP 8),不使用正则表达式(即它使用token_get_all()),并且还避免了非短打开标签(例如<?xml)和其他非-tag 场景(例如,包含“标签”的 PHP 字符串)。

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

该工具运行的默认模式只是查找引用并显示它们。没有文件被修改。

-askmode 中,这是目前唯一修改文件的模式,该工具会询问是否可以根据每个文件替换每组引用。也就是说,如果有 500 个文件,总共有 2000 个短打开标签引用,它只会询问 500 次。

即使使用文件级分组,该工具在进行更改时也可能过于谨慎。但我们谈论的是可能在一天内修改系统上的数千个文件。我不认为完全自动化是正确的答案。我只花了几个小时就仔细考虑了我使用该工具管理的所有系统上数千个文件的每一个更改。

token_get_all()我在使用和编写令牌解析器方面有相当多的经验。

于 2019-04-26T15:21:49.727 回答
0

我以前必须经历过这个,我发现最好分阶段进行。试图捕获所有内容的糟糕脚本可能会弄乱很多文件。

我使用 Coda(或任何其他 Web 编辑器)对非常特定的字符串进行简单的查找和替换。

例如以 " 开头

这可能看起来有点乏味,但我确信在我不知道的地方没有搞砸。回去真的很痛苦。

于 2009-03-26T05:36:02.913 回答
0

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" ?>'; ?>
于 2009-03-26T08:40:57.040 回答
0

不幸的是,自动化解决方案可能不起作用。我的建议:

1)使用 grep 查找所有短标签:

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

2)遍历每个文件和行并手动修复

我知道如果您有一个庞大的项目,这可能不是一个可行的解决方案,但对我来说效果很好。

于 2013-11-26T20:42:48.077 回答
0

当我更新 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

于 2020-06-26T13:02:23.540 回答