Legacy Password Migration Check
Verifies modern password hashes and upgrades legacy hashes after successful authentication.
Function signature
ogVerifyAndUpgradePassword(password, stored_hash, legacy_options = array())
Categories
- Security
Parameters
passwordSubmitted password.stored_hashCurrent stored password hash.legacy_optionsOptional legacy algorithm and salt metadata. Recognized keys: `algorithm`, `salt`.Return value
Short public-safe status message.
- verified
- new_hash
- needs_upgrade
- legacy_match
Compatibility
Existing function name and call order preserved; metadata signature corrected to source.
Minimum PHP version: 7.4
Security notes
Validate request method, identity, permissions, and caller-owned allowlists before use; keep secrets out of public output.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Verifies a password and prepares a modern replacement hash when needed.
*
* Modern hashes are checked with password_verify(). Legacy md5/sha1 checks are
* included only for one-time migration after a successful login, never for new
* password creation.
*
* @param string $password Submitted password.
* @param string $stored_hash Current stored password hash.
* @param array $legacy_options Optional legacy algorithm and salt metadata.
* @return array Verification status and replacement hash when needed.
*/
function ogVerifyAndUpgradePassword($password, $stored_hash, $legacy_options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array(
'verified' => false,
'new_hash' => '',
'needs_upgrade' => false,
'legacy_match' => false
)
);
$password = (string)$password;
$stored_hash = (string)$stored_hash;
if (!is_array($legacy_options)) {
$legacy_options = array();
}
if (empty($password) || empty($stored_hash)) {
$result['message'] = 'Password and stored hash are required.';
return $result;
}
$verified = false;
$legacy_match = false;
$new_hash = '';
if (password_verify($password, $stored_hash)) {
$verified = true;
if (password_needs_rehash($stored_hash, PASSWORD_DEFAULT)) {
$new_hash = password_hash($password, PASSWORD_DEFAULT);
}
} else {
$algorithm = '';
if (!empty($legacy_options['algorithm'])) {
$algorithm = strtolower(trim((string)$legacy_options['algorithm']));
}
$salt = '';
if (!empty($legacy_options['salt'])) {
$salt = (string)$legacy_options['salt'];
}
$legacy_candidate = '';
if ($algorithm == 'md5') {
$legacy_candidate = md5($password);
} elseif ($algorithm == 'sha1') {
$legacy_candidate = sha1($password);
} elseif ($algorithm == 'md5_salt_password') {
$legacy_candidate = md5($salt . $password);
} elseif ($algorithm == 'sha1_salt_password') {
$legacy_candidate = sha1($salt . $password);
}
if (!empty($legacy_candidate) && hash_equals($stored_hash, $legacy_candidate)) {
$verified = true;
$legacy_match = true;
$new_hash = password_hash($password, PASSWORD_DEFAULT);
}
}
$result['success'] = true;
$result['message'] = 'Password verification completed.';
$result['data'] = array(
'verified' => $verified,
'new_hash' => $new_hash,
'needs_upgrade' => !empty($new_hash),
'legacy_match' => $legacy_match
);
return $result;
}