Last active
February 3, 2017 00:25
-
-
Save Phoenix2k/6583f970bfedd67d58c0a1fdc796b53a to your computer and use it in GitHub Desktop.
Class: Converts plain text links into <a> HTML elements (supports `rel` and `target`)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Converts URLs in a string into hyperlinks. | |
* | |
* Example: <?php echo new ConvertLinks( 'Text containing a link http://gist.github.com', 'external', '_blank' ); ?> | |
* Output: Text containing a link <a href="http://gist.github.com" rel="external" target="_blank">http://gist.github.com</a> | |
* | |
* @param string $input Text containing links | |
* @param string $rel Rel attribute value (optional) | |
* @param string $target Target attribute value (optional) | |
* | |
* @see https://developer.wordpress.org/reference/functions/make_clickable/ | |
* | |
* @return string | |
*/ | |
class ConvertLinks { | |
protected static $input; | |
protected static $rel; | |
protected static $target; | |
protected $output; | |
function __construct( $input = '', $rel = '', $target = '' ) { | |
$this::$input = $input; | |
$this::$rel = $rel; | |
$this::$target = $target; | |
$pattern = '#([\s>])([\w]+?://[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]*)#is'; | |
preg_match_all( $pattern, $this::$input, $urls ); | |
// Bail out if we have nothing to work with | |
if ( empty( $urls ) || false === isset( $urls[0] ) ) return $this::$input; | |
// Loop through each link | |
foreach ( $urls[0] as $url ) { | |
$output = preg_replace_callback( $pattern, function( $matches ) { | |
$attributes = array(); | |
$prefix = $matches[1]; | |
$suffix = ''; | |
$url = $matches[2]; | |
if ( empty( $url ) ) return $matches[0]; | |
// Move special characters outside of link | |
// Covers links that end or split sentences | |
while ( true === in_array( substr( $url, -1 ), array( '.', ',', ';', ':' ) ) ) { | |
$suffix .= substr( $url, -1 ); | |
$url = substr( $url, 0, strlen( $url ) -1 ); | |
} | |
// Add rel="" attribute | |
if ( ! empty( $this::$rel ) ) { | |
$rel = sprintf( 'rel="%s"', htmlspecialchars( $this::$rel, ENT_QUOTES ) ); | |
array_push( $attributes, $rel ); | |
} | |
// Add target="" attribute | |
if ( ! empty( $this::$target ) ) { | |
$target = sprintf( 'target="%s"', htmlspecialchars( $this::$target, ENT_QUOTES ) ); | |
array_push( $attributes, $target ); | |
} | |
// Compile attributes | |
$safe_attributes = empty( $attributes ) ? '' : ' ' . join( ' ', $attributes ); | |
// Sanitize URL | |
$safe_url = htmlspecialchars( $url, ENT_QUOTES ); | |
// Build HTML tag | |
$link = sprintf( '<a href="%s"%s>%s</a>', $safe_url, $safe_attributes, $safe_url ); | |
return $prefix . $link . $suffix; | |
// Add extra space in case the string starts with a link | |
}, ' ' . $this::$input ); | |
// Remove nested links | |
$output = preg_replace( '#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', '$1$3</a>', $output ); | |
// Rremove extra whitespace and update output | |
$this->output = trim( $output ); | |
} | |
} | |
// Return output as a string | |
function __toString( ) { | |
return $this->output; | |
} | |
} | |
// Give it a spin! | |
echo new ConvertLinks( 'http://gist.github.com So http://gist.github.com?param=value many http://gist.github.com#supports/hasbangs/ links http://gist.github.com?param=combo#works/as/well!', 'external', '_blank' ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment