PHP 简介07-文件操作

1.文件操作函数

1.回顾:

文件常见分类:file(文件) 和 dir(文件夹)

路径: 相对路径 . 当前目录 .. 上级目录

​ 绝对路径 (盘符型,网址型,根www)

2.文件属性:

1.文件类型:

filetype(' 文件路径 ') 输入一个文件路径,返回文件类型(file 文件|dir 文件夹)

2.文件大小:

filesize(' 文件路径 ') 输入一个文件路径,检测文件大小,单位是字节(不支持文件夹,结果不准确,以最小文件单元(4096字节)作为单元计算)

3.文件是否存在:

file_exists(' 文件路径 ') 输入一个路径,返回判断结果bool值

4.文件是否可读可写

is_readable(' 文件路径 ') 输入一个路径,判断是否可读,返回bool值

is_writeable(' 文件路径 ') 输入一个路径,判断是否可写,返回bool值

5.返回文件的创建/修改/访问时间

filectime(' 文件路径 ') 输入路径,返回文件的创建(creative)时间

filemtime(' 文件路径 ') 输入路径,返回文件的修改(modification)时间

fileatime(' 文件路径 ') 输入路径,返回文件的访问(access)时间

6.获取目录/文件名

dirname(' __FILE__ ') 输入当前文件路径,获取路径名(dir)

basename(' __FILE__ ') 输入当前文件路径,获取文件名(file)

1
2
3
4
5
6
需求:面试题 获取该地址的文件扩展名
$url = 'http://www.baidu.com/av/gt18/ka.n.g.mp4?age=18&type=人兽#xxoo';
$a=basename($url);
$a=strtok($a,'?');
$a=strrchr($a,'.');

7.网址解析

parse_url(' url ')

1
2
3
4
5
6
7
8
9
10
$url='http://www.baidu.com:80/av/gt18/ka.n.g.mp4?age=18&type=人兽#xxoo'
var_dump(parse_url($ur;));
/*array (size=6)
'scheme' => string 'http' (length=4) #协议
'host' => string 'www.baidu.com' (length=13) #域名
'port' => int 80 #端口
'path' => string '/av/gt18/ka.n.g.mp4' (length=19) #路径
'query' => string 'age=18&type=人兽' (length=18) #参数
'fragment' => string 'xxoo' (length=4)*/ #锚点

8.盘符解析

pathinfo(' $path ')

1
2
3
4
5
6
7
8
$path='D:\wamp\www\s86\0422\01-file.php';
var_dump($path);
/*array (size=4)
'dirname' => string 'D:\wamp\www\s86\0422' (length=20) #路径名
'basename' => string '01-file.php' (length=11) #文件名
'extension' => string 'php' (length=3) #扩展名
'filename' => string '01-file' (length=7)*/ #文件名(无后缀)

3.递归函数(三元归一遍历)

1.函数

opendir(' path ') 打开一个目录,返回资源

readdir(' resource name ') 读取一个资源,返回当前资源名(实际上利用指针)

close(' resource name ') 关闭一个资源,释放内存

2.应用

​ 需求:将./demo1 目录中的所有文件名,输出到屏幕上

​ 1.原始访问方式:

1
2
3
4
5
6
7
8
9
10
$handle=opendir('./demo1');		#windows中,每个文件夹中都有 . 和 .. 文件夹
var_dump(readdir($handle)); #当前目录 .
var_dump(readdir($handle)); #上级目录 ..
var_dump(readdir($handle));
...
var_dump(readdir($handle));

var_dump(readdir($handle)); #超出范围之外,返回false
closedir($handle);

​ 2.循环访问方式:

1
2
3
4
5
6
7
8
9
10
$handle=opendir('./demo1');
while( ($file=readdir($handle))!=false ){ #循环访问方式
if($file=='.'||$file=='..'){ #排除显示 . 和 ..
continue;
}
echo $file;
echo '<br>';
}
closedir($handle); #关闭资源

3.递归函数

1.函数:

is_file( 'path name' ) 判断当前路径是否为文件

is_dir( 'path name' ) 判断当前路径是否为目录

​ 注:参数必须为完整的地址,否则输出false。相对,绝对都可以

2.递归函数:

​ 1)函数自己调用自己

​ 2)必须要有终止条件

3.应用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1.需求:函数功能-输出所有子目录下的所有文件和子目录
function getFile( $dir )
{
$handle=opendir($dir); #打开目录,获取资源
while(($file=readdir($handle))!=false){ #读取资源
if($file=='.'|$file=='..'){ #排除 . 和 .. 文件夹
continue;
}
$path=$dir.'/'.$file; #拼凑完整路径
if(is_file($path)){ #判断是否为文件,是则输出文件名
echo $file.'<br>';
}
if(is_dir($path)){ #判断是否为目录,是则输出目录名,
echo $file.'<br>';
getFile($path); #调用函数打开子目录
}
}
closedir($handle); #关闭资源
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2.需求:函数功能-获取某个目录的大小
function getDirSize( $dir )
{
$handle=opendir($dir);
$sum=0;
while(($file=readdir($handle))!=false){
if($file='.'|'..'){
continue;
}
$path=$dir.'/'.$file;
if(is_file($path)){
$sum=$sum+fileseze($path);
}
if(is_dir($path)){
$sum+=getDieSize($path);
}
}
closedir($handle);
renturn $sum;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
3.需求:函数功能-统计某个目录下有多少个文件和文件夹
function getFileNumber( $dir )
{
$handle=opendir($dir);
$dirSum=0;
$fileSum=0;
while(($file=readdir($handle))!=false){
if($file='.'||$file='..'){
continue;
}
$path=$dir.'/'.$file;
if(is_file($path)){
$fileSum+=1;
}
if(is_dir($path)){
$dirSum+=getFileNumber($path);
$fileSum+=getFileNumber($path);
}
}
closedir($handle);
}

4.文件操作

1.拷贝文件

​ copy( 来源地址,目标地址 ) 将目标文件拷贝到目标文件中(不支持目录拷贝)

copy('./01-file.php','./demo1/01-file.php');

2.创建目录

​ mkdir( 目录路径 ) 在目标路径创建一个文件夹

​ mkdir( 目录路径,0777,true ) 在目标路径创建多级目录文件夹

mkdir('./x/y/z', 0777, true);

3.删除目录

​ rmdir( 目录路径 ) 只能删除空文件夹

rmdir('./x');

4.创建/删除文件

​ touch( 文件名 ) 创建文件

​ unlink( 文件名 ) 删除文件

touch('./demo1/test.php'); unlink('./demo1/test.php');

5.重命名/剪切文件

​ rename( 旧文件名,新文件名 ) 修改目录,剪切

rename('./test', './demo1/test.txt'); #修改目录,剪切

rename('./test.txt', './testxxx.txt'); # 目录不变,重命名

5.文件编码问题

Windows默认gbk编码,PHP默认utf-8编码,编码不一致时,会发生编码解析问题

​ iconv( 源编码,目标编码,内容 )

copy(iconv('utf-8','gbk','./递归.png'),'./xx.png')

6.baidu云盘递归遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>百度云盘</title>
<style>
table{width: 500px;/*height: 60px;*/margin:20px auto;border-collapse:collapse;font-size: 14px;}
table tr:hover{background: #f4fbff;}
table tr:hover th{border-color: #cbedff;}
table tr:hover td{border-color: #cbedff;}
table th{text-align: left;border-bottom:1px solid #ccc;/*line-height: 30px;*/border-color: #999;}
table td{border-bottom:1px solid #ccc;border-color: #999;}
.dir{background:url('./Baidu/icon.png') -380px -627px;width: 26px;height: 26px;display:inline-block;vertical-align: middle;}
.file{background:url('./Baidu/icon.png') -380px -627px;width: 26px;height: 26px;display:inline-block;vertical-align: middle;}
</style>
</head>
<body>
<table>
<tr>
<th>文件名</th>
<th>大小</th>
<th>修改日期</th>
</tr>
<!-- <tr>
<td><div class="dir"></div>我的卡包</td>
<td>xxx</td>
<td>xxxxxx</td>
</tr> -->
<?php
$x=empty($_GET['path'])?'./demo1':$_GET['path'];
getFileName($x);
?>

</table>
</body>
</html>


<?php

function getFileName($dir){

$handle=opendir($dir);

// $file=readdir($handle);

while(($file=readdir($handle))!=false){

echo '<tr>';

if ($file=='.'||$file=='..') {
continue;
}

$path=$dir.'/'.$file;

if (is_file($path)) {
echo '<td><div class="file"></div>'.$file.'</td>';
echo '<td>'.filesize($path).'</td>';
}

if (is_dir($path)) {
echo "<td><div class='dir'></div><a href='?path={$path}'>{$file}</a></td>";
echo '<td> - </td>';
}
echo '<td>'.filemtime($path).'</td>';

echo '</tr>';

}

closedir($handle);

}



?>


7.文件加载

1.函数:

include ' 文件路径 ' #加载(当做关键字使用) 依赖 require ' 文件路径 '

include( 文件路径 ) #加载(当做函数使用) 依赖 require( 文件路径 )

include_once( 文件路径 ) #加载一次 依赖 require_once( 文件路径 )

include_once ' 文件路径 ' #加载一次 依赖 require_once ' 文件路径 '

2.作用:

​ 将文件A加载到文件B中,文件B从而可以使用文件A中的所有数据

​ 相当于将文件A的所有代码复制到文件B中的 include / require

3.使用

include './demo.php'; require './demo.php';

include_once './demo.php'; require_once './demo.php';

4.特性

​ 1.include / require 可以重复加载

​ 2.但被重复加载的文件内部,函数和常量会被重定义,报错

​ 3.避免重复加载,可以通过include_once / require_once只加载一次

​ 4.include 加载出错,不会终止程序,require 加载出错,立马终止程序

​ 5.支持相对路径,盘符路径,不支持网址路径

8.文件内容操作函数

1.向文件赋予内容

file_put_contents('文件路径','文件内容');

​ 若文件路径不存在,则自动创建;若路径存在,则先将文件大小截为0,再写入内容(覆盖)

代码实例file_put_contents('./test.txt','how are you?');

2.获取文件的所有内容

file_get_contents('文件路径');

​ 支持全格式地址,若输入网址地址,则爬取跳转当前页面(只有外表,无功能)

代码实例echo file_get_contents('./test.txt');

echo file_get_contents('http://www.baidu.com');

3.打开一个文件

fopen('文件路径','打开模式'); 返回值:资源

​ #打开模式详解:

​ r 只读,指针指向文件开头,若文件不存在,报错

​ w 只写,指针指向文件开头,若文件不存在,则自动创建,且大小截为0

​ a 追加,指针指向文件末尾,若文件不存在,则自动创建

​ + 增强,既可以读又可以写,但需要以上模式配合

代码实例$handle=fopen('.test.txt','r');

4.读取内容

fread('文件资源','字节'); 读取资源,返回内容,每次读取指定字节数据

​ 当函数读取资源超出资源范围时,返回空字符串

1
2
3
4
5
读取方式1:
while( ($x=fread($handle,1)) !== '' ){
echo $x;
}

1
2
3
4
读取方式2:
echo fread($handle,11);
echo fread($handle,filesize('./test.txt'));

5.写入内容

fwrite('文件资源','内容')

​ 将内容写入目标文件,写入方式由 fopen() 的打开模式决定

​ 代码实例:

1
2
3
4
1.写入:
$handle=fopen('./text.txt','w');
fwrite($handle,'MVP'); #MVP

1
2
3
4
2.追加:
$handle=fopen('.text.txt','a');
fwrite($handle,'ADD'); #MVPADD

1
2
3
4
3.增强:r+
$handle=fopen('./test.txt','r+');
fwrite($handle,'abc'); #abcADD(覆盖前面的)

1
2
3
4
4.增强:w+
$handle=fopen('./test.txt','w+');
fwrite($handle,'def'); #def(覆盖全部的)

1
2
3
4
5.增强:a+
$handle=fopen('./test.txt','a+');
fwrite($handle,'GG'); #defGG(覆盖全部的)

6.关闭资源

fclose($handle); 释放内存,节省空间

9.文件上传

1.文件上传限制:

  • 表单限制 MAX_FILE_SIZE HTML页面自定义大小,一旦超过,error=2

    ​ 可通过F12跳过限制(一般都是通过隐藏域MAX_FILE_SIZE修改赋值)

  • post协议限制 post_max_size 一旦超过8M,$_FILES直接为空

  • 服务器限制 upload_max_filesize 一旦超过2M,error=1

2.文件上传相关函数

​ $_FILES 专门用于接收上传文件,返回结果为数组

​ $is_uploaded_file( 临时文件地址 ) 检测是否通过post发送,返回bool值

​ uniqid() 基于一微秒产生的唯一ID,适合低频率

​ file_exists( ) 文件是否存在,返回bool

​ move_uploaded_file( 临时文件,目标文件 ) 移动临时文件到存储目录

1
2
3
4
5
6
7
8
9
10
array (size=1)
'icon' =>
array (size=5)
icon => file表单的name名
name => 上传的文件名
type => 上传的文件类型
tmp_name => 临时文件
error => 错误号 0:没错 非0:有错
size => 上传的文件大小

​ 上传文件初版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function upload()
{
#1.检测文件是否符合服务器大小限制($_FILES是否为空)
$key=key($_FILES);
if(is_null($key)){ #若超过8M,错误号2,post协议不通过,FILES数组为空
echo '文件太大,上传失败';
echo <meta http-equiv="refresh"content="3;url='.$_SERVER['HTTP_REFERER'].'">;
die; #回到上一级
}

#2.获取错误号,输出错误信息
$error=$_FILES[$key]['error']; #获取当前错误号
if($error!=0){ #若错误号不为0,即上传失败,输出原因
switch($error){
case1:echo '文件太大,上传失败';break;
case2:echo '文件太大,上传失败';break;
case3:echo '网络中断';break;
case4:echo '未上传文件';break;
case6:echo '服务器繁忙(服务器存储目录丢失)';break;
case7:echo '服务器繁忙(权限不足)';break;
}
echo <meta http-equiv="refresh"content="3;url='.$_SERVER['HTTP_REFERER'].'">;
die;
}

#3.检测是否是post上传过来的
$tmp=$_FILES[$key]['tmp_name']; #获取缓存目录
if(!is_uploaded_file($tmp)){ #是否通过post发送
echo '非法上传';
echo <meta http-equiv="refresh"content="3;url='.$_SERVER['HTTP_REFERER'].'">;
die;
}

#4.检测文件类型是否符合要求
$type=strtok($_FILES[$key]['type'],'/'); #获取文件类型
$allowType=['image']; #准备允许的类型
if(!in_array($type,$allowType)){
echo '上传类型不符合要求';
echo <meta http-equiv="refresh"content="3;url='.$_SERVER['HTTP_REFERER'].'">;
}

#5.设计新的文件名(唯一)(格式:20190423xxxx.jpg)
$suffix=strrchr($_FILES[$key]['name'],'.'); #4.1获取扩展名
$filename=date('Ymd').uniqid().$suffix; #产生唯一ID

#6.设置存储目录 upload/年/月/日/
$dir='upload/'.date('/Y/m/d/');
if(!file_exists($dir)){
mkdir($dir,0777,true);
}
#7.移动临时文件到存储目录
if(move_upload_file($tmp,$dir.$filename)){
echo '上传成功';
}else{
echo '上传失败';
}
}


​ 上传文件完全版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* upload 单文件上传
* @param string $saveDir 存储目录
* @param array $allowType 允许类型
* @return string 错误信息
* @return array 新的文件名
*/
function upload($saveDir='uploads/',$allowType=['image'])
{
#1.检测文件是否符合服务器大小限制($_FILES是否为空)
$key=key($_FILES);
if(is_null($key)){ #若超过8M,错误号2,post协议不通过,FILES数组为空
return '文件太大,上传失败'; #返回信息
}

#2.获取错误号,输出错误信息
$error=$_FILES[$key]['error']; #获取当前错误号
if($error!=0){ #若错误号不为0,即上传失败,输出原因
switch($error){
case 1:return '文件太大,上传失败';break;
case 2:return '文件太大,上传失败';break;
case 3:return '网络中断';break;
case 4:return '未上传文件';break;
case 6:return '服务器繁忙(服务器存储目录丢失)';break;
case 7:return '服务器繁忙(权限不足)';break;
}
}

#3.检测是否是post上传过来的
$tmp=$_FILES[$key]['tmp_name']; #获取缓存目录
if(!is_uploaded_file($tmp)){ #是否通过post发送
return '非法上传';
}

#4.检测文件类型是否符合要求
$type=strtok($_FILES[$key]['type'],'/'); #获取文件类型
if(!in_array($type,$allowType)){
return '上传类型不符合要求';
}

#5.设计新的文件名(唯一)(格式:20190423xxxx.jpg)
$suffix=strrchr($_FILES[$key]['name'],'.'); #4.1获取扩展名
$filename=date('Ymd').uniqid().$suffix; #产生唯一ID

#6.设置存储目录 upload/年/月/日/
$dir=$saveDir.date('/Y/m/d/');
if(!file_exists($dir)){
mkdir($dir,0777,true);
}
#7.移动临时文件到存储目录
if(move_uploaded_file($tmp,$dir.$filename)){
return [$filename];
}else{
return '上传失败';
}
}

$result=upload();
if(is_array($result)){
notice('上传成功','http://www.baidu.con');
}else{
notice($result);
}

/**
* notice 提示信息
* @param string $info 提示信息
* @param string $url 提示之后的跳转地址
* @param integer $time 几秒后进行跳转
*/
function notice($info,$url=null,$time=3)
{
echo $info;
if($is_null($url)){
$url=$_SERVER['HTTP_REFERER'];
}
echo "<meta http-equiv='refresh' content='{$time}; url={$url}'>";
die;
}

10.文件下载

1.步骤

​ 1.接收下载的文件名

1
2
3
$name = $_GET['name'];
$suffix=strchr($name,'');

​ 2.凑完整的路径

1
2
$path = './download/'.$name;

​ 3.准备下载之后的名字

1
2
3
$filename=str_shuffle(md5($name)).$suffix;
header("content-disposition:attachment;filename={$filename}");

​ 4.读取文件内容

1
2
readfile($path);