<?php
    function parse($text)
    {
        // Find each character group: [...]
    	preg_match_all('/(.*?)(?:\[([^[\]]{1,30})\]|$)/s', $text, $matches, PREG_SET_ORDER);
        $groups = [];
        foreach ($matches as $match) {
            if (!empty($match[1])) {
                // Prefix: foo
                $groups []= $match[1];
            }
            if (!empty($match[2])) {
                // Group: [a-z0-9]
                // For each range, add the chars to an array. ['a', 'b', ..., 'z', '0', ..., '9']
                $chrs = [];
                preg_match_all('/(.)(?:-(.))?/', $match[2], $ranges, PREG_SET_ORDER);
                foreach ($ranges as $rng)
                {
                    if (empty($rng[2])) {
                        $chrs []= $rng[1];
                    }
                    else {
                        $chrs = array_merge($chrs, range($rng[1], $rng[2]));
                    }
                }
                $groups []= $chrs;
            }
        }
        return $groups;
    }
    
    function permute($groups, $index = 0)
    {
        $result = [];
        if ($index >= count($groups))
        {
            // Reached the end. Return a single, empty result.
            $result []= '';
        }
        else if (is_string($groups[$index]))
        {
            // Current group is a simple string. Prepend it to all tail results.
            $prefix = $groups[$index];
            foreach (permute($groups, $index+1) as $s)
            {
                $result []= $prefix . $s;
            }
        }
        else {
            // Otherwise it is an array of characters. Prepend each to every tail result.
            $chars = $groups[$index];
            foreach (permute($groups, $index+1) as $s)
            {
                foreach ($chars as $ch) {
                    $result []= $ch . $s;
                }
            }
        }
        
        return $result;
    }
    
    $text = 'test[A-BXZ][0-1][x-z]foo';
    
    $groups = parse($text);
    print_r($groups);
    
    $permutations = permute($groups);
    print_r($permutations);
?>