Skip to content
← Back to Functions
Code

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;
}