I need to extract all links in a body of text in php and make them clickable. The problem is I can't seem to simplify the text of the link in any way.
I tried using preg_replace_callback but I can't seem to get the trimming function working properly:
function trimUrl($url){
$maxLength = 3;
if(strlen($url)>$maxLength){
$urlShort = substr($str,0,$maxLength).'...';
}
else{
$urlShort = $url;
}
return $urlShort;
}
function enableLinks($text){
return preg_replace_callback("!(((f|ht)tp(s)?://)[-a-zA-Zа-яА-Я()0-9#:%_+.~#?&;//=]+)!i", "<a href='$1' target='_blank'>".trimUrl("$1")."</a>", $text);
}
enableLinks("Visit more work at http://www.google.com");
How can I run a second function within the preg_replace_callback that trims the output text?
What if you used a function inside that function. So if the first function evaluates to true then run this next function? And also try using preg_replace_callback in a variable format so its easier to work with
First, you are using substring(). Where have you defined the variable $str? And, if you do this:
$var = preg_replace_callback("!(((f|ht)tp(s)?://)[-a-zA-Zа-яА-Я()0-9#:%_+.~#?&;//=]+)!i", "<a href='$1' target='_blank'>".trimUrl("$1")."</a>", $text);
Than can you use a new function:
return function($var);
Ended up using a more expanded function to achieve this, works on multiple urls with or without "http://":
function trimUrlOutput($url){
$maxLength = 30;
if(strlen($url)>$maxLength){
$urlShort = substr($url,0,$maxLength).'...';
}
else{
$urlShort = $url;
}
return $urlShort;
}
function enableLinks($text){
$text = ereg_replace( "www\.", "http://www.", $text );
$text = ereg_replace( "http://http://www\.", "http://www.", $text );
$text = ereg_replace( "https://http://www\.", "https://www.", $text );
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
if(preg_match_all($reg_exUrl, $text, $url)) {
$matches = array_unique($url[0]);
foreach($matches as $match) {
$linkText = trimUrlOutput($match);
$replacement = "<a href=".$match." target='_blank'>{$linkText}</a>";
$text = str_replace($match,$replacement,$text);
}
return $text;
}
else{
return $text;
}
}
enableLinks("Visit more work at http://www.google.com");
Hope this helps someone.
Related
I'm using the code given on this page to look through a string and turn the URL into an HTML link.
It works quite well, but there is a little issue with the "replace" part of it.
The problem occurs when I have almost identical links. For example:
https://example.com/page.php?goto=200
and
https://example.com/page.php
Everything will be fine with the first link, but the second will create a <a> tag in the first <a> tag.
First run
https://example.com/page.php?goto=200
Second
https://example.com/page.php?goto=200">https://example.com/page.php?goto=200</a>
Because it's also replacing the html link just created.
How do I avoid this?
<?php
function turnUrlIntoHyperlink($string){
//The Regular Expression filter
$reg_exUrl = "/(?i)\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/";
// Check if there is a url in the text
if(preg_match_all($reg_exUrl, $string, $url)) {
// Loop through all matches
foreach($url[0] as $newLinks){
if(strstr( $newLinks, ":" ) === false){
$link = 'http://'.$newLinks;
}else{
$link = $newLinks;
}
// Create Search and Replace strings
$search = $newLinks;
$replace = ''.$link.'';
$string = str_replace($search, $replace, $string);
}
}
//Return result
return $string;
}
?>
You need to add a whitespace identifier \s in your regex at the start, also remove \b because \b only returns the last match.
You regex can written as:
$reg_exUrl = "/(?i)\s((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/"
check this one: https://regex101.com/r/YFQPlZ/1
I have change the replace part a bit, since I couldn't get the suggested regex to work.
Maybe it can be done better, but I'm still learning :)
function turnUrlIntoHyperlink($string){
//The Regular Expression filter
$reg_exUrl = "/(?i)\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/";
// Check if there is a url in the text
if(preg_match_all($reg_exUrl, $string, $url)) {
// Loop through all matches
foreach($url[0] as $key => $newLinks){
if(strstr( $newLinks, ":" ) === false){
$url = 'https://'.$newLinks;
}else{
$url = $newLinks;
}
// Create Search and Replace strings
$replace .= ''.$url.',';
$newLinks = '/'.preg_quote($newLinks, '/').'/';
$string = preg_replace($newLinks, '{'.$key.'}', $string, 1);
}
$arr_replace = explode(',', $replace);
foreach ($arr_replace as $key => $link) {
$string = str_replace('{'.$key.'}', $link, $string);
}
}
//Return result
return $string;
}
I am setting up a new content plugin for Joomla 3, that should replace plugin tags with html content. Everything works fine till the moment when i am preg_replace plugin tags in $row->fulltext.
Here is the plugin code
public function onContentPrepare($context, &$row, &$params, $page = 0) {
$pattern = '#\{uni\}(.*){\/uni\}#sU';
preg_match_all($pattern, $row->fulltext, $matches, PREG_PATTERN_ORDER);
foreach($matches[1] as $k=>$uni){
preg_match('/\{uni-title\}(.*)[\{]/Ui', $uni, $unititle);
preg_match('/\{uni-text\}(.*)/si', $uni, $unitext);
$titleID = str_replace(' ', '_', trim($unititle[1]));
$newString = '<span id="'.$titleID.'">'.$unititle[1].'</span><div class="university-info-holder"><div class="university-info"><i class="icon icon-close"></i>'.$unitext[1].'</div></div>';
$row->fulltext = preg_replace($pattern,$newString,$row->fulltext);
}
}
Any ideas, why it duplicates first found match, as many times as foreach goes?
Just to mention, if i do:
echo $unititle[1];
inside foreach, items aren't duplicated, but are rendered as it should be.
There are a few problems with the original code.
It should be using $row->text instead of $row->fulltext. This is because when rendering an article Joomla merges tht introtext and fulltext fields.
It's a mistake to use $pattern for the matching when making the substitution. That's because the $pattern matches all of the items. Instead use the $match[0][$k] to do the replacement. Use str_replace instead of preg_replace because now you are matching the exact string and don't need to do a regex.
Here's the code for the whole thing.
class PlgContentLivefilter extends JPlugin{
public function onContentPrepare($context, &$row, &$params, $page = 0) {
return $renderUniInfo = $this->renderUniInfo($row, $params, $page = 0);
}
private function renderUniInfo(&$row, &$params, $page = 0) {
$pattern = '#\{uni\}(.*){\/uni\}#sU';
preg_match_all($pattern, $row->text, $matches);
foreach($matches[0] as $k=>$uni){
preg_match('/\{uni-title\}(.*)[\{]/Ui', $uni, $unititle);
preg_match('/\{uni-text\}(.*)/si', $uni, $unitext);
print_r($unititle[1]);
$title = $unititle[1];
$text = $unitext[1];
if (preg_match('#(?:http://)?(?:https://)?(?:www\.)?(?:youtube\.com/(?:v/|embed/|watch\?v=)|youtu\.be/)([\w-]+)?#i', $unitext[1], $match)) {
$video_id = $match[1];
$video_string = '<div class="videoWrapper"><iframe src="http://youtube.com/embed/'.$video_id.'?rel=0"></iframe></div>';
$unitext[1] = preg_replace('#(?:http://)?(?:https://)?(?:www\.)?(?:youtube\.com/(?:v/|embed/|watch\?v=)|youtu\.be/)([\w-]+)?#i', $video_string, $unitext[1]);
$text = $unitext[1];
}
$titleID = str_replace(' ', '_', trim($title));
$newString = '<span id="'.$titleID.'">'.$title.'</span><div class="university-info-holder"><div class="university-info"><i class="icon icon-close"></i>'.$text.'</div></div>';
$row->text = str_replace($matches[0][$k],$newString,$row->text);
}
}
}
String
"<p>This is </p><p>Stackoverflow</p><p>site for programmers</p>"
Required Output
"This is <p>Stackoverflow</p><p>site for programmers</p>"
Small function
function remove_p($string)
{
$first_p=substr($string,0,3);
$p="<p>";
if($first_p==$p)
{
$string=str_replace('<p>','',$string,$temp=1);
$string=str_replace('</p>','',$string,$temp=1);
}
return $string;
}
But it removes all the <p> </p> tags.Why so?
I am basically writing this to remove the first paragraph tags created by ckeditor.
str_replace acts on all occurrences of a substring, not just the first. You will want to use a different function.
$string = preg_replace('~<p>(.*?)</p>~is', '$1', $string, /* limit */ 1);
To only remove the first <p> and </p> if at the start of the string, add a ^ after the first /.
See also: Using str_replace so that it only acts on the first match?
function replaceFirst($input, $search, $replacement){
$pos = stripos($input, $search);
if($pos === false){
return $input;
}
else{
$result = substr_replace($input, $replacement, $pos, strlen($search));
return $result;
}
}
$string = "This is <p>Stackoverflow</p><p>site for programmers</p>";
echo $string;
echo replaceFirst($string, '<p>', '');
Output:
This is <p>Stackoverflow</p><p>site for programmers</p>
This is Stackoverflow</p><p>site for programmers</p>
Source: #2031045
Hope this helps!
$str = "This is <p>Stackoverflow</p><p>site for programmers</p>";
function remove_p($string)
{
$string=str_replace('<p>','',$string,$temp=1);
$string=str_replace('<\p>','',$string,$temp=1);
return $string;
}
echo(remove_p($str));
The result is:
This is Stackoverflow
site for programmers
Try using the method of this answer.
function remove_p($string)
{
return replaceFirst(replaceFirst($string, '<p>', ''), '</p>', '');
}
Or read about Regular Expressions.
I am trying to find the word and add a number next to it. How could he do? I tried with the code below, but I could not. Could anyone help me?
Thank you!
$string = 'I220ABCD I220ABCDEF I220ABCDEFG'
if (preg_match("/I220.*/", $string, $matches)) {
echo $matches[0];
}
Expected result:
I220ABCD9
I220ABCDEF10
I220ABCDEFG11
Use preg_replace_callback instead like this:
$str = 'I220AB FRRRR CD I221ABCDEF I220AB DSFDSF CDEFG';
$repl= preg_replace_callback('~(I220[^\s]+)~', function($m) {
static $i=9;
return $m[1] . $i++;
}, $str);
echo $repl\n"; // I220AB9 FRRRR CD I221ABCDEF I220AB10 DSFDSF CDEFG
I dont know what your requirnments for adding the number at the end are so i just incremeneted during the loop;
$string = 'I220ABCD I220ABCDEF I220ABCDEFG';
$arrayStrings = explode(" ", $string);
$int = 9;
$newString = '';
foreach($arrayStrings as $stringItem)
{
if (preg_match("/I220.*/", $stringItem, $matches))
{
$stringItem = $stringItem.$int;
$newString = $newString.$stringItem." ";
$int++;
}
}
echo $newString;
Use preg_replace_callback():
$string = 'I220ABCD I220ABCDEF I220ABCDEFG';
// This requires PHP5.3+ since it's using an anonymous function
$result = preg_replace_callback('/I220[^\s]*/', function($match){
return($match[0].rand(0,10000)); // Add a random number between 0-10000
}, $string);
echo $result; // I220ABCD3863 I220ABCDEF5640 I220ABCDEFG989
Online demo.
You'll need to use a catch block in your regex e.g. "/I220([^ ]+)/" and if you want them all, you'll need to use preg_match_all, too.
preg_replace_callback with your needs:
$string = 'I220ABCD I220ABCDEF I220ABCDEFG';
class MyClass{
private static $i = 9;
private static function callback($matches){
return $matches[0] . self::$i++;
}
public static function replaceString($string){
return preg_replace_callback('/I220[^\s]+/',"self::callback",$string);
}
}
echo(MyClass::replaceString($string));
of course you can edit to class to initialize the way you want
Based on a question I had answered here ( Use PHP to Replace HTML with HTML ), I'd like to be able to filter my output text for email addresses, and convert those text emails to "mailto" links.
Here's the PHP code that works, but only for converting some HTML to other HTML. What I've tried to do is have this function look for an email address, and convert it to a "mailto" link. For whatever reason, the code doesn't convert the email addresses. Here's my PHP:
function text_filter($string) {
$search = array('<p>__</p>', '/[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/');
$replace = array('<hr />', '$2');
$processed_string = str_replace($search, $replace, $string);
echo $processed_string;
}
When I use this function for output, this is what the code looks like:
<?php text_filter( get_the_content() ); ?>
str_replace() doesn't use regular expressions, rewritten with preg_replace().
Added delimiters to first matching expression.
Fixed replacement from $1 to $2.
function text_filter($string) {
$search = array('/<p>__<\/p>/', '/([a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})/');
$replace = array('<hr />', '$1');
$processed_string = preg_replace($search, $replace, $string);
echo $processed_string;
}
#Adam Baney - This will work even when used repeatedly.
// EMAILS
$str = preg_replace('~(^|[\s\.,;\n\(])([a-zA-Z0-9._+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})~',
'$1$2',
$str);
// PHONE NUMBERS
$str = preg_replace_callback('~(^|[\s\.,;\n\(])(?<! )([0-9 \+\(\)]{9,})~', function($m) {
return $m[1].''.$m[2].'';
}, $str);
You can't use str_replace to do a regular expression replace.
You will need to split the actions up.
function text_filter($string) {
$search = array('<p>__</p>');
$replace = array('<hr />');
$processed_string = str_replace($search, $replace, $string);
$processed_string = preg_replace('/[a-zA-Z0-9._-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/','$2',$processed_string);
echo $processed_string;
}
See: http://www.php.net/manual/en/function.preg-replace.php for preg replacing.
function obfuscate_email($content){
$pattern = '#([0-9a-z]([-_.]?[0-9a-z])*#[0-9a-z]([-.]?[0-9a-z])*\\.';
$pattern .= '[a-wyz][a-z](fo|g|l|m|mes|o|op|pa|ro|seum|t|u|v|z)?)#i';
$replacement = '\\1';
$content = preg_replace($pattern, $replacement, $content);
return $content;
}
And add filter
add_filter( 'the_content', 'obfuscate_email' );
Another way to do it in order so that it would work with existing html links in text:
function html_parse_text($text)
{
$text = preg_replace("/(?<!\")(((f|ht){1}tps?:\/\/)[-a-zA-Z0-9#:%_\+.~#?&\/\/=]+)/",
'<a href="\\1" target=_blank>\\1</a>', $text);
$text = preg_replace("/([[:space:]()[{}])(www.[-a-zA-Z0-9#:%_\+.~#?&\/\/=]+)/",
'\\1<a href="http://\\2" target=_blank>\\2</a>', $text);
$text = preg_replace("/(?<!\")([_\.0-9a-z-]+#([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3})/",
'<a href="mailto:\\1" target=_blank>\\1</a>', $text);
return $text;
}
Here is another version of this that seems to work for me. I've added + char to handle "plus addressing" (like some+email#address.com)
function replaceemail($text) {-
$ex = "/([a-zA-Z0-9._+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})/";
preg_match_all($ex, $text, $url);
foreach($url[0] as $k=>$v) $text = str_replace($url[0][$k], ''.$url[0][$k].'', $text);
return $text;
}