PHP 文件操作基础
打开与关闭文件
使用 fopen 打开文件,第一个参数是文件路径,第二个参数是打开模式,返回一个资源句柄,操作完成后用 fclose 关闭。
$fp = fopen('test.txt', 'r');
// ... 读写操作
fclose($fp);
常用打开模式:
| 模式 | 说明 |
|---|---|
r |
只读,指针在文件开头 |
r+ |
读写,指针在文件开头 |
w |
只写,清空文件,不存在则创建 |
w+ |
读写,清空文件 |
a |
追加写入,指针在文件末尾 |
a+ |
追加读写 |
读取文件
// 读取一行
$line = fgets($fp);
// 读取一个字符
$char = fgetc($fp);
// 读取指定长度
$content = fread($fp, 1024);
// 一次读取整个文件(不需要手动 fopen)
$content = file_get_contents('test.txt');
// 把整个文件读入数组,每行一个元素
$lines = file('test.txt');
写入文件
$fp = fopen('test.txt', 'a');
fwrite($fp, "新的一行内容\n");
fclose($fp);
// 简便写法
file_put_contents('test.txt', "内容\n", FILE_APPEND);
其他常用文件函数
file_exists('test.txt'); // 判断文件是否存在
filesize('test.txt'); // 文件大小(字节)
unlink('test.txt'); // 删除文件
rename('a.txt', 'b.txt'); // 重命名或移动
copy('a.txt', 'b.txt'); // 复制文件
is_file('test.txt'); // 是否为常规文件
is_dir('/var/www'); // 是否为目录
mkdir('newdir'); // 创建目录
rmdir('newdir'); // 删除空目录
文件上传
前端表单
上传文件必须满足两个条件:method 为 post,并且 enctype 设置为 multipart/form-data。
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="photo">
<input type="submit" value="上传">
</form>
后端处理
上传的文件信息保存在超全局数组 $_FILES 中,以表单里 name 作为键。
var_dump($_FILES['photo']);
$_FILES['photo'] 包含以下字段:
name:原始文件名type:MIME 类型(客户端提供,不可信)tmp_name:服务器上的临时文件路径error:错误码size:文件大小(字节)
临时文件在脚本结束后会被自动删除,所以必须用 move_uploaded_file 把它移到目标位置。
if ($_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
die('上传出错,错误码:' . $_FILES['photo']['error']);
}
// 简单校验:只允许 jpg 和 png
$allow = ['image/jpeg', 'image/png'];
if (!in_array($_FILES['photo']['type'], $allow, true)) {
die('文件类型不允许');
}
// 按日期分目录
$dir = './uploads/' . date('Ymd') . '/';
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
// 生成随机文件名,避免中文名和重名问题
$ext = pathinfo($_FILES['photo']['name'], PATHINFO_EXTENSION);
$newName = md5(uniqid(mt_rand(), true)) . '.' . $ext;
if (move_uploaded_file($_FILES['photo']['tmp_name'], $dir . $newName)) {
echo '上传成功:' . $dir . $newName;
} else {
echo '移动文件失败';
}
错误码说明
| 错误码 | 含义 |
|---|---|
UPLOAD_ERR_OK (0) |
上传成功 |
UPLOAD_ERR_INI_SIZE (1) |
超过 php.ini 中 upload_max_filesize 限制 |
UPLOAD_ERR_FORM_SIZE (2) |
超过表单 MAX_FILE_SIZE 限制 |
UPLOAD_ERR_PARTIAL (3) |
文件只有部分被上传 |
UPLOAD_ERR_NO_FILE (4) |
没有上传文件 |
UPLOAD_ERR_NO_TMP_DIR (6) |
找不到临时目录 |
UPLOAD_ERR_CANT_WRITE (7) |
文件写入失败 |
相关配置项
在 php.ini 中可以调整上传相关的配置:
file_uploads = On
upload_max_filesize = 2M
post_max_size = 8M
max_file_uploads = 20
注意 post_max_size 要大于等于 upload_max_filesize,否则整个 POST 数据都会被丢弃,$_POST 和 $_FILES 都会是空的。
安全校验要点
客户端传来的 type 和 name 都可以伪造,实际项目中应该:
- 使用
finfo_file检测真实 MIME 类型 - 用
getimagesize验证是否真的是图片(针对图片上传) - 自己生成随机文件名,禁止直接使用用户上传的文件名
- 把上传目录设置为不可执行脚本,例如 Nginx 中禁用该目录的 PHP 解析
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['photo']['tmp_name']);
finfo_close($finfo);
if (!in_array($mime, ['image/jpeg', 'image/png'], true)) {
die('不是合法的图片文件');
}
小结
文件操作核心是 fopen 系列函数和 file_get_contents、file_put_contents 这两个简便函数;文件上传核心是理解 $_FILES 的结构,用 move_uploaded_file 保存临时文件,同时做好类型校验和文件名处理,注意 php.ini 中上传大小限制的配置。