jetstream intertia版でLaravel-Excelを導入した際、ログイン時にhtmlentitiesのエラーが表示されるようになりました。
過去にも同じような事象が発生したため、忘れないように覚書をしておきます。
エラー内容
実際のエラー画面は下記になります。
原文
htmlentities(): Only basic entities substitution is supported for multi-byte encodings other than UTF-8; functionality is equivalent to htmlspecialchars
翻訳
htmlentities(): UTF-8 以外のマルチバイト エンコーディングでは、基本的なエンティティの置換のみがサポートされています。機能は htmlspecialchars と同等です
Queryを見てみるとsessionsでエラーになっていることがわかります。
htmlentitiesとは
htmlentitiesとは、適用可能な文字を全てHTMLエンティティに変換するPHPの関数です。
Laravelではログインする際にアクセス元から試行回数や規制文字などをチェックしています。
そのチェックで利用している関数にcleanRateLimiterKeyというのがあり、htmlentitiesを呼び出しています。
Illuminate\Cache\RateLimiter.php
public function cleanRateLimiterKey($key)
{
return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlentities($key));
}
preg_replace関数はhtmlentitiesで変換したHTMLエンティティを正規表現で置換しています。
preg_replace($正規表現パターン, $置換後の文字列, $置換対象)
cleanRateLimiterKeyパラメータの$keyはアクセス元(メールアドレス/IP)を渡しているようで、tooManyAttempts(試行回数確認)などの関数内で利用されています。
/**
* Determine if the given key has been "accessed" too many times.
*
* @param string $key
* @param int $maxAttempts
* @return bool
*/
public function tooManyAttempts($key, $maxAttempts)
{
if ($this->attempts($key) >= $maxAttempts) {
if ($this->cache->has($this->cleanRateLimiterKey($key).':timer')) {
return true;
}
$this->resetAttempts($key);
}
return false;
}
解決方法
解決方法としては2つあります。
① htmlentitiesでエンコーディング方法がおかしくなっているためUTF-8を明示する
② htmlspecialcharsを利用する
① UTF-8を明示的に指定する
htmlentities($key)をhtmlentities($key, ENT_COMPAT | ENT_HTML401, ‘UTF-8’)に変更します。
public function cleanRateLimiterKey($key)
{
return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlentities($key, ENT_COMPAT | ENT_HTML401, 'UTF-8'));
}
② htmlspecialcharsに置換する
htmlentitiesをhtmlspecialcharsに変更します。
※2024/01/28現在、公式がhtmlentitiesを利用しており、ログインフォームはシステム上で最大リスク箇所になりますので関数変更はおすすめできません。自己判断でお願いします。
public function cleanRateLimiterKey($key)
{
return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlspecialchars($key));
}
最後に
いままで問題なく利用できていたのに急に利用できなくなり、調査に時間を取られて開発が進まないことはよくありますね。
今回はcomposerでアプリケーションをインストールした際に発生しましたが、アンインストールしても直りませんでした。
DatabaseやコンポーネントでUTF-8を指定していても、PHP側で指定していない場合、同様事象が発生する可能性があると思います。
解決方法の参考にしていただければ幸いです。