diff options
16 files changed, 209 insertions, 431 deletions
diff --git a/nuldoc-src/html.ts b/nuldoc-src/html.ts index 2832490..5e573ad 100644 --- a/nuldoc-src/html.ts +++ b/nuldoc-src/html.ts @@ -160,7 +160,7 @@ function elementNodeToHtmlText(e: Element, ctx: Context): string { } } s += ">"; - if (dtd.type === "block") { + if (dtd.type === "block" && e.name !== "pre") { s += "\n"; } } @@ -171,7 +171,7 @@ function elementNodeToHtmlText(e: Element, ctx: Context): string { ctx.isInPre = true; } forEachChild(e, (c) => { - if (dtd.type === "block") { + if (dtd.type === "block" && !ctx.isInPre) { if (isInlineNode(c)) { if (needsIndent(prevChild)) { s += indent(ctx); @@ -191,11 +191,13 @@ function elementNodeToHtmlText(e: Element, ctx: Context): string { ctx.indentLevel -= 1; if (e.name !== "__root__" && !dtd.auto_closing) { - if (dtd.type === "block") { - if (needsLineBreak(prevChild)) { - s += "\n"; + if (e.name !== "pre") { + if (dtd.type === "block") { + if (needsLineBreak(prevChild)) { + s += "\n"; + } + s += indent(ctx); } - s += indent(ctx); } s += `</${e.name}>`; if (dtd.type === "block") { diff --git a/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html index ae44da9..ed91b45 100644 --- a/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html +++ b/public/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html @@ -56,8 +56,7 @@ タイトル落ち。まずはこのコードを見て欲しい。 </p> - <pre class="highlight" language="cpp" linenumbering="unnumbered"> - <code>#include <iostream> + <pre class="highlight" language="cpp" linenumbering="unnumbered"><code>#include <iostream> [[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]] [[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]] @@ -75,8 +74,7 @@ // [[using]] int main() { std::cout << "Hello, World!" << std::endl; -}</code> - </pre> +}</code></pre> <blockquote> <p> @@ -126,10 +124,8 @@ std::cout << "Hello, World!" << std::endl; 上のコードでは<code>[[using]]</code>をコメントアウトしているが、これは<code>using</code>キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。 </p> - <pre class="highlight" language="cpp" linenumbering="unnumbered"> - <code>// using の例 -[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文</code> - </pre> + <pre class="highlight" language="cpp" linenumbering="unnumbered"><code>// using の例 +[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文</code></pre> <p> C++17 の仕様も見てみる (正確には標準化前のドラフト)。 diff --git a/public/posts/2021-10-02/python-unbound-local-error/index.html b/public/posts/2021-10-02/python-unbound-local-error/index.html index 27c2d05..0516d6f 100644 --- a/public/posts/2021-10-02/python-unbound-local-error/index.html +++ b/public/posts/2021-10-02/python-unbound-local-error/index.html @@ -60,15 +60,13 @@ Python でクロージャを作ろうと、次のようなコードを書いた。 </p> - <pre class="highlight" language="python" linenumbering="unnumbered"> - <code>def f(): + <pre class="highlight" language="python" linenumbering="unnumbered"><code>def f(): x = 0 def g(): x += 1 g() -f()</code> - </pre> +f()</code></pre> <p> 関数<code>g</code>から 関数<code>f</code>のスコープ内で定義された変数<code>x</code>を参照し、それに 1 を足そうとしている。 これを実行すると<code>x += 1</code>の箇所でエラーが発生する。 @@ -84,8 +82,7 @@ f()</code> local変数<code>x</code>が代入前に参照された、とある。これは、<code>f</code>の<code>x</code>を参照するのではなく、新しく別の変数を<code>g</code>内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<code>var</code>を変数宣言のための構文として擬似的に利用している。 </p> - <pre class="highlight" language="python" linenumbering="unnumbered"> - <code># 注: var は正しい Python の文法ではない。上記参照のこと + <pre class="highlight" language="python" linenumbering="unnumbered"><code># 注: var は正しい Python の文法ではない。上記参照のこと def f(): var x # f の local変数 'x' を宣言 x = 0 # x に 0 を代入 @@ -94,21 +91,18 @@ var x # g の local変数 'x' を宣言 # たまたま f にも同じ名前の変数があるが、それとは別の変数 x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) # 加算する前の値を参照しようとするが、まだ代入されていないためエラー -g()</code> - </pre> +g()</code></pre> <p> 当初の意図を表現するには、次のように書けばよい。 </p> - <pre class="highlight" language="python" linenumbering="unnumbered"> - <code>def f(): + <pre class="highlight" language="python" linenumbering="unnumbered"><code>def f(): x = 0 def g(): nonlocal x ## (*) x += 1 -g()</code> - </pre> +g()</code></pre> <p> <code>(*)</code>のように、<code>nonlocal</code>を追加する。これにより一つ外側のスコープ (<code>g</code>の一つ外側 =<code>f</code>) で定義されている<code>x</code>を探しに行くようになる。 diff --git a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html index ed7ccd5..1163674 100644 --- a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html +++ b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html @@ -65,14 +65,12 @@ 上記ページの例から引用する: </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ ruby-1.9.1 -ve 'p RUBY_ENGINE' + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ruby-1.9.1 -ve 'p RUBY_ENGINE' ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] "ruby" $ jruby -ve 'p RUBY_ENGINE' jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] -"jruby"</code> - </pre> +"jruby"</code></pre> <p> それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 @@ -192,12 +190,10 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] <a href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</a>より引用: </p> - <pre class="highlight" language="c" linenumbering="unnumbered"> - <code>/* + <pre class="highlight" language="c" linenumbering="unnumbered"><code>/* * Ruby engine. */ -#define MRUBY_RUBY_ENGINE "mruby"</code> - </pre> +#define MRUBY_RUBY_ENGINE "mruby"</code></pre> </div> </article> </main> diff --git a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html index 9b1df47..ed8d9e8 100644 --- a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html +++ b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html @@ -65,20 +65,17 @@ 使われることは稀だが、Ruby では<code>then</code>がキーワードになっている。次のように使う: </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code>if cond then + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code>if cond then puts "Y" else puts "N" - end</code> - </pre> + end</code></pre> <p> このキーワードが現れうる場所はいくつかあり、<code>if</code>、<code>unless</code>、<code>rescue</code>、<code>case</code>構文がそれに当たる。 上記のように、何か条件を書いた後<code>then</code>を置き、式がそこで終了していることを示すマーカーとして機能する。 </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code># Example: + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code># Example: if x then a @@ -97,8 +94,7 @@ end case x when p then a -end</code> - </pre> +end</code></pre> </section> <section id="section--_なぜ普段は書かなくてもよいのか"> @@ -107,21 +103,17 @@ end</code> 普通 Ruby のコードで<code>then</code>を書くことはない。なぜか。次のコードを実行してみるとわかる。 </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code>if true puts 'Hello, World!' end</code> - </pre> + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code>if true puts 'Hello, World!' end</code></pre> <p> 次のような構文エラーが出力される。 </p> - <pre class="monospaced highlight"> - <code>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' + <pre class="monospaced highlight"><code>20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' if true puts 'Hello, World!' end ^~~~ 20:1: syntax error, unexpected `end', expecting end-of-input - ...f true puts 'Hello, World!' end</code> - </pre> + ...f true puts 'Hello, World!' end</code></pre> <p> 二つ目のメッセージは無視して一つ目を読むと、<code>then</code>か<code>;</code>か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 @@ -131,10 +123,8 @@ end</code> ポイントは改行が<code>then</code>(や<code>;</code>) の代わりとなることである。<code>true</code>の後に改行を入れてみる。 </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code>if true -puts 'Hello, World!' end</code> - </pre> + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code>if true +puts 'Hello, World!' end</code></pre> <p> 無事 Hello, World! と出力されるようになった。 @@ -147,27 +137,21 @@ puts 'Hello, World!' end</code> なぜ<code>then</code>や<code>;</code>や改行 (以下 「<code>then</code>等」) が必要なのだろうか。次の例を見てほしい: </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code>if a b end</code> - </pre> + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code>if a b end</code></pre> <p> <code>then</code>も<code>;</code>も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。 </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価 + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code># a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価 if a then b -end</code> - </pre> +end</code></pre> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、 + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code># a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、 # その結果が truthy なら何もしない if a(b) then -end</code> - </pre> +end</code></pre> <p> <code>then</code>等はこの曖昧性を排除するためにあり、条件式は<code>if</code>から<code>then</code>等までの間にある、ということを明確にする。 C系の<code>if</code>後に来る<code>(</code>/<code>)</code>や、Python の<code>:</code>、Rust/Go/Swift などの<code>{</code>も同じ役割を持つ。 @@ -188,8 +172,7 @@ end</code> <a href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</a> </p> - <pre class="highlight" language="yacc" linenumbering="unnumbered"> - <code>p_case_body : keyword_in + <pre class="highlight" language="yacc" linenumbering="unnumbered"><code>p_case_body : keyword_in { SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); p->command_start = FALSE; @@ -214,17 +197,14 @@ end</code> /*% %*/ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/ } - ;</code> - </pre> + ;</code></pre> <p> 簡略版: </p> - <pre class="highlight" language="yacc" linenumbering="unnumbered"> - <code>p_case_body : keyword_in p_top_expr then compstmt p_cases -;</code> - </pre> + <pre class="highlight" language="yacc" linenumbering="unnumbered"><code>p_case_body : keyword_in p_top_expr then compstmt p_cases +;</code></pre> <p> ここで、<code>keyword_in</code>は文字通り<code>in</code>、<code>p_top_expr</code>はいわゆるパターン、<code>then</code>は<code>then</code>キーワードのことではなく、この記事で<code>then</code>等と呼んでいるもの、つまり<code>then</code>キーワード、<code>;</code>、改行のいずれかである。 @@ -234,8 +214,7 @@ end</code> これにより、<code>case</code>-<code>when</code>による従来の構文と同じように、<code>then</code>等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる: </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code>case x + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code>case x in 1 then a in 2 then b in 3 then c @@ -254,20 +233,17 @@ case x in 1; a in 2; b in 3; c -end</code> - </pre> +end</code></pre> <p> ところで、<code>p_top_expr</code>には<code>if</code>による guard clause が書けるので、その場合は<code>if</code>-<code>then</code>と似たような見た目になる。 </p> - <pre class="highlight" language="ruby" linenumbering="unnumbered"> - <code>case x + <pre class="highlight" language="ruby" linenumbering="unnumbered"><code>case x in 0 then a in n if n < 0 then b in n then c -end</code> - </pre> +end</code></pre> </section> <section id="section--_まとめ"> diff --git a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html index 8bcb923..5b1f86a 100644 --- a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html +++ b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html @@ -55,8 +55,7 @@ Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 </p> - <pre class="highlight" language="rust" linenumbering="unnumbered"> - <code>#![allow(non_camel_case_types)] + <pre class="highlight" language="rust" linenumbering="unnumbered"><code>#![allow(non_camel_case_types)] #![allow(dead_code)] struct bool; @@ -75,8 +74,7 @@ struct u128; struct usize; struct f32; struct f64; -struct str;</code> - </pre> +struct str;</code></pre> <p> では、普段単に<code>bool</code>と書いたとき、この<code>bool</code>は一体どこから来ているのか。rustc のソースを追ってみた。 @@ -111,34 +109,29 @@ struct str;</code> <code>rustc</code>はセルフホストされている (=<code>rustc</code>自身が Rust で書かれている) ので、<code>bool</code>や<code>char</code>などで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことに<code>i128</code>/<code>u128</code>というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って<code>git grep</code>してみる。 </p> - <pre class="monospaced highlight"> - <code>$ git grep "\bi128\b" | wc # i128 + <pre class="monospaced highlight"><code>$ git grep "\bi128\b" | wc # i128 165 1069 15790 $ git grep "\bu128\b" | wc # u128 293 2127 26667 $ git grep "\bbool\b" | wc # cf. bool の結果 -3563 23577 294659</code> - </pre> +3563 23577 294659</code></pre> <p> 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 </p> - <pre class="monospaced highlight"> - <code>$ git grep "\bi128\b" + <pre class="monospaced highlight"><code>$ git grep "\bi128\b" ... rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128)); -...</code> - </pre> +...</code></pre> <p> <code>rustc_resolve</code>というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 </p> - <pre class="highlight" language="rust" linenumbering="unnumbered"> - <code>/// Interns the names of the primitive types. + <pre class="highlight" language="rust" linenumbering="unnumbered"><code>/// Interns the names of the primitive types. /// /// All other types are defined somewhere and possibly imported, but the primitive ones need /// special handling, since they have no place of origin. @@ -169,8 +162,7 @@ table.insert(sym::u64, Uint(UintTy::U64)); table.insert(sym::u128, Uint(UintTy::U128)); Self { primitive_types: table } } -}</code> - </pre> +}</code></pre> <p> これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 @@ -186,8 +178,7 @@ Self { primitive_types: table } とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 </p> - <pre class="highlight" language="rust" linenumbering="unnumbered"> - <code> /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. + <pre class="highlight" language="rust" linenumbering="unnumbered"><code> /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. /// (略) fn resolve_ident_in_lexical_scope( &mut self, @@ -207,8 +198,7 @@ return Some(LexicalScopeBinding::Item(binding)); } None -}</code> - </pre> +}</code></pre> <p> 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。<code>if ns == TypeNS</code>のブロック内では、<code>primitive_type_table</code>(上記の<code>PrimitiveTypeTable::new()</code>で作られた変数) に含まれている識別子 (<code>bool</code>、<code>i32</code>など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 @@ -226,15 +216,13 @@ None 動作がわかったところで、例として次のコードを考える。 </p> - <pre class="highlight" language="rust" linenumbering="unnumbered"> - <code>#![allow(non_camel_case_types)] + <pre class="highlight" language="rust" linenumbering="unnumbered"><code>#![allow(non_camel_case_types)] struct bool; fn main() { let _: bool = bool; -}</code> - </pre> +}</code></pre> <p> ここで<code>main()</code>の<code>bool</code>は<code>struct bool</code>として解決される。なぜなら、プリミティブ型の判定をする前に<code>bool</code>という名前の別の型が見つかるからだ。 diff --git a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html index db28b1c..8e34b4d 100644 --- a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html +++ b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html @@ -112,30 +112,24 @@ <a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</a> </p> - <pre class="highlight" language="c" linenumbering="unnumbered"> - <code> {"BufAdd", EVENT_BUFADD}, -{"BufCreate", EVENT_BUFADD},</code> - </pre> + <pre class="highlight" language="c" linenumbering="unnumbered"><code> {"BufAdd", EVENT_BUFADD}, +{"BufCreate", EVENT_BUFADD},</code></pre> <p> <a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</a> </p> - <pre class="highlight" language="c" linenumbering="unnumbered"> - <code> {"BufRead", EVENT_BUFREADPOST}, + <pre class="highlight" language="c" linenumbering="unnumbered"><code> {"BufRead", EVENT_BUFREADPOST}, {"BufReadCmd", EVENT_BUFREADCMD}, -{"BufReadPost", EVENT_BUFREADPOST},</code> - </pre> +{"BufReadPost", EVENT_BUFREADPOST},</code></pre> <p> <a href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</a> </p> - <pre class="highlight" language="c" linenumbering="unnumbered"> - <code> {"BufWrite", EVENT_BUFWRITEPRE}, + <pre class="highlight" language="c" linenumbering="unnumbered"><code> {"BufWrite", EVENT_BUFWRITEPRE}, {"BufWritePost", EVENT_BUFWRITEPOST}, -{"BufWritePre", EVENT_BUFWRITEPRE},</code> - </pre> +{"BufWritePre", EVENT_BUFWRITEPRE},</code></pre> </section> <section id="section--_neovim_のソースコード"> @@ -148,24 +142,20 @@ <a href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</a> </p> - <pre class="highlight" language="lua" linenumbering="unnumbered"> - <code> aliases = { + <pre class="highlight" language="lua" linenumbering="unnumbered"><code> aliases = { BufCreate = 'BufAdd', BufRead = 'BufReadPost', BufWrite = 'BufWritePre', FileEncoding = 'EncodingChanged', -},</code> - </pre> +},</code></pre> <p> ところで、上では取り上げなかった<code>FileEncoding</code>だが、これは<code>:help FileEncoding</code>にしっかりと書いてある。 </p> - <pre class="monospaced highlight"> - <code> *FileEncoding* + <pre class="monospaced highlight"><code> *FileEncoding* FileEncoding Obsolete. It still works and is equivalent -to |EncodingChanged|.</code> - </pre> +to |EncodingChanged|.</code></pre> </section> <section id="section--_まとめ"> diff --git a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html index 8a3b304..f4e2b71 100644 --- a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html +++ b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html @@ -115,11 +115,9 @@ なお、<code>:g/^/m0</code>は全ての行を入れ替えるが、<code>:N,Mg/^/mN-1</code>とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。 </p> - <pre class="highlight" language="vim" linenumbering="unnumbered"> - <code>command! -bar -range=% + <pre class="highlight" language="vim" linenumbering="unnumbered"><code>command! -bar -range=% \ Reverse -\ <line1>,<line2>g/^/m<line1>-1</code> - </pre> +\ <line1>,<line2>g/^/m<line1>-1</code></pre> <p> これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 @@ -152,15 +150,13 @@ 前述した<code>:Reverse</code>コマンドの定義を少し変えて、次のようにする: </p> - <pre class="highlight" language="vim" linenumbering="unnumbered"> - <code>function! s:reverse_lines(from, to) abort + <pre class="highlight" language="vim" linenumbering="unnumbered"><code>function! s:reverse_lines(from, to) abort execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1) endfunction command! -bar -range=% \ Reverse - \ call <SID>reverse_lines(<line1>, <line2>)</code> - </pre> + \ call <SID>reverse_lines(<line1>, <line2>)</code></pre> <p> 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 @@ -211,11 +207,9 @@ </p> </blockquote> - <pre class="highlight" language="vim" linenumbering="unnumbered"> - <code>command! -bar -range=% + <pre class="highlight" language="vim" linenumbering="unnumbered"><code>command! -bar -range=% \ Reverse - \ keeppatterns <line1>,<line2>g/^/m<line1>-1</code> - </pre> + \ keeppatterns <line1>,<line2>g/^/m<line1>-1</code></pre> <p> まさにこのための Exコマンド、<code>:keeppatterns</code>が存在する。<code>:keeppatterns {command}</code>のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 @@ -230,13 +224,11 @@ <section id="section--_コピペ用再掲"> <h2><a href="#section--_コピペ用再掲">コピペ用再掲</a></h2> - <pre class="highlight" language="vim" linenumbering="unnumbered"> - <code>" License: Public Domain + <pre class="highlight" language="vim" linenumbering="unnumbered"><code>" License: Public Domain command! -bar -range=% \ Reverse - \ keeppatterns <line1>,<line2>g/^/m<line1>-1</code> - </pre> + \ keeppatterns <line1>,<line2>g/^/m<line1>-1</code></pre> </section> </div> </article> diff --git a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html index d16739b..bbeacb2 100644 --- a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html +++ b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -66,8 +66,7 @@ ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php declare(strict_types=0O1); @@ -135,8 +134,7 @@ $👉, $👍, $👍, $📝, $👉, $👎, $📝, $👈, $📝, - ]);</code> - </pre> + ]);</code></pre> <p> この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 @@ -165,8 +163,7 @@ なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 </p> - <pre class="monospaced highlight"> - <code>+ + + + + + + + + + + <pre class="monospaced highlight"><code>+ + + + + + + + + + [ > + + + > + + + + + @@ -187,8 +184,7 @@ < . > + + . > - . -< .</code> - </pre> +< .</code></pre> <p> 実行結果はこちら:<a href="https://ideone.com/22VWmb">https://ideone.com/22VWmb</a> @@ -271,9 +267,7 @@ ソースコードのライセンスを示したこの部分だが、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>https://creativecommons.org/publicdomain/zero/1.0/</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>https://creativecommons.org/publicdomain/zero/1.0/</code></pre> <p> 完全に合法な PHP のコードである。<code>https:</code>部分はラベル、<code>//</code>以降は行コメントになっている。 @@ -286,13 +280,11 @@ ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>assert(0 === +!![]); + <pre class="highlight" language="php" linenumbering="unnumbered"><code>assert(0 === +!![]); assert(1 === +![]); assert(2 === ![]+![]); assert(3 === ![]+![]+![]); -assert(10 === +(![].+!![]));</code> - </pre> +assert(10 === +(![].+!![]));</code></pre> <p> <code>[]</code>に<code>!</code>を適用すると<code>true</code>が返ってくる。それに<code>+</code>を適用すると、<code>bool</code>から<code>int</code>ヘの型変換が走り、<code>1</code>が生成される。<code>10</code>はさらにトリッキーだ。まず<code>1</code>と<code>0</code>を作り、<code>.</code>で文字列として結合する (<code>'10'</code>)。これに<code>+</code>を適用すると、<code>string</code>から<code>int</code>への型変換が走り、<code>10</code>が生まれる (コード量に頓着しないなら、<code>1</code>を 10 個足し合わせてももちろん 10 が作れる)。 @@ -333,8 +325,7 @@ assert(10 === +(![].+!![]));</code> ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php /********************************************************* * This program displays a PHPer token. * @@ -367,8 +358,7 @@ assert(10 === +(![].+!![]));</code> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x); $x = implode("\n", str_split($x, length: 5)); echo "{$x}\n\n"; - }</code> - </pre> + }</code></pre> <p> さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数<code>N</code>を特定する必要がある。 @@ -384,43 +374,33 @@ assert(10 === +(![].+!![]));</code> まずはソースコードを読んでいく。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$token = [ + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$token = [ // 略 - ];</code> - </pre> + ];</code></pre> <p> 数値からなる<code>$token</code>があり、各要素をループしている。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = $x ^ N;</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = $x ^ N;</code></pre> <p> まずは排他的論理和 (xor) を取り、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = sprintf('%025b', $x);</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = sprintf('%025b', $x);</code></pre> <p> 二進数に変換して、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);</code></pre> <p> 0 を空白に、1 を<code>#</code>にし、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> $x = implode("\n", str_split($x, length: 5));</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> $x = implode("\n", str_split($x, length: 5));</code></pre> <p> 5文字ごとに区切ったあと、改行で結合している。 @@ -474,16 +454,13 @@ assert(10 === +(![].+!![]));</code> <code>N</code>は高々 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);</code></pre> <p> なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $x = 0x14B499C; @@ -498,15 +475,13 @@ assert(10 === +(![].+!![]));</code> "#####\n" . " # # \n" . "#####\n" . - " # # ");</code> - </pre> + " # # ");</code></pre> <p> この一連の変換に対する逆変換を考えると、次のようになる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $x = " # # \n" . @@ -521,8 +496,7 @@ $x = bindec($x); $n = $x ^ 0x14B499C; -echo "N = $n\n";</code> - </pre> +echo "N = $n\n";</code></pre> <p> これを実行すると、<code>N</code>が得られる。 @@ -536,8 +510,7 @@ echo "N = $n\n";</code> ソースコードはこちら。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php // License: https://creativecommons.org/publicdomain/zero/1.0/ // This is a quine-like program to generate a PHPer token. @@ -565,16 +538,13 @@ echo "N = $n\n";</code> $t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs[$i])) break; else $t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n"; $ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10)); - printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));</code> - </pre> + printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));</code></pre> <p> コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ php toquine.php | php | php | php | ...</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php toquine.php | php | php | php | ...</code></pre> <p> 実際にはもう少しパイプで繋げなければならない。 diff --git a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html index bf174b8..be694e9 100644 --- a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html +++ b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html @@ -43,9 +43,7 @@ こんなものを作った。 </p> - <pre class="monospaced highlight"> - <code>$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</code> - </pre> + <pre class="monospaced highlight"><code>$ term-banner 'Hello, World!' 'こんにちは、' '世界!'</code></pre> <p> image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner のスクリーンショット] diff --git a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html index fbac1f0..ea60e83 100644 --- a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html +++ b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html @@ -111,9 +111,7 @@ 書いたものがこちら: </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]</code></pre> <p> しめて 123 バイトとなった (末尾改行を含めずにカウント)。 @@ -123,8 +121,7 @@ こちらは改行とスペースを追加したバージョン: </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>[<?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code>[<?php $n = $argv[1]; foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x) @@ -132,8 +129,7 @@ $r[] = $x; echo implode(', ', $r ?? []); - ?>]</code> - </pre> + ?>]</code></pre> </section> <section id="section--_使用したテクニック"> diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html index abdb48e..f7ce047 100644 --- a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html +++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -125,8 +125,7 @@ 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 </p> - <pre class="highlight" language="c" linenumbering="unnumbered"> - <code>#\ + <pre class="highlight" language="c" linenumbering="unnumbered"><code>#\ i\ n\ c\ @@ -199,8 +198,7 @@ 10 ); - /* あとは同じように普通のプログラムを変形するだけなので省略 */</code> - </pre> + /* あとは同じように普通のプログラムを変形するだけなので省略 */</code></pre> <p> バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 @@ -260,12 +258,10 @@ また、2文字だと文字列がまともに書けないのも辛い。<code>''</code>だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$a + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$a =' a' -;;</code> - </pre> +;;</code></pre> <p> とすると<code>$a</code>は<code>"\na"</code>になるのだが、余計な改行が入ってしまう。 @@ -284,13 +280,11 @@ a' まずは普通に書くとしよう。 </p> - <pre class="monospaced highlight"> - <code><?php + <pre class="monospaced highlight"><code><?php for ($i = 1; $i < 100; $i++) { echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; - }</code> - </pre> + }</code></pre> <p> 素直に書いた fizzbuzz とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 @@ -303,16 +297,14 @@ a' <code>for</code>は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code>系の関数を使って、適当に置き換えるとしよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $s = range(1, 100); array_walk( $s, fn($i) => printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), - );</code> - </pre> + );</code></pre> <p> <code>array_walk</code>や<code>range</code>、<code>printf</code>といった<code>for</code>よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、<code>echo</code>は文 (statement) であり式 (expression) ではないので、式である<code>printf</code>に置き換えた。 @@ -325,8 +317,7 @@ a' <code>range</code>、<code>array_walk</code>、<code>printf</code>は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $r = 'range'; $w = 'array_walk'; @@ -337,8 +328,7 @@ a' $s, fn($i) => $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), - );</code> - </pre> + );</code></pre> <p> これで関数を呼び出している所は短くなった。では、<code>$r</code>や<code>$w</code>や<code>$p</code>、また<code>'Fizz'</code>や<code>'Buzz'</code>はどうやって 1行2文字に収めるのか。次のテクニックへ移ろう。 @@ -365,21 +355,18 @@ a' というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、<code>Fizz</code>という文字列が欲しければ、次のようにする。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$f + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$f =F .i .z .z -;;</code> - </pre> +;;</code></pre> <p> こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code>演算子を使って抑制してやるとよい。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$f + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$f =@ F. @i @@ -387,8 +374,7 @@ F. @z .# @z -;;</code> - </pre> +;;</code></pre> <p> むしろ、このことがわかっていたからこそ PHP 8.x での動作を要件に課したところがある。 @@ -405,8 +391,7 @@ F. ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$a = "12345"; + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$a = "12345"; $b = "world"; // $a ^ $b は次のコードと同じ @@ -416,26 +401,22 @@ $result .= $a[$i] ^ $b[$i]; } echo $result; -// => F]AXQ</code> - </pre> +// => F]AXQ</code></pre> <p> これを踏まえ、次のコードを見てみよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$x = "x\nOm\n"; + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$x = "x\nOm\n"; $y = "\nk!\no"; $r = $x ^ $y; -echo "$r\n";</code> - </pre> +echo "$r\n";</code></pre> <p> 実行すると、<code>range</code>が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$x + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$x ='x Om '; @@ -446,15 +427,13 @@ o' ; $r = $x ^ $y; -echo "$r\n";</code> - </pre> +echo "$r\n";</code></pre> <p> さらに<code>#</code>を使って適当に調整すると、次のようになる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$x + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$x =# 'x Om @@ -471,8 +450,7 @@ $x $y ;# -echo "$r\n";</code> - </pre> +echo "$r\n";</code></pre> <p> 1行あたり2文字で、<code>range</code>という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 @@ -490,8 +468,7 @@ echo "$r\n";</code> 完成したものがこちら。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $x =# @@ -639,8 +616,7 @@ echo "$r\n";</code> )# .' ') - );</code> - </pre> + );</code></pre> </section> <section id="section--_感想など"> @@ -660,8 +636,7 @@ echo "$r\n";</code> PHP では、バッククォートを使ってシェルを呼び出せる。これは<code>shell_exec</code>関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php printf(` e\ @@ -672,8 +647,7 @@ echo "$r\n";</code> 1\ 2\ 3\ - `);</code> - </pre> + `);</code></pre> <p> なお、ここでは簡単のため出力に<code>printf</code>をそのまま使っているが、実際には<code>printf</code>という文字列を合成して可変関数で呼び出す。 @@ -701,8 +675,7 @@ echo "$r\n";</code> もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $c = 'chr'; @@ -730,33 +703,28 @@ ${ 1\ 2\ 3\ -`);</code> - </pre> +`);</code></pre> <p> 先程と同じく、<code>chr</code>や<code>printf</code>を生成する部分は長くなるので省いた。 </p> - <pre class="monospaced highlight"> - <code>${ + <pre class="monospaced highlight"><code>${ '_ -'}</code> - </pre> +'}</code></pre> <p> は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。 </p> - <pre class="monospaced highlight"> - <code>e\ + <pre class="monospaced highlight"><code>e\ c\ h\ o\ \ 1\ 2\ -3\</code> - </pre> +3\</code></pre> <p> これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう (試してないけど)。 @@ -770,11 +738,9 @@ o\ ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 </p> - <pre class="monospaced highlight"> - <code>${ + <pre class="monospaced highlight"><code>${ '_ -'}</code> - </pre> +'}</code></pre> <p> 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 diff --git a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html index a2bf44c..db0e7b6 100644 --- a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html +++ b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html @@ -68,8 +68,7 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php $π = $argv[1] ?? null; if ($π === null) { @@ -89,8 +88,7 @@ if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { echo "Token: {$t}\n"; } else { echo "Failed.\n"; -}</code> - </pre> +}</code></pre> </section> <section id="section--_トークン入手方法"> @@ -99,19 +97,15 @@ echo "Failed.\n"; ソースを見るとわかるとおり、<code>$argv[1]</code>を参照している。それを<code>$π</code>なる変数に代入しているので、円周率を渡してみる。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ php Q.php 3.14 - Failed.</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.14 + Failed.</code></pre> <p> 失敗してしまった。精度を上げてみる。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ php Q.php 3.1415 -Failed.</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.1415 +Failed.</code></pre> <p> だめだった。これを成功するまで繰り返す。 @@ -121,10 +115,8 @@ Failed.</code> 最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ php Q.php 3.1415926535897932 -Token: #YO</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ php Q.php 3.1415926535897932 +Token: #YO</code></pre> <p> めでたくトークン「#YO」が手に入った。 @@ -137,24 +129,20 @@ Token: #YO</code> 短いので頭から追っていく。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$π = $argv[1] ?? null; + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$π = $argv[1] ?? null; if ($π === null) { exit('No input.'); } $π = trim($π); if (!is_numeric($π)) { exit('Invalid input.'); - }</code> - </pre> + }</code></pre> <p> 入力のバリデーション部分。数値のみ受け付ける。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$s = implode(array_map(chr(...), str_split($π, 2)));</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$s = implode(array_map(chr(...), str_split($π, 2)));</code></pre> <p> <code>$π</code>を 2 文字ごとに区切り (<code>str_split</code>)、数値を ASCII コードと見做して文字に変換 (<code>chr</code>) して結合 (<code>implode</code>) している。 @@ -164,17 +152,13 @@ Token: #YO</code> 例えば、<code>$π</code>が<code>'656667'</code>だったとすると、<code>65</code>、<code>66</code>、<code>67</code>に対応した<code>'A'</code>、<code>'B'</code>、<code>'C'</code>へと変換され、<code>'ABC'</code>になる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$π = '656667'; + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$π = '656667'; $s = implode(array_map(chr(...), str_split($π, 2))); echo $s; -// => ABC</code> - </pre> +// => ABC</code></pre> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>preg_match('/(\x23.+?) /', $s, $m); -$t = $m[1] ?? '';</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>preg_match('/(\x23.+?) /', $s, $m); +$t = $m[1] ?? '';</code></pre> <p> 正規表現でマッチングしている。<code>\x23</code>は<code>#</code>と同じであることに留意すると、この正規表現は「<code>#</code>から始まる 2 以上の長さ (含<code>#</code>) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。 @@ -184,13 +168,11 @@ $t = $m[1] ?? '';</code> なお、<code>#</code>を直接書いていないのは、<code>/#.+?) /</code>と書くと、<code>#.+?)</code>という意図せぬトークンが登録されてしまうからである。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { + <pre class="highlight" language="php" linenumbering="unnumbered"><code>if (md5($t) === '056e831a4146bf123e8ea16613303d2e') { echo "Token: {$t}\n"; } else { echo "Failed.\n"; -}</code> - </pre> +}</code></pre> <p> 最後にトークンのハッシュ値を見て、想定解かどうかを確認する。 diff --git a/public/posts/2022-10-28/setup-server-for-this-site/index.html b/public/posts/2022-10-28/setup-server-for-this-site/index.html index 6e002c3..71c6e44 100644 --- a/public/posts/2022-10-28/setup-server-for-this-site/index.html +++ b/public/posts/2022-10-28/setup-server-for-this-site/index.html @@ -73,10 +73,8 @@ ローカルマシンで鍵を生成する。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key - $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key + $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key</code></pre> <p> <code>teika.key</code>はローカルからサーバへの接続用、<code>github2teika.key</code>は、GitHub Actions からサーバへのデプロイ用。 @@ -89,13 +87,11 @@ <code>.ssh/config</code>に設定しておく。 </p> - <pre class="highlight" language="ssh_config" linenumbering="unnumbered"> - <code>Host teika + <pre class="highlight" language="ssh_config" linenumbering="unnumbered"><code>Host teika HostName ********** User ********** Port ********** - IdentityFile ~/.ssh/teika.key</code> - </pre> + IdentityFile ~/.ssh/teika.key</code></pre> </section> </section> @@ -114,28 +110,22 @@ 管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。<code>sudo</code>グループに追加して<code>sudo</code>できるようにし、<code>su</code>で切り替え。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo adduser ********** + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo adduser ********** $ sudo adduser ********** sudo $ su ********** - $ cd</code> - </pre> + $ cd</code></pre> </section> <section id="section--_ホスト名を変える"> <h3><a href="#section--_ホスト名を変える">ホスト名を変える</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo hostname teika</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo hostname teika</code></pre> </section> <section id="section--_公開鍵を置く"> <h3><a href="#section--_公開鍵を置く">公開鍵を置く</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ mkdir ~/.ssh + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ mkdir ~/.ssh $ chmod 700 ~/.ssh - $ vi ~/.ssh/authorized_keys</code> - </pre> + $ vi ~/.ssh/authorized_keys</code></pre> <p> <code>authorized_keys</code>には、ローカルで生成した<code>~/.ssh/teika.key.pub</code>と<code>~/.ssh/github2teika.key.pub</code>の内容をコピーする。 @@ -148,10 +138,8 @@ SSH の設定を変更し、少しでも安全にしておく。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak - $ sudo vi /etc/ssh/sshd_config</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak + $ sudo vi /etc/ssh/sshd_config</code></pre> <ul> <li> @@ -177,10 +165,8 @@ そして設定を反映。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo systemctl restart sshd -$ sudo systemctl status sshd</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo systemctl restart sshd +$ sudo systemctl status sshd</code></pre> </section> <section id="section--_ssh_で接続確認"> @@ -189,9 +175,7 @@ $ sudo systemctl status sshd</code> 今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ ssh teika</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh teika</code></pre> </section> <section id="section--_ポートの遮断"> @@ -200,13 +184,11 @@ $ sudo systemctl status sshd</code> デフォルトの 22 番を閉じ、設定したポートだけ空ける。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo ufw deny ssh + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo ufw deny ssh $ sudo ufw allow ******* $ sudo ufw enable $ sudo ufw reload - $ sudo ufw status</code> - </pre> + $ sudo ufw status</code></pre> <p> ここでもう一度 SSH の接続確認を挟む。 @@ -219,48 +201,38 @@ $ sudo systemctl status sshd</code> GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key -$ cat ~/.ssh/github.key.pub</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key +$ cat ~/.ssh/github.key.pub</code></pre> <p> <a href="https://github.com/settings/ssh">GitHub の設定画面</a>から、この公開鍵を追加する。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ vi ~/.ssh/config</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ vi ~/.ssh/config</code></pre> <p> 設定はこう。 </p> - <pre class="highlight" language="ssh_config" linenumbering="unnumbered"> - <code>Host github.com + <pre class="highlight" language="ssh_config" linenumbering="unnumbered"><code>Host github.com HostName github.com User git -IdentityFile ~/.ssh/github.key</code> - </pre> +IdentityFile ~/.ssh/github.key</code></pre> <p> 最後に接続できるか確認しておく。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>ssh -T github.com</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>ssh -T github.com</code></pre> </section> <section id="section--_パッケージの更新"> <h3><a href="#section--_パッケージの更新">パッケージの更新</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo apt update + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo apt update $ sudo apt upgrade $ sudo apt update $ sudo apt upgrade - $ sudo apt autoremove</code> - </pre> + $ sudo apt autoremove</code></pre> </section> </section> @@ -275,16 +247,12 @@ IdentityFile ~/.ssh/github.key</code> <section id="section--_使うソフトウェアのインストール"> <h3><a href="#section--_使うソフトウェアのインストール">使うソフトウェアのインストール</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo apt install docker docker-compose git make</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo apt install docker docker-compose git make</code></pre> </section> <section id="section--_メインユーザが_docker_を使えるように"> <h3><a href="#section--_メインユーザが_docker_を使えるように">メインユーザが Docker を使えるように</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>sudo adduser ********** docker</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>sudo adduser ********** docker</code></pre> </section> <section id="section--_httphttps_を通す"> @@ -293,37 +261,29 @@ IdentityFile ~/.ssh/github.key</code> 80 番と 443 番を空ける。 </p> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ sudo ufw allow 80/tcp + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ sudo ufw allow 80/tcp $ sudo ufw allow 443/tcp $ sudo ufw reload - $ sudo ufw status</code> - </pre> + $ sudo ufw status</code></pre> </section> <section id="section--_リポジトリのクローン"> <h3><a href="#section--_リポジトリのクローン">リポジトリのクローン</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ cd + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ cd $ git clone git@github.com:nsfisis/nsfisis.dev.git $ cd nsfisis.dev - $ git submodule update --init</code> - </pre> + $ git submodule update --init</code></pre> </section> <section id="section--_certbot_で証明書取得"> <h3><a href="#section--_certbot_で証明書取得">certbot で証明書取得</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ docker-compose up -d acme-challenge - $ make setup</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ docker-compose up -d acme-challenge + $ make setup</code></pre> </section> <section id="section--_サーバを稼動させる"> <h3><a href="#section--_サーバを稼動させる">サーバを稼動させる</a></h3> - <pre class="highlight" language="shell-session" linenumbering="unnumbered"> - <code>$ make serve</code> - </pre> + <pre class="highlight" language="shell-session" linenumbering="unnumbered"><code>$ make serve</code></pre> </section> </section> diff --git a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html index 7aa97a9..808f1b4 100644 --- a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html +++ b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html @@ -72,8 +72,7 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> @@ -82,8 +81,7 @@ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code> - </pre> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> <p> "And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。 @@ -96,8 +94,7 @@ 実行してみると、次のような出力が得られる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code># + <pre class="highlight" language="php" linenumbering="unnumbered"><code># <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> @@ -106,15 +103,13 @@ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> - <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code> - </pre> + <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> <p> 1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code># + <pre class="highlight" language="php" linenumbering="unnumbered"><code># W <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> @@ -123,15 +118,13 @@ W <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?> -<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code> - </pre> +<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> <p> 今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code># + <pre class="highlight" language="php" linenumbering="unnumbered"><code># W E L @@ -140,8 +133,7 @@ V E P H -P</code> - </pre> +P</code></pre> <p> トークン「#WELOVEPHP」が手に入った。 @@ -158,9 +150,7 @@ P</code> Vim で開くと次のようになる (1 行目を抜粋)。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?></code></pre> <p> <code><200b></code>と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。 @@ -185,17 +175,13 @@ P</code> 続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて<code><200b></code>と記載する。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>fn($s)=>chr(strlen($s)/3)</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>fn($s)=>chr(strlen($s)/3)</code></pre> <p> PHP の<code>strlen()</code>は文字列のバイト数を返す。1 行目の<code>$s</code>は以下の内容となっており、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>$s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code>$s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'</code></pre> <p> このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは<code>#</code>の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。 diff --git a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html index 3100b8e..81d673f 100644 --- a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html +++ b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html @@ -82,8 +82,7 @@ 注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php try { f(g() / __LINE__); } catch (Throwable $e) { @@ -194,8 +193,7 @@ function g() { return __LINE__; - }</code> - </pre> + }</code></pre> <p> "Catchline" と名付けた作品。実行するとトークン<code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code>が得られる。 @@ -239,8 +237,7 @@ このうち 1つ目のケースは、<code>finally</code>節の中でエラーを投げると PHP 処理系が勝手に<code>$previous</code>を設定してくれる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php try { try { @@ -253,8 +250,7 @@ // => Error 2 echo $e->getPrevious()->getMessage() . PHP_EOL; // => Error 1 - }</code> - </pre> + }</code></pre> <p> この知識を元に、トークンの出力部を解析してみる。 @@ -267,8 +263,7 @@ 出力部をコメントや改行を追加して再掲する: </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php try { f(g() / __LINE__); } catch (Throwable $e) { @@ -276,8 +271,7 @@ printf('%c', $e->getLine() + 23); } echo "\n"; - }</code> - </pre> + }</code></pre> <p> 出力をおこなう<code>catch</code>節を見てみると、<code>Throwable::getPrevious()</code>を呼び出してエラーチェインを辿り、<code>Throwable::getLine()</code>でエラーが発生した行数を取得している。その行数に<code>23</code>なるマジックナンバーを足し、フォーマット指定子<code>%c</code>で出力している。 @@ -287,9 +281,7 @@ フォーマット指定子<code>%c</code>は、整数を ASCII コード<span></span>と見做して印字する。トークン<code>#base64_decode('SGVsbG8sIFdvcmxkIQ==')</code>の<code>b</code>であれば、ASCII コード<code>98</code>なので、75 行目で発生したエラー、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code> 1, 20 => 0 / 0,</code> - </pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code> 1, 20 => 0 / 0,</code></pre> <p> によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。 @@ -306,8 +298,7 @@ <code>f()</code>の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意): </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>function f(int $i) { + <pre class="highlight" language="php" linenumbering="unnumbered"><code>function f(int $i) { if ($i < 0) f(); try { match ($i) { @@ -326,24 +317,19 @@ } finally { f($i - 1); } - }</code> - </pre> + }</code></pre> <p> 前述のように、<code>finally</code>節でエラーを投げると PHP 処理系が<code>$previous</code>を設定する。ここでは、エラーを繋げるために<code>f()</code>を再帰呼び出ししている。最初に<code>f()</code>を呼び出している箇所を確認すると、 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php try { - f(g() / __LINE__); // 3 行目</code> - </pre> + f(g() / __LINE__); // 3 行目</code></pre> - <pre class="highlight" language="php" linenumbering="unnumbered"> - <code>function g() { + <pre class="highlight" language="php" linenumbering="unnumbered"><code>function g() { return __LINE__; // 111 行目 - }</code> - </pre> + }</code></pre> <p> <code>f()</code>には<code>111 / 3</code>で<code>37</code>が渡されることがわかる。そこから 1 ずつ減らして再帰呼び出ししていき、0 より小さくなったら<code>f()</code>を引数なしで呼び出す。引数の数が足りないと呼び出しに失敗するので、再帰はここで止まる。 |
