Improved Blockland authentication for PHP (Fixes auth with special characters)

Author Topic: Improved Blockland authentication for PHP (Fixes auth with special characters)  (Read 2183 times)

This is an improvement on the PHP function Zapk released previously. The most notable change from his function is that this function properly handles the url and character encoding that the auth server expects, thus allowing people using special characters in their usernames to authenticate successfully. Other than that, this function also parses the auth server response to an extent for easier usage.

Code: [Select]
<?php
function 
BlocklandAuthenticate($username)
{
$username mb_convert_encoding(urldecode($username), "ISO-8859-1");
$username str_replace("%""%25"$username);
$encodeChars = array(" ""@""$""&""?""=""+"":"",""/");
$encodeValues = array("%20""%40""%24""%26""%3F""%3D""%2B""3A","%2C""%2F");
$username str_replace($encodeChars$encodeValues$username);

$postData "NAME=${username}&IP=${_SERVER['REMOTE_ADDR']}";

$opts = array('http' => array('method' => 'POST''header' => "Connection: keep-alive\r\nUser-Agent: Blockland-r1986\r\nContent-type: application/x-www-form-urlencoded\r\nContent-Length: "strlen($postData) . "\r\n"'content' => $postData));

$context  stream_context_create($opts);
$result file_get_contents('http://auth.blockland.us/authQuery.php'false$context);
$parsedResult explode(' 'trim($result));

if($parsedResult[0] == "NO")
return false;

else if(!is_numeric($parsedResult[1]))
{
print($result);
return false;
}

else
return intval($parsedResult[1]);
}
?>


  • Usage
    Say the user wants to register under the name "Badspot", and you want valid Blockland users only.
    You would handle the value returned by BlocklandAuthenticate(username). In this case, username would be "Badspot".

    It sends the username and the client's IP address to the auth server, where it checks to see if the IP has played under that username last.

    If their IP address does not match Badspot's IP address (which is saved on the auth server), it will return incorrect. If it does, it will return correct.

  • Correct
    When correct, this function will return an integer of the user's BL_ID

  • Incorrect
    If it's incorrect, it will simply return false.



    I hope you find this resource helpful.

Thank you for doing this.
I know Ive had my troubles with my own name.

This is fine and all, but I do wonder the following:

How come you're requesting the connection to be kept alive? Isn't this a one-time connection that will disconnect when you're done?

When it comes to the encoding, I would suggest the usage of rawurlencode as that does exactly as you're algorithm does. Then better, you could use urlencode instead as that complies with the application/x-www-form-urlencoded. Was there a certain reason for this as well?

How come you're requesting the connection to be kept alive? Isn't this a one-time connection that will disconnect when you're done?

When it comes to the encoding, I would suggest the usage of rawurlencode as that does exactly as you're algorithm does. Then better, you could use urlencode instead as that complies with the application/x-www-form-urlencoded. Was there a certain reason for this as well?
The auth server always replies with Connection: close, so it makes no difference. It was just one of the things I left in on accident while debugging issues, since Blockland doesn't send a keep-alive header whereas PHP sends one by default.

Blockland does not url encode in a way that is even remotely standard, only a few characters are encoded. And the master server appears to only decode in the exact same format. This is why I had to write my own encode rules. If this were not the case zapk's function would have worked with special characters, because it uses http_build_query which automatically url encodes the data you input to it.
« Last Edit: October 16, 2016, 03:24:19 AM by Pecon »

The auth server always replies with Connection: close, so it makes no difference. It was just one of the things I left in on accident while debugging issues, since Blockland doesn't send a keep-alive header whereas PHP sends one by default.
Is it needed to have it there, as we probably want to replicate how Blockland sends it to avoid any issues?

Also, what about the user agent? Is that for debugging purposes as well?

Blockland does not url encode in a way that is even remotely standard, only a few characters are encoded. And the master server appears to only decode in the exact same format. This is why I had to write my own encode rules. If this were not the case zapk's function would have worked with special characters, because it uses http_build_query which automatically url encodes the data you input to it.
That is indeed interesting. I knew Blockland did their own things, but I wasn't aware of this fact. Thanks for clearing it up.
« Last Edit: October 16, 2016, 03:36:04 AM by mctwist »

Is it needed to have it there, as we probably want to replicate how Blockland sends it to avoid any issues?

Also, what about the user agent? Is that for debugging purposes as well?
I couldn't find a way to remove the connection header.

The user agent is the same one Blockland sends.

I couldn't find a way to remove the connection header.
Then how about use "Connection: close"? Shouldn't hurt a tiniest bit and it tells more what your code want to accomplish.

That reminds me. Why print out the errors when they could be put somewhere else?

The user agent is the same one Blockland sends.
I spent a couple of minutes to throw together a function that could get the newest revision from the Development board:
Code: [Select]
<?php
function GetBlocklandRevision()
{
// Prepare http request
$options = [];
$options['http'] = [];
$options['http']['method'] = 'GET';
$options['http']['header'] = "Connection: close\r\n";

$context stream_context_create($options);

// Get content from Development board
$content file_get_contents('https://forum.blockland.us/index.php?board=41.0'false$context);

// Locate revision numbers
preg_match_all("/[^0-9a-zA-Z](r[0-9]{4})[^0-9a-zA-Z]/"$content$result);

// Avoid possible errors that could arise
if (count($result) != || count($result[1]) == 0)
return false;

// Get result and sort it
$result $result[1];
$result rsort($result);

return $result[0];
}

Not perfect, but it indeed works.