跳到主要内容

PHP 文件操作

本章将介绍 PHP 的文件读写、目录操作和文件上传。

文件读取

读取整个文件

<?php
// file_get_contents - 读取整个文件为字符串
$content = file_get_contents("test.txt");
echo $content;

// 读取远程文件
$html = file_get_contents("https://example.com");

// file - 读取文件到数组(每行一个元素)
$lines = file("test.txt");
foreach ($lines as $line) {
echo $line;
}

// FILE_IGNORE_NEW_LINES - 去除行尾换行符
$lines = file("test.txt", FILE_IGNORE_NEW_LINES);

// FILE_SKIP_EMPTY_LINES - 跳过空行
$lines = file("test.txt", FILE_SKIP_EMPTY_LINES);

// readfile - 直接输出文件内容
readfile("test.txt");
?>

使用 fopen 读取

<?php
// 打开文件
$file = fopen("test.txt", "r");

// 检查是否打开成功
if (!$file) {
die("无法打开文件");
}

// 逐行读取
while (!feof($file)) {
$line = fgets($file);
echo $line;
}

// 读取指定长度
$content = fread($file, 1024); // 读取 1024 字节

// 读取单个字符
$char = fgetc($file);

// 关闭文件
fclose($file);
?>

使用 fopen 模式

模式说明
r只读,文件指针在开头
r+读写,文件指针在开头
w只写,清空文件或创建新文件
w+读写,清空文件或创建新文件
a只写,文件指针在末尾(追加)
a+读写,文件指针在末尾(追加)
x只写,创建新文件,若存在则失败
x+读写,创建新文件,若存在则失败

文件写入

写入文件

<?php
// file_put_contents - 写入整个文件
file_put_contents("test.txt", "Hello World");

// 追加内容
file_put_contents("test.txt", "\n新内容", FILE_APPEND);

// 锁定文件
file_put_contents("test.txt", "内容", FILE_APPEND | LOCK_EX);

// 使用 fwrite
$file = fopen("test.txt", "w");
fwrite($file, "Hello World\n");
fwrite($file, "第二行\n");
fclose($file);

// 追加写入
$file = fopen("test.txt", "a");
fwrite($file, "追加内容\n");
fclose($file);
?>

文件锁定

<?php
$file = fopen("test.txt", "w");

// 获取独占锁
if (flock($file, LOCK_EX)) {
fwrite($file, "写入内容");
flock($file, LOCK_UN); // 释放锁
}

fclose($file);

// 非阻塞锁
$file = fopen("test.txt", "w");
if (flock($file, LOCK_EX | LOCK_NB)) {
fwrite($file, "内容");
flock($file, LOCK_UN);
} else {
echo "文件被锁定";
}
fclose($file);
?>

文件信息

检查文件

<?php
// 检查文件是否存在
var_dump(file_exists("test.txt")); // bool(true/false)

// 检查是否是文件
var_dump(is_file("test.txt"));

// 检查是否可读
var_dump(is_readable("test.txt"));

// 检查是否可写
var_dump(is_writable("test.txt"));

// 检查是否可执行
var_dump(is_executable("script.sh"));
?>

获取文件属性

<?php
// 文件大小(字节)
echo filesize("test.txt");

// 文件类型
echo filetype("test.txt"); // file
echo filetype("/var/www"); // dir

// 修改时间
echo filemtime("test.txt"); // Unix 时间戳
echo date("Y-m-d H:i:s", filemtime("test.txt"));

// 访问时间
echo fileatime("test.txt");

// 创建时间(Windows)
echo filectime("test.txt");

// 文件权限
echo fileperms("test.txt");
echo decoct(fileperms("test.txt") & 0777); // 八进制权限

// 文件所有者
echo fileowner("test.txt");

// 获取详细信息
$stat = stat("test.txt");
print_r($stat);
// [size] => 1024
// [mtime] => 1234567890
// ...
?>

文件操作

复制、重命名、删除

<?php
// 复制文件
copy("source.txt", "dest.txt");

// 重命名/移动文件
rename("old.txt", "new.txt");
rename("file.txt", "/path/to/file.txt"); // 移动

// 删除文件
unlink("test.txt");

// 检查后删除
if (file_exists("test.txt")) {
unlink("test.txt");
}
?>

文件路径

<?php
$path = "/var/www/html/index.php";

// 获取文件名
echo basename($path); // index.php
echo basename($path, ".php"); // index

// 获取目录名
echo dirname($path); // /var/www/html

// 路径信息
$info = pathinfo($path);
// [
// "dirname" => "/var/www/html",
// "basename" => "index.php",
// "extension" => "php",
// "filename" => "index"
// ]

// 绝对路径
echo realpath("test.txt");

// 路径拼接
echo __DIR__ . "/test.txt";

// 使用 DIRECTORY_SEPARATOR(跨平台)
$path = "folder" . DIRECTORY_SEPARATOR . "file.txt";
?>

目录操作

创建和删除目录

<?php
// 创建目录
mkdir("newdir");

// 创建多级目录
mkdir("a/b/c", 0777, true);

// 删除空目录
rmdir("emptydir");

// 递归删除目录
function deleteDir($dir) {
if (is_dir($dir)) {
$items = scandir($dir);
foreach ($items as $item) {
if ($item != "." && $item != "..") {
$path = $dir . "/" . $item;
if (is_dir($path)) {
deleteDir($path);
} else {
unlink($path);
}
}
}
rmdir($dir);
}
}
?>

遍历目录

<?php
// scandir - 获取目录内容
$files = scandir("/var/www");
// [".", "..", "html", "cgi-bin"]

// 排除 . 和 ..
$files = array_diff(scandir("/var/www"), [".", ".."]);

// 使用 opendir
$dir = opendir("/var/www");
while (($file = readdir($dir)) !== false) {
echo $file . "\n";
}
closedir($dir);

// 递归遍历
function listFiles($dir, $level = 0) {
$items = scandir($dir);
foreach ($items as $item) {
if ($item == "." || $item == "..") continue;

$path = $dir . "/" . $item;
echo str_repeat(" ", $level) . $item . "\n";

if (is_dir($path)) {
listFiles($path, $level + 1);
}
}
}

listFiles("/var/www");
?>

使用 RecursiveDirectoryIterator

<?php
$dir = "/var/www";
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::SELF_FIRST
);

foreach ($iterator as $file) {
if ($file->isDir()) {
echo "[DIR] " . $file . "\n";
} else {
echo "[FILE] " . $file . "\n";
}
}

// 过滤特定文件
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir)
);

$phpFiles = new RegexIterator($iterator, '/\.php$/');
foreach ($phpFiles as $file) {
echo $file . "\n";
}
?>

文件上传

HTML 表单

<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<input type="file" name="files[]" multiple>
<button type="submit">上传</button>
</form>

处理上传

<?php
// 检查是否有文件上传
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 单文件上传
$file = $_FILES['file'];

// 文件信息
$name = $file['name']; // 原始文件名
$type = $file['type']; // MIME 类型
$tmp = $file['tmp_name']; // 临时文件路径
$error = $file['error']; // 错误码
$size = $file['size']; // 文件大小(字节)

// 错误检查
if ($error === UPLOAD_ERR_OK) {
// 验证文件
$allowed = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 2 * 1024 * 1024; // 2MB

if (!in_array($type, $allowed)) {
die("不支持的文件类型");
}

if ($size > $maxSize) {
die("文件太大");
}

// 生成唯一文件名
$ext = pathinfo($name, PATHINFO_EXTENSION);
$newName = uniqid() . '.' . $ext;
$destination = "uploads/" . $newName;

// 移动文件
if (move_uploaded_file($tmp, $destination)) {
echo "上传成功:" . $newName;
} else {
echo "上传失败";
}
}
}
?>

多文件上传

<?php
// 多文件上传
$files = $_FILES['files'];
$count = count($files['name']);

for ($i = 0; $i < $count; $i++) {
$name = $files['name'][$i];
$tmp = $files['tmp_name'][$i];
$error = $files['error'][$i];

if ($error === UPLOAD_ERR_OK) {
$destination = "uploads/" . basename($name);
move_uploaded_file($tmp, $destination);
}
}
?>

上传错误码

错误码常量说明
0UPLOAD_ERR_OK成功
1UPLOAD_ERR_INI_SIZE超过 php.ini 中 upload_max_filesize
2UPLOAD_ERR_FORM_SIZE超过表单中 MAX_FILE_SIZE
3UPLOAD_ERR_PARTIAL文件只有部分被上传
4UPLOAD_ERR_NO_FILE没有文件被上传
6UPLOAD_ERR_NO_TMP_DIR找不到临时文件夹
7UPLOAD_ERR_CANT_WRITE文件写入失败

文件下载

<?php
$file = "downloads/document.pdf";

if (file_exists($file)) {
// 设置响应头
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));
header('Pragma: public');

// 清空输出缓冲
ob_clean();
flush();

// 输出文件内容
readfile($file);
exit;
}
?>

配置选项

<?php
// php.ini 中的文件上传配置
// file_uploads = On ; 是否允许文件上传
// upload_max_filesize = 2M ; 最大上传文件大小
// post_max_size = 8M ; POST 数据最大大小
// upload_tmp_dir = ; 临时文件目录
// max_file_uploads = 20 ; 最大同时上传文件数

// 运行时修改(部分配置)
ini_set('upload_max_filesize', '10M');
ini_set('post_max_size', '12M');
?>

小结

本章我们学习了:

  1. 文件读取:file_get_contents、fopen、fgets
  2. 文件写入:file_put_contents、fwrite
  3. 文件信息:file_exists、filesize、filemtime
  4. 文件操作:copy、rename、unlink
  5. 目录操作:mkdir、rmdir、scandir
  6. 文件上传:$_FILES、move_uploaded_file
  7. 文件下载:header、readfile

下一章我们将学习表单处理。