我有很多年来编写的大量php文件,我需要将所有短开标签正确替换为正确的显式开放标签.
change "<?" into "<?php"
Run Code Online (Sandbox Code Playgroud)
我认为这个正则表达式将正确选择它们:
<\?(\s|\n|\t|[^a-zA-Z])
Run Code Online (Sandbox Code Playgroud)
照顾像这样的案件
<?//
<?/*
Run Code Online (Sandbox Code Playgroud)
但我不知道如何处理整个文件夹树并检测.php文件扩展名并应用正则表达式并在文件更改后保存.
如果你掌握了正确的工具,我觉得这可以非常简单.(sed手册中有一个有趣的黑客:4.3示例/将文件重命名为小写).
也许我错了.
或许这可能是一个oneliner?
ax.*_*ax. 16
不要使用正则表达式来解析正式语言 - 你总会遇到你没想到的干草堆.喜欢:
<?
$bla = '?> now what? <?';
Run Code Online (Sandbox Code Playgroud)
使用知道语言结构的处理器更安全.对于html,这将是一个xml处理器; 对于php,内置的tokenizer扩展.它有T_OPEN_TAG解析器令牌,匹配<?php,<?或<%,和T_OPEN_TAG_WITH_ECHO,匹配<?=或<%=.替换所有短开的标签,你会发现所有这些令牌和更换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
Run Code Online (Sandbox Code Playgroud)
ps token_get_all()的手册页和googleing for tokenizer,token_get_all和解析器令牌名称的创意组合可能有所帮助.
pps还看到Regex解析define()内容,可能吗?在这里
rin*_*ter 14
如果您使用的是tokenizer选项,这可能会有所帮助:
$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;
Run Code Online (Sandbox Code Playgroud)
请注意,如果未启用短标记,则标记生成器将无法正确标记短标记.也就是说,您无法在短标签不起作用的系统上运行此代码.您必须在其他地方运行它来转换代码.
作为 工具中的固定器,已经解决了该问题,该php-cs-fixer工具可以轻松安装并经过测试和维护。
然后修复很容易:
$ php-cs-fixer fix --fixers=short_tag --diff --dry-run <path>
Run Code Online (Sandbox Code Playgroud)
只需替换<path>为您要更改的目录或文件的路径即可。给定的命令是首先检查(--dry-run 和--diff参数)。
安装就像
$ composer global require friendsofphp/php-cs-fixer
Run Code Online (Sandbox Code Playgroud)
如果您已经在路径中安装了composer并在全局composer bin目录中安装(推荐)。
我之前的答案只是用 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';
}
Run Code Online (Sandbox Code Playgroud)
但请注意,我还没有在任何实际代码上测试过这个,所以它可能会“爆炸”。
我建议你修改你的代码(等等,它已经修改了,对吧?..对吗?)并在修改后的代码上运行你的测试套件(不要告诉我你没有测试!),因为你可以如果没有成熟的 FSM 解析器,不确定它是否做正确的事情。