【问题标题】:Properly rendering stored HTML正确呈现存储的 HTML
【发布时间】:2023-04-08 19:41:02
【问题描述】:

我网站的一部分允许用户在文本框中创建 cmets,以存储在 SQL 数据库中。因为很多人从word或其他地方复制/粘贴东西,我必须保留<p><br>标签来保持格式,还有<a>标签让用户创建自己的链接。其他一切都被剥离了。我这样完成的:

$text = strip_tags( $text, '<br><a><p>' );

但是今天一个用户来找我,告诉我他们丢失了大部分文字,因为他们为了视觉效果做了一个箭头&lt;-。所以现在我知道剥离标签会删除 &lt; 之后的所有内容。

我可以使用preg_replace 实现类似的效果,如下所示:

preg_replace('/((?!<((\/)?p|br|a))<[^>]*>)/', "", $text);

但这仍然有一个缺点,即只有当标签跨越一行时才有效(我认为),留下 html cmets 和可能我不知道的其他一些东西。我有哪些选择?有没有万能的解决方案?我可以使用的图书馆?我大部分时间都是独自工作,所以我不太了解行业标准。

【问题讨论】:

  • 如果我理解正确,您是在让用户在 cmets 文本框中输入 HTML 标签?
  • 是的,只是因为人们从其他来源复制粘贴并希望提交时格式看起来相同。主要是间距。
  • 那么这些用户使用 HTML 标签来格式化他们的文本?我建议只输入 HTML 编码,根本不允许用户输入 HTML。如果必须格式化,您可以查看富文本编辑器控件。
  • 我可以使用 preg_replace 实现类似的效果...但这仍然有缺点,即仅当标签跨越一行时才有效(我认为)。并不是因为您可以使用一些修饰符使 PHP 中的正则表达式跨越多行。考虑您的正则表达式,但带有多行和不区分大小写标志:preg_replace('/((?!&lt;((\/)?p|br|a))&lt;[^&gt;]*&gt;)/sim', "", $text);
  • 使用Markdown

标签: php regex


【解决方案1】:

使用 html 净化器。它有助于清理顶部的 html 并删除不需要的代码,例如,如果用户在提交之前添加了可能对您的网站造成损害的脚本标签(XSS 攻击)html 净化器。它还添加或完成 html,例如用户输入 gamer ... 在不关闭标签的情况下,它将关闭标签并输出更清晰的 html。

【讨论】:

    【解决方案2】:

    我可以使用 preg_replace 实现类似的效果...但这仍然有缺点,即仅当标签跨越一行时才有效(我认为)。 不是这样!您可以使用一些修饰符使 PHP 正则表达式跨越多行。 考虑下面的多行 HTML 字符串示例:

        <?php
            // $s IS A MULTILINE HTML SNIPPET CONTAINING THE FOLLOWING HTML TAGS
            // <div>, <a>, <blockquote>, <em>, <strong>, <span>, <br /> 
            $s  = "<div class='one'>
                        <a href='/link.php'>
                            <blockquote>
                                There is real Power in the Hearts of men: not just Power but
                                \"something so much powerful than Power\" that Power itself begs to \"power down\".
                            </blockquote>
                        </a>
                        <p class='lv'>
                            This Power is not in the Head nor in the Intellect nor in the Skills of Man...
                            <em class='em1'>but in the deep recess of the Human Heart...</em>
                            and it speaks volumes yet only very few understand its language -
                            <strong>The Language of Love</strong>
                            - The Greatest Power You can have.... The Power to which nothing is Impossible!!!
                        </p>
                        <br />
                        <span>Do you know this Power? <--</span>
                        <strong>Do you Speak Love???</strong>
                    </div>";
    
            // THIS CONCISE REGEX PATTERN REMOVES ALL HTML TAGS WITHIN THE MULTILINE STRING
            // EXCEPT FOR TAGS LIKE: <a> <p> <br />
            // IT WOULD ALSO LEAVE <- OR <-- OR <------ UNTOUCHED
            $r  = preg_replace("#<(?!\/[ap]|[ap\-]|br).*?>#si", "", $s);
            echo ($r);
    

    如果您查看了Source Code,您会发现除了&lt;br&gt;, &lt;p&gt;, &lt;a&gt; and Symbols like &lt;-- 之外的所有HTML 标签都被删除了。实际上,Source 看起来像这样:

        <a href='/link.php'>
    
                There is real Power in the Hearts of men: not just Power but
                "something so much powerful than Power" that Power itself begs to "power down".
    
        </a>
        <p class='lv'>
            This Power is not in the Head nor in the Intellect nor in the Skills of Man...
            but in the deep recess of the Human Heart...
            and it speaks volumes yet only very few understand its language -
            The Language of Love
            - The Greatest Power You can have.... The Power to which nothing is Impossible!!!
        </p>
        <br />
        Do you know this Power? <--
        Do you Speak Love???
    

    祝你好运...

    【讨论】:

    • 这里的m 修饰符实际上没有被使用。 m 用于 ^$s 允许 . 包含新行。
    【解决方案3】:

    如果您的情况像您在问题中向我们展示的那样简单,我不会使用 HTML Purifier 等外部库。

    strip_tags() 函数有自己的方法来确定标签。它不将&lt; 视为真实标签的一种方法是它后面跟一个空格。 space 我的意思是 0x090x0d 以及 0x20 之间的任何字符(isSpace() internal函数通过来自php_strip_tags_ex() 的调用来工作)。

    因此,一种解决方法可能是在&lt;- 字符之间放置一个允许的空格,然后在执行strip_tags() 后将其还原,但您最好不仅要注意&lt; 字符后跟-,而且任何&lt; 字符后跟[^a-zA-Z!?\s] 字符(不是字母的字符,!? 标记,\s 任何类型的空白字符(空格很好!))

    我想选择我的空格字符作为回车符\r,即十六进制的0x0D。那更具体:

    $text = preg_replace( "~<\r([^a-zA-Z!?\s])~", "<\1", strip_tags( preg_replace( '~<([^a-zA-Z!?\s])~', "<\r\1", $text ), '<p><a><br>' ) );
    

    【讨论】:

      【解决方案4】:

      我可以建议您对用户提交的数据进行编码,然后删除您不允许的标签。这样您就不会删除页面上正常显示的标签。

      请注意,在大字符串上运行复杂的正则表达式效率不高。

      从用户那里获取输入对其进行编码,而不是&amp;lt;p&amp;gt;,您将保存&amp;lt;p&amp;gt;,然后您可以将其作为html插入到页面中,因此它将呈现为html但没有实际标签,这样您就不用'不需要删除任何东西。

      你可以使用htmlspecialchars(string)这里是example

      【讨论】:

      • 我的意思是有很多我不允许的标签,这就是为什么我有一个白名单而不是黑名单。而且我很想避免使用正则表达式,但我不确定还能做什么。
      猜你喜欢
      • 2012-03-05
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 2021-08-29
      相关资源
      最近更新 更多