Seditio Source
Root |
./othercms/ips_4.3.4/system/3rd_party/phpass/phpass.php
<?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;
    }
}