PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/utils/whatsapi/whatsprot.class.php

https://github.com/ziadmohd/Wassapp-PHP
PHP | 338 lines | 319 code | 19 blank | 0 comment | 3 complexity | a0c18314996b0ddf6708cc84855ba2ef MD5 | raw file
  1. <?php
  2. require "protocol.class.php";
  3. require "func.php";
  4. class WhatsProt
  5. {
  6. protected $_phoneNumber;
  7. protected $_imei;
  8. protected $_name;
  9. protected $_whatsAppHost = "bin-short.whatsapp.net";
  10. protected $_whatsAppServer = "s.whatsapp.net";
  11. protected $_whatsAppGroupServer = "g.us";
  12. protected $_whatsAppRealm = "s.whatsapp.net";
  13. protected $_whatsAppDigest = "xmpp/s.whatsapp.net";
  14. protected $_device = "iPhone";
  15. protected $_whatsAppVer = "2.8.2";
  16. protected $_port = 5222;
  17. protected $_timeout = array("sec" => 2, "usec" => 0);
  18. protected $_incomplete_message = "";
  19. protected $_disconnectedStatus = "disconnected";
  20. protected $_connectedStatus = "connected";
  21. protected $_loginStatus;
  22. protected $_accountinfo;
  23. protected $_messageQueue = array();
  24. protected $_socket;
  25. protected $_writer;
  26. protected $_reader;
  27. protected $_debug;
  28. function __construct($Number, $imei, $Nickname, $debug = false)
  29. {
  30. $this->_debug = $debug;
  31. $dict = getDictionary();
  32. $this->_writer = new BinTreeNodeWriter($dict);
  33. $this->_reader = new BinTreeNodeReader($dict);
  34. $this->_phoneNumber = $Number;
  35. $this->_imei = $imei;
  36. $this->_name = $Nickname;
  37. $this->_loginStatus = $this->_disconnectedStatus;
  38. }
  39. protected function addFeatures()
  40. {
  41. $child = new ProtocolNode("receipt_acks", NULL, NULL, "");
  42. $parent = new ProtocolNode("stream:features", NULL, array($child), "");
  43. return $parent;
  44. }
  45. protected function addAuth()
  46. {
  47. $authHash = array();
  48. $authHash["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl";
  49. $authHash["mechanism"] = "DIGEST-MD5-1";
  50. $node = new ProtocolNode("auth", $authHash, NULL, "");
  51. return $node;
  52. }
  53. public function encryptPassword()
  54. {
  55. if(stripos($this->_imei, ":") !== false){
  56. $this->_imei = strtoupper($this->_imei);
  57. return md5($this->_imei.$this->_imei);
  58. }
  59. else {
  60. return md5(strrev($this->_imei));
  61. }
  62. }
  63. protected function authenticate($nonce)
  64. {
  65. $NC = "00000001";
  66. $qop = "auth";
  67. $cnonce = random_uuid();
  68. $data1 = $this->_phoneNumber;
  69. $data1 .= ":";
  70. $data1 .= $this->_whatsAppServer;
  71. $data1 .= ":";
  72. $data1 .= $this->EncryptPassword();
  73. $data2 = pack('H32', md5($data1));
  74. $data2 .= ":";
  75. $data2 .= $nonce;
  76. $data2 .= ":";
  77. $data2 .= $cnonce;
  78. $data3 = "AUTHENTICATE:";
  79. $data3 .= $this->_whatsAppDigest;
  80. $data4 = md5($data2);
  81. $data4 .= ":";
  82. $data4 .= $nonce;
  83. $data4 .= ":";
  84. $data4 .= $NC;
  85. $data4 .= ":";
  86. $data4 .= $cnonce;
  87. $data4 .= ":";
  88. $data4 .= $qop;
  89. $data4 .= ":";
  90. $data4 .= md5($data3);
  91. $data5 = md5($data4);
  92. $response = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc=%s,qop=%s,digest-uri="%s",response=%s,charset=utf-8',
  93. $this->_phoneNumber,
  94. $this->_whatsAppRealm,
  95. $nonce,
  96. $cnonce,
  97. $NC,
  98. $qop,
  99. $this->_whatsAppDigest,
  100. $data5);
  101. return $response;
  102. }
  103. protected function addAuthResponse()
  104. {
  105. $resp = $this->authenticate($this->challengeArray["nonce"]);
  106. $respHash = array();
  107. $respHash["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl";
  108. $node = new ProtocolNode("response", $respHash, NULL, base64_encode($resp));
  109. return $node;
  110. }
  111. protected function sendData($data)
  112. {
  113. socket_send( $this->_socket, $data, strlen($data), 0 );
  114. }
  115. protected function sendNode($node)
  116. {
  117. $this->DebugPrint($node->NodeString("tx ") . "\n");
  118. $this->sendData($this->_writer->write($node));
  119. }
  120. protected function readData()
  121. {
  122. $buff = "";
  123. $ret = socket_read( $this->_socket, 1024 );
  124. if ($ret)
  125. {
  126. $buff = $this->_incomplete_message . $ret;
  127. $this->_incomplete_message = "";
  128. }
  129. return $buff;
  130. }
  131. protected function processChallenge($node)
  132. {
  133. $challenge = base64_decode($node->_data);
  134. $challengeStrs = explode(",", $challenge);
  135. $this->challengeArray = array();
  136. foreach ($challengeStrs as $c)
  137. {
  138. $d = explode("=", $c);
  139. $this->challengeArray[$d[0]] = str_replace("\"", "", $d[1]);
  140. }
  141. }
  142. protected function sendMessageReceived($msg)
  143. {
  144. $requestNode = $msg->getChild("request");
  145. if ($requestNode != null)
  146. {
  147. $xmlnsAttrib = $requestNode->getAttribute("xmlns");
  148. if (strcmp($xmlnsAttrib, "urn:xmpp:receipts") == 0)
  149. {
  150. $recievedHash = array();
  151. $recievedHash["xmlns"] = "urn:xmpp:receipts";
  152. $receivedNode = new ProtocolNode("received", $recievedHash, null, "");
  153. $messageHash = array();
  154. $messageHash["to"] = $msg->getAttribute("from");
  155. $messageHash["type"] = "chat";
  156. $messageHash["id"] = $msg->getAttribute("id");
  157. $messageNode = new ProtocolNode("message", $messageHash, array($receivedNode), "");
  158. $this->sendNode($messageNode);
  159. }
  160. }
  161. }
  162. protected function processInboundData($data)
  163. {
  164. try
  165. {
  166. $node = $this->_reader->nextTree($data);
  167. while ($node != null)
  168. {
  169. $this->DebugPrint($node->NodeString("rx ") . "\n");
  170. if (strcmp($node->_tag, "challenge") == 0)
  171. {
  172. $this->processChallenge($node);
  173. }
  174. else if (strcmp($node->_tag, "success") == 0)
  175. {
  176. $this->_loginStatus = $this->_connectedStatus;
  177. $this->_accountinfo = array('status'=>$node->getAttribute('status'),'kind'=>$node->getAttribute('kind'),'creation'=>$node->getAttribute('creation'),'expiration'=>$node->getAttribute('expiration'));
  178. }
  179. if (strcmp($node->_tag, "message") == 0)
  180. {
  181. array_push($this->_messageQueue, $node);
  182. $this->sendMessageReceived($node);
  183. }
  184. if (strcmp($node->_tag, "iq") == 0 AND strcmp($node->_attributeHash['type'], "get") == 0 AND strcmp($node->_children[0]->_tag, "ping") == 0)
  185. {
  186. $this->Pong($node->_attributeHash['id']);
  187. }
  188. $node = $this->_reader->nextTree();
  189. }
  190. }
  191. catch (IncompleteMessageException $e)
  192. {
  193. $this->_incomplete_message = $e->getInput();
  194. }
  195. }
  196. public function accountInfo(){
  197. if(is_array($this->_accountinfo)){
  198. print_r($this->_accountinfo);
  199. }
  200. else{
  201. echo "No information available";
  202. }
  203. }
  204. public function Connect(){
  205. $Socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
  206. socket_connect( $Socket, $this->_whatsAppHost, $this->_port );
  207. $this->_socket = $Socket;
  208. socket_set_option($this->_socket, SOL_SOCKET, SO_RCVTIMEO, $this->_timeout);
  209. }
  210. public function Login()
  211. {
  212. $resource = "$this->_device-$this->_whatsAppVer-$this->_port";
  213. $data = $this->_writer->StartStream($this->_whatsAppServer, $resource);
  214. $feat = $this->addFeatures();
  215. $auth = $this->addAuth();
  216. $this->sendData($data);
  217. $this->sendNode($feat);
  218. $this->sendNode($auth);
  219. $this->processInboundData($this->readData());
  220. $data = $this->addAuthResponse();
  221. $this->sendNode($data);
  222. $cnt = 0;
  223. do
  224. {
  225. $this->processInboundData($this->readData());
  226. } while (($cnt++ < 100) && (strcmp($this->_loginStatus, $this->_disconnectedStatus) == 0));
  227. }
  228. # Pull from the socket, and place incoming messages in the message queue
  229. public function PollMessages()
  230. {
  231. $this->processInboundData($this->readData());
  232. }
  233. # Drain the message queue for application processing
  234. public function GetMessages()
  235. {
  236. $ret = $this->_messageQueue;
  237. $this->_messageQueue = array();
  238. return $ret;
  239. }
  240. protected function SendMessageNode($msgid, $to, $node)
  241. {
  242. $serverNode = new ProtocolNode("server", null, null, "");
  243. $xHash = array();
  244. $xHash["xmlns"] = "jabber:x:event";
  245. $xNode = new ProtocolNode("x", $xHash, array($serverNode), "");
  246. $messageHash = array();
  247. if (!strpos($to,'-')) {
  248. $messageHash["to"] = $to . "@" . $this->_whatsAppServer;
  249. }
  250. else {
  251. $messageHash["to"] = $to . "@" . $this->_whatsAppGroupServer;
  252. }
  253. $messageHash["type"] = "chat";
  254. $messageHash["id"] = $msgid;
  255. $messsageNode = new ProtocolNode("message", $messageHash, array($xNode, $node), "");
  256. $this->sendNode($messsageNode);
  257. }
  258. public function Message($msgid, $to, $txt)
  259. {
  260. $bodyNode = new ProtocolNode("body", null, null, $txt);
  261. $this->SendMessageNode($msgid, $to, $bodyNode);
  262. }
  263. public function MessageImage($msgid, $to, $url, $file, $size, $icon)
  264. {
  265. $mediaAttribs = array();
  266. $mediaAttribs["xmlns"] = "urn:xmpp:whatsapp:mms";
  267. $mediaAttribs["type"] = "image";
  268. $mediaAttribs["url"] = $url;
  269. $mediaAttribs["file"] = $file;
  270. $mediaAttribs["size"] = $size;
  271. $mediaNode = new ProtocolNode("media", $mediaAttribs, null, $icon);
  272. $this->SendMessageNode($msgid, $to, $mediaNode);
  273. }
  274. public function Pong($msgid)
  275. {
  276. $whatsAppServer = $this->_whatsAppServer;
  277. $messageHash = array();
  278. $messageHash["to"] = $whatsAppServer;
  279. $messageHash["id"] = $msgid;
  280. $messageHash["type"] = "result";
  281. $messsageNode = new ProtocolNode("iq", $messageHash, null, "");
  282. $this->sendNode($messsageNode);
  283. }
  284. protected function DebugPrint($debugMsg)
  285. {
  286. if ($this->_debug)
  287. {
  288. print($debugMsg);
  289. }
  290. }
  291. /**
  292. * TODO
  293. */
  294. public function RequestLastSeen($var){
  295. return null;
  296. }
  297. }
  298. ?>