Jump to content
Larry Ullman's Book Forums

Using Ajax To Check Database For Available Usernames


Recommended Posts

Okay so I just finished reading the Javascript book (including Ch 11) and I am pushing forward trying to get AJAX to work on my prototype website for the first time. Specifically I want to have my registration page use AJAX to notify the user of whether their desired username is available in our system or not.

 

I am familiar with HTML / CSS so I don't think the issue is in there, and am familiar enough with PHP and MySQL but not necessarily how PHP interacts with Javascript via AJAX.

 

Here is my code, emphasis on the Javascript portion (and PHP portion) because those are the parts that I am most unfamiliar with:

 

<tr>
 <td class="form_left"><label for="username">Username:</label></td>
 <td class="form_right"><input type="text" id="username" name="username" size="25" maxlength="25"
	 value="<?php if (isset($_POST['username'])) {echo $_POST['username'];} ?>" onkeyup="verifyUsername()" /><span id="usernameSpan"
		 style="color:red;">*</span></td>
</tr>
...
<script src="/js/register.js"></script>
<script src="/js/ajax.js"></script>

 

Here is my PHP code:

 

require_once ($_SERVER["DOCUMENT_ROOT"] . '/includes/config.inc.php');[/background][/size][/font][/color]
[color=#000000][font=verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif][size=3][background=rgb(245, 245, 245)]//
if (isset ($_POST['enteredUsername'])) {
$submitted_username = $_POST['enteredUsername'];
 require_once (MYSQL); // Connect to the db.
}
$check_username_query = "SELECT username FROM users WHERE username = $submitted_username";
$r = mysqli_query ($dbc, $check_username_query) ;
if (mysqli_num_rows($r) == 0) {
echo 'VALID';
}
else {
echo 'INVALID';
}

 

And here is my Javascript code:

 

function verifyUsername() {
'use strict';

//Get a reference (get element by ID) to the entered username value:
var ajax = getXMLHttpRequestObject();

var enteredUsername = U.$('username');
var usernameSpan = U.$('usernameSpan');
// Validate the first name:
if (/[a-zA-Z0-9._-]{1,25}$/i.test(username.value)) { //tested true in console
		 if (usernameSpan.textContent !== undefined) {
			 usernameSpan.textContent = "";


		 }
		 else {usernameSpan.innerText = "";}

		 //Begin the AJAX request

		 ajax.onreadystatechange = function() {
			 if (ajax.readyState == 4){
				 //Check the status code:
				 if ( (ajax.status >= 200 && ajax.status < 300)
				 || (ajax.status == 304) ) {
				 if (ajax.responseText == 'VALID') {
					 if (usernameSpan.textContent !== undefined) {
						 usernameSpan.textContent = "Username available";
					 }
					 else {usernameSpan.innerText = "Username available";}
					 }
				 else {
					 if (ajax.responseText == 'INVALID'){

					 if (usernameSpan.textContent !== undefined) {
						 usernameSpan.textContent = "Username not available";
					 }
					 else {usernameSpan.innerText = "Username not available";}
						 }
					 }
					 }
				 }
			 };

			 ajax.open('POST', 'resources/verifyusername.php', true);
			 ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
			 var data = 'enteredUsername=' + encodeURIComponent(username.value);
			 ajax.send(data);

		 }

else {
if (usernameSpan.textContent !== undefined) {
			 usernameSpan.textContent = "Username must be 25 characters or less, contain only \n\
				 numbers, letters, '.', '_', and '-'.	 ";
			 }
		 else {usernameSpan.innerText = "Username must be 25 characters or less, contain only \n\
				 numbers, letters, '.', '_', and '-'.";
			 }

		 }


} //End of verifyUsername() function

 

As of right now when I enter a username it changes the asterisk to a blank spot. This means that my PERL regular expression is at least passing.

 

registration_error.png

 

If I can at least narrow down the error to whether it's the PHP or Javascript code causing the issue then that will make it much easier to eventually find and fix the problem. Any help would be greatly appreciated! Once I get this AJAX thing down the first time it will make all subsequent attempts much easier because I will have a template to base my attempts off of. I have been dabbling in the Developer's Console in Chrome which at least shows verifyusername.php being initiated by register.js but not much more info.

Link to comment
Share on other sites

For starters, you have to get rid of this event handler:

 

onkeyup="verifyUsername()"

I explain why that's bad several times over in the book.

 

Second, I don't think you want to do the Ajax request with EVERY keyup. That's terribly inefficient.

 

Third, you should perform a GET request of the PHP script.

 

Fourth, your PHP script is open to SQL injection attacks.

 

Fifth, you're not quoting the username, which is a string, in your PHP query.

 

There may be more problems, but you need to fix those first.

Link to comment
Share on other sites

danconia, not to double-team you, but I'm in agreement with Larry that your code has several core issues that you need to deal with before you even think about using Ajax.

If you can be patient, in the next day or two, I will try and post some sample code that will hopefully guide you in the right direction.

Link to comment
Share on other sites

Yeah I've started making changes according to your guys' suggestions. I've chopped out the unnecessary code a bit to try to isolate the problem but am still having issues. Unfortunately all of the tutorials that I see online use JQuery and I'm not sure I want to go through delving too deep into that right now since Ajax itself is giving me a hassle.

Link to comment
Share on other sites

Okay, I think I finally have the time to make a proper response.

 

More than anything though, I don't want to just give you the answer, as you seem pretty close to discovering what to do on your own.

Instead, I will try to provide some useful hints, and we can further discuss things as necessary.

 

Ajax, as the technique is called, refers to using a special Javascript object called the XMLHttpRequest object to send a request to another script asynchronously (i.e., without having to reload the page) to get information or perform some processing.

 

There are two main types of Ajax requests: get and post. These should sound familiar to you, and just like PHP, get should be used to retrieve data while post should be used to make changes to existing data or to hide the data being sent to a script.

 

In your case, since you're using a SELECT statement to check whether a user name is already in use on your site, you should use the get method. As such, you'll want to adjust your PHP script to use the $_GET superglobal, not the $_POST superglobal.

 

There are four main parts to managing an Ajax request to a PHP script. The first part is to actually create the (hopefully cross-browser-compatible) Ajax object. I'll trust you can do this on your own.

 

The next part is to set up a special event handler for Ajax requests. I think Larry explains this in the book, but whenever you send an Ajax request to another script, the Ajax object receives constant updates from the script that was called regarding the status of the request. The event handler you want to use for this purpose is the onreadystatechange event handler. The following is an example of how to set this event handler up:

 

ajax.onreadystatechange = handleResponse;

 

In the above example, ajax is the variable containing the Ajax object and handleResponse is the function that is called whenever the onreadystatechange event fires (which is quite often after a request is made).

 

The onreadystatechange event handler can be set up at any time, but I recommend setting it up before any Ajax requests are actually made. To keep things simple, I usually set up the onreadystatechange event handler right after the Ajax object is created.

 

The next step is to actually make an Ajax request. There are two methods you need to call for a get request. The first is the open method, and the second is the send method.

 

The Ajax open method essentially sets up the request. The following is the general format for an open method call:

 

ajax.open('get', 'php-script-path.php?parameters-here');

 

Like any get request, don't forget to attach the necessary parameters to the end of the URL so that the PHP script you're calling has access to the info. For parameter data you want to send that is stored in a JS variable, I recommend executing the encodeURIComponent function on the JS variable in order to properly encode the data for use in a URL.

 

After you've executed the open method, you need to call the send method, which is simple for get requests, because the argument is always null. The following is an example:

 

ajax.send(null);

 

At this point, your Ajax request has been sent to the PHP script. The onreadystatechange event is going to start firing like crazy until the request has been processed. Within the function called by the onreadystatechange event, you need to monitor for certain Ajax statuses, and when you observe those statuses, you will know that you have gotten a complete response.

 

Specifically, the two things you want to monitor for are a ready state of 4 and a status of 200 (please see an Ajax reference for details on what these mean). You might, for example, write an Ajax onreadystatechange event handler function as follows:

 

function handleResponse() {

 if ((ajax.readyState === 4) && (ajax.status === 200)) { // You have received a proper response from the PHP script you called.

   // The return string is stored in the ajax.responseText property.

 }

}

 

Once you have gotten a response, you can access it from the ajax.responseText property.

 

That's basically all there is to an Ajax request. From there, you can build infinitely complex requests and/or series of requests, but in the end, the concept is all the same.

 

Does that answer your questions about Ajax?

 

As a couple of side comments not related to Ajax but regarding what you're trying to do:

1) I would use the onkeydown event handler.

2) I would definitely not send an Ajax request every time a key is pressed. You'll quickly bog down the server. There are two common alternatives: i) Don't make the Ajax request until the text input loses focus, or ii) Set up a timer that makes an Ajax request only after, say, 2 seconds have passed since the user last pressed a key in the text input.

3) I wouldn't start making Ajax requests until the user has typed at least 3-4 characters into the text input.

 

Well, hope that helps.

Let us know if you have any other questions.

Link to comment
Share on other sites

Thank you HartleySan, I am still digging through and it looks like the issue is probably with AJAX sending the GET request. I finally figured out how to use the developer's console in Chrome and these are the errors that I am getting:

 

An error occurred in script '/home/kylhur/danconia.us/resources/verifyusername.php' on line 11: Undefined variable: submitted_username

An error occurred in script '/home/kylhur/danconia.us/resources/verifyusername.php' on line 12: Undefined variable: dbc

An error occurred in script '/home/kylhur/danconia.us/resources/verifyusername.php' on line 12: mysqli_query() expects parameter 1 to be mysqli, null given

An error occurred in script '/home/kylhur/danconia.us/resources/verifyusername.php' on line 15: mysqli_num_rows() expects parameter 1 to be mysqli_result, null given

 

I specifically noticed the following:

[GLOBALS] => Array

*RECURSION*

[_POST] => Array

(

)

[_GET] => Array

(

)

So I gotta look closer at my request object I believe. Then once I get that working I can debug the PHP and MySQL code.

Link to comment
Share on other sites

Yeah I have made several changes to the PHP file and then finally tried using just the URL for the PHP script and appending the variables to the end. It seems that, among other things, my mysqli_escape_string function didn't include the first parameter ($dbc). Once I fixed this and entered in the URL it gave me back the simple "VALID" text response.

 

 

<?php
require_once ($_SERVER["DOCUMENT_ROOT"] . '/includes/config.inc.php');

//
if (isset ($_GET['enteredUsername'])) {
     require_once (MYSQL); // Connect to the db.
   $trimmed_username = trim($_GET['enteredUsername']);
   $submitted_username = mysqli_real_escape_string($dbc, $trimmed_username);

   }

$check_username_query = "SELECT username FROM users WHERE username = '$submitted_username'";
$r = mysqli_query($dbc, $check_username_query);


if (mysqli_num_rows($r) == 0) {
   echo 'VALID';
}
else {
   echo 'INVALID';
}
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
?>

 

For the Javascript I used the below code and it appears that when I tried to set the enteredUsername variable it didn't work or something because later on it was not be encoded into the URI.

 

function verifyUsername() {
   'use strict';

   //Get a reference (get element by ID) to the entered username value:
   var ajax = getXMLHttpRequestObject();


  [b] var enteredUsername = document.getElementById('username');[/b]
   var usernameSpan = U.$('usernameSpan');

   // Validate the first name:
if (/[a-zA-Z0-9._-]{1,25}$/i.test(enteredUsername.value)) { //tested true in console
		    if (usernameSpan.textContent !== undefined) {
			    usernameSpan.textContent = "";

		    }
		    else {usernameSpan.innerText = "";}

		    //Begin the AJAX request

		    ajax.onreadystatechange = function() {
			    if (ajax.readyState == 4){
				    //Check the status code:
				    if ( (ajax.status >= 200 && ajax.status < 300)
				    || (ajax.status == 304) ) {
				    if (ajax.responseText == 'VALID') {
					    if (usernameSpan.textContent !== undefined) {
						    usernameSpan.textContent = "Username available";
					    }
					    else {usernameSpan.innerText = "Username available";}
					    }
				    else {
					    if (ajax.responseText == 'INVALID'){

					    if (usernameSpan.textContent !== undefined) {
						    usernameSpan.textContent = "Username not available";
					    }
					    else {usernameSpan.innerText = "Username not available";}
						    }  
					    }
					    }
				    }
			    };

			    [b]var data = 'enteredUsername=' + encodeURIComponent(enteredUsername.value);[/b]
			    ajax.open('GET', 'resources/verifyusername.php?' + data, true);
			    //ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

			    ajax.send(data);

		    }

 else {
 if (usernameSpan.textContent !== undefined) {
			    usernameSpan.textContent = "Username must be 25 characters or less, contain only \n\
				    numbers, letters, '.', '_', and '-'.	    ";
			    }
		    else {usernameSpan.innerText = "Username must be 25 characters or less, contain only \n\
				    numbers, letters, '.', '_', and '-'.";
			    }

		    }

} //End of verifyUsername() function

 

So I decided to change the encodeURIComponent paranthetical to document.getElementById("username").value, and it worked! I am still not completely certain why the original enteredUsername.value didn't work but I'll have to look into it a bit more.

Link to comment
Share on other sites

One important thing to note with your PHP code is that you're running the query outside of the if statement. Pretty much everything in your PHP file should be within that if statement.

 

Also, enteredUsername doesn't work because it doesn't exist in the anonymous function called by the onreadystatechange event handler.

Basically, that variable is not automatically passed to the anonymous function.

Hopefully, that clears that up.

Link to comment
Share on other sites

 Share

×
×
  • Create New...