2011-03-15 5 views
13

के साथ नियमित अभिव्यक्तियों का उपयोग करके अंतिम HTML आउटपुट को छोटा करना Google पेज आपको HTML को कम करने का सुझाव देता है, यानी, सभी अनावश्यक रिक्त स्थान हटा दें। CodeIgniter में गीज़िपिंग आउटपुट की सुविधा है या इसे .htaccess के माध्यम से किया जा सकता है। लेकिन फिर भी मैं अंतिम HTML आउटपुट से अनावश्यक रिक्त स्थान भी हटाना चाहता हूं।कोडइग्निटर

मैंने कोड के इस टुकड़े के साथ ऐसा करने के लिए थोड़ा सा खेला, और ऐसा लगता है। यह वास्तव में HTML में परिणाम देता है जो अतिरिक्त रिक्त स्थान के बिना होता है और अन्य टैब स्वरूपण को हटा देता है।

class Welcome extends CI_Controller 
{ 
    function _output() 
    { 
     echo preg_replace('!\s+!', ' ', $output); 
    } 

    function index(){ 
    ... 
    } 
} 

समस्या <pre>, <textarea>, आदि जैसे टैग .. जो उन में रिक्त स्थान हो सकता है और एक रेगुलर एक्सप्रेशन उन्हें हटाने चाहिए हो सकता है। तो, मैं नियमित अभिव्यक्ति का उपयोग करके इन निश्चित टैग के लिए रिक्त स्थान या स्वरूपण को प्रभावित किए बिना अंतिम HTML से अतिरिक्त स्थान कैसे हटा सकता हूं?

@Alan मूर के लिए धन्यवाद, इस सवाल का जवाब मिल गया है यह मेरे लिए काम किया

echo preg_replace('#(?ix)(?>[^\S ]\s*|\s{2,})(?=(?:(?:[^<]++|<(?!/?(?:textarea|pre)\b))*+)(?:<(?>textarea|pre)\b|\z))#', ' ', $output); 

ridgerunner इस नियमित अभिव्यक्ति का विश्लेषण करने का एक बहुत अच्छा काम किया है। मैं अपने समाधान का उपयोग कर समाप्त हो गया। राइडर करने के लिए चीयर्स।

+12

नियमित अभिव्यक्तियों का उपयोग करके HTML न करें। – SLaks

+0

आपके लिए अनंत अपवॉट, स्लैक्स। –

+0

ठीक है, तो अंतिम HTML आउटपुट को फिर से सुधारने का एक अच्छा तरीका क्या हो सकता है? – Aman

उत्तर

43

कैसे एलन मूर का regex काम करता है (और हाँ, यह काम करता है), मैं यह टिप्पणी की है, तो यह मात्र मनुष्यों द्वारा पढ़ा जा सकता की स्वतंत्रता लिया है के बारे में उत्सुक उन लोगों के लिए:

function process_data_alan($text) // 
{ 
    $re = '%# Collapse ws everywhere but in blacklisted elements. 
     (?>    # Match all whitespans other than single space. 
      [^\S ]\s*  # Either one [\t\r\n\f\v] and zero or more ws, 
     | \s{2,}  # or two or more consecutive-any-whitespace. 
     ) # Note: The remaining regex consumes no text at all... 
     (?=    # Ensure we are not in a blacklist tag. 
      (?:   # Begin (unnecessary) group. 
      (?:   # Zero or more of... 
       [^<]++ # Either one or more non-"<" 
      | <   # or a < starting a non-blacklist tag. 
       (?!/?(?:textarea|pre)\b) 
      )*+   # (This could be "unroll-the-loop"ified.) 
     )    # End (unnecessary) group. 
      (?:   # Begin alternation group. 
      <   # Either a blacklist start tag. 
      (?>textarea|pre)\b 
      | \z   # or end of file. 
     )    # End alternation group. 
     ) # If we made it here, we are not in a blacklist tag. 
     %ix'; 
    $text = preg_replace($re, " ", $text); 
    return $text; 
} 

मैं मैं यहां चारों ओर नया हूं, लेकिन मैं सही देख सकता हूं कि एलन रेगेक्स पर काफी अच्छा है। मैं केवल निम्नलिखित सुझाव जोड़ूंगा।

  1. एक अनावश्यक कैप्चर समूह है जिसे हटाया जा सकता है।
  2. हालांकि ओपी ने ऐसा नहीं कहा, <SCRIPT> तत्व <PRE> और <TEXTAREA> ब्लैकलिस्ट में जोड़ा जाना चाहिए।
  3. 'S' पीसीआरई "अध्ययन" संशोधक जोड़ना इस रेगेक्स को लगभग 20% तक बढ़ा देता है।
  4. फ्रेडल के "अनोलिंग-द-लूप" दक्षता निर्माण को लागू करने के लिए परिपक्व समूह में एक वैकल्पिक समूह है।
  5. एक और अधिक गंभीर नोट पर, यह एक ही प्रत्यावर्तन समूह: (यानी (?:[^<]++|<(?!/?(?:textarea|pre)\b))*+) बड़े लक्ष्य तार पर अत्यधिक PCRE प्रत्यावर्तन, जो चुपचाप SEG गलती करने के लिए अपाचे/पीएचपी निष्पादन के कारण एक ढेर-अतिप्रवाह में परिणाम कर सकते की संभावना है और कोई चेतावनी के साथ दुर्घटनाग्रस्त। (अपाचे httpd.exe का विन 32 बिल्ड विशेष रूप से इसके लिए अतिसंवेदनशील है क्योंकि इसमें * निक्स एक्जिक्यूटिव की तुलना में केवल 256 केबी स्टैक है, जो आम तौर पर 8 एमबी स्टैक या अधिक के साथ बनाया जाता है।) फिलिप हैज़ल (पीसीआरई रीजिक्स इंजन का लेखक PHP में उपयोग किया जाता है) प्रलेखन में इस मुद्दे पर चर्चा करता है: PCRE DISCUSSION OF STACK USAGE। यद्यपि एलन ने इस दस्तावेज़ में फिलिप के रूप में एक ही फिक्स को सही तरीके से लागू किया है (पहले विकल्प के लिए एक स्वामित्व वाला प्लस लागू करना), यदि HTML फ़ाइल बड़ी है और इसमें बहुत से गैर-ब्लैकलिस्ट किए गए टैग हैं तो भी बहुत सी रिकर्सन होगी। जैसे मेरे Win32 बॉक्स पर (256 केबी स्टैक वाले निष्पादन योग्य के साथ), स्क्रिप्ट केवल 60 केबी की टेस्ट फ़ाइल के साथ उड़ाती है। ध्यान दें कि दुर्भाग्य से PHP अनुशंसाओं का पालन नहीं करता है और 100000 पर डिफ़ॉल्ट रिकर्सन सीमा मार्ग बहुत अधिक सेट करता है। (पीसीआरई दस्तावेज़ों के मुताबिक इसे 500 से विभाजित स्टैक आकार के बराबर मान पर सेट किया जाना चाहिए)।

    // Set PCRE recursion limit to sane value = STACKSIZE/500 
    // ini_set("pcre.recursion_limit", "524"); // 256KB stack. Win32 Apache 
    ini_set("pcre.recursion_limit", "16777"); // 8MB stack. *nix 
    function process_data_jmr1($text) // 
    { 
        $re = '%# Collapse whitespace everywhere but in blacklisted elements. 
         (?>    # Match all whitespans other than single space. 
          [^\S ]\s*  # Either one [\t\r\n\f\v] and zero or more ws, 
         | \s{2,}  # or two or more consecutive-any-whitespace. 
         ) # Note: The remaining regex consumes no text at all... 
         (?=    # Ensure we are not in a blacklist tag. 
          [^<]*+  # Either zero or more non-"<" {normal*} 
          (?:   # Begin {(special normal*)*} construct 
          <   # or a < starting a non-blacklist tag. 
          (?!/?(?:textarea|pre|script)\b) 
          [^<]*+  # more non-"<" {normal*} 
         )*+   # Finish "unrolling-the-loop" 
          (?:   # Begin alternation group. 
          <   # Either a blacklist start tag. 
          (?>textarea|pre|script)\b 
          | \z   # or end of file. 
         )    # End alternation group. 
         ) # If we made it here, we are not in a blacklist tag. 
         %Six'; 
        $text = preg_replace($re, " ", $text); 
        if ($text === null) exit("PCRE Error! File too big.\n"); 
        return $text; 
    } 
    

    पश्चलेख:

यहाँ एक उन्नत संस्करण जो मूल की तुलना में तेजी है, बड़ा इनपुट के प्रबंधन, और शान से संदेश यदि इनपुट स्ट्रिंग को संभालने के लिए बहुत बड़ी है के साथ विफल है मैं इस PHP/अपाचे सेग-गलती की समस्या से घनिष्ठ परिचित हूं, क्योंकि मैं इस मुद्दे के साथ कुश्ती के दौरान ड्रूपल समुदाय की मदद करने में शामिल था। देखें: Optimize CSS option causes php cgi to segfault in pcre function "match"। हमने फ्लक्सबीबी फोरम सॉफ्टवेयर प्रोजेक्ट पर बीबीसीओडी पार्सर के साथ इसका अनुभव भी किया।

उम्मीद है कि इससे मदद मिलती है।

+0

वाह जो गहन विश्लेषण में काफी था, मुझे इन सभी विवरणों को नहीं पता था। Thanx बहुत, मैं आपके regex कोशिश करेंगे। – Aman

+0

क्या आपके पास परीक्षण फ़ाइल हो सकती है जिसका आप उपयोग कर रहे थे? – Aman

+0

@Aman हां, लेकिन यह पोस्ट करने से पहले कुछ समय होगा (फ़ाइल प्रगति पर एक लेख है (एचटीएमएल में) ...) – ridgerunner

0

मैंने दो परियोजनाओं में @ridgerunner से जवाब लागू किया, और परियोजनाओं में से किसी एक के लिए स्टेजिंग में कुछ गंभीर मंदी (10-30 सेकंड अनुरोध समय) को मार दिया। मुझे पता चला कि मुझे pcre.recursion_limit और pcre.backtrack_limit दोनों को भी काम करने के लिए बहुत कम सेट करना पड़ा था, लेकिन फिर भी यह प्रसंस्करण के लगभग 2 सेनकंड के बाद छोड़ देगा और झूठी वापसी होगी।

चूंकि, मैंने इसे इस समाधान (आसान-से-समझने वाले रेगेक्स के साथ) के साथ बदल दिया है, जो Smarty 2 से outputfilter.trimwhitespace फ़ंक्शन से प्रेरित है। यह कोई बैकट्रैकिंग या रिकर्सन नहीं करता है, और हर बार काम करता है (नीले चंद्रमा में एक बार आपदाजनक रूप से असफल होने की बजाय):

function filterHtml($input) { 
    // Remove HTML comments, but not SSI 
    $input = preg_replace('/<!--[^#](.*?)-->/s', '', $input); 

    // The content inside these tags will be spared: 
    $doNotCompressTags = ['script', 'pre', 'textarea']; 
    $matches = []; 

    foreach ($doNotCompressTags as $tag) { 
     $regex = "!<{$tag}[^>]*?>.*?</{$tag}>!is"; 

     // It is assumed that this placeholder could not appear organically in your 
     // output. If it can, you may have an XSS problem. 
     $placeholder = "@@<'-placeholder-$tag'>@@"; 

     // Replace all the tags (including their content) with a placeholder, and keep their contents for later. 
     $input = preg_replace_callback(
      $regex, 
      function ($match) use ($tag, &$matches, $placeholder) { 
       $matches[$tag][] = $match[0]; 
       return $placeholder; 
      }, 
      $input 
     ); 
    } 

    // Remove whitespace (spaces, newlines and tabs) 
    $input = trim(preg_replace('/[ \n\t]+/m', ' ', $input)); 

    // Iterate the blocks we replaced with placeholders beforehand, and replace the placeholders 
    // with the original content. 
    foreach ($matches as $tag => $blocks) { 
     $placeholder = "@@<'-placeholder-$tag'>@@"; 
     $placeholderLength = strlen($placeholder); 
     $position = 0; 

     foreach ($blocks as $block) { 
      $position = strpos($input, $placeholder, $position); 
      if ($position === false) { 
       throw new \RuntimeException("Found too many placeholders of type $tag in input string"); 
      } 
      $input = substr_replace($input, $block, $position, $placeholderLength); 
     } 
    } 

    return $input; 
}