I applaud your intentions. Getting this part of security right is far more important than most people realize.
For a big part of what you want to do (that is,make an actually secure login page), the "lazy way" (or rather "a way that may
seem a bit too lazy") is the right way these days. And that's because PHP has added proper ways to do the password hashing and verification to the language. The built-in method uses a proper cryptographically-random salt (created using mcrypt_create_iv() and dev/urandom) and BCRYPT (the key stretcher/hash based on Blowfish) by default, so it's best practices all around, and as the situation changes, the defaults for the functions will change to become more secure over time. There is not only no need to roll your own anymore, it's actually gotten to the point that rolling your own will be setting yourself up for failure in the long run.
The new features are built into PHP 5.5.x. We'll be upgrading to that here in the not-too-distant future. In the meantime, there is a compatibility script that will bring the identical functions into PHP 5.4.x
available here on github. (It's written by the same guy who wrote the core password functions for PHP 5.5, and is 100% compatible with the current defaults.) All you need to do is make a conditional require call:
PHP:
if (!function_exists("password_hash")) {
require_once(<path to compatibility script>);
}
That way, when the server is upgraded to PHP 5.5 and beyond, you will be using what's built into the language rather than what's built into the compatibility script, getting the "free security upgrades" along the way. (The conditional require is to ensure that you don't try to redefine functions that already exist in the language.) You shouldn't have to revisit the code for many years.
The language functions (and the compatibility script) consists of a set of four functions:
password_hash();
password_verify();
password_needs_rehash(); and
password_get_info(). If you use the defaults (highly recommended, since you lose the auto-upgrade feature if you don't), you only need to use the first three (the server will use the password_get_info() code inside of password_needs_rehash(), but there's no reason for you to use it yourself).
To create a has of the user-supplied password (which you would do at registration, or for a password reset, or if the current hash needs rehashing), it's a simple matter of doing this:
PHP:
$hash = password_hash($password, PASSWORD_DEFAULT);
That will return an ugly string looking something like this:
$2y$10$TR5/RZjbQuQNgwZqFcWuB.JBwefFGCPepA4G8H2rsyh9woEP8n6uC. The "$2y" at the front means "I used BCRYPT", the "$10" following that means "I used a cost factor of 10", the first few bytes of the rest (the computer knows which ones; you don't have to) is the salt, and the rest is the actual hash. So all of the information the sever needs to either re-do the hash the same way or to see if the hash method needs to be upadated is all stored in the hash string. That means that verifying the user password is as simple as this:
PHP:
if (password_verify($password, $hash_you_got_from_database) {
// the user has supplied the correct password
}
If the user has successfully logged in, and while you still have the plain text password in memory, you can do this:
PHP:
if (password_needs_rehash($hash_you_got_from_database, PASSWORD_DEFAULT) {
// the computer checks the algorithm and cost factor part of the hash
$hash = password_hash($password, PASSWORD_DEFAULT);
// update database with new hash...
}
That just leaves the database side of things.