Advent of code 2016/21
Ajax Direct

Answer

Part 1 :
Part 2 :
function solve($pass, $instructions, $reverse = false) {
    $pass = set(str_split($pass));

    foreach ($instructions as $line) {

        if (preg_match("/rotate (right|left) (\d)/", $line, $matches)) {
            $direction = ($matches[1] == "left" && !$reverse) || ($matches[1] == "right" && $reverse) ? -1 : 1;
            $pass = $pass->rotate(($matches[2] % count($pass)) * $direction);
        }

        if (preg_match("/swap position (\d) with position (\d)/", $line, $matches)) {
            [$pass[$matches[1]], $pass[$matches[2]]] = [$pass[$matches[2]], $pass[$matches[1]]];
        }

        if (preg_match("/swap letter (\w) with letter (\w)/", $line, $matches)) {
            [$a, $b] = [$pass->search($matches[1]), $pass->search($matches[2])];
            [$pass[$a], $pass[$b]] = [$pass[$b], $pass[$a]];
        }

        if (preg_match("/reverse positions? (\d) through (\d)/", $line, $matches)) {
            $pass->splice(
                $matches[1], $matches[2] - $matches[1] + 1,
                $pass->slice($matches[1], $matches[2] - $matches[1] + 1)->reverse()
            );
        }

        if (preg_match("/move position (\d) to position (\d)/", $line, $matches)) {
            [$a, $b] = $reverse ? [$matches[2], $matches[1]] : [$matches[1], $matches[2]];
            $letter = $pass[$a];
            unset($pass[$a]);
            $pass->splice($b, 0, [$letter]);
        }

        if (preg_match("/rotate based on position of letter (\w)/", $line, $matches)) {
            $rots = $rots ?? set(range(0, $pass->count() - 1))->map(fn ($i) => ($i + 1 + ($i > 3 ? 1 : 0)) % $pass->count());

            if (!$reverse) {
                $pass = $pass->rotate($rots[$pass->search($matches[1])]);
            } else {
                $rrots = $rrots ?? $rots->map(fn ($v, $k) => ($v + $k) % $rots->count(), true)->flip();
                $pos = $rrots[$pass->search($matches[1])];
                $pass = $pass->rotate($pos - $pass->search($matches[1]));
            }
        }
    }

    return $pass->join("");
}

// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = solve("abcdefgh", $input->lines, false);
$solution_2 = solve("fbgdceah", $input->lines->reverse(), true);