【问题标题】:preg_replace causing dollar signs get removedpreg_replace 导致美元符号被删除
【发布时间】:2019-05-31 02:05:01
【问题描述】:

我有一个电子邮件系统,用户在其中写一条消息,它会发送消息。 我刚刚发现的主要问题,考虑这段代码

    $findEmail = $this->Data->field('body', array('id' => 1610));

    //$getUserEmailTemplate will take frm dbase and e.g: 
    //Hi, @@MESSAGE@@. From: StackOverflow
    //It should change @@MESSAGE@@ part to data from $findEmail (in this example is the $74.97 ...)

    $getUserEmailTemplate = $findUser['User']['email_template'];
    $emailMessage = preg_replace('/\B@@MESSAGE@@\B/u', $findEmail, $getUserEmailTemplate);

    debug($findEmail);
    debug($emailMessage);

并为 $findemail 结果的电子邮件考虑此输入:

$74.97
$735.00s

$email 消息将导致:

.97
5.00s

我该如何解决这个问题?我觉得我的 preg_replace 模式有问题。

用户模板可以是任何东西,只要其中有@@MESSAGE@@,那部分就会改成用户消息输入。

谢谢

【问题讨论】:

    标签: php regex string cakephp preg-replace


    【解决方案1】:

    高票函数escape_backreference在一般情况下是不完整的:它只会逃避$n形式的反向引用,而不是${n}\n形式的反向引用。

    要避免任何潜在的反向引用,请更改

        $emailMessage = preg_replace('/\B@@MESSAGE@@\B/u', $findEmail, $getUserEmailTemplate);
    

        $emailMessage = preg_replace('/\B@@MESSAGE@@\B/u', addcslashes($findEmail, '\\$'), $getUserEmailTemplate);
    

    【讨论】:

      【解决方案2】:

      原因如下:

      替换文本的$1 部分代表找到的第一个组/匹配项。因此,如果您有abc 123 并尝试使用preg_match('/([\w]+)-([\d]+)/'),正则表达式将在内部存储$1 = abc$2 = 123 之类的内容。这些变量将存在,即使它们没有价值。

      所以,例如:

      $text = '[shortcode]';
      $replacement = ' some $var $101 text';
      $result = preg_replace('/\[shortcode\]/', $var, $text);
      // returns "some $var 1 text"
      

      由于匹配组$10 为空,将被替换为空字符串。

      这就是为什么您需要在运行 preg_replace 函数之前从您的 REPLACEMENT 文本中转义任何 $NN

      编码愉快。

      【讨论】:

        【解决方案3】:

        预解析替换文本以转义$ 后跟一个数字(请记住,$n 在替换文本中使用时具有特殊含义)。请参阅 php.net 文档页面上的 comment

        如果您的替换文本有可能包含任何字符串,例如 “$0.95”,您需要转义那些 $n 反向引用:

        <?php
          function escape_backreference($x){
            return preg_replace('/\$(\d)/', '\\\$$1', $x);
          }
        ?>
        

        【讨论】:

        • 好的。所以preg_replace 杀死了$
        • 它不会杀死 all $'s,只有 $'s 后跟 0 - 99 之间的数字(反向引用的最大数量),因为有没有这样的子模式,它用一个空字符串代替这些子模式。一个简单的addcslashes($replacestring,'$'); 会处理它。
        • 嗯,你可以,不过这可能有点矫枉过正。 \$ 在替换中没有后跟数字也将是 $ 在结果中,所以,addcslashes 工作正常,可能比提供的替换功能更少的开销(尽管它在技术上更 正确 解决方案)。我评论的主要原因是djot的评论,我对当前的答案没有异议,我投了赞成票。
        • @Wrikken:我不是故意的,我很抱歉。不过,为了减轻进一步的困惑,我将语义更改为更明确一点。 ;-)
        【解决方案4】:

        如果(曾经)有一个模板在 $getUserEmailTemplate 中,你确实用这一行覆盖(销毁)了它;

        $getUserEmailTemplate = "@@MESSAGE@@";
        

        所以只需删除这一行并确保$getUserEmailTemplate 确实包含任何内容,而且最好的是一个模板。

        【讨论】:

        • 也许你最好在这里使用str_replace() ;)
        • 请检查我编辑的描述。这就是模板获取数据的方式
        • 似乎使用 str_replace 解决了问题。我会再测试一些。谢谢
        【解决方案5】:

        猜测您的模板只包含“纯”PHP 并尝试使用 $74 作为变量,该变量不存在且不包含任何数据。所以将模板中的引号改为单引号'

        猜测的模板:

        $tpl = "Sum: $74.97"; //results in "Sum: .97"
        

        修正模板:

        $tpl = 'Sum: $74.97'; //results in "Sum: $74.97"
        

        【讨论】:

        • 我尝试的时候并没有解决问题。从我的代码中,我将其更改为 smtg,例如 $getUserEmailTemplate = '@@MESSAGE@@';它仍然会导致同样的问题。
        • 您的代码不正确,因为您甚至没有模板。您还用电子邮件消息替换消息,即美元;)???
        猜你喜欢
        • 2018-03-22
        • 1970-01-01
        • 1970-01-01
        • 2016-02-09
        • 2021-02-20
        • 2018-07-13
        • 2014-04-07
        • 1970-01-01
        相关资源
        最近更新 更多