1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-13 22:54:25 +01:00
invoiceninja/app/Libraries/lib_autolink.php

318 lines
9.3 KiB
PHP
Raw Normal View History

2017-01-30 20:40:43 +01:00
<?php
//
// A PHP auto-linking library
//
// https://github.com/iamcal/lib_autolink
//
// By Cal Henderson <cal@iamcal.com>
// This code is licensed under the MIT license
//
//###################################################################
//
// These are global options. You can set them before calling the autolinking
// functions to change the output.
//
2017-01-30 17:05:31 +01:00
$GLOBALS['autolink_options'] = [
2017-01-30 20:40:43 +01:00
// Should http:// be visibly stripped from the front
// of URLs?
2017-01-30 17:05:31 +01:00
'strip_protocols' => false,
];
2017-01-30 20:40:43 +01:00
//###################################################################
2017-01-30 17:05:31 +01:00
2017-01-30 20:40:43 +01:00
function autolink($text, $limit = 30, $tagfill = '', $auto_title = true)
2017-01-30 17:05:31 +01:00
{
$text = autolink_do($text, '![a-z][a-z-]+://!i', $limit, $tagfill, $auto_title);
$text = autolink_do($text, '!(mailto|skype):!i', $limit, $tagfill, $auto_title);
$text = autolink_do($text, '!www\\.!i', $limit, $tagfill, $auto_title, 'http://');
2017-01-30 20:40:43 +01:00
2017-01-30 17:05:31 +01:00
return $text;
}
2017-01-30 20:40:43 +01:00
//###################################################################
2017-01-30 17:05:31 +01:00
2017-01-30 20:40:43 +01:00
function autolink_do($text, $sub, $limit, $tagfill, $auto_title, $force_prefix = null)
2017-01-30 17:05:31 +01:00
{
2017-01-30 20:40:43 +01:00
$text_l = strtolower($text);
2017-01-30 17:05:31 +01:00
$cursor = 0;
$loop = 1;
$buffer = '';
while (($cursor < strlen($text)) && $loop) {
$ok = 1;
$matched = preg_match($sub, $text_l, $m, PREG_OFFSET_CAPTURE, $cursor);
2017-01-30 20:40:43 +01:00
if (! $matched) {
2017-01-30 17:05:31 +01:00
$loop = 0;
$ok = 0;
} else {
$pos = $m[0][1];
$sub_len = strlen($m[0][0]);
2017-01-30 20:40:43 +01:00
$pre_hit = substr($text, $cursor, $pos - $cursor);
2017-01-30 17:05:31 +01:00
$hit = substr($text, $pos, $sub_len);
$pre = substr($text, 0, $pos);
$post = substr($text, $pos + $sub_len);
$fail_text = $pre_hit.$hit;
$fail_len = strlen($fail_text);
2017-01-30 20:40:43 +01:00
//
// substring found - first check to see if we're inside a link tag already...
//
2017-01-30 17:05:31 +01:00
$bits = preg_split('!</a>!i', $pre);
$last_bit = array_pop($bits);
if (preg_match("!<a\s!i", $last_bit)) {
2017-01-30 20:40:43 +01:00
//echo "fail 1 at $cursor<br />\n";
2017-01-30 17:05:31 +01:00
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
2017-01-30 20:40:43 +01:00
//
// looks like a nice spot to autolink from - check the pre
// to see if there was whitespace before this match
//
2017-01-30 17:05:31 +01:00
if ($ok) {
if ($pre) {
2017-01-30 20:40:43 +01:00
if (! preg_match('![\s\(\[\{>]$!s', $pre)) {
2017-01-30 17:05:31 +01:00
2017-01-30 20:40:43 +01:00
//echo "fail 2 at $cursor ($pre)<br />\n";
2017-01-30 17:05:31 +01:00
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
}
2017-01-30 20:40:43 +01:00
//
// we want to autolink here - find the extent of the url
//
2017-01-30 17:05:31 +01:00
if ($ok) {
if (preg_match('/^([a-z0-9\-\.\/\-_%~!?=,:;&+*#@\(\)\$]+)/i', $post, $matches)) {
$url = $hit.$matches[1];
$cursor += strlen($url) + strlen($pre_hit);
$buffer .= $pre_hit;
2017-01-30 17:05:31 +01:00
$url = html_entity_decode($url);
2017-01-30 20:40:43 +01:00
//
// remove trailing punctuation from url
//
2017-01-30 17:05:31 +01:00
while (preg_match('|[.,!;:?]$|', $url)) {
2017-01-30 20:40:43 +01:00
$url = substr($url, 0, strlen($url) - 1);
2017-01-30 17:05:31 +01:00
$cursor--;
}
foreach (['()', '[]', '{}'] as $pair) {
$o = substr($pair, 0, 1);
$c = substr($pair, 1, 1);
if (preg_match("!^(\\$c|^)[^\\$o]+\\$c$!", $url)) {
2017-01-30 20:40:43 +01:00
$url = substr($url, 0, strlen($url) - 1);
2017-01-30 17:05:31 +01:00
$cursor--;
}
}
2017-01-30 20:40:43 +01:00
//
// nice-i-fy url here
//
2017-01-30 17:05:31 +01:00
$link_url = $url;
$display_url = $url;
2017-01-30 17:05:31 +01:00
if ($force_prefix) {
$link_url = $force_prefix.$link_url;
}
2017-01-30 17:05:31 +01:00
if ($GLOBALS['autolink_options']['strip_protocols']) {
if (preg_match('!^(http|https)://!i', $display_url, $m)) {
2017-01-30 20:40:43 +01:00
$display_url = substr($display_url, strlen($m[1]) + 3);
2017-01-30 17:05:31 +01:00
}
}
2017-01-30 17:05:31 +01:00
$display_url = autolink_label($display_url, $limit);
2017-01-30 20:40:43 +01:00
//
// add the url
//
2017-01-30 17:05:31 +01:00
$currentTagfill = $tagfill;
2017-01-30 20:40:43 +01:00
if ($display_url != $link_url && ! preg_match('@title=@msi', $currentTagfill) && $auto_title) {
2017-01-30 17:05:31 +01:00
$display_quoted = preg_quote($display_url, '!');
2017-01-30 20:40:43 +01:00
if (! preg_match("!^(http|https)://{$display_quoted}$!i", $link_url)) {
2017-01-30 17:05:31 +01:00
$currentTagfill .= ' title="'.$link_url.'"';
}
}
2017-01-30 20:40:43 +01:00
$link_url_enc = htmlspecialchars($link_url);
$display_url_enc = htmlspecialchars($display_url);
2017-01-30 17:05:31 +01:00
$buffer .= "<a href=\"{$link_url_enc}\"$currentTagfill>{$display_url_enc}</a>";
} else {
2017-01-30 20:40:43 +01:00
//echo "fail 3 at $cursor<br />\n";
2017-01-30 17:05:31 +01:00
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
}
2017-01-30 20:40:43 +01:00
//
// add everything from the cursor to the end onto the buffer.
//
2017-01-30 17:05:31 +01:00
$buffer .= substr($text, $cursor);
2017-01-30 17:05:31 +01:00
return $buffer;
}
2017-01-30 20:40:43 +01:00
//###################################################################
2017-01-30 17:05:31 +01:00
function autolink_label($text, $limit)
{
2017-01-30 20:40:43 +01:00
if (! $limit) {
2017-01-30 17:05:31 +01:00
return $text;
}
2017-01-30 17:05:31 +01:00
if (strlen($text) > $limit) {
2017-01-30 20:40:43 +01:00
return substr($text, 0, $limit - 3).'...';
2017-01-30 17:05:31 +01:00
}
2017-01-30 17:05:31 +01:00
return $text;
}
2017-01-30 20:40:43 +01:00
//###################################################################
2017-01-30 20:40:43 +01:00
function autolink_email($text, $tagfill = '')
2017-01-30 17:05:31 +01:00
{
2017-01-30 20:40:43 +01:00
$atom = '[^()<>@,;:\\\\".\\[\\]\\x00-\\x20\\x7f]+'; // from RFC822
2017-01-30 20:40:43 +01:00
//die($atom);
2017-01-30 20:40:43 +01:00
$text_l = strtolower($text);
2017-01-30 17:05:31 +01:00
$cursor = 0;
$loop = 1;
$buffer = '';
2017-01-30 17:05:31 +01:00
while (($cursor < strlen($text)) && $loop) {
2017-01-30 20:40:43 +01:00
//
// find an '@' symbol
//
2017-01-30 17:05:31 +01:00
$ok = 1;
$pos = strpos($text_l, '@', $cursor);
2017-01-30 17:05:31 +01:00
if ($pos === false) {
$loop = 0;
$ok = 0;
} else {
2017-01-30 20:40:43 +01:00
$pre = substr($text, $cursor, $pos - $cursor);
2017-01-30 17:05:31 +01:00
$hit = substr($text, $pos, 1);
$post = substr($text, $pos + 1);
2017-01-30 17:05:31 +01:00
$fail_text = $pre.$hit;
$fail_len = strlen($fail_text);
2017-01-30 20:40:43 +01:00
//die("$pre::$hit::$post::$fail_text");
2017-01-30 20:40:43 +01:00
//
// substring found - first check to see if we're inside a link tag already...
//
2017-01-30 17:05:31 +01:00
$bits = preg_split('!</a>!i', $pre);
$last_bit = array_pop($bits);
if (preg_match("!<a\s!i", $last_bit)) {
2017-01-30 20:40:43 +01:00
//echo "fail 1 at $cursor<br />\n";
2017-01-30 17:05:31 +01:00
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
2017-01-30 20:40:43 +01:00
//
// check backwards
//
2017-01-30 17:05:31 +01:00
if ($ok) {
if (preg_match("!($atom(\.$atom)*)\$!", $pre, $matches)) {
2017-01-30 20:40:43 +01:00
// move matched part of address into $hit
2017-01-30 17:05:31 +01:00
$len = strlen($matches[1]);
$plen = strlen($pre);
2017-01-30 20:40:43 +01:00
$hit = substr($pre, $plen - $len).$hit;
$pre = substr($pre, 0, $plen - $len);
2017-01-30 17:05:31 +01:00
} else {
2017-01-30 20:40:43 +01:00
//echo "fail 2 at $cursor ($pre)<br />\n";
2017-01-30 17:05:31 +01:00
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
2017-01-30 20:40:43 +01:00
//
// check forwards
//
2017-01-30 17:05:31 +01:00
if ($ok) {
if (preg_match("!^($atom(\.$atom)*)!", $post, $matches)) {
2017-01-30 20:40:43 +01:00
// move matched part of address into $hit
2017-01-30 17:05:31 +01:00
$len = strlen($matches[1]);
2017-01-30 17:05:31 +01:00
$hit .= substr($post, 0, $len);
$post = substr($post, $len);
} else {
2017-01-30 20:40:43 +01:00
//echo "fail 3 at $cursor ($post)<br />\n";
2017-01-30 17:05:31 +01:00
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
2017-01-30 20:40:43 +01:00
//
// commit
//
2017-01-30 17:05:31 +01:00
if ($ok) {
$cursor += strlen($pre) + strlen($hit);
$buffer .= $pre;
$buffer .= "<a href=\"mailto:$hit\"$tagfill>$hit</a>";
}
}
2017-01-30 20:40:43 +01:00
//
// add everything from the cursor to the end onto the buffer.
//
2017-01-30 17:05:31 +01:00
$buffer .= substr($text, $cursor);
2017-01-30 17:05:31 +01:00
return $buffer;
}
2017-01-30 20:40:43 +01:00
//###################################################################;