让用户点击一个链接,然后浏览器下载一个包含指定网页源代码的文件(通常是 .txt 或 .html 文件),而不是在浏览器中直接显示它。

php设计网页代码下载
(图片来源网络,侵删)

我们将从最基础的方法开始,逐步完善,并加入错误处理和更高级的功能。


核心思路

要实现文件下载,而不是在浏览器中显示,我们需要利用 PHP 的 HTTP 头信息,关键的头信息是:

  1. Content-Type: text/plain (或 text/html): 告诉浏览器这个文件的类型是纯文本(或HTML),浏览器通常会根据这个类型决定如何处理。
  2. Content-Disposition: attachment; filename="...": 这是最关键的一步。 attachment 指示浏览器应该将内容作为附件下载,而不是在浏览器中内联显示。filename 属性则指定了下载时用户看到的默认文件名。

基础实现(下载静态网页)

假设我们有一个固定的网页,example.html,我们希望用户可以下载它的源代码。

文件结构:

php设计网页代码下载
(图片来源网络,侵删)
/your-project-root/
├── index.php          // 下载入口页面
└── example.html        // 需要被下载的目标文件

example.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">这是一个示例页面</title>
</head>
<body>
    <h1>Hello, World!</h1>
    <p>这是一个用于演示下载功能的HTML页面。</p>
    <p>当前时间戳是: <?php echo time(); ?></p>
</body>
</html>

index.php 下载页面代码:

<?php
// --- 1. 设置目标文件路径 ---
// __DIR__ 是 PHP "魔术常量",包含当前文件所在的目录。
$filePath = __DIR__ . '/example.html';
// --- 2. 安全检查:文件是否存在且可读 ---
if (!file_exists($filePath) || !is_readable($filePath)) {
    // 如果文件不存在或不可读,输出错误信息并停止脚本
    http_response_code(404); // 发送 404 Not Found 状态码
    die('错误:文件不存在或无法读取。');
}
// --- 3. 获取文件名和文件内容 ---
// 使用 basename() 安全地获取文件名,防止目录遍历攻击
$fileName = basename($filePath);
$fileContent = file_get_contents($filePath);
// --- 4. 设置HTTP头信息,触发下载 ---
// 重要:在输出任何内容之前设置头信息!
header('Content-Type: text/html; charset=utf-8'); // 指定文件类型和字符编码
header('Content-Disposition: attachment; filename="' . $fileName . '"'); // 告诉浏览器这是附件
header('Content-Length: ' . filesize($filePath)); // 可选,但推荐,提供文件大小
header('Cache-Control: no-cache, must-revalidate'); // 禁用缓存
header('Pragma: no-cache'); // 禁用缓存 (兼容性)
header('Expires: 0'); // 禁用缓存
// --- 5. 输出文件内容 ---
// 将文件内容直接输出到浏览器
echo $fileContent;
// 结束脚本
exit;
?>

如何使用:

  1. example.htmlindex.php 放在同一目录下。
  2. 通过浏览器访问 index.php
  3. 你会看到一个文件下载对话框,提示你下载 "example.html"。

进阶实现(动态获取任意URL的代码)

这个功能更强大,允许用户输入一个URL,然后下载该网页的源代码。

php设计网页代码下载
(图片来源网络,侵删)

文件结构:

/your-project-root/
└── download_dynamic.php

download_dynamic.php 代码:

<?php
// --- 1. 检查是否提供了URL ---
if (!isset($_GET['url']) || empty($_GET['url'])) {
    // 如果没有提供URL,显示一个简单的表单
    ?>
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>网页代码下载器</title>
        <style>
            body { font-family: sans-serif; line-height: 1.6; padding: 20px; max-width: 600px; margin: auto; }
            input[type="text"] { width: 100%; padding: 8px; margin-bottom: 10px; box-sizing: border-box; }
            input[type="submit"] { padding: 10px 15px; background-color: #007bff; color: white; border: none; cursor: pointer; }
        </style>
    </head>
    <body>
        <h1>网页代码下载器</h1>
        <p>请输入您想下载源代码的网页URL:</p>
        <form action="" method="get">
            <input type="text" name="url" placeholder=" https://www.example.com" required>
            <input type="submit" value="下载源代码">
        </form>
    </body>
    </html>
    <?php
    exit; // 显示完表单后结束脚本
}
// --- 2. 获取并清理URL ---
$url = trim($_GET['url']);
// --- 3. 安全检查:验证URL格式 ---
if (!filter_var($url, FILTER_VALIDATE_URL)) {
    http_response_code(400);
    die('错误:提供的URL格式无效。');
}
// --- 4. 使用cURL获取网页内容 ---
$ch = curl_init();
// 设置cURL选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 将获取的内容作为字符串返回,而不是直接输出
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 跟随重定向
curl_setopt($ch, CURLOPT_MAXREDIRS, 5); // 限制最多重定向次数
curl_setopt($ch, CURLOPT_USERAGENT, 'My-Code-Downloader/1.0'); // 设置一个自定义的User-Agent
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // 连接超时时间
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 总执行超时时间
// 执行cURL请求
$htmlContent = curl_exec($ch);
// 检查是否有错误发生
if (curl_errno($ch)) {
    http_response_code(500);
    die('cURL错误: ' . curl_error($ch));
}
// 获取HTTP状态码
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// --- 5. 检查HTTP响应是否成功 ---
if ($httpCode != 200) {
    http_response_code($httpCode);
    die("错误:无法获取网页,服务器返回的状态码是: " . $httpCode);
}
// --- 6. 设置头信息并输出 ---
// 从URL中提取一个安全的文件名
$downloadFileName = 'downloaded_page_' . time() . '.html';
header('Content-Type: text/html; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $downloadFileName . '"');
header('Content-Length: ' . strlen($htmlContent));
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
echo $htmlContent;
exit;
?>

如何使用:

  1. 将上述代码保存为 download_dynamic.php
  2. 在浏览器中访问 download_dynamic.php
  3. 你会看到一个输入框,输入一个有效的URL(https://www.php.net)。
  4. 点击“下载源代码”按钮,浏览器就会开始下载该网页的HTML源代码文件。

重要注意事项和最佳实践

  1. header() 函数必须在任何输出之前调用! 这是最常见的错误,在 header() 之前,不能有任何HTML标签、空格或PHP的输出(即使是 echo " "; 也不行)。<?php 标签前的空行也会导致输出。

  2. 安全性至关重要!

    • URL过滤:在方法二中,我们使用了 filter_var() 来验证URL,防止用户输入恶意内容或进行SSRF(服务器端请求伪造)攻击。
    • 文件路径安全:在方法一中,使用 basename() 来确保我们只获取文件名,而不是类似 ../../../etc/passwd 这样的危险路径。
    • 限制下载范围:对于生产环境,你可能需要限制用户只能下载特定域名下的网页,以防止滥用你的服务器去抓取其他网站。
  3. 错误处理 始终检查文件是否存在、是否可读、网络请求是否成功,向用户提供清晰的错误信息,而不是直接暴露服务器错误细节。

  4. 性能考虑 下载大文件可能会消耗大量服务器内存和带宽,对于非常大的文件,可以考虑使用 readfile() 函数,它更高效,因为它会以流的方式传输文件,而不是一次性将整个文件读入内存。

    // 使用 readfile() 的示例
    header('Content-Type: text/html');
    header('Content-Disposition: attachment; filename="example.html"');
    readfile($filePath); // 直接读取并输出文件内容
    exit;
功能点 实现方法 关键代码/函数
触发下载 设置 Content-Disposition: attachment header('Content-Disposition: attachment; filename="..."'
指定文件类型 设置 Content-Type header('Content-Type: text/html; charset=utf-8'
获取文件内容 读取本地文件或远程URL file_get_contents(), curl_exec()
安全处理 验证和清理用户输入 filter_var(), basename()
防止错误 header() 前不输出任何内容 确保 PHP 脚本顶部无空格/空行

通过以上步骤,你已经可以创建一个功能完整且相对安全的网页代码下载器了,你可以根据实际需求选择基础方法或进阶方法,并在此基础上进行扩展。