challenge 改行をBRタグに置き換える

一部のHTMLタグを通すフィルタ どう書く?の続編です。 前回の条件を満たしつつ、入力中の改行を<br/>に置き換えてください。ただし、たとえば"<a\nhref=...>"といったようにタグの中に改行がある場合、単純に置換するわけには行かないことに注意してください。

また、ユーザの入力注の<br>は<br/>に変換してください。

このお題はperezvonさんの提案を元にした三部作の二問目です。ご協力ありがとうございました。

Posted feedbacks - PHP

通すタグに含まれる改行は一度アトリビュート毎に分解するからそこで
消えるかと思いきや、''で括られてたりすると残るのでした。
URLに改行が含まれるというのもアレですが…
'&lt;~&gt;'に変換されたタグに含まれる改行をどうするか迷ったのですが
今回は<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('&lt;','&gt;'),$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('&lt;','&gt;'),$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
);
?>

Index

Feed

Other

Link

Pathtraq

loading...