#php #regex
#php #регулярное выражение
Вопрос:
У меня есть этот код: https://gist.github.com/jasny/2000705 Как мне изменить его, чтобы он работал только со ссылками, которые заканчиваются на jpg, gif, bmp и т.д.?
Исходный код:
<?php
/**
* Turn all URLs in clickable links.
*
* @param string $value
* @param array $protocols http/https, ftp, mail, twitter
* @param array $attributes
* @param string $mode normal or all
* @return string
*/
public function linkify($value, $protocols = array('http', 'mail'), array $attributes = array())
{
// Link attributes
$attr = '';
foreach ($attributes as $key => $val) {
$attr = ' ' . $key . '="' . htmlentities($val) . '"';
}
$links = array();
// Extract existing links and tags
$value = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (amp;$links) { return '<' . array_push($links, $match[1]) . '>'; }, $value);
// Extract text links for each protocol
foreach ((array)$protocols as $protocol) {
switch ($protocol) {
case 'http':
case 'https': $value = preg_replace_callback('~(?:(https?)://([^s<] )|(www.[^s<] ?.[^s<] ))(?<![.,:])~i', function ($match) use ($protocol, amp;$links, $attr) { if ($match[1]) $protocol = $match[1]; $link = $match[2] ?: $match[3]; return '<' . array_push($links, "<a $attr href="$protocol://$link">$link</a>") . '>'; }, $value); break;
case 'mail': $value = preg_replace_callback('~([^s<] ?@[^s<] ?.[^s<] )(?<![.,:])~', function ($match) use (amp;$links, $attr) { return '<' . array_push($links, "<a $attr href="mailto:{$match[1]}">{$match[1]}</a>") . '>'; }, $value); break;
case 'twitter': $value = preg_replace_callback('~(?<!w)[@#](w )~', function ($match) use (amp;$links, $attr) { return '<' . array_push($links, "<a $attr href="https://twitter.com/" . ($match[0][0] == '@' ? '' : 'search/#') . $match[1] . "">{$match[0]}</a>") . '>'; }, $value); break;
default: $value = preg_replace_callback('~' . preg_quote($protocol, '~') . '://([^s<] ?)(?<![.,:])~i', function ($match) use ($protocol, amp;$links, $attr) { return '<' . array_push($links, "<a $attr href="$protocol://{$match[1]}">{$match[1]}</a>") . '>'; }, $value); break;
}
}
// Insert all link
return preg_replace_callback('/<(d )>/', function ($match) use (amp;$links) { return $links[$match[1] - 1]; }, $value);
}
Ответ №1:
Вы можете добавить еще один вызываемый аргумент $allowed_types
, который содержит все расширения, которые вы хотите разрешить.
Затем вы должны получить подстроку после последнего символа ‘.’ и сравнить ее с вашим списком разрешенных расширений.
Это основная идея, я уверен, что ее можно значительно улучшить.
/**
* Turn all URLs in clickable links.
*
* @param string $value
* @param array $protocols http/https, ftp, mail, twitter
* @param array $attributes
* @param string $mode normal or all
* @return string
*/
function linkify($value, $allowed_types = array('jpg', 'png'), $protocols = array('http', 'mail'), array $attributes = array()) {
/**
* Get position of last dot in string
*/
$dot_pos = strrpos($value, '.');
if(!$dot_pos) {
return FALSE;
}
/**
* Get substring after last dot
*/
$extension = substr($value, $dot_pos 1);
if(!in_array($extension, $allowed_types)) {
/**
* Extension not in allowed types
*/
return FALSE;
}
// Link attributes
$attr = '';
foreach ($attributes as $key => $val) {
$attr = ' ' . $key . '="' . htmlentities($val) . '"';
}
$links = array();
// Extract existing links and tags
$value = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (amp;$links) {
return '<' . array_push($links, $match[1]) . '>';
}, $value);
// Extract text links for each protocol
foreach ((array) $protocols as $protocol) {
switch ($protocol) {
case 'http':
case 'https': $value = preg_replace_callback('~(?:(https?)://([^s<] )|(www.[^s<] ?.[^s<] ))(?<![.,:])~i', function ($match) use ($protocol, amp;$links, $attr) {
if ($match[1])
$protocol = $match[1];
$link = $match[2] ? : $match[3];
return '<' . array_push($links, "<a $attr href="$protocol://$link">$link</a>") . '>';
}, $value);
break;
case 'mail': $value = preg_replace_callback('~([^s<] ?@[^s<] ?.[^s<] )(?<![.,:])~', function ($match) use (amp;$links, $attr) {
return '<' . array_push($links, "<a $attr href="mailto:{$match[1]}">{$match[1]}</a>") . '>';
}, $value);
break;
case 'twitter': $value = preg_replace_callback('~(?<!w)[@#](w )~', function ($match) use (amp;$links, $attr) {
return '<' . array_push($links, "<a $attr href="https://twitter.com/" . ($match[0][0] == '@' ? '' : 'search/#') . $match[1] . "">{$match[0]}</a>") . '>';
}, $value);
break;
default: $value = preg_replace_callback('~' . preg_quote($protocol, '~') . '://([^s<] ?)(?<![.,:])~i', function ($match) use ($protocol, amp;$links, $attr) {
return '<' . array_push($links, "<a $attr href="$protocol://{$match[1]}">{$match[1]}</a>") . '>';
}, $value);
break;
}
}
// Insert all link
return preg_replace_callback('/<(d )>/', function ($match) use (amp;$links) {
return $links[$match[1] - 1];
}, $value);
}
Комментарии:
1. кстати, я только что понял, что это будет работать только с одной ссылкой, если у меня было две ссылки на изображения в строке, она будет перехватывать только вторую, поскольку она ищет последнюю точку в строке. Есть идеи, как обойти это?
2. Вы разбиваете большую ссылку на основные ссылки и запускаете ее через ту же функцию. Эта логика будет лучше вне вышеуказанной функции.
3. Спасибо за вашу помощь, я создал рабочий код, который работает со многими ссылками на изображения 🙂