ActiveTK's Note

【PHP】自動でHTMLを圧縮してソースコードを美しくするプログラム


作成日時 2023/08/06 15:14
最終更新 2023/08/06 16:17


  • まず初めに
  • プログラム本体
  • プログラムの解説
  • まとめ

  • まず初めに

    プログラミングは一般に、手段とされます。それは、お金を得るため、便利なアプリで誰かに貢献するためなど様々です。

    しかし、その事実がある一方で、手段として割り切る考え方は避けるべきであります。 "人が呼吸するように、鷲が空を舞うように"、思いのまま言語をコントロールできるようになるには、むしろ自己目的化が求められます。

    これには、例えばソースコードの「美」を追求したり、9割9部10厘の人が知らない隠し要素を実装することなどが該当します。

    本記事では、PHPで自動でHTMLを圧縮してソースコードを美しくする方法をご紹介します。


    プログラム本体

    以下のプログラムをコピーして、PHPファイルの先頭に貼り付ければ動作します。

    または、単一のPHPファイルとして保存して、require_onceで呼び出しても大丈夫です。

    <?php
    
      define( "LOAD_START_TIME", microtime(true) );
    
      function minifier_output($buffer) {
    
        foreach(headers_list() as $line)
        {
          list($title, $data) = explode(": ", $line, 2);
          if (strtolower($title) == "content-type" && false === strpos($data, "text/html"))
            return $buffer;
        }
    
        $buffer = preg_replace_callback("/<pre.*?<\/pre>/is", function($matches) {
          return "_______here___prf__start" . base64_encode(urlencode($matches[0])) . "_______here___prf__end";
        }, $buffer);
        $buffer = preg_replace_callback("/<script.*?<\/script>/is", function($matches) {
          return "_______here___sct__start" . base64_encode(urlencode($matches[0])) . "_______here___sct__end";
        }, $buffer);
        $buffer = preg_replace_callback("/<textarea.*?<\/textarea>/is", function($matches) {
          return "_______here___txs__start" . base64_encode(urlencode($matches[0])) . "_______here___txs__end";
        }, $buffer);
    
        $buffer = preg_replace(array("/\>[^\S]+/s", "/[^\S]+\</s", "/(\s)+/s" ), array(">", "<", " "), $buffer);
    
        $buffer = preg_replace_callback("/_______here___prf__start.*?_______here___prf__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
        $buffer = preg_replace_callback("/_______here___sct__start.*?_______here___sct__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
        $buffer = preg_replace_callback("/_______here___txs__start.*?_______here___txs__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
    
        if (substr($buffer, 0, 15) == "<!DOCTYPE html>")
          $buffer = substr($buffer, 15);
    
        return
          "<!DOCTYPE html><!--\n" .
            "\n" .
            "  www.example.com / (c) 2023 ActiveTK.\n\n" .
            "  Server-Side Time: " . (microtime(true) - LOAD_START_TIME) . "s\n" .
            "  Cached Date: " . (new DateTime("now", new DateTimeZone("GMT")))->format("Y-m-d H:i:sP") . "\n" .
            "\n" .
          "\n-->" . $buffer . "\n";
    
        return $buffer . "\n";
    
      }
    
      ob_start("minifier_output");
    
    ?>

    下の画像のように、HTMLが圧縮されてコメントが追加されます。


    プログラムの解説

    PHPにはob_startという出力したHTMLをクライアントに流さず、一時的にバッファーに保存できる関数があります。

    これを利用した次のコードをPHPファイルの先頭にコピペすれば、自動でHTMLから空白や改行が削除されて出力されます。

    <?php
    
      function minifier_output($buffer) {
        $buffer = preg_replace(array("/\>[^\S]+/s", "/[^\S]+\</s", "/(\s)+/s" ), array(">", "<", " "), $buffer);
        return $buffer . "\n";
      }
    
      ob_start("minifier_output");
    
    ?>

    ただし、注意しなければならないのは、preやscript、textareaのように中の改行を削除されては困るタグがあります。

    そのため、ページ内にそのようなタグを含む場合には、以下のように「中身をエンコードしておく」処理を追加して下さい。

    <?php
    
      function minifier_output($buffer) {
    
        $buffer = preg_replace_callback("/<pre.*?<\/pre>/is", function($matches) {
          return "_______here___prf__start" . base64_encode(urlencode($matches[0])) . "_______here___prf__end";
        }, $buffer);
        $buffer = preg_replace_callback("/<script.*?<\/script>/is", function($matches) {
          return "_______here___sct__start" . base64_encode(urlencode($matches[0])) . "_______here___sct__end";
        }, $buffer);
        $buffer = preg_replace_callback("/<textarea.*?<\/textarea>/is", function($matches) {
          return "_______here___txs__start" . base64_encode(urlencode($matches[0])) . "_______here___txs__end";
        }, $buffer);
    
        $buffer = preg_replace(array("/\>[^\S]+/s", "/[^\S]+\</s", "/(\s)+/s" ), array(">", "<", " "), $buffer);
    
        $buffer = preg_replace_callback("/_______here___prf__start.*?_______here___prf__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
        $buffer = preg_replace_callback("/_______here___sct__start.*?_______here___sct__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
        $buffer = preg_replace_callback("/_______here___txs__start.*?_______here___txs__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
    
        return $buffer . "\n";
      }
    
      ob_start("minifier_output");
    
    ?>

    また、require_once経由でこの関数を呼び出しており、レスポンスがhtmlであるか分からない場合、以下のように実装しておくと便利です。

    <?php
    
      function minifier_output($buffer) {
    
        // Content-Typeの値からレスポンスの種類を調べる
        foreach(headers_list() as $line)
        {
          list($title, $data) = explode(": ", $line, 2);
          if (strtolower($title) == "content-type" && false === strpos($data, "text/html"))
            return $buffer;
        }
    
        //
        // 省略
        //
    
        return $buffer . "\n";
    
      }
    
      ob_start("minifier_output");
    
    ?>

    HTMLに任意のメッセージを追加する

    HTML内にアスキーアートなどのコメントアウトがあると、view-source:やcurlで閲覧した際に綺麗に見えます。

    ソースコードを圧縮すると同時に、以下のようにHTML内にコメントを追加することができます。

    <?php
    
      // 処理時間計測用
      define( "LOAD_START_TIME", microtime(true) );
    
      function minifier_output($buffer) {
    
        $buffer = preg_replace_callback("/<pre.*?<\/pre>/is", function($matches) {
          return "_______here___prf__start" . base64_encode(urlencode($matches[0])) . "_______here___prf__end";
        }, $buffer);
        $buffer = preg_replace_callback("/<script.*?<\/script>/is", function($matches) {
          return "_______here___sct__start" . base64_encode(urlencode($matches[0])) . "_______here___sct__end";
        }, $buffer);
        $buffer = preg_replace_callback("/<textarea.*?<\/textarea>/is", function($matches) {
          return "_______here___txs__start" . base64_encode(urlencode($matches[0])) . "_______here___txs__end";
        }, $buffer);
    
        $buffer = preg_replace(array("/\>[^\S]+/s", "/[^\S]+\</s", "/(\s)+/s" ), array(">", "<", " "), $buffer);
    
        $buffer = preg_replace_callback("/_______here___prf__start.*?_______here___prf__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
        $buffer = preg_replace_callback("/_______here___sct__start.*?_______here___sct__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
        $buffer = preg_replace_callback("/_______here___txs__start.*?_______here___txs__end/is", function($matches) {
          return urldecode(base64_decode(substr(substr($matches[0], 24), 0, -22)));
        }, $buffer);
    
        if (substr($buffer, 0, 15) == "<!DOCTYPE html>")
          $buffer = substr($buffer, 15);
    
        // コメントを追加
        return
          "<!DOCTYPE html><!--\n" .
            "\n" .
            "  ActiveTK.jp / (c) 2023 ActiveTK.\n\n" .
            "  Server-Side Time: " . (microtime(true) - LOAD_START_TIME) . "s\n" .
            "  Cached Date: " . (new DateTime("now", new DateTimeZone("GMT")))->format("Y-m-d H:i:sP") . "\n" .
            "\n" .
          "\n-->" . $buffer . "\n";
    
        return $buffer . "\n";
    
      }
    
      ob_start("minifier_output");
    
    ?>

    まとめ

    本記事では、PHPで自動でHTMLを圧縮してソースコードを美しくする方法をご紹介させて頂きました。

    綺麗であること以上に、ネットワークの負荷が軽減されるなどのメリットもありますから、ぜひ試してみてください。