From f7ae224f3e2530bb4b05166b6013f8a42432086e Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 20 Mar 2023 22:03:50 +0900 Subject: feat(nuldoc): rename simpara to para See also: https://tdg.docbook.org/tdg/sdocbook/5.1/para.html --- .../posts/2022-04-09/phperkaigi-2022-tokens.xml | 204 ++++++++++----------- 1 file changed, 102 insertions(+), 102 deletions(-) (limited to 'content/posts/2022-04-09/phperkaigi-2022-tokens.xml') diff --git a/content/posts/2022-04-09/phperkaigi-2022-tokens.xml b/content/posts/2022-04-09/phperkaigi-2022-tokens.xml index 352eba0..898d7ea 100644 --- a/content/posts/2022-04-09/phperkaigi-2022-tokens.xml +++ b/content/posts/2022-04-09/phperkaigi-2022-tokens.xml @@ -23,21 +23,21 @@
はじめに - + 本日開始された PHPerKaigi 2022 の PHPer チャレンジにおいて、弊社 デジタルサーカス株式会社 の問題を 3問作成した。この記事では、これらの問題の解説をおこなう。 - - + + リポジトリはこちら: https://github.com/nsfisis/PHPerKaigi2022-tokens - +
第1問 brainf_ck.php - + ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 - + - + この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 - +
解説
絵文字 - + まず目につくのは大量の絵文字だろう。 PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。 - +
プログラム全体 - + Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。 - - + + https://ja.wikipedia.org/wiki/Brainfuck - - + + なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 - + - + 実行結果はこちら: https://ideone.com/22VWmb - - + + それぞれの絵文字で表された関数が、各命令に対応している。 - + $👉: > $👈: < @@ -177,51 +177,51 @@ $🤡: [ $🎪: ] - + , (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。 - - + + なお、$🐘 はいわゆる main 関数であり、プログラムの実行部分である。 - +
絵文字の選択 - + おおよそ意味に合致するよう選んでいるが、$🤡$🎪 は弊社デジタルサーカスにちなんでいる。 また、$🐘 は PHP のマスコットの象に由来する。 - +
strict_types - + declare 文の strict_types に指定できるのは、01 の数値リテラルだが、 0x00b1 のような値も受け付ける。 今回は、PHP 8.1 から追加された、0O または 0o から始まる八進数リテラルを使った。 - +
URL - + ソースコードのライセンスを示したこの部分だが、 - + - + 完全に合法な PHP のコードである。 https: 部分はラベル、// 以降は行コメントになっている。 - +
リテラルなしで数値を生成する - + ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。 - + - + []! を適用すると true が返ってくる。それに + を適用すると、bool から int ヘの型変換が走り、1 が生成される。10 はさらにトリッキーだ。まず 10 を作り、. で文字列として結合する ('10')。これに + を適用すると、string から int への型変換が走り、10 が生まれる (コード量に頓着しないなら、1 を 10 個足し合わせてももちろん 10 が作れる)。 - - + + また、error_reporting に指定しているのは -1 である。 これは、! によって文字列を false にし、+ によって false0 にし、さらにビット反転して -1 にしている。 - +
<literal>if</literal> 文なしで条件分岐 - + 三項演算子ないし match 式を使うことで、if を一切書かずに条件分岐ができる。 また、&& / || も使えることがある。 遅延評価が不要なケースでは、[$t, $f][$cond] のような形で分岐することもできる。 - +
<literal>while</literal>、<literal>for</literal> 文なしでループ - + 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った ($z)。 - - + + 実際のところ、$🤡$🎪$🐘 は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。 - - + + なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。 - +
第2問 riddle.php - + ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 - + - + さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数 N を特定する必要がある。 - - + + ここでは、私の想定解を解説する。 - +
読解 - + まずはソースコードを読んでいく。 - + - + 数値からなる $token があり、各要素をループしている。 - + - + まずは排他的論理和 (xor) を取り、 - + - + 二進数に変換して、 - + - + 0 を空白に、1 を # にし、 - + - + 5文字ごとに区切ったあと、改行で結合している。 - +
ヒント - + 次に、ソースコードに書いてあるヒントを読んでいく。 - + N それ自体は、42 や 8128 といったような特別な意味を持たず、ランダムに決められている $token の各要素は、1文字を表す 1文字は 5x5 のセルからなる 出力されるのは、完全な PHPer トークンである - + ここで、PHPer トークンは必ず # 記号から始まることを思いだすと、 $token の最初の数字 0x14B499C は、変換の結果 # になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。 - +
解く - + ここまでわかれば、あと一歩で解ける。すなわち、0x14B499C# に変換されるような N を見つければよい。 - - + + N は高々 - + - + なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 - + - + この一連の変換に対する逆変換を考えると、次のようになる。 - + - + これを実行すると、N が得られる。 - +
第3問 toquine.php - + ソースコードはこちら。 - + - + コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 - + - + 実際にはもう少しパイプで繋げなければならない。 - +
解説
プログラム全体 - + コメントにもあるとおり、これは quine (風) のプログラムになっている。 Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。 - - + + このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 異なるのはトークンになっている部分のみである。 - +
トークン - + $xs がトークンに対応している。変換のロジックは riddle.php とほぼ同じなので省略する。 - +
状態保持 - + トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、LINE から情報を取得している。 - +
ROT 13 - + Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 これがあまり美しくないので、toquine.php では、ROT 13 変換を使って難読化した。 - - + + それにしてもなぜこんなものが標準ライブラリに……。 - +
おわりに - + 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。 - - + + 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 来年は 5問、より面白い問題を持っていきます。 - - + + 実はもう作りはじめているので、どうか来年もありますように……。 - +
-- cgit v1.2.3-70-g09d2