处理用户输入HTML:textarea未闭合标签问题求助
Hey there, let's fix that unclosed tag problem you're dealing with! Your current code does a solid job stripping out unwanted tags and cleaning up any attributes, but it doesn't handle unclosed <b>, <u>, or <i> tags—this can lead to weird formatting where the rest of your content stays bold/italic/underlined indefinitely. Here are two reliable ways to solve this:
This is the most robust tool for filtering and fixing HTML. It automatically closes unclosed tags, ensures proper nesting, and avoids all the edge cases that regex can miss.
- First, install it via Composer (if you're using it):
composer require ezyang/htmlpurifier - Then set up the purifier to only allow your three tags:
require_once __DIR__ . '/vendor/autoload.php'; $config = HTMLPurifier_Config::createDefault(); // Only permit <b>, <u>, <i> $config->set('HTML.Allowed', 'b,u,i'); $purifier = new HTMLPurifier($config); // Process the user input $description = $purifier->purify($_POST['description']);
This will take something like <b>This is a <i>Test and turn it into <b>This is a <i>Test</i></b>, fixing the unclosed tags automatically.
If you don't want to add a third-party library, you can use a simple function to track and close unopened tags. Just keep in mind: regex isn't perfect for HTML, so this works best for basic, straightforward input.
Here's the code:
function closeUnclosedTags($html) { // Grab all open <b>, <u>, <i> tags (ignore self-closing ones, though we don't have those here) preg_match_all('/<([bui])(?![^>]*\/>)/i', $html, $openTags); // Reverse the list so we close inner tags first $openTags = array_reverse($openTags[1]); foreach ($openTags as $tag) { // Check if this tag has a matching closing tag later in the string $tagStartPos = strpos($html, '<' . $tag . '>'); if ($tagStartPos !== false && !preg_match('/<\/' . $tag . '>/i', substr($html, $tagStartPos))) { // Add the closing tag at the end $html .= '</' . strtolower($tag) . '>'; } } return $html; } // Run your original cleanup first $description = strip_tags($_POST['description'], "<b><u><i>"); $description = preg_replace("/<([a-z][a-z0-9]*)[^>]*?(\/?)>/i",'<$1$2>', $description); // Now close any unclosed tags $description = closeUnclosedTags($description);
This will handle most cases where tags are left unclosed, though it might not fix messy nesting (like <b><i>Test</b>) perfectly—it'll still add the missing </i>, which is better than leaving the formatting broken.
内容的提问来源于stack exchange,提问作者Antonio Neto

