Laravel-admin 中 summernote 圖片 base64 轉檔案

beatles發表於2019-08-23

背景: 不喜歡資料庫中儲存大段的 base64 圖片, 太佔空間了; laravel-admin 中沒找到其它特別好用的富文字編輯器, 所以改吧.

  1. 最初的想法是直接改 summernote 的 js 檔案, 可是要動到 vendor 中的內容, 不想改
  2. 在表單內容儲存到資料庫之前 (或之後) 把 base64 的圖片儲存成檔案, 並用檔案的路徑代替之前的 base64串

實現:
在 laravel-admin 的控制器中重寫 store, update, destroy 方法, 前兩個用於 base64 轉 檔案, 後一個用於刪除圖片

// ArticlesController.php
/********** 以下重寫 store, update, destroy 方法, 用於 summernote 上傳的base64圖片轉檔案或刪除 *******/
public function store()
{
    request()['content'] = summernote_base64_to_file(request()['content']);

    parent::store();
}

public function update($id)
{
    request()['content'] = summernote_base64_to_file(request()['content']);

    parent::update($id);
}

public function destroy($id)
{
    $article = Article::find($id);
    summernote_delete_image($article->content);

    parent::destroy($id);
}
    // helpers.php
    function summernote_base64_to_file($content)
    {
        if (!($content && \Str::contains($content, ['src="data:image', 'src=\'data:image']))) {
            return $content;
    }

    $pattern = '/(data:image\/)([^;]+)(;base64,)([^\"]+)/';
    $res     = preg_replace_callback($pattern, function ($matches) {
        // 生成路徑
        $public_path = public_path();
        $folder_path = '/summernote/' . date('Ym') . '/' . date('d') . '/';
        if (!is_dir($dir = $public_path . $folder_path)) {
            mkdir($dir, 0777, true);
        }

        // 生成檔名
        $matches[2] = $matches[2] === 'jpeg' ? 'jpg' : $matches[2];
        $filename   = md5(time() . \Illuminate\Support\Str::random()) . '.' . $matches[2];
        $file       = $dir . $filename;

        // 儲存檔案
        file_put_contents($file, base64_decode($matches[4]));// base64 轉圖片

        // 返回相對路徑
        return $folder_path . $filename;
    }, $content);

    return $res;
}

function summernote_delete_image($content)
{
    if (!($content && \Str::contains($content, ['summernote']))) {
        return null;
    }

    $pattern = '/(\/summernote[^\'\"]+)/';
    $times   = preg_match_all($pattern, $content, $matches);
    if ($times) {
        foreach ($matches[0] as $value) {
            unlink(public_path() . $value);
        }
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章