ThinkPHP模型修改器_自动将相对路径转为绝对路径【指南】

星枫小哥_8458

星枫小哥_8458

2026-05-11

710人浏览

原创

setxxxattr 不适合处理相对路径转绝对路径,因其不解析html、无请求上下文、在队列/命令行中易失效,且正则易误匹配、硬编码协议致混合内容、误处理协议相对url等。

thinkphp模型修改器_自动将相对路径转为绝对路径【指南】

模型修改器(setXxxAttr)不能安全、可靠地将相对路径转为绝对路径——它不解析 HTML 结构,不感知请求上下文,且在非 HTTP 生命周期中(如队列、命令行)极易失效。

为什么 setXxxAttr 不适合处理相对路径转绝对路径

修改器本质是字段值单向转换函数,输入是原始 POST 数据或程序赋值,输出是写入数据库的字符串。它既不调用 DOM 解析器,也不持有 $this->request 实例(TP6/8 中模型默认无 Request 依赖)。常见翻车点:

  • 直接对富文本字段(如 content)用 preg_replace 匹配 src="xxx":一旦内容含双引号嵌套、HTML 注释、CDATA 或 JS 字符串,正则就误匹配或崩溃;
  • 在 setContentAttr() 里调用 $this->request->domain():命令行执行 php think queue:work 时该对象为 null,触发致命错误;
  • 补全逻辑硬编码 https://:HTTP 站点生成 HTTPS 链接,浏览器主动拦截混合内容;
  • 未校验原始 src 值:把 //cdn.com/a.jpg(协议相对)或 data:image/png;base64,... 也拼上域名,结果变成无效 URL。

真正该用的地方:控制器层 + 专用服务方法

路径补全必须发生在「能安全解析 HTML」+「明确当前请求协议与域名」的环节。推荐在控制器中调用独立服务方法,再传给模型:

示例(TP8):

// app/service/HtmlUrlParser.php
<?php namespace app\service;

use think\Request;

class HtmlUrlParser
{
    protected Request $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function fixImageSrc(string $html): string
    {
        // 使用 DOMDocument 更安全(比正则强一个量级)
        $dom = new \DOMDocument();
        libxml_use_internal_errors(true);
        $dom->loadHTML('<?xml encoding="UTF-8">' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        libxml_clear_errors();

        foreach ($dom->getElementsByTagName('img') as $img) {
            $src = $img->getAttribute('src');
            if (!$src || filter_var($src, FILTER_VALIDATE_URL)) {
                continue; // 已是有效 URL,跳过
            }
            if (str_starts_with($src, '//') || str_starts_with($src, 'data:') || str_starts_with($src, 'javascript:')) {
                continue;
            }

            $base = $this->request->scheme() . '://' . $this->request->host();
            $fixed = rtrim($base, '/') . '/' . ltrim($src, '/');
            $img->setAttribute('src', $fixed);
        }

        return $dom->saveHTML($dom->documentElement);
    }
}

控制器中调用:

btpanel phpsite 宝塔面板PHP网站
btpanel phpsite 宝塔面板PHP网站

宝塔面板 PHP 网站管理:站点创建、删除、启停、PHP 版本切换、域名管理、SSL证书管理、伪静态管理、数据库管理

下载
$data['content'] = app(HtmlUrlParser::class)->fixImageSrc($this->request->post('content'));
$model->save($data); // 此处 save() 不绕过修改器,但 content 已是处理后 HTML

若坚持塞进模型,必须避开 Attr 后缀规则

别用 setContentAttr(),改用普通公共方法,在 save() 前显式调用:

public function fixRelativePaths(): self
{
    if ($this->content) {
        $this->content = $this->parseAndFixHtml($this->content);
    }
    return $this;
}

// 调用方式:
$model->content = $rawContent;
$model->fixRelativePaths()->save();

这样做的好处:

  • 完全规避修改器生命周期限制,$this->request 可安全注入(需在构造时传入或通过容器获取);
  • 方法名语义清晰,不会被框架误认为是自动转换钩子;
  • 便于单元测试,可 mock Request 对象验证补全逻辑;
  • 后续扩展支持 href、background、srcset 等属性更自然。

补全逻辑里三个必须检查的点

无论在哪一层实现,漏掉任意一项都会导致线上图片大面积挂掉:

  • filter_var($src, FILTER_VALIDATE_URL) 必须前置判断——放过已合法 URL,只处理相对路径;
  • 拼接前用 rtrim($base, '/') + ltrim($src, '/'),避免生成 https://a.com//uploads/b.jpg 这类双斜杠 URL;
  • 绝对不要用 $_SERVER['HTTP_HOST'] —— 它可被客户端伪造,应始终走 $this->request->host()(TP 自动过滤)或 $this->request->url(true) 提取可信 host。

最易被忽略的是 DOM 解析环节:不用 DOMDocument 而硬上正则,等于在生产环境埋雷——HTML 复杂度稍高,第一次采集到带内联 SVG 的文章,src 就会消失。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php thinkphp 修改器

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

9984

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

5921

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2075

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3708

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4414

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3451

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

4917

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

3862

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

11842

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
墨刀帮助中心
墨刀帮助中心

共0课时 | 0人学习

MyEclipse学习中心
MyEclipse学习中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习