laravelで、特定のhtmlタグのみサニタイズしない処理を実装したのでまとめます。 ブログの記事投稿機能などで、特定のhtmlタグのみ利用者に使用を許可したい場合などに使う想定です。
設定ファイルに許可するhtmlタグ一覧を定義し、 そのhtmlタグはサニタイズしないという方式で実装しました。
設定ファイル(config.general.php)
<?php
return [
'apply_tags' => [
'h1', 'h2', 'h3', 'h4', 'h5',
'b', 'a', 'img', 'u', 'br',
'table', 'tr', 'th', 'td', 'tbody', 'thead',
]
];
?>
ここにサニタイズしないhtmlタグを配列で定義します。 これ以外のタグはサニタイズ対象になります。
App/Utils/TagSanitize.php
<?php
namespace App\Utils;
use App;
use Config;
use Log;
class TagSanitize
{
/**
* サニタイズを行う。
* @param string $content サニタイズを行う文字列
* @param array $apply_tags サニタイズを行わない(タグ使用を許可する)タグ名一覧
* @return string サニタイズ後の文字列
*/
public static function sanitize($content, $apply_tags) {
Log::debug('TagSanitize sanitize()');
Log::debug($content);
Log::debug($apply_tags);
$content = htmlspecialchars($content);
if (!is_array($apply_tags) || count($apply_tags) == 0 ) return $content;
foreach($apply_tags as $tag) {
if (strpos($tag, '/') === false) {
$content = preg_replace_callback("/<\/?". $tag . "( .*?>|\/?>)/i",
function ($matches) {
$target_str = $matches[0];
$target_str = str_replace("<", "<", $target_str);
$target_str = str_replace(">", ">", $target_str);
$target_str = str_replace(""", "\"", $target_str);
return $target_str;
},
$content);
}
}
Log::debug($content);
return $content;
}
/**
* ページの本文で使用できるタグの一覧を取得する
* @return array サニタイズしないタグ一覧
*/
public static function getContentApplyTagList() {
return Config::get('general.apply_tags');
}
}
サニタイズ処理を行うクラスです。
使い方
上記の二つのファイルをControllerで使用する場合の例です。
use App\Utils\TagSanitize;
~~省略~~
public function index(Request $request) {
$content = "<b>テスト</b><br><div>タグテストです</div>";
// サニタイズ
$apply_tags = TagSanitize::getContentApplyTagList();
$content = TagSanitize::sanitize($content, $apply_tags);
}
この例だと、 b, brタグはConfigのapply_tags配列にあるのでサニタイズされませんが、divタグはサニタイズされます。
注意点
設定ファイルの更新や、名前空間の更新をしないと正しく読み込めないかもしれないので、 エラーが発生する場合はこちらのコマンドを打ってみてください。
$ php artisan config:cache
$ composer dump-autoload
参考
こちらのサイトを参考にさせていただきました、ありがとうございます。