summaryrefslogtreecommitdiffhomepage
path: root/services/blog/public/posts/2025-01-08/phperkaigi-2023-tokens-q1/index.html
blob: e7cd528244a58c3c0392a197699201e0d500fb01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
<!DOCTYPE html>
<html lang="ja-JP">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="author" content="nsfisis">
    <meta name="copyright" content="&copy; 2025 nsfisis">
    <meta name="description" content="PHPerKaigi 2023 でデジタルサーカス株式会社から出題した問題を解説する。全5問中の第1問。">
    <meta name="keywords" content="カンファレンス,PHP,PHPerKaigi,Piet">
    <meta property="og:type" content="article">
    <meta property="og:title" content="PHPerKaigi 2023 トークン問題解説 (1/5)|REPL: Rest-Eat-Program Loop">
    <meta property="og:description" content="PHPerKaigi 2023 でデジタルサーカス株式会社から出題した問題を解説する。全5問中の第1問。">
    <meta property="og:site_name" content="REPL: Rest-Eat-Program Loop">
    <meta property="og:locale" content="ja_JP">
    <meta name="Hatena::Bookmark" content="nocomment">
    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
    <title>PHPerKaigi 2023 トークン問題解説 (1/5)|REPL: Rest-Eat-Program Loop</title>
    <link rel="stylesheet" href="/style.css?h=f4a12de8fc55ef1668e211e6c6db4ade">
  </head>
  <body class="single">
    <header class="header">
      <div class="site-logo">
        <a href="/">REPL: Rest-Eat-Program Loop</a>
      </div>
      <nav class="nav">
        <ul>
          <li>
            <a href="/about/">About</a>
          </li>
          <li>
            <a href="/posts/">Posts</a>
          </li>
          <li>
            <a href="/slides/">Slides</a>
          </li>
          <li>
            <a href="/tags/">Tags</a>
          </li>
        </ul>
      </nav>
    </header>
    <main class="main">
      <article class="post-single">
        <header class="post-header">
          <h1 class="post-title">PHPerKaigi 2023 トークン問題解説 (1/5)</h1>
          <ul class="post-tags">
            <li class="tag">
              <a href="/tags/conference/">カンファレンス</a>
            </li>
            <li class="tag">
              <a href="/tags/php/">PHP</a>
            </li>
            <li class="tag">
              <a href="/tags/phperkaigi/">PHPerKaigi</a>
            </li>
            <li class="tag">
              <a href="/tags/piet/">Piet</a>
            </li>
          </ul>
        </header>
        <nav class="toc">
          <h2>目次</h2>
          <ul>
            <li>
              <a href="#section--intro">はじめに</a>
            </li>
            <li>
              <a href="#section--quiz">Q1: An Art of Computer Programming</a>
            </li>
            <li>
              <a href="#section--how-to-solve">解き方</a>
            </li>
            <li>
              <a href="#section--commentary">解説</a>
              <ul>
                <li>
                  <a href="#section--commentary--read-as-image">画像として解釈する</a>
                </li>
                <li>
                  <a href="#section--commentary--password">パスワード</a>
                </li>
                <li>
                  <a href="#section--commentary--png-steganography">PNG ステガノグラフィ</a>
                </li>
                <li>
                  <a href="#section--commentary--php-program">実行される PHP プログラム</a>
                </li>
                <li>
                  <a href="#section--commentary--piet-source-code">Piet のソースコード</a>
                </li>
                <li>
                  <a href="#section--commentary--misc">その他小ネタ</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#section--outro">おわりに</a>
            </li>
          </ul>
        </nav>
        <div class="post-content">
          <section id="changelog">
            <h2><a href="#changelog">更新履歴</a></h2>
            <ol>
              <li class="revision">
                <time datetime="2025-01-08">2025-01-08</time>: 公開
              </li>
              <li class="revision">
                <time datetime="2025-01-11">2025-01-11</time>: 読みやすさのため一部の文言を調整
              </li>
            </ol>
          </section>
          <section id="section--intro">
            <h2><a href="#section--intro">はじめに</a></h2>
            <div class="admonition">
              <div class="admonition-label">
                NOTE
              </div>
              <div class="admonition-content">
                <p>
                  これは PHPerKaigi 2023 の記事です。今は 2025 年ですが、PHPerKaigi 2023 の記事です。
                </p>
              </div>
            </div>
            <p>
              2023-03-23 から 2023-03-25 にかけて開催された <a href="https://phperkaigi.jp/2023/" rel="noreferrer" target="_blank">PHPerKaigi 2023</a> では、PHPer チャレンジという企画がおこなわれた。PHPer チャレンジとは、スポンサーのパンフレットやカンファレンス会場などから「#」記号で始まる文字列を集め、景品などを得るという企画である。この文字列は「PHPer トークン」と呼ばれている。弊社 <a href="https://www.dgcircus.com/" rel="noreferrer" target="_blank">デジタルサーカス株式会社</a> からは、トークン問題という形で、PHP に関する問題を解くと PHPer トークンが得られるようになっている問題を出題した。
            </p>
            <p>
              <a href="/posts/2023-04-04/phperkaigi-2023-report/">PHPerKaigi 2023 の参加レポ</a> でも書いたとおり、この年のトークン問題は「昨年の PHPerKaigi 2022 が終わった段階から作り始め、約半年かけて制作」された。PHPerKaigi 当日も <a href="/slides/2023-03-25/phperkaigi-2023-tokens/">PHPer チャレンジ解説セッション</a> という形で解説の機会を頂いたのだが、せっかく時間をかけて作題したので記事の形でも残しておこうと思う。
            </p>
            <p>
              この記事では、全5問ある中の第1問について解説する。他の問題については以下のリンクを参照のこと。
            </p>
            <ol>
              <li>
                <a href="/posts/2025-01-08/phperkaigi-2023-tokens-q1/">第1問 (この記事)</a>
              </li>
              <li>
                第2問 (TODO: 執筆中)
              </li>
              <li>
                第3問 (TODO: 執筆中)
              </li>
              <li>
                第4問 (TODO: 執筆中)
              </li>
              <li>
                第5問 (TODO: 執筆中)
              </li>
            </ol>
            <p>
              それぞれの問題はこちらの GitHub リポジトリ ( <a href="https://github.com/nsfisis/PHPerKaigi2023-tokens" rel="noreferrer" target="_blank">nsfisis/PHPerKaigi2023-tokens</a> ) からも閲覧できる。
            </p>
          </section>
          <section id="section--quiz">
            <h2><a href="#section--quiz">Q1: An Art of Computer Programming</a></h2>
            <p>
              第1問『An Art of Computer Programming』はこちら。
            </p>
            <p>
              <img alt="全体がQRコードになっており、中央には小さな文字で「Password is one of the PHPer tokens.」と書かれている" src="/posts/2025-01-08/phperkaigi-2023-tokens-q1/Q1.png">
            </p>
          </section>
          <section id="section--how-to-solve">
            <h2><a href="#section--how-to-solve">解き方</a></h2>
            <p>
              まずはトークンを得る方法を解説抜きで説明する。次のように実行する。
            </p>
            <div class="codeblock">
              <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ echo "#iwillblog" | php Q1.png >/dev/null</span></span></code></pre>
            </div>
            <p>
              無事に実行できていれば「#ModernPHPisStaticallyTypedLanguage」というトークンが得られる。
            </p>
          </section>
          <section id="section--commentary">
            <h2><a href="#section--commentary">解説</a></h2>
            <section id="section--commentary--read-as-image">
              <h3><a href="#section--commentary--read-as-image">画像として解釈する</a></h3>
              <p>
                まずは素直に画像として見てみよう。全体は QR コードになっている。適当な QR コードリーダで読み込むと、次のようなテキストが表示されるはずだ。
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>Guess password. $ echo "password" | php Q1.png >/dev/null</span></span></code></pre>
              </div>
              <p>
                メッセージは、この画像の実行方法とこの問題でやるべきこと (パスワードの推測) を示している。
              </p>
              <p>
                次に QR コードの中央部に目を向けると、小さな文字で「Password is one of the PHPer tokens.」と書かれているのがわかる。他の PHPer トークンの中から適切な1つを見つけだし、「パスワード」として渡すことで答えとなる PHPer トークンが得られるというわけだ。
              </p>
            </section>
            <section id="section--commentary--password">
              <h3><a href="#section--commentary--password">パスワード</a></h3>
              <p>
                不正なパスワードを使って実行してみると、次のようなエラーメッセージが表示される。
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ echo "foo" | php Q1.png >/dev/null</span></span>
<span class="line"><span>401 Unauthorized</span></span></code></pre>
              </div>
              <p>
                すでに <a href="#section--how-to-solve">「解き方」の節</a> で示したように、パスワードである PHPer トークンは「#iwillblog」である。これを与えて実行すると正解のトークンが得られる。
              </p>
              <p>
                このパスワードの選択にはとある事情がある。今回の問題の作問は前回の開催 (PHPerKaigi 2022) 直後からスタートしており、この時点では PHPerKaigi 2023 で登録される PHPer トークンにどのようなものがあるかはまったくわからない状態であった。作問作業を早期に終わらせるには、次回開催でも確実に使われるであろう定番のトークンを予測して選ぶ必要があったのだ。かくして、私が知る限り毎回登場しているトークンである「#iwillblog」に白羽の矢が立てられた。
              </p>
              <p>
                なお、解いてくださった方の中には、先頭の「#」を入力せずに何度も試してしまい答えが得られずじまいになった方もいらっしゃるようだった。問題を置いていたリポジトリにヒントとしてパスワードのトークンが「i」で始まると書いていたのだが、これが意図せずミスリードになってしまった。これは私のミスである。
              </p>
            </section>
            <section id="section--commentary--png-steganography">
              <h3><a href="#section--commentary--png-steganography">PNG ステガノグラフィ</a></h3>
              <p>
                QR コードも言っているように、このファイルは PNG 画像であるにもかかわらず PHP で実行することができる。なぜこのようなことが可能なのか。
              </p>
              <p>
                PNG 画像のフォーマットは、次のようになっている。
              </p>
              <ol>
                <li>
                  マジックナンバーなど
                </li>
                <li>
                  PNG ヘッダ (<code>IHDR</code> チャンク)
                </li>
                <li>
                  実際の画像データ (<code>IDAT</code> チャンク)
                </li>
                <li>
                  PNG フッタ (<code>IEND</code> チャンク)
                </li>
              </ol>
              <p>
                PNG フッタの後ろにあるデータは、画像ビューアには解釈されず、画像の表示には影響を与えない。したがって、PNG フッタの後ろには任意のデータを埋め込むことができる。
              </p>
              <p>
                さて、PHP には、PHP プログラムの始まりを示すための PHP タグ (<code>&lt;?php</code> または <code>&lt;?</code>) がある。CLI で実行する場合、PHP タグよりも前にあるデータは標準出力へそのまま出力される。
              </p>
              <p>
                この画像ファイルは次のような構造になっていた。
              </p>
              <ol>
                <li>
                  マジックナンバーなど
                </li>
                <li>
                  PNG ヘッダ (<code>IHDR</code> チャンク)
                </li>
                <li>
                  実際の画像データ (<code>IDAT</code> チャンク)
                </li>
                <li>
                  PNG フッタ (<code>IEND</code> チャンク)
                </li>
                <li>
                  <strong>PHP タグ (<code>&lt;?php</code>)</strong>
                </li>
                <li>
                  <strong>通常の PHP ソースコード</strong>
                </li>
              </ol>
              <p>
                PNG ファイルとして読むときは PNG フッタ以降は無視され、PHP スクリプトとして読むときは PHP タグ以前が無視されるという仕掛けである。
              </p>
              <p>
                <code>strings</code> コマンドを使うと、隠されたデータを簡単に閲覧できる。
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>IHDR</span></span>
<span class="line"><span>-HHc</span></span>
<span class="line"><span>&#x3C;PLTE</span></span>
<span class="line"><span>IDATx</span></span>
<span class="line"><span>IEND</span></span>
<span class="line"><span>&#x3C;?php</span></span>
<span class="line"><span>error_reporting(-1);</span></span>
<span class="line"><span>$b = unpack('C*', file_get_contents(__FILE__));</span></span>
<span class="line"><span>$w = $b[20]+2;</span></span>
<span class="line"><span>$h = $b[24]+2;</span></span>
<span class="line"><span>// (以下略)</span></span></code></pre>
              </div>
              <p>
                <code>IHDR</code> や <code>IEND</code> が PNG 画像の一部で、<code>&lt;?php</code> からが実際のプログラムになっている。もちろんこれを PHP プログラムとして動かすと、PHP タグより前にある PNG 画像としてのデータはそのまま標準出力へと出力されてしまう。それを防ぐため、QR コードを読み込んだときの実行方法
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>Guess password. $ echo "password" | php Q1.png >/dev/null</span></span></code></pre>
              </div>
              <p>
                には標準出力を捨てるよう <code>&gt;/dev/null</code> と指定されている。
              </p>
              <p>
                なお、このように PNG 画像などに本来のデータとは異なる別のデータを隠すことを「ステガノグラフィ」( <a href="https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%86%E3%82%AC%E3%83%8E%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%BC" rel="noreferrer" target="_blank">Wikipedia「ステガノグラフィー」</a> ) と呼ぶ。
              </p>
            </section>
            <section id="section--commentary--php-program">
              <h3><a href="#section--commentary--php-program">実行される PHP プログラム</a></h3>
              <p>
                画像の正体がわかったところで、画像に隠されていた PHP プログラムについて見ていこう。先ほどは一部しか記載しなかったので、全体を載せる。なお、ある程度ゴルフしながら書いたので、空白こそ残しているものの可読性は非常に低いことと思う。
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">&#x3C;?</span><span style="color:#005CC5">php</span></span>
<span class="line"><span style="color:#005CC5">error_reporting</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">);</span></span>
<span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> unpack</span><span style="color:#24292E">(</span><span style="color:#032F62">'C*'</span><span style="color:#24292E">, </span><span style="color:#005CC5">file_get_contents</span><span style="color:#24292E">(</span><span style="color:#005CC5">__FILE__</span><span style="color:#24292E">));</span></span>
<span class="line"><span style="color:#24292E">$w </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $b[</span><span style="color:#005CC5">20</span><span style="color:#24292E">]</span><span style="color:#D73A49">+</span><span style="color:#005CC5">2</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$h </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $b[</span><span style="color:#005CC5">24</span><span style="color:#24292E">]</span><span style="color:#D73A49">+</span><span style="color:#005CC5">2</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$cs </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [];</span></span>
<span class="line"><span style="color:#D73A49">for</span><span style="color:#24292E"> ($y </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $y </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> $h; $y</span><span style="color:#D73A49">++</span><span style="color:#24292E">)</span></span>
<span class="line"><span style="color:#D73A49">  for</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $x </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> $w; $x</span><span style="color:#D73A49">++</span><span style="color:#24292E">)</span></span>
<span class="line"><span style="color:#24292E">    $cs[$y</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w </span><span style="color:#D73A49">+</span><span style="color:#24292E"> $x] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> ($x</span><span style="color:#D73A49">*</span><span style="color:#24292E">$y </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> ||</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $w</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#D73A49"> ||</span><span style="color:#24292E"> $y </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $h</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span></span>
<span class="line"><span style="color:#D73A49">                        ?</span><span style="color:#005CC5"> 0</span></span>
<span class="line"><span style="color:#D73A49">                        :</span><span style="color:#24292E"> $b[</span><span style="color:#005CC5">122</span><span style="color:#D73A49">+</span><span style="color:#24292E">($y</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">($w</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">+</span><span style="color:#24292E">$x</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">];</span></span>
<span class="line"><span style="color:#24292E">$i </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> stream_isatty</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDIN</span><span style="color:#24292E">)</span></span>
<span class="line"><span style="color:#D73A49">    ?</span><span style="color:#24292E"> []</span></span>
<span class="line"><span style="color:#D73A49">    :</span><span style="color:#005CC5"> array_map</span><span style="color:#24292E">(</span><span style="color:#005CC5">ord</span><span style="color:#24292E">(</span><span style="color:#D73A49">...</span><span style="color:#24292E">), </span><span style="color:#005CC5">str_split</span><span style="color:#24292E">(</span><span style="color:#005CC5">trim</span><span style="color:#24292E">((</span><span style="color:#D73A49">string</span><span style="color:#24292E">) </span><span style="color:#005CC5">fgets</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDIN</span><span style="color:#24292E">))));</span></span>
<span class="line"><span style="color:#24292E">$m </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [];</span></span>
<span class="line"><span style="color:#24292E">$pc </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$dp </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$cc </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$c0 </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$ns </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">$o </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">while</span><span style="color:#24292E"> (</span><span style="color:#005CC5">true</span><span style="color:#24292E">) {</span></span>
<span class="line"><span style="color:#24292E">  $ns</span><span style="color:#D73A49">++</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">  if</span><span style="color:#24292E"> ($ns </span><span style="color:#D73A49">></span><span style="color:#005CC5"> 1e5</span><span style="color:#24292E">) {</span></span>
<span class="line"><span style="color:#005CC5">    echo</span><span style="color:#032F62"> "infinite loop detected</span><span style="color:#005CC5">\n</span><span style="color:#032F62">"</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">    break</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">  $c1 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $cs[$pc];</span></span>
<span class="line"><span style="color:#24292E">  $y </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#005CC5">6</span><span style="color:#D73A49"> +</span><span style="color:#6F42C1"> intdiv</span><span style="color:#24292E">($c1</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">, </span><span style="color:#005CC5">3</span><span style="color:#24292E">) </span><span style="color:#D73A49">-</span><span style="color:#6F42C1"> intdiv</span><span style="color:#24292E">($c0</span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">, </span><span style="color:#005CC5">3</span><span style="color:#24292E">)) </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 6</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">  $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> $c1</span><span style="color:#D73A49">%</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> -</span><span style="color:#24292E"> $c0</span><span style="color:#D73A49">%</span><span style="color:#005CC5">3</span><span style="color:#24292E">) </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 3</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">  match</span><span style="color:#24292E"> (($c0 </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">*</span><span style="color:#24292E"> ($c1 </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">*</span><span style="color:#24292E"> ($y</span><span style="color:#D73A49">*</span><span style="color:#005CC5">3</span><span style="color:#D73A49"> +</span><span style="color:#24292E"> $x)) {</span></span>
<span class="line"><span style="color:#005CC5">    1</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $b,</span></span>
<span class="line"><span style="color:#005CC5">    2</span><span style="color:#D73A49"> =></span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m),</span></span>
<span class="line"><span style="color:#005CC5">    3</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m) </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m),</span></span>
<span class="line"><span style="color:#005CC5">    4</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($x, $y) => $y </span><span style="color:#D73A49">-</span><span style="color:#24292E"> $x)(</span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m), </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span>
<span class="line"><span style="color:#005CC5">    5</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m) </span><span style="color:#D73A49">*</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m),</span></span>
<span class="line"><span style="color:#005CC5">    8</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($m) </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> ?</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> :</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">,</span></span>
<span class="line"><span style="color:#005CC5">    11</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $cc </span><span style="color:#D73A49">*=</span><span style="color:#005CC5"> pow</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span>
<span class="line"><span style="color:#005CC5">    12</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $m[</span><span style="color:#005CC5">count</span><span style="color:#24292E">($m)</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">],</span></span>
<span class="line"><span style="color:#005CC5">    13</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $m </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (</span><span style="color:#D73A49">fn</span><span style="color:#24292E">($n, $d, $m, $l) => [</span></span>
<span class="line"><span style="color:#D73A49">            ...</span><span style="color:#005CC5">array_slice</span><span style="color:#24292E">($m, </span><span style="color:#005CC5">0</span><span style="color:#24292E">, $l</span><span style="color:#D73A49">-</span><span style="color:#24292E">$d),</span></span>
<span class="line"><span style="color:#D73A49">            ...</span><span style="color:#005CC5">array_reverse</span><span style="color:#24292E">([</span></span>
<span class="line"><span style="color:#D73A49">              ...</span><span style="color:#005CC5">array_reverse</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_slice</span><span style="color:#24292E">($m, $l</span><span style="color:#D73A49">-</span><span style="color:#24292E">$d, $d</span><span style="color:#D73A49">-</span><span style="color:#24292E">$n)),</span></span>
<span class="line"><span style="color:#D73A49">              ...</span><span style="color:#005CC5">array_reverse</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_slice</span><span style="color:#24292E">($m, $l</span><span style="color:#D73A49">-</span><span style="color:#24292E">$n)),</span></span>
<span class="line"><span style="color:#24292E">            ]),</span></span>
<span class="line"><span style="color:#24292E">          ])(</span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m), </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m), $m, </span><span style="color:#005CC5">count</span><span style="color:#24292E">($m)),</span></span>
<span class="line"><span style="color:#005CC5">    15</span><span style="color:#D73A49"> =></span><span style="color:#D73A49"> !</span><span style="color:#005CC5">empty</span><span style="color:#24292E">($i) </span><span style="color:#D73A49">and</span><span style="color:#24292E"> $m[] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_shift</span><span style="color:#24292E">($i),</span></span>
<span class="line"><span style="color:#005CC5">    16</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $o </span><span style="color:#D73A49">.=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%d'</span><span style="color:#24292E">, </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span>
<span class="line"><span style="color:#005CC5">    17</span><span style="color:#D73A49"> =></span><span style="color:#24292E"> $o </span><span style="color:#D73A49">.=</span><span style="color:#005CC5"> sprintf</span><span style="color:#24292E">(</span><span style="color:#032F62">'%c'</span><span style="color:#24292E">, </span><span style="color:#005CC5">array_pop</span><span style="color:#24292E">($m)),</span></span>
<span class="line"><span style="color:#D73A49">    default</span><span style="color:#D73A49"> =></span><span style="color:#032F62"> 'nop'</span><span style="color:#24292E">,</span></span>
<span class="line"><span style="color:#24292E">  };</span></span>
<span class="line"><span style="color:#24292E">  $c0 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $c1;</span></span>
<span class="line"><span style="color:#D73A49">  for</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; $j </span><span style="color:#D73A49">&#x3C;</span><span style="color:#005CC5"> 8</span><span style="color:#24292E">; $j</span><span style="color:#D73A49">++</span><span style="color:#24292E">) {</span></span>
<span class="line"><span style="color:#24292E">    $v </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [];</span></span>
<span class="line"><span style="color:#D73A49">    if</span><span style="color:#24292E"> ($c1 </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) {</span></span>
<span class="line"><span style="color:#24292E">      $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $pc </span><span style="color:#D73A49">%</span><span style="color:#24292E"> $w;</span></span>
<span class="line"><span style="color:#24292E">      $y </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> intdiv</span><span style="color:#24292E">($pc, $w);</span></span>
<span class="line"><span style="color:#24292E">      $e </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [($y</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, ($h</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w</span><span style="color:#D73A49">+</span><span style="color:#24292E">$x, $y</span><span style="color:#D73A49">*</span><span style="color:#24292E">$w, $x][$dp];</span></span>
<span class="line"><span style="color:#24292E">      $z </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $w, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#24292E">$w][$dp];</span></span>
<span class="line"><span style="color:#D73A49">      for</span><span style="color:#24292E"> ($ep </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $pc; $ep </span><span style="color:#D73A49">!==</span><span style="color:#24292E"> $e; $ep </span><span style="color:#D73A49">+=</span><span style="color:#24292E"> $z)</span></span>
<span class="line"><span style="color:#D73A49">        if</span><span style="color:#24292E"> ($cs[$ep] </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">break</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">      $ep </span><span style="color:#D73A49">-=</span><span style="color:#24292E"> $z;</span></span>
<span class="line"><span style="color:#24292E">      $pc </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $ep;</span></span>
<span class="line"><span style="color:#24292E">    } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span>
<span class="line"><span style="color:#24292E">      $q </span><span style="color:#D73A49">=</span><span style="color:#24292E"> [$pc];</span></span>
<span class="line"><span style="color:#24292E">      $ep </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $pc;</span></span>
<span class="line"><span style="color:#D73A49">      while</span><span style="color:#24292E"> (</span><span style="color:#D73A49">!</span><span style="color:#005CC5">empty</span><span style="color:#24292E">($q)) {</span></span>
<span class="line"><span style="color:#24292E">        $qq </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> array_pop</span><span style="color:#24292E">($q);</span></span>
<span class="line"><span style="color:#24292E">        $v[$qq] </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">        foreach</span><span style="color:#24292E"> ([$qq</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $qq</span><span style="color:#D73A49">+</span><span style="color:#24292E">$w, $qq</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $qq</span><span style="color:#D73A49">-</span><span style="color:#24292E">$w] </span><span style="color:#D73A49">as</span><span style="color:#24292E"> $qp) {</span></span>
<span class="line"><span style="color:#D73A49">          if</span><span style="color:#24292E"> ($cs[$qp] </span><span style="color:#D73A49">!==</span><span style="color:#24292E"> $c1) </span><span style="color:#D73A49">continue</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">          if</span><span style="color:#24292E"> (</span><span style="color:#005CC5">isset</span><span style="color:#24292E">($v[$qp])) </span><span style="color:#D73A49">continue</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">          $q[] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $qp;</span></span>
<span class="line"><span style="color:#24292E">          $qx </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $qp </span><span style="color:#D73A49">%</span><span style="color:#24292E"> $w;</span></span>
<span class="line"><span style="color:#24292E">          $qy </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> intdiv</span><span style="color:#24292E">($qp, $w);</span></span>
<span class="line"><span style="color:#24292E">          $x </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $ep </span><span style="color:#D73A49">%</span><span style="color:#24292E"> $w;</span></span>
<span class="line"><span style="color:#24292E">          $y </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> intdiv</span><span style="color:#24292E">($ep, $w);</span></span>
<span class="line"><span style="color:#D73A49">          if</span><span style="color:#24292E"> (</span></span>
<span class="line"><span style="color:#24292E">            ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 0</span><span style="color:#D73A49"> &#x26;&#x26;</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> $qx </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($x </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $qx </span><span style="color:#D73A49">&#x26;&#x26;</span><span style="color:#24292E"> ($y</span><span style="color:#D73A49">&#x3C;=></span><span style="color:#24292E">$qy) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span>
<span class="line"><span style="color:#D73A49">            ||</span><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> &#x26;&#x26;</span><span style="color:#24292E"> ($y </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> $qy </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($y </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $qy </span><span style="color:#D73A49">&#x26;&#x26;</span><span style="color:#24292E"> ($qx</span><span style="color:#D73A49">&#x3C;=></span><span style="color:#24292E">$x) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span>
<span class="line"><span style="color:#D73A49">            ||</span><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> &#x26;&#x26;</span><span style="color:#24292E"> ($qx </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($qx </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $x </span><span style="color:#D73A49">&#x26;&#x26;</span><span style="color:#24292E"> ($qy</span><span style="color:#D73A49">&#x3C;=></span><span style="color:#24292E">$y) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span>
<span class="line"><span style="color:#D73A49">            ||</span><span style="color:#24292E"> ($dp </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 3</span><span style="color:#D73A49"> &#x26;&#x26;</span><span style="color:#24292E"> ($qy </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> $y </span><span style="color:#D73A49">||</span><span style="color:#24292E"> ($qy </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $y </span><span style="color:#D73A49">&#x26;&#x26;</span><span style="color:#24292E"> ($x</span><span style="color:#D73A49">&#x3C;=></span><span style="color:#24292E">$qx) </span><span style="color:#D73A49">===</span><span style="color:#24292E"> $cc)))</span></span>
<span class="line"><span style="color:#24292E">          )</span></span>
<span class="line"><span style="color:#24292E">            $ep </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $qp;</span></span>
<span class="line"><span style="color:#24292E">        }</span></span>
<span class="line"><span style="color:#24292E">      }</span></span>
<span class="line"><span style="color:#24292E">    }</span></span>
<span class="line"><span style="color:#24292E">    $np </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $ep </span><span style="color:#D73A49">+</span><span style="color:#24292E"> [</span><span style="color:#005CC5">1</span><span style="color:#24292E">, $w, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#24292E">$w][$dp];</span></span>
<span class="line"><span style="color:#D73A49">    if</span><span style="color:#24292E"> ($cs[$np] </span><span style="color:#D73A49">!==</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) {</span></span>
<span class="line"><span style="color:#24292E">      $b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> count</span><span style="color:#24292E">(</span><span style="color:#005CC5">array_keys</span><span style="color:#24292E">($v));</span></span>
<span class="line"><span style="color:#24292E">      $pc </span><span style="color:#D73A49">=</span><span style="color:#24292E"> $np;</span></span>
<span class="line"><span style="color:#D73A49">      break</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#24292E">    }</span></span>
<span class="line"><span style="color:#D73A49">    if</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">===</span><span style="color:#005CC5"> 7</span><span style="color:#24292E">) </span><span style="color:#D73A49">break</span><span style="color:#005CC5"> 2</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#D73A49">    if</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> ===</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">) $cc </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> -</span><span style="color:#24292E">$cc;</span></span>
<span class="line"><span style="color:#D73A49">    if</span><span style="color:#24292E"> ($j </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 2</span><span style="color:#D73A49"> ===</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) $dp </span><span style="color:#D73A49">=</span><span style="color:#24292E"> ($dp</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">%</span><span style="color:#005CC5"> 4</span><span style="color:#24292E">;</span></span>
<span class="line"><span style="color:#6A737D">// The original Piet image is wrong: it outputs 403 error for invalid passwords.</span></span>
<span class="line"><span style="color:#6A737D">// Failure of authentication should be notified by 401, not 403.</span></span>
<span class="line"><span style="color:#6A737D">// I noticed that one month before PHPerKaigi, but I could not read or write (paint)</span></span>
<span class="line"><span style="color:#6A737D">// Piet any longer at that time.</span></span>
<span class="line"><span style="color:#005CC5">fwrite</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDERR</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">(</span><span style="color:#032F62">'403 Forbidden'</span><span style="color:#24292E">, </span><span style="color:#032F62">'401 Unauthorized'</span><span style="color:#24292E">, $o));</span></span></code></pre>
              </div>
              <p>
                これは一体なんなのか。ずばり、難解プログラミング言語の一つ Piet のインタプリタである。Piet はピエト・モンドリアン (『赤・青・黄のコンポジション』などで知られる抽象画家) の作品にインスピレーションを受けて作られた、画像をソースコードとするプログラミング言語である。インタプリタは画像の各ピクセルの上を進みながら、色等に応じて特定の処理をおこなっていく。ここでは詳しい言語仕様については解説しないので、気になる方は <a href="https://ja.wikipedia.org/wiki/Piet" rel="noreferrer" target="_blank">Wikipedia の記事「Piet」</a> などを参照してほしい。
              </p>
              <p>
                プログラムの冒頭にあるこの箇所
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#24292E">$b </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> unpack</span><span style="color:#24292E">(</span><span style="color:#032F62">'C*'</span><span style="color:#24292E">, </span><span style="color:#005CC5">file_get_contents</span><span style="color:#24292E">(</span><span style="color:#005CC5">__FILE__</span><span style="color:#24292E">));</span></span></code></pre>
              </div>
              <p>
                で <code>__FILE__</code> つまりこの画像ファイルを読み込んでいる。先ほど Piet は画像をソースコードにしていると説明した。そう、今回の問題の画像ファイル <code>Q1.png</code> は、PHP 製 Piet インタプリタであると同時に、Piet のソースコード画像でもあるのだ。QR コード中央のカラフルな部分が Piet の命令になっている。
              </p>
            </section>
            <section id="section--commentary--piet-source-code">
              <h3><a href="#section--commentary--piet-source-code">Piet のソースコード</a></h3>
              <p>
                さて、Piet でどのようなコードが書かれて (いや、描かれて) いるのかを解説したいところだが、今の私にはできそうにない。というのも、すでに述べたように Piet は「難解プログラミング言語」である。およそ人が描いたり読んだりするようには作られていない。性質としては、パズルに近い代物である。
              </p>
              <p>
                というわけで、ここではあらましを説明するだけでご容赦いただきたい。それぞれの部分はおおよそ次のようなことをやっている (再検証・再読解はしていないので大嘘かもしれない)。
              </p>
              <ul>
                <li>
                  左上: 入力受け付け
                  <ul>
                    <li>
                      標準入力から1文字ずつ読み込み、入力がなくなるまでスタックに積む。多分。
                    </li>
                  </ul>
                </li>
                <li>
                  上辺、右辺: パスワードの検証
                  <ul>
                    <li>
                      入力がパスワードと一致するか (= <code>#iwillblog</code> かどうか) を調べる。多分。
                    </li>
                  </ul>
                </li>
                <li>
                  下辺、左辺、上辺の3列目、右辺の3列目、下辺の2列目: トークンの出力
                  <ul>
                    <li>
                      パスワードと一致していればここに飛んでくる。正解のトークンを出力する。多分。
                    </li>
                  </ul>
                </li>
                <li>
                  右辺の2列目、上辺の2列目: 不正解のメッセージ出力
                  <ul>
                    <li>
                      パスワードと一致していなければここに飛んでくる。不正解のときのメッセージを出力する。多分。
                    </li>
                  </ul>
                </li>
              </ul>
              <p>
                ところで、先ほど掲載した Piet のインタプリタのソースコード末尾には次のような箇所がある。
              </p>
              <div class="codeblock">
                <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#6A737D">// The original Piet image is wrong: it outputs 403 error for invalid passwords.</span></span>
<span class="line"><span style="color:#6A737D">// Failure of authentication should be notified by 401, not 403.</span></span>
<span class="line"><span style="color:#6A737D">// I noticed that one month before PHPerKaigi, but I could not read or write (paint)</span></span>
<span class="line"><span style="color:#6A737D">// Piet any longer at that time.</span></span>
<span class="line"><span style="color:#005CC5">fwrite</span><span style="color:#24292E">(</span><span style="color:#005CC5">STDERR</span><span style="color:#24292E">, </span><span style="color:#005CC5">str_replace</span><span style="color:#24292E">(</span><span style="color:#032F62">'403 Forbidden'</span><span style="color:#24292E">, </span><span style="color:#032F62">'401 Unauthorized'</span><span style="color:#24292E">, $o));</span></span></code></pre>
              </div>
              <p>
                コメントにも書かれているが、この Piet のソースコード画像には誤りがあった。本来 HTTP のステータスコードを真似るのなら、認証の失敗には 401 を返さなければならない。しかし、Piet のソースは 403 を返すように書いてしまっていた。そのことに私が気付いたのは PHPerKaigi 2023 が開催されるひと月前で、その時点で私はこの Piet のソースコードを (ちょうどこの記事でそうなっているのと同じように) 読解できなくなっていた。さらに悪いことに、正しいメッセージ「401 Unauthorized」は元の「403 Forbidden」よりも3文字長い。3文字出力が長くなるということは、それだけ Piet で塗るべきピクセルが増えることを意味する。もはや3文字追加で出力するだけの余白はこの画像に残されていなかった (と思う。腕ききの Piet プログラマならできるかもしれないので挑戦してみてほしい)。
              </p>
              <p>
                これを解決するために私が選んだのは、インタプリタを改造し、本来のメッセージとは異なるメッセージを無理やり出力させて帳尻を合わせることだった。そういうわけでこの Piet インタプリタは完全な Piet インタプリタではなく、「403 Forbidden」というテキストを絶対に出力できない。
              </p>
            </section>
            <section id="section--commentary--misc">
              <h3><a href="#section--commentary--misc">その他小ネタ</a></h3>
              <p>
                ここまでで問題の核心部分は説明し終えたので、ここからは残った小ネタを紹介しておく。
              </p>
              <p>
                この問題のタイトル『An Art of Computer Programming』は、ドナルド・クヌースの『The Art of Computer Programming』をパロディしたものである。
              </p>
              <p>
                この問題で得られるトークン「#ModernPHPisStaticallyTypedLanguage」は特に元ネタがあるわけではない。当然のような顔で嘘を主張したかったのでこうなった。
              </p>
            </section>
          </section>
          <section id="section--outro">
            <h2><a href="#section--outro">おわりに</a></h2>
            <p>
              この問題の自己評価はこちら。問題の出題順はおおよそ作成した順になっているのだが、そのせいで難易度高めの問題が1問目に配置されてしまった。これは反省点の一つである。
            </p>
            <ul>
              <li>
                難しさ: ★★★★
              </li>
              <li>
                お気に入り度: ★★
              </li>
              <li>
                鮮やかさ: ★★★★★★★
              </li>
            </ul>
          </section>
        </div>
      </article>
    </main>
    <footer class="footer">
      &copy; 2021 nsfisis
    </footer>
  </body>
</html>