Skip to content

Instantly share code, notes, and snippets.

@elazar
Created November 6, 2011 04:55
Show Gist options
  • Save elazar/1342491 to your computer and use it in GitHub Desktop.
Save elazar/1342491 to your computer and use it in GitHub Desktop.
Iterator to generate sequential passwords within a given length range
<?php
/**
* Iterator to generate sequential passwords within a given length range.
*/
class PasswordIterator implements Iterator
{
/**
* Length of the next password to be generated
* @var int
*/
protected $length;
/**
* Minimum password length
* @var int
*/
protected $min;
/**
* Maximum password length
* @var int
*/
protected $max;
/**
* Number of passwords that have been generated, returned by key()
* @var int
*/
protected $counter;
/**
* Next password to be returned, stored in an array with one character
* per element to allow for easy incrementation, returned by current()
* @var array
*/
protected $password;
/**
* Mapping of ASCII codes to corresponding characters, used for
* incrementation
* @var array
*/
protected $chr;
/**
* Mapping of ASCII characters to corresponding codes, used for
* incrementation
* @var array
*/
protected $ord;
/**
* First character to which a character position is reset when its
* preceding character is incremented
* @var string
*/
protected $first;
/**
* Last character to which a character position is set before its
* preceding character is incremented
* @var string
*/
protected $last;
/**
* Last character position for the current password length
* @var int
*/
protected $end;
/**
* Last password of the current length that will be generated, used to
* indicate when the length must be incremented
* @var string
*/
protected $stop;
/**
* Initializes properties used for password storage and incrementation.
*
* @param int $min Minimum password length, defaults to 1
* @param int $max Maximum password length, defaults to none
* @return void
*/
public function __construct($min = 1, $max = null)
{
$this->min = $min;
$this->max = $max;
$this->chr = array_combine(range(32, 126), array_map('chr', range(32, 126)));
$this->ord = array_flip($this->chr);
$this->first = reset($this->chr);
$this->last = end($this->chr);
$this->rewind();
}
/**
* Increments the password length and adjusts related properties
* accordingly.
* @return void
*/
protected function increment()
{
$this->length++;
$this->password = array_fill(0, $this->length, $this->first);
$this->stop = array_fill(0, $this->length, $this->last);
$this->end = $this->length - 1;
}
/**
* Reinitializes properties to begin generating passwords of the
* minimum length again.
* @return void
*/
public function rewind()
{
$this->length = $this->min - 1;
$this->counter = 1;
$this->increment();
}
/**
* Returns the current password.
* @return string
*/
public function current()
{
return implode('', $this->password);
}
/**
* Returns the number of passwords generated.
* @return int
*/
public function key()
{
return $this->counter;
}
/**
* Generates a new password.
* @return void
*/
public function next()
{
$this->counter++;
if ($this->password == $this->stop) {
$this->increment();
} else {
for ($left = $this->end; isset($this->password[$left]) && $this->password[$left] == $this->last; $left--);
if (isset($this->password[$left]) && $this->password[$left] != $this->last) {
$this->password[$left] = $this->chr[$this->ord[$this->password[$left]] + 1];
for ($index = $left + 1; $index < $this->length; $index++) {
$this->password[$index] = $this->first;
}
}
}
}
/**
* Returns whether the next password is valid with respect to the
* given length range.
* @return boolean TRUE if the current password has a length under the
* maximum or no maximum is set
*/
public function valid()
{
return $this->max ? ($this->max >= $this->length) : true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment