www.webdeveloper.com
Results 1 to 7 of 7

Thread: Variable is only defined after using "alert". What am I missing?

  1. #1
    Join Date
    Jun 2009
    Posts
    13

    Variable is only defined after using "alert". What am I missing?

    Hi Everyone
    I'm trying to build a CHAP login system with javascript md5. I'm fairly new to JS. I've worked it out based on various tutorials, but I also want to add a "salt" to the login. So therefore I've trying to get my JS to fetch a "salt" value from my database based on the users email adress that he/she enters.
    The problem is in the while-loop in the function checkForm().
    It works, but only when I put in an alert function to write out the output. The first alert will say "undefined" to the variable, the second will have the value. I put in the while loop to make it wait until it had it's reply from the server, but if I take out the alert in the loop it just continues, and posts the "salt" variable as "undefined" when it is passed to the php login file. Can anyone suggest to me what happens!
    Thanks!

    Code:
    <script language="javascript" src="md5.js"></script>
    <script language="javascript">
    var salt ="";
    var crossxhr = CrossXHR(); 
    
    function CrossXHR() {
      var crossxhr = false;
      if(window.XMLHttpRequest) {
        crossxhr = new XMLHttpRequest();
          if(crossxhr.overrideMimeType) {
            crossxhr.overrideMimeType('text/xml');
          }
      } else if(window.ActiveXObject) {
        try {
          crossxhr = new ActiveXObject('Msxml2.XMLHTTP');
        } catch(e) {
        try {
          crossxhr = new ActiveXObject('Microsoft.XMLHTTP');
        } catch(e) {
          crossxhr = false;
        }
      }
    }
      return crossxhr;
    }
    
    function getsalt(userid){
      crossxhr.onreadystatechange=function() {
          if(crossxhr.readyState==4) {
    	    salt=crossxhr.responseText;
    	  }
        } 
      crossxhr.open("GET","salt.php?email="+userid,true);
      crossxhr.send(null);
    }
    
    function checkForm(){
      valid=true;
      var usrid=document.getElementById('email');   // get 'email' field
      if(!usrid){return};
      if(!usrid.value){showError(usrid,'Enter your ID')};
      var slt=document.getElementById('salt'); // get 'salt' field
      
      while (salt=="") {
        salt=getsalt("test1@test.dk");
        alert("Salt value:"+salt);
        slt.value=salt;
      }
    
      // get 'password' field
      var psw=document.getElementById('passwd');
      if(!psw){return};
      if(!psw.value){showError(psw,'Enter your password')};
      // get 'challenge' field
      var chlng=document.getElementById('challenge');
      if(!chlng){return};
      // make MD5 hash of password and concatenate challenge value
      // next calculate MD5 hash of combined values 
      chlng.value=hex_md5(hex_md5(psw.value)+'<?php echo $chlgen->getChallengeVar('challenge')?>');
      // chlng.value=salte;
      // clear password field
      psw.value='';
      return valid;
    }

  2. #2
    Join Date
    Oct 2008
    Location
    U.S.
    Posts
    726
    The problem is in the while-loop in the function checkForm().
    I put in the while loop to make it wait until it had it's reply from the server,
    Those things themselves are part of the problem, as you are not quite approaching the process correctly. There is never any guarantee on how long it can take to get a response from the server. In most cases we humans perceive it to be pretty quick (especially from a localhost!), but now, as far as the machines involved are concerned it does not make sense to have a loop running at a rate of x number of loops per nanosecond or whatever, waiting for a variable to become defined via a response from the server (I'm not attempting to scold or anything, just to explain reasoning and method). The better way is to pass a function to the crossxhr object in order that the crossxhr object can invoke the passed function at the appropriate time (when the crossxhr object has received a successful response). Also, the global variable salt is not necessary, as when passing a callback function to the crossxhr object, as I show below, the function should have a parameter supplied (in this case the 'v' parameter of foo) through which the crossxhr object can send it's responseText into for further handling at that time, without the global lookup for the salt variable being necessary.
    So, my recommended changes are highlighted below:

    Code:
    <script type="text/javascript" src="md5.js"></script>
    <script type="text/javascript"> 
    var crossxhr = CrossXHR();
    
    function CrossXHR() {
        var crossxhr = false;
        if(window.XMLHttpRequest) {
            crossxhr = new XMLHttpRequest();
            if(crossxhr.overrideMimeType) {
                crossxhr.overrideMimeType('text/xml');
            }
        } else if(window.ActiveXObject) {
            try {
                crossxhr = new ActiveXObject('Msxml2.XMLHTTP');
            } catch(e) {
                try {
                    crossxhr = new ActiveXObject('Microsoft.XMLHTTP');
                } catch(e) {
                    crossxhr = false;
                }
            }
        }
        return crossxhr;
    }
    
    function getsalt(userid,callback){
        crossxhr.onreadystatechange = function() {
            if(crossxhr.readyState == 4 && typeof callback == 'function') {
    	    var salt = crossxhr.responseText;
                callback(salt);
    	}
        }; 
        crossxhr.open("GET","salt.php?email="+userid,true);
        crossxhr.send(null);
    }
    
    function checkForm(){
        valid=true;
        var usrid=document.getElementById('email');   // get 'email' field
        if(!usrid){return};
        if(!usrid.value){showError(usrid,'Enter your ID')};
        var foo = function (v) { //used as a callback function to pass to the crossxhr object
            var slt=document.getElementById('salt'); // get 'salt' field
            alert("Salt value:" + v);
            slt.value = v;
        };
        getsalt("test1@test.dk", foo); //pass the anonymous function to the getsalt function & thereby to the crossxhr object to run it it's self
        // get 'password' field
        var psw=document.getElementById('passwd');
        if(!psw){return};
        if(!psw.value){showError(psw,'Enter your password')};
        // get 'challenge' field
        var chlng=document.getElementById('challenge');
        if(!chlng){return};
        // make MD5 hash of password and concatenate challenge value
        // next calculate MD5 hash of combined values 
        chlng.value=hex_md5(hex_md5(psw.value)+'<?php echo $chlgen->getChallengeVar('challenge')?>');
        // chlng.value=salte;
        // clear password field
        psw.value='';
        return valid;
    }
    
    </script>

  3. #3
    Join Date
    Oct 2008
    Location
    U.S.
    Posts
    726
    Addendum and side note to the previous, another thing you could do with the getsalt function is to make the callback a property of the crossxhr object it's self, also, within the crossxhr.onreadystatechange function, could just use 'this' to refer to it's self, so the following would be another way you could do the getsalt function, just as something else you might want to try:

    Code:
    function getsalt(userid,callback){
        if (typeof callback == 'function') {
            crossxhr.onSuccess = callback;
        }
        crossxhr.onreadystatechange = function() {
            if(this.readyState == 4 && this.onSuccess) {
                this.onSuccess(this.responseText);
    	}
        }; 
        crossxhr.open("GET","salt.php?email="+userid,true);
        crossxhr.send(null);
    }

  4. #4
    Join Date
    Jun 2009
    Posts
    13

    Problem still exists...

    Thanks "astupidname" for your nice reply. I see your points, and just tried to implement them :-), but there's still a problem somehow. The 'alert' inside the 'foo' callback function returns nothing for the variable 'v'. However, if I add an 'alert' after the 'getsalt' function is called, the 'slt' variable gets its value, maybe because it gaines time? If I take away both 'alerts' then then scripts continues and returns valid at the end even though 'slt' has no value. I'm thinking that there's some basic stuff I've missed out?!? How can I avoid it terminating the checkForm() function before it has it's salt value?
    Thanks again for your reply....

  5. #5
    Join Date
    Oct 2008
    Location
    U.S.
    Posts
    726
    but there's still a problem somehow. The 'alert' inside the 'foo' callback function returns nothing for the variable 'v'. However, if I add an 'alert' after the 'getsalt' function is called, the 'slt' variable gets its value, maybe because it gaines time? If I take away both 'alerts' then then scripts continues and returns valid at the end even though 'slt' has no value.
    Umm, not sure why you have a problem with it, I just tried a test of it on my end (using both methods I posted earlier) and it works fine every time. I will say I forgot to catch one thing in my previous posts, is that the onreadystatechange function would be best to also have checking of status code at least to confirm that it is 200 (o.k.), and have added that in below.
    How can I avoid it terminating the checkForm() function before it has it's salt value?
    If the intent of that question is because the checkForm function is being returned to the forms onsubmit function and thereby the 'valid' variable which is returned as true or false (potentially) from the checkForm function basically controls the submission, you might actually not want to use an onsubmit event or a submit button, but perhaps use a regular type="button" input with an onclick="checkForm();" attribute, and then instead fire the forms submit() function from the foo function, as foo probably won't fire before the checkForm function is finished.
    An example of how I would set-up the script somewhat differently in this case (also note further improvements to the getsalt function):

    Code:
    <script type="text/javascript">var crossxhr = CrossXHR();
    
    function CrossXHR() {
        var crossxhr = false;
        if(window.XMLHttpRequest) {
            crossxhr = new XMLHttpRequest();
            if(crossxhr.overrideMimeType) {
                crossxhr.overrideMimeType('text/xml');
            }
        } else if(window.ActiveXObject) {
            try {
                crossxhr = new ActiveXObject('Msxml2.XMLHTTP');
            } catch(e) {
                try {
                    crossxhr = new ActiveXObject('Microsoft.XMLHTTP');
                } catch(e) {
                    crossxhr = false;
                }
            }
        }
        return crossxhr;
    }
    
    function getsalt(userid,callback){
        if (typeof callback == 'function') {
            crossxhr.onSuccess = callback;
            crossxhr.onreadystatechange = function() {
                if(this.readyState == 4) {
                    if (this.status == 200) {
                        this.onSuccess(this.responseText);
                    } else {
                        alert('Error retrieving response!');
                    }
    	    }
            }; 
            crossxhr.open("GET","salt.php?email="+userid+ "&ii="+ Math.random(),true);
            crossxhr.send(null);
        }
    }
    
    function checkForm(){ //use a type="button" input with an onclick="checkForm();" attribute to call this function and trigger the forms submission from foo
        valid=true;
        var usrid=document.getElementById('email');   // get 'email' field
        if(!usrid){return};
        if(!usrid.value){showError(usrid,'Enter your ID')};
        // get 'password' field
        var psw=document.getElementById('passwd');
        if(!psw){return};
        if(!psw.value){showError(psw,'Enter your password')};
        // get 'challenge' field
        var chlng=document.getElementById('challenge');
        if(!chlng){return};
        // make MD5 hash of password and concatenate challenge value
        // next calculate MD5 hash of combined values 
        chlng.value=hex_md5(hex_md5(psw.value)+'<?php echo $chlgen->getChallengeVar('challenge')?>');
        // chlng.value=salte;
        // clear password field
        psw.value='';
         //I'm assuming that above here you would actually do more intense checking of the fields values
         //than what is shown here, and change valid to false if bad values before here
        if (valid) {
            var foo = function (v) { //used as a callback function to pass to the crossxhr object
                var slt=document.getElementById('salt'); // get 'salt' field
                alert("Salt value:" + v);
                slt.value = v;
                 //give the form an id of 'someForm', or whatever, and trigger the submission of the form here
                document.getElementById('someForm').submit(); //submit the form
            };
            getsalt("test1@test.dk", foo); //pass the anonymous function to the getsalt function & thereby to the crossxhr object to run it it's self
        } else {
            alert('Not valid');
        }
    }</script>
    If I'm misunderstanding anything, or you still have trouble, post the form and how you are invoking the checkForm function so I can see more how you're going about that.
    Good luck!
    Last edited by astupidname; 06-20-2009 at 10:08 AM.

  6. #6
    Join Date
    Jun 2009
    Posts
    13

    now it works...but only on 'localhost'

    Hi 'astupidname'. Thanks once again for your nice reply. I fiddled around with it and after a while I got it to work on my localhost (MAMP, since I'm on a Mac).
    I basically did everything you suggested. I think what finally did the trick was to use a regular button instead of submit as you suggested. However, being happy that it worked, I decided to upload it to my web host, and sadly found that it now stopped working. I've tried to upload the files with alerts in all sorts of places, and based on these alerts it seems as if the 'var foo = function (v)' never runs on the server. Also alerts within 'function getsalt(); are never executed it seems. Do you have any idea what could be different on the server?
    Thanks for your help!!!!
    I now posted the entire code of the javascript for you to see....

    Code:
    <script type="text/javascript" src="md5.js"></script>
    <script type="text/javascript" src="XMLHttpRequest.js"></script>
    <script type="text/javascript">
    function getsalt(userid,callback){
        if (typeof callback == 'function') {
            crossxhr.onSuccess = callback;
            crossxhr.onreadystatechange = function() {
                if(this.readyState == 4) {
                    if (this.status == 200) {
                        this.onSuccess(this.responseText);
                    } else {
                        alert('Error retrieving response!');
                    }
    	    }
            }; 
            crossxhr.open("GET","salt.php?email="+userid+ "&ii="+ Math.random(),true);
            crossxhr.send(null);
        }
    }
    
    function checkForm(){ //use a type="button" input with an onclick="checkForm();" attribute to call this function and trigger the forms submission from foo
        valid=true;
        var usrid=document.getElementById('email');   // get 'email' field
        if(!usrid.value){
          valid=false;
          return;
        };
        var psw=document.getElementById('passwd');    // get 'password' field
        if(!psw.value){
          valid=false;
          return;
        };
        var chlng=document.getElementById('challenge');  // get 'challenge' field
        if (valid) {
            var foo = function (v) { //used as a callback function to pass to the crossxhr object
                var slt=document.getElementById('salt'); // get 'salt' field
                slt.value = v;
                // make MD5 hash of password+salt and concatenate challenge value, and MD5 hash again
                chlng.value=hex_md5(hex_md5(psw.value+slt.value)+'<?php echo $chlgen->getChallengeVar('challenge')?>');
                // clear password field
                psw.value='';
                // trigger the submission of the form here
                document.getElementById('loginform').submit(); //submit the form
            };
            getsalt(usrid.value, foo); //pass the anonymous function to the getsalt function & thereby to the crossxhr object to run it it's self
        } else {
            alert('Not valid');
            return;
        }
         
    }
    
    /*
     * display error messages
     */
    function showError(obj,message){
      if(!obj.errorNode){
        obj.onchange=hideError;
        var p=document.createElement('p');
        p.appendChild(document.createTextNode(message));
        obj.parentNode.appendChild(p);
       obj.errorNode=p;
     }
      valid=false;
      return
    }
    /*
     * hide error messages
     */
    function hideError(){
      this.parentNode.removeChild(this.errorNode);
      this.errorNode=null;
      this.onchange=null;
    }
    
    </script>
    </head>
    
    <body class="background">
    
    <table>
      <tr>
          <td>
          <div class="body"><b>Login for Administratorer</b></div>
        </td>
      </tr>
      <tr>
        <td class="body">
          <!-- login form -->
          <form id="loginform" method="post" action="login_[checkin].php" >
            <?PHP
    	    if (!isset($_REQUEST['logmsg']))
    		  {
    	    	$_REQUEST['logmsg'] = "";
    		  }
    
    	    switch($_REQUEST['logmsg'])
    		  {
    		  case "0":
    		    echo "BrugerID og/eller password er forkert!";
    		    break;
    	   	  case "1":
    		    echo "Du er nu logget ud.";
    		    break;
    		  case "2":
    		    echo "Timeout - Du er logget automatisk ud.";
    		    break;
    		  default:
    		    echo "Angiv brugerID og password: ".$_REQUEST['logmsg'];
                break;
    		  }
    	    ?>
    	    <br>
    		BrugerID <input type="text" name="email" id="email" /><br />
    		Password <input type="password" name="passwd" id="passwd" /><br />
    		<input type="hidden" name="challenge" id="challenge" />
    		<input type="hidden" name="salt" id="salt" />
    		<input name="send" value="send" type="button" onClick="checkForm()">
    	  </form>
          <a href="forgot.php" class="loginform">Glemt password?</a>
        </td>
      </tr>
     
    </table>
    </body>
    </html>

  7. #7
    Join Date
    Oct 2008
    Location
    U.S.
    Posts
    726
    and based on these alerts it seems as if the 'var foo = function (v)' never runs on the server. Also alerts within 'function getsalt(); are never executed it seems. Do you have any idea what could be different on the server?
    No. I just tested it both from localhost and from server and it works fine for me! (I tested without the md5 stuff and the php block in the form just to simplify for me). You are entering values into the textboxes before hitting the button right?? You say alerts within getsalt don't even fire, but that would tell me that getsalt is not even being called due to lack of input values... ?? Or perhaps lack of an actual crossxhr object due to --> Paths to the other scripts correct and everything?? Check to make sure that no files got accidentally renamed during upload or character case of file name is correct on server. I once had a problem with an ftp client (which I no longer use of course) that converted to lower case at times I didn't want it to, so maybe something strange like that, I can't say otherwise.
    Last edited by astupidname; 06-21-2009 at 03:41 PM.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles