Skip to content

Instantly share code, notes, and snippets.

@mingtsay
Last active February 3, 2019 04:53
Show Gist options
  • Save mingtsay/49df26da9e6094b70e81 to your computer and use it in GitHub Desktop.
Save mingtsay/49df26da9e6094b70e81 to your computer and use it in GitHub Desktop.
Password Generator by Ming Tsay
<?php
define('PWGEN_SYMBOLS', 0x01);
define('PWGEN_NUMBERS', 0x02);
define('PWGEN_LOWERS', 0x04);
define('PWGEN_UPPERS', 0x08);
define('PWGEN_EX_SIMILAR', 0x10);
define('PWGEN_EX_AMBIGUOUS', 0x20);
define('PWGEN_SEPARATOR_ARRAY', 0);
define('PWGEN_SEPARATOR_LF', 1);
define('PWGEN_SEPARATOR_CR', 2);
define('PWGEN_SEPARATOR_CRLF', 3);
define('PWGEN_SEPARATOR_TAB', 4);
define('PWGEN_SEPARATOR_COMMA', 5);
define('PWGEN_SEPARATOR_SEMICOLON', 6);
function pwgen($length = 16, $chars = 15, $counts = 1, $sep = 0) {
if (is_int($chars)) {
$symbols = '!#$%&*+-=?@^_' . (PWGEN_EX_SIMILAR & $chars ? '' : '|') . (PWGEN_EX_AMBIGUOUS & $chars ? '' : '{}[]()/\'"`~,;:.<>\\');
$numbers = '23456789' . (PWGEN_EX_SIMILAR & $chars ? '' : '01');
$lowers = 'abcdefghjkmnpqrstuvwxyz' . (PWGEN_EX_SIMILAR & $chars ? '' : 'ilo');
$uppers = 'ABCDEFGHJKLMNPQRSTUVWXYZ' . (PWGEN_EX_SIMILAR & $chars ? '' : 'IO');
$characters = (PWGEN_SYMBOLS & $chars ? $symbols : '') . (PWGEN_NUMBERS & $chars ? $numbers : '') . (PWGEN_LOWERS & $chars ? $lowers : '') . (PWGEN_UPPERS & $chars ? $uppers : '');
} else $characters = $chars;
if (is_int($sep)) {
$separator = false;
switch ($sep) {
case PWGEN_SEPARATOR_LF: $separator = "\n"; break;
case PWGEN_SEPARATOR_CR: $separator = "\r"; break;
case PWGEN_SEPARATOR_CRLF: $separator = "\r\n"; break;
case PWGEN_SEPARATOR_TAB: $separator = "\t"; break;
case PWGEN_SEPARATOR_COMMA: $separator = ','; break;
case PWGEN_SEPARATOR_SEMICOLON: $separator = ';'; break;
}
} else $separator = $sep;
$pwgen = array();
for ($i = 0; $i < $counts; ++$i) {
$randoms = random_ints(0, strlen($characters) - 1, $length);
$pw = '';
foreach ($randoms as $random) $pw .= $characters[$random];
$pwgen[] = $pw;
}
return false === $separator ? ($counts === 1 ? $pwgen[0] : $pwgen) : implode($separator, $pwgen);
}
if ('cli' === PHP_SAPI) {
$usage = 'Usage: php pwgen.php [options]
-l LENGTH --length=LENGTH Set password length. Default: -l16
-c FLAGS --characters=CHARS Set the characters for generating.
Default: -cABLNSU
B --include-symbols Include symbols. (e.g. @#$%)
N --include-numbers Include numbers. (e.g. 123456)
L --include-lowers Include lowercase characters.
(e.g. abcdefgh)
U --include-uppers Include uppercase characters.
(e.g. ABCDEFGH)
S --exclude-similar Exclude similar characters.
(e.g. i,|,1,l,I,o,0,O)
A --exclude-ambiguous Exclude ambiguous characters.
({}[]()/\\\'"`~,;:.<>)
-n COUNTS --counts=COUNTS Amount of generating. Default: -n1
-s FLAGS --separator=STR Set separator for generating more than
one password. Default: -sF
F --separator-lf "\n"
R --separator-cr "\r"
N --separator-newline "\r\n"
--separator-crlf "\r\n"
T --separator-tab "\t"
C --separator-comma ","
S --separator-semicolon ";"
-t --no-trailing Don\'t print the trailing newline
character.
-h --help Display this message.
';
$args = array(
'length' => false,
'character-flag' => 0,
'characters' => '',
'counts' => false,
'separator-flag' => 0,
'separator' => '',
'no-trailing' => false,
'help' => false,
'error' => false,
);
$display_help = false;
for ($i = 1; $i < $argc; ++$i) {
$arg = $argv[$i];
if ('-' === $arg[0]) {
if ('-' === $arg[1]) {
$e = explode('=', $arg, 2);
if (count($e) > 1) switch ($e[0]) {
case '--length':
if (!is_numeric($e[1])) {
$args['error'] = 'Invalid length: ' . $e[1];
break 2;
}
$args['length'] = (int) $e[1];
break;
case '--characters':
if ($args['character-flag']) {
$args['error'] = 'Cannot use `--characters` and `-c FLAGS` at the same time.';
break 2;
}
$args['characters'] = $e[1];
break;
case '--counts':
if (!is_numeric($e[1])) {
$args['error'] = 'Invalid counts: ' . $e[1];
break 2;
}
$args['counts'] = (int) $e[1];
break;
case '--separator':
if ($args['separator-flag']) {
$args['error'] = 'Cannot use `--separator` and `-s FLAG` at the same time.';
break 2;
}
$args['separator'] = $e[1];
break;
default:
$args['error'] = 'Unknown option: ' . $arg;
break 2;
} else {
if ('clude' === substr($arg, 4, 5) && $args['characters'] !== '') {
$args['error'] = 'Cannot use `--characters` and `-c FLAGS` at the same time.';
break;
}
if ('separator' === substr($arg, 2, 9) && $args['separator'] !== '') {
$args['error'] = 'Cannot use `--separator` and `-s FLAG` at the same time.';
break;
}
if ('separator' === substr($arg, 2, 9) && $args['separator-flag']) {
$args['error'] = 'Only one flag can be set for the separator.';
break;
}
switch ($arg) {
case '--length':
case '--characters':
case '--counts':
case '--separator':
$args['error'] = "Error: option `$arg` must have a value.";
break 2;
case '--include-symbols': $args['character-flag'] += PWGEN_SYMBOLS; break;
case '--include-numbers': $args['character-flag'] += PWGEN_NUMBERS; break;
case '--include-lowers': $args['character-flag'] += PWGEN_LOWERS; break;
case '--include-uppers': $args['character-flag'] += PWGEN_UPPERS; break;
case '--exclude-similar': $args['character-flag'] += PWGEN_EX_SIMILAR; break;
case '--exclude-ambiguous': $args['character-flag'] += PWGEN_EX_AMBIGUOUS; break;
case '--separator-lf': $args['separator-flag'] = PWGEN_SEPARATOR_LF; break;
case '--separator-cr': $args['separator-flag'] = PWGEN_SEPARATOR_CR; break;
case '--separator-newline':
case '--separator-crlf': $args['separator-flag'] = PWGEN_SEPARATOR_CRLF; break;
case '--separator-tab': $args['separator-flag'] = PWGEN_SEPARATOR_TAB; break;
case '--separator-comma': $args['separator-flag'] = PWGEN_SEPARATOR_COMMA; break;
case '--separator-semicolon': $args['separator-flag'] = PWGEN_SEPARATOR_SEMICOLON; break;
break;
case '--no-trailing':
$args['no-trailing'] = true;
break;
case '--help':
$args['help'] = true;
break;
default:
$args['error'] = 'Unknown option: ' . $arg;
break 2;
}
}
} else {
$e = strlen($arg) > 2 ? substr($arg, 2) : ($argc > $i + 1 ? $argv[++$i] : ' ');
switch($arg[1]) {
case 'l':
if (!is_numeric($e)) {
$args['error'] = 'Invalid length: ' . $e;
break 2;
}
$args['length'] = (int) $e;
break;
case 'c':
if ($args['characters'] !== '') {
$args['error'] = 'Cannot use `--characters` and `-c FLAGS` at the same time.';
break 2;
}
for ($j = 0; $j < strlen($e); ++$j)
switch ($e[$j]) {
case 'B': $args['character-flag'] += PWGEN_SYMBOLS; break;
case 'N': $args['character-flag'] += PWGEN_NUMBERS; break;
case 'L': $args['character-flag'] += PWGEN_LOWERS; break;
case 'U': $args['character-flag'] += PWGEN_UPPERS; break;
case 'S': $args['character-flag'] += PWGEN_EX_SIMILAR; break;
case 'A': $args['character-flag'] += PWGEN_EX_AMBIGUOUS; break;
default:
$args['error'] = 'Invalid character flag: ' . $e[$j];
break 4;
}
break;
case 'n':
if (!is_numeric($e)) {
$args['error'] = 'Invalid counts: ' . $e;
break 2;
}
$args['counts'] = (int) $e;
break;
case 's':
if ($args['separator'] !== '') {
$args['error'] = 'Cannot use `--separator` and `-s FLAG` at the same time.';
break 2;
}
if (strlen($e) > 1) {
$args['error'] = 'Only one flag can be set for the separator.';
break 2;
}
switch ($e) {
case 'F': $args['separator-flag'] = PWGEN_SEPARATOR_LF; break;
case 'R': $args['separator-flag'] = PWGEN_SEPARATOR_CR; break;
case 'N': $args['separator-flag'] = PWGEN_SEPARATOR_CRLF; break;
case 'T': $args['separator-flag'] = PWGEN_SEPARATOR_TAB; break;
case 'C': $args['separator-flag'] = PWGEN_SEPARATOR_COMMA; break;
case 'S': $args['separator-flag'] = PWGEN_SEPARATOR_SEMICOLON; break;
default:
$args['error'] = 'Invalid separator flag: ' . $e;
break 3;
}
break;
case 't':
$args['no-trailing'] = true;
break 2;
case 'h':
$args['help'] = true;
break 2;
default:
$args['error'] = 'Unknown option: ' . $arg;
break 2;
}
}
} else {
$args['error'] = 'Unknown option: ' . $arg;
break;
}
}
if ($args['help'] || $args['error']) {
if ($args['error'])
fwrite(STDERR, $args['error'] . "\n\n");
fwrite(STDERR, $usage);
exit(64); // EX_USAGE
}
$config = array(
'length' => 16,
'characters' =>
PWGEN_SYMBOLS |
PWGEN_NUMBERS |
PWGEN_LOWERS |
PWGEN_UPPERS |
PWGEN_EX_SIMILAR |
PWGEN_EX_AMBIGUOUS,
'counts' => 1,
'separator' => PWGEN_SEPARATOR_LF,
);
if ($args['length'] !== false) $config['length'] = $args['length'];
if ($args['characters'] !== '') $config['characters'] = $args['characters'];
if ($args['character-flag']) $config['characters'] = $args['character-flag'];
if ($args['counts'] !== false) $config['counts'] = $args['counts'];
if ($args['separator'] !== '') $config['separator'] = $args['separator'];
if ($args['separator-flag']) $config['separator'] = $args['separator-flag'];
echo(pwgen($config['length'], $config['characters'], $config['counts'], $config['separator']) . ($args['no-trailing'] ? '' : "\n"));
}
function random_ints($min, $max, $count) {
$mod = $max - $min + 1;
$random = file_get_contents('/dev/urandom', false, null, -1, $count);
$result = array();
for ($i = 0; $i < strlen($random); ++$i)
$result[] = hexdec(bin2hex($random[$i])) % $mod + $min;
return $result;
}
@mingtsay
Copy link
Author

mingtsay commented Mar 8, 2016

pwgen - Generate password with /dev/urandom

Description
mixed pwgen( [ int $length = 16 [, mixed $chars = 15 [, int $counts = 1 [, mixed $sep = 0 ]]]] )

Parameters
See the usage for CLI below.

Return Values
Returns the generated password string. It returns an array when counts greater than 1 and sep is set to zero.

For CLI:

~ $ php pwgen.php --help
Usage: php pwgen.php [options]

    -l LENGTH       --length=LENGTH     Set password length. Default: -l16

    -c FLAGS        --characters=CHARS  Set the characters for generating.
                                        Default: -cABLNSU
                B   --include-symbols   Include symbols. (e.g. @#$%)
                N   --include-numbers   Include numbers. (e.g. 123456)
                L   --include-lowers    Include lowercase characters.
                                        (e.g. abcdefgh)
                U   --include-uppers    Include uppercase characters.
                                        (e.g. ABCDEFGH)
                S   --exclude-similar   Exclude similar characters.
                                        (e.g. i,|,1,l,I,o,0,O)
                A   --exclude-ambiguous Exclude ambiguous characters.
                                        ({}[]()/\'"`~,;:.<>)

    -n COUNTS       --counts=COUNTS     Amount of generating. Default: -n1

    -s FLAGS        --separator=STR     Set separator for generating more than
                                        one password. Default: -sF
                F   --separator-lf          "\n"
                R   --separator-cr          "\r"
                N   --separator-newline     "\r\n"
                    --separator-crlf        "\r\n"
                T   --separator-tab         "\t"
                C   --separator-comma       ","
                S   --separator-semicolon   ";"

    -t              --no-trailing       Don't print the trailing newline
                                        character.

    -h              --help              Display this message.
~ $

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment