• Receive GMod Server log with PHP
    9 replies, posted
Hi, I'm developing my own RCon application in PHP on my website to communicate with my Garry's Mod server. I am experienced with general web development (html, javascript) and PHP, but I'm fairly new to networking. I am able to connect to the server, send RCon commands, and receive responses from said commands. I'm looking for a way to receive server logs, and display them in (semi) real-time on the console application. From what I understand, I need to turn logging on, and then specify an IP:Port to the GMod server with [B]logaddress_add[/B]; then listen for incoming connections on a UDP socket, process the data so it's usable, log it to a database, and then use Javascript on the console page to pull new logs out of the database and display them in a textarea. I've specified the IP:Port to send the logs to with the [B]logaddress_add[/B] command, and I have logging turned on. The Javascript and database parts are not a problem. What I'm currently stuck on is trying to figure out how to listen for this log data being sent by using a UDP socket. The code below works up until I call [B]socket_recvfrom[/B], then it stalls and never writes anything to the log.txt file. If I comment that function call out, the debug messages display that the socket is created and the binding worked (as far as I know). I've tried using the IP address of the webserver as the value of $host, but there was no apparent difference, so I'm currently using "0.0.0.0". I have also opened port 10000 on the webserver. If anyone could give me some pointers on what I might be doing wrong, or where to go from here, it would be greatly appreciated. Here's the code I have so far for receiving incoming log data. [code] <?php $host = "0.0.0.0"; $port = 10000; define('EOL', '<br>'); // for debugging purposes //Create a UDP socket if(!($socket = socket_create(AF_INET, SOCK_DGRAM, 0))){ $errorcode = socket_last_error(); $errormsg = socket_strerror($errorcode); die("Couldn't create socket: [$errorcode] $errormsg".EOL); } // Reuse socket option -- is this even necessary? if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) { echo 'Unable to set option on socket: '. socket_strerror(socket_last_error()).EOL; } echo "Socket created".EOL; // Bind the source address if(!socket_bind($socket, $host , $port)){ $errorcode = socket_last_error(); $errormsg = socket_strerror($errorcode); die("Could not bind socket : [$errorcode] $errormsg".EOL); } echo "Socket bind OK".EOL; while(1){ //Receive data $r = socket_recvfrom($socket, $buf, 512, 0, $remote_ip, $remote_port); file_put_contents('log.txt', $buf); // log data to txt file } socket_close($socket); [/code]
Try using [URL="http://koraktor.de/steam-condenser/"]steam condenser[/URL].
I have looked into Steam Condenser, but it doesn't currently support this functionality. This is still marked as an open issue, according to: [url]https://github.com/koraktor/steam-condenser/issues/181[/url]
I dont know if it is the cause, but $remote_ip and $remote_port is not defined in your code.
$remote_ip and $remote_port (in the code above) are passed by reference and assigned values by the function. I found a solution to the problem of not receiving a response. The server seems to require you to send it a message first, before it starts sending the log data back. I found this tip here. There was nothing else wrong with the code I posted above. [code] // IP:Port to send the logs to (web server) $host="xxx.xxx.xxx.xxx"; $port = 10000; // IP:Port the logs are being sent from (your server) $remote_ip = 'xxx.xxx.xxx.xxx'; $remote_port = 27015; // Create socket if (!($socket = socket_create(AF_INET, SOCK_DGRAM, 0))){ exit; } // Make reusable if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)){ exit; } // Bind the source address if(!socket_bind($socket, $host , $port)){ exit; } // Send first message - SRCDS needs to receive a message first before it starts sending $msg = ""; // Message can be anything, it doesn't matter $len = strlen($msg); socket_sendto($socket, $msg, $len, 0, $remote_ip, $remote_port); // Get database - my own convenience function // You can disregard the bits of database code if (!$db = get_database()){ exit; } // Edit: Moved prepared statement here - thanks to benjojo $statement = $db->prepare("INSERT INTO server_logs (content) VALUES (:content)"); // Gather log data while(1){ $r = socket_recvfrom($socket, $buf, 512, 0); $buf = substr($buf, 7); // Remove weird characters at beginning $buf = str_replace(array("\0", "\r"), '', $buf); // Remove unwanted escape sequences // Log code to database (using PDO) $statement->execute(array(':content'=>$buf)); } // Might want to implement your own failsafe system to break out of the above // While loop to turn off logging // Close PDO cursor $statement->cursorClose(); // Close socket socket_close($socket); [/code] Facepunch seems to be having trouble displaying my code, so I've pasted a clean version of it on the NFOServers Forum where I also asked about this: [B][U][URL="http://www.nfoservers.com/forums/viewtopic.php?f=1&t=10090#p52911"]Thread Here[/URL][/U][/B] The code is slightly different than what I have on my site, because I edited it for posting on the forum. I haven't tested it, though it should work. I only say this as a disclaimer because I removed some code that pertained only to my site. The database management code can be disregarded, and you can implement your own system for logging the data. Also, there were the characters "ÿÿÿÿRL" at the beginning of each log entry. I'm not sure if this is part of the actual log from the server, or something else. Either way, it seemed to repeat consistently, so I thought it would be safe to trim that part out. Let me know if you spot any bugs in the code so I can correct it.
[QUOTE=Riyuzakisan;43058076] Let me know if you spot any bugs in the code so I can correct it.[/QUOTE] More knit picky at most but also a good SQL based tip. If you prepare something you can execute it as many times as you want, Since preparing is quite expensive on the database end, if you are logging like this then just keep executing the same statement with diff prams each time. This generally only really matters in high load or high latency, This could be the case though if your SQL server is not on the invoker's end, or not even on the same LAN. [code] <?php // IP:Port to send the logs to (web server) $host="xxx.xxx.xxx.xxx"; $port = 10000; // IP:Port the logs are being sent from (your server) $remote_ip = 'xxx.xxx.xxx.xxx'; $remote_port = 27015; // Create socket if (!($socket = socket_create(AF_INET, SOCK_DGRAM, 0))){ exit; } // Make reusable if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)){ exit; } // Bind the source address if(!socket_bind($socket, $host , $port)){ exit; } // Send first message - SRCDS needs to receive a message first before it starts sending $msg = ""; // Message can be anything, it doesn't matter $len = strlen($msg); socket_sendto($socket, $msg, $len, 0, $remote_ip, $remote_port); // Get database - my own convenience function // You can disregard the bits of database code if (!$db = get_database()){ exit; } $statement = $db->prepare("INSERT INTO server_logs (content) VALUES (:content)"); // Gather log data while(1){ $r = socket_recvfrom($socket, $buf, 512, 0); $buf = substr($buf, 7); // Remove weird characters at beginning $buf = str_replace(array("\0", "\r"), '', $buf); // Remove unwanted escape sequences // Log code to database (using PDO) $statement->execute(array(':content'=>$buf)); } // Might want to implement your own failsafe system to break out of the above // While loop to turn off logging // Close PDO cursor if (isset($statement)){ $statement->cursorClose(); } // Close socket socket_close($socket); ?> [/code]
Ah, I see. Thanks for the tip, benjojo.
Hey, could I get Your contact (steam, skype, email) please?
[email]riyuzakisan@gmail.com[/email]
I tried to use the code but I got this error: [IMG]http://174.103.68.195/pics/error.png[/IMG] please help!
Sorry, you need to Log In to post a reply to this thread.