Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
Vendored
+171
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* Wolfram|Alpha password strength calculation
|
||||
*
|
||||
* @see https://gist.github.com/1514997 (original source this class is based on)
|
||||
* @see http://www.wolframalpha.com/input/?i=password+strength+for+god
|
||||
* @see https://github.com/rchouinard/phpass
|
||||
* @license MIT
|
||||
*/
|
||||
class PasswordStrength {
|
||||
|
||||
const STRENGTH_VERY_WEAK = 1;
|
||||
const STRENGTH_WEAK = 2;
|
||||
const STRENGTH_FAIR = 3;
|
||||
const STRENGTH_STRONG = 4;
|
||||
const STRENGTH_VERY_STRONG = 5;
|
||||
|
||||
public function classifyScore($score) {
|
||||
if ($score < 50) return self::STRENGTH_VERY_WEAK;
|
||||
if ($score < 60) return self::STRENGTH_WEAK;
|
||||
if ($score < 75) return self::STRENGTH_FAIR;
|
||||
if ($score < 90) return self::STRENGTH_STRONG;
|
||||
return self::STRENGTH_VERY_STRONG;
|
||||
}
|
||||
|
||||
public function classify($pw) {
|
||||
return $this->classifyScore($this->calculate($pw));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate score for a password
|
||||
*
|
||||
* @param string $pw the password to work on
|
||||
* @return int score
|
||||
*/
|
||||
public function calculate($pw) {
|
||||
$length = strlen($pw);
|
||||
$score = $length * 4;
|
||||
$nUpper = 0;
|
||||
$nLower = 0;
|
||||
$nNum = 0;
|
||||
$nSymbol = 0;
|
||||
$locUpper = array();
|
||||
$locLower = array();
|
||||
$locNum = array();
|
||||
$locSymbol = array();
|
||||
$charDict = array();
|
||||
// count character classes
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$ch = $pw[$i];
|
||||
$code = ord($ch);
|
||||
/* [0-9] */ if ($code >= 48 && $code <= 57) { $nNum++; $locNum[] = $i; }
|
||||
/* [A-Z] */ elseif ($code >= 65 && $code <= 90) { $nUpper++; $locUpper[] = $i; }
|
||||
/* [a-z] */ elseif ($code >= 97 && $code <= 122) { $nLower++; $locLower[] = $i; }
|
||||
/* . */ else { $nSymbol++; $locSymbol[] = $i; }
|
||||
if (!isset($charDict[$ch])) {
|
||||
$charDict[$ch] = 1;
|
||||
}
|
||||
else {
|
||||
$charDict[$ch]++;
|
||||
}
|
||||
}
|
||||
// reward upper/lower characters if pw is not made up of only either one
|
||||
if ($nUpper !== $length && $nLower !== $length) {
|
||||
if ($nUpper !== 0) {
|
||||
$score += ($length - $nUpper) * 2;
|
||||
}
|
||||
if ($nLower !== 0) {
|
||||
$score += ($length - $nLower) * 2;
|
||||
}
|
||||
}
|
||||
// reward numbers if pw is not made up of only numbers
|
||||
if ($nNum !== $length) {
|
||||
$score += $nNum * 4;
|
||||
}
|
||||
// reward symbols
|
||||
$score += $nSymbol * 6;
|
||||
// middle number or symbol
|
||||
foreach (array($locNum, $locSymbol) as $list) {
|
||||
$reward = 0;
|
||||
foreach ($list as $i) {
|
||||
$reward += ($i !== 0 && $i !== $length -1) ? 1 : 0;
|
||||
}
|
||||
$score += $reward * 2;
|
||||
}
|
||||
// chars only
|
||||
if ($nUpper + $nLower === $length) {
|
||||
$score -= $length;
|
||||
}
|
||||
// numbers only
|
||||
if ($nNum === $length) {
|
||||
$score -= $length;
|
||||
}
|
||||
// repeating chars
|
||||
$repeats = 0;
|
||||
foreach ($charDict as $count) {
|
||||
if ($count > 1) {
|
||||
$repeats += $count - 1;
|
||||
}
|
||||
}
|
||||
if ($repeats > 0) {
|
||||
$score -= (int) (floor($repeats / ($length-$repeats)) + 1);
|
||||
}
|
||||
if ($length > 2) {
|
||||
// consecutive letters and numbers
|
||||
foreach (array('/[a-z]{2,}/', '/[A-Z]{2,}/', '/[0-9]{2,}/') as $re) {
|
||||
preg_match_all($re, $pw, $matches, PREG_SET_ORDER);
|
||||
if (!empty($matches)) {
|
||||
foreach ($matches as $match) {
|
||||
$score -= (strlen($match[0]) - 1) * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// sequential letters
|
||||
$locLetters = array_merge($locUpper, $locLower);
|
||||
sort($locLetters);
|
||||
foreach ($this->findSequence($locLetters, mb_strtolower($pw)) as $seq) {
|
||||
if (count($seq) > 2) {
|
||||
$score -= (count($seq) - 2) * 2;
|
||||
}
|
||||
}
|
||||
// sequential numbers
|
||||
foreach ($this->findSequence($locNum, mb_strtolower($pw)) as $seq) {
|
||||
if (count($seq) > 2) {
|
||||
$score -= (count($seq) - 2) * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $score;
|
||||
}
|
||||
/**
|
||||
* Find all sequential chars in string $src
|
||||
*
|
||||
* Only chars in $charLocs are considered. $charLocs is a list of numbers.
|
||||
* For example if $charLocs is [0,2,3], then only $src[2:3] is a possible
|
||||
* substring with sequential chars.
|
||||
*
|
||||
* @param array $charLocs
|
||||
* @param string $src
|
||||
* @return array [[c,c,c,c], [a,a,a], ...]
|
||||
*/
|
||||
private function findSequence($charLocs, $src) {
|
||||
$sequences = array();
|
||||
$sequence = array();
|
||||
for ($i = 0; $i < count($charLocs)-1; ++$i) {
|
||||
$here = $charLocs[$i];
|
||||
$next = $charLocs[$i+1];
|
||||
$charHere = $src[$charLocs[$i]];
|
||||
$charNext = $src[$charLocs[$i+1]];
|
||||
$distance = $next - $here;
|
||||
$charDistance = ord($charNext) - ord($charHere);
|
||||
if ($distance === 1 && $charDistance === 1) {
|
||||
// We find a pair of sequential chars!
|
||||
if (empty($sequence)) {
|
||||
$sequence = array($charHere, $charNext);
|
||||
}
|
||||
else {
|
||||
$sequence[] = $charNext;
|
||||
}
|
||||
}
|
||||
elseif (!empty($sequence)) {
|
||||
$sequences[] = $sequence;
|
||||
$sequence = array();
|
||||
}
|
||||
}
|
||||
if (!empty($sequence)) {
|
||||
$sequences[] = $sequence;
|
||||
}
|
||||
return $sequences;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user