<?
function get_all_urls($str)
{
$tag_name = "(?>(?i)[!a-z](?!--)[-:_a-z]*)";
$quotes = "(?>\"(?>[^\"]*)\"|'(?>[^']*)')";
$param_name = "(?>${quotes}|[^\"'\\s>](?:[^\\s>=/]+|/(?!>))*)";
$param_value = "(?>${quotes}|[^\"'\\s>](?:[^\\s>/]+|/(?!>))*)";
$param_pair = "(?>${param_name}(?:\\s*=\\s*${param_value}?|(?!\\s*=)))";
$params = "(?>(?:\\s+${param_pair})*\\s*)";
$tag = "(?></?${tag_name}${params}/?>)";
$script = "(?>(?i)<script${params}(?:(?s)/>|>.*?</script${params}>))";
$style = "(?>(?i)<style${params}(?:(?s)/>|>.*?</style${params}>))";
$comment = "(?>(?s)<!--.*?-->)";
$text = "(?>(?:[^<]+|(?!${tag})(?!${comment})<)+)";
$html_element = "(?>${text}|${comment}|${script}|${style}|${tag})";
$html_doc = "(?>(?s)^${html_element}*$)";
// разбиваем строку $str на отдельные html-элементы (тэги и текст)
preg_match_all('#' . $html_element . '#', $str, $matches);
$tmp = $matches[0];
$n = sizeof($tmp);
// обрабатываем полученные html-элементы
$urls = array();
$in_a = false; // флаг того, что мы находимся внутри тэга <a>
$content = ''; // тут будет храниться содержимое тэга <a>
$href = ''; // тут будет храниться содержимое параметра href тэга <a>
for ($i = 0; $i < $n; $i++) {
switch (true) {
case preg_match('#^<a.*/>$#is', $tmp[$i]) :
// короткий тэг <a> (без внутреннего текста)
if ($in_a) {
// не допускаются вложенные тэги <a>
$content .= $tmp[$i];
break;
}
$href = get_href($tmp[$i], $param_pair, $param_value);
if (is_string($href)) {
$urls[] = array(
'href' => $href,
'content' => '',
);
}
break;
case preg_match('#^<a.*>$#is', $tmp[$i]) :
// открывающий тэг <a>
if ($in_a) {
// не допускаются вложенные тэги <a>
$content .= $tmp[$i];
break;
}
$in_a = true; // находимся внтри тэга <a>
$content = ''; // обнуляем содержимое тэга
$href = get_href($tmp[$i], $param_pair, $param_value);
break;
case preg_match('#^</a.*>$#is', $tmp[$i]) :
// закрывающий тэг </a>
if (!$in_a) {
// не допускаются закрывающие тэги </a> без открывающего
$content .= $tmp[$i];
break;
}
$in_a = false;
if (is_string($href)) {
$urls[] = array(
'href' => $href,
'content' => $content,
);
}
break;
default :
$content .= $tmp[$i];
break;
} // switch ($tmp[$i])
} // for ($i = 0; $i < $n; $i++)
return $urls;
}
/**
возвращает значение параметра href в тэге <a>.
Если такого параметра не найдено, возвращает null
*/
function get_href($tag_a, $param_pair, $param_value)
{
if (preg_match("#^(?i)<a(?:\\s+(?!href)${param_pair})*\\s+href\\s*=\\s*(${param_value}?)#", $tag_a, $matches)) {
$href = $matches[1];
if ($href == '') {
return '';
}
if ($href{0} == "'" || $href{0} == '"') {
$href = substr($href, 1, -1);
}
return html_entity_decode($href, ENT_QUOTES);
}
return null; // не найден параметр href в тэге a
}
/**********************************************************************/
function do_tests($tests)
{
$n = sizeof($tests);
for ($i = 0; $i < $n; $i++) {
echo '<div style="padding:10px; margin:10px; border: 1px solid; background: #ddd">';
echo '<h2>test number ', ($i + 1), '</h2>';
echo 'Test string: <pre style="font-weight:bold; border:1px solid; margin: 5px 0px; background:#ccc">', htmlspecialchars($tests[$i]), '</pre><br/>';
echo 'Result:';
echo '<pre style="font-weight:bold; border:1px solid; margin: 5px 0px; background:#ccc">';
ob_start();
var_dump(get_all_urls($tests[$i]));
$tmp = ob_get_contents();
ob_end_clean();
echo htmlspecialchars($tmp);
echo '</pre>';
echo '</div>';
}
}
$tests = array(
// это тесты, которые были встречены в этом топике
'<a href="http://site.com" alt="link end with </a>" title="another href <a>example</a>" target=link1>link text</b></a>',
'<a href="1" alt=""><b>2</b></a>',
'<a href="dite.com" alt="1">bb</a>',
'<a href="1"><b>text</b></a>',
'<a href=a.com>test</a>',
'<a href="a.com" alt="" ><b>test</b></a>',
'<a href="java script::follow(\'http://domain.com\')">link text</a>',
// а это тесты от меня лично :)
'<a alt="" href="a.com" ><b>test</b></a>', // href не на первом месте
'</a><a title href="abc"/><a href=dfdf >te<a href=aaa> st</a tsfd d >', // много тэгов <a>
'test<a href= >test</a>', // пустая ссылка
// не достаем ссылки из яваскрипта
'<script>document.write("<a href=\'aaa.com\'>test</a>");</script><a href = bbb.com><img src="abc.test" /></a>',
'<div title="<a href=abcd>test</a>">test</div>', // не достаем ссылки из свойств тэгов
);
do_tests($tests);
?>