str_replace适合简单占位符替换,需注意参数顺序、键名匹配及编码问题;复杂逻辑须用preg_replace_callback并限制回调函数;输出前须按上下文(HTML/PDF)做对应转义与清洗。

用 str_replace 做简单占位符替换最直接
多数合同模板只有几十个固定占位符,比如 {customer_name}、{contract_date},这时候别上正则、别搞模板引擎——str_replace 足够快又安全。
常见错误是把键名和值顺序搞反,或者传入非字符串导致静默失败。注意:str_replace 第一个参数是待替换内容(数组或字符串),第二个是替换后的内容,第三个才是原文本。
- 批量替换推荐用数组形式:
str_replace(array_keys($data), array_values($data), $template) - 确保
$data的键全是字符串,且不含正则元字符(它不解析正则,但若键里有/或.等,容易让人误以为要转义) - 如果占位符带空格或换行(如
{ customer_name }),必须让键名完全匹配,建议统一模板规范,而不是在代码里 trim
遇到嵌套逻辑或条件占位符就得换 preg_replace_callback
当合同里出现类似 {if:is_vip}尊贵VIP{else}普通客户{/if} 或 {amount|format_currency} 这类结构时,str_replace 就无能为力了。
用 preg_replace_callback 可以按需执行 PHP 表达式,但风险也高:用户可控的模板里若允许任意回调,等于开放远程代码执行入口。生产环境务必限制可调用函数白名单。
- 正则模式别写成
/\{(.+?)\}/这种宽泛匹配,容易误伤 JSON 或注释;建议锚定前缀,比如/\{\w+:[^\}]+\}/ - 回调函数里对
$matches[0]做trim和前缀识别,再分发到不同处理器,避免一个函数塞满所有逻辑 - 绝对不要用
eval或create_function动态执行用户输入内容
文件路径和编码问题常导致替换后乱码或空白
合同模板通常是 UTF-8 编码的 .docx 拆包 XML 或纯文本 HTML,但 PHP 默认读取可能按 ISO-8859-1 解析,尤其 Windows 服务器上更易出问题。
错误现象包括:中文全变成 ,或整段被跳过(因 BOM 头或非法字节中断 file_get_contents)。
- 读取模板前加
mb_internal_encoding('UTF-8'),并用file_get_contents后立刻检查mb_strlen($content, 'UTF-8') === 0判断是否读取失败 - 如果模板来自上传,确认
$_FILES['file']['tmp_name']对应的文件本身是 UTF-8,不是记事本另存为 ANSI 的“假 UTF-8” - 写入结果时,如果是生成 HTML 合同,响应头必须设
Content-Type: text/html; charset=utf-8,否则浏览器按默认编码渲染
客户数据含特殊字符时,得提前过滤还是留到前端?
比如客户名是 O'Reilly & Co.,直接填进 HTML 模板会破坏结构;填进 PDF 模板又可能触发字体缺失报错。
这不是“该不该转义”的选择题,而是“在哪一层转义”的定位问题:HTML 输出必须 htmlspecialchars,PDF 渲染(如 TCPDF)通常要求原始 UTF-8 字符,但禁止控制字符。
- 数据库取出数据后,先做基础清洗:
trim、str_replace(["\r\n", "\r"], "\n", $str)统一行尾,去掉零宽空格(\xe2\x80\x8b) - HTML 场景下,只在插入到 HTML 属性或文本节点前用
htmlspecialchars($str, ENT_QUOTES, 'UTF-8');别在入库前就转义,否则导出 Excel 或发邮件时还得反转 - PDF 场景下,重点检查是否含不可见控制字符(
preg_match('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', $str)),这类字符 TCPDF 会直接报错退出
动态替换看着简单,真正卡住人的永远是模板来源不可控、客户数据不可信、输出目标不统一这三件事。盯紧编码、过滤点、输出上下文,比选什么高级模板引擎重要得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











