这是咱们前面讲过动态网页的结构,那么我们根据这个图回忆一下前面学的东西。
咱们前面学了php的变量、运算符和流程控制,是不是相当于我们学会了做“运算器”
咱们学的表单、http的请求以及 _POST等是不是相当于学会了“输入设备”
咱们捋一下流程:
通过http请求(含数据),
_GET接收数据,然后php运算处理,返回给浏览器
graph LR
http请求-->$_POST/$_GET接收数据
$_POST/$_GET接收数据-->PHP运算处理
PHP运算处理-->返回到浏览器输出
其实我们是不是已经完整的学完了一种动态网页访问流程。不过咱们这个流程似乎比着上面的流程还有点去区别,就是少了存储器。
其实存储器是存在的,比如我们前面写的例子:
<?php
$id = $_GET['id'];
//方法1
/*$content = '';
if ($id == 1) {
$content = '文章1的内容';
}elseif ($id == 2) {
$content = '文章2的内容';
}elseif ($id == 3) {
$content = '文章3的内容';
}elseif ($id == 4) {
$content = '文章4的内容';
}elseif ($id == 5) {
$content = '文章1的内容';
}else{
$content = '错误,没有这个文章';
}
echo $content;*/
//方法2
$articles = array('文章1的内容','文章2的内容','文章3的内容','文章4的内容','文章5的内容');
$num = $id - 1;
if(in_array($num, array(0,1,2,3,4,5))){
echo $articles[$num];
}else{
echo '错误,没有这个文章';
}
第一种方法,我们把内容写在了php运算过程中了,和运算混写在一起了;第二种方法中,我们把数据保存在一个数据里,然后根据传来的参数去数据里调配内容。
这两种写法,都是把php的运算处理和数据的保存放到一起,第二种方法虽然似乎分离开来写,但是最终的保存还是在同一个文件里。
这样是不是说明,咱们动态网页的访问流程中有内容存储的过程?这样我们前面的那个流程图的所有部分是不是都涉及到了?
这样写虽然能达到保存数据的目的,但是他的缺点也是十分明显的,比如:如果在其它的文件里我们也需要调去一篇文章的内容,就必须要再写一遍文章的内容保存到新建的这个php文件中,如果将来这篇文章内容有修改,那么是不是要把涉及这篇文章的所有文件都要修改一遍?这样是不是非常麻烦,非常的不易维护?这个问题怎么解决?
其实,通过前面我们的两个方法的对比,我们就能看出思想:分离。方法2中,我们把功能不同的部分分开,php运算的部分写一块,内容保存的部分写在另外一块。那么我们完全可以把保存也分离开来,比如我们把文章的内容保存在一个文件中,所有需要运算的代码都去这个文件读取内容,然后需要更改的时候,只需要修改一下这个文件里的内容就行了。
那么接下来,我们就学习一下php对文件的操作:
前面我们说了:
我们把文章的内容保存在一个文件中,所有需要运算的代码都去这个文件读取内容,然后需要更改的时候,只需要修改一下这个文件里的内容就行了
这段话是不是说明我们对文件的操作有三种情况:“读”、“写”、“修改”,其实修改也就是“读”和“写”一种连续操作,那么我们其实对文件的操作就剩两种情况:“读”和“写”
读文件
我们平时读取一个文件的一个流程是什么?
graph LR
找到文件-->打开文件
打开文件-->读取内容
读取内容-->关闭文件
php的读取文件也是按照这个流程的,每一步操作都有自己内置的函数:
获取文件长度:filesize
打开文件:fopen
读取文件:fread
关闭文件:fclose
$f = fopen('./file', 'r');
print_r($f);
我们先打开一下文件,不要在意文件的后缀名,看看返回值是什么!
我们可以看到,返回值是Resource,这是一个资源类型,我们前面学变量的类型的时候,讲过有哪8大类型?
什么是资源类型? PHP手册(语言参考部分)中这样定义的:资源 resource 是一种特殊变量,保存了到外部资源的一个引用。简单的来说,我们可以把它理解成一个通道,通过这个通道,我们可以对外部资源进行操作,就像我们喝牛奶时用的吸管一样,我们可以通过这个吸管吸出牛奶,也可以通过这个习惯从外部往牛奶盒里灌装牛奶。
同样的,我们通过前面打开的资源可以读数据,就像通过吸管吸出牛奶一样。
$f = fopen('./file', 'r');
$res = fread($f, 3);
print_r($res);
fclose($f);
echo gettype($res);
如果我们想全部读取出来,怎么操作?这就用到了我们的filesize函数了。
$f = fopen('./file', 'r');
$res = fread($f, filesize('./file'));
print_r($res);
fclose($f);
echo gettype($res);
我们可以看到文件的内容被读出来了,如果我们保存每篇文章内容的时候用特殊的符号做个分割标记,我们拿着读取到的数据,用我们前面学的把字符串分割成数组的函数分割成数组,然后再根据接收来的参数,做出不同的返回值就行了。
分隔符的选择:尽量避免可能和文章的内容相同就行,比如我们可以用“{!:delimiter:!}”作为分隔符。
比如咱们文章的内容是这样的:
文章11的内容{!:delimiter:!}文章22的内容{!:delimiter:!}文章33的内容{!:delimiter:!}文章44的内容{!:delimiter:!}文章55的内容
$f = fopen('./file', 'r');
$res = fread($f, filesize('./file'));
fclose($f);
$articles = explode('{!:delimiter:!}', $res);
print_r($articles);
通过打印结果,我们是不是可以看到,前面的那个文章列表的代码可以这样改写了。
$f = fopen('./file', 'r');
$res = fread($f, filesize('./file'));
fclose($f);
$articles = explode('{!:delimiter:!}', $res);
$num = $id - 1;
if(in_array($num, array(0,1,2,3,4,5))){
echo $articles[$num];
}else{
echo '错误,没有这个文章';
}
写文件
前面我们学了读文件,接下来我们学习写文件,还是老路子,我们平时写文件的流程是什么?
先看看写入文件流程:
graph LR
找到文件-->打开文件
打开文件-->写入内容
写入内容-->关闭文件
修改文件内容流程:
graph LR
找到文件-->打开文件
打开文件-->读取内容
读取内容-->找到修改的部分
找到修改的部分-->修改内容
修改内容-->写入新内容
写入新内容-->关闭文件
从流程中可以看到,咱们流程比着前面的“读文件流程”只多个“写入内容”,写入文件PHP用的是fwrite。下面我们写一遍:
添加文件内容:
//开头写入模式打开
/*$f = fopen('./file', 'w');
$content = '我是中国人!';
fwrite($f, $content);
fclose($f);*/
//追加写入模式打开
$f = fopen('./file', 'a');
$content = '我爱中国!';
fwrite($f, $content);
fclose($f);
接下来我们看看修改文件内容:
//读写模式打开文件
$f = fopen('./file', 'r+');
//读取文件的所有内容
$result = fread($f, filesize('./file'));
//对文件内容进行修改
$result_array = explode('{!:delimiter:!}', $result);
$change = '我是修改文章33后的内容';
$result_array[2] = $change;
$result_string = implode('{!:delimiter:!}', $result_array);
//将新内容写入文件
fwrite($f, $result_string);
fclose($f);
运行该段程序后,我们会发现,并不是我们想要的结果,它直接在文件的后面追加内容了,可是我们明明用“r+”打开的文件啊,“r+”模式打开,文件的指针不是在开头吗?想一想为什么。
其实原因也很简单,因为我们使用fread的时候,把文件的指针移动到了内容的末尾,因此,这个时候我们写入,就是从内容的末尾开始写入的。因此,如果想覆盖写入,只需要将文件指针移到开头就行了,移动文件指针到开头的函数是:rewind();那么为omen的代码这样修改一下就行了:
//读写模式打开文件
$f = fopen('./file', 'r+');
//读取文件的所有内容
$result = fread($f, filesize('./file'));
//对文件内容进行修改
$result_array = explode('{!:delimiter:!}', $result);
$change = '我是修改文章33后的内容';
$result_array[2] = $change;
$result_string = implode('{!:delimiter:!}', $result_array);
//移动文件指针到开头
rewind($f);
//将新内容写入文件
fwrite($f, $result_string);
fclose($f);
其实,我们会发现,我们不管读还是写,流程基本是一样,每次都要写这些代码,根据我们前面学的函数思想,我们完全可以把读和写内容分别封装成函数,每次读的时候,传点参数就行了。
不过php关于文件的读写,已经给我们封装过两个函数:
file_put_contents 和 file_get_contents
下面我带着大家简单的学一下这两个的简单用法,具体的其它用法需要大家课下好好的看手册和查资料。
file_put_contents( data[, context])
和依次调用fopen(),fwrite() 以及 fclose() 功能一样,我们这里就学习一下他的写入文件
$data = 'DDDDDDDDDDDDDDDDDDDD';
print_r(file_put_contents('./putcontent', $data));
默认情况下,如果被写入的文件存在,那么是覆盖写入内容,如果想追加写入,可以置顶第三个参数为:FILE_APPEND 即可。
$data = 'EEEEEEEEEEEEEEEE';
print_r(file_put_contents('./putcontent', $data, FILE_APPEND));
$data 也可以为数组
$data = array('aaaaaaaaaa', 'CCCCCCCCC', 'bbbbbbbbbb');
print_r(file_put_contents('./putcontent', $data));
file_get_contents($path)
print_r(file_get_contents('./putcontent'));