src/Matchers/SpatialMatch.php
protected static function graphMatch($password, $graph)
    {
        $result = [];
        $i = 0;

        $passwordLength = strlen($password);

        while ($i < $passwordLength - 1) {
            $j = $i + 1;
            $lastDirection = null;
            $turns = 0;
            $shiftedCount = 0;

            while (true) {
                $prevChar = $password[$j - 1];
                $found = false;
                $curDirection = -1;
                $adjacents = isset($graph[$prevChar]) ? $graph[$prevChar] : [];
                // Consider growing pattern by one character if j hasn't gone over the edge.
                if ($j < $passwordLength) {
                    $curChar = $password[$j];
                    foreach ($adjacents as $adj) {
                        ++$curDirection;
                        $curCharPos = static::indexOf($adj, $curChar);
                        if ($adj && $curCharPos !== -1) {
                            $found = true;
                            $foundDirection = $curDirection;

                            if (1 === $curCharPos) {
                                // index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
                                // for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
                                ++$shiftedCount;
                            }
                            if ($lastDirection !== $foundDirection) {
                                // adding a turn is correct even in the initial case when last_direction is null:
                                // every spatial pattern starts with a turn.
                                ++$turns;
                                $lastDirection = $foundDirection;
                            }

                            break;
                        }
                    }
                }

                // if the current pattern continued, extend j and try to grow again
                if ($found) {
                    ++$j;
                }
                // otherwise push the pattern discovered so far, if any...
                else {
                    // Ignore length 1 or 2 chains.
                    if ($j - $i > 2) {
                        $result[] = [
                            'begin' => $i,
                            'end' => $j - 1,
                            'token' => substr($password, $i, $j - $i),
                            'turns' => $turns,
                            'shifted_count' => $shiftedCount,
                        ];
                    }
                    // ...and then start a new search for the rest of the password.
                    $i = $j;

                    break;
                }
            }
        }

        return $result;
    }
protected static function graphMatch($password, $graph)
    {
        $result = [];
        $i = 0;

        $passwordLength = strlen($password);

        while ($i < $passwordLength - 1) {
            $j = $i + 1;
            $lastDirection = null;
            $turns = 0;
            $shiftedCount = 0;

            while (true) {
                $prevChar = $password[$j - 1];
                $found = false;
                $curDirection = -1;
                $adjacents = isset($graph[$prevChar]) ? $graph[$prevChar] : [];
                // Consider growing pattern by one character if j hasn't gone over the edge.
                if ($j < $passwordLength) {
                    $curChar = $password[$j];
                    foreach ($adjacents as $adj) {
                        ++$curDirection;
                        $curCharPos = static::indexOf($adj, $curChar);
                        if ($adj && $curCharPos !== -1) {
                            $found = true;
                            $foundDirection = $curDirection;

                            if (1 === $curCharPos) {
                                // index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
                                // for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
                                ++$shiftedCount;
                            }
                            if ($lastDirection !== $foundDirection) {
                                // adding a turn is correct even in the initial case when last_direction is null:
                                // every spatial pattern starts with a turn.
                                ++$turns;
                                $lastDirection = $foundDirection;
                            }

                            break;
                        }
                    }
                }

                // if the current pattern continued, extend j and try to grow again
                if ($found) {
                    ++$j;
                }
                // otherwise push the pattern discovered so far, if any...
                else {
                    // Ignore length 1 or 2 chains.
                    if ($j - $i > 2) {
                        $result[] = [
                            'begin' => $i,
                            'end' => $j - 1,
                            'token' => substr($password, $i, $j - $i),
                            'turns' => $turns,
                            'shifted_count' => $shiftedCount,
                        ];
                    }
                    // ...and then start a new search for the rest of the password.
                    $i = $j;

                    break;
                }
            }
        }

        return $result;
    }
protected static function graphMatch ( $ password , $ graph ) { $ result = [ ] ; $ i = 0 ; $ passwordLength = strlen ( $ password ) ; while ( $ i < $ passwordLength - 1 ) { $ j = $ i + 1 ; $ lastDirection = null ; $ turns = 0 ; $ shiftedCount = 0 ; while ( true ) { $ prevChar = $ password [ $ j - 1 ] ; $ found = false ; $ curDirection = - 1 ; $ adjacents = isset ( $ graph [ $ prevChar ] ) ? $ graph [ $ prevChar ] : [ ] ; // Consider growing pattern by one character if j hasn't gone over the edge. if ( $ j < $ passwordLength ) { $ curChar = $ password [ $ j ] ; foreach ( $ adjacents as $ adj ) { ++ $ curDirection ; $ curCharPos = static :: indexOf ( $ adj , $ curChar ) ; if ( $ adj && $ curCharPos !== - 1 ) { $ found = true ; $ foundDirection = $ curDirection ; if ( 1 === $ curCharPos ) { // index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc. // for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted. ++ $ shiftedCount ; } if ( $ lastDirection !== $ foundDirection ) { // adding a turn is correct even in the initial case when last_direction is null: // every spatial pattern starts with a turn. ++ $ turns ; $ lastDirection = $ foundDirection ; } break ; } } } // if the current pattern continued, extend j and try to grow again if ( $ found ) { ++ $ j ; } // otherwise push the pattern discovered so far, if any... else { // Ignore length 1 or 2 chains. if ( $ j - $ i > 2 ) { $ result [ ] = [ 'begin' => $ i , 'end' => $ j - 1 , 'token' => substr ( $ password , $ i , $ j - $ i ) , 'turns' => $ turns , 'shifted_count' => $ shiftedCount , ] ; } // ...and then start a new search for the rest of the password. $ i = $ j ; break ; } } } return $ result ; }
Match spatial patterns in a adjacency graph.

@param string $password
@param array  $graph

@return array
Match spatial patterns in a adjacency graph .