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);
}
}
?>
上传错误码
| 错误码 | 常量 | 说明 |
|---|---|---|
| 0 | UPLOAD_ERR_OK | 成功 |
| 1 | UPLOAD_ERR_INI_SIZE | 超过 php.ini 中 upload_max_filesize |
| 2 | UPLOAD_ERR_FORM_SIZE | 超过表单中 MAX_FILE_SIZE |
| 3 | UPLOAD_ERR_PARTIAL | 文件只有部分被上传 |
| 4 | UPLOAD_ERR_NO_FILE | 没有文件被上传 |
| 6 | UPLOAD_ERR_NO_TMP_DIR | 找不到临时文件夹 |
| 7 | UPLOAD_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');
?>
小结
本章我们学习了:
- 文件读取:file_get_contents、fopen、fgets
- 文件写入:file_put_contents、fwrite
- 文件信息:file_exists、filesize、filemtime
- 文件操作:copy、rename、unlink
- 目录操作:mkdir、rmdir、scandir
- 文件上传:$_FILES、move_uploaded_file
- 文件下载:header、readfile
下一章我们将学习表单处理。