0

I currently have the following code to add an a href to user-submitted plain text where HTTPS:// is found. The problem is that this obviously changes all links in the text to the same name/location. How can I do this process seperately for every instance of HTTPS:// in the text?

//Example variables (usually from MySQL)
$moreOrig = "https://duckduckgo.com is better than https://google.com";
// The Regular Expression filter
$testUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";

if (preg_match($testUrl, $moreOrig, $url)) {
//split into parts if user has a /something to clean url
    $parts = explode ("/", $url[0]);

    //glue
    list($first, $second, $third) = $parts;

    //output
    $shortUrl = implode ("/", array($third));

    $more = nl2br(preg_replace($testUrl, "<a href='" . $url[0] . "' rel = 'nofollow'>" . $shortUrl . "</a>", $moreOrig));
  }

Output, desired vs actual ( assume input variable = "https://duckduckgo.com?q=Duck+Duck+Go is better than https://google.com?q=Duck+Duck+Go")

Desired:
<a href = "https://duckduckgo.com?q=Duck+Duck+Go">duckduckgo.com</a> is better than <a href = "https://google.com?q=Duck+Duck+Go">google.com.</a>
<br>
Actual:
<a href = "https://duckduckgo.com?q=Duck+Duck+Go">duckduckgo.com</a> is better than <a href = "https://google.com?q=Duck+Duck+Go">google.com.</a>
7
  • Possible duplicate of PHP: How can I make preg_match match only the first occurrence? Commented Nov 1, 2018 at 15:42
  • @GeorgeAppleton I think my question is different because I want to replace all occurances, not just the first. Commented Nov 1, 2018 at 15:44
  • You can just put it in a loop, if you want to replace all occurrences how is that different to what you're doing now though? A desired input and output would be helpful I think Commented Nov 1, 2018 at 15:45
  • You can easily capture the link in the regex and use $1 to put it back in where you use $url[0] now. However, to manipulate it to get a short url, you would probably need preg_replace_callback(). Commented Nov 1, 2018 at 15:47
  • Hi @JohnS. Can you show us what output you expect? Commented Nov 1, 2018 at 15:48

3 Answers 3

4
<?php declare(strict_types = 1);

$input = "
xxx
https://duckduckgo.com/url/foo
xxx
https://bing.com
xxx
https://google.com/
xxx
";

$result = preg_replace_callback(
    "@
        (?:http|ftp|https)://
        (?:
            (?P<domain>\S+?) (?:/\S+)|
            (?P<domain_only>\S+)
        )
    @sx",
    function($a){
        $link = "<a href='" . $a[0] . "'>";
        $link .= $a["domain"] !== "" ? $a["domain"] : $a["domain_only"];
        $link .= "</a>";
        return $link;
    },
    $input
);

echo $result;
Sign up to request clarification or add additional context in comments.

9 Comments

The capture group around the whole pattern doesn't seem necessary.
Actually, there's no need for the callback. Just use replace with $0 and $2 in the replacement.
Right. Thanks!!
\b inside a character class means "backspace". Your negated character class will be better written as \S that means not a space (any kind of)
TIL. Thanks for the hint.
|
0

You can do this easily with preg_replace_callback.

<?php

//Example variables (usually from MySQL)
$string = "https://duckduckgo.com is better than https://google.com";

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

$result = preg_replace_callback($pattern, function($match) {
    $url = $match[0];
    return sprintf('<a href="%1$s">%1$s</a>', $url);
}, $string);

// Result:
// "<a href="https://duckduckgo.com">https://duckduckgo.com</a> is better than <a href="https://google.com">https://google.com</a>"

Comments

0

You does not need to use preg_match(), explode() and implode(). Just use preg_replace(). You need to use a group match for whole of url to replacing it by <a></a>

$testUrl = "@((https?|ftps?)://([\w\-.]+\.[a-zA-Z]{2,3})(/\S*)?)@";
$newStr = preg_replace($testUrl, "<a href='$1'>$3</a>", $moreOrig);

Check result in demo

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.