<?php

class passgen {

    public 
$answers 3;
    public 
$length 20;
    
    public 
$error false;
    public 
$error_settings false;
    public 
$password '';

    private 
$input null;
    private 
$number '';
    
    
    public function 
__construct$INPUT null$answers null$length null ) {
        
        if( 
null !== $answers ) {
            
$this->answers $answers;
        }
        
        if(
            ( 
null !== $INPUT && count($INPUT) < ) ||
            
$this->answers 2
        
) {
            
$this->error_settings 'Cannot have less than 2 answers.';
            return 
false;
        }
        
        if( 
null !== $length ) {
            
$this->length $length;
        }
        
        if( 
$this->length 10 || $this->length 40 ) {
            
$this->error_settings 'The length must be at least 10 chars and max 40.';
            return 
false;
        }
        
        if( 
null === $INPUT ) {
            return 
false;
        }
        
        
$this->input = (array)$INPUT;
        foreach( 
$this->input as &$inp ) { $inp trim($inp); }
        
        
$answers = array();
        foreach( 
$this->input as $answer ) {
        
            
$answer trim($answer);
        
            if( 
strlentrim($answer) ) < ) {
                
$this->error 'Each answer must have 1 or more characters.';
                return 
false;
            }
            if( 
in_array($answer$answers) ) {
                
$this->error 'You must have different answers. Two or more of your answers are the same.';
                return 
false;
            }
            
$answers[] = $answers;
            
$this->calculateNumericalValue$answer );
        }
        
$this->password $this->computePassword();
        
    }
    
    
    private function 
calculateNumericalValue$word ) {
        
$allLength md5implode(''$this->input) );
        
$word sha1($allLength $word);
        foreach( 
str_split($word) as $w ) {
            
$this->number .= decbin ord($w) );
        }
    }
    
    
    private function 
computePassword() {
        
        
$splitTheNumber str_split($this->number);
        
$position 0;
        
$noOfBits 8;
        
        
$counter 0;
        
        foreach( 
$splitTheNumber as $digit ) {
            
            if( 
$position strlen($this->number) - $noOfBits ) {
                break;
            }
            
            
// get current number
            
$currentNumber = (int) ( bindec ( (string) substr($this->number$position$noOfBits) ) );

            
$charToAdd $this->addChar$currentNumber );
            
            if( 
false !== $charToAdd ) {
                
$charsToAdd[$counter] = $charToAdd;
                
$counter++;
            }
            
            
$position++;
            
        }

        
$rangeLength floor($counter/$this->length);
        
        
// return $rangeLength;
        
$password '';
        for( 
$i 0$i<=$counter$i++ ) {
            
            if( !( 
$i $rangeLength ) && isset($charsToAdd[$i]) ) {
                
$password .= $charsToAdd[$i];
            }
        }
        
        return 
$password;
    }
    
    private function 
addChar$currentNumber ) {
        
/*
            special    -> 33 - 47, 58 - 64, 91 - 96
            digit    -> 48 - 57
            A-Z        -> 65 - 90
            a-z        -> 97 - 122
        */
        
if(
        
            
// special chars
            
$currentNumber >= 33 && $currentNumber <= 47 ) ||
            ( 
$currentNumber >= 58 && $currentNumber <= 64 ) ||
            ( 
$currentNumber >= 91 && $currentNumber <= 96 ) ||
            
            
// digit
            
$currentNumber >= 48 && $currentNumber <= 57 ) ||
            
            
// upper
            
$currentNumber >= 65 && $currentNumber <= 90 ) ||
            
            
// lower
            
$currentNumber >= 97 && $currentNumber <= 100 )
        
        ) {
            return 
chr($currentNumber);
        }
        
        
// lower
        
if( $currentNumber >= && $currentNumber <= 22 ) {
            return 
chr('1'.$currentNumber);
        }

        return 
false;
        
    }
    
}

/*

// Usage
// $a = new passgen( array( 'answer', 'first', 'last' ) );
$PWD = new passgen( array( 'answer', 'first', 'last' ), 3, 20 );
echo '<br />Error: '.$PWD->error;
echo '<br />Settings error: '.$PWD->error_settings;
echo '<br />Password: '.$PWD->password;

*/