Xat Bot


SUBMITTED BY: BobbyBG

DATE: May 11, 2017, 8:42 a.m.

FORMAT: PHP

SIZE: 21.6 kB

HITS: 681

  1. <?php
  2. /**
  3. * @author BobbyBG
  4. * @copyright 2015
  5. *
  6. * This is just a basic version of my Xat Bot you can build upon to add the feature you want.
  7. *
  8. */
  9. set_time_limit(0);//No time out
  10. $bot = new BasicXatBot();
  11. $roomID = 88973610;//Don't know how to get this ID? goto xat.com/ROOM_YOU_WANT_BOT_IN and View Source(Firefox: Ctrl+U, Internet Explorer: View>Source) Look for "flashvars="id=#########&..." the ID is the number you want
  12. $bot->connect("174.36.242.26","10024"); //Connect to XAT...this IP will change as necessary automatically depending on the room you want to join.
  13. $bot->join($roomID);
  14. while(true){
  15. if($bot->read()=='DIED') {
  16. $bot->connect("174.36.242.26","10024");
  17. $bot->join($roomID);
  18. }
  19. }
  20. class BasicXatBot {
  21. private $soc; //Socket for bot
  22. private $debug = false; //Used to toggle debugging output.
  23. private $packet; //Stores information about the last recieved packet of each kind
  24. private $userInfo; //Stores User information
  25. //If you don't know where to get these you should probably not be trying to make your own bot.
  26. //Go download WPE Pro and check out the packets XAT sends and learn about how XAT works.
  27. //The UserID and K Value are the source or the 'old falsh' error(if you get it) make sure you get these values from a REGISTERED account
  28. private $userID = "351599155"; //The Bot's UserID
  29. private $k = "3607438505"; //The Bot's K value
  30. //Bot Account Settings
  31. private $name = "XBot"; //The display name the bot will use
  32. private $avatar = -1; //The Avatar value for the bot, this can be an id number or an image url.
  33. private $homepage = ""; //The bot's homepage link.
  34. private $roomID; //This gets set in code, don't touch it here. just used ->join(ID)
  35. /**
  36. * This is where everything the bot does needs to happen, this is the only default function you should need to edit
  37. * @param $event The event that just occured(and thus needs to be handled)
  38. * @param $data Any data relating to this event.
  39. */
  40. function handleEvent($event,$data) {
  41. $info = $this->getUserArray($data['id']);
  42. switch($event) {
  43. case 'userJoined':
  44. /* $data['id'] Has the ID of the user who just joined
  45. $data['old'] Sometimes XAT sends packets that are not current(for example when you join a room, old ==true for all users who are already in the room when you join, but still this event is handled as thought they just joined */
  46. //Do whever you want with users joining here...
  47. echo ((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) has just joined.\n";
  48. break;
  49. case 'userLeft':
  50. /* $data['id'] The ID of the user that just left. */
  51. echo ((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) has just left.\n";
  52. break;
  53. case 'privateMessage':
  54. /* $data['id'] The ID of the user that just left.
  55. $data['message'] The message sent to you as a PM */
  56. echo "[PM] ".((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) -> $data[message]\n";
  57. //Example of a private message command
  58. $command = explode(' ',$data['message'],2); //First parse the first word out see if it is a command...
  59. //[0] has first word [1] has everything else
  60. if($command[0]{0}=='!'){//I am use ! as the character to signify a command, so check if the first character is right.
  61. switch($command[0]) {
  62. case '!say':
  63. case '!speak':
  64. case '!talk':
  65. $this->sendPrivateMessage($command[1],$data['id']);
  66. break;
  67. case '!info':
  68. $this->sendPrivateMessage('I am a bot ^_^',$data['id']);
  69. break;
  70. }
  71. }
  72. break;
  73. case 'privateChat':
  74. /* $data['id'] The ID of the user that just left.
  75. $data['message'] The message sent to you as a PC */
  76. echo "[PC] ".((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) -> $data[message]\n";
  77. //Example of a private chat command
  78. $command = explode(' ',$data['message'],2); //First parse the first word out see if it is a command...
  79. //[0] has first word [1] has everything else
  80. if($command[0]{0}=='!'){//I am use ! as the character to signify a command, so check if the first character is right.
  81. switch($command[0]) {
  82. case '!info':
  83. $this->sendPrivateChat('I am a bot ^_^',$data['id']);
  84. break;
  85. }
  86. }
  87. break;
  88. case 'message':
  89. /* $data['id'] The ID of the user
  90. $data['old'] See $data['old'] under userJoined
  91. $data['message'] The message sent to main chat */
  92. echo ((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])."($info[rank]) -> $data[message]\n";
  93. //How to do main chat commands:
  94. if($data['old']) return; //Old message
  95. $command = explode(' ',trim($data['message']),2); //First parse the first word out see if it is a command...
  96. //[0] has first word [1] has everything else
  97. if($command[0]{0}=='!'){//I am use ! as the character to signify a command, so check if the first character is right.
  98. switch($command[0]) {
  99. case '!say':
  100. case '!speak':
  101. case '!talk':
  102. //Multiple cases lead to the same code being run...
  103. $this->sendMessage($command[1]);
  104. break;
  105. case '!slap':
  106. case '!slaps':
  107. case '!hit':
  108. $this->sendMessage(((trim($info['registeredName'])!='')?$info['registeredName']:$info['name'])." slaps $command[1] around a bit with a large trout.");
  109. break;
  110. case '!avatar'://steal an avatar via !avatar USER_ID
  111. $user = $this->getUserArray($command[1]);
  112. $this->sendMessage(str_replace('(','( ',$user['avatar']));
  113. break;
  114. case '!info':
  115. $this->sendMessage('I am a bot ^_^',$data['id']);
  116. break;
  117. case '!yt':
  118. case '!youtube':
  119. case '!y':
  120. if(trim($command[1])=='') $this->sendMessage("Usage: $command[0] SEARCH TERMS HERE");
  121. else {
  122. //Yeah I know I don't really need urlencode() i could just replace spaces with + but this is a bit more secure.
  123. $res = $this->get('http://www.youtube.com/results?search_query='.urlencode(preg_replace("/[^A-Za-z0-9 !.,:[]\s\s+]/",'',$command[1])));
  124. for($i=0;$i<3;$i++) {
  125. $msg=$this->getBetween($res, '<h3>', '</h3>');
  126. $res = str_replace('<h3>'.$msg,'</h3>',$res);
  127. $url = "http://www.youtube.com".$this->getBetween($msg,'href="', '"');
  128. $title = @ereg_replace('[^A-Za-z0-9 -()[]<>{}&@]','',$this->getBetween($msg,'title="', '"'));
  129. $this->sendMessage($title." - $url");
  130. sleep(1);//Xat won't let us send more than 1 message per second, it ignores anything faster.
  131. }
  132. }
  133. break;
  134. case '!g':
  135. case '!google':
  136. $res = $this->get('http://www.google.com/search?hl=en&source=hp&biw=&bih=&q='.str_replace(' ','+',$command[1]).'&btnG=Google+Search',true);
  137. for($i=0;$i<3;$i++) {
  138. $msg=$this->getBetween($res, '<h3 class="r"><a href="', '"');
  139. $res = str_replace('<h3 class="r"><a href="'.$msg,'',$res);
  140. $this->sendMessage($msg);
  141. sleep(1);
  142. }
  143. }
  144. }
  145. break;
  146. }
  147. }
  148. /* ****************************************************** */
  149. /* *YOU SHOULD NOT NEED TO EDIT ANYTHING AFTER THIS LINE* */
  150. /* ****************************************************** */
  151. /**
  152. * Connects to a given ip on the given port
  153. * @param $ip The IP to connect to.
  154. * @param $port The port on the IP to connect to.
  155. */
  156. function connect($ip, $port) {
  157. if($this->soc!=null) socket_close($this->soc);
  158. $this->soc = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
  159. if(!$this->soc) die(socket_strerror(socket_last_error($this->soc)));
  160. if(!socket_connect($this->soc,$ip,$port)) die("Could not connect.");
  161. }
  162. /**
  163. * Writes the given message to the object socket($this->soc)
  164. * @param $message The packet to send.
  165. */
  166. function send($message) {
  167. if($this->debug)echo "->>\t$message\n";
  168. socket_write($this->soc, $message."\0", strlen($message)+1);
  169. }
  170. /**
  171. * Reads a message from the socket, will read until entire message has been recieved or connection closes.
  172. * @param $parse Used for recursive calls to tell the function not to parse a partial packet
  173. */
  174. function read($parse=true) {
  175. $res = rtrim(socket_read($this->soc, 4096));
  176. if($this->debug)echo "<<-\t$res\n";
  177. if(!$res) {
  178. return "DIED"; //Used to gracefully handle a closed socket
  179. }
  180. if($res{strlen($res)-1}!='>') { $res.=$this->read(false);} //Recursive call for messages split over several packets.
  181. if($parse)$this->parse($res);
  182. return $res;
  183. }
  184. /**
  185. * Parses the recieved packets into their message and types.
  186. * @param $packet The packet recieved.
  187. */
  188. function parse($packet) {
  189. if(substr_count($packet,'>')>1) $packet = explode('/>',$packet);//If necessary split the packet into individual messages
  190. foreach((Array)$packet as $p) {
  191. $p = trim($p);
  192. if(strlen($p)<5) return;//garbage data
  193. $type = trim(strtolower(substr($p,1,strpos($p.' ',' '))));//packet type
  194. $p = trim(str_replace("<$type",'',str_replace('/>','',$p)));//remove details so it is just the info to be parsed
  195. parse_str(str_replace('"','',str_replace('" ','&',str_replace('="','=',str_replace('&','__38',$p)))),$this->packet[$type]);
  196. foreach($this->packet[$type] as $k=>$v) {
  197. $this->packet[$type][$k] = str_replace('__38','&',$v); //htmlspecial chars are protected instead of being parsed
  198. }
  199. $this->handle($type,$p);
  200. }
  201. }
  202. /**
  203. * This is the inital handler for the packets, parses them and sends them off to their respective function to be handled further.
  204. * @param $type The character code indicating the type of data within the message.
  205. * @param $message The data the message contains.
  206. */
  207. function handle($type,$msg) {
  208. switch($type) {
  209. case 'gp':
  210. if(isset($this->packet['gp']['x']))
  211. $this->send('<x i="'.$this->packet['gp']['x'].'" u="'.$this->userID.'" t="j" />'); //Handle groups
  212. break;
  213. case 'q'://XAT notice to change ip/port
  214. $this->connect($this->packet['q']['d'], $this->packet['q']['p']);
  215. $this->join($this->roomID);
  216. break;
  217. case 'o':
  218. $this->packet['o']['u'] = $this->parseU(@$this->packet['u']['u']);
  219. $this->userInfo[$this->packet['o']['u']]['name'] = @$this->packet['o']['n'];
  220. $this->userInfo[$this->packet['o']['u']]['registeredName'] = ((isset($this->packet['o']['N']))?$this->packet['o']['N']:'');
  221. $this->userInfo[$this->packet['o']['u']]['avatar'] = @$this->packet['o']['a'];
  222. $this->userInfo[$this->packet['o']['u']]['homepage'] = @$this->packet['o']['h'];
  223. $this->userInfo[$this->packet['o']['u']]['rank'] = $this->f2rank(@$this->packet['o']['f']);
  224. break;
  225. case 'u':
  226. //Joined
  227. //Default Bot stuff regarding userInformation
  228. $this->packet['u']['u'] = $this->parseU(@$this->packet['u']['u']);
  229. $this->userInfo[$this->packet['u']['u']]['name'] = @$this->packet['u']['n'];
  230. $this->userInfo[$this->packet['u']['u']]['registeredName'] = ((isset($this->packet['u']['N']))?$this->packet['u']['N']:'');
  231. $this->userInfo[$this->packet['u']['u']]['avatar'] = @$this->packet['u']['a'];
  232. $this->userInfo[$this->packet['u']['u']]['homepage'] = @$this->packet['u']['h'];
  233. $this->userInfo[$this->packet['u']['u']]['rank'] = $this->f2rank(@$this->packet['u']['f']);
  234. $event = 'userJoined';
  235. $data['id'] = $this->packet['u']['u'];
  236. $data['old'] = ($type=='o'||(isset($this->packet['u']['s']))?true:false);
  237. $this->handleEvent($event,$data);
  238. break;
  239. case 'l':
  240. //User Left or was kicked, banned
  241. unset($this->userInfo[$this->packet['l']['u']]);
  242. $event = 'userLeft';
  243. $data['id'] = $this->packet['l']['u'];
  244. $this->handleEvent($event,$data);
  245. break;
  246. case 'p':
  247. //Private message/chat recieved
  248. $event = ((isset($this->packet['p']['d']))?'privateChat':'privateMessage');
  249. $data['id'] = $this->parseU(@$this->packet['p']['u']);
  250. $data['message'] = $this->packet['p']['t'];
  251. $this->handleEvent($event,$data);
  252. break;
  253. case 'm':
  254. //message to main chat.
  255. $event = 'message';
  256. $data['id'] = $this->parseU(@$this->packet['m']['u']);
  257. $data['message'] = $this->packet['m']['t'];
  258. $data['old'] = ((isset($this->packet['m']['s']))?true:false);
  259. $this->handleEvent($event,$data);
  260. break;
  261. }
  262. }
  263. /**
  264. * Joins a room.
  265. * @param $roomID the numeric roomID to join.
  266. */
  267. function join($roomID) {
  268. //Announce we are here:
  269. $this->send('<y m="1" />');//Anounces our arrival to the server and gets some information to send back
  270. $this->read(); //Auto parsed into $this->packet['y']
  271. $this->send('<j2 q="1" y="'.$this->packet['y']['i'].'" k="'.$this->k.'" k3="0" z="12" p="0" c="'.$roomID.'" f="0" u="'.$this->userID.'" d0="0" n="'.$this->name.'" a="'.$this->avatar.'" h="'.$this->homepage.'" v="0" />');
  272. $this->roomID = $roomID;
  273. }
  274. /**
  275. * Parses the u value from a packet to get just the id
  276. * @param $id the id to be parsed.
  277. */
  278. function parseU($id) {
  279. if(substr_count($id,'_')>=1) $id = substr($id,0,strpos($id,'_'));
  280. return $id;
  281. }
  282. /**
  283. * Converts an f value to a string containing the corresponding rank...this if you don't understand bitwise operations is a little 'magical' deal with it.
  284. * @param $f The f value to be parsed.
  285. */
  286. function f2rank($f) {
  287. $f = $this->parseU($f);
  288. if($f==-1) return 'guest';
  289. //Okay, 98% of you reading this on NewHax won't know what any of this means; if you do you are more adnvanced than I expected
  290. //Not that this is advnaced stuff, but basiclly it is a bit-wise comparision(notice & instead of && it is checking if certain binary bits are set to 1
  291. //The F value is essientially a bunch of flags where for example 00010000 == banned(the 0s can be 0 or 1, just as long as that one 1 is a one you are banned.
  292. if((16 & $f)) return 'banned';
  293. if((1 & $f)&&(2 & $f)) return 'member';
  294. if((4 & $f)) return 'owner';
  295. if((32 & $f)&&(1 & $f)&&!(2 & $f)) return 'main';
  296. if(!(1 & $f)&&!(2 & $f)) return 'guest';
  297. if((16 & $f)) return 'banned';
  298. if((2 & $f)&&!(1 & $f)) return 'mod';
  299. }
  300. /**
  301. * Returns an assoc array of information regarding the user with the given id
  302. * @param $id The user id you want information on.
  303. */
  304. function getUserArray($id) {
  305. $id = $this->parseU($id);
  306. if(isset($this->userInfo[$id])) {
  307. return $this->userInfo[$id];
  308. } else return false;
  309. }
  310. /**
  311. * Sends the given message to the main chat
  312. * @param $message
  313. */
  314. function sendMessage($message) {
  315. if(empty($message))return;
  316. $this->send('<m t="'.$message.'" u="'.$this->userID.'" />');
  317. }
  318. /**
  319. * Sends a PC to the given ID
  320. * @param $message The message to send.
  321. * @param $id The id to send the message to
  322. */
  323. function sendPrivateChat($message, $id) {
  324. if(empty($message))return;
  325. $this->send('<p u="'.$id.'" t="'.$message.'" s="2" d="'.$this->userID.'" />');
  326. }
  327. /**
  328. * Sends a PM to the given ID
  329. * @param $message The message to send.
  330. * @param $id The id to send the message to
  331. */
  332. function sendPrivateMessage($message,$id) {
  333. $id = $this->parseU($id);
  334. if(empty($message))return;
  335. $this->send('<p u="'.$id.'" t="'.$message.'" />');
  336. }
  337. /**
  338. * Makes the given $id an owner, assuming the bot is main
  339. * @param $id The id to promote
  340. */
  341. function mod($id) {
  342. $this->send('<c u="'.$this->parseU($id).'" t="/M" />');
  343. }
  344. /**
  345. * Makes the given $id a mod, assuming the bot is owner
  346. * @param $id The id to promote
  347. */
  348. function owner($id) {
  349. $this->send('<c u="'.$this->parseU($id).'" t="/m" />');
  350. }
  351. /**
  352. * Makes the given $id a member, assuming the bot is mod
  353. * @param $id The id to member
  354. */
  355. function member($id) {
  356. $this->send('<c u="'.$this->parseU($id).'" t="/e" />');
  357. }
  358. /**
  359. * KIcks the given ID assuming the bot is a mod and $id is a member or less
  360. * @param $id The id to kick
  361. */
  362. function kick($message, $id) {
  363. $this->send('<c p="'.$message.'" u="'.$this->parseU($id).'" t="/k" />');
  364. }
  365. /**
  366. * Bans the ID for a given time(0 is forever)
  367. * @param $id The id to ban
  368. */
  369. function ban($message, $id, $time) {
  370. if(empty($time)) $time = 3600;
  371. $this->send('<c p="'.$message.'" u="'.$this->parseU($id).'" t="/g'.$time.'" />');
  372. }
  373. /**
  374. * Unbans the given ID
  375. * @param $id The id to unban
  376. */
  377. function unban($id) {
  378. $this->send('<c u="'.$this->parseU($id).'" t="/u" />');
  379. }
  380. /**
  381. * Performs a basic HTTP GET to the given URL
  382. * @param $url The url to retrieve, please include http:// and www if necessary
  383. * @param $includeHeader Tells teh function wether or not to include the server header respond before the main content
  384. */
  385. function get($url, $includeHeader=false) {
  386. $urlp = parse_url($url);
  387. $fp = fsockopen($urlp['host'],80);
  388. $path = explode('/',$url,4);
  389. $path = ((count($path)>=4)?$path[3]:"");
  390. $req = "GET /$path HTTP/1.1\r\n";
  391. $req .= "Host: $urlp[host]\r\n";
  392. $req .= "Connection: Close\r\n\r\n";
  393. fputs($fp, $req);
  394. $res = "";
  395. while(!feof($fp)) $res .= fgets($fp, 4096);
  396. fclose($fp);
  397. if($includeHeader) return $res;
  398. $res = explode("\r\n\r\n",$res,2);
  399. return $res[1];
  400. }
  401. /**
  402. * A utility function to get all text beween $start and $end
  403. * @param $content The content from which we are grabbing data
  404. * @param $start where to start grabbing from
  405. * @param $end the end of the content to grab
  406. */
  407. function getBetween($content,$start,$end){
  408. $r = explode($start, $content);
  409. if (isset($r[1])){
  410. $r = explode($end, $r[1]);
  411. return $r[0];
  412. }
  413. return '';
  414. }
  415. }
  416. ?>

comments powered by Disqus