как найти ссылки только на изображения в строке и связать их

#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. Спасибо за вашу помощь, я создал рабочий код, который работает со многими ссылками на изображения 🙂