最近需要批量向织梦后台导入一些数据,但是遇到了一个头疼的问题。
环境:xampp + 别人的dede后台。
首先,利用curl发送post请求登录login.php,成功,并且保存了cookie文件。
第二步,post发送数据包到co_get_corule.php,失败,得到登录页面的源码。
于是,尝试简单的get请求,get获取index.php,同上,依旧是cookie没带上的效果。
第三步,检查cookie文件,确实存在,且内容也是正确的。
经过多次重复试验,依旧失败,于是发帖求助。
1 <?php 2 header("Content-type: text/html; charset=utf-8"); 3 !extension_loaded('curl') && die('The curl extension is not loaded.'); 4 $cookie_jar = tempnam('./cookies','cookie');//存放COOKIE的文件 5 6 //登陆认证 7 $url = 'http://localhost/dede/login.php'; 8 9 10 //本来封装了函数,后来一直不成功,于是还原成了最原始的代码积木 11 12 $post_data='gotopage=index.php&dopost=login&adminstyle=newdedecms&userid=admin&pwd=admin'; 13 14 $ch = curl_init(); 15 16 curl_setopt($ch, CURLOPT_URL, $url); 17 curl_setopt($ch, CURLOPT_HEADER, 0); 18 curl_setopt($ch, CURLOPT_POST, 1); //设置post方式 19 curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 ); // 1相当于return,0相当于echo 20 21 curl_setopt($ch,CURLOPT_COOKIESESSION,true); 22 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); //设置需要post的数据 23 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar); //保存cookie信息 24 25 curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1); //是否抓取跳转后的页面,1是自动跳转 26 //curl_setopt($ch, CURLOPT_NOBODY,1); //输出的不包含body部分 27 28 $output1 = curl_exec($ch); 29 30 //写入结果到文件 31 file_put_contents('login.txt', $output1); 32 33 curl_close($ch); 34 35 36 37 //这里本来封装了函数,后来一直不成功,于是还原成了最原始的代码积木 38 39 $url2 = "http://localhost/dede/index.php"; 40 $ch2 = curl_init(); 41 42 curl_setopt($ch2, CURLOPT_URL, $url2); 43 curl_setopt($ch2, CURLOPT_HEADER, 0); 44 45 curl_setopt ( $ch2, CURLOPT_RETURNTRANSFER, 1 ); // 1相当于return,0相当于echo 46 curl_setopt($ch2, CURLOPT_BINARYTRANSFER, true); 47 48 curl_setopt($ch2, CURLOPT_TIMEOUT, 30); //超时时间30s 49 curl_setopt($ch2,CURLOPT_COOKIESESSION,true); 50 curl_setopt($ch2, CURLOPT_HTTPGET, 1); // 发送一个常规的get请求 51 curl_setopt($ch2, CURLOPT_AUTOREFERER, 1); // 自动设置Referer 52 curl_setopt($ch2,CURLOPT_COOKIEFILE,$cookie_jar);//发送cookie文件 53 curl_setopt($ch2, CURLOPT_COOKIEJAR, $cookie_jar); //保存cookie信息 54 55 curl_setopt($ch2, CURLOPT_FOLLOWLOCATION,1); //是否抓取跳转后的页面,1是自动跳转 56 //curl_setopt($ch, CURLOPT_NOBODY,1); //输出的不包含body部分 57 58 $output = curl_exec($ch2); 59 file_put_contents('index.txt', $output); 60 curl_close($ch2); 61 62 63 unlink($cookie_jar); 64 ?>
【PS:实在不知道如何验证cookie是否起作用了】
以上是拆掉函数后的原始代码,不具可读性,只求能解决这个坎儿,期待大家的帮忙,谢谢!
抓包看下,第二次请求时,COOKIE 是否包含在请求中。
也可以 curl_setopt($ch,CURLOPT_VERBOSE,0L),从输出看下请求和响应的内容。
不好意思,回复挤成一块了,我截图上传哈。
@不要呵呵:你这是只是Response,你的 Request 呢?
你第二次发起请求的 Request 的 Header 中应该包含:
Cookie:xxxxxxxxxxxxxxxxxxxxxxxxxx
@Launcher:
没有Cookie:xxxx这行。如图:
另外,求截php发送的数据包方法。截浏览器的只能截取到 GET:/caiji.php ***
谢谢
@不要呵呵: 你用 CURLOPT_HTTPHEADER 把那个 COOKIE 加上。
@Launcher:
$header[]= 'Cookie: menuitems=xxxxxxxx...";
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER,$header);
手动添加cookie后,正常进入了需要登陆的页面了。但是在firebug里面依旧看不到我发送的cookie
Cookie:xxxxxxxxxxxxxxxxxxxxxxxxxx
现在的疑问:
1、手动设置cookie就能成功,而调用api的却没成功
2、firebug里面看不到我手动设置的cookie头
3、curl帮我保存的cookie文件,session过期时间为何是1981年呢?
感激不尽!
@不要呵呵: 看不到是不可能的,是你抓取的包有问题。如果是 Windows 系统,可以使用 Fiddler 和 Microsoft Network Monitor 来抓去包,使用前者的话,你需要在 libcurl 中设置 HTTP 代理为本机,端口号可以从 Fiddler 的选项中找到。
你说的使用 API 的方式,应该是指使用 CURLOPT_COOKIEFILE 设置后不起作用吧!首先你得检查使用 CURLOPT_COOKIEJAR 后,是否保存了 COOKIE,注意只有调用了 curl_easy_cleanup 后才会保存。其次,在使用 CURLOPT_COOKIEFILE 时,你需要检查读取的文件中是否有 COOKIE 信息,你可以进入源码调试下,在处理 CURLOPT_COOKIEFILE 时,libcurl 是否读取到了你设置的 COOKIE。
另外 HTTP Response Header 中的 Expires 跟 SESSION 无关,它是用来表示响应的缓存有效期的。
Session
@Launcher:
感谢你在百忙中抽空帮我。
刚才我做了个对比:
1、使用Microsoft Network Monitor 监听apache发送的数据包
2、使用Microsoft Network Monitor 截获ie登录目标后台
3、使用Microsoft Network Monitor 截获firefox登录目标后台
由第一点得到:cookie确实由curl加入到了http请求头部里面,具体数据如下:
Cookie: PHPSESSID=b2qdqolekobbcq9p9s0i02onj6; DedeLoginTime__ckMd5=160a742df0464593; DedeLoginTime=1398868032; DedeUserID__ckMd5=adc11e494632c401; DedeUserID=1
firefox的cookie行如下:
Cookie: menuitems=1_1%2C2_1%2C3_1; Hm_lvt_2310b8fc76ab1532b04dc0f587e6a640=1385623511; pgv_pvi=6713670656; Hm_lvt_2fe99d3e28a6deb7b6f59b7add268f7a=1385623516; DedeUserID=1; DedeUserID__ckMd5=adc11e494632c401; DedeLoginTime=1398868517; DedeLoginTime__ck
IE的cookie头如下:
Cookie: menuitems=1_1%2C2_1%2C3_1; DedeUserID=1; DedeUserID__ckMd5=adc11e494632c401; DedeLoginTime=1398863428; DedeLoginTime__ckMd5=11e6c4db51052b1e;PHPSESSID=a12qtpfhu9vnbv8dd3c6b7qvn6; path=/
经过对比试验发现:
menuitems、pgv_pvi …… 这些都不影响正常访问。
关闭firefox和ie,手工把这3个cookie加入到代码中访问,发现浏览器的cookie都能正常访问,而curl获取的却不行。
对比手工加入浏览器cookie访问更新的cookie文件,发现:
正常访问更新cookie后,PHPSESSID 这一整行在cookie里面找不到了。
实在想不通这是怎么回事儿了。麻烦再指点一二。谢谢!
@不要呵呵: 因为没法测试,所以我还是讲清楚流程,你自己还是需要进入 libcurl 的源码跟踪调试下。
首先,客户端发起一个登录的请求,服务器通过验证后,返回的响应的 HEADER 中应该包括:
Set-Cookie: PHPSESSID=a12qtpfhu9vnbv8dd3c6b7qvn6; path=/
这是一个检查点,就是检查返回的响应中是否有 Set-Cookie,可以这样:
curl_easy_setopt(curl,CURLOPT_HEADERFUNCTION,....),然后在回调函数中观察 Set-Cookie 标头。
在确定包含 Set-Cookie 后,调用 curl_easy_cleanup 后,看使用 CURLOPT_COOKIEJAR 后保存的 Cookie 文件中是否包含正确的 Cookie。如果没有包含正确的 Cookie,那么你需要在 libcurl 的源码中搜索 CURLOPT_COOKIEJAR,找到 libcurl 如何将 Set-Cookie 标头的内容写入文件的。
@Launcher: 最近比较忙,没来的及回复哈,见谅。
同样的代码,使用C++调用libcurl居然成功了。
现在还没完全弄明白是什么原因,不过成功解决了问题。
具体细节问题我日后再慢慢调试吧,非常谢谢你的帮助!
cookie所属域名看了没,跨域cookie传不过去的
以前也做个类似的案例,都很顺利,但是这次的不可以。麻烦吴哥针对这个例子给指点一二,谢谢!
@不要呵呵: 话说为什么COOKIE会是文件,
你看下第一次的回话ID和第二次的回话ID是不是同一个
@吴瑞祥: 非常谢谢你的帮助!