функция, чтобы проверить, содержат ли теги привязки атрибуты href с 301

Я сделал эту функцию, чтобы проверить, есть ли у контента 301 перенаправление. Пожалуйста, помогите мне оптимизировать его лучше, потому что он слишком медленный.

function contains_http_301_link($content, $current_site){
$pattern = '~<a(.*?)href="([^"]+)"(.*?)>~';
$links = array();
// Check if there is a url in the content
if(preg_match_all($pattern, $content, $urls)) {
    foreach($urls[0] as $url){
        // get external links

        if ( !strpos( $url, $current_site )) {                                   // Is an external link
            $vowels = array('"' ,"<a", " ", "href", "=", ">");
            $links[] = str_replace($vowels, "", $url);
        }
    }
}
foreach ($links as $link) {
    $_headers = @get_headers($link,1); 
    if($_headers && strpos( $_headers[0], '301')) { 
        return true;
    } 
}
return false;
}

1 ответ
1

Я никогда не пытался выполнить такую ​​задачу, но предполагаю, что вам нравились методы cURL (включая CURLOPT_NO_BODY и CURLINFO_HTTP_CODE) как предлагают на 1 и 2.

Что касается синтаксического анализа html-документа, использование регулярного выражения может превзойти законный синтаксический анализатор, но вам может понравиться более точный скейпинг, если вы используете парсер DOM.

Поскольку вы сосредоточены на производительности, я [cringe] предложить регулярное выражение для анализа вашего html.

Ваш шаблон ~<a(.*?)href="([^"]+)"(.*?)>~ использует ленивые квантификаторы, и это может немного замедлить работу. Кроме того, ваш <a(.*?)href позволит сопоставить <a data-href и <abbr href — а это не то, что вы намеревались сделать.

Ваше намерение состоит в том, чтобы захватить ТОЛЬКО URL-адрес внутри href атрибут, поэтому не пытайтесь сопоставить больше, чем вам нужно. Вы, вероятно, сможете обойтись без ограничения слов после того, как a и пробел перед href, затем сбросьте совпадение полной строки с помощью K чтобы сохранить только значение href. Если это недостаточно сильная проверка, вы можете добавить опережающий просмотр, чтобы убедиться, что открывающий тег заполнен правильно.

  • ~<ab.*? href="K[^"]+~ или же
  • ~<ab.*? href="K[^"]+(?=".*?>)~

В любом случае ваш код может пропустить этап очистки. Слава богу, потому что $vowels содержит данные, которые не являются всеми гласными.

strpos() может вернуться false или же 0 как смещение. Это означает, что вы не должны полагаться на условие манипулирования типом, используя просто !. Вы должны явно проверить false или если вы используете версию php, которая пользуется str_contains() — это сработает.

Я лично осуждаю использование «оператора stfu» (@), но поскольку я не знаком с этой задачей, я не буду называть ее мерзостью.

function contains_http_301_link(string $content, string $current_site): bool
{
    preg_match_all('~<ab.*? href="K[^"]+~', $content, $matches);
    foreach ($matches[0] as $url) {
        if (strpos($url, $current_site) !== false) {
            continue;
        }
        $headers = @get_headers($url, 1);
        if($headers && strpos($headers[0], '301') !== false) {
            return true;
        } 
    }
    return false;
}

Я мог бы включить $current_site фильтрация в регулярное выражение, но это может принести больше вреда, чем пользы.


Если вы собирались развлечь (и протестировать) сценарий парсера DOM, возможно, используйте это:

function contains_http_301_link(string $content, string $current_site): bool
{
    $dom = new DOMDocument; 
    $dom->loadHTML($content);
    $xpath = new DOMXPath($dom);
    foreach ($xpath->query("//a[not(contains(@href, '$current_site'))]/@href") as $href) {
        $headers = @get_headers($href->nodeValue, 1);
        if($headers && strpos($headers[0], '301') !== false) {
            return true;
        } 
    }
    return false;
}

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *