文章目录
表单传值
概念
表单传值即通过浏览器通过表单元素将用户的选择或者输入的数据提交给后台服务器语言
为什么使用表单传值
动态网站(WEB2.0)的特点就是后台根据用户的需求定制数据,所谓的“需求”就是用户通过当前的选择或者输入的数据信息,表单就是这些数据的承载者
表单传值方式
GET传值
- form表单
<form method = "get"></form>
- a标签
<a href="www.itcast.cn/index/php?学科=php">
- location对象的href属性
<script>location.href="www.itcast.cn/index.php?data=php"</script>
- location对象的assign()方法
<script>location.assign("www.itcast.cn/index.php?data=php")</script>
POST传值
<form method="post"></form>
GET传值和POST传值的区别
- GET传输的数据主要用来获取数据,不改变服务器上的资源
- POST传输的数据主要用来增加数据,会改变服务器上的资源
- 传输方式上POST必须使用form表单,而GET可以使用form和URL
- GET传输数据可以在URL中对外可见(GET传值最终会在浏览器的地址栏中全部显示:?数据名=数据值&数据名2=数据值2…),而POST不可见
- GET和POST能传输的数据大小不同,GET为2k,POST理论上无限制(事实上GET和POST本身没有数据长度限制,但是浏览器厂家做了限制)
- GET和POST能够传输的数据格式有区别:GET传输简单数据(数值/字符串),POST可以提交复杂数据(如二进制)
PHP接收数据的三种方式
$_GET
方式:接受GET方式提交的数据$_POST
方式:接受POST方式提交的数据$_REQUEST
方式:接受POST或者GET提交的所有数据
不管是$_GET
,$_POST
还是$_REQUEST
,三个都是PHP超全局预定义数组,表单元素的name属性的值作为数组的下标,而value属性对应的值就是数组的元素值
$_REQUEST
存储数据本质上就是将$_POST
和$_GET
合并存储到一个数组,如果数组下标冲突,那么POST会覆盖GET
PHP处理复选框数据
复选框单项的命名方式
复选框通常是将一类内容以同名的形式传递给后台,数据库存储通常是一个字段存储
① 在浏览器端,checkbox的name属性不论什么都会被浏览器毫无保留的提交
② 在PHP中$_POST/$_GET都会对同名name属性进行覆盖
解决方案:浏览器不识别[]
(浏览器不认为有特殊性),但是PHP认为[]
有特殊性,会认为该符号是数组的形式,所以PHP就会自动的将同名但是带有[]
的元素组合到一起形成一个数组
单选按钮的数据处理
- 表单中的name属性必须使用同名
- 后台接受数据也不需要额外处理
- 数据库存储的话只需要一个字段存储普通数据即可
- PHP拿到数据之后,组织SQL直接存储到数据表即可
多选按钮的数据处理
- 表单中name属性使用数组格式:名字[]
- 后台接受到数据之后是一个数组(数组不能存储到数据库)
- PHP需要将数组转换成指定格式的字符串:使用分隔符分隔每一个元素并且形成字符串:
inplode('分隔符',数组)
- PHP组织SQL直接存储到数据库
- 从数据库取出时,使用
explode
把字符串变成数组
无选中情况
如果表单提交时没有复选框或者单选框被选中,那么浏览器就不会提交复选框或单选框的内容,因此在PHP使用单/复选框时需要先判断是否存在该数据
文件上传
原理
文件上传:文件从用户本地电脑通过传输方式(WEB表单)保存到服务器所在电脑的指定目录下
- 增加文件上传表单:浏览器请求一个服务器的HTML脚本(包含文件上传表单)
- 用户从本地选择一个文件(点击上传框(按钮))
- 用户点击上传:文件会通过互联网传输到服务器上
- 服务器操作系统会将文件保存到临时目录:是以临时文件格式保存(windows下为tmp)
- 服务器脚本开始工作:判断文件有效
- 服务器脚本将有效文件从临时目录移动到指定的目录下(完成)
表单编写
method
属性:文件表单提交方式必须为POSTenctype
属性:form表单属性,主要是规范表单数据的编码方式
在PHP中接收文件
在PHP中有一个预定义变量$_FILES
专门用来存储用户上传的文件
$_FILES变量详解
name
:文件在用户(浏览器端)电脑上实际存在的名字(用来保留后缀)tmp_name
:文件上传到服务器后操作系统保存的临时路径(用来给PHP后期使用)type
:NIME(多功能互联网邮件扩展)类型,用来在计算机中客户端识别文件类型(确定用什么软件打开)error
:文件上传的代号,用来告知应用软件(PHP)文件接受过程中出现了什么问题(PHP后期根据代码进行文件判断)size
:文件大小(PHP根据实际需求来确定是否保留)
移动临时文件到目标位置
文件上传之后会保存到$_FILES中,那么访问文件信息的形式就是$_FILES['表单name属性值']['元素信息']
- 判断是否为上传的文件:
is_uploaded_file()
- 移动文件:
move_uploaded_file()
<?php
$file = $_FILES['img']; //获取文件信息
if (is_uploaded_file($file['tmp_name'])) { //判断是否为上传的文件
if (move_uploaded_file($file['tmp_name'], 'uploads/' . $file['name'])) { //判断是否移动成功
echo 'succeed';
} else {
echo 'failed';
}
} else {
echo '文件上传失败';
}
多文件上传
- 当商品需要上传多个图片进行展示的时候:需要使用多文件上传,针对一个内容但是不同的文件说明:同名表单
同名表单会将表单名字(如img[ ])形成一个数组,而且同时将文件对应的五个要素:name、tmp_name、size、error都形成对应数量的数组,每个文件上传对应数组元素的下标都是一样的:如name[0]和type[0]来自同一个文件 - 当商品需要进行多个维度的图片说明的时候:需要使用多文件上传,针对的是不同内容所以表单的名字不一样:批量解决问题
不同名表单:每个文件都会形成一个属于自己独立的5个元素的数组
对多文件上传的文件信息的读取
不同名多文件上传处理方式:按照表单名字从$_FILES中取出来就可以直接使用(明确知道表单中有多少个文件上传);如果不确定表单中有多少个文件上传,不适合挨个去取(效率不高),可以通过遍历$_FILES数组,挨个取出来实现文件上传
同名多文件上传处理方式:想办法得到一个文件对应的五个元素数组。从$_FILES中把对应的name/tmp_name/size/error/type挨个取出来存放到不同的数组中
<?php
echo '<pre>';
for ($i = 0; $i < count($_FILES['upload']['name']); $i++) {
//Get the temp file path
$tmpFilePath = $_FILES['upload']['tmp_name'][$i];
//Make sure we have a filepath
if ($tmpFilePath != "") {
//Setup our new file path
$newFilePath = "uploads/" . $_FILES['upload']['name'][$i];
//Upload the file into the temp dir
if (move_uploaded_file($tmpFilePath, $newFilePath)) {
//Handle other code here
}
}
}
MySQL扩展
PHP针对Mysql数据库操作提供的扩展:允许PHP当做mysql的客户端连接服务器进行操作
连库基本操作
连接数据库服务器
mysqli_connect(服务器地址,用户名,密码)
设置连接编码
保持客户端与服务器之间的沟通顺畅:同一字符集语言
mysqli_query('set names xxx')
mysqli_set_charset('xxx')
如何确定使用哪种编码:当前客户端执行脚本的界面是什么字符集就设置为什么
确定要使用的数据库
mysqli_query('use xxx')
mysqli_select_db('xxx')
关闭连接
主动释放连接:mysql服务器的连接资源是有限的,不用了需要释放(PHP脚本执行结束系统会自动释放)
语法:mysqli_close()
执行增删改操作
mysqli_query函数执行结果返回的是true或者false,true代表执行成功,false代表执行失败,失败原因分两种:一种是SQL指令本身语法错误,第二种是执行失败
插入数据
mysqli_query('insert ...')
<?php
$link = mysqli_connect('localhost', 'root', 'songyahui');
mysqli_query($link, 'use News');
$sql = "insert into n_news values(null,'heima',1,'黑马','itcaster',123)";
if (mysqli_query($link, $sql)) {
echo '数据插入成功';
} else {
echo '数据插入失败';
}
查询操作
执行查询语句
mysqli_query('select')
其他类似查询语句,比如show,desc
以上两种情况的总结:凡是执行操作希望拿到数据库返回的数据进行展示的
执行结果的处理:成功为结果集,失败为false
成功返回结果:SQL指令没有错误,但是如果查询结果本身为空,返回也是true
获取结果集行数
mysqli_num_rows()
:获取结果集中到底有多少行记录
解析结果集
将一种结果集资源(PHP不能直接使用),转换成一种PHP能够解析的数据格式:通过从结果集中(结果集指针:类似数组指针)按照结果集指针所在位置取出对应的一条记录(一行),返回一个数组,同时指针下移,直到指针移除结果集
mysqli_fetch_assoc()
:获取关联数组,表的表头名字作为数组下标,元素值作为数组元素值
mysqli_fetch_row()
:获取索引数组,只获取数据的值,然后数组的下标从0开始索引
mysqli_fetch_array()
:获取关联或者索引数组,但是默认是同时存在:一个记录取两次,形成一组关联数组和一组索引数组,可以通过第二个参数来决定获取方式:mysqli_assoc只获取关联数组,mysqli_num只获取索引数组,mysqli_both两种都获取,注意第二个参数要大写
其他相关函数
有关字段信息
mysqli_num_fields()
:获取一个指定结果集中所有的字段数
mysqli_field_name()
:获取一个指定结果集中指定位置字段的名字,索引从0开始
有关出错信息
mysqli_error()
:获取出错对应的提示信息
mysqli_errno()
:获取出错对应的错误提示代号
错误的判断:基于mysqli_query这个函数执行的结果,结果返回false就代表执行错误
其他函数
mysqli_insert_id()
:获取上次插入操作所产生的自增长ID,如果没有自增长ID则返回0
HTTP协议
HTTP协议初步认识
HTTP协议概念
HTTP协议,即超文本传输协议(Hypertext transfer protocol),是一种详细规定了浏览器和万维网(www = World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议
HTTP协议是用于从www服务器传输超文本到本地浏览器的传送协议,它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形等)。
HTTP协议特点
- 客服/服务器模式:客户端(浏览器)/服务端
- 简单快速:客服向服务器请求服务时,只需传送请求方法和路径,由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度更快
- 灵活:HTTP允许传输任意类型的数据对象(MIME类型)
- 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接,采用这种方式可以节省传输时间
- 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
HTTP协议分类
- HTTP请求协议:浏览器向服务器发起请求的时候需要遵循的协议
- HTTP响应协议:服务器向浏览器发起响应的时候需要遵循的协议
HTTP请求
请求行
格式:请求方式 资源路径 协议版本号-GET /index.php HTTP/1.1
请求行独占一行(第一行)
请求头
请求头就是各项协议内容:具体的协议内容不会每次都全部使用
- Host:请求的主机地址(必须)
- Accept:当前请求能够接收服务器返回的类型(MIME)类型
- Accept-language:接收的语言
- User-Agent:客户浏览器所在点的一些信息
请求头不固定数量,每个请求协议也是独占一行,最后会有一行空行(用来区分请求头和请求体)
请求体
请求体就是请求数据
只有POST请求会有请求体,GET请求所有的数据都是跟在URL之后,会在请求行中的资源路径上体现
基本格式:资源名字 = 资源值&资源名字 = 资源值...
HTTP响应
响应行
形式:协议版本号 状态码 状态消息(独占一行)-HTTP/1.1 200 ok
响应头
具体协议内容:
- 时间:Date: Tue, 30 Jun 2020 09:13:23 GMT
- 服务器:Server:Apache/2.2.22 (win 32) PHP/5.3.13
- 内容长度:Content-Length:1571,数据具体的字节数(响应体)
- 内容类型:Content-Type:text/html:告诉浏览器对应的数据格式
以上并不是所有的响应头;
响应头一个占一行,最后一行空行(用来区分响应头和响应体)
响应体
实际服务器响应给浏览器的内容
常用HTTP状态码
- 200 ok:成功
- 403 Forbidden:没权限访问
- 404 Not Found:没找到页面
- 500 Server Internal Error:服务器内部错误
常见HTTP响应设置及使用
PHP中针对HTTP协议(响应)进行了底层设计,可以通过函数header来实现修改http响应(响应头)
注意事项:
header可以设计HTTP响应,因为HTTP协议的特点是:响应行,响应头,响应体。通过header设计响应头的时候,不应该有任何内容输出,所以一旦产生内容输出(哪怕一个空格),系统都会认为响应头已经结束而响应体开始了,所以如果先输出内容后设置响应头(header使用),理论设置无效
在PHP5以后,增加程序缓存内容:允许服务器脚本在输出内容的时候,不直接返回浏览器而是先在服务器端使用程序缓存保留(php.ini中使用output_buffering),有了该内容之后,在程序缓存内会自动调整响应头和响应体(允许响应头在已经输出的内容之后再设置),但是会报错总结:header设置响应体之前不要有任何输出
- location:重定向,立即跳转(响应体不用解析)
浏览器在解析服务器响应的时候,先判定响应行,继续响应头,最后响应体:location是在响应头中,所以浏览器一旦见到该协议项,不再向下解析
语法:header('location:test.php');
- refresh:重定向,定时跳转(响应体会解析)
延时重定向:浏览器会根据具体时间延迟后在访问指定跳转链接:浏览器在准备跳转访问之前,会继续解析HTTP协议(响应头和响应体)
语法:header('refresh:3;url=test.php');
- content-type:内容类型,MIME类型
语法:header('content-type:text/html;charset:utf-8');
- content-disposition:内容类型,MIME类型扩展,激活浏览器文件下载对话框
浏览器在解析内容的时候,默认是直接解析:那么有时候需要浏览器不解析,当做内容下载成文件时就需要使用该设置
语法:header('content-disposition:attachment;filename=girl.jpg');
PHP模拟HTTP请求
原理
PHP可以通过模拟HTTP协议发起HTTP请求
CURL是一个非常强大的开源库,支持很多协议,包括HTTP、FTP、TELNET等,我们使用它来发送HTTP请求,它给我们带来的好处是可以通过灵活的选项设置不同的HTTP协议参数,并且支持HTTPS。CURL可以根据URL前缀是“HTTP”还是“HTTPS”自动选择是否加密发送内容
前提条件:HTTP协议的客户端/服务端模式,HTTP协议不局限于一定要浏览器访问
CURL扩展库使用
- 去ini文件中开启CURL扩展
- 如果扩展无法使用,则需要将对应的dll文件放到C盘的windows目录下
- 重启Apache
模拟步骤:
- 建立连接:
curl_init()
:激活一个CURL连接功能,用一个变量来接收 - 设置请求选项:
curl_setopt()
:
CURLOPT_URL
:连接对象
CURLOPT_RETURNTRANSFER
:将服务器执行的结果(响应)以文件流的形式返回给请求界面(PHP脚本)
CURLOPT_POST
:是否采用POST方式发起请求(默认为GET)
CURLOPT_POSTFIELDS
:用来传递POST提交的数据,分文两种方式:字符串(name=abc&pswd=123)以及数组形式(array(‘name’=>‘abc’,…))
CURLOPT_HEADER
:是否得到相应的header信息(响应头),默认不获取 - 执行请求:
curl_exec()
:执行选项(与服务器发起请求),得到服务器返回的内容 - 关闭连接:
curl_close()
:关闭资源
文件编程
文件编程初步认识
文件编程的必要性
文件编程指利用PHP代码针对文件(文件夹)进行增删查改操作
在实际开发项目中,会有很多内容(文件上传、配置文件等)具有很多不确定性,不能在一开始就手动创建,需要根据实际需求和数据本身来进行管理,这个时候就可以使用PHP文件变成来实现代码批量控制和其他操作
文件操作的分类
- 目录操作:文件夹,用来存放文件的特殊文件
- 文件操作:用来存放内容
目录操作
文件操作创建目录结构
mkdir(路径名字);
:创建成功返回true,创建失败返回false
如果我们重复创建了一个同名文件夹,那么浏览器会报错,但有时我们做的这些操作都是为了得到已经创建了该文件夹这样的一个结果,如果结果已经存在了,那么可以忽略该错误:抑制错误-@mkdir(路径名字);
删除目录
语法:rmdir(文件夹路径);
读取目录
读取方式:将文件夹(路径)按照资源方式打开
opendir()
:打开资源,返回一个路径资源,包含指定目录下的所有文件(文件夹)readdir()
:从资源中读取指针所在位置的文件名字,然后指针下移,直到指针移出资源
每个文件夹都包含两个文件夹,分别是./
和../
文件夹,代表当前目录和上一级目录,且这两个文件夹排在第1,2位
读取所有目录我们可以使用遍历:
while($file = readdir($r)){
echo $file,'<br/>';
}
关闭目录
closedir()
:关闭资源
其他目录操作
dirname(路径)
:得到该路径(可以是文件夹,也可以是具体文件)的上一层路径realpath(路径):得到真实路径
:得到该文件夹的路径,如果路径参数给的是一个具体文件,那么会返回falseis_dir()
:判断指定路径是否为目录,返回true或falsescandir()
:封装版的opendir()+readdir()+closedir()
,获取一个指定路径下的所有文件信息,以数组形式返回
递归遍历目录
指定一个目录的情况下,将其下的所有文件和目录,及其目录内部的所有内容都输出出来
递归算法:
将大问题切成相似的小问题,然后可以调用解决大问题的方法来解决小问题
递归遍历目录的思维逻辑:
- 设计一个能够遍历一层文件的函数
- 找到递归点:遍历得到的文件是目录,应该调用当前函数(调用自己)
① 需要构造路径(遍历得到的结果只是文件的名字)
② 需要注意排除./
和../
- 找到递归出口:遍历完这个文件夹之后,发现没有任何子文件夹(函数不再调用自己)
补充:如何显示层级关系?
函数第一次运行遍历的结果是最外层目录,内部调用一次说明进入一个子目录,子目录再调用一次函数进入孙目录,如果能够在第一次调用的时候给个标记,然后在进入的时候,通过标记的变化来识别层级关系,就可以达到目的。通过该标记还可以进行相应的缩进
代码实现
<?php
$dir = realpath('./father/');
function my_scandir($dir, $level = 0)
{
//保证文件安全:如果不是路径则没有必要执行
if (!is_dir($dir)) dir($dir . '<br/>');
//读取全部路径信息,遍历输出
$files = scandir($dir);
foreach ($files as $file) {
if ($file == '.' || $file == '..') continue;
//$file就是一个个文件名
echo str_repeat(" ", $level) . $file . '<br/>';
//构造路径
$file_dir = $dir . '/' . $file;
if (is_dir($file_dir)) my_scandir($file_dir, $level + 1);
}
}
my_scandir($dir);
文件操作
常见文件操作函数
file_get_contents(文件路径)
:获取指定文件的所有内容,如果路径不存在最好做安全处理file_put_contents(文件路径,内容)
:将指定内容写入到指定文件内,如果当前路径下不存在指定的文件,函数会自动创建(如果路径不存在则不会创建路径)
旧版本PHP常见文件操作函数
旧版本PHP中是将文件操作用资源形式处理,不论是读还是写都依赖资源指针:文件内容中指针所在位置
fopen(文件路径,打开模式)
:打开一个文件资源,限定打开模式fread(资源,长度)
:从打开的资源中读取指定长度的内容(字节)fwrite(资源,内容)
:向打开的资源中写入指定的内容fclose(资源)
:关闭资源
其他文件操作函数
is_file()
:判断文件是否正确(不识别路径)filesize()
:获取文件大小file_exists()
:判断文件是否存在(识别路径)unlink()
:取消文件名字与磁盘地址的连接filemtime()
:获取文件最后一次修改的时间fseek()
:设定fopen打开的文件的指针位置fgetc()
:一次获取一个字符fgets()
:一次获取一个字符串(默认行)file()
:读取整个文件,类似file_get_contents,但file是按行读取,返回一个数组
文件下载
文件下载:从服务器将文件通过HTTP协议传输到浏览器,浏览器不解析并保存成相应的文件
提供下载方式可以使用HTML中的a标签<a href="互联网绝对文件路径">
,但不推荐,缺点:
- a标签能够让浏览器自动下载的内容有限,浏览器是发现如果解析不了了才会启用下载
- a标签下载的文件存储路径会需要通过href属性写出来,这样会暴露服务器存储数据的位置
PHP下载:
php下载:读取文件内容,以文件流的形式传递给浏览器,在响应头中告知浏览器不要解析,激活下载框实现下载
- 指定浏览器解析字符集
- 设定响应头
① 设定文件返回类型:image/jpg||application/octem-stream
② 设定返回文件计算方式:Accept-ranges:bytes
③ 设定下载提示:content-disposition:attachment:filename=‘文件名’
④ 设定文件大小:Accept-length:文件大小(字节) - 读取文件
如果文件较小,可以使用file_get_contents()
来读取文件,如果文件较大,则需要使用fopen()
- 输出文件
示例代码:
<?php
//设定解析字符集
header('content-type:text/html;charset=utf8');
$file = 'c++笔记.docx';
//设定下载响应头
header('content-type:application/octem-stream'); //以文件流形式传输数据给浏览器
header('accept-ranges:bytes'); //以字节方式计算
header('content-disposition:attachment;filename=' . $file); //附件下载,指定命名
header('accept-length:' . filesize($file));
//如果文件的名字是从文件夹读取出来的,而且存在中文,那么如果直接使用名字作为下载名字会出现乱码,就需要进行字符集转码:$file = iconv('gbk', 'utf-8', $file);
//输出文件
echo file_get_contents($file);
//大文件下载
//方案1:直接读,再输出
// $f = @fopen($file, 'r') or die();
// while ($row = fread($f, 1024)) {
// echo $row;
// }
//方案2:判定是否可读,再读和输出
// while (!feof($f)) {
// echo fread($f, 1024);
// }
fclose($file);
会话技术
会话技术初步认识
会话技术介绍
web会话可简单理解为:用户开一个浏览器,访问某一个web站点,在这个站点点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称为一个会话
HTTP协议的特点是无状态/无连接,当一个浏览器连续多次请求同一个web服务器时,服务器时无法区分多个操作是否来自同一个浏览器(用户)。会话技术就是通过HTTP协议想办法让服务器能够识别来自同一个浏览器的多次请求,从而方便浏览器(用户)在访问同一个网站的多次操作中,能够持续进行而不需要进行额外的身份验证
会话技术分类
- cookie技术
cookie是在HTTP协议下,服务器或脚本可以维护客户工作站上信息的一种方式。cookie是由web服务器保存在用户浏览器(客户端)上的小文本文件(HTTP协议响应头),它可以包含有关用户的信息。无论何时用户链接到服务器(HTTP请求携带数据),web站点都可以访问cookie信息 - session技术
senssion没有恰当的翻译,一般翻译为“时域”。在计算机专业术语中,senssion是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间。以及如果需要的话,可能还有一定的操作空间。senssion技术是将数据保存到服务端,无论何时用户链接到服务器,web站点都可以访问session信息,session技术的实现是依赖于cookie技术的
cookie与session的区别
- 安全性方面
- session存储在服务器端,安全性高
- cookie存储浏览器端,安全性低
- 数据大小方面
- cookie的数量和大小都有限制
- session数据存储不限
- 可用数据类型
- cookie只能存储简单数据,如数值/字符串
- session可以存储复杂数据(自动序列化)
- 存储位置
- cookie存在浏览器中
- session存在服务器上
cookie的基本使用
cookie原理
cookie技术:服务器将数据通过HTTP响应存储到浏览器上,浏览器可以在以后携带对应的cookie数据访问服务器
- 第一次请求时,PHP通过
setcookie
函数将数据通过http协议响应头传输给浏览器 - 浏览器在第一次响应的时候将cookie数据保存到浏览器
- 浏览器后续请求同一个网站的时候,会自动检测是否存在cookie数据,如果存在将在请求同中将数据携带到服务器
- PHP执行的时候会自动判断浏览器请求中是否携带cookie,如果携带,自动保存到
$_COOKIE
中 - 利用$_COOKIE访问cookie数据
设置cookie信息
setcookie
函数用来设定cookie信息
setcookie(名字,值);
- cookie名的设置:字符串,作第一个参数
- cookie值的设置:第二个参数
- cookie值的类型要求:必须是简单类型中的整数或者字符串
COOKIE(会话技术)能够实现跨脚本共享数据
cookie高级使用
cookie的生命周期
cookie生命周期:cookie在浏览器的生存时间
- 默认(不设定)的生命周期:默认是关闭浏览器后(会话结束)
- 设定一个常规日期戳的周期:通过setcookie第三个参数可以限定生命周期,是用时间戳来表示,从格林威治时间开始
- 设定为"0"的周期,当时间戳设置为0的时候,表示就是会话结束就过期
删除cookie
服务器没有权限去操作浏览器上的内容,但可以通过设定生命周期来让浏览器自动判定cookie是否有效,无效会清除
- 清空cookie数据内容:
setcookie('name','');
- 设置过期的时间戳:
setcookie('name','wsc',time());
cookie作用范围
不同的文件夹层级中,设定的cookie默认是在不同的文件夹下有访问限制。上层文件夹中设定的cookie可以在下层(子文件夹)中访问,而子文件夹中设定的cookie不能在上层文件夹中访问
- 默认的范围:上层看不到下层的内容,而下层可以看到上层的内容
- 设置范围为
/
:告知浏览器当前cookie的作用范围是网站根目录:setcookie(名字,值,生命周期,作用范围);
cookie跨子域
跨子域:在同一级别域名下,myitcast.com(一级域名)可以有多个子域名(www.myitcast.com和gz.myitcast.com),他们之间是搭建在不同的服务器上(不同网站根目录文件夹),但是可以通过COOKIE设置实现对应的cookie共享访问,但是默认是不允许跨域名访问的
- 设定cookie的有效域名(不同的域名、主机之间不能共享cookie)
可以通过setcookie
的第五个参数来控制:setcookie(名字,值,生命周期,作用范围,有效域名)
- 不设定时的默认有效域名
- 跨子域的设定方法:在设定域名访问的时候设定上级域名即可:myitcast.com,这个是所有以myitcast.com结尾的网站都可以共享cookie
cookie数组数据
cookie本身只支持简单数据(数据或字符串),能够保留的数据本身有限,也不成体系。如果需要使用cookie来保留一组数据的话,要想办法凑成数组,但cookie不支持数组
- 伪装数组,虽然浏览器不接受中括号,但是PHP会将中括号当数组处理:
setcookie('数组名[下标]',值);
- 读取伪装数组:
$_COOKIE[数组名][下标];
session基本使用
会话技术的本质是为了实现跨脚本共享数据:在一个脚本中定义数据,在另外一个脚本中保存数据
session原理
session与浏览器无关,但是与cookie有关
- PHP碰到
session_start()
时开启session会话,会自动检测sessionID
a)如果碰到cookie中存在,使用现成的
b)如果cookie中不存在,则创建一个sessionID,并通过响应头以cookie形式保存到浏览器上 - 初始化超全局变量
$_SESSION
为一个空数组 - PHP通过sessionID去指定位置(session文件存储位置),匹配对应的文件
a)不存在该文件:创建一个以sessionID命名的文件
b)存在该文件:读取文件内容(反序列化),将数据存储到$_SESSION
中 - 脚本执行结束,将
$_SESSION
中保存的所有数据序列化存储到sessionID对应的文件夹
session的使用
任何时候都要先开启session
$_SESSION
是通过session_start()
函数的调用才会定义的,没有直接定义
- 设置session信息
如果想存储数据到session中,那么只要不断给$SESSION
数组添加元素即可(数值,字符串都可以) - 读取session信息
通过数组访问即可
删除一个session信息
删除session就是将session数据清理掉($_SESSION拿不到)
语法:unset($_SESSION[元素下标]);
删除全部session信息
删除全部数据就是让$_SESSION
变成一个空数组
语法:$_SESSION = array();
session相关配置
session基础配置
- session.name:session名字,保存到cookie中sessionID对应的名字
- session.auto_start:是否自动开启session(无需手动session_start()),默认关闭
- session.save_handler:session数据的保存方式,默认是文件形式
- session.save_path:session文件默认存储的范围,默认存在系统临时文件,我们需要指定一个文件夹来存储
session常用配置
- session.cookie_lifetime:PHPsessionID在浏览器端对应cookie的生命周期,默认是会话结束
- session.cookie_path:sessionID在浏览器存储之后允许服务器访问的路径(cookie有作用范围)
- session.cookie_domain:cookie允许访问的子域(cookie可以跨子域)
如何进行配置
- php.ini中配置:全局配置,修改php.ini中的配置项
- 脚本中配置:PHP可以通过
ini_set
函数来在运行中设定某些配置项(只会对当前运行的脚本有效),把这种配置称之为项目级:
ini_set('session.save_path','E:/server/sessions');
销毁session
前面的删除session是指删除session数据,$_SESSION中看不到而已,而销毁session是指删除session对应的session文件
系统提供了一个函数session_destory()
,会自动根据session_start得到的sessionID去找到指定的session文件,并把其删除
session垃圾回收机制
垃圾回收机制原理
session会话技术后,session文件并不会自动清除,如果每天有大量session文件产生但是又都是失效的,会增加服务器的压力和影响session效率
垃圾回收,是指session机制提供了一种解决垃圾session文件的方式:给session文件指定周期,通过session文件最后更改时间与生命周期进行综合判定,如果已经过期则删除对应的session文件,如果没有过期则保留。这样就可以及时清理无效的僵尸文件,从而提高空间利用率和session工作效率
- 任何一次session开启(session_start),session都会尝试去读取session文件
- 读取session文件后,有可能触发垃圾回收机制(在session系统中也是一个函数,自己有一定几率调用)
- 垃圾回收机制会自动读取所有session文件的最后编辑时间,然后加上生命周期与当前时间进行比较
a)过期:删除
b)有效:保留
垃圾回收参数设置
- session.gc_maxlifetime = 1440;规定的session文件最大的生命周期是1440秒,即24分钟
- session.gc_probability = 1; 垃圾回收概率分子
- session.gc_divisor = 1000; 垃圾回收概率分母
即默认触发概率为1/1000
禁用cookie后如何使用session
禁用cookie后不能使用session的原因
session技术需要利用到cookie技术来保存sessionID,从而使得PHP能够在跨脚本的时候得到相同的sessionID,从而访问同一个session文件
解决思路:最终让session_start在开启之前拿到原来的sessionID
实现无cookie使用session
在PHP中,想要解决没有cookie也实现session技术的方式有两种
方案一:
利用PHP提供的session函数session_id
和session_name
来获得和设置sessionID或者name从而解决session_start产生新sessionID的情况
a)在session保存数据的脚本中获取sessionID和名字
b)将数据传送给另外一个脚本(使用URL或Form表单)
c)在需要使用到session的脚本中先接受数据
d)阻止session_start产生新的ID:session_id(获取数据中的ID);
方案二:
可以利用session已经提供的解决方案自动操作
原因1:默认session配置只允许使用cookie保存sessionID:cookie_only
原因2:默认关闭了其他能够传送数据的方式,值保留了cookie
a)修改PHP配置文件,开启其他方式传输sessionID,关闭只允许使用cookie传输功能
b)一旦配置开启,PHP会自动将sessionID和session名字在其他位置绑定数据,同时还会在session_start的时候,考虑其他方式(表单)传递的数据,而不是只有cookie
GD图像处理
GD图像处理基本技术
GD库引入与介绍
GD库的概念:Graphic Device,图像处理扩展(外部提供的API),能够允许PHP在脚本中使用对应的函数来实现某些图像制作功能
GD库的引入:GD库是外部提供的API,已经被集成到PHP扩展库中,只需在PHP的配置文件中开启对应的GD2扩展即可
画图介绍
画图本质是在内存中开辟一块很大的内存区域用于图片制作
画图的基本流程:
- 准备画布
- 开始作画
- 保存内容
- 销毁画布
创建画布资源
imagecreate(宽,高)
:创建一个空白画布(背景色是白色)imagecreatetruecolor(宽,高)
:创建一个真彩画布(背景色是黑色的,需要填充)iamgecreatefromjpeg(图片文件路径)
:打开一个jpeg格式的图片资源imagecreatefromgif(图片文件路径)
:打开个gif格式图片资源(PHP中无法实现动态)imagecreatefrompng(图片文件路径)
:打开png格式图片资源
操作画布资源
所有的画布资源操作都是需要指定画布资源,而且是作为第一个参数
- 分配颜色:
imagecolorallocate(画布资源,红色,绿色,蓝色);
,根据RGB三色组给指定画布资源分配一组颜色,会返回一个颜色句柄(一组整数),每一个色组都是从0到255
在真彩图片资源中,所有分配的颜色都不会自动给图片资源上色,是用来后续操作图片资源的时候,指定着色的。但是如果当前使用的是imagecreate创建的图片资源,那么第一个分配的颜色,会自动被着色为图片背景色
- 凡是给图片上增加内容,基本都需要分配颜色(每一个操作图片的函数之前,都需要先调用分配颜色的函数得到一个颜色)
- 填充区域:
imagefill(画布资源,起始X坐标,起始Y左边,颜色句柄);
:指定位置开始填充指定颜色
imagefill填充逻辑:从指定点开始,自动匹配相邻点,如果颜色一致,自动渲染,扩展到全图 - 画直线:
imageline(图片资源,起始点X,起始点Y,终点X,终点Y,颜色);
- 画矩形:
imagerectangle(图片资源,左上角X,左上角Y,右下角X,右下角Y);
- 画圆弧:
imagearc(图像资源,轴点X,轴点Y,宽度,高度,弧度重点,颜色);
- 在画布上写字:
a)写英文:imagestring(图片资源,文字大小,起始X,起始Y,内容,颜色);
b)写中文:imagettftext(图片资源,文字大小,旋转角度,起始X,起始Y,颜色,字体(绝对路径),内容);
输出画布资源
- 输出为图片文件:以图片文件形式保存到本地文件夹
- 输出为网页图片:将图片展示给HTML
相关函数:
imagejpeg()
:保存成jpeg格式图片
imagepng()
:保存成png格式图片
imagegif()
:保存成gif格式图片
如果图片只是提供了图片资源,不指定保存的文件位置(第二个参数),那么系统认为是输出给浏览器;如果指定了位置,那么系统认为是保存到本地
如果要输出给浏览器则必须告知浏览器响应头这是图片脚本,不然会乱码
两个小细节:
1)如果图片输出或者保存出错,浏览器只会让你看到错误的图片,但不会告知你错误原因代码,此时我们需要关闭header的图片设置,再看问题
2)如果图片输出出错,且关掉header也看不到错误,最大的可能是图片输出之前输出了别的额外内容,如空格、空行、pre等,此时应该查看网页源代码,看是否有多余的输出
销毁画布资源
语法:iamgedestory(画布资源);
获取图片信息
- 获取图片尺寸:
imagesx()
,imagesy()
- 获取图片所有信息:
getimagesize()
GD图像处理应用案例
验证码的实现
验证码(CAPTCHA)是“completely autpmated public turing test to tell computers and humans apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式,我们利用比较简易的方式实现了这个功能。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类
图片验证码:计算机将拿到的验证码存放到图片中,然后用户看到并识别,随后提交给服务器,服务器再根据用户提交的和服务器之前生成的进行比较
实现步骤:
- 实现验证码图片的展示
a)生成图片资源,设定背景色
b)写入文字
c)输出图片给浏览器
d)关闭资源 - 实现验证码文字的随机变化
a)制作目标字符串集:从这里选内容
b)一个汉字在utf8中占用3个字节:确定字符数
c)随机取出对应的字符
d)将取到的字符放到指定的图片位置即可 - 文字颜色随机改变
- 添加验证码背景干扰和噪点(干扰点、干扰线、修改字体大小,位置等)
- 实现点击刷新验证码功能:
a)创建一个表单文件,里面有一个img标签能够显示图片:<img src = '验证码.php'>
b)实现点击更换验证码:让src重新请求PHP脚本,产生一张新的验证码。因此需要给img标签添加一个点击事件:img的src是否重新请求,取决于浏览器,而浏览器重新发起请求取决于src是否改变
c)在src后面添加一个?
+随机数
就可以让每次点击的src都不一样,即可重新请求PHP脚本
<img src="test.php" onclick="this.src='test.php?' + Math.random()" />
验证码脚本完整代码
<?php
//设置响应头
header('content-type:image/png');
//获得画布资源
$img = imagecreatetruecolor(200, 50);
//设置画布颜色并填充
$img_color = imagecolorallocate($img, 70, 115, 100);
imagefill($img, 0, 0, $img_color);
//设置字符颜色和字体
$str_color1 = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
$str_color2 = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
$str_color3 = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
$str_color4 = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
$typeface = 'D:\phpstudy_pro\WWW\simhei.ttf';
//制作字符串验证源
$words = '啊啊给我一杯忘情水换我一生不流泪';
//记录字符串字符数
$count = mb_strlen($words);
//使用rand随机生成一个数字,代表从第几个字符开始截取
$char1 = mb_substr($words, rand(0, $count - 1), 1);
$char2 = mb_substr($words, rand(0, $count - 1), 1);
$char3 = mb_substr($words, rand(0, $count - 1), 1);
$char4 = mb_substr($words, rand(0, $count - 1), 1);
//书写汉字
imagettftext($img, 28, 30, 10, 30, $str_color1, $typeface, $char1);
imagettftext($img, 28, 60, 50, 30, $str_color2, $typeface, $char2);
imagettftext($img, 28, -30, 100, 30, $str_color3, $typeface, $char3);
imagettftext($img, 28, -30, 150, 30, $str_color4, $typeface, $char4);
//增加干扰点和干扰线
for ($i = 0; $i < 7; $i++) {
$star_color = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
imagestring($img, 2, rand(5, 195), rand(5, 45), '*', $star_color);
$line_color = imagecolorallocate($img, rand(0, 255), rand(0, 255), rand(0, 255));
imageline($img, rand(0, 5), rand(0, 50), rand(195, 200), rand(0, 50), $line_color);
}
imagepng($img);
imagedestroy($img);
缩略图的实现
制作图片缩略图的原理
将原图打开,然后放到另外一个较小的图片资源中,得到一个尺寸上较小的图,最后进行保存即可
实现固定宽高的缩略图
- 得到一张原图资源
- 得到一个缩略图资源(较小)
- 图片采样赋值:GD提供了一个函数:
imagecopyresampled($dst_image,$src_image,$dst_x,$dst_y,$src_x,$src_y,$dst_w,$dst_h,$src_w,$src_h)
dst_image:目标图象连接资源
src_image:源图象连接资源。
dst_x:目标 X 坐标点
dst_y:目标 Y 坐标点
src_x:源的 X 坐标点
src_y:源的 Y 坐标点
dst_w:目标宽度
dst_h:目标高度
src_w:源图象的宽度
src_h:源图象的高度 - 保存缩略图到本地
- 销毁所有资源(原图和缩略图):imagedestory()
//制作一个缩略图
<?php
$src_tiger = 'D:\phpstudy_pro\WWW\tiger.jpg';
$tiger = imagecreatefromjpeg($src_tiger);
$dst = imagecreatetruecolor(100, 100);
imagecopyresampled($dst, $tiger, 0, 0, 0, 0, 100, 100, imagesx($tiger), imagesy($tiger));
header('content-type:image/jpeg');
imagejpeg($dst);
实现等比缩放的固定宽或高的缩略图
优点:图片不会失真(变形)
缺点:缩略图有些部分需要进行额外填充(白色填充:补白)
等比例缩略图与固定缩略图的制作区别:在于需要通过计算来得出缩略图的宽和高,算法原理:
- 计算缩略图宽高比
- 计算原图宽高比
- 比较:
a)如果缩略图宽高比大于原图宽高比,则将缩略图中用原图的高尽可能填满,即缩略图的高是完整的,但宽度不够
b)如果缩略图宽高比小于原图宽高比,则将缩略图中用原图的宽尽可能填满,即缩略图的宽是完整的,但高度不够 - 将图片放到缩略图中间
水印图的实现
制作水印图的原理
水印图制作原理:将一个带有明显标志的图片放到另外一张需要处理的图片之上
制作固定位置的水印图(左上角)
a)获取原图资源(需要放上水印图)
b)获取水印图资源
c)合并图片(把水印图合到目标图上):imagecopymerge(目标资源,水印资源,目标起始X,目标起始Y,水印起始X,水印起始Y,目标宽,目标高,透明度);
d)保存输出
e)清除资源
实现可选9个位置的水印图
a)创建一个制作水印图的函数结构:原图路径,水印图路径,水印图存储路径,错误信息记录,水印加载位置(1代表左上角,以此类推至右下角),透明度
b)结果是希望产生水印图,但是要考虑两种结果。如果成功了,返回文件保存名字;如果失败了,返回false,但是还需要告知外界错误原因:通过引用传参
c)制作水印图前提:原图和水印图都存在(判断MIME类型)
d)判定保存路径是否存在
e)打开原图和水印图资源:确定要用什么函数来打开图片资源(通过判断图面MIME类型来确定)
f)计算水印位置,合并图片
g)保存带水印图片
<?php
/*
*制作水印图
*@param1 string $src_image,原图路径
*@param2 string $wat_image,水印图路径
*@param3 string $path,水印图存储路径
*@param4 string &$error,记录错误信息的变量
*@param5 int $position = 1,水印加载位置:1代表左上角以此类推至右下角
*@param6 int $pct = 20,透明度,默认20
*/
function watermark($src_image, $wat_image, $path, &$error, $position = 1, $pct = 20)
{
if (!is_file($src_image)) {
$error = '原图不存在';
return false;
}
if (!is_file($wat_image)) {
$error = '原图不存在';
return false;
}
if (!is_dir($path)) {
$error = '保存位置错误';
return false;
}
$src_info = getimagesize($src_image);
$wat_info = getimagesize(($wat_image));
//定义一组数据,用来产生对应图片格式
$allow = array(
'image/jpeg' => 'jpeg',
'image/jpg' => 'jpeg',
'image/gif' => 'gif',
'image/png' => 'png',
'image/pjpeg' => 'jpeg'
);
//匹配数据
if (!array_key_exists($src_info['mime'], $allow)) {
$error = '当前文件资源不允许制作水印图!';
return false;
}
if (!array_key_exists($wat_info['mime'], $allow)) {
$error = '当前水印图不允许作资源使用!';
return false;
}
//组合出一个函数名
$src_open = 'imagecreatefrom' . $allow[$src_info['mime']];
$wat_open = 'imagecreatefrom' . $allow[$wat_info['mime']];
$src_save = 'image' . $allow[$src_info['mime']];
//打开原图资源
$src = $src_open($src_image); //因为$src_open($src_image)的值为imagecreatefromjpeg,所以给它加上括号就可以当imagecreatefromjpeg()函数来使用,相当于$src = imagecreatefromjpeg($src_image),同时jpeg会根据上面的mime类型而实时改变
$wat = $wat_open($wat_image);
//计算水印图在原图中出现的位置
$start_x = $start_y = 0;
switch ($position) {
case 1: //左上
break;
case 2: //上中
$start_x = floor(($src_info[0]) / 2);
break;
case 3: //右上
$start_x = $src_info[0] - $wat_info[0];
break;
case 4: //中左
$start_y = floor(($src_info[1] - $wat_info[1]) / 2);
break;
case 5: //中心
$start_x = floor(($src_info[0] - $wat_info[0]) / 2);
$start_y = floor(($src_info[1] - $wat_info[1]) / 2);
break;
case 6: //中右
$start_x = $src_info[0] - $wat_info[0];
$start_y = floor(($src_info[1] - $wat_info[1]) / 2);
break;
case 7: //下右
$start_y = $src_info[1] - $wat_info[1];
break;
case 8:
$start_x = floor(($src_info[0] - $wat_info[0]) / 2);
$start_y = $src_info[1] - $wat_info[1];
break;
case 9:
$start_x = $src_info[0] - $wat_info[0];
$start_y = $src_info[1] - $wat_info[1];
break;
}
//合并图片资源
if (imagecopymerge($src, $wat, $start_x, $start_y, 0, 0, $wat_info[0], $wat_info[1], $pct)) {
//保存图片
$filename = 'watermark_' . trim(strrchr($src_image, '/'), '/');
$src_save($src, $path . '/' . $filename);
} else {
//失败
$error = '水印图制作失败!';
return false;
}
}
$res = watermark('D:/phpstudy_pro/WWW/wallpaper.jpg', 'd:/phpstudy_pro/WWW/wtm.jpg', './', $error, 9);
if ($res) {
echo $res;
} else {
echo $error;
}