PageRenderTime 73ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/php/whatsapp.class.php

https://github.com/satup/WhatsAPI
PHP | 321 lines | 284 code | 28 blank | 9 comment | 32 complexity | 49b5f1f304c7a133eec384fc7167adf5 MD5 | raw file
  1. <?php
  2. require "func.php";
  3. require "decode.php";
  4. class WhatsApp {
  5. private $_server = 's.whatsapp.net';
  6. private $_host = 'bin-short.whatsapp.net';
  7. private $_Digest_Uri = 'xmpp/s.whatsapp.net';
  8. private $_Realm = 's.whatsapp.net';
  9. private $_Qop = 'auth';
  10. private $_contype = 'STREAM_CLIENT_PERSISTENT';
  11. /*
  12. Account Info
  13. */
  14. private $_accinfo;
  15. private $_account_status; // Active or not ..
  16. private $_account_kind; // paid or free ..
  17. private $_account_creation ; // Timestamp of creation date
  18. private $_account_expiration; // Timestamp of expiration date
  19. function __construct($Number, $Password){
  20. $this->_number = $Number;
  21. $this->_password = $Password;
  22. }
  23. function _identify($str){
  24. $msg_identifier = "\x5D\x38\xFA\xFC";
  25. $server_delivery_identifier = "\x8C";
  26. $client_delivery_identifier = "\x7f\xbd\xad";
  27. $acc_info_iden = "\x99\xBD\xA7\x94";
  28. $last_seen_ident = "\x48\x38\xFA\xFC";
  29. $last_seen_ident2 = "\x7B\xBD\x4C\x8B";
  30. if(startsWith($str,$msg_identifier,3)){
  31. if(endsWith($str,$server_delivery_identifier)){
  32. return 'server_delivery_report';
  33. }
  34. else if(endsWith($str,$client_delivery_identifier)){
  35. return 'client_delivery_report';
  36. }
  37. else{
  38. return 'msg';
  39. }
  40. }
  41. else if(startsWith($str,$acc_info_iden,3)){
  42. return 'account_info';
  43. }
  44. else if(startsWith($str,$last_seen_ident,3) && strpos($str, $last_seen_ident2)){
  45. return 'last_seen';
  46. }
  47. }
  48. function Connect(){
  49. $Socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
  50. socket_connect( $Socket, $this->_host, 5222 );
  51. $this->_socket = $Socket;
  52. }
  53. function send($data){
  54. socket_send( $this->_socket, $data, strlen($data), 0 );
  55. }
  56. function read(){
  57. $buff = socket_read( $this->_socket, 1024 );
  58. $resarray = explode("\x00", $buff);
  59. $removed = array_shift($resarray);
  60. $rescount = count($resarray);
  61. if ($rescount != 0){
  62. foreach($resarray as $k=>$v){
  63. $rcvd_type = $this->_identify($v);
  64. if($rcvd_type == 'msg'){
  65. $msg = $this->parse_received_message($v);
  66. echo json_encode($msg); // Do something with the message here ?
  67. }
  68. else if ($rcvd_type == 'account_info'){
  69. $accinfo = $this->parse_account_info($v);
  70. $this->accinfo = $accinfo;
  71. }
  72. else if ($rcvd_type == 'last_seen'){
  73. $lastseen = $this->parse_last_seen($v);
  74. echo json_encode($lastseen); // They're stored in account variables too
  75. }
  76. }
  77. unset($rcvd_type);
  78. }
  79. return $buff;
  80. }
  81. function parse_received_message($msg){
  82. // RCVD MSG IN STRING
  83. $length = substr($msg,0,1);
  84. $message['length'] = ord($length); // PACKET EXCLUDING 00 AND FIRST HEX SHOULD EQUAL THIS NUMBER
  85. $msg = substr($msg,2); // Remove Length & F8
  86. $message['sec_length'] = ord(substr($msg,0,1)); // Length of something i dont know excatly what
  87. $msg = substr($msg,5); // Remove Second Length ( 1 HEX ) , Remove XML Chrs ( 4 HEX )
  88. $message['from_number_length'] = ord(substr($msg,0,1));
  89. $msg = substr($msg,1); // Remove Length
  90. $message['from_number'] = substr($msg,0,$message['from_number_length']);
  91. $msg = substr($msg,$message['from_number_length']); // Remove NUMBER
  92. $msg = substr($msg,3); // Remove F8 & XML ( 2 HEX )
  93. $message['message_id_length'] = ord(substr($msg,0,1));
  94. $msg = substr($msg,1); // Remove Length
  95. $message['message_id'] = substr($msg,0,$message['message_id_length']);
  96. $msg = substr($msg,$message['message_id_length']);
  97. $msg = substr($msg,4); // Remove XML ( 4 HEX )
  98. $message['timestamp_length'] = ord(substr($msg,0,1));
  99. $msg = substr($msg,1); // Remove Length
  100. $message['timestamp'] = substr($msg,0,$message['timestamp_length']);
  101. $msg = substr($msg,$message['timestamp_length']); // Remove Timestamp
  102. // Check for Retry header
  103. if(substr($msg,0,1) == "\x88"){
  104. $msg = substr($msg,4); // Remove Retry Length , i dont think i will need it
  105. }
  106. $msg = substr($msg,9); // Remove XMPP XML and Name XML Headers
  107. $message['sender_name_length'] = ord(substr($msg,0,1));
  108. $msg = substr($msg,1); // Remove Length
  109. $message['sender_name'] = substr($msg,0,$message['sender_name_length']);
  110. $msg = substr($msg,$message['sender_name_length']); // Remove sender from msg
  111. $msg = substr($msg,9); // Remove body headers
  112. $message['body_txt_length'] = ord(substr($msg,0,1));
  113. $msg = substr($msg,1); // Remove Length
  114. $message['body_txt'] = substr($msg,0,$message['body_txt_length']);
  115. $msg = substr($msg,$message['body_txt_length']); // Remove body txt
  116. $msg = substr($msg,9); // Remove XMPP XML and Name XML Headers
  117. $message['time_length'] = ord(substr($msg,0,1));
  118. $msg = substr($msg,1); // Remove Length
  119. $message['time'] = substr($msg,0,$message['time_length']);
  120. $msg = substr($msg,$message['time_length']);
  121. return $message;
  122. }
  123. function parse_account_info($msg){
  124. $msg = substr($msg,3); // Remove Length,F8,second length
  125. $msg = substr($msg,4); // Remove Success XML
  126. // Next should be status
  127. $acst = substr($msg,0,1);
  128. if($acst == "\x09"){
  129. $this->_account_status = 'active';
  130. } else {
  131. $this->_account_status = 'inactive';
  132. }
  133. $msg = substr($msg,2); // Remove status & KIND XML
  134. $actkind = substr($msg,0,1);
  135. if($actkind == "\x37"){
  136. $this->_account_kind = 'free';
  137. } else {
  138. $this->_account_kind = 'paid';
  139. }
  140. $msg = substr($msg,3); // Remove XML
  141. $creation_timstamp_len = ord(substr($msg,0,1)); // Should return 10 for the next few thousdands years
  142. $msg = substr($msg,1); // Remove Length
  143. $this->_account_creation = substr($msg,0,$creation_timstamp_len);
  144. $msg = substr($msg,$creation_timstamp_len); // Remove Timestamp
  145. $msg = substr($msg,2); // Remove Expiration XML
  146. $expr_length = ord(substr($msg,0,1)); // Should also be 10
  147. $msg = substr($msg,1); // Remove Length
  148. $this->_account_expiration = substr($msg,0,$expr_length);
  149. $x['status'] = $this->_account_status;
  150. $x['kind'] = $this->_account_kind;
  151. $x['creation'] = $this->_account_creation;
  152. $x['expiration'] = $this->_account_expiration;
  153. return $x;
  154. }
  155. function parse_last_seen($msg){
  156. $msg = substr($msg,7); // Remove Some XML DATA
  157. $moblen = ord(substr($msg,0,1));
  158. $msg = substr($msg,1); // Remove Length
  159. $lastseen['mobile'] = substr($msg,0,$moblen);
  160. $msg = substr($msg,$moblen);
  161. $msg = substr($msg,16); // Remove Some More XML DATA
  162. $last_seen_len = ord(substr($msg,0,1));
  163. $msg = substr($msg,1); // Remove Length
  164. $lastseen['seconds_ago'] = substr($msg,0,$last_seen_len);
  165. return $lastseen;
  166. }
  167. function status(){
  168. $status = socket_get_status($this->_socket);
  169. print_r($status);
  170. }
  171. function Login()
  172. {
  173. $Data = "WA"."\x01\x00\x00\x19\xf8\x05\x01\xa0\x8a\x84\xfc\x11"."iPhone-2.6.9-5222".
  174. "\x00\x08\xf8\x02\x96\xf8\x01\xf8\x01\x7e\x00\x07\xf8\x05\x0f\x5a\x2a\xbd\xa7";
  175. $this->send($Data);
  176. $Buffer = $this->read();
  177. $Response = base64_decode( substr( $Buffer, 26 ) );
  178. $arrResp = explode( ",", $Response );
  179. $authData = array();
  180. foreach( $arrResp AS $Key => $Value )
  181. {
  182. $resData = explode( "=", $Value );
  183. $authData[ $resData[0] ] = str_replace( '"', '', $resData[1] );
  184. }
  185. $ResData = $this -> _authenticate( $authData['nonce'] );
  186. $Response = "\x01\x31\xf8\x04\x86\xbd\xa7\xfd\x00\x01\x28" . base64_encode( $ResData );
  187. $this->send($Response);
  188. $rBuffer =$this->read();
  189. $this->read();
  190. // this packet contains the name
  191. $next = "\x00\x12\xf8\x05\x74\xa2\xa3\x61\xfc\x0a\x41\x68\x6d\x65\x64\x20\x4d\x6f\x68\x64\x00\x15\xf8\x06\x48\x43\x05\xa2\x3a\xf8\x01\xf8\x04\x7b\xbd\x4d\xf8\x01\xf8\x03\x55\x61\x24\x00\x12\xf8\x08\x48\x43\xfc\x01\x32\xa2\x3a\xa0\x8a\xf8\x01\xf8\x03\x1f\xbd\xb1";
  192. $stream = $this->send($next);
  193. $this->read();
  194. }
  195. public function _authenticate( $nonce,$_NC = '00000001'){
  196. $cnonce = random_uuid();
  197. $a1 = sprintf('%s:%s:%s', $this ->_number, $this ->_server, $this ->_password);
  198. if (true) {
  199. $a1 = pack('H32', md5($a1) ) . ':' . $nonce . ':' . $cnonce;
  200. }
  201. $a2 = "AUTHENTICATE:" . $this->_Digest_Uri;
  202. $password = md5($a1) . ':' . $nonce . ':' . $_NC . ':' . $cnonce . ':' . $this->_Qop . ':' .md5($a2);
  203. $password = md5($password);
  204. $Response = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc=%s,qop=%s,digest-uri="%s",response=%s,charset=utf-8',
  205. $this -> _number, $this->_Realm, $nonce, $cnonce, $_NC, $this->_Qop, $this->_Digest_Uri, $password);
  206. return $Response;
  207. }
  208. public function Message($msgid,$to,$txt){
  209. $long_txt_bool = isShort($txt);
  210. $txt_length = hex2str(_hex(strlen($txt)));
  211. $to_length = chr(mb_strlen($to,"UTF-8"));
  212. $msgid_length = chr(mb_strlen($msgid));
  213. $content = "\xF8\x08\x5D\xA0\xFA\xFC$to_length";
  214. $content .= $to;
  215. $content .= "\x8A\xA2\x1B\x43\xFC$msgid_length";
  216. $content .= $msgid;
  217. $content .= "\xF8\x02\xF8\x04\xBA\xBD\x4F\xF8\x01\xF8\x01\x8C\xF8\x02\x16";
  218. if(!$long_txt_bool){
  219. $content .= "\xFD\x00$txt_length";
  220. } else {
  221. $content .= "\xFC$txt_length";
  222. }
  223. $content .= $txt;
  224. $total_length = hex2str(_hex(strlen($content)));
  225. if(strlen($total_length) == '1'){ $total_length = "\x00$total_length"; }
  226. $msg ="";
  227. $msg .= "$total_length";
  228. $msg .= $content;
  229. //echo str2hex($msg);
  230. $stream = $this->send($msg);
  231. $this->read();
  232. $this->read();
  233. $this->read();
  234. }
  235. public function sendImage($msgid,$to,$path,$size,$link,$b64thumb){
  236. $thumb_length = hex2str(_hex(strlen($b64thumb)));
  237. $to_length = chr(mb_strlen($to,"UTF-8"));
  238. $msgid_length = chr(mb_strlen($msgid));
  239. $path_length = chr(mb_strlen($path));
  240. $size_length = chr(mb_strlen($size)); // in bytes
  241. $link_length = chr((strlen($link)));
  242. $content = "\xF8\x08\x5D\xA0\xFA\xFC$to_length";
  243. $content .= $to;
  244. $content .= "\x8A\xA2\x1B\x43\xFC$msgid_length";
  245. $content .= $msgid;
  246. $content .= "\xF8\x02\xF8\x04\xBA\xBD\x4F\xF8\x01\xF8\x01\x8C\xF8\x0C\x5C\xBD\xB0\xA2\x44\xFC\x04\x66\x69\x6C\x65\xFC$path_length";
  247. $content .= $path;
  248. $content .= "\xFC\x04\x73\x69\x7A\x65\xFC$size_length";
  249. $content .= $size;
  250. $content .= "\xA5\xFC$link_length";
  251. $content .= $link;
  252. $content .= "\xFD\x00$thumb_length";
  253. $content .= $b64thumb;
  254. $total_length = hex2str(_hex(strlen($content)));
  255. $msg ="";
  256. $msg .= "$total_length";
  257. $msg .= $content;
  258. //echo str2hex($msg);
  259. $stream = $this->send($msg);
  260. $this->read();
  261. }
  262. public function Subscribe($mobile){
  263. $mob_len = chr(mb_strlen($mobile,"UTF-8"));
  264. $content = "\xF8\x05\x74\xA2\x98\xA0\xFA\xFC$mob_len";
  265. $content .= "$mobile";
  266. $content .= "\x8A";
  267. $len = strlen($content);
  268. $total_length = chr($len);
  269. $request = "\x00";
  270. $request .= "$total_length";
  271. $request .= $content;
  272. $stream = $this->send($request);
  273. $this->read();
  274. }
  275. public function RequestLastSeen($mobile){
  276. $mob_len = chr(mb_strlen($mobile,"UTF-8"));
  277. $content = "\xF8\x08\x48\x43\xFC\x01\x37\xA2\x3A\xA0\xFA\xFC$mob_len";
  278. $content .= "$mobile";
  279. $content .= "\x8A\xF8\x01\xF8\x03\x7B\xBD\x4C";
  280. $len = strlen($content);
  281. $total_length = chr($len);
  282. $request = "\x00";
  283. $request .= "$total_length";
  284. $request .= $content;
  285. $stream = $this->send($request);
  286. $this->read();
  287. $this->read();
  288. }
  289. public function accountInfo(){
  290. echo json_encode($this->accinfo);
  291. }
  292. }
  293. ?>