标题:PHP中的文件系统函数(二)
PHP中的文件系统函数(二)
这次我们来学习的是一些不是太常用,但却也非常有用的一些函数。它们中有些大家可能见过或者使用过,有一些可能就真的没什么印象了。它们都是 PHP 中文件系统相关操作函数的一部分。存在即合理,或许只是我们的业务开发中还没有接触到而已。不管别的,先混个脸熟,在真正需要它们的时候你能马上想起来 PHP 就自带一个这样的函数就可以了。
目录判断、创建、删除、路径缓存信息
var_dump(is_dir("./")); // bool(true)
var_dump(disk_free_space("./")); // float(7727517696)
var_dump(disk_total_space("./")); // float(250790436864)
is_dir() 函数估计大家会比较常用,就是用来判断给定的路径是否存在或者是否正常。一般在手动创建目录之前都会使用这个函数来判断一下目录是否已经创建过了,常见于上传相关的业务场景开发中。disk_free_space() 和 disk_total_space() 则是获取指定目录的剩余磁盘空间和总的磁盘空间数据的函数。因为我的电脑是 Mac 系统,所以总的磁盘空间就是 250G 的,可用的空间为 7G ,看来马上就要准备清理一下电脑了。
var_dump(mkdir("./a")); // bool(true)
var_dump(rmdir("./a")); // bool(true)
mkdir() 函数用于创建一个目录,它除了给定的路径参数外,还有一个可选参数可以设置目录的文件权限,也是传递 0777 之类的值就可以了,这个函数相信大家不会很陌生,大部分的文件上传分目录的能力正是使用 is_dir() 来配合 mkdir() 进行目录创建的。rmdir() 是用于删除目录的,这个函数有两个前提,一是要删除的目录必须是空的,二是要有删除这个目录的权限,如果任一条件不满足的话,就会报出一个 E_WARNING 级别的错误。
realpath('./');
var_dump(realpath_cache_get());
// array(8) {
// ["/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202010/source"]=>
// array(4) {
// ["key"]=>
// float(1.4990943845035E+19)
// ["is_dir"]=>
// bool(true)
// ["realpath"]=>
// string(61) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202010/source"
// ["expires"]=>
// int(1603327834)
// }
// ["/Users/zhangyue/MyDoc/博客文章"]=>
// array(4) {
// ["key"]=>
// int(8597410586338680)
// ["is_dir"]=>
// bool(true)
// ["realpath"]=>
// string(34) "/Users/zhangyue/MyDoc/博客文章"
// ["expires"]=>
// int(1603327834)
// }
// ["/Users"]=>
// ……
// ……
var_dump(realpath_cache_size()); // int(673)
realpath_cache_get() 函数用于获取真实目录缓存的详情,我们需要先使用 realpath() 获得一个目录路径,然后就可以看到 realpath_cache_get() 里面的内容。可以看出它返回的数组中,是这条路径从第一个目录到这个目录中的所有目录信息,包括每一级目录的 realpath 、 is_dir 等属性信息。realpath_cache_size() 获取的是真实路径缓冲区的大小,也就是真实路径缓存区大小在内存中的使用量。
软连接信息
上篇文章中我们已经学过了如何创建连接文件,这次我们再来看看两个小的关于连接信息的函数。
var_dump(readlink('ltest2.txt')); // "test.txt"
var_dump(is_link('ltest2.txt')); // bool(true)
readlink() 函数用于获得软连接所连接到的真实文件的名称。在上篇文章中,我们创建的 ltest2.txt 文件正是 test.txt 文件的软连接。而 is_link() 函数则用于判断给定的文件是否是一个连接文件。
拷贝、移动、改名、删除文件操作
var_dump(copy('test.txt', 'cp_test.txt')); // bool(true)
var_dump(is_file("cp_test.txt")); // bool(true)
var_dump(move_uploaded_file('test.txt', 'mv_upload_test.txt')); // bool(false)
var_dump(is_file("mv_upload_test.txt")); // bool(false)
var_dump(is_uploaded_file("mv_upload_test.txt")); // bool(false)
var_dump(copy('test.txt', 're_test.txt')); // bool(true)
var_dump(rename('re_test.txt', 'new_re_test.txt')); // bool(true)
var_dump(copy('test.txt', 'del_test.txt')); // bool(true)
var_dump(unlink("del_test.txt")); // bool(true)
对于文件来说,copy() 是非常常用的一个函数。不管是写代码还是日常办公,复制粘贴这样的拷贝操作都是我们工作中的重心所在。PHP 提供的 copy() 函数就是专门用于文件拷贝的,不过需要注意的是,一定要有文件和拷贝目标目录的读写权限哦。
move_uploaded_file() 文件相信大家也是非常熟悉的,在上传文件的操作中也是经常会用到的一个功能。不过需要注意的是,从文件名就可以看出,move_uploaded_file() 的作用是移动已上传文件,也就是 $_FILES 里面 tmp 中的文件,它是不能当做 copy() 函数来使用的。从演示代码中就可以看出,对于普通文件来说,它是无法拷贝移动的。is_uploaded_file() 函数就是用于判断要操作的文件是不是一个 PHP 已上传文件。
通过上面这两个函数,相信不少人都会想到文件上传中他们的使用,这里就给出一个简单的伪代码。
if(!move_uploaded_file('xxxx', 'xxxx')){
if(copy('xxxx', 'xxxx')){
// 上传成功
}else{
// 上传失败
}
}
很多教程里都会有这样的写法,甚至一些框架中也会有这样的写法。其实就是先使用 move_uploaded_file() 去移动上传文件,如果失败了,再使用 copy() 函数拷贝一次。如果还是失败了,就认为整个上传操作失败了。
rename() 函数用于给文件改名,其实它就是类似于 Linux 系统中的 mv 命令。
is_file() 函数用于判断给定的文件是否是一个正常的文件。在操作系统中,特别是 Linux 系统中,一切皆文件,所以这个函数真正最常用的场景是判断给定的路径到底是目录还是一个文件,很多时候我们会用它来判断上传成功后的文件是否正常,或者判断一个给定的路径到底是一个目录还是一个文件。
最后就是 unlink() 函数。在 PHP 中,没有 delete 或者 rm 这样的函数,unlink() 就是用于删除文件的。不过它的名字起得却像是要解除符号连接文件的连接一样,不管是连接文件还是普通文件,都是通过这个 unlink() 函数来进行删除的。
文件一次性读取
关于文件一次性读取到内容和流式按字节或行来读取的内容我们之前已经有一篇文章详细的学习讲解过,大家可以移步 PHP大文件读取操作 中查看。所以这里我们就简单的贴出代码演示一下。
var_dump(file_exists('test.txt')); // bool(true)
var_dump(readfile('test.txt')); // asdfasdfint(8)
var_dump(file('test.txt'));
// array(1) {
// [0]=>
// string(8) "asdfasdf"
// }
$c = file_get_contents('test.txt');
var_dump($c); // string(8) "asdfasdf"
var_dump(file_put_contents('fpc_test.txt', $c)); // int(8)
file_exists() 函数是专业的用于判断文件是否存在的函数,上面的 is_file() 会更多地用于上传之后的操作。而 file_exists() 则是在日常的代码编写中非常常用的函数。readfile() 直接读取文件内容到内容中,file_get_contents() 也是这样的功能,只不过 file_get_contents() 返回的是以字符串为格式的文件内容。注意看我们 var_dump() 的结果,file_get_contents() 明显的标了是 string(8) 这样的类型,而 readfile() 是直接输出内容,不走缓冲区的,也就是说它是类似于 phpinfo() 这样的函数。需要使用 ob_start() 之类的函数才能将 readfile() 函数读取的内容放到一个变量中,我们之前的文章也专门讲过缓冲区的概念,PHP中的输出缓冲控制 。它的返回值是文件的字节数,也就是后面的 int(8) 。
file() 函数是将文件的内容保存到一个数组中,它会默认以行进行分隔,也就是每一行分为数组中的一个元素。
file_put_contents() 是将给定的内容写入到一个文件中,和 file_get_contents() 配合也可以实现一个拷贝的操作。
文件属性
var_dump(fileatime('test.txt')); // int(1603243708)
var_dump(filectime('test.txt')); // int(1603242166)
var_dump(filemtime('test.txt')); // int(1603242166)
var_dump(fileinode('test.txt')); // int(8707958352)
var_dump(filesize('test.txt')); // int(8)
var_dump(filetype('test.txt')); // string(4) "file"
var_dump(is_executable('test.txt')); // bool(true)
var_dump(is_writable('test.txt')); // bool(true)
var_dump(is_readable('test.txt')); // bool(true)
很明显,fileatime() 、filectime() 、filemtime() 对应的就是文件的上次访问时间、inode修改时间以及修改时间,和 Linux 系统中的文件相关的那三个时间概念一致。fileinode() 用于获得文件的 inode 信息。filesize() 就是文件的大小,filetype() 是文件的类型信息。
is_executable() 用于判断文件是否可以执行,is_writable() 、is_readable() 判断文件是否可以写和读。这三个函数对应的就是文件的权限相关的判断。
创建不重名文件及临时文件
var_dump(tempnam('./', 't_')); // string(70) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/202010/source/t_Gx6S5d"
$temp = tmpfile();
fwrite($temp, "writing to tempfile");
fseek($temp, 0);
// sleep(30); // /tmp/phpU2LZ3V 文件
echo fread($temp, 1024), PHP_EOL; // writing to tempfile
fclose($temp); // 文件直接被删除了
tempnam() 函数会根据指定的 prefix 参数来生成一个随机不重名的空文件。在测试代码中,我们给定的 prefix 的值是 t_ ,最后生成的文件就是 t_Gx655d 这样一个空的文件。
tmpfile() 在之前的文章中也讲解过,它是生成一个临时文件,一般会放在 /tmp 目录下(如果你没有修改 php.ini 文件中的相关设置的话)。这个函数创建文件后会返回一个句柄,一旦使用 fclose() 关闭了这个文件句柄,那么文件就马上会被删除掉。
按规则返回目录内容
foreach (glob("*.txt") as $filename) {
echo "$filename size: " . filesize($filename) , PHP_EOL;
}
// cp_test.txt size 8
// fpc_test.txt size 8
// ltest.txt size 8
// ltest2.txt size 8
// new_re_test.txt size 8
// test.txt size 8
// test3.txt size 0
foreach (glob("../../202009/*.md") as $filename) {
echo "$filename size: " . filesize($filename) , PHP_EOL;
}
// ./../202009/1.PHP中的PDO操作学习(三)预处理类及绑定数据.md size: 16881
// ../../202009/10.PHP中非常好玩的Calendar扩展学习.md size: 8784
// ../../202009/11.学习PHP中的国际化功能来查看货币及日期信息.md size: 5521
// ../../202009/12.PHP中的日期相关函数(一).md size: 14217
// ../../202009/13.PHP中的日期相关函数(二).md size: 9858
// ../../202009/2.PHP中的PDO操作学习(四)查询结构集.md size: 12825
// ../../202009/3.在PHP中使用SPL库中的对象方法进行XML与数组的转换.md size: 6068
// ../../202009/4.PHP中的MySQLi扩展学习(一)MySQLi介绍.md size: 6029
// ../../202009/5.PHP中的MySQLi扩展学习(二)mysqli类的一些少见的属性方法.md size: 9726
// ../../202009/6.PHP中的MySQLi扩展学习(三)mysqli的基本操作.md size: 9403
// ../../202009/7.PHP中的MySQLi扩展学习(四)mysqli的事务与预处理语句.md size: 3556
// ../../202009/8.PHP中的MySQLi扩展学习(五)MySQLI_STMT对象操作.md size: 7450
// ../../202009/9.PHP中的MySQLi扩展学习(六)MySQLI_result对象操作.md size: 10650
glob 函数也是之前有讲解过的一个函数,它会根据指定的规则返回目录中的所有文件或者目录信息。可以方便地用于目录地遍历操作。注意这里的规则参数不是完全的正则表达式,关于它具体支持的语法可以自行查阅相关的文档。
文件 umask 操作
$old = umask(0);
echo $old, PHP_EOL; // 18
$now = umask();
echo $now, PHP_EOL; // 0
umask() 函数就是操作当前执行进程的 umask 信息,和 Linux 中的 umask 命令一样,用于指定当前创建的目录文件的默认权限信息。在 PHP 中,umask() 将 PHP 的 umask 设定为 mask & 0777 ,并返回原来的 umask 。当 PHP 被作为服务器模块使用时,在每个请求结束后 umask 会被恢复。具体的 umask 知识大家可以参考 Linux 中的相关内容。
配置文件信息读取
最后这两个函数是用于读取 PHP 类型的配置文件信息的,什么叫 PHP 类型的配置文件信息?其实就是类似于 php.ini 文件那样的配置文件,key=value 这种形式的配置文件。就像 Laravel 的 .env 文件也是可以使用这两个函数进行读取的。
var_dump(parse_ini_file('/usr/local/etc/php/7.3/php.ini'));
// array(133) {
// ["#zend_extension"]=>
// string(9) "xdebug.so"
// ["extension"]=>
// string(6) "vld.so"
// ["engine"]=>
// ……
// ……
var_dump(parse_ini_file('/usr/local/etc/php/7.3/php.ini', true));
// array(38) {
// ["#zend_extension"]=>
// string(9) "xdebug.so"
// ["extension"]=>
// string(6) "vld.so"
// ["PHP"]=>
// array(45) {
// ["engine"]=>
// string(1) "1"
// ["short_open_tag"]=>
// ……
// ……
parse_ini_file() 函数就是直接读取指定路径的配置文件内容,在这里我们直接测试的就是读取 php.ini 文件。它有一个可选参数,如果设置为 true 的话,返回的就是数组分类的结构化的内容。
$ini = file_get_contents('/usr/local/etc/php/7.3/php.ini');
var_dump(parse_ini_string($ini));
// array(133) {
// ["#zend_extension"]=>
// string(9) "xdebug.so"
// ["extension"]=>
// string(6) "vld.so"
// ["engine"]=>
// ……
// ……
var_dump(parse_ini_string($ini, true));
// array(38) {
// ["#zend_extension"]=>
// string(9) "xdebug.so"
// ["extension"]=>
// string(6) "vld.so"
// ["PHP"]=>
// array(45) {
// ["engine"]=>
// string(1) "1"
// ["short_open_tag"]=>
// ……
// ……
parse_ini_string() 则是从给定的字符串中读取配置信息,同样也有一个格式化分组输出的参数可选。它和 parse_ini_file() 是完全相同的,唯一的区别就是一个是从文件路径读取,一个是从字符串读取。
总结
一口气介绍了这么多函数,大家是不是都用过呢?有人要说了,写这玩意干嘛,直接去看文档不就好了嘛?那可不一样哦,文档中很多函数的介绍就一句话,示例代码也都是使用英文注释的,咱这虽说也是一个搬运工,但咱不仅是简单地搬运了一下,还把例子重写了,另外还加上了一些应用场景的介绍哦!至于各位看官感觉好不好,那就仁者见仁,智者见智咯!
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/7.PHP中的文件系统函数(二).php
参考文档:
https://www.php.net/manual/zh/ref.filesystem.php