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

(图片来源网络,侵删)
我们将从最基础的方法开始,逐步完善,并加入错误处理和更高级的功能。
核心思路
要实现文件下载,而不是在浏览器中显示,我们需要利用 PHP 的 HTTP 头信息,关键的头信息是:
Content-Type: text/plain(或text/html): 告诉浏览器这个文件的类型是纯文本(或HTML),浏览器通常会根据这个类型决定如何处理。Content-Disposition: attachment; filename="...": 这是最关键的一步。attachment指示浏览器应该将内容作为附件下载,而不是在浏览器中内联显示。filename属性则指定了下载时用户看到的默认文件名。
基础实现(下载静态网页)
假设我们有一个固定的网页,example.html,我们希望用户可以下载它的源代码。
文件结构:

(图片来源网络,侵删)
/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;
?>
如何使用:
- 将
example.html和index.php放在同一目录下。 - 通过浏览器访问
index.php。 - 你会看到一个文件下载对话框,提示你下载 "example.html"。
进阶实现(动态获取任意URL的代码)
这个功能更强大,允许用户输入一个URL,然后下载该网页的源代码。

(图片来源网络,侵删)
文件结构:
/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;
?>
如何使用:
- 将上述代码保存为
download_dynamic.php。 - 在浏览器中访问
download_dynamic.php。 - 你会看到一个输入框,输入一个有效的URL(
https://www.php.net)。 - 点击“下载源代码”按钮,浏览器就会开始下载该网页的HTML源代码文件。
重要注意事项和最佳实践
-
header()函数必须在任何输出之前调用! 这是最常见的错误,在header()之前,不能有任何HTML标签、空格或PHP的输出(即使是echo " ";也不行)。<?php标签前的空行也会导致输出。 -
安全性至关重要!
- URL过滤:在方法二中,我们使用了
filter_var()来验证URL,防止用户输入恶意内容或进行SSRF(服务器端请求伪造)攻击。 - 文件路径安全:在方法一中,使用
basename()来确保我们只获取文件名,而不是类似../../../etc/passwd这样的危险路径。 - 限制下载范围:对于生产环境,你可能需要限制用户只能下载特定域名下的网页,以防止滥用你的服务器去抓取其他网站。
- URL过滤:在方法二中,我们使用了
-
错误处理 始终检查文件是否存在、是否可读、网络请求是否成功,向用户提供清晰的错误信息,而不是直接暴露服务器错误细节。
-
性能考虑 下载大文件可能会消耗大量服务器内存和带宽,对于非常大的文件,可以考虑使用
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 脚本顶部无空格/空行 |
通过以上步骤,你已经可以创建一个功能完整且相对安全的网页代码下载器了,你可以根据实际需求选择基础方法或进阶方法,并在此基础上进行扩展。
