Chinaunix首页 | 论坛 | 博客
  • 博客访问: 317345
  • 博文数量: 153
  • 博客积分: 3347
  • 博客等级: 中校
  • 技术积分: 1556
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-30 17:50
文章分类

全部博文(153)

文章存档

2013年(7)

2012年(21)

2011年(46)

2010年(16)

2009年(63)

我的朋友

分类:

2009-12-30 18:41:30

/**
* 基于 版
* 去除大段注释,以及无用代码
* 仅使用发消息及获取好友列表功能
* 2008-12-15 李勇
*/
class MSN{
    
//dispatch服务器地址及端口
    
private $server = 'messenger.hotmail.com';
    private 
$port = 1863;

    private 
$passport_url = '';

    private 
$prod_key = 'PK}_A_0N_K%O?A9S';
    private 
$prod_id = 'PROD0114ES4Z%Q5W';

    private 
$clientid = '0x7000800C';

    private 
$id;
    private 
$fp = false;
    private 
$error = '';

    private 
$authed = false;
    private 
$user = '';
    private 
$password = '';

    private 
$passport_policy = '';
    private 
$oim_try = 3;
    private 
$oim_ticket = '';
    private 
$contact_ticket = '';

    private 
$debug = true;

    private 
$timeout = 15;
    private 
$stream_timeout = 2;

    private 
$sb;
    private 
$font_fn = 'Arial';
    private 
$font_co = '333333';
    private 
$font_ef = '';

    private 
$max_msn_message_len = 1664;
    private 
$max_yahoo_message_len = 518;

    
/**
     * 构造函数,需要以下PHP扩展的支持curl,prece,mhash,mcrypt,bcmath
     *
     * @return MSN
     */
    
public function MSN(){
        if (!
function_exists('curl_init')) die("We need curl module!\n");
        if (!
function_exists('preg_match')) die("We need pcre module!\n");
        if (!
function_exists('mhash'))die("We need mhash module  !\n");
        if (!
function_exists('mcrypt_cbc')) die("We need mcrypt module !\n");
        if (!
function_exists('bcmod'))die("We need bcmath module !\n");

        return;
    }

    
/**
     * 登录指定MSN账号
     *
     * @param string $user
     * @param string $password
     * @return bool
     * @uses
     *      var
     *          id
     *          fp
     *          =>error
     *          =>authed
     *          timeout
     *          =>passport_policy
     *          =>oim_ticket
     *          =>contact_ticket
     *          =>user
     *          =>password
     *      function
     *          readln
     *          writeln
     *          readdata
     *          debug_message
     *          get_passport_ticket
     *          generateLoginBLOB
     */
    
public function connect($user, $password){
        
$this->id = 1;

        
$server='messenger.hotmail.com';
        
$port=1863;

        
$errno=0;
        
$errstr='';
        
$stream_timeout = 2;

        
$this->fp = @fsockopen($server, $port, $errno, $errstr, 5);
        if (!
$this->fp) {
            
$this->error = "Can't connect to $server:$port, error => $errno, $errstr";
            return 
false;
        }

        
stream_set_timeout($this->fp, $stream_timeout);
        
$this->authed = false;

        
$this->writeln("VER $this->id MSNP15 CVR0");

        
$start_tm = time();
        while (!
feof($this->fp)) {
            
$data = $this->readln();
            
// no data?
            
if ($data === false) {
                if (
$this->timeout > 0) {
                    
$now_tm = time();
                    
$used_time = ($now_tm >= $start_tm) ? $now_tm - $start_tm : $now_tm;
                    if (
$used_time > $this->timeout) {
                        
// logout now
                        // NS: >>> OUT
                        
$this->writeln("OUT");
                        
fclose($this->fp);
                        
$this->error = 'Timeout, maybe protocol changed!';
                        
$this->debug_message("*** $this->error");
                        return 
false;
                    }
                }
                continue;
            }
            
$code = substr($data, 0, 3);
            
$start_tm = time();
            switch (
$code) {
                case 
'VER':
                    
$this->writeln("CVR $this->id 0x0409 winnt 5.1 i386 MSMSGS 8.1.0178 msmsgs $user");
                    break;
                case 
'CVR':
                    
$this->writeln("USR $this->id SSO I $user");
                    break;
                case 
'USR':
                    if (
$this->authed) return true;

                    
// max. 16 digits for password
                    
if (strlen($password) > 16)
                    
$password = substr($password, 0, 16);

                    
$this->user = $user;
                    
$this->password = $password;

                    
// NS: <<< USR {id} SSO S {policy} {nonce}
                    
@list(/* USR */, /* id */, /* SSO */, /* S */, $policy, $nonce,) = @explode(' ', $data);

                    
$this->passport_policy = $policy;
                    
$aTickets = $this->get_passport_ticket();
                    if (!
$aTickets || !is_array($aTickets)) {
                        
// logout now
                        // NS: >>> OUT
                        
$this->writeln("OUT");
                        
fclose($this->fp);
                        
$this->error = 'Passport authenticated fail!';
                        
$this->debug_message("*** $this->error");
                        return 
false;
                    }

                    
$this->oim_ticket = $aTickets['oim_ticket'];
                    
$this->contact_ticket = $aTickets['contact_ticket'];

                    
// NS: >>> USR {id} SSO S {ticket} {login_code}
                    
$this->writeln("USR $this->id SSO S ".$aTickets['ticket']." ".$this->generateLoginBLOB($aTickets['secret'], $nonce));

                    
$this->authed = true;
                    break;
                case 
'XFR':
                    @list(
/* XFR */, /* id */, /* NS */, $server, /* ... */) = @explode(' ', $data);
                    @list(
$ip, $port) = @explode(':', $server);
                    
// this connection will close after XFR
                    
fclose($this->fp);

                    
$errno=0;
                    
$errstr='';
                    
$this->fp = @fsockopen($ip, $port, $errno, $errstr, 5);
                    if (!
$this->fp) {
                        
$this->error = "Can't connect to $ip:$port, error => $errno, $errstr";
                        
$this->debug_message("*** $this->error");
                        return 
false;
                    }

                    
stream_set_timeout($this->fp, $this->stream_timeout);
                    
$this->writeln("VER $this->id MSNP15 CVR0");
                    break;
                case 
'GCF':
                    
// return some policy data after 'USR {id} SSO I {user}' command
                    // NS: <<< GCF 0 {size}
                    
@list(/* GCF */, /* 0 */, $size,) = @explode(' ', $data);
                    
// we don't need the data, just read it and drop
                    
if (is_numeric($size) && $size > 0)
                    
$this->readdata($size);
                    break;
                default:
                    
// we'll quit if got any error
                    
if (is_numeric($code)) {
                        
// logout now
                        // NS: >>> OUT
                        
$this->writeln("OUT");
                        
fclose($this->fp);
                        
$this->error = "Error code: $code, please check the detail information from: ";
                        
$this->debug_message("*** $this->error");
                        return 
false;
                    }
                    
// unknown response from server, just ignore it
                    
break;
            }
        }
        
// never goto here
        
return false;
    }


    
/**
     * 获取通行证的令牌
     *
     * @param string $url
     * @return string
     * @uses
     *      var
     *          user<=
     *          password<=
     *          passport_url<=
     *          passport_policy<=
     *      function
     */
    
private function get_passport_ticket($url = ''){
        
$user = $this->user;
        
$password = htmlspecialchars($this->password);
        if (
$url === '')
        
$passport_url = $this->passport_url;
        else
        
$passport_url = $url;
        
$XML = '
          xmlns:wsse=""
          xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
          xmlns:wsp=""
          xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
          xmlns:wsa=""
          xmlns:wssc=""
          xmlns:wst="">

  
    {7108E71A-9926-4FCB-BCC9-9A9D3F32E423}
    4
    1
    
    AQAAAAIAAABsYwQAAAAxMDMz
  
  
    
      '.$user.'
      '.$password.'
    
  



  
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          
        

      

    
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          messengerclear.live.com
        

      

      .$this->passport_policy.'">
    
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          messenger.msn.com
        

      

      
    
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          contacts.msn.com
        

      

      
    
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          messengersecure.live.com
        

      

      
    
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          spaces.live.com
        

      

      
    
    
      http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue
      
        
          storage.msn.com
        

      

      
    
  

'
;
        
$curl = curl_init();
        
curl_setopt($curl, CURLOPT_URL, $passport_url);
        if (
$this->debug) curl_setopt($curl, CURLOPT_HEADER, 1);
        
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
        
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
        
curl_setopt($curl, CURLOPT_POST, 1);
        
curl_setopt($curl, CURLOPT_POSTFIELDS, $XML);
        
$data = curl_exec($curl);
        
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        
curl_close($curl);

        if (
$http_code != 200) {
            
// sometimes, redirect to another URL
            // MSNP15
            //psf:Redirect
            //
            //Authentication Failure
            
if (strpos($data, 'psf:Redirect') === false) {
                
$this->debug_message("*** Can't get passport ticket! http code = $http_code");
                return 
false;
            }
            
preg_match("#(.*)#", $data, $matches);
            if (
count($matches) == 0) {
                
$this->debug_message("*** redirect, but can't get redirect URL!");
                return 
false;
            }
            
$redirect_url = $matches[1];
            if (
$redirect_url == $passport_url) {
                
$this->debug_message("*** redirect, but redirect to same URL!");
                return 
false;
            }
            
$this->debug_message("*** redirect to $redirect_url");
            return 
$this->get_passport_ticket($redirect_url);
        }
        
// sometimes, rediret to another URL, also return 200
        // MSNP15
        //psf:Redirect
        //
        //Authentication Failure
        
if (strpos($data, 'psf:Redirect') !== false) {
            
preg_match("#(.*)#", $data, $matches);
            if (
count($matches) != 0) {
                
$redirect_url = $matches[1];
                if (
$redirect_url == $passport_url) {
                    
$this->debug_message("*** redirect, but redirect to same URL!");
                    return 
false;
                }
                
$this->debug_message("*** redirect to $redirect_url");
                return 
$this->get_passport_ticket($redirect_url);
            }
        }

        
preg_match("#".
        
"(.*)(.*)".
        
"(.*)(.*)".
        
"(.*)(.*)".
        
"(.*)(.*)".
        
"(.*)(.*)".
        
"(.*)(.*)".
        
"(.*)(.*)".
        
"#",
        
$data, $matches);
        
// no ticket found!
        
if (count($matches) == 0) {
            
$this->debug_message("*** Can't get passport ticket!");
            return 
false;
        }
        
// yes, we get ticket
        
$aTickets = array(
        
'ticket' => html_entity_decode($matches[1]),
        
'secret' => html_entity_decode($matches[3]),
        
'contact_ticket' => html_entity_decode($matches[7]),
        
'oim_ticket' => html_entity_decode($matches[9]),
        );
        return 
$aTickets;
    }


阅读(1026) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~