To match a nested structure, you need a recursive pattern, example:
$data = '[quote]something [quote]something else[/quote] some text here[/quote]';
$pattern = '~\[quote](?>[^][]+|(?R))*\[/quote]~';
if (preg_match_all($pattern, $data, $m))
print_r(m);
pattern details:
~ # pattern delimiter: do not choose the slash here
\[quote] #
(?> # open an atomic group: possible content between tags
[^][]+ # all that is not a square bracket
| # OR
(?R) # recurse the whole pattern
)* # close the atomic group, repeat zero or more times
\[/quote] #
~
Note that it's quite easy. But now if your code may contain other parasite tags between "quote" tags, you only need to change the atomic group to allow them (written in extended mode):
(?> [^][]+ | \[/? (?!quote\b) [^]]* ] | (?R) )*