Australia's Leading Digital Marketing Experts. T. 1300 235 433  |  Aggreagtion Enquires Welcome

Linkify a URL, Email, or FTP Address With PHP (Version 2)

This is the second of a few functions that will linkify text with PHP (see the first here). Based on WordPress' make_clickable() function, this function will create hyperlinks from URLs, partial URLs (no schema), FTP addresses, and emails. If you would like to shorten a URL in addition to creating an active link, modify beliefmedia_create_short() (as provided in the previous function) as required.

Ensure you close the pre tag on line 23. It had to be removed to preserve page formatting. Download the code below to avoid errors.

1
<?php 
2
/*
3
 Linkify a URL With PHP (Version 2)
4
 http://www.beliefmedia.com/code/php-snippets/linkify-links-php
5
*/
6
 
7
function beliefmedia_linkify($text) {
8
 
9
  $r = '';
10
 
11
  /* Split out HTML tags */
12
  $textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE );
13
 
14
  /* Keep track of how many levels link is nested inside < pre > or <code> */
15
  $nested_code_pre = 0;
16
 
17
  foreach ( $textarr as $piece ) {
18
    if ( preg_match( '|^<code[\s>]|i', $piece ) || preg_match( '|^<pre[\s>]|i', $piece ) || preg_match( '|^<script[\s>]|i', $piece ) || preg_match( '|^<style[\s>]|i', $piece ) )
19
      $nested_code_pre++;
20
 
21
    /* Make sure you close the pre tags on this line. Had to remove for formatting. Best to download the code... */
22
    elseif ( $nested_code_pre && ( '</code>' === strtolower( $piece ) || '/pre' === strtolower( $piece ) || '</script>' === strtolower( $piece ) || '</style>
23
 
24
' === strtolower( $piece ) ) )
25
    $nested_code_pre--;
26
 
27
    if ( $nested_code_pre || empty( $piece ) || ( $piece[0] === '<' && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
28
      $r .= $piece;
29
      continue;
30
    }
31
 
32
    /* Long strings might contain expensive edge cases ... */
33
    if ( 10000 < strlen( $piece ) ) {
34
 
35
      /* ... break it up (2100: Extra room for scheme and leading and trailing paretheses) */
36
      foreach ( bm_split_str_by_whitespace( $piece, 2100 ) as $chunk ) {
37
        if ( 2101 < strlen( $chunk ) ) {
38
          $r .= $chunk; // Too big, no whitespace: bail.
39
         } else {
40
          $r .= beliefmedia_linkify($chunk);
41
        }
42
      }
43
 
44
      } else {
45
 
46
        /* Pad with whitespace to simplify the regexes */
47
        $ret = " $piece ";
48
        $url_clickable = '~([\\s(<.,;:!?])([\\w]{1,20}+://(?=\S{1,2000}\s)[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+(?:[\'.,;:!?)][\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++)*)(\)?)~xS';
49
 
50
        /* Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times */
51
        $ret = preg_replace_callback( $url_clickable, 'beliefmedia_url_clickable', $ret );
52
        $ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', 'beliefmedia_ftp_clickable', $ret );
53
        $ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', 'beliefmedia_email_clickable', $ret );
54
 
55
        /* Remove our whitespace padding */
56
        $ret = substr($ret, 1, -1);
57
        $r .= $ret;
58
      }
59
    }
60
 
61
 /* Cleanup of accidental links within links */
62
 return preg_replace('#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r);
63
}
64
 
65
function beliefmedia_email_clickable( $matches ) {
66
  $email = $matches[2] . '@' . $matches[3];
67
  return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
68
}
69
 
70
function beliefmedia_ftp_clickable($matches) {
71
 
72
  $ret = '';
73
  $dest = $matches[2];
74
  $dest = 'http://' . $dest;
75
 
76
  /* removed trailing [.,;:)] from URL */
77
  if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
78
    $ret = substr($dest, -1);
79
    $dest = substr($dest, 0, strlen($dest)-1);
80
  }
81
 
82
  /* $dest = esc_url($dest); */
83
  if (empty($dest)) return $matches[0];
84
 
85
 return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\" target=\"_blank\">$dest</a>$ret";
86
}
87
 
88
function bm_split_str_by_whitespace($string, $goal) {
89
 
90
  $chunks = array();
91
  $string_nullspace = strtr($string, "\r\n\t\v\f ", "\000\000\000\000\000\000");
92
 
93
  while ($goal < strlen($string_nullspace)) {
94
    $pos = strrpos(substr($string_nullspace, 0, $goal + 1), "\000");
95
 
96
    if (false === $pos) {
97
      $pos = strpos($string_nullspace, "\000", $goal + 1);
98
      if (false === $pos) {
99
        break;
100
      }
101
    }
102
 
103
    $chunks[] = substr($string, 0, $pos + 1);
104
    $string = substr($string, $pos + 1);
105
    $string_nullspace = substr($string_nullspace, $pos + 1);
106
  }
107
 
108
  if ($string) $chunks[] = $string;
109
 
110
 return $chunks;
111
}
112
 
113
 
114
function beliefmedia_url_clickable( $matches ) {
115
 
116
  $url = $matches[2];
117
 
118
  if ( ')' == $matches[3] && strpos($url, '(' )) {
119
    /* If trailing character is a closing parethesis, and URL has an opening parenthesis in it, add closing parenthesis to the URL */
120
    $url .= $matches[3];
121
    $suffix = '';
122
 
123
  } else {
124
    $suffix = $matches[3];
125
  }
126
 
127
  /* Include parentheses in the URL only if paired */
128
  while (substr_count($url, '(' ) < substr_count( $url, ')')) {
129
    $suffix = strrchr($url, ')') . $suffix;
130
    $url = substr($url, 0, strrpos( $url, ')' ));
131
  }
132
 
133
  if (empty($url)) return $matches[0];
134
 
135
 return $matches[1] . "<a href=\"$url\" rel=\"nofollow\" target=\"_blank\">$url</a>" . $suffix;
136
}

Usage is as follows:

1
<?php 
2
$text = 'Fully constructed URL: http://www.beliefmedia.com/. Partial URL (no schema): www.flight.org/. Email: email marty@test.com.';
3
echo beliefmedia_linkify($text);

The function will return the following:

Fully constructed URL: http://www.beliefmedia.com/. Partial URL (no schema): http://www.flight.org/. Email: email marty@test.com.

Like this article?

Share on facebook
Share on Facebook
Share on twitter
Share on Twitter
Share on linkedin
Share on Linkdin
Share on pinterest
Share on Pinterest

Leave a comment