You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP中实现PDF动态网站式查看?支持分页加载无需完整下载

嘿,我之前在项目里刚好遇到过类似的需求,给你两个靠谱的方案,既能保留PDF的原格式,又能实现动态逐页查看,不用下载完整文件:

方案1:结合PDF.js与PHP实现交互式逐页渲染

PDF.js是Mozilla推出的纯JS库,能直接在浏览器里渲染PDF,而且天生支持按需加载单页——也就是说,浏览器只会下载当前查看页面的字节数据,不用拉整个PDF文件。你只需要用PHP做两件事:一是做权限校验(如果需要的话),二是确保支持字节范围请求(让PDF.js能精准请求需要的文件片段)。

PHP后端示例(权限验证+支持范围请求)

<?php
// 先做权限校验,比如检查用户是否登录
session_start();
if (!isset($_SESSION['authenticated'])) {
    header('HTTP/1.1 403 Forbidden');
    exit('抱歉,你没有访问权限');
}

$pdfFile = './path/to/your/document.pdf';

// 处理字节范围请求,这是实现按需加载的关键
if (isset($_SERVER['HTTP_RANGE'])) {
    list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
    list($start, $end) = explode('-', $range);
    
    $fileSize = filesize($pdfFile);
    $start = intval($start);
    $end = $end ? intval($end) : $fileSize - 1;
    $length = $end - $start + 1;

    $fp = fopen($pdfFile, 'rb');
    fseek($fp, $start);
    $content = fread($fp, $length);
    fclose($fp);

    header('HTTP/1.1 206 Partial Content');
    header('Content-Type: application/pdf');
    header('Content-Length: ' . $length);
    header('Content-Range: bytes ' . $start . '-' . $end . '/' . $fileSize);
} else {
    // 如果没有范围请求,就返回完整文件(也可以强制只允许范围请求)
    header('Content-Type: application/pdf');
    header('Content-Length: ' . filesize($pdfFile));
    readfile($pdfFile);
}
?>

前端简单实现(用PDF.js渲染)

你可以把PDF.js的核心文件下载到本地项目里(不用外链),然后用下面的代码实现基础的分页查看:

<div id="pdf-viewer"></div>
<button id="next-page">下一页</button>

<script src="./pdf.min.js"></script>
<script>
const pdfUrl = './your-php-script.php'; // 指向上面的PHP脚本
const viewer = document.getElementById('pdf-viewer');
const nextBtn = document.getElementById('next-page');

let pdfDoc = null;
let currentPage = 1;

async function initPDF() {
    pdfDoc = await pdfjsLib.getDocument(pdfUrl).promise;
    renderPage(currentPage);
}

async function renderPage(pageNum) {
    const page = await pdfDoc.getPage(pageNum);
    const viewport = page.getViewport({ scale: 1.5 }); // 调整缩放比例

    // 创建画布渲染页面
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = viewport.width;
    canvas.height = viewport.height;
    
    // 清空容器,渲染新页面
    viewer.innerHTML = '';
    viewer.appendChild(canvas);
    
    await page.render({ canvasContext: ctx, viewport }).promise;
}

// 下一页按钮逻辑
nextBtn.addEventListener('click', () => {
    if (currentPage < pdfDoc.numPages) {
        currentPage++;
        renderPage(currentPage);
    }
});

initPDF();
</script>

这个方案的优势是完全保留PDF的原生交互(比如选文字、复制、搜索),而且加载速度快,适合需要完整PDF体验的场景。

方案2:用PHP Imagick提取单页为图片(兼容性拉满)

如果你的用户不需要PDF的交互功能,只是要查看内容,那可以用PHP的Imagick扩展把PDF的单页转成图片,然后逐页输出。这样浏览器只加载当前页的图片,完全不用处理PDF文件,兼容性极好。

PHP后端示例(提取指定页码为图片)

<?php
// 确认Imagick扩展已安装
if (!extension_loaded('imagick')) {
    die('请先安装Imagick扩展');
}

$pdfPath = './path/to/your/document.pdf';
$pageNum = isset($_GET['page']) ? intval($_GET['page']) : 1;

// 注意:Imagick的PDF页码从0开始,所以要减1
$imagick = new Imagick();
$imagick->setResolution(150, 150); // 设置分辨率,避免图片模糊
$imagick->readImage($pdfPath . '[' . ($pageNum - 1) . ']');
$imagick->setImageFormat('png'); // 也可以用jpeg,体积更小

header('Content-Type: image/png');
echo $imagick;
$imagick->destroy();
?>

前端只需要做个分页器,点击按钮请求不同的?page=X参数,就能加载对应页面的图片了。这个方案的缺点是丢失了PDF的交互性,但胜在简单,不用引入前端库,所有浏览器都能直接显示。

几个关键提醒
  • 不管用哪个方案,都不要把PDF文件直接暴露在公网,一定要用PHP脚本做权限校验,防止未授权访问。
  • 方案1里,如果你用的是Apache或Nginx,大部分默认支持字节范围请求,但如果不行,就用上面PHP脚本里的手动处理逻辑。
  • 方案2里,可以把生成的图片缓存起来,比如存在服务器的缓存目录里,下次请求同页面时直接返回缓存,提升性能。

内容的提问来源于stack exchange,提问作者Shivam Verma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:28:00