Valhalla Legends Forums Archive | Battle.net Bot Development | PHP Bnet Stats Function Source

AuthorMessageTime
LockesRabb
If possible, please make this post a sticky so people requesting PHP bnet info can refer to this post. Muy gracias.

------------------

This PHP function was coded by Donald Cullen, AKA DM-Kyro for the gaming clan based at www.dementedminds.org.

You are free to use this script as you wish, as long as proper due credit is given. But please do not distribute. This code was uploaded to thank the bot development forum @ vL for all of their assistance, not for people to rip off.

------------------

[code]   function getstats($account, $realm, $game){
      ##############################################################
      #
      # Function to obtain and return stats
      #
      # Parameters:   $account is the battle.net alias you're checking
      #       $realm is the server you'll be querying
      #       $game is the game stats you want from
      #
      # Bugs: 2 (non-fixable)
      #
      # Explaination:    Every once in a while, all attempts
      #      to connect to the server will be
      #      refused for unknown reasons for a
      #      certain unknown length of time. Also
      #      frequent rapid connections will
      #      (Included failed ones!) result in the
      #      server the script is hosted on being
      #      ipbanned.
      #
      # Returns:    Stats in one string. If error results,
      #      including bnet errors, it will return
      #      "abort" along with the reason.
      ##############################################################
   
      ##   Configuration phase
   
      $cfgServer = "$realm.battle.net";
      $cfgPort = 6112;
      $cfgTimeOut = 1;
      $cfgUser = "WhateverName";
      $cfgPassword = "WhateverPassword";
      $terminate = FALSE;
      $refusalreason = "";
   
      if($game == "STAR" || $game == "SEXP" || $game == "WAR3" || $game == "W3XP"){
         $loopx = 3;
      } else if($game == "W2BN"){
         $loopx = 4;
      } else {
         $terminate = true;
         $refusalreason = "Unknown $game abbreviation.";
      }
   
      ##   Parameter verification phase
   
      if(!$account || !$realm || !$game){
         $terminate = true;
         $refusalreason = "Missing information.";
      }
   
      ##   Connection phase
   
      if(!$terminate){
          $usenet_handle = fsockopen("tcp://".$cfgServer, $cfgPort, $errno, $errstr, $cfgTimeOut);

         if(!$usenet_handle) {
            $terminate = true;
            $refusalreason = "Connection Failed.";
         }
      }
   
      ##   Login phase
   
      if(!$terminate){
         $constring = chr(3).chr(4);
         $enter = chr(10).chr(13);
         fputs($usenet_handle, $constring);
         if(!$cfgUser){
            fputs($usenet_handle, "anonymous".$enter);
         } else {
            fputs($usenet_handle, $cfgUser.$enter);
             fputs($usenet_handle, $cfgPassword.$enter);
         }
   
         $skip = 0;
         $abort = FALSE;
         $sd = 0;
         while($skipa != 4 && !$abort){
            if(false === ($info = fgets($usenet_handle))){
               $terminate = true;
               $refusalreason = "Socket read failed! Reason: ".socket_strerror($ret);
               $abort = true;
            }
            $refuse = strpos($info, "refused");
            if($refuse){
               $terminate = true;
               $refusalreason = "Connection was refused.";
               $abort = true;
            }
            $badlogin = strpos($info, "Login Incorrect");
            if($badlogin){
               $terminate = true;
               $refusalreason = "Invalid login.";
               $abort = true;
            }
            $tmp = substr($info, 0, 4);
            $tmp = "a$tmp";
            $res = strpos($info, "1018");
            if(strpos($tmp, "1018")){
               $skipa++;
            }
            $sd++;
            if ($sd == 40){
               $abort = TRUE;
            }
         }
      }
   
      ##   Stats Phase
   
      if(!$terminate){
         fputs($usenet_handle, "/stats ".$account." ".$game.$enter);
         $skipa = 0;
         $abort = FALSE;
         $sd = 0;
         while($skipa != $loopx && !$abort){
            $info = fgets($usenet_handle);
            $tmp = substr($info, 0, 4);
            $tmp = "a$tmp";
            if(strpos($tmp, "1018")){
               $bneterrchk = substr($info, 0, 18);
               if($bneterrchk == "1018 INFO \"INVALID"){
                  $temp = ltrim(rtrim(substr($info, 11)));
                  $temp = substr($temp, 0, strlen($temp) - 1);
                  $terminate = TRUE;
                  $refusalreason = "BNET: Account mismatch! ".$temp;
                  $abort = TRUE;
               } else {
                  $skipa++;
                  $temp = ltrim(rtrim(substr($info, 11)));
                  $temp = substr($temp, 0, strlen($temp) - 1);
                  $retu = $retu." | ".$temp;
               }
            }
            if(strpos($tmp, "1019")){
               $temp = ltrim(rtrim(substr($info, 12)));
               $temp = substr($temp, 0, strlen($temp) - 1);
               $terminate = TRUE;
               $refusalreason = "BNET: ".$temp;
               $abort = TRUE;
            }
            $sd++;
            if ($sd == 7){
               $terminate = TRUE;
               $refusalreason = "Timed out.";
            }
         }
      }
   
      ##   Finalization Phase and Error handling
   
      if($usenet_handle != ""){
         fclose($usenet_handle);
      }
      if(!$terminate){
         return $retu;
      } else {
         $error = "abort ".$refusalreason;
         return $error;
      }
   }[/code]

Information on the function, as well as which part does what has already been explained inside the function. What the script basically does is open a php socket, connects to battle.net, logs in (if you're not anonymous), obtains stats info, then disconnects from battle.net. Reason for disconnection is because PHP is once-run based language- everything has to be done in one run- so if you don't close a socket at the end of the script, then any further attempts to connect to bnet will be refused since the first one is still open. Hence why the script disconnects at the end. It's mainly for re-usability.

Comments, criticism, questions, suggestions, are all welcome. Flames however are not. :P
May 28, 2004, 8:17 PM
AC_Drkan
Not complaining but....

For some reason that script will not run. Its weird because it looks like it will connect but when i ran it i had it whisper to me when it was being used in addition to the /stats call.

i never got anything
June 2, 2004, 8:50 PM
Myndfyr
One suggestion -- and I'm not really certain about the scope and function of PHP sockets or anything, but more of a general design decision.

Say you have a members page for a clan, and want to look up the stats for 20 people at a time.

The way I would structure this is:

1.) Open a socket to Battle.net
2.) Log in
3.) Request stats for user 1
4.) Request stats for user 2
... etc.
23.) Close the socket.

It seems like what you're doing is making one connection per request, which is sub-optimal. I didn't look at your code, so I could be incorrect -- it just seemed like that's how you described it.

Anyway, cheers.
June 2, 2004, 11:15 PM
LockesRabb
mindfyre- yeah, way my site uses it, it looks up stats of an user upon request. *a* being the keyword (or letter? :P) here. i didnt design it in mind for multiple stats checking operations. but if i ever adapt it to be able to handle multiple users, yeah that's probably the way it should be done. thanks.

AC_Drkan- as for the code not working- did you attempt to debug it? because it works perfectly for me. suggestion, put in debugging code (ie, echoing where the script is as it goes thru code, also echoing var's contents, etc). Or maybe the script is aborting due to an error and you're not checking for the string "abort" since it returns that along with the reason why the script aborted (in other words, you should put in an error handler to trap abort events simply by checking to see if the first five letters of the string is abort and if so react based on that. if the script is indeed aborting, it most likely is aborting before it even starts the bnet rountines, so if thats the case, then the place to check would be near the start of the function before and during the login of bnet (not after since it is obviously aborting before it carries out commands).

[edited for clarity]
June 3, 2004, 12:08 AM

Search