2010-06-21 63 views
1

我目前正在登錄的用戶可以寫評論的主頁。註釋字符串首先通過str_replaces表情符號的函數運行。從那以後,我希望它來交換評論代碼的正則表達式的問題

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

有:

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

這樣做的原因是,我想要去除的文本不是由我的註釋代碼控制的所有HTML代碼,以防某些用戶決定獲得創意 -

並認爲最好使用preg替換,但代碼我結束了(部分原因是從我可靠的「O reilly Sql和Php」書中讀取了關於reg exp的內容,以及部分來自網絡)是相當瘋狂的,最重要的是,它不起作用。

任何幫助,將不勝感激,謝謝。

它可能可以交換整個代碼,而不是像我所做的那樣在2段中交換。只是決定讓兩個較小的零件先工作會更容易,然後再合併它們。

代碼:

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; 
} 
+1

這完全不能回答你的問題,但你真的可能想看看現有的工具,像[Markdown](http://daringfireball.net/projects/markdown/)(SO使用的格式),而不是滾動你自己 – 2010-06-21 22:14:03

+1

我不認爲你可以通過[a-zA-Z0-9]匹配一個網址,那麼像 - ,/,&,:,#,這樣的字符怎麼樣?等等...... – cypher 2010-06-21 22:19:18

回答

2

我嘗試了一下有以下幾點:

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,並把這個邏輯你的回調函數內。

最後,這顯然是一個常見的「問題」,並已被其他人解決了很多次,如果使用更成熟的開源解決方案是一種選擇,我建議尋找一個。

+0

非常感謝您的快速回答。 Reg exp對於noob來說真的很混亂,並且無論經過多年的編程經驗,可能仍然會感到困惑。我的大腦只是通過觀察支架的質量而融化:) 你是上帝,代碼的作用像一個魅力,非常感謝你的幫助。 – Rakoon 2010-06-21 22:25:56

+1

@Rakoon - 不需要對我們有宗教信仰。我認爲經驗在這裏扮演一個小角色。 :) – ChaosPandion 2010-06-21 22:29:53

+0

是的。但是,在絞盡腦汁想了很長一段時間之後,對於一個棘手的問題(對於一個noob)來說,一個直接的,聰明的答案讓我只是有點虔誠地傾向於:) – Rakoon 2010-06-21 22:37:15

4

看起來你正在使用類似於BBCode的東西。爲什麼不使用BBCode解析器,比如這個?

http://nbbc.sourceforge.net/

它也處理的笑臉,用圖片替換它們。如果你使用他們的測試頁面,你仍然會看到文本,因爲他們沒有託管這些圖像,他們很快地設置了alt-text。

+0

嗯。一個好主意,但我得到的解析工作,並不需要超過一些簡單的格式選項。表情符號是自定義的,並且嵌入到我製作的主題系統中,以便人們可以擁有獨立於主題的表情。 無論如何,感謝您的答案。 – Rakoon 2010-06-21 22:28:36

2

@Lauri Lehtinen的回答對於瞭解該技術背後的想法很有幫助,但是您不應該在實踐中使用它,因爲這會讓您的網站極易受到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 results

正如你所看到的,它的工作原理。

+0

你好,謝謝你的回覆。這可能不是我正在編寫的頁面的問題,因爲它是一個Web應用程序,用戶可以在其中更改內容並添加和刪除畫廊或博客文章。但是,用戶是由超級管理員指定的人員,因此人們無法註冊並獲得評論。 如果我決定擴展模型以允許註冊,這將成爲一個更大的問題。 O reilly書中提到了剝離標籤和我相信的東西叫做real_escape_string,它可以保留文本。 在此之後,人們仍然可以寫出有害的文字,還是允許它的鏈接形式? – Rakoon 2010-06-22 11:24:06

+0

@Rakoon:'mysql_real_escape_string'和變體用於防止稱爲* SQL注入*的不同類別的攻擊。同樣糟糕,但不同。此代碼用於轉義文本以防止XSS。逃避一切總是好事,因爲你應該假定所有的用戶輸入都是不好的,即使它來自「可信用戶」。例如,如果一個黑客設法獲得一個可信用戶的登錄證書,那麼該怎麼辦?使用'render'函數使所有「代碼」 - 使註釋和博客文章安全。 – 2010-06-22 14:58:23

+0

我必須承認,我對於瞭解整個代碼仍然有些笨拙。例如,是否可以用「」代替「javascript:」?或者這是否意味着黑客使用瞭解決方法?我的印象是,大多數在本頁面上回答我的問題的嚮導可能會在幾秒鐘內破解我的網站,無論如何。 我應該嘗試閱讀您使用的不同代碼以嘗試變得更加開明。 基本上我應該使用EscapeShellArg和真正的逃脫,然後做一個XSS不相容? – Rakoon 2010-06-22 16:37:43