X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FMsn%2Fextlib%2Fphpmsnclass%2Fmsn.class.php;h=996c5571c20bd2c0a29458b7b1a00ef654f2e97b;hb=5bf0c9f610d2fe7852ffafbcd51436c9e057b0a7;hp=5c79b3126161414ebef8d645c00bb9c76d400c69;hpb=f122d0b660e392fe5ce28a4ec14db6d45bd6b017;p=quix0rs-gnu-social.git diff --git a/plugins/Msn/extlib/phpmsnclass/msn.class.php b/plugins/Msn/extlib/phpmsnclass/msn.class.php index 5c79b31261..996c5571c2 100644 --- a/plugins/Msn/extlib/phpmsnclass/msn.class.php +++ b/plugins/Msn/extlib/phpmsnclass/msn.class.php @@ -12,7 +12,7 @@ Documentation on the MSN protocol can be found at: http://msnpiki.msnfanatic.com This class uses MSNP15. In addition to PHP5, the additional php modules required are: -curl pcre mhash mcrypt bcmath +curl pcre mcrypt bcmath */ @@ -23,10 +23,10 @@ class MSN { const PROD_KEY = 'PK}_A_0N_K%O?A9S'; const PROD_ID = 'PROD0114ES4Z%Q5W'; const LOGIN_METHOD = 'SSO'; - + const OIM_SEND_URL = 'https://ows.messenger.msn.com/OimWS/oim.asmx'; const OIM_SEND_SOAP = 'http://messenger.live.com/ws/2006/09/oim/Store2'; - + const OIM_MAILDATA_URL = 'https://rsi.hotmail.com/rsi/rsi.asmx'; const OIM_MAILDATA_SOAP = 'http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata'; const OIM_READ_URL = 'https://rsi.hotmail.com/rsi/rsi.asmx'; @@ -42,16 +42,16 @@ class MSN { const DELMEMBER_URL = 'https://contacts.msn.com/abservice/SharingService.asmx'; const DELMEMBER_SOAP = 'http://www.msn.com/webservices/AddressBook/DeleteMember'; - + // the message length (include header) is limited (maybe since WLM 8.5 released) // for WLM: 1664 bytes // for YIM: 518 bytes const MAX_MSN_MESSAGE_LEN = 1664; const MAX_YAHOO_MESSAGE_LEN = 518; - + private $debug; private $timeout; - + private $id; private $ticket; private $user = ''; @@ -76,7 +76,7 @@ class MSN { private $port = 1863; private $clientid = ''; - + private $error = ''; private $authed = false; @@ -156,7 +156,6 @@ class MSN { // Check support if (!function_exists('curl_init')) throw new Exception("curl module not found!\n"); if (!function_exists('preg_match')) throw new Exception("pcre module not found!\n"); - if (!function_exists('mhash')) throw new Exception("mhash module not found!\n"); if (!function_exists('mcrypt_cbc')) throw new Exception("mcrypt module not found!\n"); if (!function_exists('bcmod')) throw new Exception("bcmath module not found!\n"); @@ -181,7 +180,7 @@ class MSN { /** * Signon methods */ - + /** * Connect to the NS server * @@ -262,7 +261,7 @@ class MSN { $this->user = $user; $this->password = $password; // NS: <<< USR {id} SSO S {policy} {nonce} - @list(/* USR */, /* id */, /* SSO */, /* S */, $policy, $nonce,) = @explode(' ', $data); + @list(/* USR */, /* id */, /* SSO */, /* S */, $policy, $nonce) = @explode(' ', $data); $this->passport_policy = $policy; $aTickets = $this->get_passport_ticket(); @@ -271,7 +270,7 @@ class MSN { // NS: >>> OUT $this->ns_writeln("OUT"); @fclose($this->NSfp); - $this->error = 'Passport authenticated fail!'; + $this->error = 'Passport authentication failed!'; return false; } @@ -291,7 +290,7 @@ class MSN { // NS: <<< XFR {id} NS {server} 0 {server} // MSNP15 // NS: <<< XFR {id} NS {server} U D - @list(/* XFR */, /* id */, $Type, $server, /* ... */) = @explode(' ', $data); + @list(/* XFR */, /* id */, $Type, $server) = @explode(' ', $data); if ($Type!='NS') break; @list($ip, $port) = @explode(':', $server); // this connection will close after XFR @@ -313,7 +312,7 @@ class MSN { case 'GCF': // return some policy data after 'USR {id} SSO I {user}' command // NS: <<< GCF 0 {size} - @list(/* GCF */, /* 0 */, $size,) = @explode(' ', $data); + @list(/* GCF */, /* 0 */, $size) = @explode(' ', $data); // we don't need the data, just read it and drop if (is_numeric($size) && $size > 0) $this->ns_readdata($size); @@ -345,7 +344,7 @@ class MSN { /* FIXME Don't implement the signon as a loop or we could hang * the queue handler! */ $this->debug_message('*** Trying to connect to MSN network'); - + // Remove any remaining switchboard sessions $this->switchBoardSessions = array(); $this->switchBoardSessionLookup = array(); @@ -358,7 +357,10 @@ class MSN { } // Update contacts - if ($this->UpdateContacts() === false) continue; + if ($this->UpdateContacts() === false) { + $this->signonFailure(''); + continue; + } // Get membership lists if (($this->aContactList = $this->getMembershipList()) === false) { @@ -480,8 +482,10 @@ class MSN { * @return void */ private function signonFailure($message) { - $this->debug_message($message); - $this->callHandler('ConnectFailed'); + if(!empty($message)) { + $this->debug_message($message); + } + $this->callHandler('ConnectFailed', $message); $this->NSRetryWait($this->retry_wait); } @@ -504,7 +508,7 @@ class MSN { /** * NS and SB command handling methods */ - + /** * Read and handle incoming command from NS * @@ -527,7 +531,7 @@ class MSN { $this->signon(); return; } - + switch (substr($data, 0, 3)) { case 'SBS': // after 'USR {id} OK {user} {verify} 0' response, the server will send SBS and profile to us @@ -550,7 +554,7 @@ class MSN { case 'LST': // NS: <<< LST {email} {alias} 11 0 - @list(/* LST */, $email, /* alias */,) = @explode(' ', $data); + @list(/* LST */, $email) = @explode(' ', $data); @list($u_name, $u_domain) = @explode('@', $email); if (!isset($this->aContactList[$u_domain][$u_name][1])) { $this->aContactList[$u_domain][$u_name][1]['Allow'] = 'Allow'; @@ -561,7 +565,7 @@ class MSN { case 'ADL': // randomly, we get ADL command, someone add us to their contact list for MSNP15 // NS: <<< ADL 0 {size} - @list(/* ADL */, /* 0 */, $size,) = @explode(' ', $data); + @list(/* ADL */, /* 0 */, $size) = @explode(' ', $data); if (is_numeric($size) && $size > 0) { $data = $this->ns_readdata($size); preg_match('##', $data, $matches); @@ -613,7 +617,7 @@ class MSN { case 'RML': // randomly, we get RML command, someome remove us to their contact list for MSNP15 // NS: <<< RML 0 {size} - @list(/* RML */, /* 0 */, $size,) = @explode(' ', $data); + @list(/* RML */, /* 0 */, $size) = @explode(' ', $data); if (is_numeric($size) && $size > 0) { $data = $this->ns_readdata($size); preg_match('##', $data, $matches); @@ -643,7 +647,7 @@ class MSN { case 'MSG': // randomly, we get MSG notification from server // NS: <<< MSG Hotmail Hotmail {size} - @list(/* MSG */, /* Hotmail */, /* Hotmail */, $size,) = @explode(' ', $data); + @list(/* MSG */, /* Hotmail */, /* Hotmail */, $size) = @explode(' ', $data); if (is_numeric($size) && $size > 0) { $data = $this->ns_readdata($size); $aLines = @explode("\n", $data); @@ -788,7 +792,7 @@ class MSN { case 'UBM': // randomly, we get UBM, this is the message from other network, like Yahoo! // NS: <<< UBM {email} $network $type {size} - @list(/* UBM */, $from_email, $network, $type, $size,) = @explode(' ', $data); + @list(/* UBM */, $from_email, $network, $type, $size) = @explode(' ', $data); if (is_numeric($size) && $size > 0) { $data = $this->ns_readdata($size); $aLines = @explode("\n", $data); @@ -827,7 +831,7 @@ class MSN { case 'UBX': // randomly, we get UBX notification from server // NS: <<< UBX email {network} {size} - @list(/* UBX */, /* email */, /* network */, $size,) = @explode(' ', $data); + @list(/* UBX */, /* email */, /* network */, $size) = @explode(' ', $data); // we don't need the notification data, so just ignore it if (is_numeric($size) && $size > 0) $this->ns_readdata($size); @@ -836,7 +840,7 @@ class MSN { case 'CHL': // randomly, we'll get challenge from server // NS: <<< CHL 0 {code} - @list(/* CHL */, /* 0 */, $chl_code,) = @explode(' ', $data); + @list(/* CHL */, /* 0 */, $chl_code) = @explode(' ', $data); $fingerprint = $this->getChallenge($chl_code); // NS: >>> QRY {id} {product_id} 32 // NS: >>> fingerprint @@ -860,7 +864,7 @@ class MSN { // NS: <<< XFR {id} NS {server} U D // for normal switchboard XFR // NS: <<< XFR {id} SB {server} CKI {cki} U messenger.msn.com 0 - @list(/* XFR */, /* {id} */, $server_type, $server, /* CKI */, $cki_code, /* ... */) = @explode(' ', $data); + @list(/* XFR */, /* {id} */, $server_type, $server, /* CKI */, $cki_code) = @explode(' ', $data); @list($ip, $port) = @explode(':', $server); if ($server_type != 'SB') { // maybe exit? @@ -887,20 +891,19 @@ class MSN { // someone is trying to talk to us // NS: <<< RNG {session_id} {server} {auth_type} {ticket} {email} {alias} U {client} 0 $this->debug_message("NS: <<< RNG $data"); - @list(/* RNG */, $sid, $server, /* auth_type */, $ticket, $email, $name,) = @explode(' ', $data); + @list(/* RNG */, $sid, $server, /* auth_type */, $ticket, $email, $name) = @explode(' ', $data); @list($sb_ip, $sb_port) = @explode(':', $server); $this->debug_message("*** RING from $email, $sb_ip:$sb_port"); $this->addContact($email, 1, $email, true); $this->connectToSBSession('Passive', $sb_ip, $sb_port, $email, array('sid' => $sid, 'ticket' => $ticket)); break; - + case 'NLN': // NS: <<< NLN {status} {email} {networkid} {nickname} {clientid} {dpobj} - // NS: <<< NLN NLN darkip@inflatablegoldfish.com 1 Luke 2685403136 0 - @list(/* NLN */, $status, $email, $network, $nickname, /* clientid */, /* dbobj */,) = @explode(' ', $data); + @list(/* NLN */, $status, $email, $network, $nickname) = @explode(' ', $data); $this->callHandler('StatusChange', array('screenname' => $email, 'status' => $status, 'network' => $network, 'nickname' => $nickname)); break; - + case 'OUT': // force logout from NS // NS: <<< OUT xxx @@ -945,11 +948,14 @@ class MSN { // SB: <<< IRO {id} {rooster} {roostercount} {email} {alias} {clientid} @list(/* IRO */, /* id */, $cur_num, $total, $email, $alias, $clientid) = @explode(' ', $data); $this->debug_message("*** $email joined session"); - $session['joined'] = true; + if ($email == $session['to']) { + $session['joined'] = true; + $this->callHandler('SessionReady', array('to' => $email)); + } break; case 'BYE': $this->debug_message("*** Quit for BYE"); - $this->endSBSession(); + $this->endSBSession($socket); break; case 'USR': // SB: <<< USR {id} OK {user} {alias} @@ -966,13 +972,15 @@ class MSN { case 'JOI': // SB: <<< JOI {user} {alias} {clientid?} // someone join us - // we don't need the data, just ignore it - // no more user here - $session['joined'] = true; + @list(/* JOI */, $email) = @explode(' ', $data); + if ($email == $session['to']) { + $session['joined'] = true; + $this->callHandler('SessionReady', array('to' => $email)); + } break; case 'MSG': // SB: <<< MSG {email} {alias} {len} - @list(/* MSG */, $from_email, /* alias */, $len, ) = @explode(' ', $data); + @list(/* MSG */, $from_email, /* alias */, $len) = @explode(' ', $data); $len = trim($len); $data = $this->sb_readdata($socket, $len); $aLines = @explode("\n", $data); @@ -1309,7 +1317,7 @@ class MSN { break; } $this->debug_message("*** MSG from $from_email: $sMsg"); - $this->callHandler('IMin', array('sender' => $from_email, 'message' => $sMsg, 'network' => $network, 'offline' => false)); + $this->callHandler('IMin', array('sender' => $from_email, 'message' => $sMsg, 'network' => 1, 'offline' => false)); break; case '217': $this->debug_message('*** User '.$session['to'].' is offline. Trying OIM.'); @@ -1319,7 +1327,6 @@ class MSN { if (is_numeric($code)) { $this->error = "Error code: $code, please check the detail information from: http://msnpiki.msnfanatic.com/index.php/Reference:Error_List"; $this->debug_message("*** SB: $this->error"); - $sessionEnd=true; } break; } @@ -1353,7 +1360,7 @@ class MSN { /** * Switchboard related methods */ - + /** * Send a request for a switchboard session * @@ -1406,12 +1413,12 @@ class MSN { 'offline' => false, 'XFRReqTime' => time() ); - + // Change the index of the session to the socket $intsocket = (int) $socket; $this->switchBoardSessions[$intsocket] = $this->switchBoardSessions[$to]; unset($this->switchBoardSessions[$to]); - + $id = &$this->switchBoardSessions[$intsocket]['id']; if ($mode == 'Active') { @@ -1428,7 +1435,7 @@ class MSN { $this->sb_writeln($socket, $id, "ANS $id $this->user $ticket $sid"); } } - + /** * Called when we want to end a switchboard session * or a switchboard session ends @@ -1463,14 +1470,8 @@ class MSN { if (self::socketcheck($socket)) { return false; } - - $intsocket = (int) $socket; - if (!$this->switchBoardSessions[$intsocket]['joined']) { - // If our participant has not joined the session yet we can't message them! - return false; - } - $id = &$this->switchBoardSessions[$intsocket]['id']; + $id = &$this->switchBoardSessions[(int) $socket]['id']; $aMessage = $this->getMessage($message); // CheckEmotion... @@ -1481,6 +1482,7 @@ class MSN { if ($this->sb_writeln($socket, $id, "MSG $id N $len") === false || $this->sb_writedata($socket, $SendString) === false) { + $this->endSBSession($socket); return false; } } @@ -1488,7 +1490,8 @@ class MSN { if ($this->sb_writeln($socket, $id, "MSG $id N $len") === false || $this->sb_writedata($socket, $aMessage) === false) { - return false; + $this->endSBSession($socket); + return false; } // Don't close the SB session, we might as well leave it open @@ -1521,37 +1524,58 @@ class MSN { * where network is 1 for MSN, 32 for Yahoo * and 'Offline' for offline messages * @param string $message Message + * @param boolean &$waitForSession Boolean passed by reference, + * if set to true on return, message + * did not fail to send but is + * waiting for a valid session + * + * @return boolean true on success */ - public function sendMessage($to, $message) { + public function sendMessage($to, $message, &$waitForSession) { if ($message != '') { - list($name, $host, $network) = explode('@', $to); - $network = $network == '' ? 1 : $network; + $toParts = explode('@', $to); + if(count($toParts) < 3) { + list($name, $host) = $toParts; + $network = 1; + } else { + list($name, $host, $network) = $toParts; + } + $recipient = $name.'@'.$host; if ($network === 1) { if (!isset($this->switchBoardSessionLookup[$recipient])) { - if (!isset($this->switchBoardSessions[$recipient]) || time() - $this->switchBoardSessions[$recipient]['XFRReqTime'] > $this->XFRReqTimeout) { - $this->debug_message("*** No existing SB session or request has timed out"); - $this->reqSBSession($recipient); - } - return false; + if (!isset($this->switchBoardSessions[$recipient]) || time() - $this->switchBoardSessions[$recipient]['XFRReqTime'] > $this->XFRReqTimeout) { + $this->debug_message("*** No existing SB session or request has timed out"); + $this->reqSBSession($recipient); + } + + $waitForSession = true; + return false; } else { $socket = $this->switchBoardSessionLookup[$recipient]; - if ($this->switchBoardSessions[(int) $socket]['offline']) { + $intsocket = (int) $socket; + if ($this->switchBoardSessions[$intsocket]['offline']) { $this->debug_message("*** Contact ($recipient) offline, sending OIM"); $this->endSBSession($socket); + $waitForSession = false; return $this->sendMessage($recipient.'@Offline', $message); } else { + if ($this->switchBoardSessions[$intsocket]['joined'] !== true) { + $this->debug_message("*** Recipient has not joined session, returning false"); + $waitForSession = true; + return false; + } + $this->debug_message("*** Attempting to send message to $recipient using existing SB session"); if ($this->sendMessageViaSB($recipient, $message)) { $this->debug_message('*** Message sent successfully'); return true; - } else { - $this->debug_message('*** Message sending failed, requesting new SB session'); - $this->reqSBSession($recipient); - return false; } + + $waitForSession = false; + return false; } } } elseif ($network == 'Offline') { @@ -1595,7 +1619,7 @@ class MSN { /** * OIM methods */ - + /** * Get OIM mail data * @@ -1798,7 +1822,7 @@ class MSN { $this->debug_message("*** OIM ($msgid) deleted"); return $sMsg; } - + /** * Send offline message * @@ -1910,11 +1934,11 @@ X-OIM-Sequence-Num: 1 } return array('challenge' => $challenge, 'auth_policy' => $auth_policy); } - + /** * Contact / Membership list methods */ - + /** * Fetch contact list * @@ -2339,7 +2363,7 @@ X-OIM-Sequence-Num: 1 $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_close($curl); $this->debug_message("*** Get Result:\n$data"); - + if ($http_code != 200) return false; $p = $data; $aMemberships = array(); @@ -2419,11 +2443,11 @@ X-OIM-Sequence-Num: 1 } return $aContactList; } - + /** * MsnObj related methods */ - + /** * * @param $FilePath 圖檔路徑 @@ -2463,14 +2487,14 @@ X-OIM-Sequence-Num: 1 } return $DefineString; } - + /** * Socket methods */ - + /** * Read data of specified size from NS socket - * + * * @param integer $size Size to read * @return string Data read */ @@ -2489,7 +2513,7 @@ X-OIM-Sequence-Num: 1 /** * Read line from the NS socket - * + * * @return string Data read */ private function ns_readln() { @@ -2503,9 +2527,9 @@ X-OIM-Sequence-Num: 1 /** * Write line to NS socket - * + * * Also increments id - * + * * @param string $data Line to write to socket * @return mixed Bytes written or false on failure */ @@ -2520,7 +2544,7 @@ X-OIM-Sequence-Num: 1 /** * Write data to NS socket - * + * * @param string $data Data to write to socket * @return mixed Bytes written or false on failure */ @@ -2534,7 +2558,7 @@ X-OIM-Sequence-Num: 1 /** * Read data of specified size from given SB socket - * + * * @param resource $socket SB socket * @param integer $size Size to read * @return string Data read @@ -2554,7 +2578,7 @@ X-OIM-Sequence-Num: 1 /** * Read line from given SB socket - * + * * @param resource $socket SB Socket * @return string Line read */ @@ -2569,9 +2593,9 @@ X-OIM-Sequence-Num: 1 /** * Write line to given SB socket - * + * * Also increments id - * + * * @param resource $socket SB socket * @param integer $id Reference to SB id * @param string $data Line to write @@ -2588,7 +2612,7 @@ X-OIM-Sequence-Num: 1 /** * Write data to given SB socket - * + * * @param resource $socket SB socket * @param $data Data to write to socket * @return mixed Bytes written or false on error @@ -2620,16 +2644,16 @@ X-OIM-Sequence-Num: 1 $info = stream_get_meta_data($socket); return $info['eof']; } - + /** * Key generation methods */ - + private function derive_key($key, $magic) { - $hash1 = mhash(MHASH_SHA1, $magic, $key); - $hash2 = mhash(MHASH_SHA1, $hash1.$magic, $key); - $hash3 = mhash(MHASH_SHA1, $hash1, $key); - $hash4 = mhash(MHASH_SHA1, $hash3.$magic, $key); + $hash1 = $this->mhash_sha1($magic, $key); + $hash2 = $this->mhash_sha1($hash1.$magic, $key); + $hash3 = $this->mhash_sha1($hash1, $key); + $hash4 = $this->mhash_sha1($hash3.$magic, $key); return $hash2.substr($hash4, 0, 4); } @@ -2639,7 +2663,7 @@ X-OIM-Sequence-Num: 1 $key3 = $this->derive_key($key1, 'WS-SecureConversationSESSION KEY ENCRYPTION'); // get hash of challenge using key2 - $hash = mhash(MHASH_SHA1, $challenge, $key2); + $hash = $this->mhash_sha1($challenge, $key2); // get 8 bytes random data $iv = substr(base64_encode(rand(1000,9999).rand(1000,9999)), 2, 8); @@ -2653,7 +2677,7 @@ X-OIM-Sequence-Num: 1 return base64_encode($blob); } - + /** * Generate challenge response * @@ -2733,11 +2757,11 @@ X-OIM-Sequence-Num: 1 return $hash; } - + /** * Utility methods */ - + private function Array2SoapVar($Array, $ReturnSoapVarObj = true, $TypeName = null, $TypeNameSpace = null) { $ArrayString = ''; foreach($Array as $Key => $Val) { @@ -2745,7 +2769,7 @@ X-OIM-Sequence-Num: 1 $Attrib = ''; if (is_array($Val[':'])) { foreach ($Val[':'] as $AttribName => $AttribVal) - $Attrib .= " $AttribName = '$AttribVal'"; + $Attrib .= " $AttribName = '$AttribVal'"; } if ($Key{0} == '!') { //List Type Define @@ -2765,7 +2789,7 @@ X-OIM-Sequence-Num: 1 if ($ReturnSoapVarObj) return new SoapVar($ArrayString, XSD_ANYXML, $TypeName, $TypeNameSpace); return $ArrayString; } - + private function linetoArray($lines) { $lines = str_replace("\r", '', $lines); $lines = explode("\n", $lines); @@ -2776,7 +2800,7 @@ X-OIM-Sequence-Num: 1 } return $Data; } - + /** * Get Passport ticket * @@ -3023,7 +3047,7 @@ X-OIM-Sequence-Num: 1 $this->ABAuthHeader = new SoapHeader('http://www.msn.com/webservices/AddressBook', 'ABAuthHeader', $this->Array2SoapVar($ABAuthHeaderArray)); return $aTickets; } - + /** * Generate the data to send a message * @@ -3042,7 +3066,7 @@ X-OIM-Sequence-Num: 1 $msg = substr($sMessage, 0, $maxlen); return $msg_header.$msg; } - + /** * Sleep for the given number of seconds * @@ -3052,7 +3076,7 @@ X-OIM-Sequence-Num: 1 $this->debug_message("*** Sleeping for $wait seconds before retrying"); sleep($wait); } - + /** * Sends a ping command * @@ -3064,7 +3088,7 @@ X-OIM-Sequence-Num: 1 // NS: >>> PNG $this->ns_writeln("PNG"); } - + /** * Methods to add / call callbacks */ @@ -3093,7 +3117,7 @@ X-OIM-Sequence-Num: 1 * Registers a user handler * * Handler List - * IMIn, Pong, ConnectFailed, Reconnect, + * IMIn, SessionReady, Pong, ConnectFailed, Reconnect, * AddedToList, RemovedFromList, StatusChange * * @param string $event Event name @@ -3109,24 +3133,24 @@ X-OIM-Sequence-Num: 1 return false; } } - + /** * Debugging methods */ - + /** * Print message if debugging is enabled - * + * * @param string $str Message to print */ private function debug_message($str) { if (!$this->debug) return; echo $str."\n"; } - + /** * Dump binary data - * + * * @param string $str Data string * @return Binary data */ @@ -3155,4 +3179,32 @@ X-OIM-Sequence-Num: 1 $buf .= "$h_str $a_str\n"; return $buf; } + + function mhash_sha1($data, $key) + { + if (extension_loaded("mhash")) + return mhash(MHASH_SHA1, $data, $key); + + if (function_exists("hash_hmac")) + return hash_hmac('sha1', $data, $key, true); + + // RFC 2104 HMAC implementation for php. Hacked by Lance Rushing + $b = 64; + if (strlen($key) > $b) + $key = pack("H*", sha1($key)); + $key = str_pad($key, $b, chr(0x00)); + $ipad = str_pad("", $b, chr(0x36)); + $opad = str_pad("", $b, chr(0x5c)); + $k_ipad = $key ^ $ipad ; + $k_opad = $key ^ $opad; + + $sha1_value = sha1($k_opad . pack("H*", sha1($k_ipad . $data))); + + $hash_data = ''; + $str = join('',explode('\x', $sha1_value)); + $len = strlen($str); + for ($i = 0; $i < $len; $i += 2) + $hash_data .= chr(hexdec(substr($str, $i, 2))); + return $hash_data; + } }