steve steve - 2 months ago 14
JSON Question

PHP json encode not properly decoding in javascript

So I have an issue where data that's encoded using php is not decoding properly in javascript. Here is the error:
Error

The JSON looks fine but javascript is throwing an error and I have no idea why.

Here is my code:

JS:

function requestData( url )
{
document.getElementById( "spinner" ).style.visibility = "visible";

var xhttp;
xhttp = new XMLHttpRequest( );
xhttp.onreadystatechange = function( ) {
if ( this.readyState == 4 ) {
if( this.status == 200 )
{
document.getElementById( "spinner" ).style.visibility = "hidden";

console.log( this.responseText );

return this.responseText;
}
else
{
document.getElementById( "spinner" ).style.visibility = "hidden";

document.getElementById( "errorsec" ).innerHTML = ":( An unknown error has happened and your request was canceled. Code: " + this.status;

return false;
}
}
};
xhttp.open( "GET", url, true );
xhttp.send( );
}

function handleSignup( )
{
var username = document.getElementById( "un" ).value; // Get text field values
var password = document.getElementById( "pw" ).value;

var requestObject = requestData( "../../FRAMEWORK/createaccount.php?name=" + username + "&password=" + password, false );

var returnObject;

if( requestObject != false )
{
requestObject = JSON.parse( requestObject );

console.log( returnObject.value );
}
}


PHP:

<?php
# REV 1.0.0

$name = $_GET[ "name" ]; # Get values to set
$password = $_GET[ "password" ];

$file = fopen( "../USER_STORE/userindex.json", "r" ); # Load user index
$accounts = json_decode( fread($file, filesize( "../USER_STORE/userindex.json" ) ), true );
fclose($file);

$alreadyExists = false; # Check to see if username already is in use
foreach($accounts as $val) {
if( $val == $name )
{
$alreadyExists = true;
}
}

if( !$alreadyExists ) # If username is not in use
{
$UUID = sizeof( $accounts ) + 1;

$toAppend = array( "username" => $name, "password" => hash( "sha256", $password ) ); # Create append list

mkdir( "../USER_STORE/" . $UUID ); # Append user data
$file = fopen( "../USER_STORE/" . $UUID . "/accountinfo.json", "w" );
fwrite( $file, json_encode( $toAppend ) );
fclose( $file );

$accounts[ $UUID ] = $name; # Create new user index

$file = fopen( "../USER_STORE/userindex.json", "w" ); # Update userindex
fwrite( $file, json_encode( $accounts ) );
fclose( $file );

$return = array( "value" => "created" ); # Return message
echo( json_encode( $return ) );
}
else # Account is in use
{
$return = array( "value" => "account_in_use" ); # Return error message
echo( json_encode( $return ) );
}
?>

Answer

XMLHttpRequest works asynchronously. So your function requestData ends after the xhttp.send(); and does not return anything. The event handler for readystatechange (which is called a bit later, once XMLHttpRequest actually receives the response from the server) does return a value, but nothing is done with it.

Solution: move parsing and interpretation of the response in that event handler.

Additional notes:

  1. When you build an URL, you need to escape (using encodeURIComponent) the parameters. What do you think will happen if any of the two fields contains spaces, or special characters such as % or &?

  2. When you hash a password, you have to salt it first. Or use a ready-made function such as password_hash which will do it for you.

  3. You may want to use file_get_contents / file_put_contents to read/write your user file, that will simplify your code quite a bit. Or better yet, a database.