Извлечение URL из текста в PHP

У меня есть этот текст:

$string = "this is my friend's website http://example.com I think it is coll";

Как извлечь ссылку в другую переменную?

Я знаю, что это должно быть с помощью регулярного выражения особенно preg_match() но я не знаю как?

11 ответов

Вероятно, самый безопасный способ - использовать фрагменты кода из WordPress. Загрузите последнюю версию (в настоящее время 3.1.1) и посмотрите wp-includes/formatting.php. Есть функция с именем make_clickable, которая имеет простой текст для параметра и возвращает отформатированную строку. Вы можете получить коды для извлечения URL-адресов. Это довольно сложно, хотя.

Это регулярное выражение в одну строку может быть полезным.

preg_match_all('#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#', $string, $match);

Но это регулярное выражение все еще не может удалить некоторые неправильно сформированные URL (напр. http://google:ha.ckers.org).

См. Также: Как имитировать поведение Auto-Link в Stackru

Я пытался сделать, как сказал Nobu, используя Wordpress, но с большим количеством зависимостей от других функций WordPress, вместо этого я решил использовать регулярное выражение Nobu для preg_match_all() и превратил его в функцию, используя preg_replace_callback(); функция, которая теперь заменяет все ссылки в тексте ссылками. Он использует анонимные функции, поэтому вам понадобится PHP 5.3, или вы можете переписать код, чтобы использовать вместо него обычную функцию.

<?php 

/**
 * Make clickable links from URLs in text.
 */

function make_clickable($text) {
    $regex = '#\bhttps?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#';
    return preg_replace_callback($regex, function ($matches) {
        return "<a href=\'{$matches[0]}\'>{$matches[0]}</a>";
    }, $text);
}

URL-адреса имеют довольно сложное определение - вы должны решить, что вы хотите захватить в первую очередь. Простой пример захвата всего, что начинается с http:// а также https:// может быть:

preg_match_all('!https?://\S+!', $string, $matches);
$all_urls = $matches[0];

Обратите внимание, что это очень просто и может захватывать недействительные URL. Я бы порекомендовал ознакомиться с регулярными выражениями POSIX и PHP для более сложных вещей.

Код, который работал для меня (особенно если у вас есть несколько ссылок в вашей строке $):

$string = "this is my friend's website http://example.com I think it is cool, but this is cooler http://www.memelpower.com :)";
$regex = '/\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i';
preg_match_all($regex, $string, $matches);
$urls = $matches[0];
// go over all links
foreach($urls as $url) 
{
    echo $url.'<br />';
}

Надеюсь, что это помогает и другим.

Если текст, из которого вы извлекаете URL-адреса, отправляется пользователем и вы собираетесь отображать результат в виде ссылок где угодно, вам следует быть ОЧЕНЬ ОЧЕНЬ осторожными, чтобы избежать уязвимостей XSS, в первую очередь URL-адресов протокола "javascript:", но также искаженных URL-адреса, которые могут обмануть ваше регулярное выражение и / или отображающий браузер для выполнения их как URL-адреса Javascript. По крайней мере, вы должны принимать только те URL, которые начинаются с "http", "https" или "ftp".

Есть также запись в блоге Джеффа, где он описывает некоторые другие проблемы с извлечением URL.

preg_match_all('/[a-z]+:\/\/\S+/', $string, $matches);

Это простой способ, который сработает во многих случаях, но не во всех. Все совпадения помещаются в $ совпадений. Обратите внимание, что это не распространяется на ссылки в элементах привязки (

Вы могли бы сделать как это..

<?php
$string = "this is my friend's website http://example.com I think it is coll";
echo explode(' ',strstr($string,'http://'))[0]; //"prints" http://example.com

Вы можете попробовать это найти ссылку и отредактировать ссылку (добавьте ссылку href).

$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";

// The Text you want to filter for urls
$text = "The text you want to filter goes here. http://example.com";

if(preg_match($reg_exUrl, $text, $url)) {

       echo preg_replace($reg_exUrl, "<a href="{$url[0]}">{$url[0]}</a> ", $text);

} else {

       echo "No url in the text";

}

обратитесь сюда: http://php.net/manual/en/function.preg-match.php

preg_match_all ("/a[\s]+[^>]*?href[\s]?=[\s\"\']+".
                "(.*?)[\"\']+.*?>"."([^<]+|.*?)?<\/a>/",
                $var, &$matches);

$matches = $matches[1];
$list = array();

foreach($matches as $var)
{    
    print($var."<br>");
}

Есть много крайних случаев с URL-адресами. Например, URL-адрес может содержать скобки или не содержать протокол и т. Д. Вот почему регулярного выражения недостаточно.

Я создал библиотеку PHP, которая может справиться с множеством крайних случаев: выделение URL-адресов.

Пример:

<?php

use VStelmakh\UrlHighlight\UrlHighlight;

$urlHighlight = new UrlHighlight();
$urlHighlight->getUrls("this is my friend's website http://example.com I think it is coll");
// return: ['http://example.com']

Подробнее см. Readme. Для случаев покрытых URL см. Test.

Вот функция, которую я использую, не могу вспомнить, откуда она взялась, но, похоже, довольно хорошо справляется с поиском ссылок в тексте. и делать на них ссылки.

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

function make_links($str){

  $pattern = '(?xi)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))';

  return preg_replace_callback("#$pattern#i", function($matches) {
    $input = $matches[0];
    $url = preg_match('!^https?://!i', $input) ? $input : "http://$input";
    return '<a href="' . $url . '" rel="nofollow" target="_blank">' . "$input</a>";
  }, $str);
} 

Использование:

$subject = 'this is a link http://google:ha.ckers.org maybe don't want to visit it?';
echo make_links($subject);

Выход

this is a link <a href="http://google:ha.ckers.org" rel="nofollow" target="_blank">http://google:ha.ckers.org</a> maybe don't want to visit it?
<?php
preg_match_all('/(href|src)[\s]?=[\s\"\']?+(.*?)[\s\"\']+.*?/', $webpage_content, $link_extracted);

предварительный просмотр

public function find_links($post_content){
    $reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
    // Check if there is a url in the text
    if(preg_match_all($reg_exUrl, $post_content, $urls)) {
        // make the urls hyper links,
        foreach($urls[0] as $url){
            $post_content = str_replace($url, '<a href="'.$url.'" rel="nofollow"> LINK </a>', $post_content);
        }
        //var_dump($post_content);die(); //uncomment to see result
        //return text with hyper links
        return $post_content;
    } else {
        // if no urls in the text just return the text
        return $post_content; 
    }
}

Это Regex прекрасно работает для меня, и я проверил со всеми типами URL,

<?php
$string = "Thisregexfindurlhttp://www.rubular.com/r/bFHobduQ3n mixedwithstring";
preg_match_all('/(https?|ssh|ftp):\/\/[^\s"]+/', $string, $url);
$all_url = $url[0]; // Returns Array Of all Found URL's
$one_url = $url[0][0]; // Gives the First URL in Array of URL's
?>

Проверено много URL можно найти здесь http://www.rubular.com/r/bFHobduQ3n

Другие вопросы по тегам