aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/posts/2022-11-19
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/2022-11-19')
-rw-r--r--content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml52
1 files changed, 33 insertions, 19 deletions
diff --git a/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml b/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml
index bc93868..f1df049 100644
--- a/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml
+++ b/content/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2.xml
@@ -28,7 +28,8 @@
<section xml:id="_問題">
<title>問題</title>
<simpara>注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。</simpara>
- <programlisting language="php" linenumbering="unnumbered">&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
+ <programlisting language="php" linenumbering="unnumbered">
+ &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
@@ -37,13 +38,15 @@
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
- &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;</programlisting>
+ &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
+ </programlisting>
<simpara>"And Then There Were None" (そして誰もいなくなった) と名付けた作品。変則 quine (自分自身と同じソースコードを出力するプログラム) になっている。</simpara>
</section>
<section xml:id="_トークン入手方法">
<title>トークン入手方法</title>
<simpara>実行してみると、次のような出力が得られる。</simpara>
- <programlisting language="php" linenumbering="unnumbered">#
+ <programlisting language="php" linenumbering="unnumbered">
+ #
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
@@ -52,9 +55,11 @@
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
- &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;</programlisting>
+ &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
+ </programlisting>
<simpara>1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。</simpara>
-<programlisting language="php" linenumbering="unnumbered">#
+<programlisting language="php" linenumbering="unnumbered">
+ #
W
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
@@ -63,34 +68,43 @@ W
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
-&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;</programlisting>
+ &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s='​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"​"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
+</programlisting>
<simpara>今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。</simpara>
-<programlisting language="php" linenumbering="unnumbered">#
-W
-E
-L
-O
-V
-E
-P
-H
-P</programlisting>
+<programlisting language="php" linenumbering="unnumbered">
+ #
+ W
+ E
+ L
+ O
+ V
+ E
+ P
+ H
+ P
+</programlisting>
<simpara>トークン「#WELOVEPHP」が手に入った。</simpara>
</section>
<section xml:id="_解説">
<title>解説</title>
<simpara>一見すると同じ行が 10 行並んでいるだけなのにも関わらず、なぜそれぞれの行で出力が変わるのか。ソースコードをコピーして、適当なエディタに貼り付けるとわかりやすい。</simpara>
<simpara>Vim で開くと次のようになる (1 行目を抜粋)。</simpara>
- <programlisting language="php" linenumbering="unnumbered">&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"&lt;200b&gt;"):fn($s)=&gt;chr(strlen($s)/3))($s='&lt;200b&gt;&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"&lt;200b&gt;"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;</programlisting>
+ <programlisting language="php" linenumbering="unnumbered">
+ &lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"&lt;200b&gt;"):fn($s)=&gt;chr(strlen($s)/3))($s='&lt;200b&gt;&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"&lt;200b&gt;"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;')."\n","\x27$s\x27");?&gt;
+ </programlisting>
<simpara><literal>&lt;200b&gt;</literal> と表示されているのは、Unicode の U+200b で、ゼロ幅スペースである。</simpara>
<note>
<simpara>エディタによっては、ゼロ幅スペースが見えないことがある。VSCode ではブラウザと同様に不可視だった。</simpara>
</note>
<simpara>文字列リテラルの中にゼロ幅スペースを仕込むことで、見た目を変えずに情報をエンコードすることが可能となる。</simpara>
<simpara>続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて <literal>&lt;200b&gt;</literal> と記載する。</simpara>
- <programlisting language="php" linenumbering="unnumbered">fn($s)=&gt;chr(strlen($s)/3)</programlisting>
+ <programlisting language="php" linenumbering="unnumbered">
+ fn($s)=&gt;chr(strlen($s)/3)
+ </programlisting>
<simpara>PHP の <literal>strlen()</literal> は文字列のバイト数を返す。1 行目の <literal>$s</literal> は以下の内容となっており、</simpara>
- <programlisting language="php" linenumbering="unnumbered">$s='&lt;200b&gt;&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"&lt;200b&gt;"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;'</programlisting>
+ <programlisting language="php" linenumbering="unnumbered">
+ $s='&lt;200b&gt;&lt;?php printf((isset($s)?fn($s)=&gt;trim($s,"&lt;200b&gt;"):fn($s)=&gt;chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?&gt;'
+ </programlisting>
<simpara>このソースコードは UTF-8 で書かれているので、105 バイトになる。それを 3 で割ると 35 となり、これは <literal>#</literal> の ASCII コードと一致する。他の行も、同様にしてゼロ幅スペースを詰めることで文字列長を調整し、トークンをエンコードしている。</simpara>
<simpara>デコード部以外の部分は、quine のための記述である。</simpara>
</section>