PHP Projects: How to Create a Secure, Session-Based Login Script | John Morris | Skillshare

PHP Projects: How to Create a Secure, Session-Based Login Script

John Morris, I help freelancers get clients.

Play Speed
  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x
5 Lessons (2h 7m)
    • 1. Welcome & Introduction

    • 2. Create a Simple, No Database Login

    • 3. Create an Advanced, Database-Driven Login

    • 4. Add In a Remember Me Feature

    • 5. Create a Secure Password Reset


About This Class

You'll learn how to create a secure, session-based login system in PHP. There's two versions: 1) a simple non-database version we'll create first to quickly over all the base concepts. Then 2) we'll convert that into full-fledged database-driven login script complete with:

  • Secure, session-based user access
  • User registration
  • Remember me feature
  • Email-based password reset
  • Cryptographically secure tokens
  • SQL injection prevention
  • Install script

And more.


This is an advanced course. The topics covered here assume a certain level of PHP knowledge. It's frankly only a small percentage of developers in the world who know how to do this properly. I strongly recommend you take my PHP 101 course BEFORE taking this one. Only jump into this when you're ready to challenge yourself and take your PHP skills up a notch.

Comes with full source code in the Class Project section.


1. Welcome & Introduction: Hey there, John Morris Here, John Morris online dot com. So I want to be real quick what you're going to learn in this course, So you're going to learn how to build a I would say fairly advanced log in script. So this log in script, of course, is run by sessions. You'll see it has a remember me feature here fully functioning. Remember me feature. So if someone checks this on and they close their browser and come back, it will remember them and they'll still be logged in, even though, because we're using sessions closing the browser destroys the sessions. We use cookies to help get them log back in. Remember them? You could see it here. Has a registration will talk about. There's easy ways, toe toe, add fields and so forth. We have password reset along with it so you can have ah, password emailed. Have them reset. So it's a It's a fairly fully functioning log in script, and we're gonna walk through kind of how to settle this up, all the code securing all of this stuff because we start talking about Remember me feature and a reset password feature. Those things are pretty sensitive in terms of being able to secure those. We'll talk about making sure those air cryptographic Lee secure. We'll talk about now, inserting all this stuff in the database, how to create the database for this sort of thing. There's an install script as a part of this that will take a look at and just really break it all apart, show you how to do it. And and like I said, this is a fairly advanced ah sort of form here. So this is something that you can learn how to do. And if you if you really nail this down, I mean, this is this is not something that every coder and out there knows. I would say it's probably, I don't know, 10% 20% maybe of people out there that really understand how to do this So you can really set yourself apart. Ah, in a big way with knowing how to do this. So again, we're going to dig into all that. I'm gonna show you how to build a wall, how to secure it. Ah, and how to make it all work. That's what's in this course. Ah, I'm sure there's an enroll button or or something around here somewhere. So go ahead and click that, and I'll look forward to seeing you in the course. 2. Create a Simple, No Database Login: Hey there. John Morrissey, John Morris online dot com. This lesson. I'm gonna walk you through the simple version of this log in form. So this is Ah, this would be something that you're not going to distribute. Maybe more used for internal sort of things. And, you know, you just want to don't have toe don't wanna have to worry about database and all that sort of thing. You just wanna have a simple kind of log in script that then you can just put kind of whatever content you want in there for logged in users. You may be the only logged in user. You may have a few people. It's really up to you. You can add more users, but again, it's just a simple, non data based version of a log in script. So let me just show you this real quick. I have ah, password, pretty name and password here, and actually, I do need to change some right there. But we'll do that when we get in here. So if we hit submit, you can see what I come to. A simple screen that says, welcome John Morris. And then it s so it has my name and knows who I am and then has this click here to log out links. So this is where you could I just have really simple in here, but I'm showing that you can actually grab some user data. So it knows who I am, and I'm logged in. If I kind of reload this page, you know, it still is going to recognize that I'm logged in, and then I just have a simple log out link here. So if I click here to log out says you are now logged out and if I go back here Ah, this is actually the home page. So this is index dot PHP and is bringing up the log in screen again. So I'm sure you have all that works, but that's essentially what the script does. If I put in just some gobbledygook for ah, name and pastor and try to submit it, you can see I don't get logged in. And if I try to refresh this page to get back in, I can't get back in. Okay, so it's a simple idea here. Now let's kind of jump over and see all the code behind this. So like I said, this is a non database log in script. So where we actually keep the user's data is in a conflict file. And so this is essentially I've just created in ah array and the kind of a global Natan space here called users. And in it I have the user name, the password and the name. So just some simple data. You could, of course, add whatever data you wanted to this and it be just fine. You can also, if I just kind of copy this and copy Paste and let's just change. Let's just add a new user here. So, Dawn Juan, we'll enter all this year and we'll save that. And if I come back over here and now, I log in with my Don Juan user name and hit submit. Now it knows that I'm Don one, and I'm I'm logged in so you can easily add new users to this again, not using a database, and you might be wondering about saving these user names and passwords in a PHP file like this. It's perfectly fine, because if they if they got there, they can't view this conflict file directly there, right? There's no way to do that. Servers all protect against that sort of thing. Because if they got access to your coat, even if you were, let's say, storing these in a database and you were hashing you would still have to have your nonsense and all that sort of stuff state saved in your files. So if they get access to your code like this, then they can get they can get into anywhere that they want. So, ah, having him in plain text or not hashed here isn't any more, more or less safe. Ah, Then if we were to try and Hashem here and do all that sort of thing, that wouldn't make it any more safe because they would have the nonsense, um, or the salts. And they could just recreate. Ah, the hash anyway, So it's perfectly fine to do this for this particular ah scenario here, they're not going to be able to get access to this file. Ah, to be able to see these passwords and so forth. Right, So that's the conflict file. I'm gonna go ahead and close kind of shut that one out because we won't really be using that anymore. Um, our main file here is that kind of our handlers are index dot PHP and into it. We're requiring this low dot PHP and so in load. I've talked about this before, but I like thes load files because I can put all my require statements in this load file and then in every file where I need access to those I can just do this require once on load , and it loads all of the stuff that's in here instead of having to take all this stuff and put it at the top of here. So that's essentially what load does it's gonna load our conflict file. I just showed you. And then it's gonna load a file from our includes folder, which is actually our log in class that we're gonna be, ah, using here. So we'll get to that in a second. But that's what low does. I'm just trying to kind of go through the ones that we can kind of get rid of right off the bat. So Ah, that's low dot PHP. All right, so now we can kind of dive into this and show you the initial handler, so we have low dot PHP being loaded in, so that gives us access to our conflict file and to our log in class. And then we're basically need to do two things. So first off, we need to check if there is any sort of log in data that's been submitted. So if we need to check if that log in form has been submitted So we're going to check if Post data if If the request method is a post method. Basically, if a form has been submitted and if so, then the first thing that we're gonna do is we're going to pass the post data to this verify log in method in our log in class, and again we'll go through what that is. But we need to be able to handle those form submission. So that's essentially what this block a code is right here. It's handling the Loggins. Now you notice we're not redirecting or anything like that, and I'll show you why? Because we're gonna be using sessions. And that's one of the nice things about using sessions is we don't have to do a bunch of redirects and so forth. So ah, again, we were handling Loggins. We're going to check to see, basically, if we need to handle long, and if so, we're gonna handle it and then we're going to come back here and on every page load. We're going to verify the session. So essentially, what this does is it takes the session data. It checks to see if there's any set session data related to this user being logged. Man, we'll talk about what all that is here in just a second, but it's gonna check to see if that data exists. If it exists, that's going to check it against what we have in our conflict file. Make sure that it's not some wonky Ah, or there's some sort of attack or hack or anything like that. It's gonna check against what we have in our conflict file. And if there's a match, then if the user is really a user in our system, then it's gonna go ahead and allow this session to continue. And then based off of that, if if we verify the session, then we're going to include our home page, which is the one that said Welcome, John. Click here to log out that's our home page. And then if the user isn't verified, then we're going to include our log in dot PHP. So home dot PHP it says, Hey, welcome And then the user name and has the click toe log out here. This is actually included inside of index Stop PHP. So this index stop peach PHP is kind of a rapper for the whole system, and it's it's really a handler. Ah, and then, of course, if they are not authenticated, then we display our log and form here, and that's what this is. We'll get out all this in just a second. But what I want you toe understand about this particular page is that, um it is a it's handling Loggins, but be it's really it's It's a handler page, so index dot PHP really itself doesn't display anything All it does. Is it Zalkind like a point guard in basketball, it's directing traffic. And so it's it's saying, Was there ah, post emission. OK, do this and then once that's done. But if then we're gonna check and verify the user, the users verified that we're gonna load this page if the user is not verified. then we're going to load this page, okay? And so all of the actual pages that you're going to actually see display on are going to be included into this index dot PHP. Now, one thing about that, the reason I bring all this up is because if you wanted to create, let's say you wanted to create Ah, and saying about page or something like that then And you wanted to create a whole sort of new page right here. We're doing home or log in. Okay, so this is basically the home page. Let's say you wanted to create an about page. You would use this same handler. You would use all the same code, maybe get rid of the Loggins here and if ah, this this log in part here. But the handling the request here because I'll show you in the form of the second way. You could do that, but ah, you could probably get rid of this part. But you would still want this part. And in that case of saying about page, it would be about dot PHP or log and dot PHP. Okay, so every page that you create is going to verify the session and then either displayed the page that they're supposed to see or display the log in page. You could also you don't have to do an include of log in here. You could do. You could do, ah, header redirect to a log in page. So you have options with all of this stuff, and there's about 100 different ways toe to do this sort of thing. But this is the way that I've I've chosen to do that. So I just want to try and give you the bigger picture here for a second of the ways that you can change this and use this and so forth. So every page that you create is going toe to try and authenticate the use Earth using. Verify this verify session method, and it's either going to display the page of their verified or it's going to display, log in and or redirect them to a log in page. Um, if they're not verified, every single page that you created okay, with that out of the way, then we know this is the handler. We know that we're including logging a PHP. We have home dot PHP Let's go ahead and look at the the actual logic behind Verify, log in and verify session because those are the two main things here. All right, so this is our class class log in. We have this public. Ah, property for this called user. We'll talk about that here in just a second. Um and then we have our constructor method in our constructor. What we're doing is a were globalizing. Our users array from our conflict file member because it was created in the global scope. And so now we're inside of a function. We have to globalize it in here. And then what we're doing down here is basically capturing that so we don't have to globalize in every other function. We're capturing it as this property. Uh, this property called users, so that allows us to then use this property throughout the rest of our class. The other thing we're doing is starting our session because any time you want to use sessions, you have tow start the session at the highest point. Really? And in this case, this is pretty high up in our system. Moving, Remember, from our low dot PHP, we include the uh, the conflict file, and then we include this log in class. So this section is getting started basically right at because because it's in the constructor method. It's getting started basically right after the conflict file, which is fine. It just needs to be started before there's any actual output. Well, there's not gonna be out any output in the conflict file, so this works just fine. So we get our users of rail set for us to be able to use this again. Remember, this is our actual user names and passwords from our conflict file. We start our session. That's what we're doing in our constructor. And we're in stance, singing an instance of it at the bottom of this file. So basically, every page that this is included into you're going to instance, eat an instance of this class and then you're going to start your session, you're going to get your users rail set up. So you're basically primed and ready to work with this just by including it into ah, particular file. All right, so verify Log in. So what we did is we passed in our post data, so our post data is just a user name and password. So the first thing that we're gonna do is we're going to check and see if the user name and the password are actually set in that post data. And that's why we're using an or statement here. So if this one is, if the user name is not set or the password has not said either one is not set, we're just gonna return. False. And our session, our session data won't get created, and therefore they won't be. They won't be authorized as logged in, and they won't be able to access protected content. So, um, anything short of this session right here, essentially getting created is not going to allow them toe log in. So, uh, returning false appear makes it so they can't log in. Next thing we're gonna do is we have kind of we have, ah, kind of custom method here and essentially what this does. It's just like it's a lot like the in array function in PHP. Except what it does is it actually goes kind of one level deeper because of the way our Reyes set up. But essentially what this method is doing is it is checking the user name that was passed, and it's looping through our users array from our conflict file to see if that user name exists in our conflict file. That's what this method is doing. You can look down here to see how it does it, but I mean, as long as your users or a looks like the one that I have in the conflict file this functional work, just find. Basically, what is doing is it's just looping through the array first and then running in array on the elements inside of the array. So we look at our conflict file because it's a multidimensional ray. You have this array. It's a looping through each one of these needs. One of these is an array. So then it's checking this individual array right here to see if this user name exists. That's essentially what that that method is doing right here. And then it's going to, if it does exist, is going to return the actual item. So it's going to return all of its going to return this array right here, or if it matched this one. It'll, uh, return this one, and of course, if it doesn't match any, it's gonna return. False. So that's how we That's essentially how we off of in Kato Log in. We take the user name that was passed. If that user name exists, we grab that particular ah, user data that array of data right here and then what we do next is so we've returned that from this. So this is our array of data. The user name exists. So this is our ray about that particular user. And so we've stored that that as this user now, So this is that a ray data from the conflict file? And if that's not false because, ah, this method returns false if the user name wasn't found. So if it's not false, we know we have used that user name exists. And now what we're gonna do is we're going to check the password from our post data against the password from the that particular user in our conflict file. So we're just checking to see the passwords match, which, of course, makes sense. If the passwords match, then what we're gonna do is going to set a session very ill call variable called user name , equal to the user name that we got from our conflict file. So this is what we're This is the big thing that we're after here. Basically, if the user name what? What? All we're doing up to this point is checking to see if the user name exists in our conflict file in our users array. And if the password that was submitted in the form matches the password that we have in our conflict file for that user So again, that's what you would imagine that that you would do if it exists. And if all that matches, then we're setting this session variable so that we can now check to see if this session variable has been exists. When we verify our session down here because we verified the password now way don't want them to have to log in on every on every page load, right, because I would obviously be really annoying. So what we're doing is we're saving the user name is a session, and then we're just checking that going forward. And then, of course, were training True, in case we want to run anything off of this for displaying messages and self and Of course , if none of this if this fails, at some point, we're just gonna return. False. So again, verify. Log in. It's checking to see if the user name exists. It's checking to see if the password for that user matches. And if so, it's setting a session variable called user name, equal to the user name that was that was submitted, and that is in the conflict file. All right, so that's verify. Log in now that if we go back to index, that's why here all we need to do is mean t verify. The log in is run that, and we don't need to run any else, sort of. If else statements off of this, either. The when this verify log in runs, either that session variable is going to get created or it's not. And then from there, well, it's the same as every page load. Then we just verify whether that that session variable exists or not. And we we then include the proper ah template file. Based off of that. So handling Loggins is the whole point is just to create that session variable. Okay, so then we need to verify the session So what we do in verifying the session is again gonna be pretty straightforward. So what we do is we grab that session variable. The one we just created up here Session user name. So we grabbed that. Now, of course, if we try to grab this and it doesn't exist than all the rest of this is going to fail, Okay, so but we grab that that Ah, even we don't want to just check that this session variable iss set we every page load we want to check and make sure that it matches a user that's in our in our in our conflict file because it is possible that someone could just figure out a way to set session user name to true and then be ableto there's ways that people can get sort of around that now. Session variables, It's a little bit. It's a little bit more difficult, but we want to just add an extra layer of security here. So what we're doing is we're grabbing that session user name and then we're going to run it back through this in a ray. Are that same method from down here and check to see if that user name that's in that session Ah, variable matches what is in our conflict file? So every page load we're taking that session variable and we're checking it against what's in our conflict file so that we're making sure that it matches up and someone doesn't log in to their account and then try to go into there's ways that people can kind of hack around this if you don't do that. So again, we're just checking on every page load to make sure that the user that is we think is logged in is the one that is actually logged in the existing are, ah, our conflict file. And we're not going. We're only going to display their data. Okay, So when we verify the session and that user name does exist in our conflict file, so if that is not equal toe false right here, then we're gonna set this user the property of user equal to that user that we just pulled from our conflict file. So again, this is gonna have all that a raid data and then we're gonna return. True if that this the session is verified and false. If not now, this is important right here, because this is what gives us access to our data because we have set this to the property for this class. If we come back over to Index, you can see that we're setting right here, user equal to that property from our log in class again. Remember, we in stance in an instance of it down here and we set that to log in. So when you do that, you can access class properties this way right here. And what we've done is we've set that too. What was from the data we have in our conflict file after verifying the session? So we verify the session. Essentially big picture wise. We're verifying the session, verifying that the user name is valid. And then we are grabbing the data about that user, and we're storing it into this user variable right here so that we can access it on these pages here. Okay, so from that, if we now come over to home dot PHP and we're logged in, you can see that we're using that user variable right here to display the name. So that is what? When we display this name right here. That's what does that is all of that stuff Grabbing the data, verifying the session and then echoing it out right here, OK, And then last but not least, we have I've included some templates stuff in here. This is really, really simple sort of template stuff, so I wouldn't get too wrapped up on it. You can, quite literally the reason I wrote this the way that I did with the index file. And this being the handler and using includes all that sort of thing. The reason I did that is so that when you're building these pages right here the log in page, uh, the home page right here. You can build these pretty much like, just regular template files that you may have seen me do tutorials on before that you're used to meaning you can include a header. You can include a four footer. And you could include bootstrap into all of this. You don't have to worry about the actual log in system in terms of all of that, when it comes to how you're gonna template this out. So again, I've got a header and a footer. We can look at these real quick. I just made him really basic. Just got the doc type of the H smell tags, the head tag, basic head tag stuff. And again, if you've watched any of my template ing videos all the stuff that I talk about in there in terms of how to go about template ing would apply Ah, in here as well. Footer is really simple just closing those tags we go to style. Just some really basic styling here. Um, my recommendation is, if you're gonna go in and really template this out, I would just kind of get rid of all of this CSS and kind of rewrite the CSS from scratch. How How you want to and again Because of the way this is done, you can put whatever you want into these header files. You don't have to worry about the log in part of it. So that's what makes this part of it kind of important. And and handy is your not having to inject all of this stuff into your template files. You've really separated the log in logic from the template ing logic, and you could just template how you want and then you have access to this in these files. Here, these template files, you have access to this user variable, which is the main one that you need access to for displaying user data. And you could, of course, expand that user data as much as you want. All right, so that's Ah ah ah. Simple. Set up here for using this If you want to add again. If you want to add users to this, this is where you would do this again. This is something you would not distribute toe toe other people. This would be something that you're using for internal use that Onley You're gonna be seeing the code on your not giving this to other people. Or if you are giving it to other people, your It's like a friend of yours and your erasing this users array and then user names and passwords before you. You give it to them so they don't know what your user names and passwords are. All right. So Ah, that'll do it for this lesson. Thanks for watching. Talk to you next time 3. Create an Advanced, Database-Driven Login: Hey there. John Morrissey, John Morris online dot com. This lesson. I'm gonna show you how to create a little bit more of an advanced log in script, and this may be the one that you're a little bit more interested in. This would be something that you could redistribute. This is involving a database kind of more of the the advanced, complex, modern type log and script that you might imagine when you hear someone say log in script. So what I'm gonna do is I'm gonna go through the things that I have changed here because I What I did, just so you know, is I took this folder for the simple one, and I just completely copied it over into the all of all the files over into this advanced one. And then I only had to change a few things. So, for example, I want to show you we talked a lot about the index file last time. Well, the index file here hasn't actually changed. And that was one of the reasons why doing it this way is works really well is because we're just calling methods. And Aiken, you know, I can verify the log in and verify the session, however, want that's not going to change. So whether I'm using ah, text file or I'm using a database, none of this stuff sort of changes. So there's a lot of stuff that we didn't have to change here. So I'm gonna go through the stuff that that did change. Now the first sort of big one that's going to have changed is the conflict file. And that's because we're no longer putting creating our users array in here and storing our user names and passwords in the conflict file. We're gonna be storing them in a database. So here, this is probably more like a regular conflict file that you might see. Where has the database details in here. So we have the user name, the password, the database name, the database host, and then the character set. And then along with that, I'm gonna go ahead and close that because we really won't be talking about that too much anymore. Um, also have this load file, and in it I have conflict up PHP, and now I have a new one to class db dot PHP and then to log in dot PHP. So we had confident log in before. Now we've added this db dot PHP Because we're going to be interacting with the database that classes right here. This is a PDO based database class that I've actually written. Um, I've done tutorials and written on and so forth in other courses and so forth. You're obviously gonna get this with the source code that you get. I'm not going to be going through this database in in depth, mainly because it's not really necessary for what we're doing here. This database class just works. I'll show you how to use the database class or how we're using it throughout our log in script. But I have full other tutorials where I talk about actually writing a database script. So if you're interested in that, I would go check those out. So ah, again, class dash db dot PHP Again, I'm gonna close this because we're not going to really talk a ton about it. Like I said confit, the DB class, the log in class. So I'm gonna close this because we're not going to really talk about it much anymore, and so we're kind of starting to get down to just a few things. Ah, left here. So the two main things that we changed our this verify log in in this verify session method . And then we added, Ah, register method here. So we hop over to the front and just show you this real quick. So I don't have gone through and deleted all of the users. I was doing some testing. There's no users in the database right now, actually. Can show you that real quick. We go to users. There's nothing in here. Okay, so we obviously wouldn't be able to log in here. So I've added this link on the log in page that says Register here and that takes us to this registered at PHP page. And so just go ahead and enter my details here, and we'll do the password is Morris and will hit cement. So says count created successfully. No one can go log in here and will do John and Morris. And you can see we're logged in here. And if we go to the database now, we go to users. You can see we have a user. Ah, user named John The password. The password is hashed we have our name. So we're getting records in here. Now, if I log out here and go to register again and let me just try and use that same user name and register, it says that user name already do this. So we got some basic checking Teoh, see if user names already exists. We got adding records to a database being ableto log in, then using that information, hashing passwords, all that sort of thing. So that's what I'm gonna basically show you here in this. All right? So as I said, the main things that we changed our verify log in and verify session. But in order to get to that point, we have to do some some sort of a little bit of back work. So the first thing that we need to do is actually over here in PHP my admin, which was to create our database. So if we go back here and we go to just go home and we click on databases now, if you're if you're doing this on ah, remote Web server, you probably have to go in, see panel. And there's a way to do that in C panel you can just, of course, do that. Um, but you can also do it from right here inside PHP in my admin. But you can see right here under databases. It says create database. So I just typed in log in. I set the collation. Teoh ut utf eight MB four underscore. Been? I believe it. Waas Yeah, right here. This right now, As of the time I'm recording, this is the kind of the recommended generic one. Um, but this the the time that I've been doing this, this sort of thing has tended to change. So depending on when you're watching this, I would just go and kind of Google what the sort of standard collation should be. There are exceptions of that. You notice there's different, um, languages and stuff here. So if you're gonna be using primarily with a certain language that maybe you would consider using Ah, some of those. But again, I would just look it up. I hesitate to tell you to use a particular one simply because in my experience, I've seen this kind of fluctuate and change and so forth, so I would just look it up. But in any case, you just type the name of the database and hit create. And so once you have the database, then that's when you can go over to your conflict file and you can put in the name of the database and then on a remote server, you'll have ah, user name and password that you create when you do that as well. So you can put that information in here once you've done that, then I created you need You've got the database, but I need to create the table with the fields and so forth. And so I created an install script here. So once you have your database details set in your conflict file, then we're gonna include the conflict file in the database class. And you could just load this page so you can just go to slash install dot PHP and load this page, and it will go ahead and create the table for you. Course. If you want to create it manually, all the information is in here. You can do that inside of PHP. My admin. Once you go into a database, um, then you can go in and create tables so create table right here put the name of the table, the number of columns it go and it would have let you enter all that information and you've got all the data here. So I d the name of this one is I d. It's an int unsigned auto. So it tells you all of the information right here for each one if you want to create it manually. In any case, Ah, if we go to once, it's all done. If we go to installed at PHP so it's only gonna created fit doesn't exist. We can kind of go back here. This is what is going to return. It's going to describe that table that users table that we just created. So you'll know when you go to this install script if it was actually created or not. All right, so then once you've got it installed, if you do using this sort of remote or whatever, then ah, I would go ahead and get rid of this install script. It's not necessarily gonna hurt anything because, um, we're not taking any sort of user input. And, um, you know, we're only creating the table if it doesn't already exist. But you are kind of putting your database structure out there for everybody to see. And I'm of the opinion too. Give people as little information as possible about my stuff. So, um, again, I would I would delete this offer there. All right, so with that said, we get rid of that. And now we've got So now we've got a database created. We've got our tables. Now all we need to really do, is we. First, we need to allow people to register, and then we need to change the way we verify our Loggins and our sessions to match what we have in the database. So go to registered up PHP. We've got a pretty standard form here, I would say so. We're putting in our load file here. So we have access to all of our our conflict file in our database class and our log in class. And then we're doing the same thing we did before and actually have Loggins here. This should be handled. Hey, can see. I just copied it straight over handle registrations, registration. And then we change this to register status. But we're just calling the method log in register. So before we were used on the log in page we're using. Ah, the well, actually, on the index page week. Um, right here we were using Verify Log in. I basically just copied this over here and changed it to register. So we're gonna call this register method, which we are adding to our log in class. We'll get to that in a second. Ah, we have our header included. The form is pretty standard. The only thing that's really different is the action. Instead of submitting to index, stop PHP because index dot PHP is what handles are Loggins. We're going to submit this to itself. So we're just gonna leave the action blank in this formal submit to itself and then we're going to use the post method. Ah, we have a sort of ah, status message here will kind of get to that in just a second. It doesn't really make sense until, you know, understand what's new in the class. But the field A so far as the form, the fields are all pretty much the same. Except we've added this field for full name since we're registering. And that's one of the fields that we want to collect. So where's before on the log? Inform you only asking for the user name and password because that's all you need to log them in here when they register. We're also asking for their full name so that we have that data. Now, of course, the more data you want to collect and be able display in your kind of members area your ad Maneri or there you're logged in area. The more you would ask for information here, and you have to change your of course, your database to be able to store that data and so forth. But I think you kind of get the idea here. This this form is really pretty much the same as the log in form. Um And then we added a link down here to the log and form here. So when someone submits this form, what's gonna happen is it's gonna trigger this if block right here, because that the request method will have been post and is gonna pass the post data to this register method that we added over here in our ah, log in class. All right, so let's go ahead and take a look at that register method. So what we're doing with the register methods were grabbing our were passing in our post data. The first thing that we're going to do is we're gonna check and see if the user name that was passed in on a registration form already exists because we can't really do anything if it already exists. So I created this helper function or help her method called user exists. And so if we come down here, well, and in that we were gonna pass in the user name that was submitted in our post data. So what we do down here is we just run a simple query to our database, and we're gonna select all of the information from our users table where the user name equals the user name that was passed in. Now, this get results method here is specific to this database class that I wrote, and it allows you this does use prepared statements, and so it allows you to use prepared statements without without actually having to ah, right. All of the binding and the executing and the preparing and all that stuff yourself. The database clip class handles all of that. And so basically, what you pass into the dates based class is your query with your placeholder in it. So that's right here and then the actual array of data to fit into. So this used this element. User name matches up to this place holder, and it will pass in this data. Using prepared statements will bind it correctly and all that. So really handy makes this a lot easier to run prepared statements. Inquiries this way helps abstract that from actually being in this this log in class. So what this is going to give us back is the results of this are going to be, Ah, it's going to be, ah, an array with Are you all of our user data? So it's going to be we go to users. It's going to be an array with this data, the i d. The user name, the password and the name. And so since we are already running that query instead of just returning tour false, where we're actually going to do our database class, we look at the get results method. If there are results, is going to return results. But if there's not, it's just gonna return. False. So what we're gonna check for here is to make sure that false isn't what was returned from that query A false was returned. Then we're gonna skip this block essentially, and we're gonna return false down here. However, if it was not false, then we're going to return the user. And this is a little quirk of this because this is the get results method. It actually puts the results into an indexed array. Now, in this case, there's only gonna be one element because there's only one user whose and user name is gonna match this user name. So there's only one element in the array. So we have to return the element at zero Index. So it's a little bit of a quirk, but it's not really a huge deal here. So we're gonna return that user data using this user exists block. So because we're already running the query, we're going to just kind of save ourselves a little bit of performance and just gravel the data because we're gonna need it anyway, Um and so that's what we're doing here. So again, this returns false. If the user ah does not exist So if the user doesn't ah, if it if it does, If the user does not equal false meaning that basically the if the user exists that already exists, then we're going to return this array with the status of zero, which means basically is for false and say this user name already exists. I'll show you where we're going to use these messages here in a second. But in this particular method, instead of just returning to her false because we have multiple things that could happen, the user name could already exist. The count could be created successfully or there could be some sort of unknown air. Because we have multiple things and we don't we won't know exactly which one. We can't really just return to her false If we want to display useful status messages and in particular this one right here, we want to be able to tell them that you use your name already exists. So we were going to return and said, just returned false. We're going to return an array that says, Hey, it didn't work and then gives a message that we can use right? So if the user name exists we're going to return that. However, if it doesn't exist, then we'll continue on here and we're gonna go ahead an insert that user into the database . So we're using the insert method from the database class. We're gonna insert it into the user's table we're in. Insert the into the user name field. We're gonna insert the post data from the user name. Now again, Remember these these database class methods that database class does the prepared statements for you. So I'm not I'm not putting in a new escaped un prepared data here may look like it here because I'm not doing anything, um, passing post user names straight into this method. But this method does all of that fourth okay, so they can put passing the user name into the user name field. The password were running password hash. So this password has is the hashes of built in PHP function that we have now that works really, really well. I strongly recommend you use it over anything that you may have ever seen in the past me or anybody else to do. This is the latest and greatest way to patch hash passwords. And because it's a built in PHP function. PHP as it upgrades and updates, is going to continue to do all the things necessary. Toe hash this properly so we don't have to worry about it. And so we pass in the password that the user entered when they submitted the registration form, and we use this algorithm password default. I I want to really recommend to you, unless you really have a good reason. Solid reason. Know why exactly? I want to recommend that you use password default because password default is going to use the latest and greatest algorithm PHP again as it upgrades is going to use the best algorithm available. So this will basically ensure that you are always using the best algorithm toe hash, a password instead of you having to figure it out. You can just let them handle that, so use password default that's gonna hash the password for us, and then we're gonna pass in our our name from our post out of here as well. So we gotta user name or password or name. All are going to be inserted into our database using our database class. So if that returned that that ah method from the database classes just gonna return, true or false. It was either inserted or it wasn't. And so if it's true, then we're going to return. Ah, status message of one. And that the count or a status of one? A message of the count created successfully. If it didn't, it'll skipped this block and it will come down to this return and will return zero. And there was some sort of unknown air occurred. We don't really know what the error is. This is something that be pretty rare. If it's probably gonna be something to do with your database got I mean, you're gonna have bigger problems, I guess, Is what I would say if if that's getting triggered. All right. So that register form, then, are this register method will insert the user into the database if they're that user name is unique, and it will return us a status message that we can work with. So if we come over here to register, weakens the register status is set to whatever there's register method returned, so register status is going to be set to that array, the with the status and then the message depending on whether the user name existed, whether was inserted correctly, etcetera. It's gonna give us that back. So because of that, we can then display appropriate messages here. So first, we're gonna check and see if register status is set right? Because if if if this was even, because if there was no post data submitted, its not going to be set. So we don't need to display anything and then if it was set, were running a tour in Eri here. And basically what this, uh, turn areas checking is if the status is equal to true which one, if you don't use three equals here if you don't use strict one is the same is true is that the same is true but it will. It will. Ah, it will make This will evaluate to true for that status message of one. So this will if if that status is set toe one than this will be true. And in that case, the class will set this class variable to success. And if it's not, if the status messages not true, then it will set this class, um, this class variable toe error. So down here is where we then echo whatever that class is. So this is for our message. So this basically eyes so we can give the proper CSS for an air message or for, ah, success message. So that allows us to ah, change that class based on what we got back from our database query. Then down here instead of hand hard coating a status message, we just We just echo out the status messages that we got back from our from our log in script. So it will go. It will be one of these messages right here. Use the name already exists. Count created successfully, or an unknown air occur depending on which of those happens to be true. Right? So that'll that's how we handle our air messages. And just real quick. If we go to the register and it's to John John Morris, that should already exist. Yeah, that's how we get that that user name. Ah, right here. Or that. That air message right here. Okay, so that shows you the registration part of it. Now, let's go into how we verify this. So again, we're now interacting with a database here, so we need to We need to change, verify, log in and verify session just a little bit. Well, we've already got a method down here that allows us to check if a user name exists and if so, gives us the data for that user back. Well, that's really what we need for both of these scenarios already. So under verify, log in. But you can see we're still doing this, that we did this before. So post use name and post passwords. We're checking to see if there said if they're not set, we can't do anything anyway. And then we're running. This user exists method and we're passing in the user name. So the using that was submitted by the form, and so we're going to just run that through user exists, And if it exists, we're gonna get user data back. If not, we're gonna get false back so we can run that same if block if false and its strict here because we want. Make sure it's strictly false because that's what it returns. If it's false. Ah, if users is false or if it's not false, then we're gonna go ahead and do everything inside of this block. If not if ah, if the user is false, we're going to return false down here. Okay, So if the user does exist than what we're gonna do is we're going to verify the password. So we're going to use password Verify. So this is another built in PHP function for passwords. So they had password hash and out, and then they also had added password verify. It makes it really, really easy to hash passwords and check to see Verify those passwords. We don't have to do any heavy lifting. So all we have to do is take the password that was submitted by the user, which is gonna be there plain text version. And we take the password that we have from our database, which is the hash version. And we pass those into password, verify and password. Verify will basically rehash the paint plain text password in the exact same way that it was originally hashed before it was stored in the database when they registered and it will check to see that they match. So this method will do all of that for us. You've seen in the stuff I've done the past before this came out with passwords you would used to have to do all that. Now you don't have to do any of it. All you have to do is pass the password that was entered in the form and the password hash that you have stored in your database into bastard. Verify and it'll check it all for you. If that password verifies, then we can do what we did before we can set session user name to, ah, the user user name. And that's how we Then that's then what we use for verify session down here and we'll return true here. So that's how we verify Log in. And ultimately, what we're after is if the log in is good, we're going to set this session user name and then we'll use that right here and verify session, and we're gonna do again. We're gonna grab the user name, we're gonna grab it. Ah, the session user name and we're gonna again run that user name through user exists to see if that user exists. Because remember, we did this before. The only difference is is we were going to our conflict file in our users array to see if the user exists there. Here. We're actually acquiring our database again. So every time the page loads where you run this verify session method, it's going to look for a user name, this user name block being set in the sessions variable. And it's going to check what set their against what's in the database and see if that user actually exists in the database. So if that user exists, we're gonna store, remember, user exist, this user exist. Method returns the user, all the user data if that user exists. And so we're going to store that as this user variable again, we're going to check to see whether or not, um, this was false or not. So if the user does exist, then we're going to set this user equal to user, just like we did before and were turned true. Otherwise, we're going to return false. So hopefully what you've seen from all meet me going through all of this. Is that the difference from a big picture perspective? The difference between doing this the log in checks and having this this log in verification between doing in a text file and doing in the database is not all that different. The only real difference is that you have to have the register thing. And technically, you don't even need to have that. You could go in and enter that information manually, although the hashing would be problematic in that sense. But these these methods right here are really not all that different. All you're doing is just grabbing the data from the database instead of grabbing it from the conflict file and pretty much running very, very similar checks and doing very, very similar things. So when we call this advanced, it's actually not all that much more complicated than what we did before. And from a big picture perspective. We really haven't changed much, and that's quite literal. If we go to the index page, nothing has changed here. So it's on Lee Internal stuff that's really changed, So the idea is the same. You want to verify the log in the Loggins correct? You want to create the session variable and then every page load that you wanna have protected. You will check that session variable to see if exist. If it's exists in the session array, and then if the user name that's in it actually exists in your database. It's a verified user. And then on top of that, once you have that base stuff in place, you could to do all sorts of things. You could grab more data for each user so you can display that. I mean, that's how you have no e commerce sites that no, All the different orders that you you've made or you know, you log in tow. I don't know PlayStation site, and it has all this information about your Microsoft site. It has all the orders and stuff that you've bought and all this information, all it all sort of is based on this very fundamental thing of being able to verify Loggins and verify users. So ah, learning how to do this is a foundational thing that will allow you to then expand from there. So that's it. I mean, that there's really, uh actually there is? Well, no, we we actually covered log out in the other one. So the log out is the same here. You just destroy the session. Um, and that's pretty much it. So that's pretty straightforward. One other thing I should mention, I was going to mention the last one. And then I think I didn't. I had mentioned how we were seeing. When we're typing in our password in the the password block, we're actually seeing them. That's because I had set this type to text. You actually want to set this type two password. And I did change that over here in the log in one as well. So that's why if we come over here and we type in this block now, you're actually seeing the dots instead of the words. So All right, the loot for this lesson takes watching. We'll talk to next time. 4. Add In a Remember Me Feature: Hey there, John Morse. Here. John Morris online dot com. This lesson we're gonna get into adding a remember me functionality to your log, inform your long and script here. Now, I'm gonna preface all of this by saying that when you do this, you are, in a way kind of creating a backdoor into your system. Now we're gonna go through how you secure that. And probably most of what we're doing here is the securing part of it. Because the actual do doing the remember me functionality is pretty simple and straightforward. It's what Really the most complex part is actually securing it. So you might find for your application that the remember me thing is not as big of a deal. And so you would be just fine, in my opinion, not adding this into your script if you don't wanna have that kind of back door, OK, you I think you'll see what I mean by that when we get into this. But what I guess what I want to get at is you don't have to have this and then for some applications, for example, ah, banking applications would be a really obvious example. This is this is something that you really wouldn't want to dio, because again, it's kind of ah, kind of a back door into our system. So with that kind of caveat, let's go ahead and then take a look at how you would do this if you want to do it. So the first thing that we need to do is I think the probably the most obvious part is we need to add a new input to our form. So if we look at our script here, we have this new remember me kind of check box here, and we just do input. I did it in ah, paragraph tag. Just because we have this remember me text and to create a little more Ah, space here between the actual cement button and the remember me block just for aesthetics primarily. So we have input type of checks box. The name is Remember me? Who's that? The value toe one. So if it's checked, essentially the value that is in our post array will be one. And then we have our remember me text right here, so pretty straightforward on that. What that basically does is again when the former submitted, there will be a new element in the ray array with the key of remember me and the value set toe one. Really? The value doesn't matter too much because we're just gonna Basically, If it's not, if this isn't checked, this isn't gonna be in the array anyway. Ah, this thing, this element altogether won't be there, so but that's ah, just how we're doing it here. So that said, then what we're gonna do here is we're going to add than some functionality to our verify log in because this is our log in form. We're doing this on our log in, so we have to add a little bit to it. So everything is the same up until this point right here. So essentially this little block right here, we're just checking to see if the remember me element eyes essentially set. And this the way this works that basically will check to see if it's set toe one. So it's checking to see if that that check box has been checked. And if so, we're going to call this new method we've created called Remember me and we're gonna pass in our user data that we already have available to us here because we're gonna need it. And I remember me functionality. And we already have it here, so no need to query the database again. So we're gonna go ahead and pass that into this remember me? Method. Right. So the basically, this has two parts. So once we ah, once we've kind of checked our form, then essentially what we're going to do is we're going to create a We're going to create tokens. We're gonna store them in the database. So if we go over and look at the data base, we have a new table called off tokens and in off tokens. The format is would come over here to the structure, and we have an I d. That's an int. We have a selector, we have a token, we have a user name, and then we have a time at which it expires. And if we come over here and look at our install script, I have added this to the install script here. So you could. All you would need to do is just visit your install script again, and it won't create this database because that already exists, and it will create this new one for you since this one doesn't exist. So all you have to do is just visit this install page again. It will auto create this this table for you. But again, this is where we're going to store our authentication tokens that are going to allow us to remember people. Essentially. So that's what this all does here. So basically, we're going to store the tokens, and then, ah, when someone visits a page, we're gonna pull the data and we're gonna check it against Ah, cookie. So the first thing that we need to do here is we need to create thes selectors and the these authenticate this authenticator. Essentially, this is creating a public and private keys, I would say is generally what we're doing here. So the selector you're going to see here, we're going to store the selector basically wide open in our cookie, and then our authenticator, we're going to do some a little bit of encoding and then we're using random bytes were using encoding here. Basically, we're just ah generating. Ah, random numbers here to do this. So I mean, it's probably not exactly that but I kind of look at it like a public and private key. Um, And so what we do here is, once we have those those generated, then we're going to set a cookie. The name of the cookie will be remember me? And actually, it's good. And put this down here. The the value of the cookie. The data that's actually being stored in the cookie is the selector colon. And then we base 64 code again the authenticator. Or in this case, that is the first time for the authenticator. So this creates a cookie that essentially has this data, the selector and this authenticator in it, we said, Ah, time here. Ah, when we wanted to expire, this is Ah, it's like 10 days in the future. Ah, this is the path of the domain. If it's empty, it's gonna just choose the current domain. And then this is for ah, believe it's https only. And then TLS only something like that. So these are if we go and look at Francisco and look at set cookie. So yeah, secure. And then http, only So this is basically, um it's only going to do it if it's an https connection, so you'll have to pay attention to that. Depending on where you install this, you may have to set that the false and then HC TP only means that it can't be accessed through languages like javascript, which is important. So you only wanted this to be able to be accessed through Http again. This is all part of the way that we're securing this. Okay, so we're gonna set this cookie, and then when we set this cookie, that is, that is what's going to that Cookies going to reside in the user's browser. So when they say close their browser, that cookie won't get deleted. And the next time they open their because again with sessions, every time they croak closed their browser, essentially, that's gonna end the session so they would be basically automatically logged out. This is allowing us to persist Loggins across ah, browser sessions. So that cookie, when they close the browser will still be there. So when they open their browser back up and they come to visit our page, if they've clicked that, remember me? Check box. Then we're going to essentially auto log them back in is really what this is. So what were again? We've set the cookie. Here we have our selector. We have our authenticator, and that's what we're going to need for then you for our token here. So this part right here is essentially we're cleaning up the old tokens. So if you with this system, if you log in and you check the remember me box, it's gonna create a token it's gonna stored in the database. And then if you actually hit the log out button, we're gonna delete the cookie from your browser because you have, essentially, when you click logged out and again, you could change the way the behavior of this however you want. But in my opinion, when you click log out, you are basically saying that I don't want to be remembered anymore. I don't wanna be auto logged in the next time. I can't I come back. Otherwise I mean, why would you click log out? So we're gonna delete Ah, that cookie. Well, what happens when you delete the cookie is that if they come back to the site and they click that remember me box, we're gonna generate another token and that the selector and the authentic air gonna be different. And so it's going to create a new, basically new token inside of the database for that user. So, essentially, what would happen is, if we didn't do any cleanup, you would have, you know, multiple tokens in the database for the same user. And then depending on how many users you are, you have you would each one of them, each one who uses could have multiple tokens. 10 15 Over time, it could be 100 200. So that that a that table's gonna grow huge and be you're gonna have a lot of these off tokens out there, which is just never a good idea for anything related to security. So essentially, what we're doing here is when they when we they log in and this remember me, boxes checked and we're running this remember me method here. We're gonna assume that were all the old tokens air basically gonna be invalid? So that's essentially what this does now. The only they should only ever have one token in the in the database in the table. Um, because we're deleting them as they create new ones But if for some reason there was a bunch of them or whatever, this will actually delete every single token in the database that for this particular user who was logging in at this moment. So if they had 10 and there would delete all 10 So that's that's what this does right here . Then from there. What we want to do is we want to insert the new token. Now that we've said our cookie, we've cleaned up all of our old tokens. Now we want to insert this new token in the database so that we can use it when we're verifying our session. So we do. Ah, insert in her database, where incident and off tokens we have selector, token user name and expires who passed on our selector. Straight up we hash are authenticator basically the reason, as as I understand it and again some of this stuff when you start getting into this really heavy security in cryptography and all this stuff gets a lick, it's a little confusing, even for me. But basically the idea here is by hashing this authenticator. Even if someone got access to our database and got the selector and the authenticator, they would still have to do. Ah, work to be to unhatched sh this token. So and it's significant, and enough that it would it would take them a while to be able to do that. So that's why we hash this. And then we associate it with the user name. Because, of course, one token belongs Toa one user, and then we set in there when it expires, in case we ever want to use that at some point. Although, really, what matters is the time we set here for this cookie expiring. Okay, so with that what we end up just to recap someone clicks the remember me box. We run this remember me method. And what that method does is it creates a basically a public and private key. Kind of that we store in our cookie, and we also store in our database. Okay, so it's again, it's a cookie on their browser. And we've also started in our database in this off tokens, uh, this off tokens table. So as you if you're falling long, you could start to see there. What that allow what that's going to allow us to do is when they come back to the site, be able to grab the cookie and say, OK, you have this cookie. Let's check the database to see if that's a valid authorization token. And if it is, then we're gonna be able to auto log them in and that that part of it is essentially what we do right here. So this is all the new stuff right here Before we would do user name was Ah do session user name and all this stuff was here before. So this this block of code, right? Here's what we've added. So basically what we're doing is we're checking to see if session user name is set because again in this, in this scenario, we're assuming they've closed their browser. And so the session will have been ended. And so when they come back session user name will not not be set. So we're going to check and see if that said, if it's if it's empty, if it's empty and there's a cookie set for this for our site named Remember me, that basically is telling us we have the scenario we want, which is they don't have an active session and they do have the remember me cookie. So that means we're gonna go ahead and auto log them in. So what we do is we use this lift list and ah, we explode our cookie. So I remember when we said our cookie Ah, we created a string with a colon in it like this. And then we have selector on one side and authenticator on the other side. So essentially, when we explode it, what we end up with is we end up with an array. One element is the selector, and one element is the authenticator, and then we run. We run that through list, which basically takes the element that is the selector and sets that equal to the variable selector and the element that is the authenticator and sets that equal to the authenticator variable here. So we end up with, um, are actual selector from our cookie set to salt the selector valuable and the actual authenticator data from our cookie set to authenticator, which is what we want, basically. All right, So then what we're gonna do is when a query, our database, and we're going to select the data from the off tokens database where the selector equals. Ultimately, we're doing prepared statement, but ultimately, where it equals R selectors. So we're taking the selector from our cookie and using that to queer database and find that selector in our off tokens table. Now, if it doesn't exist, then that means something's not right. And so we're not gonna word we're not going to do any of this stuff, okay? We're not gonna verify the session. Essentially, we're What would basically happen is when we come down here to run the hash equals it would fail. Therefore, we would not set the session here, and so we would continue down here and ultimately returned false, so we would never verify the session. Okay, so that's what we're doing here is to see if that selector exists. If that selector does exist, then we are going to grab basically all that off token data. So that's again. It's going to have ah, the i d. The selector, the token, the user name and when it expires, and so we're grabbing all of that off token data, and then what we're gonna do is we're gonna use this hash equals ah, function here. So, basically hash equals is gonna check the the the the The token that we have from our database against the authenticator that we have from our cookie is going to see if they equal each other and you use hash equals because again, this gets complicated. But there's a timing issue where, um if you don't use hash equals, it could actually make it easier for someone to try and brute force because they change the certain first part of, ah, the token. They change the letter, it'll actually make it run faster. I mean, again, it gets really, really deep into this. Um, I don't know that that's necessarily 100% need to know. The need to know is that you need to run the shash equals. And so we pass in our token, which again, this token is where we saved our authenticator. We pash past that in and then we passed in our authenticator that we actually got from our cookie. So our authenticator that we got from our database compare it to our authenticator that we got from our cookie. And so it's going to see if they equal one another if they dio. So, if this is true. Then what we're gonna do is remember, this assumes that user name here is empty. So the first thing and we need user name down here if we're gonna do an actual authentication. So we need to set user name equal to the user name that we now have gotten from our database from our log in here. So we first do that, and then we also need to set our session variable. So the cookie is basically gonna be almost kind of a one time bypass. So it's going to it's going to essentially bypass just the standard check for session and check the this off token and all this stuff. And then if that's all good, then it's going to set the session and then from every page review from then on will be based off of this session because this session will now not be empty. So this stuff this if block will never trigger, okay, And then that once we have our user name and our sessions set, and then we can go back into our regular coaches like we had before, which is where we get the user data so that we can display that on our pages. So, as you can see, that's why I see this is kind of a back door in the sense that you're using a cookie to get around your sort of session authentication. Now you're tying it right back into it. But that's a sexual essentially what this allows you to do. And that's how you do. Ah, remember me? Functionality. Now a couple. I would call caveats here, depending on what version of PHP you're running. You may not have this random bytes function, and you may not have the hash equals function here. So what I've done is I've included a class called Random Compact, which will make make this random bytes function available. If it's not by available by the fall in PHP. And this hacks hash equals class, which will make hash equals available if it's not available by default in PHP, both checked to see if those functions already exists before actually doing anything. So if they already exist, they're just gonna use the built in PHP ones. But if they don't exist, then they're going to use the ones that they've created in these classes that basically do the same thing. So one thing you'll notice in our ah load and I would open in our low dot PHP is now we're including this random comm pat, and this hash equals here as well. So if you want to, maybe you don't want to include those. What you could do is come in here and you could comment thes out and then just try and run a log in. If you don't get any heirs running a log in, then you can safely remove this random compact folder in this hash equals file and these requires right here. And because you have what you need for built built in for PHP. So, um, if in their their function, don't exist errors. So if you don't have what you need any, just tryingto do a log and it's gonna throw on air and you're gonna know right away. So again you can calm it. Those out, see if it works and if it does, and you should be good to go, All right. So with all that said, then we can kind of take a look at this. Let me go ahead and log in, and I'm going to hit the remember me block and hit submit and that logs me in and we can come over here to the off tokens and you can see that created a new off token here. Ah, for me to use. And then if we come over here, then we go to our settings and it takes a second to get here. Ah, video to content settings, cookies and then see all cookies and down. And, of course, depending on what browser used be different. I got a type of the domain I'm on. And then if we look in our cookies here, we have this Remember me and here's our content of our cookie here. So we have the cookie. Now, if I were to close this browser and jump back into it Ah, and the session would be ended, but I would be able to log back in with just the cookie. Now you'll see here. If I click here to log out, then I go here to click here to log back in, which just takes me to the index page. You see, the log inform comes back up. That's because if we look at our log out that dot PHP. This is essentially destroying that cookie. So the way you destroy a cookie is you said it. You set the cookie and you said it to expire to a time in the past. That's what we're doing here. That's why we have minus whatever the time is minus 3600 seconds. So that kills the cookie and that essentially, I mean, you could you could probably pol I hate to say you can't You probably hackers probably figure out a way to spoof all of that information and that cookie and be able to load it and get it back in. But that would be, I mean, very, very difficult to do. And basically, once this once you log out that that token becomes essentially invalid because the next time you log in and hit, remember me. It's going to create a whole new token. It's gonna overwrite the other one, and you don't have that cookie in your browser anymore. So basically it makes it so that you can't log in that way anymore. You have to log back in and you have to use the remember me block. And of course, if you don't check the remember me, Block. It's not going to do any of that off cookie stuff. Just doesn't do any of it because it's all based on whether or not that check boxes checked or not. All right, so that is how to add. Remember me, functionality to your log in script. Thanks for watching. We'll talk to you next time. 5. Create a Secure Password Reset: Hey there, John Morse. Here. John Morris online dot com. This lesson. I'm gonna show you how to add a password reset feature to your log in script here. So this is going to be, ah, an email password feature. And so we're gonna have to update some of the stuff that we've done up to this point so that we have Ah, an email. And the reason it's an email password reset is is basically, in most cases, that's gonna be the most secure way for you to do it. Because in order for someone to be able to hack again any any sort of this, this sort of thing is going to be a backdoor essentially into our system. So we want to be really careful with that. So some ah hacker would have to not only know the email address and all that not only hack our system, but they would have to have hacked the email account of the user. And so ah, again, when when you get to that point, that person probably has more problems than what's going on with your system. So just it it's a lot better than having something on your site where they would maybe enter some, ah, security questions or things of that nature. Ah, simply because then you're kind of putting all of that. All of the security on you and your system. Ah, and you're gonna be again. It's going to be your system. That's a target for hacking. Whereas if you do it by email, it's gonna be Gmail or Yahoo Are any one of these things? So again, generally, most situations the recommended way to do this is with an email reset. So I'm gonna show you this real quick. You'll see that we have right here. We have this reset password. So we'll go ahead and click into this, and I'm gonna go ahead and enter my email address. Now, if first off of I enter something that doesn't exist, we're going to get an error. That email just doesn't exist in our records. So there's that. And then if I do enter ah, correct email address, then we're going to get this success message that says, Check your email for the password reset link. And then if I come over here to my email program, I'll drag this down here. You can see here. Ah, what I end up with is this Ah leaking that My email here that I can use. We'll go ahead and click that and that's going to take us to this reset password page here . And then I'm going to reset my password so I don't actually remember what it was that last . I said it to go ahead and hit reset, hit, submit and it says, Password updated. Successfully going hit. Log here and we'll type in the new email here. Then we are all logged in. Okay, so that's what it allows us to do. Ah, and so it's pretty straightforward. Now if we come back and let me just jump back into my email programme real quick and I try and use that same same reset again and I try and reset my email, you'll see that I get an error code. Okay, so they wasn't able to process that. And that's what we want. Because now, once that token is used, we don't want it to be used again. Okay, I'm gonna show you how we did all of this. So that's the basic idea. So there's some things that that we've we've done here that will need to go through. First off will go over here to the install script. There's a couple changes here, and, ah, some of this comes some of this is just clean up and comes from just doing further testing on, ah, a number of different servers. So I was just trying to make sure that on all sorts of different server set up, this was still gonna work. So there are some change things that we had to clean up here one of those years. You'll notice that I've added in database details here and created a unique connection directly through PDO to the database. And the reason that I did that is ah, are our database class that we're using is primarily meant for post install, so I could go through, and I could update the database class for that. But I really didn't want to get into that with this particular this particular course, because I want to focus on the log in part s. So what I did here is just I created ah, another connection to the database of centrist separate from the one that we use in the rest of script and This is on Lee on the install page, so you can kind of look through this, but at the end of the day, it doesn't really matter. Ah, the thing that matters down here is that we've created a new table called Password Reset, and we have I d field and email field ah, selector field, a token field and an expires field. So if you look, it's almost identical to our off tokens, except we're using email now instead of user name. And that's just because for sessions we need the user named at is what we're using for password resets. The email is, is what we're using. So that's the only reason was to change things changed. You also notice that I've added another field here called email to the users table, because we need to now collect that data so that we can do send the password reset. So what you can do is if you just go into your my sequel database and you go to users and you go to operations, you can come over here and delete the table. Just delete the table. I'm assuming you're in a testing environment. Obviously, if you're gonna you've been using this already, then that's probably not necessary. Something you're gonna want to do. But he's delete the table, and then you can go back and visit the install script again. Visit install dot PHP and it'll reinstall it with the new field in there. Or you could go if you wanted to into my sequel. Ah, and you could go to think its structure and then you could add a field and so Ah, leave. It's down here. You're able toe toe. Add more fields yet create. Ah, Add one column right here So you can add a new column if you wanted and ah, at that email field in there, so whichever way that you want to do it. But all of the information in terms of how it's created is is right here. It's a ah ah var chart to 55. All right, so that is kind of some of the initial set up there. Then we also on a registration form. We've added a field for email here. So we added an email. Ah, field here. We could actually set this type two email. So the little HTM Island five will actually verify for us. That's one thing we can do there. Class is set to tech still, because we have all of our default styling based on that, it is. Technically, it is still kind of a text field is just a special kind of text field name is set to email . And then if we go to our log in script over here and we look at our register function here , So we have ah set of required fields, user name, password and email. Those are gonna be are required fields. Ah, this is just a quick check. So basically, what you do is you loop through this required array and then you check to see if that key in in the post data that was submitted is empty or not. If it's empty, if any anyone is empty, the 1st 1 that's empty, we're going to return a status message of zero Ah, status of zero. In a message of please enter your and then whatever. The key is so user name, password, email, etcetera. So that handles making sure that we get are required fields. On this end, we're also doing it on the form. And if we look at Registrar PHP. We're doing required here, but you always wanna. You don't want to rely on the HTML five stuff. You won't always have your own back and script doing those checks as well. All right, so that does required fields. And then that was I'm going over there because it's a new thing I added in here, I don't believe I had that in before. We have our standard check to see if they used name already exists. And then all we did was add this line right here, which adds now will take the email from the Post Data and put it into our database. And so that's really the only thing outside of this up here that changed in terms of inserting the data into our database. So that's pretty straightforward. So let's the register page. So now when someone registers, they'll enter their name, their email, their user name and their password and weakened. If we go to log in, click here to log out, then we'll go to register here. They will now enter name, email, address, user name and password. All right, so that gets us set up with now. We've got our email. Ah, that we're collecting. We can now use that for our password. Reset. We've got our install script. Ah, lot of this stuff hasn't really changed, Index. And this sort of stuff hasn't changed any, uh, log in here? The only thing that was added here was the link to the reset password. So if we go back to our log inform all we added on here was this reset password link. So that's all that's changed there. Our conflict file. We did add a couple things. So we because we're sending an email, we now need a few more things. So we need the URL of the site because we're going to send a link to who? Them that links back to our site. So ah, we need we need that your l instead of hard coding it throughout the script. Because if I did that, then you would have to go in and change every instance of that. I just created Ah constant here. And you can change this out for your your l Where you have this installed. It's the whatever folder. Whatever folder you have this script ah uploaded into That's what the oil you would put here again because we're sending emails. We also need a name and email address so you can set the name and email address here. Course. You also want to set your database details for the database that you create for this. Ah, and then we said a default date. Default time zone. I just said it to UTC. You can, of course, set it whatever you like. But a lot of servers these days, if you don't set this, it's gonna throw some sort of error. So I just put this in there eso that, uh, and this could be set and in any file. So some servers, if it's set in any file, then this You won't see that air. But I put it in the code just so that you don't have to deal with those errors. So and it's set to use UTC, which for our script is Ah, that's fine. The dates were not actually really displaying anywhere at this point, we're only using them for expiration times, for for our password reset and for our auto log in. So our remember me feature. So it's not something that has any importance in terms of display. Right? So that's how we changed our conflict file. And then we did change our database class just a little bit. Basically, the one we changes this user execs exist Method. I do want to cover this because this is actually a good lesson just for going about updating functions or methods. So if you remember, before this only accepted one parameter and that parameter was set defaulted to user name Well, we can. It would be nice to be able to check the If the user exists by more than just the user I d or the user name be able to check it by anything. The email and in particular, its helpful in in what we're doing with our, um, what we're doing with our our password reset because we're gonna be working with the email . So it be nice to be able to check for the user by email. And so that's what this change allows us to do. So if you remember, before it had one parameter and you would you would ah ah set. Essentially what? You what the value of the user name was so you'd pass in the user name that you wanted to check to see if that it would exist. So what I did is I left. This first parameter is still needs that same thing. But then I added a second field called Wear Field, and I defaulted it to user name. What that does is it means any of the other places where I've used user exists already, and it was for how it was constructed the old way. Those are all still going toe work, and that's important because we don't necessarily. It's not necessarily easy to go back through an update all the instances where we called user exists. And so I updated the function so that it's backwards compatible with the ways that we've already used it in our code, because that first parameter is still the same thing. And then because this one is has a default value. If the parameter is not that this second primers not passed in, it's just gonna use this user name right here. So it defaults to accepting ah user name and using the user name to Field Field to check to see if the user exists. However, now we can pass in something else we could put in the email address and the wear field be set to email. And so now it will select all users. Our select all from users. Where the email Because that's what we said is the where field Ah equals and this is our place. Holder referencing are place holder and ultimately our wear value. So where the email equals this email address or if it's the default where this user name equals, where user name equals whatever user names passed in, right. So that's one update we made to our database class there, and now we're kind of getting down to what's left here. So we have three new pages. We have lost password dot PHP reset dot PHP and reset process dot PHP. So the lost password page is where we're actually when someone wants to request and say that they've lost their password and requests an email reset. This is that page. So this page, in terms of what it is, is actually pretty straightforward. It's ah, it's a form. So we have our form here that submits to itself, and the only fielded accepts is the email address. So we come back over Here we go to reset password. It's a form with one field and it except the email address. And then if that for miss submitted, it's gonna pass the information to Los Password. Okay? And I'm kind of going from the big conceptual overview of what we did, and then we'll dive into the details. But it's gonna pass it to this last pot lost password method in our log in script class and process it and I'll show you what we do with that in a second. The next page is the actual reset page. So this is what the pages will go to when they click the link in the email. And so this one is a little bit more involved. The first thing that we need to do is you notice that where we kind of have our include up here, and we're kind of this is a little bit different than this sort of form, where we have all of our includes stuff down here. All of our PHP logic up here, right? It's kind of separated cleanly. This one's a little different because if they're, if they try to just visit this page directly and they don't have the proper query parameters in the URL. Then we need to display an air message down here that says that there was a problem and so this is a little bored mixed together. But what we're ultimately doing is we're checking to see if those query parameters exist. So there's a selector and a validator. And in the lost password method over here, what is where we actually create and send the email. We put those parameters into the U. R. L. So the link in the email will have these parameters already. So basically, this helps deal with anybody who's trying to go to that directly and and floats around. They need to have the right, ah, query parameters. So we checked to see if those career parameters exist, and then we checked to see if they are Hexi Decimal because you'll see again when we get toe lost password method, we can we we create, um, we create basically a nonce or we create a token, and we converted to Hexi Decimal. And so when we are, when someone clicks that link, the query parameters should both be Hexi decimal, and so we can check to see if they're Hexi Decimal. That essentially helps us deal with anything. Or someone might try and visit this page and set selector equal to some random Java script or some SQL String or anything like that. It's not going to validate as Hexi Decimal. And so therefore, these checks will fail. Okay, so this is just a little bit of input filtering right here. So we're going to check to see if they're Hexi Decimal. If they're not Hexi Decimal, then we're going to throw this air. And if they don't exist, this will also throw on air, by the way. So, um, this this checks both if it exists, and if it's Hexi decimal and if it doesn't meet those two conditions, then we're gonna throw in there, Does meet, meet those two conditions. Then we're creating two hidden fields right here where we are going to put in the selector and the validator. That will need to validate the token when ah, this form is submitted. And then the password here, that ah, the person, the new password the person wants to set. Okay. So they'll submit this form and then the processing script for this will check and see if the tokens that they passed in are valid. Okay, so that's what this this form does here. And then it passes that information to reset process dot PHP. Now the reason, and you notice most of the other forms they submit to themselves. The reason I have this submitting to a different PHP script is two fold one to show you how to do that gives again. And that's what they want to make clear with all of this stuff. I write this code as a training aid primarily, and so that's why I always caution people about using this in production. That's really meant more for you toe learn from it than for you to use it. And I don't really pay it. Necessarily focused too hard on making sure everything is consistent. I may I'll do something one way in one area and a different way in another area so I can show you both things. So again, this is primary training, but a so I can show you this. But be if you start trying to mixed in the get variables and and checking for those and then having also checking for the post variable it gets a little kind of gets a can get a little crazy Ah, and complicated. And I think unnecessarily so. So we just do I get checks on here, and then we're gonna pass it to reset process dot PHP. And that's where we can just handle all of our post at us. So it helps separate those two things out. So if we come over here to reset process dot PHP, you could see now this looks back to more normal. We are checking to see if it's a post Post data has been submitted, and if so, we're gonna process. We're going to send that to reset password. If no post status submitted to this page, there's no reason that they should be on this reset process page unless they've come from this form. So if they're visiting this directly, there's nothing that we can do for them. And so that's why we haven't else block right off of if post at it was submitted, and we just throw an error. So there's no other reason for them to be on this page. So then we run this Ah, reset password method will get into the details of that. We set the status accordingly here and then down here, we basically just display the data status. Either they get this air message, they get an air message generated by Reset Password, or they get a success message generated by reset password. And we just display that down here. All right, so that's kind of the big picture overview. Now, let's go into are actual log in class. And so again, we have lost password right here. Ah, this is one of our main methods and we have reset password right here. So those are two main methods that we need toe. Look through. So let's look through loss password first. All right, so if we come up here, there's reset password, and now we have lot lost password. So with lost password, the biggest thing with these tokens is we need to just make sure they're cryptographic Lee secure so that they're not really, really easy toe hack Now. Obviously, if someone gets them directly from the person's email, they're gonna be able to use them. But we want we want to make it. So it's difficult for hackers to just kind of to try to go to a reset form and try and guess them. And so that's what most of this code is going to be. But for our lost password method, it takes the post Out of that was submitted again. Remember that Post Data is, ah, going to simply be the email address here. That's all that's being submitted. Ah, And so we're gonna take that data we're gonna verify to make sure that post email was sent . If not, we're gonna throw on air. Then we're gonna check our database to see if that user exists. And this is we're part of where we were using user exists, and we're checking by email. That's why we updated that data bleed based method. If the user doesn't exist, then we're gonna throw on air because we can't reset a password for an email or user that doesn't exist. If it does, we're gonna continue on here. And first thing we do is create our selector. We're going to use random bytes its length of eight, and we're doing been toe hexi decimal. So we're creating ah, Hexi decimal. Basically, string here that we're going to use is our selector and because it's random every time that this this this method runs, it's gonna be something different. Now we're going to store it so that that's how we match everything up. But that's important that it's not having the same thing being created and the way random bytes works, you know, it creates something that's cryptographic Lee secure for these purposes. We're doing the same thing for token, except we're creating one that's longer. Ah, and we're not doing Ah, the Binda hex here. Although we will here in a second. So that creates our that essentially creates are two tokens that we need. And like, I kind of said before, this is somewhat like a public and private key. Although in our case, you're actually gonna send both of them. Ah, both of them to the user. But having these two different keys helps with timing issues and makes it harder for someone to try and come in and guess this now they've got a guess, too, and get him right and it ones a lot more, a lot longer than the other one and so forth. So once we have those two tokens, then we need to create rul that we're going to send to the the user to reset their passwords. So we're using sprint. Half we have are two placeholders. Thes percentage s is here our pages reset dot PHP. So that again, that was this reset page up here that we just looked at. That's the one they're actually going to land on when they click the link in the email. So this is where we pass in. Remember I said in our conflict file, we specified our u R l for where this script is installed. So here's where we're using that. This is ABS. You are l So that's going to make this so that when you update that conflict file and that link it sent, it will be sent to the right place and it'll go to reset dot PHP. Then we're going to use HT ht TB build query. This is basically build our query parameters for us. And so ah, we pass in our selector which we had created up here. We passed on our validator and we run it through been to Hex to create a hexi decimal here and passing our token. Now it's important to know this because both of these ultimately are running through Been to Hex, but you'll notice down here, there's something I want to show you. When we insert this into the database were using token, which is up here that doesn't have been to hex run through. So what we submit into the database is actually not run through been to Hex, but has run through a hash, so we hash it. But when we send it an email, we do run it through. Been to heck. So basically, what's going to the email is being sent through been to hex. But what's going in the database is being hashed, so the value that sent to the email address and the value that stored in the database are actually different. Okay, so again, that that's important to understand. So you don't wanna You want to make sure that your ah, you're one thing that I was tempted to do was just put been to Hex up here said token equal to been to hex random bytes. But that actually wouldn't work because of what we're doing down here. We're using token directly. Okay, so just something to keep in mind that will come up a little bit later here. So that this essentially all this. What it does is it builds rul with our domain, a reset dot PHP and then our query parameters that we need set to selector and our validator. So that gives us our u r l. Next thing we need is we need our expiration for this. So we do new day, date time. Now we do a day interval, which adds an hour to it, basically. So this token is is will be active for one hour. Of course, you can change that if you'd like, Right, You can come in here and change the amount of hours that you want this to be active for, But I wouldn't set it for too much. And I would say in most cases, if someone's resetting their password, they're probably doing it right then and there. So an hour probably makes sense. All right, so once we have that, we kind of have everything that we need. Next thing we're gonna do is before we we create any new tokens were going to dally anyone's that happen to be in there already. So if someone selects reset password and then you know they don't get to it for two hours and then they try to click the link. They're going to see an error when they try to reset their passwords so they will go and they'll reset it again. They'll create a new reset password. And what we want to do is when they do that, we want to go back and totally any old ones that they have in the database to make sure we keep that cleaned up. We don't have all these toking tokens running around out there, so delete those. And then what we're gonna do is we're going to first insert that data into our database that you are table that we created. And so we're gonna insert the email. The selector we're going toe hash the token and insert it. And then we're for the expires. Were just inserting the date in UNIX format. So a UNIX timestamp you could do date time. But in this particular case again, there's no displaying of the dates. I just feel like it's it's easier to work with, in my opinion here. But I did do with the old one A with the remember me feature I showed you how to do it with regular date time. So you could absolutely do that as well. But I just did. You do next time stamp on this one to show you how that would work. All right, So what we end up with then when we do this is we end up with a, ah, a nen tree in our password. Reset data are password reset table that has the token and all of for that particular user by their email. It's hashed and as when it expires. So it kind of sets us up to be able to handle when they click the link and submit our forms . The last thing then, of course, that we're going to do is we are going to send the email. So we're gonna check to make sure that that was inserted in the database because it doesn't make sense to send the email if we didn't actually stored in the database because they won't be able to use the link in the email. So the first thing we're gonna set our recipient that's two will just set the two equal to use your email the subject to your password reset link you can change all this if you want . The message says we received a password. Reset requests linked. Your password is blow. Uh, etcetera, etcetera. Here is your password Reset link. And then here's where we actually pass in the leak. And so we do. Ah! Ah, A draft tag. We pass in the URL here, and we're also just displaying the You are all bare here. You could maybe change that here. But I am a fan of displaying the girls raw just because some email programs, the clink might not be clickable them. I have text based, and so if you display the link raw, they can just copy it if they need to and paste it. So ah, that's what we have here. And then we have this thinks. And so this is all just creating this message that is going to be sent in our email. You can edit this accordingly. Our headers we have our from this is where we have admin name and admin email. We have our reply to set to admin Uh, oops. Actually have a type of there email. So we have that set to admin email, and then we have our content type set to HTML basically because we're using these paragraph tags so it'll make it so it shows up how we expected to show up. And then here we're going to send the email and so we'll run that male function well. And then if that male function runs right, if it's sent, we're gonna check to see if it's sent. We're going to destroy the session if they happen to have one, any session that they're in. And the reason why is basically what the common Hair says. If they're resetting their password, that means there pat the current session, the password that their log win with is about to be invalid. So we're going to destroy that session and make him re log in. So I think that's important because you don't wanna have any wonky nous there in terms of them being logged in as one via one password. But they just changed their password that could get a little wonky. They're so we're just going to destroy the session and make them re log back in, and then we're going to return a status of one or true and our message here and then You know, if any of this stuff sort of fails along the way, it's gonna fail over to this status message of false with this message here. And we're not providing too much information here because this is a password reset. So we really don't want to provide ah, too much information to someone who might be trying to hack this. So we keep these air messages kind of vague here. So if we go back and look at this when we submit this form for Los Word password, it's going to take the email address is going to check if that user exists. If that user exists, is going to create a Siri's is going to create a series of reset tokens in our table toe. Handle that, and then it's going to send an email to the user with the link that they need. That has the proper tokens for them to be able to click and then go to the reset page and reset their passwords. So that's what all of this does. All right. Next, then is are the actual reset passwords. So again, ah, well, we don't have the link here, but that this is the page here where they actually we grab their the selector in the validator from the earl. We pass it in hidden fields and we actually process the password reset. So if we look at that, we're getting our post data here, and we are again are required fields were doing are required fields. Check to see if ej there selector, validator and the password Because we need all three. And if not, we're passing in an air and you'll notice here that I added something that you can consider adding When you have something like this where you really do want to know where where there was an air If the user someone contact you via support said, Hey, I can't reset my password all of these airs because we're not trying to provide too much information to someone who might be trying to hack this. All these airs air the same we use the developer may want to know. Well, what at what point did it fail? So you see, I veracode 123 and four, so if someone says, Hey, I can't reset my password, you could say, Hey, what was the the air code that it showed when you when you had a problem. Well, it was a WRKO. It said air code three. And now you is a developer. No, this is right here where you had some sort of problem so I could be important for troubleshooting. And you could do that. Maybe only just for production. Or you could leave that live for Ah, I mean for development. Or you could leave it live when you go on, your life's over your production server. All right, So if all the fields air there and submitted in the form, we're gonna extract them. So again, extract turns the keys of that of this array into variables and sets the value of that variable to the value of that key. So basically, what we end up here with when we extract is we have our post data set to selector validator password. So selectors set to whatever the selector is valued, it leaders set the one of a validator is etcetera. Makes it just a little bit easier to work with us. We we go through here. All right, so then the next thing we're gonna do once we have that is we're going to check. We're going to query our password reset table and see if we have that. If that selector that was passed in exists in our reset table, so we may not have any in here, we don't have any in here, but this is where we're going to have that data stored. And so we're going to check this to see if we have one in there that matches what was submitted through our form, which came from the page before, which came from ah, which came ultimately from the email. All right, so we're gonna check and see if that selector exists and if it hasn't expired. So if the time set in the expire block is greater than or equal to the time now. So time returns a UNIX timestamp of the current time and we inserted into our database a UNIX timestamp of when it expires. So we're basically comparing the time now versus the expiration time and seeing if now, if the expiration time is still greater than the time now, that means that token is still valid. So we're going to select and see if we find one. If we don't. If results is empty. If we don't find one that we're in return a status message. There is an air processing your quest, Eric Ho too, because that tokens not valid. Now we're not going to tell them that that tokens not valid because we don't want to let a hacker know that that that all what's going on behind the scenes? We're just going to give them this kind of blanket statement. But we know the reason why that would have happened, because ofher code to all right. However, if that does exist, then we're going to again. This get results returns Honore with one element in it. So we need to grab the first element in that ray. That's where data actually exists. So we set off token, equal to results, and then we are creating our, um we're basically recreating what we stored in our database. So if you remember, this is important. When we sent the validator, too, the through the email, we ran it through, been to hacks, and we did not hash it. When we started in the database, we did not run it through, been to hex, but we did hash it. So again, what was sent in. The email is different from what's actually in the database. We can't just compare those two directly. We have to recalculate ah, them accordingly. So what we do is we take what was submitted in the email and we run it through hex to bin. So that's gonna when we pass it in. When we sent an email we ran through been to Hex. Now we're running through Hex to bin, so it basically undoes been to Hex. So that's the first step. So we undo. Been to hex on what was the validator in the mail. And then we run it through the same hashing algorithm and we're gonna get the same hash back. So now cowpoke should be equal to what was submitted into the database. Now we've properly normalized it. So those two things after we do this should be the same. And so then we can run. Hash equals hash equals will compare what we just calculated from what was said in the email to what was stored in the database right here. So this is checking to make sure that validators the same four the selector that we selected up here if it is the same. Then we're gonna go ahead and actually process the password update. So the first thing that we're gonna do because we're gonna grab the the user information will come. You will need that. Just, ah, in just a second here. So we're gonna grab the user information using user exists, and we're gonna pass in the email to get it. So we have our user data here, and then if the user data equals false, that means that this is just kind of Ah ah, it's Ah, it's Ah, underneath, I guess, Or an implicit check. So we've checked our token and all of that in our our password reset, we No, that's selector wouldn't necessarily exist. If there was an email data to go along with it like we could, we could probably safely assume that the that whatever email address was in our database or password reset database probably exists as a user. But there could be some funkiness and maybe not. So we're actually verifying the email address right here to see that that email eyes actually a user in our users table. So that's what essentially this is doing right here. These two lines. We're gonna query users for that email address. We know, because now we know the token and all that is valid. Now, we're gonna actually check and see if that user actually exists. They don't exist. We're gonna return an air message. Air code three here. If they do exist, well, then this won't apply, so we'll move on here. We're gonna update the password. So we're using the update method in our database class were updating the users table, and we only need to pass in the thing that we're updating, which is the password. So we're or updating the password. We're running it back through the same algorithm that we used when they create when they registered, which is we're running through password hash with the password to fall algorithm. So it's gonna be encry