preg_match - what's wrong with this code? - php

$message contains two different Youtube videos. The code below works but the problem is that the end result produces two iframes with the same video ID (the first video). How can I solve this problem?
$message = 'This is a text with 2 Youtube videos: https://www.youtube.com/watch?v=rxwMjB-Skao csassasas http://www.youtube.com/watch?v=VWEwWECAokU Enf of text';
$reg_exUrl_youtube = "/(?:http(?:s)?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\?&\"'> \r\n]+)(?![^<]*>)/";
if (preg_match($reg_exUrl_youtube, $message, $youtubeUrlData) ) {
$message = preg_replace($reg_exUrl_youtube, "<iframe title=\"{$youtubeUrlData[1]}\" class=\"youtube\" src=\"[qqqqq].youtube.com/embed/{$youtubeUrlData[1]}\" frameborder=\"0\" allowFullScreen></iframe>", $message);
}

1) The fix for your code is to use $1 instead of {$youtubeUrlData[1]} in the preg_replace() call:
$message = preg_replace($reg_exUrl_youtube, "<iframe title=\"$1\" class=\"youtube\" src=\"[qqqqq].youtube.com/embed/$1\" frameborder=\"0\" allowFullScreen></iframe>", $message);
2) Another implementation with preg_replace_callback(), which is very reliable from my experience, just as an example:
$message = 'This is a text with 2 Youtube videos: https://www.youtube.com/watch?v=rxwMjB-Skao csassasas http://www.youtube.com/watch?v=VWEwWECAokU Enf of text';
$reg_exUrl_youtube = "/(?:http(?:s)?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^\?&\"'> \r\n]+)(?![^<]*>)/";
$finalString = preg_replace_callback($reg_exUrl_youtube, function($matches) {
return "<iframe title=\"{$matches[1]}\" class=\"youtube\" src=\"[qqqqq].youtube.com/embed/{$matches[1]}\" frameborder=\"0\" allowFullScreen></iframe>";
}, $message);
echo htmlentities($finalString);

Why use an error prone regex?
Much simpler:
$message = 'This is a text with 2 Youtube videos: https://www.youtube.com/watch?v=rxwMjB-Skao csassasas http://www.youtube.com/watch?v=VWEwWECAokU Enf of text';
$a=explode(' ',$message);
foreach($a as $v){
if(strpos($v,'http')!==false && strpos($v,'youtube')!==false){
$res[]=$v;
}
}
echo var_dump($res);

Related

YouTube embedded video issue

I want to embed the YouTube video on my website. The problem is with timeline and origin link properties. For example, I have some text and 2 bbCode video tags, one with timeline and 2nd without timeline:
This is just a test example.
[youtube]https://www.youtube.com/watch?v=xHLE2LTAItw&t=53s[/youtube]
[youtube]https://www.youtube.com/watch?v=xHLE2LTAItw[/youtube]
Code:
if (preg_match_all("/\[youtube\]((\s|.)+?)\[\/youtube\]/i", $text, $matches)) {
$allMatches = count($matches[0]);
if (is_array($matches[0]) && $allMatches > 0) {
for ($i = 0; $i < $allMatches; $i++) {
$text = str_replace("watch?v=", "embed/", $text);
if (strpos($matches[0][$i], "&t=") !== false) {
$text = str_replace("&t=", "?start=", $text);
$text = preg_replace("#s\[\/youtube\]#i", "&enablejsapi=1&origin=". HAZELFENCES_WEBSITE ."[/youtube]", $text);
} else {
$text = preg_replace("#\[\/youtube\]#i", "?enablejsapi=1&origin=". HAZELFENCES_WEBSITE ."[/youtube]", $text);
}
}
$text = preg_replace("/\[youtube\]((\s|.)+?)\[\/youtube\]/i", "<iframe width=\"640\" height=\"510\" src=\"\\1\" loading=\"lazy\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>", $text);
}
}
return $text;
The iframe src from the first video returns as: src="https://www.youtube.com/embed/xHLE2LTAItw?start=53&enablejsapi=1&origin=https://test.com?enablejsapi=1&origin=https://test.com" which is wrong. It should be:
https://www.youtube.com/embed/xHLE2LTAItw?start=53&enablejsapi=1&origin=https://test.com
The video link without timeline must be:
https://www.youtube.com/embed/xHLE2LTAItw?enablejsapi=1&origin=https://test.com, which is correct using my code. The only issue is with timeline videos.
Please note, this issue is only occurs when 2 video links are available. One with timeline and the second one without timeline.
For example: https://3v4l.org/JTAUp
Any ideas how to fix it? Thank you.
Ok. It's a bit tricky but I have finally fixed it by using RegExp and preg_replace function. First of all, I have checked for the video link with timeline and then preg_replace the &t=00s[/youtube] with ?start=\\1&enablejsapi=1&origin=". HAZELFENCES_WEBSITE.
Secondly, I checked for the video without timeline and preg_replace the /embed/xHLE2LTAItw[/youtube] with /\\1\\2?enablejsapi=1&origin=". HAZELFENCES_WEBSITE ."[/youtube].
My code:
$text = str_replace("watch?v=", "embed/", $text);
$isVideoWithTimeline = preg_match("#\[youtube\](http|https):\/\/www\.youtube\.com\/([a-z]+\?v=|[a-z]+\/)[a-zA-Z0-9]+(&|&[a-zA-Z]+;)[a-zA-Z]=\d+s\[\/youtube\]#si", $text);
if ($isVideoWithTimeline > 0) {
$text = preg_replace("#&t=([0-9]+)s\[\/youtube\]#si", "?start=\\1&enablejsapi=1&origin=". HAZELFENCES_WEBSITE ."[/youtube]", $text);
}
$isVideoWithoutTimeline = preg_match("#\[youtube\](http|https):\/\/www\.youtube\.com\/([a-z]+\?v=|[a-z]+\/)[a-zA-Z0-9]+\[\/youtube\]#si", $text);
if ($isVideoWithoutTimeline > 0) {
$text = preg_replace("#/([a-z]+\?v=|[a-z]+\/)([a-zA-Z0-9]+)\[\/youtube\]#si", "/\\1\\2?enablejsapi=1&origin=". HAZELFENCES_WEBSITE ."[/youtube]", $text);
}
$text = preg_replace("/\[youtube\]((\s|.)+?)\[\/youtube\]/i", "<iframe width=\"640\" height=\"510\" src=\"\\1\" loading=\"lazy\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>", $text);
return $text;
Now, everything works well. The issue is resolved.

Regular expressions in PHP / find "<a> </a>"

I want to check a textarea. If the user enter some links in the textarea, php should automatically tag the links. I'm using this code:
$message = "text with some link within";
$url = '#(?!<a[^>]*?>)(http)?(s)?(://)?(([a-zA-Z])([-\w]+\.)+([^\s\.]+[^\s]*)+[^,.\s])(?![^<]*?</a>)#';
if(preg_match($url, $message) == 1){
$message = preg_replace($url, '$0', $message);
}
The problem is, when there's already a tagged link (with an "a" tag), regex is destroying the link.
Here is an example:
first input from textarea: Hello .... test.com
changed by regex: Hello ... test.com
this is working fine, but if you update this:
Hello ... http://test.com" target="_blank" rel="nofollow" title="test.com" target="_blank" rel="nofollow" title="test.com">test.com">test.com">test.com
Thanks for your help!
I'm not familiar with PHP and maybe this is not a good pattern for url validation, but the point is if there is already an "a" tag, the text is not replaced.
<?php
$message = array(
'Hello ... test.com',
"Hello .... http://www.test.com ..."
);
$url = '#(<a[^>]*>[^<]+</a>|((https?://)?[\w\.-]+\.[a-zA-Z]{2,3}[^\s\W]*))#';
foreach ($message as $msg) {
preg_match($url, $msg, $matches);
if(preg_match($url, $msg) == 1 && count($matches) > 2) {
$msg = preg_replace($url, '$0', $msg);
}
echo $msg.PHP_EOL;
}
// Output:
// Hello ... test.com
// Hello .... http://www.test.com ...
Hope it helps.

Regex - BBCode for Youtube tag

<?php
function convertYoutube($string) {
return preg_replace(
"/\s*[a-zA-Z\/\/:\.]*youtu(be.com\/watch\?v=|.be\/)([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i",
"<iframe width=\"420\" height=\"315\" src=\"//www.youtube.com/embed/$2\" allowfullscreen></iframe>",
$string
);
}
$text = "Youtube long url: https://www.youtube.com/watch?v=waIkasvAVGo\n\nYoutube short url: http://youtu.be/waIkasvAVGo";
echo convertYoutube($text);
I found this code on this site:
http://syframework.alwaysdata.net/convert-youtube-url-to-iframe.
The script works just fine. But want this just to work within a BBcode.
For example: [YouTube]<url>[/YouTube].
Does anyone have suggestions to how this can be resolved?
Try this:
<?php
function convertYoutube($string) {
return preg_replace(
"/\[youtube\]\s*[a-zA-Z\/\/:\.]*youtu(be.com\/watch\?v=|.be\/)([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)\[\/youtube\]/i",
"<iframe width='420' height='315' src='//www.youtube.com/embed/$2' allowfullscreen></iframe>",
$string
);
}
$text = "Youtube long url: [youtube]https://www.youtube.com/watch?v=waIkasvAVGo[/youtube]\n\nYoutube short url: [youtube]http://youtu.be/waIkasvAVGo[/youtube]";
echo convertYoutube($text);
?>

PHP preg_replace multiple url replaces

Hey I am trying to do 2 preg_replace:
1.make all urls to html links
2.make all images url to html img tag
But these regexs cancel the other one
<?php
// The Regular Expression filter
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
$reg_exImg = "!http://[a-z0-9\-\.\/]+\.(?:jpe?g|png|gif)!Ui";
// The Text you want to filter for urls
$text = "The text you want to filter goes here. http://google.comhttp://www.ynet.co.il http://dogsm.files.wordpress.com/2011/12/d7a1d7a7d795d791d799-d793d795.jpg";
// Check if there is a url in the text
$text = preg_replace($reg_exImg, '<img src=$0 >', $text);
$text = preg_replace($reg_exUrl, '$0', $text);
echo $text;
?>
How can I make that the preg_replace that make url to links dont do this to the tag?
Thanks.
Haim
This might be better as a callback.
Use just the $reg_exUrl, and do this:
$text = preg_replace_callback($reg_exUrl,function($m) {
if( preg_match("/\.(?:jpe?g|png|gif)$/i",$m[0])) {
return "<img src='".$m[0]."' />";
}
else {
return "<a href='".$m[0]."' rel='nofollow'>".$m[0]."</a>";
}
},$text);

php script to recognize text from link

I was trying to create a script in php, for displaying messages. If the messages includes a web address, then this address I wanted to be displayed as a link. This is my code that works successfuly:
<?php
if( (substr( $message, 0, 8 ) === "https://") || (substr( $message, 0, 7 ) === "http://") ){
echo "<a href='$message' target='_blank'> $message </a>";
}else{
echo " $message ";
}
?>
It is working perfect if the user inserts in message a web address only like: "http://google.com" The problem starts if the users inserts a text before or after the web address. For example if writes: "visit http://google.com site" then it is making all the phrase as a link and it does not recognises the words with the web address. Any idea how to fix this problem?
You may use filter_var with FILTER_VALIDATE_URL:
$words = explode(" ", $message);
$_words = array();
foreach($words as $word){
if(filter_var($word, FILTER_VALIDATE_URL) === false){
$_words[] = $word;
}
else{
$_words[] = "$word";
}
}
echo implode(" ", $_words);
Demo: http://phpfiddle.org/main/code/mu8-vg5
I use this within a class:
public static function CreateLinks($text) {
return preg_replace('#(https?://([-\w.]+[-\w])+(:\d+)?(/([\w-.~:/?#\[\]\#!$&\'()*+,;=%]*)?)?)#', '$1', $text);
}
To use it without a class, do this:
$message = preg_replace('#(https?://([-\w.]+[-\w])+(:\d+)?(/([\w-.~:/?#\[\]\#!$&\'()*+,;=%]*)?)?)#', '$1', $message);
So in a test case this:
$message = "Hello, take a look at http://www.google.com or wait! Maybe you where looking for http://www.bing.com";
$message = preg_replace('#(https?://([-\w.]+[-\w])+(:\d+)?(/([\w-.~:/?#\[\]\#!$&\'()*+,;=%]*)?)?)#', '$1', $message);
echo $message;
Will output:
Hello, take a look at http://www.google.com or wait! Maybe you where looking for http://www.bing.com
So, at the end your code can be replaced by just one single line! Replace this:
if( (substr( $message, 0, 8 ) === "https://") || (substr( $message, 0, 7 ) === "http://") ){
echo "<a href='$message' target='_blank'> $message </a>";
}else{
echo " $message ";
}
by this:
$message = preg_replace('#(https?://([-\w.]+[-\w])+(:\d+)?(/([\w-.~:/?#\[\]\#!$&\'()*+,;=%]*)?)?)#', '$1', $message);
Jan Goyvaerts, Regex Guru, describe pretty well in his blog
http://www.regexguru.com/2008/11/detecting-urls-in-a-block-of-text/
To find all matches in a multi-line string, use
preg_match_all('/\b(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)[-A-Z0-9+&##\/%=~_|$?!:,.]*[A-Z0-9+&##\/%=~_|$]/i', $subject, $result, PREG_PATTERN_ORDER);
$result = $result[0];
you can use preg_match function to get single match

Categories