Jak zminimalizować wynik html strony php?

143

Szukam skryptu lub klasy php, która może zminimalizować dane wyjściowe html strony php, tak jak robi to prędkość strony Google.

W jaki sposób mogę to zrobić?

m3tsys
źródło
14
Jedna linijka oparta na odpowiedzi @RakeshS:ob_start(function($b){return preg_replace(['/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s'],['>','<','\\1'],$b);});
Francisco Presencia
5
@FranciscoPresencia To naprawdę zła rzecz. Łamiesz tagi skryptów, tagi wstępne itp.
Brad
To prawda, jak zauważono w jego komentarzach do odpowiedzi, nie działa z tagami <pre>lub <code>, ponieważ wymagają one spacji do właściwej struktury. Jednak <script>powinien być normalnie zewnętrzny lub wbudowany, ale używany ;w ścisły sposób, więc działa również. Jakie inne tagi mogą się zepsuć @Brad? Nie mogłem myśleć o innych. Powinienem był jednak dodać szybki i brudny sposób przed moim poprzednim komentarzem.
Francisco Presencia,

Odpowiedzi:

213

CSS i Javascript

Rozważ następujący link, aby zminimalizować pliki Javascript / CSS: https://github.com/mrclay/minify

HTML

Powiedz Apache, aby dostarczał HTML za pomocą GZip - zwykle zmniejsza to rozmiar odpowiedzi o około 70%. (Jeśli używasz Apache, moduł konfigurujący gzip zależy od twojej wersji: Apache 1.3 używa mod_gzip, podczas gdy Apache 2.x używa mod_deflate.)

Zaakceptuj-kodowanie: gzip, deflate

Kodowanie zawartości: gzip

Użyj poniższego fragmentu kodu, aby usunąć spacje z kodu HTML za pomocą bufora pomocy ob_start:

<?php

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
        '/<!--(.|\s)*?-->/' // Remove HTML comments
    );

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

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

    return $buffer;
}

ob_start("sanitize_output");

?>
Rakesh Sankar
źródło
54
Jest to dobra funkcja, ale uważaj na to, jeśli używasz tagów PRE , czasami nowe linie zostaną tam usunięte.
fedmich
2
Gdzie powinien znajdować się ten kod, na górze czy na dole skryptu?
jdepypere
8
Możesz także użyć klasy Minify_HTML z tej biblioteki Minify ( $content = \Minify_HTML::minify($content);możesz nawet dodać wywołania zwrotne do minifier js / css dla kodu wbudowanego). Zobacz github.com/mrclay/minify/blob/master/min/lib/Minify/HTML.php
Barryvdh
21
To również łamie wbudowany JavaScript (tj. W <script>tagach), który nie ma; na końcu każdej instrukcji lub ma komentarze, które używają//
Konstantin Pereiaslov
8
to usunie spacje z textarea, pre, input, img również to łamie wbudowane javascripts. jeśli ktoś nie jest zadowolony z używania nieporęcznej klasy z analizowaniem DOM to rozwiązanie oparte na regexp działa świetnie
Peter
28

Włącz gzip, jeśli chcesz zrobić to poprawnie. Możesz też po prostu zrobić coś takiego:

$this->output = preg_replace(
    array(
        '/ {2,}/',
        '/<!--.*?-->|\t|(?:\r?\n[ \t]*)+/s'
    ),
    array(
        ' ',
        ''
    ),
    $this->output
);

To usuwa około 30% rozmiaru strony, zamieniając HTML w jedną linię, bez zakładek, bez nowych linii, bez komentarzy. Przebieg może się różnić

dogmatyczny69
źródło
1
Wykonanie obydwu jeszcze bardziej zmniejszyłoby liczbę potrzebnych bajtów.
Wander Nauta
1
faktycznie robienie obu jest takie samo jak robienie gzipa, na stronie 700kb gzip zmniejszy to do około 400kb, a preg_replace () około 450kb (wszystko w zależności od zawartości) oba będą miały wielkość 399kb ponieważ gzip usuwa spacje tak samo, a potem kompresuje to
dogmatic69
18
Może to być potencjalnie niebezpieczne, ponieważ usuwałoby również warunki warunkowe IE ... - musiałbyś zmienić to na /<!--(?![if).*?-->/
Katai
3
Nie działa, usuwa zbyt dużo, psuje kod. Wcześniej obowiązywał W3C, a potem już nie.
Codebeat
3
Niestety psuje też kod Javascript, na przykład do generowania bardziej złożonych implementacji Google Maps - do czego właśnie potrzebowałbym takiej funkcji.
richey
19

Wszystkie preg_replace()powyższe rozwiązania mają problemy z komentarzami jednowierszowymi, komentarzami warunkowymi i innymi pułapkami. Polecam skorzystać z dobrze przetestowanego projektu Minify zamiast tworzenia własnego wyrażenia regularnego od podstaw.

W moim przypadku umieszczam następujący kod na górze strony PHP, aby ją zminimalizować:

function sanitize_output($buffer) {
    require_once('min/lib/Minify/HTML.php');
    require_once('min/lib/Minify/CSS.php');
    require_once('min/lib/JSMin.php');
    $buffer = Minify_HTML::minify($buffer, array(
        'cssMinifier' => array('Minify_CSS', 'minify'),
        'jsMinifier' => array('JSMin', 'minify')
    ));
    return $buffer;
}
ob_start('sanitize_output');
Andrzej
źródło
1
Twój kod nie umieszcza html w jednej linii
karadayi
Przeczytaj pierwsze pytanie w często zadawanych pytaniach dotyczących projektu Minify . TL; DR: Ignoruj ​​ich.
Andrew,
Próbowałem, to nie działa. Mam na moim pliku php, css między tagami <style> i javascript osadzony z php między tagami <script>
João Pimentel Ferreira
gdzie umieszczasz ten kod? ostatni w stopce lub nagłówku?
Francesco
@francesco To powinien być pierwszy fragment kodu na Twojej stronie.
Andrew,
19

Wypróbowałem kilka minifier i albo usuwają za mało, albo za dużo.

Ten kod usuwa zbędne puste spacje i opcjonalne znaczniki HTML (końcowe). Odgrywa również bezpiecznie i nie usuwa niczego, co mogłoby potencjalnie zepsuć HTML, JS lub CSS.

Kod pokazuje również, jak to zrobić w Zend Framework:

class Application_Plugin_Minify extends Zend_Controller_Plugin_Abstract {

  public function dispatchLoopShutdown() {
    $response = $this->getResponse();
    $body = $response->getBody(); //actually returns both HEAD and BODY

    //remove redundant (white-space) characters
    $replace = array(
        //remove tabs before and after HTML tags
        '/\>[^\S ]+/s'   => '>',
        '/[^\S ]+\</s'   => '<',
        //shorten multiple whitespace sequences; keep new-line characters because they matter in JS!!!
        '/([\t ])+/s'  => ' ',
        //remove leading and trailing spaces
        '/^([\t ])+/m' => '',
        '/([\t ])+$/m' => '',
        // remove JS line comments (simple only); do NOT remove lines containing URL (e.g. 'src="http://server.com/"')!!!
        '~//[a-zA-Z0-9 ]+$~m' => '',
        //remove empty lines (sequence of line-end and white-space characters)
        '/[\r\n]+([\t ]?[\r\n]+)+/s'  => "\n",
        //remove empty lines (between HTML tags); cannot remove just any line-end characters because in inline JS they can matter!
        '/\>[\r\n\t ]+\</s'    => '><',
        //remove "empty" lines containing only JS's block end character; join with next line (e.g. "}\n}\n</script>" --> "}}</script>"
        '/}[\r\n\t ]+/s'  => '}',
        '/}[\r\n\t ]+,[\r\n\t ]+/s'  => '},',
        //remove new-line after JS's function or condition start; join with next line
        '/\)[\r\n\t ]?{[\r\n\t ]+/s'  => '){',
        '/,[\r\n\t ]?{[\r\n\t ]+/s'  => ',{',
        //remove new-line after JS's line end (only most obvious and safe cases)
        '/\),[\r\n\t ]+/s'  => '),',
        //remove quotes from HTML attributes that does not contain spaces; keep quotes around URLs!
        '~([\r\n\t ])?([a-zA-Z0-9]+)="([a-zA-Z0-9_/\\-]+)"([\r\n\t ])?~s' => '$1$2=$3$4', //$1 and $4 insert first white-space character found before/after attribute
    );
    $body = preg_replace(array_keys($replace), array_values($replace), $body);

    //remove optional ending tags (see http://www.w3.org/TR/html5/syntax.html#syntax-tag-omission )
    $remove = array(
        '</option>', '</li>', '</dt>', '</dd>', '</tr>', '</th>', '</td>'
    );
    $body = str_ireplace($remove, '', $body);

    $response->setBody($body);
  }
}

Ale pamiętaj, że podczas korzystania z kompresji gZip twój kod jest kompresowany znacznie bardziej niż każda minifikacja może to zrobić, łącząc minifikację i gZip, jest bezcelowe, ponieważ czas zaoszczędzony podczas pobierania jest tracony przez minifikację, a także oszczędza minimum.

Oto moje wyniki (pobieranie przez sieć 3G):

 Original HTML:        150kB       180ms download
 gZipped HTML:          24kB        40ms
 minified HTML:        120kB       150ms download + 150ms minification
 min+gzip HTML:         22kB        30ms download + 150ms minification
Radek Pech
źródło
4
Tak, zgadzam się, że jest to pozornie bezcelowe, ale może dać Ci jeden lub dwa cenne punkty w szybkości strony dla Google, co jest istotne dla Twojego rankingu Google. Twój kod jest idealny do usuwania niepotrzebnych przestrzeni. Dzięki :-)
Tschallacka
1
to działa świetnie, miałem problemy z = "/", więc wyjąłem / z '~ ([\ r \ n \ t])? ([a-zA-Z0-9] +) = "([a-zA -Z0-9 _ / \\ -] +) "([\ r \ n \ t])? ~ S '=>' 1 $ 2 = 3 $ 4 ', // $ 1 i $ 4 wstaw pierwszy znak odstępu znaleziony przed / po atrybucie
ask_io
Cóż, tak się składa, że ​​nie chcę usuwać białych znaków tylko po to, aby przyspieszyć, ale raczej dlatego, że tak powinien wyglądać HTML , aby rzeczy nie zepsuły się całkowicie, jak elementy blokowe, ale szukam też takiego, który jest w stanie ignorowania rzeczy, które muszą mieć jedną spację przed lub po (na przykład pogrubione elementy w bloku tekstu).
Deji,
Znalazłem problem z niektórymi rzeczami Jquery / Foundation ... chyba że zakomentowałem następujące linie: // usuń "puste" linie zawierające tylko znak końca bloku JS; połącz z następną linią (np. "} \ n} \ n </script>" -> "}} </script>" // '/} [\ r \ n \ t] + / s' => '} ', //' /} [\ r \ n \ t] +, [\ r \ n \ t] + / s '=>'}, ',
Ian
1
Jeśli używasz buforowania po stronie serwera (dla mnie Smarty V3), min + gzip jest dobrym rozwiązaniem, z wyjątkiem pierwszego wywołania. Tak więc, jeśli po 15 wywołaniu będzie to wymagało czasu serwera. reguła = 40x15 = (30x15 + 150) Ale przy drugim połączeniu będzie to już szybsze dla gościa.
Meloman
6

Ta praca dla mnie.

function Minify_Html($Html)
{
   $Search = array(
    '/(\n|^)(\x20+|\t)/',
    '/(\n|^)\/\/(.*?)(\n|$)/',
    '/\n/',
    '/\<\!--.*?-->/',
    '/(\x20+|\t)/', # Delete multispace (Without \n)
    '/\>\s+\</', # strip whitespaces between tags
    '/(\"|\')\s+\>/', # strip whitespaces between quotation ("') and end tags
    '/=\s+(\"|\')/'); # strip whitespaces between = "'

   $Replace = array(
    "\n",
    "\n",
    " ",
    "",
    " ",
    "><",
    "$1>",
    "=$1");

$Html = preg_replace($Search,$Replace,$Html);
return $Html;
}
Mohamad Hamouday
źródło
5

Utwórz plik PHP poza katalogiem głównym. Jeśli twój dokument główny to

/var/www/html/

utwórz plik o nazwie minify.php jeden poziom wyżej

/var/www/minify.php

Skopiuj, wklej do niego następujący kod PHP

<?php
function minify_output($buffer){
    $search = array('/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s');
    $replace = array('>','<','\\1');
    if (preg_match("/\<html/i",$buffer) == 1 && preg_match("/\<\/html\>/i",$buffer) == 1) {
        $buffer = preg_replace($search, $replace, $buffer);
    }
    return $buffer;
}
ob_start("minify_output");?>

Zapisz plik minify.php i otwórz plik php.ini. Jeśli jest to serwer dedykowany / VPS, wyszukaj następującą opcję, na współdzielonym hostingu z niestandardowym php.ini dodaj ją.

auto_prepend_file = /var/www/minify.php

Źródła: http://websistent.com/how-to-use-php-to-minify-html-output/

Avi Tyagi
źródło
2

Możesz zajrzeć do HTML TIDY - http://uk.php.net/tidy

Może być zainstalowany jako moduł PHP i usunie (poprawnie, bezpiecznie) białe znaki i wszystkie inne nieprzyjemności, jednocześnie wysyłając doskonale poprawne znaczniki HTML / XHTML. Oczyści również twój kod, co może być świetną lub straszną rzeczą, w zależności od tego, jak dobry jesteś w pisaniu prawidłowego kodu ;-)

Ponadto możesz spakować dane wyjściowe za pomocą następującego kodu na początku pliku:

ob_start('ob_gzhandler');
Rudi Visser
źródło
Problem w tym, że strona będzie hostowana na współdzielonych i nie będę miał dostępu do instalacji takich modułów.
m3tsys
Są szanse, że zostanie już zainstalowany. Sprawdź phpinfo()... zlibPowinien być przynajmniej zainstalowany umożliwiający korzystanie z ob_gzhandler.
Rudi Visser
już używam, czy if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler"); else ob_start();to nie to samo?
m3tsys
2
Tak, naprawdę nie potrzebujesz else ob_start()części, ani funkcja gzip check ... nie ob_gzhandlerwykrywa, czy przeglądarka obsługuje wewnętrznie jakąkolwiek metodę kompresji. Wystarczy mieć ob_start('ob_gzhandler');.
Rudi Visser
Czy istnieje możliwość, że TIDY będzie wolniejszy niż inne odpowiedzi tutaj z powodu dodatkowego narzutu przetwarzania? Może być dobry do programowania - wtedy możesz poprawić te błędy HTML w rzeczywistym kodzie źródłowym - ale pytam, czy jest to najlepszy wybór do produkcji.
Matt Browne,
2

Przede wszystkim gzip może Ci pomóc więcej niż Html Minifier

  1. Z nginx :

    gzip on;
    gzip_disable "msie6";
    
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  2. W Apache możesz użyć mod_gzip

Po drugie: dzięki gzip + Html Minification możesz drastycznie zmniejszyć rozmiar pliku !!!

Stworzyłem ten HtmlMinifier dla PHP .

Można pobrać go przez kompozytora: composer require arjanschouten/htmlminifier dev-master.

Istnieje dostawca usług Laravel. Jeśli nie używasz Laravela, możesz go używać z poziomu PHP.

// create a minify context which will be used through the minification process
$context = new MinifyContext(new PlaceholderContainer());
// save the html contents in the context
$context->setContents('<html>My html...</html>');
$minify = new Minify();
// start the process and give the context with it as parameter
$context = $minify->run($context);

// $context now contains the minified version
$minifiedContents = $context->getContents();

Jak widać, możesz tutaj rozszerzyć wiele rzeczy i przejść przez różne opcje. Sprawdź plik readme aby zobaczyć wszystkie dostępne opcje.

Ten HtmlMinifier jest kompletny i bezpieczny. Proces minifikacji obejmuje 3 kroki:

  1. Zastąp krytyczną zawartość tymczasową symbolem zastępczym.
  2. Uruchom strategie minifikacji.
  3. Przywróć oryginalną zawartość.

Sugerowałbym, abyś buforował dane wyjściowe swoich widoków. Proces minifikacji powinien być jednorazowy. Lub zrób to na przykład na podstawie interwału.

W tym czasie nie są tworzone jasne testy porównawcze. Jednak minifier może zmniejszyć rozmiar strony o 5-25% w zależności od Twojego znacznika!

Jeśli chcesz dodać własne strategie, możesz skorzystać addPlaceholderz addMinifiermetod i.

ArjanSchouten
źródło
Dzięki za bibliotekę. Instrukcje nie mówią, jakie pliki PHP muszę dołączyć. W końcu to wymyślę, ale prawdopodobnie powinieneś to dodać na swojej stronie internetowej.
woda różana
Wygląda na to, że nadal wymaga Illuminate \ Support \ Collection. To nie jest samodzielne rozwiązanie PHP.
woda różana
Dziękujemy za opinię! Jest to pakiet kompozytora . Zaktualizowałemrequire __DIR__ . '/vendor/autoload.php'; plik readme z następującą regułą: Jedyne, co musisz zrobić, to dołączyć ten plik. To jest generowane przez kompozytora!
ArjanSchouten
2

Mam gist GitHub zawierający funkcje PHP do minifikacji plików HTML, CSS i JS → https://gist.github.com/taufik-nurrohman/d7b310dea3b33e4732c0

Oto jak zminimalizować wyjście HTML w locie za pomocą bufora wyjściowego:

<?php

include 'path/to/php-html-css-js-minifier.php';

ob_start('minify_html');

?>

<!-- HTML code goes here ... -->

<?php echo ob_get_clean(); ?>
Taufik Nurrohman
źródło
link z
treścią
2
Zaktualizowano łącze.
Taufik Nurrohman
1

Jeśli chcesz usunąć wszystkie nowe wiersze na stronie, użyj tego szybkiego kodu:

ob_start(function($b){
if(strpos($b, "<html")!==false) {
return str_replace(PHP_EOL,"",$b);
} else {return $b;}
});
زياد
źródło
0

Dzięki Andrew . Oto, co zrobił, aby użyć tego w cakePHP:

  1. Pobierz minify-2.1.7
  2. Rozpakuj plik i skopiuj podfolder min do folderu dostawcy ciasta
  3. Tworzy MinifyCodeHelper.php w widoku / pomocniku ciasta w następujący sposób:

    App::import('Vendor/min/lib/Minify/', 'HTML');
    App::import('Vendor/min/lib/Minify/', 'CommentPreserver');
    App::import('Vendor/min/lib/Minify/CSS/', 'Compressor');
    App::import('Vendor/min/lib/Minify/', 'CSS');
    App::import('Vendor/min/lib/', 'JSMin');
    class MinifyCodeHelper extends Helper {
        public function afterRenderFile($file, $data) {
            if( Configure::read('debug') < 1 ) //works only e production mode
                $data = Minify_HTML::minify($data, array(
                    'cssMinifier' => array('Minify_CSS', 'minify'),
                    'jsMinifier' => array('JSMin', 'minify')
                ));
            return $data;
        }
    }
  4. Włączono mojego pomocnika w AppController

    public $ helpers = array ('Html', '...', 'MinifyCode');

5 ... Voila!

Mój wniosek: jeśli deflate i moduły nagłówków Apache są wyłączone na twoim serwerze, zysk jest o 21% mniejszy i 0,35s plus w żądaniu kompresji (ta liczba była w moim przypadku).

Ale gdybyś włączył moduły Apache, skompresowana odpowiedź nie ma znaczącej różnicy (dla mnie 1,3%), a czas kompresji jest taki sam (0,3 s dla mnie).

Więc ... dlaczego to zrobiłem? ponieważ dokument mojego projektu jest w komentarzach (php, css i js), a mój użytkownik końcowy nie musi tego widzieć;)

bocapio
źródło
0

Możesz użyć dobrze przetestowanego minifier Java, takiego jak HTMLCompressor , wywołując go za pomocą passthru( exec).
Pamiętaj, aby przekierować konsolę za pomocą2>&1

Może to jednak nie być przydatne, jeśli chodzi o szybkość. Używam go do statycznego wyjścia php

Ujjwal Singh
źródło