Maybe I didn't explain properly.
I'm referring to this part:
I think that this should do it:
elseif ($tag === 'web' && (($userdata['user_level'] == ADMIN) || ($userdata['user_level'] == MOD)))
{
$html = '<iframe src="' . $content . '" width="' . $width . '" height="' . $height . '" marginwidth="0" marginheight="0" frameborder="0" scrolling="yes"></iframe>';
}
Your code checks the permission with $userdata, but $userdata in bbcode.php just contains current user permission, and bbcode.php is not checking if the content is going to be added to DB or not... it just checks the level of the user viewing the parsed text.
Maybe an example will help.
If ME as an admin I add the [web]URL[/web] code, the code will be processed and shown to myself... but when a normal user try to display the post, when bbcode parses the text it checks against userdata, that means that the user won't see the content because it is not an admin... I don't know if you get my point.
On the opposite, if a normal user post the [web]URL[/web] tags, then only admins will be able to display that, not normal users... this is still leading to security issues, because any user can still inject HTML code and attack any admin or moderator who are able to display the code properly.
Instead of working on bbcode.php, you should instead work at a posting level, checking then which is the level of the user posting such a content, and remove or sanitize the unwanted tags at that stage... because it's only at that point that you can tell if the user is allowed to post such kind of content or not...
If you have a chance to test latest dev version of Icy Phoenix, there is a new option in ACP where you can allow administrators to add HTML to posts, and I'm confident that it is quite safe, because it checks the permissions when posting, and not when viewing. This just means that if a user has admin rights, can post HTML and it will be added to DB as HTML code... if the user is not an admin, any new post or post edit (because you have also to deal with post editing!) will be sanitized against any HTML markup and it will be shown as it is just text and not HTML.
Sorry, but it's tough for me trying to explain this, because it's not an easy matter.
Anyway if it is still not clear (or if I misunderstood your post), I can try to explain again.