mcrumley/php-complexify
A PHP port of the Complexify jQuery plugin for server-side password strength checking. It scores passwords by length, character variety, and common patterns, returning a complexity value and validity flag so your backend can enforce the same rules as the frontend.
Install via Composer:
composer require mcrumley/php-complexify
There is no service provider or facade — this is a plain PHP library, so the first place to look is src/ (typically a single Complexify class). Read the constructor and the evaluatePassword() signature before wiring it in; the API mirrors the JS library, so the jquery.complexify.js README is the best conceptual reference for what the numbers mean.
The canonical first use case is server-side password strength validation on registration/reset, mirroring the client-side meter so a user can't bypass it by disabling JS:
use Complexify\Complexify;
$complexify = new Complexify();
// Returns an object with at least: valid (bool), complexity (float), percentage (float)
$result = $complexify->evaluatePassword($request->input('password'));
if (! $result->valid) {
return back()->withErrors(['password' => 'Password is too weak.']);
}
Start with the default minimum complexity (the JS library defaults around 49), confirm the returned percentage behaves as you expect on a few sample passwords, then tune from there.
Form Request rule (recommended integration point). Wrap the library in a custom rule so controllers stay clean and the threshold lives in one place:
class StrongPassword implements Rule
{
public function passes($attribute, $value): bool
{
return (new Complexify())->evaluatePassword($value)->valid;
}
public function message(): string
{
return 'Choose a stronger password (mix case, numbers, symbols, length).';
}
}
Live-feedback endpoint. Keep a small JSON route that the front-end hits on keyup so the meter and the server agree:
Route::post('/password-strength', function (Request $request) {
$r = (new Complexify())->evaluatePassword($request->input('password', ''));
return response()->json(['percentage' => $r->percentage, 'valid' => $r->valid]);
})->middleware('throttle:60,1');
Always re-run the same check in the actual registration handler — the AJAX endpoint is UX, not enforcement.
Layer with breach/dictionary checks. Complexify only measures character-class entropy; pair it with a HaveIBeenPwned range check or a banned-password list for real-world strength. Treat valid as a floor, not a guarantee.
Persist the score for auditing. If you want to nudge users later ("your password is weak, consider rotating"), store complexity/percentage alongside the user (never the password) so you can re-surface the warning without re-prompting.
Consistent thresholds across client and server. If the JS widget on the page uses a different minimum than the PHP validator, users will see green but get rejected. Decide the threshold once and pass it to both.
composer.json, and be prepared to fork or replace it. Budget an afternoon to vendor a copy if PHP-version compatibility bites you on PHP 8.x.P@ssw0rd1 highly. Don't present the percentage as a security guarantee to users or auditors.dd()/Telescope aren't capturing it in the strength-check path.evaluatePassword() accepts an excluded-characters list or a dictionary path, check whether the dictionary ships with the package or must be supplied — a missing list silently weakens the check.PasswordStrength) around it so you can swap in a maintained library (e.g. zxcvbn-php) later without touching call sites.How can I help you explore Laravel packages today?