怎么解决php采集文章图片不显示

发布时间:2021-10-19 09:32:18 作者:iii
阅读:187
PHP开发者专用服务器,限时0元免费领! 查看>>
# 怎么解决PHP采集文章图片不显示

## 前言

在网站开发过程中,我们经常需要通过PHP采集其他网站的文章内容。然而,采集到的文章中的图片经常会遇到不显示的问题。这个问题可能由多种原因引起,包括图片路径问题、防盗链机制、服务器配置等。本文将详细分析PHP采集文章图片不显示的常见原因,并提供全面的解决方案。

## 目录

1. [问题概述](#问题概述)
2. [常见原因分析](#常见原因分析)
   - [相对路径问题](#相对路径问题)
   - [防盗链机制](#防盗链机制)
   - [HTTPS/HTTP混合内容](#httpshttp混合内容)
   - [图片服务器限制](#图片服务器限制)
   - [编码问题](#编码问题)
3. [解决方案](#解决方案)
   - [路径转换与修正](#路径转换与修正)
   - [图片下载与本地化](#图片下载与本地化)
   - [处理防盗链](#处理防盗链)
   - [解决混合内容问题](#解决混合内容问题)
   - [编码转换](#编码转换)
4. [实战代码示例](#实战代码示例)
   - [简单的图片采集处理](#简单的图片采集处理)
   - [完整的图片本地化方案](#完整的图片本地化方案)
   - [处理防盗链的高级方法](#处理防盗链的高级方法)
5. [性能优化与注意事项](#性能优化与注意事项)
   - [异步处理](#异步处理)
   - [缓存机制](#缓存机制)
   - [错误处理](#错误处理)
   - [法律风险](#法律风险)
6. [总结](#总结)

## 问题概述

当使用PHP采集其他网站的文章内容时,图片不显示是一个常见问题。用户可能会遇到以下几种情况:

1. 图片完全无法加载,显示为空白或占位符
2. 部分图片可以显示,部分不能显示
3. 在开发环境可以显示,但在生产环境无法显示
4. 直接访问图片URL可以显示,但在采集的内容中无法显示

这些问题不仅影响用户体验,还可能导致网站内容质量下降。下面我们将深入分析这些问题的原因,并提供相应的解决方案。

## 常见原因分析

### 相对路径问题

**问题描述**:采集到的内容中,图片使用的是相对路径(如`/images/photo.jpg`),而你的网站域名与原网站不同,导致浏览器无法正确解析图片路径。

**影响**:这是最常见的图片不显示原因之一,特别是在采集内容时没有对图片路径进行转换的情况下。

**识别方法**:检查采集到的HTML代码,查看图片的src属性是否是相对路径或缺少协议和域名的绝对路径。

### 防盗链机制

**问题描述**:许多网站会设置防盗链(Hotlink Protection),只允许特定来源的请求访问图片资源。当你的网站尝试直接引用这些图片时,服务器会返回403禁止访问或重定向到错误图片。

**影响**:图片无法加载,或者加载的是防盗链提示图片。

**识别方法**:直接访问图片URL可以显示,但在采集的内容中无法显示;或者检查网络请求返回的HTTP状态码是否为403。

### HTTPS/HTTP混合内容

**问题描述**:如果你的网站使用HTTPS,而采集的图片使用HTTP协议,现代浏览器可能会阻止加载这些"不安全"的内容。

**影响**:在控制台会看到混合内容警告,图片无法显示。

**识别方法**:浏览器开发者工具的控制台中会有相关警告信息,图片URL以http://开头。

### 图片服务器限制

**问题描述**:某些网站会对图片访问进行限制,如:
- 限制User-Agent
- 限制Referer
- 需要Cookie验证
- 请求频率限制

**影响**:图片请求被拒绝或返回错误。

**识别方法**:查看网络请求的请求头和响应状态码,对比直接访问和通过你的网站访问的区别。

### 编码问题

**问题描述**:采集的内容编码与你的网站编码不一致,导致图片URL中的特殊字符被错误解析。

**影响**:图片URL不正确,无法加载。

**识别方法**:图片URL中包含中文或特殊字符,显示为乱码或编码错误的形式。

## 解决方案

### 路径转换与修正

**完整URL转换**:将采集内容中的所有相对路径转换为完整URL。

```php
function convertRelativeToAbsoluteUrls($content, $baseUrl) {
    $base = parse_url($baseUrl);
    $baseHost = $base['scheme'] . '://' . $base['host'];
    
    // 处理没有协议开头的URL(如//example.com/image.jpg)
    $content = preg_replace('/src="\/\/([^"]+)"/', 'src="https://$1"', $content);
    
    // 处理相对路径
    $content = preg_replace('/src="\/([^"]+)"/', 'src="' . $baseHost . '/$1"', $content);
    $content = preg_replace('/src="([^\/"][^"]+)"/', 'src="' . $baseHost . '/' . dirname($base['path']) . '/$1"', $content);
    
    return $content;
}

协议自适应:自动将HTTP转换为HTTPS,避免混合内容问题。

function convertHttpToHttps($content) {
    return preg_replace('/http:\/\/([^"]+)/', 'https://$1', $content);
}

图片下载与本地化

本地化优势: - 避免原图删除导致图片丢失 - 解决防盗链问题 - 提高加载速度(可配合CDN) - 避免混合内容问题

基本流程: 1. 解析HTML,提取所有图片URL 2. 下载图片到本地服务器 3. 替换HTML中的图片链接为本地路径 4. 可选:将图片上传到云存储

function downloadAndReplaceImages($content, $baseUrl, $savePath = '/uploads/remote_images/') {
    $dom = new DOMDocument();
    @$dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'));
    
    $images = $dom->getElementsByTagName('img');
    
    foreach ($images as $img) {
        $originalSrc = $img->getAttribute('src');
        $absoluteUrl = convertToAbsoluteUrl($originalSrc, $baseUrl);
        
        try {
            $localPath = downloadImage($absoluteUrl, $savePath);
            $img->setAttribute('src', $localPath);
        } catch (Exception $e) {
            // 下载失败,可以选择保留原链接或移除图片
            error_log("Failed to download image: " . $absoluteUrl . " - " . $e->getMessage());
        }
    }
    
    return $dom->saveHTML();
}

function downloadImage($url, $savePath) {
    $pathInfo = pathinfo(parse_url($url, PHP_URL_PATH));
    $extension = isset($pathInfo['extension']) ? $pathInfo['extension'] : 'jpg';
    $filename = md5($url) . '.' . $extension;
    $fullPath = $_SERVER['DOCUMENT_ROOT'] . $savePath . $filename;
    
    // 如果已存在则直接返回
    if (file_exists($fullPath)) {
        return $savePath . $filename;
    }
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
    $imageData = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    if ($httpCode != 200 || !$imageData) {
        throw new Exception("Failed to download image. HTTP Code: " . $httpCode);
    }
    
    // 确保目录存在
    if (!file_exists($_SERVER['DOCUMENT_ROOT'] . $savePath)) {
        mkdir($_SERVER['DOCUMENT_ROOT'] . $savePath, 0755, true);
    }
    
    file_put_contents($fullPath, $imageData);
    
    return $savePath . $filename;
}

处理防盗链

方法1:伪造Referer

function getImageWithReferer($url, $referer) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_REFERER, $referer);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}

方法2:使用代理服务器

function getImageWithProxy($url, $proxy) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_PROXY, $proxy);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}

方法3:设置自定义Header

function getImageWithCustomHeaders($url) {
    $headers = [
        'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language: en-US,en;q=0.5',
        'Connection: keep-alive',
        'Upgrade-Insecure-Requests: 1',
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}

解决混合内容问题

方案1:强制使用HTTPS

function forceHttps($content) {
    return preg_replace('/http:\/\/([^"\']+)/i', 'https://$1', $content);
}

方案2:使用协议相对URL

function makeProtocolRelative($content) {
    return preg_replace('/https?:\/\/([^"\']+)/i', '//$1', $content);
}

编码转换

统一编码处理

function fixEncodingIssues($content) {
    // 转换内容编码为UTF-8
    $content = mb_convert_encoding($content, 'UTF-8', 'auto');
    
    // 处理URL编码问题
    $content = preg_replace_callback('/src="([^"]+)"/', function($matches) {
        $url = $matches[1];
        $parts = parse_url($url);
        
        if (isset($parts['path'])) {
            $pathParts = explode('/', $parts['path']);
            foreach ($pathParts as &$part) {
                $part = urlencode(urldecode($part));
            }
            $parts['path'] = implode('/', $pathParts);
        }
        
        return 'src="' . build_url($parts) . '"';
    }, $content);
    
    return $content;
}

function build_url($parts) {
    return (isset($parts['scheme']) ? "{$parts['scheme']}:" : '') . 
           ((isset($parts['user']) || isset($parts['host'])) ? '//' : '') . 
           (isset($parts['user']) ? "{$parts['user']}" : '') . 
           (isset($parts['pass']) ? ":{$parts['pass']}" : '') . 
           (isset($parts['user']) ? '@' : '') . 
           (isset($parts['host']) ? "{$parts['host']}" : '') . 
           (isset($parts['port']) ? ":{$parts['port']}" : '') . 
           (isset($parts['path']) ? "{$parts['path']}" : '') . 
           (isset($parts['query']) ? "?{$parts['query']}" : '') . 
           (isset($parts['fragment']) ? "#{$parts['fragment']}" : '');
}

实战代码示例

简单的图片采集处理

<?php
// 简单的图片采集处理示例
function simpleImageCollector($url) {
    // 获取网页内容
    $html = file_get_contents($url);
    if (!$html) {
        throw new Exception("Failed to fetch URL: " . $url);
    }
    
    // 转换相对路径为绝对路径
    $html = convertRelativeToAbsoluteUrls($html, $url);
    
    // 强制HTTPS
    $html = forceHttps($html);
    
    return $html;
}

// 使用示例
try {
    $url = "http://example.com/article";
    $processedContent = simpleImageCollector($url);
    echo $processedContent;
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}
?>

完整的图片本地化方案

”`php <?php // 完整的图片本地化处理类 class ImageLocalizer { private \(baseUrl; private \)savePath = ‘/uploads/remote_images/’; private $allowedExtensions = [‘jpg’, ‘jpeg’, ‘png’, ‘gif’, ‘webp’];

public function __construct($baseUrl, $savePath = null) {
    $this->baseUrl = $baseUrl;
    if ($savePath) {
        $this->savePath = $savePath;
    }
}

public function process($html) {
    $dom = new DOMDocument();
    @$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));

    $this->processImages($dom);
    $this->processBackgrounds($dom);

    return $dom->saveHTML();
}

private function processImages($dom) {
    $images = $dom->getElementsByTagName('img');

    foreach ($images as $img) {
        $originalSrc = $img->getAttribute('src');
        if (empty($originalSrc)) continue;

        try {
            $absoluteUrl = $this->convertToAbsoluteUrl($originalSrc);
            $localPath = $this->downloadAndSave($absoluteUrl);
            $img->setAttribute('src', $localPath);

            // 处理srcset属性
            if ($img->hasAttribute('srcset')) {
                $srcset = $this->processSrcset($img->getAttribute('srcset'));
                $img->setAttribute('srcset', $srcset);
            }
        } catch (Exception $e) {
            error_log("Image localization failed: " . $e->getMessage());
            // 可选:移除无法下载的图片
            // $img->parentNode->removeChild($img);
        }
    }
}

private function processBackgrounds($dom) {
    $elements = $dom->getElementsByTagName('*');

    foreach ($elements as $el) {
        if ($el->hasAttribute('style')) {
            $style = $el->getAttribute('style');
            $processedStyle = preg_replace_callback(
                '/url\(([^)]+)\)/i',
                function($matches) {
                    $url = trim($matches[1], '\'" ');
                    try {
                        $absoluteUrl = $this->convertToAbsoluteUrl($url);
                        $localPath = $this->downloadAndSave($absoluteUrl);
                        return 'url(' . $localPath . ')';
                    } catch (Exception $e) {
                        error_log("Background image localization failed: " . $e->getMessage());
                        return $matches[0]; // 保持原样
                    }
                },
                $style
            );
            $el->setAttribute('style', $processedStyle);
        }
    }
}

private function processSrcset($srcset) {
    $parts = explode(',', $srcset);
    $result = [];

    foreach ($parts as $part) {
        $part = trim($part);
        if (preg_match('/^([^\s]+)\s*(.*)$/', $part, $matches)) {
            $url = $matches[1];
            $descriptor = isset($matches[2]) ? $matches[2] : '';

            try {
                $absoluteUrl = $this->convertToAbsoluteUrl($url);
                $localPath = $this->downloadAndSave($absoluteUrl);
                $result[] = $localPath . ($descriptor ? ' ' . $descriptor : '');
            } catch (Exception $e) {
                error_log("Srcset image localization failed: " . $e->getMessage());
                $result[] = $part; // 保持原样
            }
        }
    }

    return implode(', ', $result);
}

private function convertToAbsoluteUrl($url) {
    // 已经是完整URL
    if (preg_match('/^https?:\/\//i', $url)) {
        return $url;
    }

    // 协议相对URL
    if (substr($url, 0, 2) === '//') {
        $base = parse_url($this->baseUrl);
        return $base['scheme'] . ':' . $url;
    }

    // 根相对路径
    if (substr($url, 0, 1) === '/') {
        $base = parse_url($this->baseUrl);
        return $base['scheme'] . '://' . $base['host'] . $url;
    }

    // 相对路径
    $base = parse_url($this->baseUrl);
    $path = isset($base['path']) ? $base['path'] : '/';
    $dir = dirname($path) === '/' ? '' : dirname($path);

    return $base['scheme'] . '://' . $base['host'] . $dir . '/' . $url;
}

private function

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

推荐阅读:
  1. dede 采集文章内容中图片不显示的问题
  2. 如何采集PHPCMS的文章内容

开发者交流群:

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php

上一篇:bootstrap如何实现表格

下一篇:jquery插件如何实现懒汉式加载图片

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》
开发者交流群×