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

タイトルに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