未分類

ルクセリタスのコード表示部分をいじり、パス表示を追加してみました。

diff --git a/js/luxe-blocks.js b/js/luxe-blocks.js
index 47d3ce8..a6e77ef 100644
--- a/js/luxe-blocks.js
+++ b/js/luxe-blocks.js
@@ -4411,6 +4411,10 @@ window.addEventListener("DOMContentLoaded", function() {
         language: {
           type: "string",
           default: ""
+        },
+        filename: {
+          type: "string",
+          default: ""
         }
       },
       supports: {
@@ -4464,45 +4468,66 @@ window.addEventListener("DOMContentLoaded", function() {
             value: ""
           }];
         return Object.keys(luxeHighlighterList).forEach(function(e) {
-          c.push({
-            label: this[e],
-            value: e
-          })
-        }, luxeHighlighterList), l.push(s(d.SelectControl, {
-          label: u("Code Language", "luxeritas"),
-          value: a,
-          options: c,
-          onChange: function(e) {
-            return n({
-              language: e
-            })
-          }
-        })), t = s("p", null, u("* The theme can be changed from the CSS tab of Luxeritas menu.", "luxeritas")), [s(p.InspectorControls, {
-          key: "syntaxHighlighterInspectorControls"
-        }, s(d.PanelBody, {
-          title: u("Settings")
-        }, l, t)), s("div", {
-          className: r + " wp-block-code"
-        }, s(p.PlainText, {
-          value: i,
-          onChange: function(e) {
-            return n({
-              content: e
+            c.push({
+              label: this[e],
+              value: e
             })
-          },
-          placeholder: u("To the right, choose a code language from the block settings.", "luxeritas"),
-          "aria-label": u("Syntax Highlighter", "luxeritas")
-        }))]
+          }, luxeHighlighterList), l.push(s(d.SelectControl, {
+            label: u("Code Language", "luxeritas"),
+            value: a,
+            options: c,
+            onChange: function(e) {
+              return n({
+                language: e,
+                filename: o.filename
+              })
+            }
+          })),
+          l.push(s(d.TextControl, {
+            label: u("File Name", "luxeritas"),
+            value: o.filename,
+            onChange: function(e) {
+              return n({
+                language: a,
+                filename: e
+              })
+            }
+          })), t = s("p", null, u("* The theme can be changed from the CSS tab of Luxeritas menu.", "luxeritas")), [s(p.InspectorControls, {
+            key: "syntaxHighlighterInspectorControls"
+          }, s(d.PanelBody, {
+            title: u("Settings")
+          }, l, t)), s("div", {
+            className: r + " wp-block-code"
+          }, s(p.PlainText, {
+            value: i,
+            onChange: function(e) {
+              return n({
+                content: e
+              })
+            },
+            placeholder: u("To the right, choose a code language from the block settings.", "luxeritas"),
+            "aria-label": u("Syntax Highlighter", "luxeritas")
+          }))]
       },
       save: function(e) {
         var t = e.attributes,
           o = t.content,
           n = t.language.replace("highlight_", "");
-        return "" != n ? s("pre", {
-          className: "line-numbers language-" + n
-        }, s("code", {
-          className: "language-" + n
-        }, o)) : s("pre", null, s("code", null, o))
+        var obj;
+        if ("" != n) {
+          var pre = {
+            className: "line-numbers language-" + n,
+          };
+          if (t.filename) {
+            pre["data-label"] = t.filename;
+          }
+          obj = s("pre", pre, s("code", {
+            className: "language-" + n
+          }, o));
+        } else {
+          obj = s("pre", null, s("code", null, o));
+        }
+        return obj;
       }
     })
   }(),
diff --git a/languages/admin/luxeritas-ja-luxe-blocks.json b/languages/admin/luxeritas-ja-luxe-blocks.json
index 4d04781..8381a3c 100644
--- a/languages/admin/luxeritas-ja-luxe-blocks.json
+++ b/languages/admin/luxeritas-ja-luxe-blocks.json
@@ -200,6 +200,9 @@
                        "Code Language": [
                                "言語"
                        ],
+                       "File Name" : [
+                               "ファイル名"
+                       ],
                        "* The theme can be changed from the CSS tab of Luxeritas menu.": [
                                "※ テーマ(見た目)は Luxeritas メニューの CSS タブから変更できます。"
                        ],

luxe-blocks.jsはminifyされてたので、以下で整形してから編集してdiffを取っています。

$ npx js-beautify -s 2 luxe-blocks.js >luxe-blocks.js.new
$ mv luxe-blocks.js.new luxe-blocks.js

編集後は以下でminifyして使っています。

$ npx -p uglify-js uglifyjs luxe-blocks.js -c --output luxe-blocks.js.new
$ mv luxe-blocks.js.new luxe-blocks.js
$ 手作業でライセンスの貼り付け

上記作業はパッチにして以下にまとめてあります。

未分類

何かと面倒なdockerでpostgresを動かし、SSLで接続した上に、せっかくSSLなのでクライアント認証する、という企画です。

CAと鍵と証明書の作成

privateなnetworkなのでオレオレCAを作成します。

create_cert.sh

#!/bin/bash
set -euo pipefail

# create root CA
openssl req -new -nodes -text -subj "/CN=ca.local" -out ca.csr -keyout ca.key
chmod og-rwx ca.key
openssl x509 -req -in ca.csr -text -days 3650 -extfile /etc/ssl/openssl.cnf -extensions v3_ca -signkey ca.key -out ca.crt
rm ca.csr

# create server cert
openssl req -new -nodes -text -out server.csr -keyout server.key -subj "/CN=server.local" 
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
rm server.csr

# create client certs
openssl req -new -nodes -text -out client1.csr -keyout client1.key -subj "/CN=client1.local" 
chmod og-rwx client1.key
openssl x509 -req -in client1.csr -text -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt
rm client1.csr

# change owner for alpine postgres
sudo chown 70 server.key
  • .certが証明書、.keyが秘密鍵
  • caがオレオレルートCAで、serverがpostgresが動くサーバ、client1がクライアント用
  • domainはとりあえず.local
  • CA自己署名証明書は10年、他は1年で作成
  • サーバの秘密鍵はalpine上のpostgresイメージのUIDに合わせて70に

postgresをdockerで起動(初回)

docker-compose.yml

version: "3"

services:
  db:
    image: postgres:12-alpine
    container_name: postgres
    command: -c ssl=on -c ssl_ca_file=/var/lib/postgresql/ca.crt -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
    ports: 
      - "5432:5432"
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_DB=postgres
      - POSTGRES_PASSWORD=secret
    volumes:
      - ./ca.crt:/var/lib/postgresql/ca.crt:ro
      - ./server.crt:/var/lib/postgresql/server.crt:ro
      - ./server.key:/var/lib/postgresql/server.key:ro
      - ./data:/var/lib/postgresql/data
  • 公式イメージではありません!

起動!

$ docker-compose up

SSLで接続(パスワード認証)

別のコンテナからホストに繋いで確認します。

$ docker run -it --rm postgres:12-alpine psql "host=(ホストIP) user=postgres password=secret"

結果

psql (12.1)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=# \q

外部からの認証をSSLクライアント認証のみに設定

サーバーを一度落とす

$ docker-compose down

./data/pg_hba.confの最後を以下に書き換える

#host all all all md5
hostssl all all all cert map=cnmap
  • (ローカルを除く)全IPからのTCPホスト接続をパスワード認証
    → (ローカルを除く)全IPからのTCPホスト接続をSSLクライアント認証(ユーザーマッピングはcnmap)

./data/pg_ident.confに以下を加える

cnmap   /^(.*)\.local$  postgres
  • cnmapという名前で、.localで終わるCNにユーザーpostgresをマッピングするルールを定義

設定確認

起動!

$ docker-compose up

パスワード認証で接続

$ docker run -it --rm postgres:12-alpine psql "host=(ホストIP) user=postgres password=secret"

結果

psql: error: could not connect to server: FATAL:  connection requires a valid client certificate
FATAL:  no pg_hba.conf entry for host "172.20.0.1", user "postgres", database "postgres", SSL off

SSLクライアント認証で接続

$ docker run -it --rm \
-v $PWD/client1.crt:/root/.postgresql/postgresql.crt \
-v $PWD/client1.key:/root/.postgresql/postgresql.key \
-v $PWD/ca.crt:/root/.postgresql/root.crt \
postgres:12-alpine psql "host=(ホストIP) user=postgres"
  • ややこしそうに見えるが、~/.postgresql/にクライアント証明書とクライアント鍵と信頼してるCAの証明書を置いて、ホスト+ユーザー指定で繋いでるだけ

結果

psql (12.1)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=# \q

参考リンク

未分類

前提

  • dockerが使える
  • Visual Studio codeが使える
  • x-debugを使用する

docker

docker-compose.yml

version: "3.1"
services:
  wordpress:
    build: .
    restart: always
    ports:
      - 80:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - ./wordpress:/var/www/html
      - ./php.ini:/usr/local/etc/php/php.ini

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - ./db:/var/lib/mysql

(編集)2021/5/26 不要なvolumeの記述を削除

Dockerfile

FROM wordpress:php7.3
RUN pecl install xdebug \
  && docker-php-ext-enable xdebug

(編集)2021/5/26 誤ったWORKDIR設定を削除

ビルド時に以下のようなメッセージ(タイミングや環境によって異なる)が出るはずなので、これをphp.iniに追加する。

zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so

php.ini

post_max_size = 50M
upload_max_filesize = 50M
memory_limit = 256M
[xdebug]
xdebug.remote_enable=1
xdebug.remote_autostart=1
; ホスト側のIP
; host.docker.internalはdockerのhostマシンのIPを解決してくれます。
; hostマシン以外のIP/WindowとMAC以外の場合は適宜IPを調べて設定してください。
xdebug.remote_host=host.docker.internal
; 空いているport番号
xdebug.remote_port=9000
; xdebugの出力するログの場所。今回は適当に/tmp配下に。
xdebug.remote_log=/tmp/xdebug.log
; Dockerイメージビルド時のメッセージをコピペして追記
zend_extension=?

(追記)2021/5/26 xdebugのバージョンが2から3に上がったらしく、3になると設定変数の名前が大きく変わっている。ほぼ同じ内容を3にしてみた。

post_max_size = 50M
upload_max_filesize = 50M
memory_limit = 256M
[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
; ホスト側のIP
; host.docker.internalはdockerのhostマシンのIPを解決してくれます。
; hostマシン以外のIP/WindowとMAC以外の場合は適宜IPを調べて設定してください。
xdebug.client_host=host.docker.internal
; 空いているport番号
xdebug.client_port=9000
; xdebugの出力するログの場所。今回は適当に/tmp配下に。
xdebug.log=/tmp/xdebug.log
; Dockerイメージビルド時のメッセージをコピペして追記
zend_extension=?

https://xdebug.org/docs/upgrade_guide/ja

Visual Studio code

.vscode/launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "pathMappings": {
                // {docker上のdocument root}:{ローカルのdocument root}
                "/var/www/html":"/path/to/wordpress"
            }
        }
    ]
}

参考サイト

未分類

今回は、wgetの–level(リンクの最大深さ)と–convert-link(オフライン閲覧用のリンク修正)の内容を検証する。

対象はGNU Wget 1.20.1。

–level(リンクの最大深さ) の検証

ここでは、最大範囲まで辿られると、時間が増えないことを検証する。

クロール先の作成

HTMLを生成するshellスクリプト

COUNT=$1
BASE_URL="https://elephantcat.work/wget_test"
for i in `seq $COUNT`;do
        FILE="$i.html"

        echo "<html lang=\"en\">" > $FILE
        echo "<body>" >> $FILE
        echo "<ul>" >> $FILE
        MAXJ=`expr $i + 1`
        for j in `seq $MAXJ`;do
                URL="$BASE_URL/$j.html"
                echo "<li><a href=\"$URL\">$j</a></li>" >> $FILE
        done
        echo "</ul>" >> $FILE
        echo "</body>" >> $FILE
        echo "</html>" >> $FILE
done

上記を実行して、50個分のHTMLを生成

$ sh create_htmls.sh 30

カレントディレクトリに1.html~30.htmlが作成されます。例えば3.htmlは以下のようなものになります。

<html lang="en">
<body>
<ul>
<li><a href="https://elephantcat.work/wget_test/1.html">1</a></li>
<li><a href="https://elephantcat.work/wget_test/2.html">2</a></li>
<li><a href="https://elephantcat.work/wget_test/3.html">3</a></li>
<li><a href="https://elephantcat.work/wget_test/4.html">4</a></li>
</ul>
</body>
</html>

3.htmlは4つのリンクを持つHTMLファイルです。同様に、n.htmlは、n+1個のリンクを持つHTMLファイルであり、1.htmlから1つずつリンクを辿る度にファイルが増えるようなネットワーク構造になっています。

測定

1.htmlを起点にレベル1つずつ増やしながら、50回時間を計測します。測定用のスクリプトが以下になります。

for i in `seq 50`; do
        rm -r elephantcat.work/wget_test
        /usr/bin/time --quiet -f %e wget --quiet --recursive --level $i --page-requisites --adjust-extension --span-hosts --convert-links --restrict-file-names=windows --domains elephantcat.work --no-parent https://elephantcat.work/wget_test/1.html
done

実行すると標準出力に実行時間が1行ずつ出るので、リダイレクトしてファイル(time.log)に落とします。

$ sh measure.sh > time.log

後はExcelなどでグラフにすればOK。今回は遊びで、PerlのText::Chartを使ってみました。

use Text::Chart qw(gen_text_chart);

chomp(my @nums=<STDIN>);
my $res = gen_text_chart(
    data => \@nums,
    chart_height => 10,
    type => 'sparkline',
);

binmode(STDOUT, ":utf8");
print $res;

これを使うとテキストで棒グラフが書けます(整形が結構大変)。

結果と考察

                                █  ▄         █     2[秒]
                             ▃▁ █▅▂█▆▂ ▄▃▂▄▂▂█▆▃▂▁
                         ▃▂  █████████▇███████████
                         ██▃▄█████████████████████
                    ▂▂▁▃▇█████████████████████████
               ▁ ▁▂▄██████████████████████████████ 1
             ▅▆█▇█████████████████████████████████
         ▂▃▄▇█████████████████████████████████████
     ▂▃▅▇█████████████████████████████████████████
 ▂▄▆██████████████████████████████████████████████ 
回数     10        20        30        40        50

30回以降横ばいに見えます。レベルは最大回数を超えると取得時間が頭打ちになるということです(当然ですが)。

–convert-link(オフライン閲覧用のリンク修正)の内容検証

前節で生成し、wgetで取得した3.htmlを見てみます。

<html lang="en">
<body>
<ul>
<li><a href="1.html">1</a></li>
<li><a href="2.html">2</a></li>
<li><a href="3.html">3</a></li>
<li><a href="4.html">4</a></li>
</ul>
</body>
</html>

上にあるものと比べると、絶対URLだったリンクURLが、相対URLになってることが分かります。絶対URLでないのは、オフライン閲覧した際にリンク切れになってしまうからです。このように、オフライン閲覧などを考慮すると、(元のサイト次第ですが)HTMLの書き換えが必要となります。以降では絶対URL→相対URLの書き換え以外のリンク書き換えパターンを見ていきます(全部ではありません)。

ディレクトリ

例えば、https://elehantcat.work/、これにもファイル名がありません。通常、この内容はtext/htmlであり、多くの場合、index.htmlやらindex.phpやらindex.jspやらindex.jsやら、拡張子は違えど、共通してindex.*という形式の名前のファイルが処理していることが多いと思います。wgetでは、ディレクトリの内容を取得すると、ファイル名にはindex.htmlを使用します。リンクURLは当然ただのディレクトリなので、オフライン閲覧のためには書き換えが必要になります。

拡張子なし

例えば最近の動的に生成されるページでは、URLを見てコントローラを選ぶルーティング機能を導入しているフレームワークが多いです。そのようなフレームワークを使用すると、URLとコントローラなどが必ずしも一対一対応しないので、URLのファイル名部分に拡張子が付かなくなります。

これらのURLからファイルとして内容をダウンロードした場合、拡張子のないファイルは見た目で何のファイルか分からず、扱いに困ります。そこで、wgetではオプション(–adjust-extension)でContent-Typeから拡張子を付けてくれる機能が追加されています。このようなケースではリンク元は拡張子がついていないため、オフライン閲覧用に書き換えが必要になります。

その他

他にもいろいろありますが、あとは自分で見つけてください。マニュアルは、以下にあります。

https://www.gnu.org/software/wget/manual/wget.html

最後に

–convert-linkによるリンク書き換え処理は全部ダウンロードが終わってからなので、Ctrl+Cで止めると書き換えずに終わってしまいます。ご注意ください。

未分類

今どきオフライン作業なんてあんまりないけど、wgetって単独ファイルだけでなく、JavaScriptなどで作られてない静的なリンクなら辿って次を取得することもできる。昔の貧弱なネットワークの頃は重宝した。

取得してみる

とりあえずこのサイトをwgetで取得してみる。パラメータは以下のサイトを参考にした。(–domains指定は–span-hostsと同時指定禁止なので除外)

shell – How to download an entire site with wget including its images – Super User

$ wget --recursive \
--level 5 \
--page-requisites \
--adjust-extension \
--span-hosts \
--convert-links \
--restrict-file-names=windows \
--domains elephantcat.work \
--no-parent \
elephantcat.work

上記コマンドを実行すると、elephantcat.workから、再帰的に5段階までリンクを辿り、同一ホスト内の全ページをローカルファイルに保存してくれる。保存する際には、ホスト名のディレクトリ下にURLから想定される名前で保存される。HTML内には埋め込まれる要素やリンクなどもあるが、静的なものは残らず解析して取ってきてくれる。クエリなどがあっても、URIとして区別されればちゃんとそれをファイル名にして保存される。

オプション説明

オプション意味
–recursive再帰的に取得
–level 数字指定された深さまで再帰的に取得
–page-requisites画像など HTMLを適切に表示するために必要なすべてのファイルを取得
–adjust-extensionMIMEタイプなどを元に拡張子を自動で修正する
–span-hosts同一ホスト内の リンク のみ辿る
–convert-links同一ホストへのリンクを相対リンクに書き換える
–restrict-file-names=windowsファイル名の大文字/小文字統一や使用禁止文字のエスケープに使用するモードの指定
–domains指定ドメイン以外を取得しない
–no-parent親ディレクトリ側へのリンクを辿らない

注意事項

重要なのは探索範囲と時間に大きく影響する–levelと、–convert-links。

–levelはサイトの大きさやクロール可能な時間に合わせて適宜修正が必要。全ての経路を辿れる深さ以上を指定しても取得時間は増加しない。

ダウンロードされたファイルは必ずしもURLとおりの構成にできるわけではないので、–convert-linksはダウンロードしたファイルをオフライン閲覧できるよう、 HTMLの中身を書き換えることを意味している。そして、この処理は、指定した範囲のファイルを全て取得し終わった後、最後に行われるので注意。「時間かかるからこの辺でやめる→Ctrl+C」とかするとこの変換はかからない。

未分類

今まではデフォルトのTwentyTwentyを使ってました。

個人的に特に不満はなかったのですが、まあいろいろやってみないとねってことで、テーマ変更にチャレンジしました。

基準は技術ブログで使えそうなテーマ。最初は検索でCoCoonとかがよく引っかかってたのですが、何かピンと来ない。何かみんな同じに見えるんですよね。

少し毛色の違うやつ…と探して海外のを見に行くと…出るわ出るわtechnologyがキーワードに入っててもトロピカルだったり、何か全然普通のテーマばかり。そしてfreeというキーワードも無視されてほとんど有料。押しの強い彼らに良いものを尋ねてはいけないようです。

初心に帰って、そう、Qiitaとかに近い使い勝手のtheme!と探してて見つけたのがコレ。Luxeritasです。

  • 目次が自動で入るらしい
  • カワイイ

ということで、とりあえず変えてみました。

未分類

前回3~4倍遅くなるということは分かっていたのですが、

PHPのリリース日とサポート期限 – Qiita

などを見てしまうと、こうせざるをえませんでした。

共有レンタルサーバの限界を見た気がします。

Herokuであればapacheなどを共有する必要もなく、コンテナごとにいくらでも選べるわけです。常駐プロセス問題も30分ルールで解決してるし最強です。

VPSなら管理権限も与えられて全部自由です。

まあVPSを借りるのが勿体ないと感じたから共有サーバなんですけどね。Herokuも考えたけど、DB容量が不足してました。PHP7でLaravelも出来る!前向きに捉えます。

未分類

さて、VALUE-SERVERでは、

  • mod_phpだけどphp5という構成
  • CGI版だけどphp7という構成

がある。

普通に考えると言語固有モジュール版であるmod_phpの方が早い。しかし、バージョンアップにより何倍も早くなるというphpではどちらが速いのかよく分からない。

幸いにもサブドメインのwww.elephantcat.workでは別のphpを設定できるので、こちらにCGI+php7を設定し、前回同様の測定をやってみた。

結果

PatternTime[s]Effective Time[s]
static HTML4.85
mod_php5 + PHP5.66.121.27
mod_cgi + PHP7.39.184.33

Effective TimeはTimeからstatic HTMLパターンの時間を引いた時間です。こうすることにより、純粋にPHPに関連する時間だけが残ります。

CGI php7ではmod_php5の約3~4倍程度の時間に収まっています。が、やはりCGIの方が遅いようです。

未分類

前書き

前回はCGIのbottleとdjangoを50回取得した時間を比較しました。

では、WordPressを推してるVALUE-SERVERが力を入れてそうなPHPだと、どれくらいの時間なのでしょうか?

ただの静的なHTMLページも加えて比較してみました。

加えたもの

<?php echo "Hello, World"; ?>
Hello, World!

比較用のシェルはこうなります。

for url in django.cgi/polls/ hello.cgi/ hello.php hello.html;do
        time bash -c "for i in {0..99};do wget -q -O - https://elephantcat.work/cgi-bin/$url >/dev/null;done"
done

結果

Patterntime[s]
CGI Python + bottle 22.22
CGI Python + django 66.00
mod_php PHP56.12
static HTML4.85

これがCGI及びPythonインタプリタの起動の遅さということです。

なお、計測器からelephantcat.workへのping100回の平均値は6.421msでした。

未分類

前回前々回で作成したHello, World!なアプリを外からGetして時間を測定してみました。

for url in django.cgi/polls/ hello.cgi/;do
        time bash -c "for i in {0..49};do wget -q -O - https://elephantcat.work/cgi-bin/$url >/dev/null;done"
done

結果は

0.33user 0.31system 0:31.69elapsed 2%CPU (0avgtext+0avgdata 7176maxresident)k
0inputs+256outputs (0major+21808minor)pagefaults 0swaps
0.30user 0.34system 0:10.98elapsed 5%CPU (0avgtext+0avgdata 7180maxresident)k
0inputs+88outputs (0major+21767minor)pagefaults 0swaps
フレームワーク 50回取得にかかった時間[秒]
django 31.7
bottle 11.0

django遅いのは分かるけど、bottleでも十分遅いと思う。

CGI Python恐るべし。