Password Policy Inspector
Scores a password against length, entropy, reuse, blacklist, and composition rules.
Function signature
ogInspectPasswordPolicy(password, options = array())
Categories
- Security
Parameters
passwordCandidate password.optionsPolicy options such as min_length and blocked_terms. Recognized keys: `blocked_terms`, `min_length`.Return value
Short public-safe status message.
- valid
- score
- errors
- warnings
- length
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.
*/
/**
* Scores a password against a configurable password policy.
*
* The function never logs or returns the password. It returns only policy
* findings that a controller can display or log safely.
*
* @param string $password Candidate password.
* @param array $options Policy options such as min_length and blocked_terms.
* @return array Policy score, validity, and messages.
*/
function ogInspectPasswordPolicy($password, $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
$password = (string)$password;
if (!is_array($options)) {
$options = array();
}
$min_length = 12;
if (!empty($options['min_length'])) {
$min_length = (int)$options['min_length'];
}
if ($min_length < 8) {
$min_length = 8;
}
$blocked_terms = array();
if (!empty($options['blocked_terms']) && is_array($options['blocked_terms'])) {
$blocked_terms = $options['blocked_terms'];
}
$errors = array();
$warnings = array();
$score = 0;
$length = strlen($password);
if ($length >= $min_length) {
$score += 30;
} else {
$errors[] = 'Password is too short.';
}
if (preg_match('/[a-z]/', $password)) {
$score += 10;
} else {
$errors[] = 'Password needs a lowercase letter.';
}
if (preg_match('/[A-Z]/', $password)) {
$score += 10;
} else {
$errors[] = 'Password needs an uppercase letter.';
}
if (preg_match('/[0-9]/', $password)) {
$score += 10;
} else {
$errors[] = 'Password needs a number.';
}
if (preg_match('/[^a-zA-Z0-9]/', $password)) {
$score += 15;
} else {
$errors[] = 'Password needs a symbol.';
}
if ($length >= 16) {
$score += 15;
}
if (!preg_match('/(.)\1{2,}/', $password)) {
$score += 10;
} else {
$warnings[] = 'Password contains repeated characters.';
}
$lower_password = strtolower($password);
foreach ($blocked_terms as $term) {
$term = strtolower(trim((string)$term));
if (!empty($term) && strpos($lower_password, $term) !== false) {
$errors[] = 'Password contains a blocked term.';
}
}
if ($score > 100) {
$score = 100;
}
$valid = empty($errors);
$result['success'] = $valid;
if ($valid) {
$result['message'] = 'Password policy passed.';
} else {
$result['message'] = 'Password policy failed.';
}
$result['data'] = array(
'valid' => $valid,
'score' => $score,
'errors' => $errors,
'warnings' => $warnings,
'length' => $length
);
return $result;
}