<?php

$charset = "abcdefghijklmnopqrstuvwxyz0123456789";
$charset_len = strlen($charset);
$state = array_fill(0, 4, 0);

function next_state() {
  global $state, $charset_len;
  for ($i = 0; $i < count($state); $i++) {
    $state[$i] = $state[$i] + 1;

    if ($state[$i] < $charset_len) {
      // Если переноса на следующий "разряд" нет, то
      // нам делать уже нечего, и мы просто выходим.
      return true;
    } else {
      // Перенос есть, его нужно добавить к следующему
      // "разряду", а этот сбросить.
      $state[$i] = 0;
    }
  }

  // Если мы здесь оказались, то инкрементировать нам
  // уже нечего, а хотелось бы.
  // Например, если $charset_len = 10, а в буфере было
  // 99999, то сейчас там 00000, т.е., мы перебрали все
  // состояния для этой длины. Можно либо увеличить длину
  // буфера (чтобы проверить следующую длину), либо
  // сигнализировать об окончании перебора.

  return false;
}

function try_state() {
  global $state, $charset;

  $password = "";

  // Отображаем текущее состояние на алфавит.
  for ($i = 0; $i < count($state); ++$i) {
    $password .= $charset[$state[$i]];
  }

  echo "Trying '$password'...";

  if (md5($password) == "e7806b130b429fc9b5890608a2c60675") {
    echo "YES!\n\nPassword is '$password'\n";
    return true;
  } else {
    echo "wrong\n";
    return false;
  }
}

while (1)
{
  if (try_state()) {
    break;
  }

  if (!next_state()) {
    echo "Bruteforce failed. Try another password length and/or another charset.\n";
    break;
  }
}
?>
