数据库中用str_replace替换短码为PHP代码时仅显示源码问题排查
嘿,我来帮你理清这个问题!你现在遇到的核心问题是:你的代码只是把数据库里的PHP代码字符串替换到邮件内容里,但PHP并不会自动执行这些嵌入的字符串代码,所以最终邮件里显示的是原始的PHP代码文本,而不是代码运行后的结果。
问题根源拆解
你用str_replace做的只是纯字符串替换:把[order_date]替换成了date("l jS F Y", strtotime($OrderDate))这个文本串,但PHP不会主动去解析执行这个字符串里的代码逻辑,自然就会直接把这段代码原样显示在邮件里了。
解决方案
下面给你两种可行的解决思路,分别对应直接执行代码(需注意安全)和更安全的短码映射方案:
方案1:执行替换后的PHP代码(快速但有安全风险)
如果一定要保留数据库存PHP代码的方式,你可以用eval来执行这段代码,同时用输出缓冲捕获执行结果:
// Make template substitutions $sqlsub = "SELECT * FROM templates_subs"; $setsub = $link->query($sqlsub); while($rowsub = $setsub->fetch_array(MYSQLI_ASSOC)) { $replacementCode = $rowsub['SubReplacement']; // 开启输出缓冲,捕获代码执行的输出 ob_start(); // 执行代码并输出结果到缓冲 eval("echo $replacementCode;"); // 获取缓冲里的执行结果 $actualReplacement = ob_get_clean(); // 替换模板中的短码 $MessageBody = str_replace($rowsub['SubOriginal'], $actualReplacement, $MessageBody); }
⚠️ 重要安全提醒:eval是非常危险的函数,如果数据库里的SubReplacement字段被注入了恶意代码(比如被攻击者篡改),eval会直接执行这些恶意代码,可能导致服务器被入侵。所以使用这个方案的前提是:只有绝对可信的人员能修改templates_subs表的内容,绝对不能让用户提交的内容进入这个字段。
方案2:短码映射(更安全、易维护)
更推荐的做法是不在数据库里存原始PHP代码,而是存短码对应的标识,然后在代码里统一处理逻辑。这种方式完全避免了eval的安全风险,也更便于维护:
- 先修改数据库的
SubReplacement字段:比如把date("l jS F Y", strtotime($OrderDate))改成order_date(一个简洁的标识)。 - 在代码里定义短码对应的处理逻辑:
// Set fields (StackOverflow example - data from a previous db query) $OrderDate = $row['OrderDate']; $CustomerName = $row['CustomerName']; // 假设你还有其他变量 // 定义短码与处理逻辑的映射 $shortcodeMap = [ 'order_date' => function() use ($OrderDate) { return date("l jS F Y", strtotime($OrderDate)); }, // 可以轻松添加更多短码 'customer_name' => function() use ($CustomerName) { // 用htmlspecialchars防止XSS风险 return htmlspecialchars($CustomerName); } ]; // Get customer order confirmation template $sql = "SELECT DeliveryTemplateSubject, DeliveryTemplateContent FROM delivery_templates WHERE DeliveryTemplateTemplate='1'"; $set = $link->query($sql); $row = $set->fetch_row(); $MessageBody = nl2br($row[1]); // Make template substitutions $sqlsub = "SELECT * FROM templates_subs"; $setsub = $link->query($sqlsub); while($rowsub = $setsub->fetch_array(MYSQLI_ASSOC)) { $shortcodeKey = $rowsub['SubReplacement']; // 如果存在对应的处理逻辑,就执行并替换 if (isset($shortcodeMap[$shortcodeKey])) { $actualReplacement = $shortcodeMap[$shortcodeKey](); $MessageBody = str_replace($rowsub['SubOriginal'], $actualReplacement, $MessageBody); } } // Email customer $subject = $row[0]; mail($CustomerEmail, $subject, $MessageBody);
这种方式的优势在于:所有的执行逻辑都在你的代码控制范围内,数据库里只是存标识,不会有恶意代码执行的风险;后续要修改短码的处理逻辑或者添加新短码,直接修改$shortcodeMap数组即可,非常清晰。
内容的提问来源于stack exchange,提问作者Stuart Pinfold

