[PHP] 可読性0の短めなbase64エンコード・デコード関数

:::note alert
いろいろ改善した結果、ほぼ全部関数の中身が変わってしまったので、新しい記事に記入しました。
入力形式は同じになります。

また、この記事に乗っているコードは使わないでください。2024/09/07以降に発生した問題については、責任を負いません。
:::

https://qiita.com/UziDeer/items/ced0dadbc741b6bb0d0f

:::note info
この記事は横幅が960px以上(PCなど)のデバイスで見ることをお勧めします。
(表を見る際にスマホだと見づらいです)
:::

<details><summary>修正内容について、改訂版が上記にありますので省略します。</summary>

:::note warn
重要な修正をしました。
$b64Arrの宣言時、演算子"+"を使っていましたが、マージするときに数値添字配列であっても上書きされてしまうことがわかりました。
array_merge()を使用してください。
(参考: https://blog.umigame.tech/post/53/)
:::
</details>

## あいさつ
こんにちは、 [codebydeer.com](https://codebydeer.com) の UziDeer です。
今回はphpを2進にしたり+/=を取り除いたりの関数を、できるだけ短い(?)コードで書きました。
作った理由は、phpのbase64関連の関数があんまり充実していなく、軽く調べてみても冗長なものしか無かったということに加え、自分のコードの内容理解を深めようと思ったからです。
短く書こうと頑張ったら可読性が死にました(笑)

では見ていきましょう。
<br>
フォローしてくれたらうれしいな
↓

https://x.com/codebydeer

## 書いたコード
<details><summary>phpのbase64関連関数たち => 改訂版に移動しました。</summary>

```diff_php
//修正しました
- $b64Arr = range("A", "Z") + range("a", "z") + range("0", "9") + ["+", "/"];
+ $b64Arr = array_merge(range("A", "Z"), range("a", "z"), range("0", "9"), ["+", "/"]);
//base64の64進の数字になる[A-Za-z0-9+/]の文字の配列を用意

function b64safe(string $b64, bool $dec = false, array $rep = [["+", "/", "="], [".", "_", "-"]]):string {
    return str_replace($rep[(int) $dec], $rep[(int) !$dec], $b64);
}


function padLen(int $abs, int $len):int {
    return ($len - ($abs + $len - 1) % $len) - 1;
}

function bin2b64(string $bin):string {
    global $b64Arr;
    $bin .= str_pad("", padLen(strlen($bin), 6), "0");
    return implode("", array_map(fn($v) => $b64Arr[base_convert($v, 2, 10)], str_split($bin, 6))).str_repeat("=", padLen(strlen($bin) / 6, 4));
}

function b642bin(string $b64):string {
    global $b64Arr;
    $b64 = str_replace("=", "", $b64);
    return implode("", array_map(fn($v) => str_pad(base_convert(array_search($v, $b64Arr, true), 10, 2), 6, "0", 0), str_split($b64)));
}
```
</details>

https://qiita.com/UziDeer/items/ced0dadbc741b6bb0d0f

<table>
  <thead>
    <tr>
      <th>関数</th> <th>引数</th> <th colspan="2">引数の説明</th> <th colspan="2">返り値</th>
    </tr>
  </thead>
  <tr>
    <td rowspan="4">b64safe()</td> <td>$b64</td> <td colspan="2">入力するbase64</td> <td rowspan="4">$repのルールによって<br>エンコード/デコードされたbase64</td>
  </tr>
  <tr>
    <td rowspan="2"> $dec </td> <td>false</td> <td>エンコード</td>
  </tr>
  <tr>
    <td>true</td> <td>デコード</td>
  </tr>
  <tr>
    <td> $rep </td> <td colspan="2">変換ルールの指定</td>
  </tr>
  <tr>
    <td rowspan="2">padLen()</td> <td>$abs</td> <td colspan="2">pad前の文字列の長さ</td> <td rowspan="2">必要なpadの長さ</td>
  </tr>
  <tr>
    <td> $len </td> <td colspan="2">pad後の文字列の長さを<br>何の倍数にするか</td>
  </tr>
  <tr>
    <td>bin2b64()</td> <td>$bin</td> <td colspan="2">入力するbinary_string</td> <td>$binからbase64へ変換した文字列</td>
  </tr>
  <tr>
    <td>bin2b64()</td> <td>$b64</td> <td colspan="2">入力するbase64</td> <td>$b64からbinaryへ変換した文字列</td>
  </tr>
</table>

<style>
    table: {
        min-width: 690px;
    }
</style>

## こだわりポイント

### ```b64safe()```で、配列のアクセスにboolを転用する

記述量・計算量節約のために、```bool```をそのまま```int```にして、うまく一行程度で表せられるようにした。

### ```padLen()```の剰余計算(```%```)を1回で済ませたところ

本来は```($len - $abs % $len) % $len```としたかったところを計算量節約で```($len - ($abs - 1) % $len) - 1```に。
そして、phpでは```負の数 % 数```の結果が負になることがあるため、せめて0の時だけでもカバーしようとなり、```($len - ($abs + $len - 1) % $len) - 1```に。

### ```bin2b64()```と```b642bin()```を、配列操作で記述量を減らす

phpの標準関数である```array_split()```や```array_map()```などをうまく使い、なるべく一行にたくさんの処理ができるように詰めた。

## さいごに

いやはや、phpは変な癖が多すぎて困っちゃいますね(;^_^
まぁ標準の関数はとっても使いやすいので、書きなれてくると「意外と便利だな」という感じもします。

余談ですが、これらの関数を書くよりこの記事を書く方がかなり時間かかっちゃいました笑笑
記事を書く練習もしていきたいものですねー

それでは！