ShoeLace1291 Posted October 10, 2010 Share Posted October 10, 2010 I found a independently created PHP class for the Steam Community API. I tried using it on my installation of Xampp and got the following error: A non-blocking socket operation could not be completed immediately. I proceeded to try uploading it to a web server and it worked fine. This is the code of the API class: <?php //==================================================================================== // PHP STEAM API CLASS //==================================================================================== // Author: |LBTG|Regime (regime@livebythegun.com) // Version: 0.1 // Date: 07/06/2009 //==================================================================================== // Notes: This is a class that allows you to easily query the Steam community // API from PHP. It is required that your PHP installation/configuration allows for // the use of sockets. If it doesn't you could ask your hosting provider to enable // them for you, or alternatively feel free to re-write this class to use something // like cURL. // An example on how to use this class has been provided with this package. There // should not be any need to edit anything in this file. //==================================================================================== // Thanks: Many thanks to Valve for providing us with the Steam community API. // Also thanks to voogru for publishing the algorythm to calculate 64 bit steam ID's. //==================================================================================== // http://www.steampowered.com/ // http://www.steamcommunity.com/ // http://www.livebythegun.com/ //==================================================================================== Class SteamAPI { //- Time out in seconds public $timeout = 3; //- API hostname private $hostname = "steamcommunity.com"; private $socket, $ip_address, $service_port; /* -- Function: constructor -- Purpose: Called when class is created. Used to set some default values. -- Arguments: none -- Returns: void */ public function __construct() { //- Get the IP address for steamcommunity.com $this->ip_address = gethostbyname($this->hostname); //- Get the port for the WWW service $this->service_port = getservbyname('www', 'tcp'); } /* -- Function: get_profile_data -- Purpose: Retrieves profile data from the Steam API for the specified steam ID. -- Arguments: $steam_id - A steam ID to perform the API call for -- Returns: An array filled with the profile data, or null if the profile does not exist */ public function get_profile_data($steam_id) { //- Calculate the 64 bit steam ID $steam_id64 = $this->get_steamid64($steam_id); if (!$steam_id64) { throw New Exception('Invalid steam ID provided'); } //- Construct HTTP request $request = "GET /profiles/" . $steam_id64 . "?xml=1 HTTP/1.1\r\n"; $request .= "Host: " . $this->hostname . "\r\n"; $request .= "Connection: Close\r\n\r\n"; //- Do HTTP request $this->steam_connect(); $response = $this->steam_request($request); $this->steam_disconnect(); //- Check if a 302 response is given. This happens if the user has a 'Custom URL' set in their profile. //- If this is the case, make another request to the custom URL if (substr($response,0,12) == "HTTP/1.1 302") { //- Get the custom URL from the response if (preg_match( '@Location: http://steamcommunity.com/id/([a-zA-Z0-9_-]+)/@', $response, $location)) { $custom_url = $location[1]; } else { throw New Exception('Custom URL redirection, but no location found.'); } //- Construct HTTP request $request = "GET /id/" . $custom_url . "?xml=1 HTTP/1.1\r\n"; $request .= "Host: " . $this->hostname . "\r\n"; $request .= "Connection: Close\r\n\r\n"; //- Do HTTP request $this->steam_connect(); $response = $this->steam_request($request); $this->steam_disconnect(); } $this->steam_validate($response); //- If there is no profile XML element, something is not right if (!preg_match( '@<profile>(.+)</profile>@s', $response, $xmlArray)) { throw New Exception('Could not parse returned steam community data. XML Root node missing.'); } //- Store XML without headers $xml_data = $xmlArray[0]; //- Parse XML. An array of data is returned $data_array = $this->parse_xml($xml_data); //- Return the data return $data_array; } /* -- Function: parse_xml -- Purpose: Populate an array with the data found in the supplied XML -- Arguments: $xml_data - The XML data to parse -- Returns: An array of data from the XML */ private function parse_xml($xml_data) { //- Create an XMLReader object to parse the XML with $reader = new XMLReader(); //- Load the XML into it try { $reader->XML($xml_data); } catch (Exception $e) { throw New Exception('Could not parse returned XML: ' . $e->getMessage()); } //- Initialize an array for the profile data $data_array = array(); //- Start reading through the XML while ($reader->read()) { //- First encounter the root element if ($reader->nodeType == XMLReader::ELEMENT) { $rootnode_name = $reader->name; //- Read through its subnodes while ($reader->read()) { if ($reader->nodeType == XMLReader::ELEMENT) { //- Store the name of the subnode $elementName = $reader->name; //- Check for sections that will result in a recursive multi dimensional array if ( $elementName == "friends" || $elementName == "weblinks" || $elementName == "groups" || $elementName == "mostPlayedGames" ) { //- Initialize an array for the data $sub_array = null; $sub_array = array(); $sub_counter = 0; while ($reader->read()) { //- Check for subnodes if ($reader->nodeType == XMLReader::ELEMENT && ($reader->name == "friend" || $reader->name == "weblink" || $reader->name == "group" || $reader->name == "mostPlayedGame")) { while ($reader->read()) { //- Get the elements from the subnodes if ($reader->nodeType == XMLReader::ELEMENT) { $subElementName = $reader->name; //- The node is not empty so an end node is required //- Consider the data invalid until it is found $validDatafield = false; while ($reader->read()) { //- Check for the subnode value if ($reader->nodeType == XMLReader::TEXT || $reader->nodeType == XMLReader::CDATA || $reader->nodeType == XMLReader::WHITESPACE || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) { //- Store the value $elementValue = $reader->value; } //- Check if this is the subnode end element else if ($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == $subElementName) { //- If so the subnode is complete $validDatafield = true; break; } } //- If this is a valid subnode, store it in the data array if ($validDatafield) { $sub_array[$sub_counter][$subElementName] = $elementValue; $elementValue = ''; } } else if ($reader->nodeType == XMLReader::END_ELEMENT && ($reader->name == "friend" || $reader->name == "weblink" || $reader->name == "group" || $reader->name == "mostPlayedGame" )) { $sub_counter++; break; } } } else if ($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == $elementName) { $validDatafield = false; $data_array[$elementName] = $sub_array; break; } } } //- Check for sections that will result in a recursive single dimensional array else if ( $elementName == "inGameInfo" || $elementName == "favoriteGame" ) { //- Initialize an array for the data $sub_array = null; $sub_array = array(); while ($reader->read()) { //- Get the elements from the subnodes if ($reader->nodeType == XMLReader::ELEMENT) { $subElementName = $reader->name; //- The node is not empty so an end node is required //- Consider the data invalid until it is found $validDatafield = false; while ($reader->read()) { //- Check for the subnode value if ($reader->nodeType == XMLReader::TEXT || $reader->nodeType == XMLReader::CDATA || $reader->nodeType == XMLReader::WHITESPACE || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) { //- Store the value $elementValue = $reader->value; } //- Check if this is the subnode end element else if ($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == $subElementName) { //- If so the subnode is complete $validDatafield = true; break; } } //- If this is a valid subnode, store it in the data array if ($validDatafield) { $sub_array[$subElementName] = $elementValue; $elementValue = ''; } } else if ($reader->nodeType == XMLReader::END_ELEMENT && ( $reader->name == "inGameInfo" || $reader->name == "favoriteGame" )) { $validDatafield = false; $data_array[$elementName] = $sub_array; break; } } } //- Check for single nodes that do not require a recursive array to be used else { //- An end node is required //- Consider the data invalid until it is found $validDatafield = false; while ($reader->read()) { //- Check for the subnode value if ($reader->nodeType == XMLReader::TEXT || $reader->nodeType == XMLReader::CDATA || $reader->nodeType == XMLReader::WHITESPACE || $reader->nodeType == XMLReader::SIGNIFICANT_WHITESPACE) { //- Store the value $elementValue = $reader->value; } //- Check if this is the subnode end element else if ($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == $elementName) { //- If so the subnode is complete $validDatafield = true; break; } } //- If this is a valid subnode, store it in the data array if ($validDatafield) { $data_array[$elementName] = $elementValue; $elementValue = ''; } } } //- Check for the final rootnode end element else if ($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == $rootnode_name) { break; } } } } //- Close the XMLReader $reader->close(); //- Add the regular steam ID to the array as well $data_array['steamID32'] = $this->calculate_steamid($data_array['steamID64']); return $data_array; } /* -- Function: get_steamid64 -- Purpose: Check whether we have a regular steam ID, or a 64 bit steam ID and return a 64 bit steam ID either way -- Arguments: $steam_arg - Either a regular, or a 64 bit steam ID -- Returns: The 64 bit steam ID, or false if an invalid argument is provided */ private function get_steamid64($steam_arg) { if (preg_match('/^STEAM_[0-9]:[0-9]:[0-9]{1,}/i', $steam_arg)) { return $this->calculate_steamid64($steam_arg); } else if (preg_match('/^76561197960[0-9]{6}$/i', $steam_arg)) { return $steam_arg; } else { return false; } } /* -- Function: calculate_steamid64 -- Purpose: Translate a steam ID to a 64 bit steam id as used by Valve -- Arguments: $steam_id - The steam ID to translate -- Returns: The 64 bit steam ID, or false if an invalid steam ID is provided */ public function calculate_steamid64($steam_id) { if (preg_match('/^STEAM_[0-9]:[0-9]:[0-9]{1,}/i', $steam_id)) { $steam_id = str_replace("_", ":", $steam_id); list($part_one, $part_two, $part_three, $part_four) = explode(':', $steam_id); $result = bcadd('76561197960265728', $part_four * 2); $result = bcadd($result, $part_two); return bcadd($result, $part_three); } else { return false; } } /* -- Function: calculate_steamid -- Purpose: Translate a 64 bit steam ID to a steam id as used by Valve -- Arguments: $steam_id64 - The 64 bit steam ID to translate -- Returns: The steam ID, or false if an invalid 64 bit steam ID is provided */ public function calculate_steamid($steam_id64) { if (preg_match('/^76561197960[0-9]{6}$/i', $steam_id64)) { $part_one = substr( $steam_id64, -1) % 2 == 0 ? 0 : 1; $part_two = bcsub( $steam_id64, '76561197960265728' ); $part_two = bcsub( $part_two, $part_one ); $part_two = bcdiv( $part_two, 2 ); return "STEAM_0:" . $part_one . ':' . $part_two; } else { return false; } } /* -- Function: steam_connect -- Purpose: Initialize a connection to the Steam API -- Arguments: none -- Returns: void */ private function steam_connect() { //- Get the TCP protocol (can also use SOL_TCP instead) $protocol = getprotobyname('tcp'); //- Create a socket $this->socket = socket_create(AF_INET, SOCK_STREAM, $protocol); if ($this->socket === false) throw New Exception('Could not create socket. Reason: ' . socket_strerror(socket_last_error())); //- The socket should time out after 3 seconds, so make it non blocking for now socket_set_nonblock($this->socket); $error = NULL; $attempts = 0; //- The time out value has to be in milliseconds $timeout_ms = $this->timeout * 1000; $connected; //- Connect the socket to the steam server while (!($connected = @socket_connect($this->socket, $this->ip_address, $this->service_port)) && $attempts++ < $timeout_ms) { $error = socket_last_error(); //- If the error is different from the below, there is a problem if ($error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) { socket_close($this->socket); throw New Exception('Could not connect to steam community: ' . socket_strerror($error)); exit; } //- Wait 1 second between attempts usleep(1000); } //- If it's still not connected then consider the connection timed out if (!$connected) { socket_close($this->socket); throw New Exception('Connection to steam community timed out.'); exit; } //- Make the socket blocking again socket_set_block($this->socket); } /* -- Function: steam_request -- Purpose: Sends a HTTP request to the Steam API -- Arguments: $request_date - The HTTP request to be sent -- Returns: The 'raw' response data received from the Steam API */ private function steam_request($request_data) { //- Write the request to the socket socket_write($this->socket, $request_data, strlen($request_data)); //- Store the response $buffer = ''; $response = ''; while ($buffer = socket_read($this->socket, 2048)) { $response .= $buffer; } return $response; } /* -- Function: steam_validate -- Purpose: Checks the HTTP response code to see if the API request was succesful -- Arguments: $response_data - The response to be validated -- Returns: void */ private function steam_validate($response_data) { //- Check if the HTTP response code is 2xx. If so the request was a success if (!preg_match('@^HTTP/1.1 2[0-9]{2}@s', $response_data)) { throw New Exception('Request made to steam community failed (HTTP response code ' . substr($this->response, 9, 3) . ')'); } } /* -- Function: steam_disconnect -- Purpose: Disconnect from the Steam API -- Arguments: none -- Returns: void */ private function steam_disconnect() { //- Close the socket socket_close($this->socket); } } ?> Quote Link to comment https://forums.phpfreaks.com/topic/215567-xampp-socket-error/ Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.