こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

エスケープしたくない、けど、したいのもある

とあるテキストデータ(.txt)を読み込み、それを表示するスクリプトをPHPで作りました。
その際、もしテキストデータにHTMLタグが入っている場合、そのまま出力させて、タグが有効になるようにしています。
(というかテキストを何も処理せずそのまま出力するだけ)
(セキュリティ的には、テキストデータは信頼できる自サイトの同一ディレクトリに置いてあるものからしか読み込ませないようになっています)

しかし、今度は逆に、もしそのテキストデータに「<hoge>」などの文字がふくまれていた場合、ブラウザはそれをタグと認識し、見えない表示になります。
本当は見えるようにそこは「&lt;hoge&gt;」と出力してほしいわけです。

かと言って、
echo htmlspecialchars($txt, ENT_QUOTES|ENT_HTML5, "UTF-8");
などエスケープして出力すると、今度はHTMLタグとして出力させたい「<br>」なども「&lt;br&gt;」として出力されてしまい都合が悪いです..

ようは、
「こんにちは<hoge><br>ほげ」
という文字列のテキストを、
「こんにちは&lt;hoge&gt;<br>ほげ」
と出力してほしい..
もちろんテキストは「hoge」であるとは限りません。

何かよい解決方法はないでしょうか?
ご教示頂けましたら幸いです。

投稿日時 - 2020-02-17 11:37:18

QNo.9713859

困ってます

質問者が選んだベストアンサー

先ほどのReplace関数用に、
変換するもののリストがあれば、よさそうには思えます。
どちらにしても、全部自動ってのは、不可能なので。
どっちをとるかは、判断が必要ですが。
1>「リスト」にあれば、そのままなのか?
2>「リスト」になければ、そのままなのか?
の2択ですね。
少なくとも、変換候補を自動で判断できない以上そこは
仕方がないかもしれません。
strposなどで、"<"を見つけたら、続く">"をスキャンしてみて、
範囲をリストから抽出など。。
$pos_start=strpos($text,"<");
if ($pos_start!==false) {
$pos_end=strpos($text,">",$pos_start); // これをしないとそれよりも「前」がヒットするため
}
あとは、substrなどで、切り出してみれば比較用文字列が取り出せるので、
それをリスト比較ですかね。。
なお、この方法を使うとき、
クオート分解がやや、めんどくさいですけどね。
<tag param="<hoge>">
と、シングルクオートまたはダブルクオート内で<>が使われる可能性があるので。そこをフィルタしつつですかね。

投稿日時 - 2020-02-17 13:54:48

お礼

ありがとうございました。地道にエスケープします..

投稿日時 - 2020-02-18 21:17:55

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ならば・・・
echo htmlspecialchars($txt, ENT_QUOTES|ENT_HTML5, "UTF-8");
これを、一度変数に押し込みます。
$temp=htmlspecialchars($txt, ENT_QUOTES|ENT_HTML5, "UTF-8");
echo str_replace("&lt;br&gt;", "<br>", $temp);
と、質問者さんが変換してほしくなかった場合のみのケースを、
元に戻してあげる!という手はいかがですか?

投稿日時 - 2020-02-17 11:56:54

補足

ご回答ありがとうございます。

ただ、テキストも決まった文字列でないのと同時に、HTMLタグも固定ではありません.. また、単なるタグでなく、<script ..ってのもありえます。
全部を置き換え指定するのも非現実的ですよね..

半角<>を全角<>にするのも何だかな~と。テキスト上では全角にしておいて..
$txt = str_replace("<", "&lt;", $txt);
$txt = str_replace(">", "&gt;", $txt);
こんな感じでしょうか..

投稿日時 - 2020-02-17 13:08:51

お礼

ご回答ありがとうございます。

ただ、テキストも決まった文字列でないのと同時に、HTMLタグも固定ではありません.. また、単なるタグでなく、<script ..ってのもありえます。
全部を置き換え指定するのも非現実的ですよね..

半角<>を全角<>にするのも何だかな~と。テキスト上では全角にしておいて..
$txt = str_replace("<", "&lt;", $txt);
$txt = str_replace(">", "&gt;", $txt);
こんな感じでしょうか..

投稿日時 - 2020-02-17 13:08:44

あなたにオススメの質問