Help us understand the problem. What is going on with this article?

Laravel5にWYSIWYGエディタを実装する方法

More than 3 years have passed since last update.

タイトルにLaravelとありますが、
composer requireとかそういうLaravelらしいことは一切しないです。
他のフレームワークでも、フレームワークなしでもできると思います。

前提

  • 既に一通りのCRUDの実装が完了していること

要件

  • 画像をローカルからアップロードできる。外部サイトにアップロードしないこと(されていいなら NicEdit がオススメです)
  • アップロードした画像はサーバー上の指定のディレクトリに格納される。base64エンコードとかされない(されていいなら Summernote がオススメです)
  • bootstrapなどのCSSフレームワークに依存しない(依存していいなら Summernote がオススメです)
  • WYSIWYGの機能は選択できる。余計な機能は表示しない。必要なら追加のプラグインが簡単に追加できる。
  • jQueryに依存しなくていいもの(依存していいなら Summernote がオススメです)
  • あまりコードの記述をしなくていいやつ(小声)

用意するもの

  • TinyMCE Ver.3.5以上 (執筆時 Ver.4.4.1)
  • jbimages (※TinyMCEのプラグイン 執筆時 Ver.2.3)
  • PHP Ver.5.2以上 (当方環境はPHP Ver.5.6.22)

TinyMCEは商用利用無料か?

  • LGPLライセンスの範囲内では無料です。
  • こっちで私が公式サポートに問い合わせた回答を載せてますのでご覧ください
  • https://teratail.com/questions/45096
  • あと、jbimagesについては後述しますが、ライセンスはCCBYなので商用利用無料です。

TinyMCE の用意

  • ここからダウンロード(Download TinyMCE Communityのほうをクリック)
  • https://www.tinymce.com/download/

  • 解凍したあと、tinymce > js > tinymce ←このフォルダの中身を全部

  • 以下のディレクトリに配置

  • /public/js/tinymce

jbimages の用意

  • ここからダウンロード(Clone or download > Download ZIPをクリック)
  • https://github.com/vikdiesel/justboil.me
  • 解凍したあと、フォルダ名を次のように変更 justboil.me-master -> jbimages
  • 以下のディレクトリに全て配置。htmlとかcssとかなんか不要に見えるものも全て配置。
  • (実際readmeとかは不要なんですが、何が不要かは実装が終わってからファイルを削除してみたりして確認して下さい)
  • /public/js/tinymce/plugins/jbimages

config.php を修正

  • 以下のPHPファイルを開く
  • /public/js/tinymce/plugins/jbimages/config.php
  • 40行目らへんを修正
    $config['img_path'] = '/images'; // Relative to domain name
    $config['upload_path'] = $_SERVER['DOCUMENT_ROOT'] . $config['img_path']; // Physical path. [Usually works fine like this]

画像のアップロード先を指定します。
絶対パスで、public以下のパスを記述
指定フォルダが /public/images/hoge/item の場合は次のとおり

    $config['img_path'] = '/images/hoge/item'; // Relative to domain name
    $config['upload_path'] = $_SERVER['DOCUMENT_ROOT'] . $config['img_path']; // Physical path. [Usually works fine like this]

画像ディレクトリのパーミッションを設定

指定フォルダが /public/images/hoge/item の場合は次のとおり

sudo chown -R apache:apache public/images/hoge/item
sudo chmod -R 777 public/images/hoge/item

Viewに読み込ませる

Laravelの場合はindex.blade.phpとかそういうの、フレームワークじゃない場合はindex.phpとかindex.htmlとか

<script type="text/javascript" src="/js/tinymce/tinymce.min.js"></script>
<script type="text/javascript">
    tinymce.init({
        selector : 'textarea',
        plugins  : 'jbimages link autolink preview',
        toolbar  : 'bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link jbimages | preview',
        menubar  : false,
        relative_urls : false
    });
</script>

<textarea name="hoge"></textarea>

おわり

Upload のボタンを押すと、モーダルが表示され画像を指定してアップロードしたらサーバーに反映されてるか確認

cd public/images/hoge/item
ls -l

「hoge.jpg」とかが出ていたら成功

日本語化

  • 以下のURLから Japaneseをクリックして、Downloadを押す
  • http://archive.tinymce.com/i18n/
  • 解凍したらlangsフォルダ内の全てを
  • 以下のディレクトリに配置
  • /public/js/tinymce/langs

Viewを修正

<script type="text/javascript">
    tinymce.init({
        selector : 'textarea',
        plugins  : 'jbimages link autolink preview',
        toolbar  : 'bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link jbimages | preview',
        menubar  : false,
        relative_urls : false
    });
</script>

「language : 'ja'」を追加。
「relative_urls : false」の末尾に「,」を追加

<script type="text/javascript">
    tinymce.init({
        selector : 'textarea',
        plugins  : 'jbimages link autolink preview',
        toolbar  : 'bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link jbimages | preview',
        menubar  : false,
        relative_urls : false,
        language : 'ja'
    });
</script>

jbimagesも日本語化

別ページでまとめましたのでそちらをご確認下さい。
http://qiita.com/qwe001/items/5e047bfe707dee2f27a8

jbimagesの改変はしてもOK?

上でしれっと元のJSファイルを改変してましたが、これはライセンス的に大丈夫なのかって話。
jbimagesのライセンスはCCBYなので、クレジット表記さえしていれば改変、商用利用OK。
なので編集して大丈夫です。クレジット情報はアップロードのポップアップウィンドウにある「JustBoil.me Images Plugin」という表記で達成されてるので、これを消さない限りはライセンス違反にはなりません。
また、公式HPに「English version only. The l18n api in TinyMCE 4.x had changed, so temporary solution was to hard-code english strings.」と書いてあり、TinyMCEのVer4系は英語の文字列を直接編集して下さいとありますので問題はないものと思われます。

アップロードされるファイル名を変更

jbimagesでアップロードされた画像はデフォルトではhoge.jpgとか、オリジナルのファイル名がつきます。
仮にファイル名がダブった場合は、hoge1.jpg, hoge2.jpgのようにオリジナルファイル名に連番がついたものになります。

この命名規則を以下の場合分けで考えて、それぞれの対処策を下記します。

ファイル名はランダムでいい
  • これは一番簡単です。以下のPHPファイルを編集
  • /public/js/tinymce/plugins/jbimages/config.php
  • 119行目らへんにある以下の記述をTRUEに変更
    $config['encrypt_name'] = FALSE;
↓
    $config['encrypt_name'] = TRUE;
ファイル名がダブった場合は元の画像を上書きする
  • これも簡単です。同じく以下のPHPファイルを編集
  • /public/js/tinymce/plugins/jbimages/config.php
  • 131行目らへんにある以下の記述をTRUEに変更
$config['overwrite'] = FALSE;
↓
$config['overwrite'] = TRUE;
アップロード可能な拡張子を制限する
  • デフォルトではgif, jpg, pngのアップロードが可能です。
  • でもgifはいらない、って場面はよくあると思うので同じく以下のPHPファイルを編集
  • /public/js/tinymce/plugins/jbimages/config.php
  • 54行目らへんにある以下の記述を変更
    $config['allowed_types'] = 'gif|jpg|png';
↓
    $config['allowed_types'] = 'jpg|png';
ファイル名を日付にする
  • これはconfig.phpではサポートされてません。結構需要あると思うんだけどなあ…
  • 「hoge.jpg」とかがきたら、ファイル名を「item_20160822000000.jpg」みたいな感じにしてアップロードします。
  • 以下のPHPファイルを編集
  • /public/js/tinymce/plugins/jbimages/ci/system/libraries/Upload.php
  • 390行目らへんにある public function set_filenameを以下のように修正
    public function set_filename($path, $filename)
    {
        if ($this->encrypt_name == TRUE)
        {
            mt_srand();
            $filename = md5(uniqid(mt_rand())).$this->file_ext;
        }

        if ( ! file_exists($path.$filename))
        {
            return $filename;
        }

        $filename = str_replace($this->file_ext, '', $filename);

        $new_filename = '';
        for ($i = 1; $i < 100; $i++)
        {
            if ( ! file_exists($path.$filename.$i.$this->file_ext))
            {
                $new_filename = $filename.$i.$this->file_ext;
                break;
            }
        }

        if ($new_filename == '')
        {
            $this->set_error('upload_bad_filename');
            return FALSE;
        }
        else
        {
            return $new_filename;
        }
    }

    public function set_filename($path, $filename)
    {
        date_default_timezone_set('Asia/Tokyo');

        if ($this->encrypt_name == TRUE)
        {
            mt_srand();
            $filename = md5(uniqid(mt_rand())).$this->file_ext;
        }

        if ( ! file_exists($path.$filename))
        {
            $filename = "item_".date("YmdHis").$this->file_ext;
            return $filename;
        }

    //  $filename = str_replace($this->file_ext, '', $filename);
        $filename = str_replace($this->file_ext, '', "item_".date("YmdHis"));

        $new_filename = '';
        for ($i = 1; $i < 100; $i++)
        {
            if ( ! file_exists($path.$filename.$i.$this->file_ext))
            {
                $new_filename = $filename.$i.$this->file_ext;
                break;
            }
        }

        if ($new_filename == '')
        {
            $this->set_error('upload_bad_filename');
            return FALSE;
        }
        else
        {
            return $new_filename;
        }
    }

秒まで取得しているので、もし1秒の間に複数枚の画像をアップロードされた場合は、連番になります。
最初の画像「20160822000000.jpg」
二つ目の画像「201608220000001.jpg」
三つ目の画像「201608220000002.jpg」

ソースコードを見る限り、1秒間に100枚までなら連番で耐えれるっぽいですね。まあそんなことそうそうないでしょうけど。

オリジナルのファイル名に日付を加えたいとかならこっち

    public function set_filename($path, $filename)
    {
        date_default_timezone_set('Asia/Tokyo');

        if ($this->encrypt_name == TRUE)
        {
            mt_srand();
            $filename = md5(uniqid(mt_rand())).$this->file_ext;
        }

        if ( ! file_exists($path.$filename))
        {
            $filename = $filename.date("YmdHis").$this->file_ext;
            return $filename;
        }

    //  $filename = str_replace($this->file_ext, '', $filename);
        $filename = str_replace($this->file_ext, '', $filename.date("YmdHis"));

        $new_filename = '';
        for ($i = 1; $i < 100; $i++)
        {
            if ( ! file_exists($path.$filename.$i.$this->file_ext))
            {
                $new_filename = $filename.$i.$this->file_ext;
                break;
            }
        }

        if ($new_filename == '')
        {
            $this->set_error('upload_bad_filename');
            return FALSE;
        }
        else
        {
            return $new_filename;
        }
    }

追記:フォントサイズのアイコンを追加する

別ページに分けましたのでそちらをご確認ください
http://qiita.com/qwe001/items/8a32c31a8cc08646c277

qwe001
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした