PHP项目视频防盗链如何代码实现拦截

wen PHP项目 24

本文目录导读:

PHP项目视频防盗链如何代码实现拦截

  1. 基于Referer验证
  2. Token验证机制
  3. 时间戳防盗链
  4. 完整示例 - 视频播放器防盗链
  5. Nginx配合使用
  6. 数据库存储验证
  7. 使用建议:

我来介绍几种PHP视频防盗链的实现方法:

基于Referer验证

<?php
class VideoAntiHotlink {
    // 允许的域名列表
    private $allowedDomains = [
        'www.yourdomain.com',
        'yourdomain.com',
        'cdn.yourdomain.com'
    ];
    // 检查Referer
    public function checkReferer() {
        if (!isset($_SERVER['HTTP_REFERER'])) {
            // 直接访问,拒绝
            $this->blockAccess();
            return false;
        }
        $referer = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
        // 检查是否在允许列表中
        foreach ($this->allowedDomains as $domain) {
            if (strpos($referer, $domain) !== false) {
                return true;
            }
        }
        // 不符合条件,拒绝访问
        $this->blockAccess();
        return false;
    }
    // 阻止访问
    private function blockAccess() {
        header('HTTP/1.0 403 Forbidden');
        header('Content-Type: application/json');
        $response = [
            'status' => 'error',
            'message' => 'Access denied'
        ];
        echo json_encode($response);
        exit;
    }
}
?>

Token验证机制

<?php
class TokenAntiHotlink {
    private $secretKey = 'your-secret-key-here';
    private $tokenExpire = 3600; // Token有效期(秒)
    // 生成访问令牌
    public function generateToken($videoId, $userId = '') {
        $timestamp = time();
        $data = [
            'video_id' => $videoId,
            'user_id' => $userId,
            'timestamp' => $timestamp,
            'expire' => $timestamp + $this->tokenExpire
        ];
        $token = base64_encode(json_encode($data));
        $signature = $this->generateSignature($token);
        return [
            'token' => $token,
            'signature' => $signature,
            'expire_time' => $data['expire']
        ];
    }
    // 验证访问令牌
    public function validateToken($token, $signature) {
        // 验证签名
        if (!$this->verifySignature($token, $signature)) {
            return ['valid' => false, 'message' => 'Invalid signature'];
        }
        // 解码token
        $data = json_decode(base64_decode($token), true);
        // 检查是否过期
        if (time() > $data['expire']) {
            return ['valid' => false, 'message' => 'Token expired'];
        }
        return ['valid' => true, 'data' => $data];
    }
    // 生成签名
    private function generateSignature($token) {
        return md5($token . $this->secretKey);
    }
    // 验证签名
    private function verifySignature($token, $signature) {
        return $this->generateSignature($token) === $signature;
    }
    // 获取视频流
    public function serveVideo($videoPath, $token, $signature) {
        $result = $this->validateToken($token, $signature);
        if (!$result['valid']) {
            header('HTTP/1.0 403 Forbidden');
            echo json_encode($result);
            exit;
        }
        // 检查视频文件是否存在
        if (!file_exists($videoPath)) {
            header('HTTP/1.0 404 Not Found');
            echo json_encode(['status' => 'error', 'message' => 'Video not found']);
            exit;
        }
        // 设置适当的响应头
        header('Content-Type: video/mp4');
        header('Content-Length: ' . filesize($videoPath));
        header('Content-Disposition: inline; filename="' . basename($videoPath) . '"');
        header('Accept-Ranges: bytes');
        header('Cache-Control: no-cache, must-revalidate');
        // 输出视频内容
        readfile($videoPath);
        exit;
    }
}
?>

时间戳防盗链

<?php
class TimestampAntiHotlink {
    private $privateKey = 'your-private-key';
    private $expireTime = 1800; // 30分钟
    // 生成带时间戳的URL
    public function generateUrl($videoUrl) {
        $timestamp = time() + $this->expireTime;
        $hash = md5($videoUrl . $timestamp . $this->privateKey);
        $params = [
            't' => $timestamp,
            'h' => $hash
        ];
        $separator = (strpos($videoUrl, '?') === false) ? '?' : '&';
        return $videoUrl . $separator . http_build_query($params);
    }
    // 验证时间戳URL
    public function validateUrl() {
        $timestamp = isset($_GET['t']) ? $_GET['t'] : 0;
        $hash = isset($_GET['h']) ? $_GET['h'] : '';
        // 检查是否过期
        if ($timestamp < time()) {
            return ['valid' => false, 'message' => 'Link expired'];
        }
        // 验证哈希值
        $currentUrl = $this->getCurrentUrl();
        $expectedHash = md5($currentUrl . $timestamp . $this->privateKey);
        if ($hash !== $expectedHash) {
            return ['valid' => false, 'message' => 'Invalid hash'];
        }
        return ['valid' => true];
    }
    // 获取当前URL(不含参数)
    private function getCurrentUrl() {
        $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
        $host = $_SERVER['HTTP_HOST'];
        $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        return $protocol . $host . $path;
    }
}
?>

完整示例 - 视频播放器防盗链

<?php
// video_player.php - 视频播放页面
session_start();
require_once 'AntiHotlink.php';
$videoId = isset($_GET['video_id']) ? $_GET['video_id'] : 0;
$tokenHandler = new TokenAntiHotlink();
// 生成视频访问令牌
$tokenData = $tokenHandler->generateToken($videoId, $_SESSION['user_id'] ?? 'guest');
?>
<!DOCTYPE html>
<html>
<head>Video Player</title>
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
    <video id="videoPlayer" controls width="800">
        <source id="source" type="video/mp4">
    </video>
    <script>
        const videoPlayer = document.getElementById('videoPlayer');
        const source = document.getElementById('source');
        // 生成带token的视频URL
        const videoUrl = `serve_video.php?video_id=<?php echo $videoId; ?>&token=<?php echo urlencode($tokenData['token']); ?>&signature=<?php echo $tokenData['signature']; ?>`;
        // 检查是否支持HLS
        if (Hls.isSupported()) {
            const hls = new Hls();
            hls.loadSource(videoUrl);
            hls.attachMedia(videoPlayer);
        } else if (videoPlayer.canPlayType('application/vnd.apple.mpegurl')) {
            videoPlayer.src = videoUrl;
        } else {
            source.src = videoUrl;
            videoPlayer.load();
        }
    </script>
</body>
</html>
<?php
// serve_video.php - 视频服务脚本
require_once 'AntiHotlink.php';
$tokenHandler = new TokenAntiHotlink();
$videoId = isset($_GET['video_id']) ? $_GET['video_id'] : 0;
$token = isset($_GET['token']) ? $_GET['token'] : '';
$signature = isset($_GET['signature']) ? $_GET['signature'] : '';
// 获取视频实际路径
$videoPath = getVideoPath($videoId); // 自定义函数
// 验证并服务视频
$tokenHandler->serveVideo($videoPath, $token, $signature);
?>

Nginx配合使用

# nginx.conf 配置
location /videos/ {
    # 防盗链配置
    valid_referers none blocked www.yourdomain.com yourdomain.com;
    if ($invalid_referer) {
        return 403;
    }
    # 限制访问方法
    limit_except GET {
        deny all;
    }
    # 缓存配置
    expires 7d;
    add_header Cache-Control "public, no-transform";
}

数据库存储验证

<?php
class DatabaseAntiHotlink {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    // 记录视频访问日志
    public function logAccess($videoId, $userId, $ip) {
        $stmt = $this->db->prepare("
            INSERT INTO video_access_logs 
            (video_id, user_id, ip_address, access_time) 
            VALUES (?, ?, ?, NOW())
        ");
        return $stmt->execute([$videoId, $userId, $ip]);
    }
    // 检查访问频率限制
    public function checkRateLimit($ip, $limit = 100, $period = 3600) {
        $stmt = $this->db->prepare("
            SELECT COUNT(*) as count 
            FROM video_access_logs 
            WHERE ip_address = ? 
            AND access_time > DATE_SUB(NOW(), INTERVAL ? SECOND)
        ");
        $stmt->execute([$ip, $period]);
        $result = $stmt->fetch();
        return $result['count'] < $limit;
    }
    // 用户权限验证
    public function checkUserPermission($userId, $videoId) {
        $stmt = $this->db->prepare("
            SELECT id FROM user_permissions 
            WHERE user_id = ? 
            AND (video_id = ? OR video_id IS NULL)
            AND expire_time > NOW()
        ");
        $stmt->execute([$userId, $videoId]);
        return $stmt->fetch() !== false;
    }
}
?>

使用建议:

  1. 多层防护:组合使用多种防盗链机制
  2. 定期更新:定期更换密钥和配置
  3. 日志监控:记录异常访问行为
  4. 性能优化:使用CDN配合防盗链
  5. 兼容性:考虑各种浏览器和播放器

这些方法可以有效防止视频资源被盗链,建议根据实际需求选择适合的方案。

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