本文目录导读:

在PHP中实现文件预览,通常会根据文件类型采用不同的方案,以下是几种常见的实现方式:
图片预览
<?php
// image_preview.php
$file = $_GET['file'] ?? '';
// 安全校验:防止路径遍历
$allowedPath = '/path/to/uploads/';
$realPath = realpath($allowedPath . $file);
if ($realPath && strpos($realPath, $allowedPath) === 0) {
$fileInfo = getimagesize($realPath);
header('Content-Type: ' . $fileInfo['mime']);
header('Content-Length: ' . filesize($realPath));
readfile($realPath);
} else {
http_response_code(404);
echo 'File not found';
}
PDF 预览
<?php
// pdf_preview.php
$file = $_GET['file'] ?? '';
// 安全校验
$filePath = '/path/to/pdfs/' . basename($file);
if (file_exists($filePath)) {
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($filePath));
readfile($filePath);
} else {
http_response_code(404);
echo 'PDF not found';
}
文本文件预览
<?php
// text_preview.php
$file = $_GET['file'] ?? '';
$filePath = '/path/to/texts/' . basename($file);
if (file_exists($filePath)) {
$content = file_get_contents($filePath);
// 检测编码
$encoding = mb_detect_encoding($content, ['UTF-8', 'GB2312', 'GBK'], true);
if ($encoding != 'UTF-8') {
$content = mb_convert_encoding($content, 'UTF-8', $encoding);
}
header('Content-Type: text/plain; charset=utf-8');
echo nl2br(htmlspecialchars($content));
} else {
http_response_code(404);
echo 'File not found';
}
Office 文档预览(使用在线预览服务)
<?php
// office_preview.php
// 方式1:使用 Microsoft Office Online
$file = $_GET['file'] ?? '';
$fileUrl = 'https://yourdomain.com/uploads/' . urlencode($file);
$previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' . urlencode($fileUrl);
header('Location: ' . $previewUrl);
exit;
// 方式2:使用 Google Docs Viewer
// $previewUrl = 'https://docs.google.com/viewer?url=' . urlencode($fileUrl) . '&embedded=true';
?>
<!DOCTYPE html>
<html>
<head>Office 文件预览</title>
</head>
<body>
<iframe src="https://view.officeapps.live.com/op/embed.aspx?src=<?php echo urlencode($fileUrl); ?>"
style="width:100%; height:600px;" frameborder="0">
</iframe>
</body>
</html>
视频文件预览
<?php
// video_preview.php
$file = $_GET['file'] ?? '';
$filePath = '/path/to/videos/' . basename($file);
if (file_exists($filePath)) {
// 支持 Range 请求,允许拖动进度条
$size = filesize($filePath);
$fp = fopen($filePath, 'rb');
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
if (isset($_SERVER['HTTP_RANGE'])) {
// 处理分段请求
preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $matches);
$start = intval($matches[1]);
$end = isset($matches[2]) && $matches[2] !== '' ? intval($matches[2]) : $size - 1;
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $start-$end/$size");
header('Content-Length: ' . ($end - $start + 1));
fseek($fp, $start);
$chunkSize = 8192;
while ($start <= $end) {
$data = fread($fp, min($chunkSize, $end - $start + 1));
echo $data;
$start += $chunkSize;
}
} else {
header('Content-Length: ' . $size);
while (!feof($fp)) {
echo fread($fp, 8192);
flush();
}
}
fclose($fp);
} else {
http_response_code(404);
echo 'Video not found';
}
通用文件预览(自动识别类型)
<?php
// universal_preview.php
class FilePreviewer {
private $allowedPaths = [
'images' => ['jpg', 'jpeg', 'png', 'gif', 'webp'],
'pdf' => ['pdf'],
'text' => ['txt', 'md', 'log', 'csv', 'xml', 'html'],
'audio' => ['mp3', 'wav', 'ogg'],
'video' => ['mp4', 'webm', 'ogg']
];
public function preview($file, $uploadDir) {
// 安全检查
$file = basename($file); // 移除路径部分
$filePath = $uploadDir . '/' . $file;
if (!file_exists($filePath)) {
return ['error' => '文件不存在'];
}
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
$mimeType = mime_content_type($filePath);
// 根据文件类型返回合适的预览结果
if (in_array($extension, $this->allowedPaths['images'])) {
return $this->imagePreview($filePath, $mimeType);
} elseif (in_array($extension, $this->allowedPaths['pdf'])) {
return $this->pdfPreview($filePath);
} elseif (in_array($extension, $this->allowedPaths['text'])) {
return $this->textPreview($filePath);
} elseif (in_array($extension, $this->allowedPaths['audio'])) {
return $this->audioPreview($filePath);
} elseif (in_array($extension, $this->allowedPaths['video'])) {
return $this->videoPreview($filePath);
} else {
return $this->downloadPreview($filePath);
}
}
private function imagePreview($filePath, $mimeType) {
header('Content-Type: ' . $mimeType);
readfile($filePath);
return ['type' => 'image', 'content' => ''];
}
private function pdfPreview($filePath) {
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($filePath) . '"');
readfile($filePath);
return ['type' => 'pdf', 'content' => ''];
}
private function textPreview($filePath) {
$content = file_get_contents($filePath);
$encoding = mb_detect_encoding($content, ['UTF-8', 'GB2312', 'GBK'], true);
if ($encoding != 'UTF-8') {
$content = mb_convert_encoding($content, 'UTF-8', $encoding);
}
header('Content-Type: text/plain; charset=utf-8');
echo '<pre>' . htmlspecialchars($content) . '</pre>';
return ['type' => 'text', 'content' => $content];
}
private function downloadPreview($filePath) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
readfile($filePath);
return ['type' => 'download'];
}
}
// 使用示例
$previewer = new FilePreviewer();
$result = $previewer->preview($_GET['file'] ?? '', '/path/to/uploads');
?>
前端配合使用
<!DOCTYPE html>
<html>
<head>文件预览系统</title>
<style>
.preview-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.file-item {
display: inline-block;
margin: 10px;
padding: 15px;
border: 1px solid #ddd;
cursor: pointer;
}
.file-item:hover {
background-color: #f5f5f5;
}
.file-icon {
font-size: 48px;
text-align: center;
}
</style>
</head>
<body>
<div class="preview-container">
<h2>文件列表</h2>
<div id="fileList">
<?php
// 显示文件列表,点击进行预览
$files = glob('/path/to/uploads/*.*');
foreach ($files as $file) {
$filename = basename($file);
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
// 根据扩展名显示不同图标
$icon = '📄';
if (in_array($extension, ['jpg', 'jpeg', 'png', 'gif'])) $icon = '🖼️';
elseif ($extension == 'pdf') $icon = '📕';
elseif (in_array($extension, ['mp4', 'webm'])) $icon = '🎥';
elseif (in_array($extension, ['mp3', 'wav'])) $icon = '🎵';
echo "<div class='file-item' onclick=\"previewFile('" . $filename . "')\">";
echo "<div class='file-icon'>" . $icon . "</div>";
echo "<div>" . $filename . "</div>";
echo "</div>";
}
?>
</div>
<div id="previewArea" style="margin-top: 20px; display: none;">
<iframe id="previewFrame" style="width: 100%; height: 600px; border: 1px solid #ddd;"></iframe>
</div>
</div>
<script>
function previewFile(filename) {
var previewArea = document.getElementById('previewArea');
var previewFrame = document.getElementById('previewFrame');
// 根据文件类型决定预览方式
previewArea.style.display = 'block';
previewFrame.src = '/preview.php?file=' + encodeURIComponent(filename);
}
</script>
</body>
</html>
安全注意事项
<?php
// security_checks.php
/**
* 文件预览安全问题
*/
class SecurityChecks {
// 1. 路径遍历防护
public function preventPathTraversal($file, $uploadDir) {
$file = basename($file); // 移除所有路径部分
$realPath = realpath($uploadDir . '/' . $file);
$realUploadDir = realpath($uploadDir);
// 确保文件在允许的目录内
if ($realPath === false || strpos($realPath, $realUploadDir) !== 0) {
return false;
}
return $file;
}
// 2. 文件类型验证
public function validateFileType($filePath) {
$allowedTypes = ['image/jpeg', 'image/png', 'application/pdf', 'text/plain'];
$mimeType = mime_content_type($filePath);
return in_array($mimeType, $allowedTypes);
}
// 3. 文件大小限制
public function checkFileSize($filePath, $maxSize = 10485760) { // 10MB default
return filesize($filePath) <= $maxSize;
}
// 4. 用户权限验证
public function checkUserPermission($filePath) {
// 实现你的权限验证逻辑
// 例如检查数据库中的文件所有权
return true;
}
}
// 综合使用
$file = $_GET['file'] ?? '';
$uploadDir = '/var/www/uploads/';
$security = new SecurityChecks();
$safeFile = $security->preventPathTraversal($file, $uploadDir);
if ($safeFile && $security->validateFileType($uploadDir . '/' . $safeFile) && $security->checkUserPermission($safeFile)) {
// 执行预览
} else {
http_response_code(403);
echo 'Access denied';
}
最佳实践建议:
- 安全优先:始终验证文件路径、类型和用户权限
- 性能优化:对大文件使用流式传输,避免一次性加载到内存
- 缓存策略:对不经常变化的文件设置缓存头,提高性能
- 错误处理:提供清晰的错误信息,但不要泄露服务器路径
- 前端适配:根据设备类型(桌面/移动)适配预览界面
选择哪种方案取决于你的具体需求、文件类型和服务器环境,对于复杂的 Office 文档,推荐使用微软或 Google 的在线预览服务。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播