最近在为学校社团写一个模拟登录教务系统来进行成绩查询的功能,语言当然是使用PHP啦,原理是通过php数据传输神器—curl扩展,向学校教务系统发送请求,通过模拟登录,获取指定url下的内容。
在开始实验之前有必要对curl扩展进行一下认识
使用CURL的PHP扩展完成一个HTTP请求的发送一般有以下几个步骤:
1. 初始化连接句柄; # curl_init()
2. 设置CURL选项(关键); # curl_setopt()
3. 执行并获取结果; #curl_exec()
4. 释放VURL连接句柄。 #curl_close()
下面看一个简单的实例
$ch = curl_init(); // 1. 初始化
curl_setopt($ch,CURLOPT_URL,$url); // 2. 设置选项,定义目标URL
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); //设置选项 , 返回url获取的内容
curl_setopt($ch,CURLOPT_HEADER,0); //设置选项 , 不返回HTTP头部信息
$output = curl_exec($ch); // 3. 执行并获取HTML文档内容
//对获取到的内容进行操作
if($output === FALSE ){
echo "CURL Error:".curl_error($ch);
}
curl_close($ch); // 4. 释放curl句柄
下面是curl_setopt选项的常用选项,在下面的实验中将会用到
CURLOPT_URL 需要获取的URL地址,也可以在 curl_init()函数中设置
CURLOPT_HEADER 不返回HTTP头部信息
CURLOPT_COOKIEJAR 连接结束后保存cookie信息的文件。
CURLOPT_COOKIEFILE 包含cookie数据的文件名
CURLOPT_REFERER 伪造来源
CURLOPT_RETURNTRANSFER 将 curl_exec()获取的信息以文件流的形式返回,而不是直接输出
CURLOPT_POST 设置post提交方式
CURLOPT_POSTFIELDS 传递post内容
现在来开始我们的模拟登录实验吧!
-
先聊一聊HTTP会话:会话是指一个用户与系统进行通讯的过程,比如从输入账户密码进入操作系统到退出操作系统就是一个会话过程。Session代表服务器与浏览器的一次会话过程,这个过程一般是连续的。在打开浏览器第一次请求网站的时候,服务器会自动为其创建一个session,并赋予其一个sessionID,发送给客户端的浏览器。以后客户端接着请求本应用中其他资源的时候,会自动在请求头上添加:(Cookie:SESSIONID=客户端第一次拿到的session ID)。这样,服务器端在接到请求时候,就会收到session ID,并根据ID在内存中找到之前创建的session对象,提供给请求使用。HTTP会话
-
第一步:抓包与分析
工具可以使用谷歌浏览器的开发者工具(按下F12键调出,点击网络选项,查看访问的资源),对需要进行模拟登录的教务系统页面进行访问,获取相关信息。
-
第二步:获取想要的信息
首先直接访问教务系统网址。我们能够很清楚的看到,验证码有着自己的地址,每一次我们刷新这个验证码URL地址的时候,这张小小的验证码都会实时的更新变化。那服务器怎么知道,在某一次提交中,是哪个人提交的表单数据,又怎么判断使用的是哪一张验证码呢!这就是一个问题了,所以HTTP会话的功能就体现出来了。当我们第一次访问网站,会和服务器建立起联系(进行了一次会话,在网页没有关闭前,这个会话一般会一直保持),会获得来一枚session,这枚session是唯一的,如果session改变,这就意味着这是一次新的会话,那么服务器收到的验证码也就无效,因为此次提交的数据,不是来自同一个会话中。这也是在验证码验证时的一个难点。所以保持会话,并提交数据就是我们需要重点处理的任务。
-
第三步:模拟登陆的思路
我们访问教务系统页面,浏览器分别向教务系统主页面(202.206.xxx.xxx)和验证码页面(202.206.xxx.xxx/ValidateCodeAction.do)发送了请求,通过查看他们的头信息,可以发现他们的SESSION信息是一样的,这证明我上面所说的是真的。
那我们想一想,我们要模拟登陆,就必须获取到验证码,当我们通过curl的到验证码后,会话就断开了,这个验证码就是一个废的验证码,当我们使用这个验证码提交登陆信息给教务系统,这次提交会生成一个新的会话,明显,这次模拟登陆会报错,理由是验证码不正确,此次会话产生的验证码与我们输入的验证码不匹配,因为一个验证码对应着一个唯一的会话。
我们怎样让我们的会话保持下来呢?这里我提供一下我的思路:
- 获取验证码,并将验证码对应的 会话id(cookie) 保存
- 提交表单,使用获取验证码得到的 会话id(cookie) ,让会话保持
- 得到信息
这里保存会话id用到的是我们的curl选项 CURLOPT_COOKIEJAR 和 CURLOPT_COOKIEFILE 。这些都讲的清楚了吧!开始写代码!
1. 获取验证码 保存会话cookie为文件
1. 全程开启session(为什么要开启,目的是为了防止访问人数过多,导致的cookie文件被重写)
2. 在当前目录下创建一个cookie文件夹用来存放会话生成的cookie文件
3. 在当前目录下创建一个images文件夹用来存放验证码文件
<?php
session_start(); //开启session,
$id=session_id(); //获取当前session的id,这个id是存放在浏览器的本地cookie中的
$_SESSION['id']=$id; //因为这个id的唯一性,可以解决高访问量时登陆失败的问题
$cookie = dirname(__FILE__) . '/cookie/'.$_SESSION['id'].'.txt'; //cookie文件保存的路径 当前路径下的cookie目录
//开始模拟访问验证码页面,获取其cookie
$verify_code_url = "http://xxx.xxx.xxx.xxx/ValidateCodeAction.do"; //这里是验证码地址
$curl = curl_init(); //初始化句柄
curl_setopt($curl, CURLOPT_URL, $verify_code_url); //设置模拟访问的URL
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie); //保存模拟访问时得到的cookie(这里是关键)
curl_setopt($curl, CURLOPT_HEADER, 0); //不输出头信息
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //返回文件流
$img = curl_exec($curl); //执行curl
curl_close($curl); //释放资源句柄
$fp = fopen("./images/verifyCode.jp