文件处理是任何 Web 应用程序的重要组成部分,PHP 拥有用于创建、读取、上传和编辑文件的多个函数。本篇文章将记录文件处理的学习过程。
本篇文章内容包括:
- 文件打开/读取
- 文件创建/写入
- 文件上传
一、文件打开/读取
在本节中,我们将学习如何在服务器上打开、读取和关闭文件。
1、打开文件 - fopen()
fopen() 函数用于打开文件或者 URL。
php
fopen(
string $filename,
string $mode,
bool $use_include_path = false,
?resource $context = null
): resource|false
fopen() 将 filename指定的名字资源绑定到一个流上。
参数
filename
必需。如果 filename 是 "scheme://..." 的格式,则被当成一个 URL,PHP 将搜索协议处理器(也被称为封装协议)来处理此模式。如果该协议尚未注册封装协议,PHP 将发出一条消息来帮助检查脚本中潜在的问题并将 filename 当成一个普通的文件名继续执行下去。
mode
必需。mode 参数指定了所要求到该流的访问类型。如下表所示:
|----|---------------------------------------------------------|
| 模式 | 描述 |
| r | 只读方式打开文件。文件指针指向文件开头。 |
| w | 只写方式打开文件。 如果文件不存在则创建新文件。 如果文件存在,则清空文件内容。 文件指针指向文件开头。 |
| a | 只写方式打开文件。 如果文件不存在,则创建新文件。 如果文件存在,则不会清空文件内容。 文件指针指向文件末尾。 |
| x | 以只写方式创建新文件。 如果文件已存在,则返回 FALSE 并产生错误。 |
| r+ | 读写方式打开文件。文件指针指向文件开头。 |
| w+ | 读写方式打开文件。 如果文件不存在则创建新文件。 如果文件存在,则清空文件内容。 文件指针指向文件开头。 |
| a+ | 读写方式打开文件。 如果文件不存在则创建新文件。 如果文件存在,则不会清空文件内容。 文件指针指向文件末尾。 |
| x+ | 以读写方式创建新文件。 如果文件已存在,则返回 FALSE 并产生错误。 |
use_include_path
可选。如果需要在 include_path中搜寻文件的话,可以将可选的第三个参数 use_include_path 设为 '1' 或 true。
context
可选。上下文流(context stream) resource。
返回值
成功时返回文件指针资源, 或者在失败时返回 false。
2、读取文件 - fread()
使用 fopen() 函数打开文件后,接下来我们就可以开始读取文件内容了。
fread() 函数从打开的文件中读取内容。
php
fread(resource $stream, int $length): string|false
fread() 从文件指针 stream 读取最多 length 个字节。该函数在遇上以下几种情况时停止读取文件:
- 读取了 length个字节
- 到达了文件末尾(EOF)
参数
stream
必需。文件系统指针。
length
必需。最多读取 length 个字节。
返回值
返回所读取的字符串, 或者在失败时返回 false。
3、关闭文件 - fclose()
使用 fopen() 函数打开的文件在完成操作后,需要将打开的文件进行关闭。
fclose() 函数用于关闭打开的文件。
php
fclose(resource $stream): bool
将 stream指向的文件关闭。
参数
stream
必需。文件系统指针。
返回值
成功时返回 true, 或者在失败时返回 false。
接下来我们通过一个示例来看一下如何使用 fopen()、fread()、fclose() 函数来完成对文件的读取操作。
首先,准备一个文本文件,向其中写入一些内容,这个文件将作为稍后文件读取时使用的测试文件。将文件命名为 test.txt(其它的什么名字都可以),内容如下(随便写点什么内容就行):
php
AJAX = Asynchronous JavaScript and XML
CSS = Cascading Style Sheets
HTML = Hyper Text Markup Language
PHP = PHP Hypertext Preprocessor
SQL = Structured Query Language
SVG = Scalable Vector Graphics
XML = EXtensible Markup Language
接下来我们来写读取文件内容的代码:
php
$file_name = "test.txt";
$file = fopen($file_name, "r"); // 以只读的方式打开 test.txt 文件
// filesize(文件路径):取得指定文件的大小。
$content = fread($file, filesize($file_name)); // 读取全部文件内容
fclose($file); // 关闭打开的文件
echo $content;
4、读取单行 - fgets()
fgets() 函数用于从文件中读取一行。相比于 fread() 函数,fgets() 函数更适合处理文本文件。
php
fgets(resource $stream, ?int $length = null): string|false
从文件指针中读取一行。
参数
stream
必需。文件系统指针。
length
可选。从指向的文件中读取一行并返回长度最多为 length - 1 字节的字符串。碰到换行符、EOF 或者已经读取了 length - 1 字节后停止(看先碰到那一种情况)。如果没有指定 length,则默认为 1K,或者说 1024 字节。
返回值
从指向的文件中读取了 length - 1 字节后返回字符串。如果文件指针中没有更多的数据了则返回 false。
示例
php
$file = fopen("test.txt", "r"); // 以只读的方式打开 test.txt 文件
$content = fgets($file); // 读取一行内容
fclose($file); // 关闭打开的文件
echo $content;
注意:在调用 fgets() 函数后,文件指针已移至下一行。
5、读取单个字符 - fgetc()
我们除了可以用 fgets() 函数读取一行内容外,还可以使用 fgetc() 函数从文件中读取单个字符。
php
fgetc(resource $stream): string|false
从文件中读取单个字符。
参数
stream
必需。文件系统指针。
返回值
返回一个包含有一个字符的字符串,该字符从 stream 指向的文件中得到。碰到 EOF 则返回 false。
示例
php
$file = fopen("test.txt", "r"); // 以只读的方式打开 test.txt 文件
$content = fgetc($file); // 读取一个字符内容
fclose($file); // 关闭打开的文件
echo $content;
注意:在调用 fgetc() 函数后,文件指针移至下一个字符。
6、检查文件末尾 - feof()
feof() 函数用于检查是否已达到"文件末尾"(EOF),在遍历读取文件内容时十分有用。
php
feof(resource $stream): bool
测试文件指针是否到了文件结束的位。
参数
stream
必需。文件系统指针。
返回值
如果文件指针到了 EOF 或者出错时则返回 true,否则返回一个错误(包括 socket 超时),其它情况则返回 false。
示例 逐行读取 test.txt 文件内容,直至文件末尾
php
$file = fopen("test.txt", "r");
while (!feof($file)) {
$content = fgets($file);
echo "$content <br>";
}
fclose($file);
二、文件创建/写入
在本节中,我们将学习如何在服务器上创建和写入文件。
1、创建文件 - fopen()
fopen() 函数也用于创建文件。如果在不存在的文件上使用 fopen(),并且该文件是打开以进行写入(w)或追加(a)的,那么它将创建该文件。
下面的示例创建了一个名为 "testfile.txt" 的新文件,该文件将在 PHP 代码所在的同一目录中创建:
php
$file = fopen("testfile.txt", "w");
如果在运行此代码时遇到错误,请检查是否已授予 PHP 文件向硬盘写入信息的权限。
2、写入文件 - fwrite()
fwrite() 函数用于向文件写入。
php
fwrite(resource $stream, string $data, ?int $length = null): int|false
fwrite() 把 data 的内容写入文件指针 stream 处。
参数
stream
必需。文件系统指针。
data
必需。要写入的字符串。
length
可选。当写入了 length 个字节或者写完了 string 以后,写入就会停止,看先碰到哪种情况。
返回值
fwrite() 返回写入的字符数, 或者在失败时返回 false。
示例
php
$file = fopen("testfile.txt", "w");
fwrite($file, "Hello World!\n");
fwrite($file, "你好,世界!\n");
fclose($file);
三、文件上传
在本节中,我们将学习如何处理文件上传。
1、配置 "php.ini" 文件
首先,确保 PHP 配置为允许文件上传。在你的 "php.ini" 文件中,搜索 file_uploads 指令,并将其设置为 On:
php
file_uploads = On
2、创建 HTML 表单
接下来,创建一个 HTML 表单,允许用户选择要上传的文件:
html
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<form action="upload.php" method="post" enctype="multipart/form-data">
选择上传的文件:
<input type="file" name="userfile">
<input type="submit" value="上传文件">
</form>
</body>
</html>
上述 HTML 表单需要遵循的一些规则:
- 确保表单使用 method="post"
- 表单还需要以下属性:enctype="multipart/form-data"。它指定提交表单时要使用的 content-type
如果不满足上述要求,文件上传将无法工作。
上述表单将数据发送到名为 "upload.php" 的文件,接下来我们就来创建该文件。
3、创建上传文件的 PHP 脚本
全局变量 $_FILES 包含有所有上传的文件信息。数组的内容来自以下范例表单。我们假设文件上传字段的名称如下例所示,为 userfile。名称可随意命名。
|--------------------------------------|---------------------------------------------------------------------------------|
| _FILES\['userfile'\]\['name'\] | 客户端机器文件的原名称。 |
| _FILES['userfile']['type'] | 文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是"image/gif"。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。 |
| _FILES\['userfile'\]\['size'\] | 已上传文件的大小,单位为字节。 |
| _FILES['userfile']['tmp_name'] | 文件被上传后在服务端储存的临时文件名。 |
| _FILES\['userfile'\]\['error'\] | 和该文件上传相关的错误代码。 |
| _FILES['userfile']['full_path'] | 浏览器提交的完整路径。该值并不总是包含真实的目录结构,因此不能被信任。从 PHP 8.1.0 起可用。 |
创建 "upload.php" 文件来接收上传的文件。
php
$uploaddir = 'uploads/'; // 指定上传文件要放置的目录
// basename(): 返回路径中的文件名部分
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']); // 指定要上传的文件的路径
/*
move_uploaded_file --- 将上传的文件移动到新位置
move_uploaded_file(string $from, string $to): bool
本函数检查并确保由 from 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 to 指定的文件。
参数
from: 上传的文件的文件名。
to: 移动文件到这个位置。
返回值
成功时返回 true。
如果 from 不是合法的上传文件,不会出现任何操作,move_uploaded_file() 将返回 false。
如果 from 是合法的上传文件,但出于某些原因无法移动,不会出现任何操作,move_uploaded_file() 将返回 false。此外还会发出一条警告。
*/
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "文件上传成功.\n";
} else {
echo "文件上传失败!\n";
}
注意:需要在 "upload.php" 文件所在的目录中创建一个名为 "uploads" 的新目录。上传的文件将保存在那里。
接受上传文件的 PHP 脚本为了决定接下来要对该文件进行哪些操作,应该实现任何逻辑上必要的检查。例如可以用 _FILES\['userfile'\]\['size'\] 变量来排除过大或过小的文件,也可以通过 _FILES['userfile']['type'] 变量来排除文件类型不相符合上传标准的文件。
如果表单中没有选择上传的文件,则 PHP 变量 _FILES\['userfile'\]\['size'\] 的值将为 0,_FILES['userfile']['tmp_name'] 将为空。
如果该文件没有被移动到其它地方也没有被改名,则该文件将在表单请求结束时被删除。
关于文件处理的学习过程就记录到此,更多关于文件处理的函数,可以查看文件系统函数。