PHP项目如何配置站点防盗链?

wen PHP项目 19

本文目录导读:

PHP项目如何配置站点防盗链?

  1. 方式一:服务器层面配置(最高效、最推荐)
  2. 方式二:PHP 代码层面配置(适合无法控制服务器的场景)
  3. 总结建议

在PHP项目中配置防盗链,主要目的是防止其他网站直接引用你的图片、CSS、JS等静态资源,从而节省带宽和服务器资源。

通常有两种主流方式:服务器层面(推荐,最有效)PHP代码层面

服务器层面配置(最高效、最推荐)

这种方式在资源被发送给用户之前就被拦截了,性能开销最小。

Nginx 配置防盗链

Nginx 通过 valid_referers 指令实现,在对应的 server 块或 location 块中添加:

server {
    listen 80;
    server_name yourdomain.com;
    # 对图片、CSS、JS等静态资源进行防盗链
    location ~* \.(gif|jpg|jpeg|png|webp|bmp|ico|svg|css|js|woff|ttf|mp4|zip|rar)$ {
        # 允许的来源域名列表(务必包含你自己的域名)
        valid_referers none blocked server_names
                       *.yourdomain.com        # 允许所有子域名
                       yourdomain.com
                       *.trusted-partner.com;  # 允许合作伙伴域名
        if ($invalid_referer) {
            # 如果来源不在白名单中,返回 403 或重定向到指定图片
            return 403;
            # 或者重定向到你设置的防盗链图片(注意:这个图片不能在防盗链范围内)
            # rewrite ^/.*$ /path/to/deny.jpg break;
        }
    }
    # 或者更简单的写法(推荐,逻辑更清晰)
    location /uploads/ {
        valid_referers none blocked server_names *.yourdomain.com yourdomain.com;
        if ($invalid_referer) {
            return 403;
        }
    }
}

配置解释:

  • none:允许直接通过浏览器地址栏访问(Referer 为空)。
  • blocked:允许 Referer 被隐藏的请求(如某些防火墙)。
  • server_names:允许来自本服务器配置的所有域名。
  • $invalid_referer:如果来源不匹配,则为 true。

生效后需重启/重载 Nginx:

nginx -s reload

Apache 配置防盗链

Apache 使用 mod_rewrite 模块,在 .htaccess 文件或虚拟主机配置中添加:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourpartner.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|bmp|webp|css|js)$ - [F,NC,L]
# 或者返回一张指定的防盗链图(该图片不能在规则范围内)
# RewriteRule \.(jpg|jpeg|png|gif)$ /path/to/deny.jpg [R,L]

注意:需要确保 Apache 开启了 mod_rewrite 且目录允许覆盖(AllowOverride All)。


PHP 代码层面配置(适合无法控制服务器的场景)

如果你的项目托管在虚拟主机或无法修改服务器配置(如 SAE、BAE),可以在 PHP 入口文件(如 index.php)或具体下载文件的 PHP 脚本中处理。

代码示例:通过读取 HTTP_REFERER 头判断

<?php
// 放在需要防盗链的图片/文件处理脚本的最开头,或者全局入口文件
function checkReferer() {
    // 允许的域名列表(务必包含你自己的所有域名,不含 http://)
    $allowed_domains = [
        'yourdomain.com',
        'www.yourdomain.com',
        'cdn.yourdomain.com',
        'localhost', // 本地测试
    ];
    // 获取来源 Referer
    $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
    // 情况1:没有来源(直接访问,例如手机端或命令行直接下载)
    // 如果要求必须携带来源才能访问,可以返回 false,但会导致直接访问被拒
    // 如果需要允许直接访问,解除下面这行的注释(配合图片防盗链通常建议允许直接访问)
    // if (empty($referer)) return true;
    $allowed = false;
    if (!empty($referer)) {
        // 解析 Referer 的域名部分(只保留主机名)
        $referer_host = parse_url($referer, PHP_URL_HOST);
        foreach ($allowed_domains as $domain) {
            // 检查是否完全匹配或属于子域名
            if ($referer_host === $domain || 
                stripos($referer_host, '.' . $domain) !== false) {
                $allowed = true;
                break;
            }
        }
    } else {
        // Referer 为空:根据业务需要决定
        // 某些爬虫或软件不发送 Referer,通常建议返回 true 允许直接访问
        $allowed = true; 
    }
    if (!$allowed) {
        // 阻止访问:显示 403 或跳转到一张警告图片
        header('HTTP/1.1 403 Forbidden');
        // 可选:返回一张指定的防盗链图片(这张图片必须可以被直接访问)
        // header('Location: http://yourdomain.com/deny.jpg');
        // 或者直接输出一段文字
        die('Access Denied: Hotlinking is not allowed.');
    }
}
// 在文件下载脚本或图片展示页面调用
checkReferer();
// --- 以下代码是你的正常业务逻辑 ---
// 
// $file = $_GET['file'];
// readfile($file);

注意事项(重要)

  • HTTP_REFERER 不可伪造?:实际上很容易伪造,所以代码层面防君子不防小人,对于重要的资源(如图片、视频),务必使用服务器层面的配置。
  • 对 CDN 的影响:如果使用了 CDN(如 Cloudflare、阿里云 CDN),需要在 CDN 层面配置防盗链,而不是仅仅在源站配置,否则 CDN 缓存会绕过 Referer 检查。
  • 空 Referer 的处理:浏览器地址栏直接输入、微信/QQ 内置浏览器、某些下载工具(wget/curl 不加 --referer)会发送空 Referer,如果允许这些情况访问,代码里要给 $allowed = true,否则用户无法直接打开你的图片。
  • 性能考虑:如果是高频访问的静态资源(如首页图片),在 PHP 里判断 Referer 会导致服务器产生大量不必要的 PHP 进程开销(即使没在读取图片前就拦截了,PHP 解释器也需要先跑起来)。强烈建议优先使用服务器层面配置

总结建议

场景 推荐方案 原因
自己有服务器权限 Nginx/Apache 配置 零开销,直接由 Web 服务器拦截,不影响 PHP 性能
虚拟主机或 PHP 环境 PHP 代码 + Web服务器配置 先用 PHP 做基础拦截,如果支持 .htaccess 就加上
使用 CDN CDN 防盗链设置 在 CDN 边缘节点拦截,比源站拦截更省流量
仅防百度/谷歌等爬虫 robots.txt + User-Agent 过滤 不需要判断 Referer,robots.txt 可以禁止爬虫直接爬取资源

最后的忠告:防盗链的 HTTP_REFERER 极易被伪造,如果你需要非常强的资源保护(如付费视频、原创高清图),请考虑以下方案:

  1. 加时间戳签名(Nginx 的 secure_link 模块 或 自己写签名逻辑)。
  2. 使用 OSS/CDN 的 Referer 黑白名单 + 空 Referer 拦截
  3. 验证码或登录鉴权(最严格,但用户体验稍差)。

抱歉,评论功能暂时关闭!