15

I'm trying to create a function that translates every occurrence of a plain text email address in a given string into it's htmlized version.

Let's say I have the following code, where htmlizeEmails is the function I'm looking for:

$str = "Send me an email to bob@example.com.";
echo htmlizeEmails($str); // Echoes "Send me an email to <a href="mailto:bob@example.com">bob@example.com</a>."

If possible, I'd like this function to use the filter_var function to check if the email is valid.

Does anyone know how to do this? Thanks!

Edit:

Thanks for the answers, I used Shocker's regex to match potential email addresses and then, only if the filter_var validates it, it gets replaced.

function htmlizeEmails($text)
    preg_match_all('/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})/', $text, $potentialEmails, PREG_SET_ORDER);
    
    $potentialEmailsCount = count($potentialEmails);
    for ($i = 0; $i < $potentialEmailsCount; $i++) {
        if (filter_var($potentialEmails[$i][0], FILTER_VALIDATE_EMAIL)) {
            $text = str_replace($potentialEmails[$i][0], '<a href="mailto:' . $potentialEmails[$i][0] .'">' . $potentialEmails[$i][0] .'</a>', $text);
        }
    }
}
Community
  • 1
  • 1
federico-t
  • 12,014
  • 19
  • 67
  • 111

4 Answers4

8
$str = preg_replace('/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})/', '<a href="mailto:$1">$1</a>', $str);

where ([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}) is the regular expression used for detecting an email address (this is a general example, email addresses may be more complicated than this and not all addresses may be covered, but finding the perfect regex for emails is up to you)

QuantumBlack
  • 1,549
  • 11
  • 27
6

There's always matching every sequence of non-space characters and testing those with filter_var, but this is probably one of those cases where it's just better to use regular expressions.

echo preg_replace('/(([\w!#$%&\'*+\-\/=?^`{|}~]|\\\\\\\\|\\\\?"|\\\\ )+\.)*([\w!#$%&\'*+\-\/=?^`{|}~]|\\\\\\\\|\\\\?"|\\\\ )+@((\w+[\.-])*[a-zA-Z]{2,}|\[(\d{1,3}\.){3}\d{1,3}\])/', '<a href="mailto:$0">$0</a>', $str);

I've tried to follow the standard as best I could without making it ridiculously compliant. And anybody who puts comments in his or her e-mail address can just be forgotten safely, I think. And it definitely works for common e-mails.


EDIT: After a long, difficult struggle, here's my regular expression to match everything:

((([a-zA-Z0-9!\#\$%&'*+\-\/=?^_`{|}~]+|"([a-zA-Z0-9!\#\$%&'*+\-\/=?^_`{|}~(),:;<>@\[\]]|\\[ \\"])+")\.)*([a-zA-Z0-9!\#\$%&'*+\-\/=?^_`{|}~]+|"([a-zA-Z0-9!\#\$%&'*+\-\/=?^_`{|}~(),:;<>@\[\]]|\\[ \\"])+"))@((([a-zA-Z0-9]([a-zA-Z0-9]*(\-[a-zA-Z0-9]*)*)?\.)*[a-zA-Z]{2,}|\[((0?\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(0?\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\]|\[[Ii][Pp][vV]6(:[0-9a-fA-F]{0,4}){6}\]))

Enjoy escaping it!

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Slightly improved version https://regex101.com/r/l8lTif/1 Matches all cases mentioned here https://blogs.msdn.microsoft.com/testing123/2009/02/06/email-address-test-cases/ and also makes inner groups non-capturing to reduce noise in matches – unxp Dec 11 '18 at 10:54
0

The code below should work fine, but it regex is easier to go with.

$str = "Send me an email to bob@example.com.";

   function htmlizestring($a){

        if(substr_count($a,"@") != 1){
            return false;
        }else{
            $b4 = stristr($a,"@",true);
            $b4pos = strripos($b4," ")+1;
            $b4 = trim(substr($b4,$b4pos));
            $after = stristr($a,"@");           
            if(substr_count($after, " ") == 0){
                $after=rtrim($after," .,");
            }else{
                $after=trim(stristr($after," ",true));
            }
            $email = $b4.$after;
            echo $email;
            if(filter_var($email, FILTER_VALIDATE_EMAIL)){
                echo "Send me an email at: <a href='mailto:".$email."'>".$email."</a>";
            }else{
                return false;
            }
        }   

    }

    htmlizestring($str);

I happen to use stristr() with the third parameter TRUE, which only works on php 5.3+

Peter
  • 2,172
  • 1
  • 15
  • 11
0

filter_var is nice to validate an email, but Dominic Sayers' is_email is even better, and my personal choice.

source code: http://code.google.com/p/isemail/source/browse/PHP/trunk/is_email.php

about: http://isemail.info/about

J. Bruni
  • 20,322
  • 12
  • 75
  • 92