CodeIgniter4は簡単にmime typeから拡張子を取得できる


画像をアップロードしてサムネイルを作成するようなjavascript系ライブラリを組み込んだ場合、最終的なデータがbase64エンコードされた文字列としてPOSTされることがあるが、PHPでここから拡張子を取得するのは地味に面倒くさい。
(大抵の場合はライブラリ側で拡張子を決め打ちしてしまうが)

拡張子を取得する例としては大まかに2通りで

例1. BASE64文字列から取得する

$data = 'data:image/jpeg;base64,/9j/hogefuga....';
$pos  = strpos($data, ';');
$type = explode(':', substr($data, 0, $pos))[1];

例2. mime typeと拡張子を対応付ける配列を用意する

こんな配列を作成して引っ張ってくる

一般に後者が使われることが多く見られるが、ぶっちゃけ面倒くさいというか、こんなの書きたくない。

こんな面倒なことはしなくていい、そう、Codeigniter4ならね

Codeigniter4には/app/Config/Mimes.php というファイルにmime typeと拡張子を紐付ける配列が既に存在しており、かつ、このファイル内に 拡張子を予測するメソッドが存在する
なお、これは

  • マニュアルには記載がない
  • CodeiIgniter3には配列の拡張子 → mime type 用の配列しか存在しない。

それがこれ

/app/Config/Mimes.php
/**
 * Attempts to determine the best file extension for a given mime type.
 *
 * @param string $type
 * @param string $proposed_extension - default extension (in case there is more than one with the same mime type)
 *
 * @return string|null The extension determined, or null if unable to match.
 */
public static function guessExtensionFromType(string $type, ?string $proposed_extension = null)
{
    $type = trim(strtolower($type), '. ');

    $proposed_extension = trim(strtolower($proposed_extension));

    if (! is_null($proposed_extension) && array_key_exists($proposed_extension, static::$mimes) && in_array($type, is_string(static::$mimes[$proposed_extension]) ? [static::$mimes[$proposed_extension]] : static::$mimes[$proposed_extension]))
    {
        return $proposed_extension;
    }

    foreach (static::$mimes as $ext => $types)
    {
        if ((is_string($types) && $types === $type) || (is_array($types) && in_array($type, $types)))
        {
            return $ext;
        }
    }

    return null;
}

素晴らしいことに staticなメソッド なのでどこからでも利用可能である。

public function postbase64image() {
    $request = \Config\Services::request();
    $data = $request->getPost('imagedata');

    // 先頭部分を削除するのは自力で書く必要がある
    $data = str_replace(' ', '+', $data);
    $data = preg_replace('#^data:image/\w+;base64,#i', '', $data);
    $data = base64_decode($data);

    // mime typeを含む画像情報を取得
    $fileInfo = getimagesizefromstring($data);

    // 拡張子を取得
    // 第2引数で同じmimeタイプの拡張子が複数ある場合の優先する拡張子を設定可能
    // 指定しない場合(null)、はMimes.phpの配列の前にあるものが優先される。
    // 例えば、application/octet-stream は第2引数を指定しない場合 csv になる。
    echo \Config\Mimes::guessExtensionFromType($fileInfo['mime']); // jpg とか png とか。

    // あとは保存するだけ
}

Codeigniter4にはマニュアルにないこういったメソッドが沢山潜んでいるので、「これは・・」と思ったときは探してみると良い。

data:image ~ ;base64 を削除するのも楽な方法ないかなぁ・・・