AprilSwenby Posted November 21, 2011 Share Posted November 21, 2011 Hello all - I am having a huge stumper. I have have been diligently working on the Pursue question for chapter 11 that requires the script to guarantee unique usernames in register.php Here is my script. I just can't figure out what I am doing wrong and why this won't work for me. I have modified it so many times! Here is what I have right now. This is what is being returned with this script: Register You are now registered! Warning: fgetcsv(): 3 is not a valid stream resource in C:\xampp\htdocs\registerpursue.php on line 55 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Register</title> <style type="text/css" media="screen"> .error { color: red; } </style> </head> <body> <h1>Register</h1> <?php // Script 11.6 - register.php /* This script registers a user by storing their information in a text file and creating a directory for them. */ error_reporting(E_ALL); // Identify the directory and file to use: $dir = '../users/'; $file = $dir . 'users.txt'; if ($_SERVER['REQUEST_METHOD'] == 'POST') { // Handle the form. $problem = FALSE; // No problems so far. // Check for each value... if (empty($_POST['username'])) { $problem = TRUE; print '<p class="error">Please enter a username!</p>'; } if (empty($_POST['password1'])) { $problem = TRUE; print '<p class="error">Please enter a password!</p>'; } if ($_POST['password1'] != $_POST['password2']) { $problem = TRUE; print '<p class="error">Your password did not match your confirmed password!</p>'; } if (!$problem) { // If there weren't any problems... if (is_writable($file)) { // Open the file. ini_set('auto_detect_line_endings', 1); $open = fopen("$file", 'a+'); //opens my data file while ($line = fgetcsv($open, 200, "\t" )!== FALSE) { //breaks my string from $file into parts $n = count($line); if ($_POST['username'] == ($line[$n])) {//checks to see if user entered data matches what's in the text file $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement break; } fclose($open); // Create the data to be written: $subdir = time() . rand(0, 4596); $data = $_POST['username'] . "\t" . md5(trim($_POST['password1'])) . "\t" . $subdir . PHP_EOL; // Write the data: file_put_contents($file, $data, FILE_APPEND | LOCK_EX); // Create the directory: mkdir ($dir . $subdir); // Print a message: print '<p>You are now registered!</p>'; } } else { // Couldn't write to the file. print '<p class="error">You could not be registered due to a system error.</p>'; } } else { // Forgot a field. print '<p class="error">Please go back and try again!</p>'; } } else { // Display the form. // Leave PHP and display the form: ?> <form action="registerpursue.php" method="post"> <p>Username: <input type="text" name="username" size="20" /></p> <p>Password: <input type="password" name="password1" size="20" /></p> <p>Confirm Password: <input type="password" name="password2" size="20" /></p> <input type="submit" name="submit" value="Register" /> </form> <?php } // End of submission IF. ?> </body> </html> Link to comment Share on other sites More sharing options...
Jonathon Posted November 21, 2011 Share Posted November 21, 2011 http://www.phpbuilder.com/board/showthread.php?t=10276226 Maybe? I don't know I haven't read all your code. Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 21, 2011 Author Share Posted November 21, 2011 Yes - that is exactly what the problem was! Thanks! I still can't get the script to recognize a duplicate user name though! I just don't know what I am doing wrong.... I feel like I've tried every method..... Link to comment Share on other sites More sharing options...
lingolatz Posted November 21, 2011 Share Posted November 21, 2011 First thing I saw was the '!==' for this condition: $open = fopen("$file", 'a+'); //opens my data file while ($line = fgetcsv($open, 200, "\t" )!== FALSE) { As for the rest of your code (put together)... $open = fopen("$file", 'a+'); //opens my data file while ($line = fgetcsv($open, 200, "\t" )!== FALSE) { //breaks my string from $file into parts $n = count($line); if ($_POST['username'] == ($line[$n])) { $problem = TRUE; print '<p>That username has been taken, please try again</p>'; break; } fclose($open); Break down: line 1: You do not need a+, although Mr. Ullman says it is most forgiving, you can get by with r. If you used a+ to be less restrictive to debug, that is understandable, but if that is the case, then you should have also appended a 'b' (binary). Regardless of what you use, I would recommend appending the 'b'. line 2: Problem mentioned above. Also, if you look at your code $line = fgetcsv($open, 200, "\t" )!== FALSE You are saying that $line is being assigned to fgetcsv($open, 200, "\t"), which is a TRUE statement (all assignments are true). Then you are using a comparative operator (!= or ==, I cannot tell) for a TRUE statement against FALSE. So say you were using !=, you are saying TRUE is not equal to FALSE, a true statement, so the '!= FALSE' would be redundant? And say you were using ==, you are asking if TRUE is equal to FALSE? My working code does not include the != or == FALSE part. Line 3: You assign $n to the amount of values in the array $line (whose values are the username, password, and subdirectories of a user, separated by tabs). Therefore, $n would be equal to three, yes? I will refer to this line while breaking down line four. Line 4: This is where you start checking if the value that you just read from the file is equal to the value submitted by the user, by using an if statement. You compare $_POST['username'] with $line[$n]. $_POST['username'] is pretty much out of our hands; we cannot control what it is equal to. But you are using two variables with $line[$n] - $line and $n. Think about what these values are equal to. To be honest, this was one of the most confusing pieces of the code to me. $line is an array assigned values of 200 bytes (or till the end of the line) of a line. The line may contain something like this: lingolatz 0ea4a0db010efd4ed3ca4ebee723b65c 13217357292811 So $line[0] would equal lingolatz, $line[1] would equal 0ea4a0db010efd4ed3ca4ebee723b65c, and $line[2] would equal 13217357292811. As mentioned earlier, $n is equal to three (unless you included more items in the users.txt file). Therefore $line[$n] is equal to $line[3], and that does not even exist. Can you tell, now, what should be used to be compared to $_POST['username']? You also use extra, unneeded parentheses to surround '$line[$n]'. The rest of your code has no problems as far as I can tell. 1 Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 21, 2011 Author Share Posted November 21, 2011 Thank you lingolatz! This helped immensly - however, I am still a little unclear when trying to follow your direction on the Here is what I have based on what you stated.... <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Register</title> <style type="text/css" media="screen"> .error { color: red; } </style> </head> <body> <h1>Register</h1> <?php // Script 11.6 - register.php /* This script registers a user by storing their information in a text file and creating a directory for them. */ error_reporting(E_ALL); // Identify the directory and file to use: $dir = '../users/'; $file = $dir . 'users.txt'; if ($_SERVER['REQUEST_METHOD'] == 'POST') { // Handle the form. $problem = FALSE; // No problems so far. // Check for each value... if (empty($_POST['username'])) { $problem = TRUE; print '<p class="error">Please enter a username!</p>'; } if (empty($_POST['password1'])) { $problem = TRUE; print '<p class="error">Please enter a password!</p>'; } if ($_POST['password1'] != $_POST['password2']) { $problem = TRUE; print '<p class="error">Your password did not match your confirmed password!</p>'; } if (!$problem) { // If there weren't any problems... if (is_writable($file)) { // Open the file. ini_set('auto_detect_line_endings', 1); $open = fopen("$file", 'r'); //opens my data file while ($line = fgetcsv($open, 20, "\t" )) { //breaks my string from $file into parts $n = count($line); if ($_POST['username'] == ($line[0]){ $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement if($_POST['password1'] == ($line[1]) { $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement if($_POST['password2'] == ($line[2]) {//checks to see if user entered data matches what's in the text file $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement break; } } fclose($open); // Create the data to be written: $subdir = time() . rand(0, 4596); $data = $_POST['username'] . "\t" . md5(trim($_POST['password1'])) . "\t" . $subdir . PHP_EOL; // Write the data: file_put_contents($file, $data, FILE_APPEND | LOCK_EX); // Create the directory: mkdir ($dir . $subdir); // Print a message: print '<p>You are now registered!</p>'; } else { // Couldn't write to the file. print '<p class="error">You could not be registered due to a system error.</p>'; } } else { // Forgot a field. print '<p class="error">Please go back and try again!</p>'; } } else { // Display the form. // Leave PHP and display the form: ?> <form action="registerpursue.php" method="post"> <p>Username: <input type="text" name="username" size="20" /></p> <p>Password: <input type="password" name="password1" size="20" /></p> <p>Confirm Password: <input type="password" name="password2" size="20" /></p> <input type="submit" name="submit" value="Register" /> </form> <?php } // End of submission IF. ?> </body> </html> You also said I have an unneeded parentheses to surround '$line[$n]'.... ($_POST['username'] == ($line[$n])) Isn't that correct syntax? The parantheses surrounds the whole thing and then opening and closing ones for ($line[$n])? Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 21, 2011 Author Share Posted November 21, 2011 or maybe this would be better...Still gives me an error Parse error: syntax error, unexpected T_VARIABLE in C:\xampp\htdocs\registerpursue.php on line 59 - but is this more on the right track? ini_set('auto_detect_line_endings', 1); $open = fopen("$file", 'r'); //opens my data file while ($line = fgetcsv($open, 20, "\t" )) { //breaks my string from $file into parts $n = count($line); if ($_POST['username'] == ($line[0] $line[1] $line[2])){ $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement break; } } fclose($open); Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 21, 2011 Author Share Posted November 21, 2011 Well - that didn't make sense either! I don't want the username compared to the passwords... So then I tried this... And my script worked without errors, but I am still able to enter duplicate usernames.... HELP! ini_set('auto_detect_line_endings', 1); $open = fopen("$file", 'r'); //opens my data file while ($line = fgetcsv($open, 20, "\t" )) { //breaks my string from $file into parts $n = count($line); if ($_POST['username'] == ($line[0])){ $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement } break; } fclose($open); Link to comment Share on other sites More sharing options...
Larry Posted November 21, 2011 Share Posted November 21, 2011 Hello April, I know you're working very hard to figure all this out, and that's quite admirable. But it would seem that the very best debugging technique you should apply is to step away from the computer. When you're really working on something, and it's all jumbled in your head, it can be hard to see the forest for the trees, and changes you make under those conditions often exacerbate the problem rather than solve it. My second piece of advice would be for you, when you are in front of the computer, to apply "rubber duck debugging": get a rubber duck, set it in front of the computer, and explain to it what each line of code is doing. By doing so, you'll be able to reassure yourself as to what's correct and hopefully catch what doesn't make sense. From the messages you've posted in these forums, I really, really think you'd benefit from picking up both habits. In terms of this particular bit of code (the last bit you posted)... - you shouldn't put $file in quotes in your fopen() line as that's entirely unnecessary. - there's no need to assign the count() of $line to $n, as $n is not used. - to debug this, add this code before your loop: print " username = -{$_POST['username']}-";This confirms the value received from the form. Then, immediately within the while loop, add this: print " line[0] = -{$line[0]}-";This confirms what the value of $line[0] is within the loop for each stored item. The use of the - before and after the value will reveal whether there are extra spaces involved or not. Remember that using print statements to verify what the exact values of variables are is one of the most important debugging techniques. 1 Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 21, 2011 Author Share Posted November 21, 2011 Hi Larry - Thank you for your advice. I did apply those debugging techniques. I found that username is correct. I also found that $line is returning the first word in my text file - so it really not "looping" through the text file to find matches. That is helpful information. So the question is - how do I get things to loop through - I thought that is what my count() was doing. Can you direct me that way? Link to comment Share on other sites More sharing options...
Larry Posted November 21, 2011 Share Posted November 21, 2011 No, your count() wasn't doing anything useful at all. I suspect the problem is in the use of 20 for the second argument of fgetscsv(). I'm not sure why you're using that value or where you came up with it, but you should reread p 327 or the PHP manual's page for fgetscsv(). Also, for future reference, it would be beneficial to those trying to help if you had included, for example, the results (i.e., output) of the debugging code I just recommended. I *think* I know what you're saying, but my advise here is based upon an interpretation of what you mean, not on the actual results. Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 21, 2011 Author Share Posted November 21, 2011 I am a little closer think. I used this code ini_set('auto_detect_line_endings', 1); $open = fopen($file, 'r'); //opens my data file while ($line = fgetcsv($open, 200, "\t" )) { //breaks my string from $file into parts if ($_POST['username'] == ($line[0])){ $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement } break; } fclose($open); This code was debugged and I ran the form, I rec'd this as the return... That was telling me that it wasn't looking throughout the text file and was only looking at just the first word in the text file. line[0] = -April- You are now registered! Then Larry I have been practicing your debugging techniques and I read through the chapter on arrays again. Here is the code I have written... ini_set('auto_detect_line_endings', 1); $open = fopen($file, 'r'); //opens my data file while ($line = fgetcsv($open, 200, "\t" )) { //breaks my string from $file into parts for($n=0; $n <= count($line); $n++) { if ($_POST['username'] == ($n[0])){ $problem = TRUE; print '<p>That username has been taken, please try again</p>'; //if above is true, print this statement } } break; } fclose($open); The problem is that - it is not recognizing unique usernames. I can enter april in as my username 100 times and it will always tell me that I've been registered. When i debugged this using this line print "<p>line[n] = -{$line[$n]}-</p>"; My output was this. (the notice is a repercussion of this line print "<p>line[n] = -{$line[$n]}-</p>"; so I'm not worried about that. So from this debugging - I am getting the feeling that it's not scanning my entire text file. It's only scanning the first line. Register line[n] = -April- line[n] = -2a2d595e6ed9a0b24f027f2b63b134d6- line[n] = -13214649081347- Notice: Undefined offset: 3 in C:\xampp\htdocs\registerpursue.php on line 59 line[n] = -- You are now registered! So my question is - how do I get this script to read and scan every word in the text file? that is what I thought i was doing with the for loop - but it's not doing that.... It only took the first 3 words. I really don't mean to keep bothering the forum lines, but I really do want to understand this..... Link to comment Share on other sites More sharing options...
Larry Posted November 21, 2011 Share Posted November 21, 2011 Okay, a couple of debugging options here: for($n=0; $n First of all, I'll just say outright that you can't do $n Now, just after that you have: if ($_POST['username'] == ($n[0])){ If you apply "rubber duck debugging" to that line, tell me about the $n variable: what it is, where it comes from, what kind of value it will have. Or you could have the PHP script tell you exactly what $n is by doing: print " n = -{$n}- ";just before that line. You could also look at your code. Previously you used this and it worked: print " line[n] = -{$line[$n]}- ";But now you're using this, and it doesn't work: if ($_POST['username'] == ($n[0])){ What's different? Finally, going back to "rubber duck debugging", how about explaining to me why you want to loop through each word in each row? What is the value of that? Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 22, 2011 Author Share Posted November 22, 2011 Hi Larry - I took a break like you said, and I feel like I'm so close! But...... This script returns about 100 lines of This username is already used. Please enter a unique username! But that's because I've been entering 'april' for the last 100 times I've been testing the script. I tried a new name and the first time I entered the name it said that I've been registered, and the second time it told me This username is already used. Please enter a unique username! You are now registered! So it's returning two of my statements that contradict each other. This is further than I've ever gotten before - because I could never get it to return that at all - but why is it repeating? I have the break; for the while Also I did this print "<p>line = -{$line}-</p>"; and found that line = -Array-. I don't even know what that means - but I think that's good - because then my text file is now in an array, but it's not split by the delimiter like I want. So to sum it up - it seems to be returning the message This username is already used. Please enter a unique username! for as many times as that name is entered and it also contradicts that message at the end by saying You are now registered! <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>Register</title> <style type="text/css" media="screen"> .error { color: red; } </style> </head> <body> <h1>Register</h1> <?php // Script 11.6 - register.php /* This script registers a user by storing their information in a text file and creating a directory for them. */ error_reporting(E_ALL); // Identify the directory and file to use: $dir = '../users/'; $file = $dir . 'users.txt'; if ($_SERVER['REQUEST_METHOD'] == 'POST') { // Handle the form. $problem = FALSE; // No problems so far. // Check for each value... if (empty($_POST['username'])) { $problem = TRUE; print '<p class="error">Please enter a username!</p>'; } if (empty($_POST['password1'])) { $problem = TRUE; print '<p class="error">Please enter a password!</p>'; } if ($_POST['password1'] != $_POST['password2']) { $problem = TRUE; print '<p class="error">Your password did not match your confirmed password!</p>'; } if (!$problem) { // If there weren't any problems... if (is_writable($file)) { // Open the file. ini_set('auto.detect_line_endings', 1); $open = fopen($file, 'r');//Check if username is duplicate: while($line = fgetcsv($open, 500, "\t")) {//Loop through the file: for($n=0; $n < count($line); $line++) { break; }//End of For if( ($line[0] == $_POST['username']) && ($line[0] == $_POST['username'])){ print '<p class="error">This username is already used. Please enter a unique username!</p>'; } }//End of while fclose($open); // Create the data to be written: $subdir = time() . rand(0, 4596); $data = $_POST['username'] . "\t" . md5(trim($_POST['password1'])) . "\t" . $subdir . PHP_EOL; // Write the data: file_put_contents($file, $data, FILE_APPEND | LOCK_EX); // Create the directory: mkdir ($dir . $subdir); // Print a message: print '<p>You are now registered!</p>'; } else { // Couldn't write to the file. print '<p class="error">You could not be registered due to a system error.</p>'; } } else { // Forgot a field. print '<p class="error">Please go back and try again!</p>'; } } else { // Display the form. // Leave PHP and display the form: ?> <form action="registerpursue.php" method="post"> <p>Username: <input type="text" name="username" size="20" /></p> <p>Password: <input type="password" name="password1" size="20" /></p> <p>Confirm Password: <input type="password" name="password2" size="20" /></p> <input type="submit" name="submit" value="Register" /> </form> <?php } // End of submission IF. ?> </body> </html> Link to comment Share on other sites More sharing options...
phpRob Posted November 22, 2011 Share Posted November 22, 2011 This is the code I used, I didn't read this post at all and thought 'd have a stab at it myself! It seems to work but as always are there any areas I coud improve on Larry? By the way I'm also learning from the book and I'm at the exact same position of the book as you April. Like Larry said it is smetimes best to step away from the computer and just think about the logic in plain english, I did this with this exercise after getting myself into a pickle and finally worked it out (I think!) <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Register</title> </head> <style> .error { color: red; } </style> <body> <?php //Identify directory and file to write to $dir = '../users/'; $file = $dir . 'users.txt'; //Set flag $problem = FALSE; //Handle form if ( ($_SERVER['REQUEST_METHOD'] == 'POST') ) { //Validate Username if ( empty($_POST['username']) ) { print '<p class="error">Please enter a username</p>'; $problem = TRUE; } //Validate Password if ( empty($_POST['password']) ) { print '<p class="error">Please enter a password</p>'; $problem = TRUE; } //Validate Password if ( ($_POST['password'] != $_POST['password1']) ) { print '<p class="error">Please make sure passwords match</p>'; $problem = TRUE; } ini_set('auto_detect_line_endings', 1); //Open file $fp = fopen($file, 'rb'); //Read file while ( $line = fgetcsv($fp, 200, "\t") ) { //Check for username pairs if ( $line[0] == $_POST['username'] ) { $problem = TRUE; print '<p>Username already exists, please choose another username</p>'; break; } } fclose($fp); //If fields are valid if ( !$problem ) { //Is file writable if ( is_writable($file)) { //Create the data $subdir = time() . rand(0, 4999); $data = $_POST['username'] . "\t" . md5(trim($_POST['password'])) . "\t" . $subdir . PHP_EOL; //Write the data file_put_contents($file, $data, FILE_APPEND | LOCK_EX ); //Create Directory mkdir($dir . $subdir); print '<p>Thankyou, you have been successfully registered</p>'; } else { print '<p class="error">Error writing to file</p>'; } } else { print '<p class="error">Please enter a valid username and password</p>'; } } else { //Display form ?> <form action="register.php" method="post"> <p>Username: <input type="text" name="username" size="20" /></p> <p>Password: <input type="password" name="password" size="20" /></p> <p>Confirm password: <input type="password" name="password1" size="20" /></p> <p><input type="submit" name="submit" value="Register" /></p> </form> <?php } //End of IF statement ?> </body> </html> Link to comment Share on other sites More sharing options...
AprilSwenby Posted November 22, 2011 Author Share Posted November 22, 2011 Yes! That worked for me too! So it seems I had it right at one point - but just had it in the wrong place! How frustrating! I've been working on this for over a week now.... Thank you so much for pointing that out to me. Link to comment Share on other sites More sharing options...
phpRob Posted November 22, 2011 Share Posted November 22, 2011 Got there in the end eh April MySql and databases next, scary... Link to comment Share on other sites More sharing options...
Recommended Posts