PHP 使用的 cURL 依靠 libcurl 库,libcurl 很好的支持 http、https,因而在登入和获取页面时完全可以充当浏览器的角色。
下面介绍一下我常用到的登入和获取页面代码,功能上,记录了登入 cookie,可以一次登入后免登入直至 cookie 过期。
应用场景:某些小型服务网站没有提供 API,但是要经常性的获取某些登入后的数据。
首先是登入函数
function curl_login($url, $ch, $cookie_jar, $loginvars) {
if (is_null($ch))
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_REFERER, $url);
//curl_setopt($ch, CURLOPT_AUTOREFERER, 1); //某些场景同上
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0");
//curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
// 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($loginvars));
//$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$content = curl_exec($ch);
if ($error = curl_error($ch)) {
echo "Curl error: $error";
return false;
}
return $ch;
}
接下来是获取页面函数
function curl_get($url, $ch, $cookie_jar, $post=''){
$timeout=30;
if (is_null($ch))
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt ($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0");
//curl_setopt ($ch, CURLOPT_HEADER, 1);
//curl_setopt($ch, CURLINFO_HEADER_OUT, 1); //To use this, have to set CURLINFO_HEADER_OUT=1
//curl_setopt ($ch, CURLOPT_COOKIESESSION, 0);
curl_setopt ($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt ($ch, CURLOPT_COOKIEJAR, $cookie_jar);
if (!empty($post))
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
else
curl_setopt($ch, CURLOPT_HTTPGET, 1); //If the previous connecting use POST, this connecting will be use post as default. So force it to use GET.
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$content = curl_exec ($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == 302) { //The most of server return 302 and redirect to login page.
echo "Waiting for login...\n";
return false;
}
if ($error = curl_error($ch)) {
echo "Curl error: $error\n";
return NULL;
}
return $content;
}
如何使用函数?
$cookie_jar = dirname(__FILE__).DIRECTORY_SEPARATOR."curl.cookie";
$curl = NULL;
$page_url = 'https://www.example.com/admin';
$content = curl_get_page($page_url, $curl, $cookie_jar);
if ($content === false) { //Cookie expired, then login in and fetch again.
$login_url = "https://www.example.com/login";
$loginvars = array(
'UserName' => 'user_007',
'Password' => 'passwd',
'rememberme' => 'true',
);
$curl = curl_login($login_url, $curl, $cookie_jar, $loginvars);
$content = curl_get($page_url, $curl, $cookie_jar);
}
这里的流程是首先尝试获取页面,如果如果服务器发送 http 302 将你跳转到登入页面,你再执行登入并记录 cookie,如果获取到了之前保存的未过期 cookie,那么就会省去登入环节。
需要注意的是
- 我这里先设置 $curl 为 NULL 是为了配合登入和延续获取页面的会话,如果直接在两个函数里写 $ch = curl_init(); 那么登入成功后获取页面的 $ch 被重置了,也就销毁了登入会话,服务器还是当你没有登入。
- 将 cookie 文件保存在安全的位置
- 不能使用 $cookie_jar = “curl.cookie” 这样的相对路径
- curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); 应用于 https 页面,也可以自行下载证书来认证而非忽略。
延伸
某些站点开启了机器检查,一种是判断 cookie,这里已经解决了,另外一种是在登入页面加了一个动态的请求验证令牌(Request Verification Token),只要先使用 curl_get()获取到这个令牌,然后在登陆的 POST 数据里提交这个令牌即可。
站内 Wiki : PHP cURL
[…] 来源:这里 […]