改行をBRタグに置き換える
Posted feedbacks - PHP
通すタグに含まれる改行は一度アトリビュート毎に分解するからそこで 消えるかと思いきや、''で括られてたりすると残るのでした。 URLに改行が含まれるというのもアレですが… '<~>'に変換されたタグに含まれる改行をどうするか迷ったのですが 今回は<br/>には変換していません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php
function safehtml($str)
{
$safetag=array('a'=>array(1,array('href','name')),'strong'=>array(1),'br'=>array(2));
$r=array();
$tags=array();
$offs=0;
while(preg_match('!<(\s*(/|)\s*(([^>\'"/]+|\'[^\']*\'|"[^"]*")*)(/|)\s*)>!',$str,$m1,PREG_OFFSET_CAPTURE,$offs))
{ $r[]=nl2br(substr($str,$offs,$m1[0][1]-$offs));
$offs=$m1[0][1]+strlen($m1[0][0]);
preg_match_all('!([^\s\'"=]+)(\s*=\s*("[^"]*"|\'[^\']*\'|[^\s]+)|)!im',$m1[3][0],$m2,PREG_SET_ORDER);
$tag=strtolower($m2[0][1]);
if(isset($safetag[$tag]))
{ if($safetag[$tag][0]&1)
{ if($m1[2][0])
{ if(array_search($tag,$tags)===false)
continue; // 開いてないタグは閉じない
while(($t=array_shift($tags))) // 開いたのと逆順に閉じる
{ $r[]="</$t>";
if($t==$tag)
break;
}
continue;
}
if(!$m1[5][0])
array_unshift($tags,$tag);
}
if($safetag[$tag][0]&2)
{ $m1[2][0]="";
$m1[5][0]="/";
}
$t=array($tag);
if(isset($safetag[$tag][1]) && !$m1[2][0])
{ array_shift($m2);
while($param=array_shift($m2))
{ if(array_search(strtolower($param[1]),$safetag[$tag][1])!==false)
$t[]=$param[0];
}
}
$r[]='<'.$m1[2][0].implode(" ",$t).$m1[5][0].'>';
}
else
$r[]=str_replace(array('<','>'),array('<','>'),$m1[0][0]);
}
$r[]=substr($str,$offs);
while(($tag=array_shift($tags))) // 閉じわすれタグを閉じる
$r[]="</$tag>";
return implode("",$r);
}
echo safehtml(<<<EOT
<a href='www.google.com'
target=_blank>link</a> <blink dummy='<'>and</blink><br> <strong onClick='alert("NG")'>cli
ck<br/>me!</strong> <z foo='<script>alert("Boo")</script>'>
EOT
);
?>
|
#2906を見て<>の対応が崩れている場合にうまく対応できていない事に気がつきました。 それから最後のタグより後ろの部分の改行を変換し忘れていたので合わせて修正しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <?php
function escapetag($str)
{
return str_replace(array('<','>'),array('<','>'),$str);
}
function safehtml($str)
{
$safetag=array('a'=>array(1,array('href','name')),'strong'=>array(1),'br'=>array(2));
$r=array();
$tags=array();
$offs=0;
while(preg_match('!<(\s*(/|)\s*(([^<>\'"/]+|\'[^\']*\'|"[^"]*")*)(/|)\s*)>!',$str,$m1,PREG_OFFSET_CAPTURE,$offs))
{ $r[]=nl2br(escapetag(substr($str,$offs,$m1[0][1]-$offs)));
$offs=$m1[0][1]+strlen($m1[0][0]);
preg_match_all('!([^\s\'"=]+)(\s*=\s*("[^"]*"|\'[^\']*\'|[^\s]+)|)!im',$m1[3][0],$m2,PREG_SET_ORDER);
$tag=strtolower($m2[0][1]);
if(isset($safetag[$tag]))
{ if($safetag[$tag][0]&1)
{ if($m1[2][0])
{ if(array_search($tag,$tags)===false)
continue; // 開いてないタグは閉じない
while(($t=array_shift($tags))) // 開いたのと逆順に閉じる
{ $r[]="</$t>";
if($t==$tag)
break;
}
continue;
}
if(!$m1[5][0])
array_unshift($tags,$tag);
}
if($safetag[$tag][0]&2)
{ $m1[2][0]="";
$m1[5][0]="/";
}
$t=array($tag);
if(isset($safetag[$tag][1]) && !$m1[2][0])
{ array_shift($m2);
while($param=array_shift($m2))
{ if(array_search(strtolower($param[1]),$safetag[$tag][1])!==false)
$t[]=$param[0];
}
}
$r[]='<'.$m1[2][0].implode(" ",$t).$m1[5][0].'>';
}
else
$r[]=escapetag($m1[0][0]);
}
$r[]=nl2br(escapetag(substr($str,$offs)));
while(($tag=array_shift($tags))) // 閉じわすれタグを閉じる
$r[]="</$tag>";
return implode("",$r);
}
echo safehtml(<<<EOT
<a href='www.google.com'
target=_blank>link</a>> <blink dummy='<'>and</blink><<br> <strong onClick='alert("NG")'>cli
ck<br/>me!</strong> <z foo='<script>alert("Boo")</script>'><
EOT
);
?>
|




にしお
#3413()
Rating-2/2=-1.00
また、ユーザの入力注の<br>は<br/>に変換してください。
このお題はperezvonさんの提案を元にした三部作の二問目です。ご協力ありがとうございました。
[ reply ]