Проблема с регулярным выражением для кода комментариев - PullRequest
1 голос
/ 22 июня 2010

В настоящее время я делаю домашнюю страницу, на которой вошедшие в систему пользователи могут оставлять комментарии. Строка комментария сначала запускается через функцию str_replaces emoticons. После этого я хочу обменять

[url=www.whatever.com]linktext[/url]

с:

<a href='www.whatever.com'>linktext</a>

Причина этого заключается в том, что я хочу удалить текст для всего HTML-кода, который не контролируется моим кодом комментария, на случай, если некоторые пользователи решат проявить творческий подход -

и подумал, что было бы лучше использовать preg replace, но код, которым я закончил (частично из чтения о reg exp из моей верной книги "O reilly Sql and Php" и частично из Интернета), довольно помешан самое главное, не работает.

Любая помощь будет оценена, спасибо.

Возможно, возможно обменяться всем кодом, а не двумя сегментами, как я это сделал. Просто решил, что сначала будет легче заставить работать две меньшие детали, а затем объединить их.

код:

function text_format($string)
{
    $pattern="/([url=)+[a-zA-Z0-9]+(])+/";
    $string=preg_replace($pattern, "/(<a href=\')+[a-zA-Z0-9]+(\'>)+/", $string);
    $pattern="/([\/url])+/";
    $string=preg_replace($pattern, "/(<\/a>)+/", $string);    
    return $string;
}

Ответы [ 3 ]

4 голосов
/ 22 июня 2010

Похоже, вы используете что-то похожее на BBCode.Почему бы не использовать синтаксический анализатор BBCode, такой как этот?

http://nbbc.sourceforge.net/

Он также обрабатывает смайлики, заменяя их изображениями.Если вы используете их тестовую страницу, вы все равно увидите текст, потому что они не размещают изображения и устанавливают для alt-text текст smily.

2 голосов
/ 22 июня 2010

@ Ответ Лаури Лехтинена хорош для изучения идеи, лежащей в основе этой техники, но вы не должны использовать ее на практике, поскольку это сделает ваш сайт чрезвычайно уязвимым для атак XSS. Кроме того, спаммеры по ссылкам оценят отсутствие rel="nofollow" в сгенерированных ссылках.

Вместо этого используйте что-то вроде:

<?php
// \author Daniel Trebbien
// \date 2010-06-22
// \par License
//  Public Domain

$allowed_uri_schemes = array('http', 'https', 'ftp', 'ftps', 'irc', 'mailto');

/**
 * Encodes a string in RFC 3986
 *
 * \see http://tools.ietf.org/html/rfc3986
 */
function encode_uri($str)
{
    $str = urlencode('' . $str);
    $search = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%3B', '%3D', '%2E', '%7E');
    $replace = array(':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', '.', '~'); // gen-delims / sub-delims / unreserved
    return str_ireplace($search, $replace, $str);
}

function url_preg_replace_callback($matches)
{
    global $allowed_uri_schemes;

    if (empty($matches[1]))
        return $matches[0];
    $href = trim($matches[1]);
    if (($i = strpos($href, ':')) !== FALSE) {
        if (strrpos($href, '/', $i) === FALSE) {
            if (!in_array(strtolower(substr($href, 0, $i)), $allowed_uri_schemes))
                return $matches[0];
        }
    }

    // unescape `\]`, `\\\]`, `\\\\\]`, etc.
    for ($j = strpos($href, '\\]'); $j !== FALSE; $j = strpos($href, '\\]', $j)) {
        for ($i = $j - 2; $i >= 0 && $href[$i] == '\\' && $href[$i + 1] == '\\'; $i -= 2)
            /* empty */;
        $i += 2;

        $h = '';
        if ($i > 0)
            $h = substr($href, 0, $i);
        for ($numBackslashes = floor(($j - $i)/2); $numBackslashes > 0; --$numBackslashes)
            $h .= '\\';
        $h .= ']';
        if (($j + 2) < strlen($href))
            $h .= substr($href, $j + 2);
        $href = $h;
        $j = $i + floor(($j - $i)/2) + 1;
    }

    if (!empty($matches[2]))
        $href .= str_replace('\\\\', '\\', $matches[2]);

    if (empty($matches[3]))
        $linkText = $href;
    else {
        $linkText = trim($matches[3]);
        if (empty($linkText))
            $linkText = $href;
    }
    $href = htmlspecialchars(encode_uri(htmlspecialchars_decode($href)));
    return "<a href=\"$href\" rel=\"nofollow\">$linkText</a>";
}

function render($input)
{
    $input = htmlspecialchars(strip_tags('' . $input));
    $input = preg_replace_callback('~\[url=((?:[^\]]|(?<!\\\\)(?:\\\\\\\\)*\\\\\])*)((?<!\\\\)(?:\\\\\\\\)*)\]' . '((?:[^[]|\[(?!/)|\[/(?!u)|\[/u(?!r)|\[/ur(?!l)|\[/url(?!\]))*)' . '\[/url\]~i', 'url_preg_replace_callback', $input);
    return $input;
}

который я считаю безопасным против XSS. Эта версия имеет дополнительное преимущество, заключающееся в том, что можно писать ссылки на URL-адреса, содержащие ']'.

Оцените этот код с помощью следующего "набора тестов":

echo render('[url=http://www.bing.com/][[/[/u[/ur[/urlBing[/url]') . "\n";
echo render('[url=][/url]') . "\n";
echo render('[url=http://www.bing.com/][[/url]') . "\n";
echo render('[url=http://www.bing.com/][/[/url]') . "\n";
echo render('[url=http://www.bing.com/][/u[/url]') . "\n";
echo render('[url=http://www.bing.com/][/ur[/url]') . "\n";
echo render('[url=http://www.bing.com/][/url[/url]') . "\n";
echo render('[url=http://www.bing.com/][/url][/url]') . "\n";
echo render('[url=    javascript: window.alert("hi")]click me[/url]') . "\n";
echo render('[url=#" onclick="window.alert(\'hi\')"]click me[/url]') . "\n";
echo render('[url=http://www.bing.com/]       [/url]') . "\n";
echo render('[url=/?#[\\]@!$&\'()*+,;=.~]       [/url]') . "\n"; // link text should be `/?#[]@!$&amp;'()*+,;=.~`
echo render('[url=http://localhost/\\\\]d]abc[/url]') . "\n"; // href should be `http://localhost/%5C`, link text should be `d]abc`
echo render('[url=\\]][/url]') . "\n"; // link text should be `]`
echo render('[url=\\\\\\]][/url]') . "\n"; // link text should be `\]`
echo render('[url=\\\\\\\\\\]][/url]') . "\n"; // link text should be `\\]`
echo render('[url=a\\\\\\\\\\]bcde\\]fgh\\\\\\]ijklm][/url]') . "\n"; // link text should be `a\\]bcde]fgh\]ijklm`

Или просто посмотрите на результаты Codepad .

Как видите, это работает.

2 голосов
/ 22 июня 2010

Я немного поэкспериментировал со следующим:

function text_format($string)
{
    return preg_replace('#\[url=([^\]]+)\]([^\[]*)\[/url\]#', '<a href="$1">$2</a>', $string);
}

Однако одна немедленная ошибка в том, что если linktext пусто, между <a> и </a> не будет ничего.Одним из способов обойти это было бы сделать еще один проход с чем-то вроде этого:

preg_replace('#<a href="([^"]+)"></a>#', '<a href="$1">$1</a>', $string);

Другой вариант - использовать preg_replace_callback и поместить эту логику в функцию обратного вызова.

Наконец, это, очевидно, распространенная «проблема», и ее неоднократно решали другие, и если вариант с более зрелым открытым исходным кодом является вариантом, я бы порекомендовал поискать его.

...