Нижеприведенная функция предназначена для применения rel="nofollow"
для всех внешних ссылок и внутренних ссылок, если только путь не соответствует предопределенному корневому URL-адресу, определенному как $my_folder
ниже.
Поэтому, учитывая переменные …
$my_folder = 'http://localhost/mytest/go/'; $blog_url = 'http://localhost/mytest';
И контент …
<a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator">internal cloaked link</a> <a href="http://cnn.com">external</a>
Конечный результат, после замены должен быть …
<a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator" rel="nofollow">internal cloaked link</a> <a href="http://cnn.com" rel="nofollow">external</a>
Обратите внимание, что первая ссылка не изменяется, так как ее внутренняя ссылка.
Ссылка на второй строке также является внутренней ссылкой, но поскольку она соответствует нашей строке $my_folder
, она также получает nofollow
.
Третья ссылка самая простая, так как она не соответствует blog_url
, ее явно внешней ссылке.
Однако в приведенном ниже скрипте ВСЕ мои ссылки получают nofollow
. Как я могу исправить скрипт, чтобы делать то, что хочу?
function save_rseo_nofollow($content) { $my_folder = $rseo['nofollow_folder']; $blog_url = get_bloginfo('url'); preg_match_all('~<a.*>~isU',$content["post_content"],$matches); for ( $i = 0; $i <= sizeof($matches[0]); $i++){ if ( !preg_match( '~nofollow~is',$matches[0][$i]) && (preg_match('~' . $my_folder . '~', $matches[0][$i]) || !preg_match( '~'.$blog_url.'~',$matches[0][$i]))){ $result = trim($matches[0][$i],">"); $result .= ' rel="nofollow">'; $content["post_content"] = str_replace($matches[0][$i], $result, $content["post_content"]); } } return $content; }
Попытайтесь сделать его более читаемым в первую очередь, и только после этого сделайте ваши правила if
более сложными:
function save_rseo_nofollow($content) { $content["post_content"] = preg_replace_callback('~<(a\s[^>]+)>~isU', "cb2", $content["post_content"]); return $content; } function cb2($match) { list($original, $tag) = $match; // regex match groups $my_folder = "/hostgator"; // re-add quirky config here $blog_url = "http://localhost/"; if (strpos($tag, "nofollow")) { return $original; } elseif (strpos($tag, $blog_url) && (!$my_folder || !strpos($tag, $my_folder))) { return $original; } else { return "<$tag rel='nofollow'>"; } }
Дает следующий результат:
[post_content] => <a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator" rel=nofollow>internal cloaked link</a> <a href="http://cnn.com" rel=nofollow>external</a>
Проблема в вашем исходном коде могла бы быть $ rseo, которая не была объявлена нигде.
Вот решение DOMDocument …
$str = '<a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator">internal cloaked link</a> <a href="http://cnn.com" rel="me">external</a> <a href="http://google.com">external</a> <a href="http://example.com" rel="nofollow">external</a> <a href="http://stackoverflow.com" rel="junk in the rel">external</a> '; $dom = new DOMDocument(); $dom->preserveWhitespace = FALSE; $dom->loadHTML($str); $a = $dom->getElementsByTagName('a'); $host = strtok($_SERVER['HTTP_HOST'], ':'); foreach($a as $anchor) { $href = $anchor->attributes->getNamedItem('href')->nodeValue; if (preg_match('/^https?:\/\/' . preg_quote($host, '/') . '/', $href)) { continue; } $noFollowRel = 'nofollow'; $oldRelAtt = $anchor->attributes->getNamedItem('rel'); if ($oldRelAtt == NULL) { $newRel = $noFollowRel; } else { $oldRel = $oldRelAtt->nodeValue; $oldRel = explode(' ', $oldRel); if (in_array($noFollowRel, $oldRel)) { continue; } $oldRel[] = $noFollowRel; $newRel = implode($oldRel, ' '); } $newRelAtt = $dom->createAttribute('rel'); $noFollowNode = $dom->createTextNode($newRel); $newRelAtt->appendChild($noFollowNode); $anchor->appendChild($newRelAtt); } var_dump($dom->saveHTML());
string(509) "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <html><body> <a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator">internal cloaked link</a> <a href="http://cnn.com" rel="me nofollow">external</a> <a href="http://google.com" rel="nofollow">external</a> <a href="http://example.com" rel="nofollow">external</a> <a href="http://stackoverflow.com" rel="junk in the rel nofollow">external</a> </body></html> "
Попробуйте это (PHP 5.3+):
и код:
function nofollow($html, $skip = null) { return preg_replace_callback( "#(<a[^>]+?)>#is", function ($mach) use ($skip) { return ( !($skip && strpos($mach[1], $skip) !== false) && strpos($mach[1], 'rel=') === false ) ? $mach[1] . ' rel="nofollow">' : $mach[0]; }, $html ); }
Примеры:
echo nofollow('<a href="link somewhere" rel="something">something</a>'); // will be same because it's already contains rel parameter echo nofollow('<a href="http://www.cnn.com">something</a>'); // ad // add rel="nofollow" parameter to anchor echo nofollow('<a href="http://localhost">something</a>', 'localhost'); // skip this link as internall link
Использование регулярных выражений для правильной работы должно быть довольно сложным. Было бы проще использовать фактический парсер, например, один из расширения DOM . DOM не очень удобен для начинающих, поэтому вы можете загружать HTML с помощью DOM и запускать модификации с помощью SimpleXML . Они поддерживаются одной и той же библиотекой, поэтому ее легко использовать с другой.
Вот как это может выглядеть:
$my_folder = 'http://localhost/mytest/go/'; $blog_url = 'http://localhost/mytest'; $html = '<html><body> <a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator">internal cloaked link</a> <a href="http://cnn.com">external</a> </body></html>'; $dom = new DOMDocument; $dom->loadHTML($html); $sxe = simplexml_import_dom($dom); // grab all <a> nodes with an href attribute foreach ($sxe->xpath('//a[@href]') as $a) { if (substr($a['href'], 0, strlen($blog_url)) === $blog_url && substr($a['href'], 0, strlen($my_folder)) !== $my_folder) { // skip all links that start with the URL in $blog_url, as long as they // don't start with the URL from $my_folder; continue; } if (empty($a['rel'])) { $a['rel'] = 'nofollow'; } else { $a['rel'] .= ' nofollow'; } } $new_html = $dom->saveHTML(); echo $new_html;
Как вы можете видеть, это очень коротко и просто. В зависимости от ваших потребностей вы можете использовать preg_match()
вместо объектов strpos()
, например:
// change the regexp to your own rules, here we match everything under // "http://localhost/mytest/" as long as it's not followed by "go" if (preg_match('#^http://localhost/mytest/(?!go)#', $a['href'])) { continue; }
Я пропустил последний блок кода в OP, когда впервые прочитал вопрос. Код, который я опубликовал (и в основном любое решение на основе DOM), лучше подходит для обработки целой страницы, а не блока HTML. В противном случае DOM попытается «исправить» ваш HTML и может добавить <body>
, DOCTYPE и т. Д. …
<? $str='<a href="http://localhost/mytest/">internal</a> <a href="http://localhost/mytest/go/hostgator">internal cloaked link</a> <a href="http://cnn.com">external</a>'; function test($x){ if (preg_match('@localhost/mytest/(?!go/)@i',$x[0])>0) return $x[0]; return 'rel="nofollow" '.$x[0]; } echo preg_replace_callback('/href=[\'"][^\'"]+/i', 'test', $str); ?>