Advent of code 2016/14
Ajax Direct

Answer

Part 1 :
Part 2 :
function xmd5($salt, $start, $count, $part2) {
    $md5 = "";
    for ($i = 0; $i < $count; $i++) {
        $add = md5($salt . ($start + $i)) ;
        if ($part2) for ($j = 0; $j < 2016; $j++) $add = md5($add);
        $md5 .= $add . "|";
    };
    return [$md5, $start + $count];
}

function solve($salt, $part2 = false) {
    [$md5, $i] = xmd5($salt, 0, 10000, $part2);

    $found = 0; $pos = -1;
    while ($found < 64) {
        preg_match("/([^|]*)(.)\\2\\2.{0,33000}\\2{5}/", $md5, $match, PREG_OFFSET_CAPTURE);
        $three = floor($match[2][1] / 33) + 1;

        [$extra, $i] = xmd5($salt, $i, $three, $part2);
        $md5 = substr($md5, $three * 33) . $extra;

        $pos += $three;
        if (!preg_match("/(.)\\1\\1/", $match[1][0], $test)) $found++;
    }

    return $pos;
}

// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = solve($input);
$solution_2 = solve($input, true);