开心网&豆瓣网发布状态PHP脚本(附Ping.fm的Custom URL使用方法)
2010-08-15 18:02 by hackerzhou20100821最新更新:豆瓣/人人/BBS/开心/嘀咕/网易微博/新浪微博状态更新PHP代码终结版
后知后觉的前几天才开始用Ping.fm同时向多个平台同步消息,感觉很强大,比如可以同时给twitter,facebook,google talk等传送消息,而国内的新浪微博和嘀咕是可以通过gtalk机器人监听用户的gtalk签名更改然后自动发状态的,但是由于不支持国内的SNS社区,如开心和人人,一大排支持同步的站点一大半不认识,感觉有点别扭,好在Ping.fm支持Custom URL,可以自己写符合它标准的service接口就可以了,这样就可以实现让自定义的网站传送消息。
之前做过日月光华/复旦泉和人人网的发文脚本,使用的是php里的curl,这次修改了一下代码,紧凑了些。开心网的登录有些的复杂,因为几个月前开心网改变了原有的登录方式,不再明文发送密码,而是登录主页的时候在主页里返回一个密钥,然后输入的用户名和密码在提交的前经过一个极其猥琐的js脚本加密。因为我要实现自动登录并且发文,所以只能用php重写了一下原生的js脚本,由于是两种脚本语言,debug起来相对比较麻烦,而且我经常忘记在php的变量前面加上$符号,这个符号让我感觉很别扭。js有无符号右移的运算符>>>,php中只有有符号右移符>>,所以需要一个新的函数做无符号右移。
下面是用给定的密钥对密码进行加密的php代码(kaixin001encrypt.php),对应于js的加密脚本 http://s.kaixin001.com.cn/js/enlogin-7.js
<?php function f($s, $x, $y, $z) { switch ($s) { case 0: return ($x & $y) ^ (~$x & $z); case 1: return $x ^ $y ^ $z; case 2: return ($x & $y) ^ ($x & $z) ^ ($y & $z); case 3: return $x ^ $y ^ $z; } } function rotl($x, $n) { return ($x << $n) | (shr32($x,32 - $n)); } function tohs($str) { return dechex($str).""; } function getCharCode($str,$index){ return ord(substr($str,$index)); } function h($msg) { $K = array(0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6); $msg .= chr(0x80); $l = strlen($msg) / 4 + 2; $N = ceil($l / 16); $M; for ($i = 0; $i < $N; $i++) { for ($j = 0; $j < 16; $j++) { $M[$i][$j] = (getCharCode($msg,$i * 64 + $j * 4) << 24) | (getCharCode($msg,$i * 64 + $j * 4 + 1) << 16) | (getCharCode($msg,$i * 64 + $j * 4 + 2) << 8 ) | (getCharCode($msg,$i * 64 + $j * 4 + 3)); } } $M[$N - 1][14] = ((strlen($msg) - 1) * 8 ) / pow(2, 32); $M[$N - 1][14] = floor($M[$N - 1][14]); $M[$N - 1][15] = ((strlen($msg) - 1) * 8 ) & 0xffffffff; $H0 = 0x67452301; $H1 = 0xefcdab89; $H2 = 0x98badcfe; $H3 = 0x10325476; $H4 = 0xc3d2e1f0; $W; $a;$b;$c;$d;$e; for ($i = 0; $i < $N; $i++) { for ($t = 0; $t < 16; $t++){ $W[$t] = $M[$i][$t]; } for ($t = 16; $t < 80; $t++){ $W[$t] = rotl($W[$t - 3] ^ $W[$t - 8] ^ $W[$t - 14] ^ $W[$t - 16], 1); } $a = $H0; $b = $H1; $c = $H2; $d = $H3; $e = $H4; for ($t = 0; $t < 80; $t++) { $s = floor($t / 20); $T = (rotl($a, 5) + f($s, $b, $c, $d) + $e + $K[$s] + $W[$t]) & 0xffffffff; $e = $d; $d = $c; $c = rotl($b, 30); $b = $a; $a = $T; } $H0 = ($H0 + $a) & 0xffffffff; $H1 = ($H1 + $b) & 0xffffffff; $H2 = ($H2 + $c) & 0xffffffff; $H3 = ($H3 + $d) & 0xffffffff; $H4 = ($H4 + $e) & 0xffffffff; } return tohs($H0).tohs($H1).tohs($H2).tohs($H3).tohs($H4); } function en($p, $key) { if ($p == "") { return ""; } $v = &sl($p, true); $k = &sl($key, false); $n = count($v) - 1; if (count($k) < 4) { $n = 3; } $z = $v[$n]; $y = $v[0]; $de = 2654435769; $mx; $e; $p; $q = floor(6 + 52 / ($n + 1)); $sum = 0; while (0 < $q--) { $sum = $sum + $de & 0xffffffff; $e = shr32($sum,2) & 3; for ($p = 0; $p < $n; $p++) { $y = $v[$p + 1]; $mx = (shr32($z,5) ^ $y << 2) + (shr32($y,3) ^ $z << 4) ^ ($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z); $z = $v[$p] = $v[$p] + $mx & 0xffffffff; } $y = $v[0]; $mx = (shr32($z,5) ^ $y << 2) + (shr32($y,3) ^ $z << 4) ^ ($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z); $z = $v[$n] = $v[$n] + $mx & 0xffffffff; } return bh($v); } function bh(&$ar) { $charHex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); $str = ""; $len = count($ar); for ($i = 0, $tmp = $len << 2; $i < $tmp; $i++) { $str .= $charHex[(($ar[$i >> 2] >> ((($i & 3) << 3) + 4)) & 0xF)]; $str .= $charHex[(($ar[$i >> 2] >> (($i & 3) << 3)) & 0xF)]; } return $str; } function &sl($s, $w) { $len = strlen($s); $v=array(); for ($i = 0; $i < $len; $i += 4) { $v[$i >> 2] = getCharCode($s,$i) | getCharCode($s,$i+1) << 8 | getCharCode($s,$i+2) << 16 | getCharCode($s,$i+3) << 24; } if ($w) { $v[count($v)] = $len; } return $v; } function shr32($x, $bits){ if($bits <= 0){ return $x; } if($bits >= 32){ return 0; } $bin = decbin($x); $l = strlen($bin); if($l > 32){ $bin = substr($bin, $l - 32, 32); }elseif($l < 32){ $bin = str_pad($bin, 32, '0', STR_PAD_LEFT); } return bindec(str_pad(substr($bin, 0, 32 - $bits), 32, '0', STR_PAD_LEFT)); } function getPassword($oriPassword, $key) { return h(en($oriPassword, $key)); } ?>
登录开心网的时候需要先抓取一遍主页,然后获得密钥,然后call kaixin001encrypt.php中加密函数,获得密文之后把密钥和密文都发送到服务器进行验证。
豆瓣网会在登录成功后拿到一个hidden的input field,发状态和注销的时候都需要传这个参数。
发状态到豆瓣网,开心网,人人网,BBS的脚本如下:
<?php $method=$_POST["method"]; $title=$_POST["title"]; $message=$_POST["message"]; $settings; init($settings); if($message!=""){ send($method,$title,$message,$settings); } function init(&$settings){ $settings=array( "enable_douban"=>"true", "douban_username"=>"##豆瓣用户名", "douban_password"=>"##豆瓣密码"), "enable_renren"=>"true", "renren_username"=>"##人人网用户名", "renren_password"=>"##人人网密码", "enable_bbs"=>"true", "bbs_username"=>"##BBS用户名", "bbs_password"=>"##BBS密码", "bbs_board_id"=>"##BBS版面ID", "bbs_night_api"=>"##0点到8点访问BBS的接口", "bbs_host"=>"http://bbs.fudan.sh.cn/q", "enable_kaixin001"=>"true", "kaixin001_username"=>"##开心网用户名", "kaixin001_password"=>"##开心网密码" ); } function send($method,$title,$message,&$settings){ if($settings["enable_douban"]==="true"){ updateDouban($message,$settings["douban_username"],$settings["douban_password"]); } if($settings["enable_renren"]==="true"){ updateRenren($message,$settings["renren_username"],$settings["renren_password"]); } if($settings["enable_bbs"]==="true"){ if($method=="status"){ $title="状态同步"; } updateBBS($title,$message,$settings["bbs_board_id"],$settings["bbs_username"],$settings["bbs_password"],$settings["bbs_host"],$settings["bbs_night_api"]); } if($settings["enable_kaixin001"]==="true"){ updateKaixin001($message,$settings["kaixin001_username"],$settings["kaixin001_password"]); } } function updateBBS($title,$content,$boardId,$bbs_username,$bbs_password,$bbs_host,$night_api) { $newtitle=iconv("UTF-8","GB2312",$title); $newcontent=iconv("UTF-8","GB2312",$content); $hour=intval(date("H")); if($hour==0||($hour>=16&&$hour<=23)){ $bbs_host=$night_api; } $cookie_jar=tempnam('./tmp','bbs'); $ch=&getCurl($cookie_jar,"POST",$bbs_host."/bbs/login"); curl_setopt($ch,CURLOPT_POSTFIELDS,'id='.urlencode($bbs_username).'&pw='.urlencode($bbs_password)); $str=&sendAndResult($ch); $ch=&getCurl($cookie_jar,"POST",$bbs_host."/bbs/snd?bid=".$boardId."&f=&e=0"); curl_setopt($ch,CURLOPT_REFERER,$bbs_host.'/bbs/pst?bid='.$boardId); curl_setopt($ch,CURLOPT_POSTFIELDS,'title='.rawurlencode($newtitle).'&sig=3&text='.urlencode($newcontent)); $str=&sendAndResult($ch); $str=iconv("GB2312","UTF-8",$str); if(strstr($str,"成功")!==false){ echo "[BBS] succeed\n"; }else{ echo "[BBS] failed\n"; } $ch=&getCurl($cookie_jar,"GET",$bbs_host."/bbs/logout"); curl_setopt($ch,CURLOPT_REFERER,$bbs_host.'/bbs/doc?board=Test'); $str=&sendAndResult($ch); } function updateRenren($status,$renren_username,$renren_password){ $cookie_jar=tempnam('./tmp','renren'); $ch=&getCurl($cookie_jar,"POST","http://passport.renren.com/PLogin.do"); curl_setopt($ch,CURLOPT_POSTFIELDS,'email='.urlencode($renren_username).'&password='.urlencode($renren_password).'&autoLogin=true&origURL=http%3A%2F%2Fwww.renren.com%2FHome.do&domain=renren.com'); $str=&sendAndResult($ch); $pattern="/get_check:'([^']+)'/"; preg_match($pattern,$str,$matches); $get_check=$matches[1]; $ch=&getCurl($cookie_jar,"POST","http://status.renren.com/doing/update.do"); curl_setopt($ch,CURLOPT_POSTFIELDS,'c='.urlencode($status).'&raw='.urlencode($status).'&isAtHome=1&publisher_form_ticket='.$get_check.'&requestToken='.$get_check); curl_setopt($ch,CURLOPT_REFERER,'http://status.renren.com/ajaxproxy.htm'); $ret=&sendAndResult($ch); if(strpos($ret,"{\"allMsg\":")===0){ echo "[Renren] succeed\n"; }else{ echo "[Renren] failed\n"; } //$ch=&getCurl($cookie_jar,"GET","http://www.renren.com/Logout.do?get_check=".$get_check); //$ret=&sendAndResult($ch); } function updateKaixin001($status,$kaixin001_username,$kaixin001_password){ include("kaixin001encrypt.php"); $cookie_jar=tempnam('./tmp','kaixin001'); $ch=&getCurl($cookie_jar,"GET","http://www.kaixin001.com/"); $str=&sendAndResult($ch); $pattern="/new EnLogin\('([^']+)'/"; preg_match($pattern,$str,$matches); $encryptKey=$matches[1]; $encryptResult=getPassword($kaixin001_password,$encryptKey); $ch=&getCurl($cookie_jar,"POST","http://www.kaixin001.com/login/login_api.php"); curl_setopt($ch,CURLOPT_POSTFIELDS,'ver=1&email='.urlencode($kaixin001_username).'&rpasswd='.$encryptResult.'&encypt='.$encryptKey.'&url=%2Fhome%2F&remember=1'); $str=&sendAndResult($ch); $ch=&getCurl($cookie_jar,"POST","http://www.kaixin001.com/friend/status_submit.php"); curl_setopt($ch,CURLOPT_POSTFIELDS,'state='.urlencode($status)); curl_setopt($ch,CURLOPT_REFERER,'http://www.kaixin001.com/home/'); $ret=&sendAndResult($ch); if(strpos($ret,"{\"state\":")===0){ echo "[Kaixin001] succeed\n"; }else{ echo "[Kaixin001] failed\n"; } //$ch=&getCurl($cookie_jar,"GET","http://www.kaixin001.com/login/logout.php"); //$ret=&sendAndResult($ch); } function updateDouban($status,$douban_username,$douban_password){ $cookie_jar=tempnam('./tmp','douban'); $ch=&getCurl($cookie_jar,"POST","http://www.douban.com/accounts/login"); curl_setopt($ch,CURLOPT_POSTFIELDS,'form_email='.urlencode($douban_username).'&form_password='.urlencode($douban_password).'&remember=on&user_login=%E8%BF%9B%E5%85%A5'); $str=&sendAndResult($ch); $pattern="/<input type=\"hidden\" name=\"ck\" value=\"([^\"]+)\"/"; $isLogin=preg_match($pattern,$str,$matches); $ck=$matches[1]; $ch=&getCurl($cookie_jar,"POST","http://www.douban.com/"); curl_setopt($ch,CURLOPT_POSTFIELDS,'ck='.$ck.'&mb_text='.urlencode($status)); curl_setopt($ch,CURLOPT_REFERER,'http://www.douban.com/'); $ret=&sendAndResult($ch); if($isLogin){ echo "[Douban] succeed\n"; }else{ echo "[Douban] failed\n"; } //$ch=&getCurl($cookie_jar,"GET","http://www.douban.com/accounts/logout?ck=".$ck); //$ret=&sendAndResult($ch); } function &getCurl($jar,$method,$url){ $ch=curl_init(); curl_setopt($ch,CURLOPT_COOKIEJAR,$jar); curl_setopt($ch,CURLOPT_COOKIEFILE,$jar); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_FOLLOWLOCATION,TRUE); curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE); if($method=="POST"){ curl_setopt($ch,CURLOPT_POST,TRUE); }else{ curl_setopt($ch,CURLOPT_POST,FALSE); } //curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6'); return $ch; } function &sendAndResult(&$ch){ $str=curl_exec($ch); curl_close($ch); unset($ch); return $str; } ?>
2010-09-13 15:35
开心网是不是又在登陆地方做手脚了,怎么之前可以登录的代码,现在登陆不上去了,是修改了加密文件了吗,还是怎么回事
2010-09-02 17:17
呵呵,不错不错
2010-09-02 17:15
呵呵,总算是可以访问到了,非常感谢您的指导,还有珍贵的文档,再次感谢,呵呵
2010-09-02 17:04
我登陆的时候设置了
$cookie_jar = tempnam(‘temp’,’cookie’);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
登陆后访问首页的时候用了
curl_setopt($ch3, CURLOPT_COOKIEFILE, $cookie_jar);
而且对应的temp目录下也有生成temp文件,怎么就不行呢,郁闷了
2010-09-02 16:44
应该是的,看到uid的返回应该是成功了,cookie_jar很重要,而且路径貌似有系统依赖
2010-09-02 16:43
这次我通过这个链接http://login.kaixin001.com/login/login_api.php?ver=1&[email protected]&rpasswd=c0c061a073f8446ac6f9cc4ac25af51bbc8d6b6&encypt=ThtijuNqrkq2ttp&url=%2Fhome%2F&remember=1
访问返回的是:{“loc”:”\/home\/?uid=36380057″}
这个应该就是转到我主页了,但是我下面继续访问
http://www.kaixin001.com/home/?uid=36380057
就不行了,没输出东西,是因为cookie没设置好吗,我看cookie的目录已经有东西了
2010-09-02 15:41
有输出了,只输出来一个 1 后面做跳转了,好像curl只能抓到第一步,跳转之后的页面就抓不到了……
2010-09-02 15:18
难道不是http://www.kaixin001.com/login/login_api.php么?推荐你用firebug抓包调试,否则会搞死的,curl也有调试选项,打开后可以看到请求的过程。看两者是不是一致。首先,不可能没有返回的,如果你看不到返回八成是你的代码写错了,如果没有足够的编程功底的话推荐你还是去弄本书来学习下
2010-09-02 14:46
您好,我又来了,呵呵
我按照您的方式传的参数如下
ver=1&[email protected]&rpasswd=7d56d61f91c480ce76d4294c694c279311e503a8&encypt=r63fwl9ZHVxlIQr&url=%2Fhome%2F&remember=1
传的路径为http://www.kaixin001.com/login/login.php
我是用curl做的,可是获得的内容还是空的,请问这块是需要记录登陆的cookie吗,先用以上的参数登陆,然后记录cookie,然后再去访问用户对应的页面
比如http://www.kaixin001.com/home/?uid=36380057吗,我就是这样做的,请问这样有问题吗,还是要用别的方法做
2010-09-02 13:52
因为会有邮件通知,自动转发到gmail邮箱之后我在手机上也能收到。
其实我对php了解的不多,毕竟不是主业,还是对java/c#/c/c++之类的比较有感觉