【问题标题】:PHP bufffer output minify, NOT textarea/prePHP 缓冲区输出缩小,而不是 textarea/pre
【发布时间】:2015-01-10 16:00:53
【问题描述】:

我正在使用缓冲区清理程序,如 PHP 手动注释中所见,但在 textareas 中出现双换行符时遇到问题。

当从我的数据库中提取一个包含双/三/四换行符的字符串并将其放入textarea 时,换行符将减少为仅一个换行符。

因此:是否可以让函数排除<pre><textarea></pre></textarea> 之间的所有输出?

看到这个问题,How to minify php html output without removing IE conditional comments?,我想我需要使用preg_match,但是我不确定如何将它实现到这个函数中。

我正在使用的功能是

function sanitize_output($buffer) {
    $search = array(
        '/\>[^\S ]+/s',  // strip whitespaces after tags, except space
        '/[^\S ]+\</s',  // strip whitespaces before tags, except space
        '/(\s)+/s'       // shorten multiple whitespace sequences
    );

    $replace = array(
        '>',
        '<',
        '\\1'
    );

    $buffer = preg_replace($search, $replace, $buffer);

    return $buffer;
}

ob_start("sanitize_output");

是的,我正在使用这种消毒剂和GZIP 来获得尽可能小的尺寸。

【问题讨论】:

  • 如果你没有时间,有一个非常愚蠢的解决方案:preg_replace 每个 textarea 和每个 pre 之间的所有内容到一个 random_string (将原始内容保存在数组中(random_string = 'original content');然后运行您的程序,然后将其替换回 (random_string -> array('random_string');。您可以轻松实现它,并等待更好的答案。如果可以等待,请等待,因为这是一个非常丑陋的解决方案: )。
  • 只是一个随机的想法(我没有测试它):编写一个给定字符串的函数将其放入列表并返回唯一 ID(列表 f.e. 中的索引)。使用该函数“输出”要放入&lt;textarea&gt; 元素中的字符串。让 minifier ob 处理程序完成其工作,然后获取其输出,识别 textarea 元素并将 ID 替换为您之前保存的文本。找到像&lt;textarea&gt;1&lt;/textarea&gt; 这样的东西比去掉空格要容易得多;即使没有regex 也可以完成(但使用它们更容易)。将列表和函数打包到一个类中,就可以开始了。
  • @axiac 这基本上是第一条评论的方法
  • 糟糕,我之前没看过。现在我看到它非常相似。 Jacek 的建议是在运行问题中显示的函数之前识别并提取字符串。我的初衷是不要把它们放在输出中。
  • 只是想一想:我不知道您为什么要对 HTML 中的作业进行这种清理,但通常没有特别需要使用这种技术压缩 HTML。您的问题没有真正简单的解决方案,也许这会产生您并不真正需要的巨大开销。也许没有清理功能,您的网站服务会更快。您应该考虑一下,也许可以在您的特定网站上测试它的好处。

标签: php preg-replace preg-match minify


【解决方案1】:

这里是cmets中提到的函数的一个实现:

function sanitize_output($buffer) {

    // Searching textarea and pre
    preg_match_all('#\<textarea.*\>.*\<\/textarea\>#Uis', $buffer, $foundTxt);
    preg_match_all('#\<pre.*\>.*\<\/pre\>#Uis', $buffer, $foundPre);

    // replacing both with <textarea>$index</textarea> / <pre>$index</pre>
    $buffer = str_replace($foundTxt[0], array_map(function($el){ return '<textarea>'.$el.'</textarea>'; }, array_keys($foundTxt[0])), $buffer);
    $buffer = str_replace($foundPre[0], array_map(function($el){ return '<pre>'.$el.'</pre>'; }, array_keys($foundPre[0])), $buffer);

    // your stuff
    $search = array(
        '/\>[^\S ]+/s',  // strip whitespaces after tags, except space
        '/[^\S ]+\</s',  // strip whitespaces before tags, except space
        '/(\s)+/s'       // shorten multiple whitespace sequences
    );

    $replace = array(
        '>',
        '<',
        '\\1'
    );

    $buffer = preg_replace($search, $replace, $buffer);

    // Replacing back with content
    $buffer = str_replace(array_map(function($el){ return '<textarea>'.$el.'</textarea>'; }, array_keys($foundTxt[0])), $foundTxt[0], $buffer);
    $buffer = str_replace(array_map(function($el){ return '<pre>'.$el.'</pre>'; }, array_keys($foundPre[0])), $foundPre[0], $buffer);

    return $buffer;
}

总有优化的余地,但这是可行的

【讨论】:

  • 不幸的是,用这个替换了原来的函数,结果是绝对没有任何东西被清理
  • @Behrens 在我的情况下它按预期工作。除textareapre 的内容外,所有Html 都经过了清理。我最后省略了ob_start(...),因为这无关紧要,但我无法想象你忘记了这一点。只用一些输出单独尝试这个脚本,看看你是否可以让它工作
  • 啊,你说得对。我省略了ob_start。它在
     中完美运行,但在 
  • 是的 - 你是对的。我完全忘记了。嗯...我认为根据您的需要更新preg_match_all 中的正则表达式将解决问题,因为无论如何我都会在最后替换旧的textarea-tag。所以试试'#\&lt;textarea.*\&gt;(.*)\&lt;\/textarea\&gt;#Uis'。我会更新我的答案
【解决方案2】:

对于PRE 有一个对TEXTAREA 不起作用的简单解决方案:用&amp;nbsp; 替换空格,然后在输出值之前使用nl2br()BR 元素替换换行符。它并不优雅,但很有效:

<pre><?php
    echo(nl2br(str_replace(' ', '&nbsp;', htmlspecialchars($value))));
?></pre>

很遗憾,它不能用于TEXTAREA,因为浏览器会将&lt;br /&gt; 显示为文本。

【讨论】:

  • 你可以用更多的代码做到这一点:$textWithBr = nl2br(str_replace(' ', '&amp;nbsp;', htmlspecialchars($value));$text = str_replace('&lt;br /&gt;', '\n', $textWithBr);
  • 我想要一个通用函数来执行此操作,而不是在每个文本区域中执行此操作。
  • @KalebKlein 它是"\n" (带引号,而不是撇号)但它没有帮助。它只会撤销nl2br 的效果。如果这对TEXTAREAs 有帮助,我一开始就不会打电话给nl2br()
【解决方案3】:

也许这会给你你需要的结果。 但总的来说,我不推荐这种清理工作,这对性能不利。在这些日子里,没有真正需要从 html 输出中去除空白字符。

function sanitize_output($buffer) {
    $ignoreTags = array("textarea", "pre");

    # find tags that must be ignored and replace it with a placeholder
    $tmpReplacements = array();
    foreach($ignoreTags as $tag){
        preg_match_all("~<$tag.*?>.*?</$tag>~is", $buffer, $match);
        if($match && $match[0]){
            foreach($match[0] as $key => $value){
                if(!isset($tmpReplacements[$tag])) $tmpReplacements[$tag] = array();
                $index = count($tmpReplacements[$tag]);
                $replacementValue = "<tmp-replacement>$index</tmp-relacement>";
                $tmpReplacements[$tag][$index] = array($value, $replacementValue);
                $buffer = str_replace($value, $replacementValue, $buffer);
            }
        }
    }

    $search = array(
        '/\>[^\S ]+/s',  // strip whitespaces after tags, except space
        '/[^\S ]+\</s',  // strip whitespaces before tags, except space
        '/(\s)+/s'       // shorten multiple whitespace sequences
    );

    $replace = array(
        '>',
        '<',
        '\\1'
    );

    $buffer = preg_replace($search, $replace, $buffer);

    # re-insert previously ignored tags
    foreach($tmpReplacements as $tag => $rows){
        foreach($rows as $values){
            $buffer = str_replace($values[1], $values[0], $buffer);
        }
    }

    return $buffer;
}

【讨论】:

    【解决方案4】:
    function nl2ascii($str){
        return str_replace(array("\n","\r"), array("&#10;","&#13;"), $str);
    }
    
    $StrTest = "test\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\rtest";
    
    ob_start("sanitize_output");
    ?>
    
    <textarea><?php echo nl2ascii($StrTest); ?></textarea>
    <textarea><?php echo $StrTest; ?></textarea>
    
    <pre style="border: 1px solid red"><?php echo nl2ascii($StrTest); ?></pre>
    <pre style="border: 1px solid red"><?php echo $StrTest; ?></pre>
    
    <?php
    ob_flush();
    

    原始输出

          <textarea>test&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;test</textarea>
    <textarea>test
    test</textarea>
    
    <pre style="border: 1px solid red">test&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;&#10;&#13;test</pre>
    <pre style="border: 1px solid red">test
    test</pre>
    

    视觉输出

    【讨论】:

    • 这可能会有所帮助(到目前为止对我来说是最好的答案),但是,获取 textarea 和 pre 节点是这个问题中最复杂的部分。这意味着,如何仅在 textarea 和 pre 节点上运行您的替换。
    【解决方案5】:

    这是我的净化 HTML 版本。我已经注释了代码,所以应该清楚它在做什么。

    function comprimeer($html = '', $arr_tags = ['textarea', 'pre']) {
        $arr_found = [];
        $arr_back = [];
        $arr_temp = [];
    
        // foreach tag get an array with tag and its content
        // the array is like: $arr_temp[0] = [ 0 = ['<tag>content</tag>'] ];
        foreach ($arr_tags as $tag) {
            if(preg_match_all('#\<' . $tag . '.*\>.*\<\/' . $tag . '\>#Uis', $html, $arr_temp)) {
                // the tag is present
                foreach($arr_temp as $key => $arr_item) {
                    // for every item of the tag keep the item
                    $arr_found[$tag][] = $arr_item[0];
                    // make an nmubered replace <tag>1</tag>
                    $arr_back[$tag][] = '<' . $tag . '>' . $key . '</' . $tag . '>';
                }
                // replace all the present tags with the numbered ones
                $html = str_replace((array) $arr_found[$tag], (array) $arr_back[$tag], $html);
            }
        } // end foreach
    
        // clean the html
        $arr_search = [
            '/\>[^\S ]+/s', // strip whitespaces after tags, except space
            '/[^\S ]+\</s', // strip whitespaces before tags, except space
            '/(\s)+/s'     // shorten multiple whitespace sequences
        ];
        $arr_replace = [
            '>',
            '<',
            '\\1'
        ];
        $clean = preg_replace($arr_search, $arr_replace, $html);
    
        // put the kept items back
        foreach ($arr_tags as $tag) {
            if(isset($arr_found[$tag])) {
                // the tag was present replace them back
                $clean = str_replace($arr_back[$tag], $arr_found[$tag], $clean);
            }   
        } // end foreach
        // give the cleaned html back
        return $clean;
    } // end function
    

    【讨论】:

    • 这个 5 年前的问题的答案在哪里,比已经接受的更好?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多