从Bash脚本修改PHP文件

时间:2012-10-29 09:38:00

标签: php html regex bash parsing

我需要从Bash脚本对PHP文件(确切地说是PHTML文件,但它们仍然是有效的PHP文件)执行一些修改。我最初的想法是使用sed或类似的实用程序与正则表达式,但阅读其他HTML解析问题的一些回复似乎可能有一个更好的解决方案。

我正面对正则表达式的问题是缺乏对检测我想匹配的字符串的支持:(src|href|action)=["']/是否在<?php ?>标签中,以便我可以执行字符串如果匹配在PHP标记中,则串联,或者如果不是,则添加新的PHP标记。例如:

(1) <img id="icon-loader-small" src="/css/images/loader-small.gif" style="vertical-align:middle; display:none;"/>
(2) <li><span class="name"><?php echo $this->loggedInAs()?></span> | <a href="/Login/logout">Logout</a></li>
(3) <?php echo ($watched_dir->getExistsFlag())?"":"<span class='ui-icon-alert'><img src='/css/images/warning-icon.png'></span>"?><span><?php echo $watched_dir->getDirectory();?></span></span><span class="ui-icon ui-icon-close"></span>
(EDIT: 4) <form method="post" action="/Preference/stream-setting" enctype="application/x-www-form-urlencoded" onsubmit="return confirm('<?php echo $this->confirm_pypo_restart_text ?>');">

在(1)中有一个src="/css,因为它不在PHP标签中,我希望它成为src="<?php echo $baseUrl?>/css。在(2)中,有一个PHP标记,但它不在href="/Login附近,因此它也变为href="<?php echo $baseUrl?>/Login。 不幸的是,(3)有src='/css里面 PHP标签(它是一个回显的字符串)。它在PHP代码中也由"引用,因此修改也需要了解它。最终结果类似于:src='".$baseUrl."/css

我的HTML和PHP文件的所有其他修改都是使用正则表达式完成的(我知道,我知道......)。如果正则表达式可以支持匹配除某个模式之外的所有内容,例如[^(<\?php)(\?>)]*,那么我将会飞过这一部分。不幸的是,这似乎是Type 2语法领域。所以 - 我该怎么用? 理想情况下,它需要默认安​​装GNU套件,但其他工具,如PHP本身或其他解释器也很好,只是不喜欢。当然,如果有人可以构建一个适用于上述示例的正则表达式,那么这将是非常好的。

编辑:(4)是令人讨厌的比赛,大多数正则表达式都会失败。

1 个答案:

答案 0 :(得分:3)

我解决这个问题的方法是将我的文件分成封装的部分。该脚本跟踪它当前所处的“上下文” - 默认设置为html,但在点击这些标签时切换到php。然后,对该部分执行操作(不一定是正则表达式),然后将其附加到输出缓冲区。完全处理文件后,输出缓冲区将写回文件。

我尝试用sed做这个,但是我遇到了无法控制打印换行的问题。基于上下文的逻辑也是硬编码的,这意味着添加新的上下文(例如ASP.NET支持)会很繁琐。我当前的解决方案是用Perl编写的并且减轻了这两个问题,虽然我在使用正则表达式实际执行某些操作时遇到了一些麻烦,但这可能只是我错误地编写了我的正则表达式。

脚本如下:

#!/usr/bin/perl -w

use strict;

#Prototypes
sub readFile(;\$);
sub writeFile($);

#Constants
my $file;
my $outputBuffer;
my $holdBuffer;
# Regexes should have s and g modifiers
# Pattern is in $_
my %contexts = (
    html => {
        operation => ''
    },
    php => {
        openTag => '<\?php |<\? ', closeTag => '\?>', operation => ''
    },
    js => {
        openTag => '<script>', closeTag => '<\/script>', operation => ''
    }
);
my $currentContext = 'html';
my $combinedOpenTags;

#Initialisation
unshift(@ARGV, '-') unless @ARGV;
foreach my $key (keys %contexts) {
    if($contexts{$key}{openTag}) {
        if($combinedOpenTags) {
            $combinedOpenTags .= "|".$contexts{$key}{openTag};
        } else {
            $combinedOpenTags = $contexts{$key}{openTag};
        }
    }
}

#Main loop
while(readFile($holdBuffer)) {
    $outputBuffer = '';
    while($holdBuffer) {
        $currentContext = "html";
        foreach my $key (keys %contexts) {
            if(!$contexts{$key}{openTag}) {
                next;
            }
            if($holdBuffer =~ /\A($contexts{$key}{openTag})/) {
                $currentContext = $key;
                last;
            }
        }
        if($currentContext eq "html") {
            $holdBuffer =~ s/\A(.*?)($combinedOpenTags|\z)/$2/s;
            $_ = $1;
        } else {
            $holdBuffer =~ s/\A(.*?$contexts{$currentContext}{closeTag}|\z)//s;
            $_ = $1;
        }
        eval($contexts{$currentContext}{operation});
        $outputBuffer .= $_;
    }
    writeFile($outputBuffer);
}

# readFile: read file into $_
sub readFile(;\$) {
    my $argref = @_ ? shift() : \$_;
    return 0 unless @ARGV;
    $file = shift(@ARGV);
    open(WORKFILE, "<$file") || die("$0: can't open $file for reading ($!)\n");
    local $/;
    $$argref = <WORKFILE>;
    close(WORKFILE);
    return 1;
}

# writeFile: write $_[0] to file
sub writeFile($) {
    open(WORKFILE, ">$file") || die("$0: can't open $file for writing ($!)\n");
    print WORKFILE $_[0];
    close(WORKFILE);
}

我希望其他人可以使用和修改它以满足他们的需求。