2014-05-08 69 views
3

我正在嘗試編寫一個MySQL搜索函數,它可以生成一個動態sql值並通過預處理語句執行它。很顯然,我想通過一個參數傳遞用戶輸入(搜索詞)的安全性,但我不知道如何匹配一個參數到多個?在查詢中標記。可能是最好的說明我的意思:MySQL存儲過程準備好的語句(動態SQL)參數化

CREATE DEFINER=`admin`@`localhost` PROCEDURE `WEBSITE_mainSearch`(
IN searchWordIn VARCHAR(128) 
) 
BEGIN 
DECLARE articlesModule BIT; 
SET @query = ''; 
SET @searchWordIn = searchWordIn; 
SELECT articlesModuleEnabled INTO articlesModule FROM sys_options WHERE ID = 1; 
SET @query = CONCAT(@query, 'SELECT blockName AS itemName, blockPath AS seoName, blockID AS itemID, MATCH(blockName, blockBody) AGAINST (?) AS relevance, \'block\' AS itemType FROM content_blocks WHERE MATCH(blockName, blockBody) AGAINST (?)') ; 
IF articlesModule = 1 THEN 
    SET @query = CONCAT(@query, 'UNION SELECT articleName AS itemName, seoName, articleID AS itemID, MATCH(articleName, articleBody) AGAINST (?) AS relevance, \'article\' AS itemType FROM news_articles WHERE MATCH(articleName, articleBody) AGAINST (?)') ; 
END IF; 
PREPARE stmt FROM @query; 


EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn; 


DEALLOCATE PREPARE stmt; 
END 

由於S的數量要動態的基礎上確定哪些模塊啓用了下去,我怎麼知道有多少時間在這個語句發送searchWordIn作爲參數EXECUTE stmt使用searchWordIn;

謝謝!

回答

5

EXECUTE聲明必須給出的參數固定的列表,所以你必須準備IF/THEN/ELSE塊執行該語句。

IF articlesModule = 1 THEN 
    SET @query = ... UNION ... 
    PREPARE stmt FROM @query; 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn; 
ELSE 
    SET @query = ...; /* no UNION */ 
    PREPARE stmt FROM @query; 
    EXECUTE stmt USING @searchWordIn, @searchWordIn; 
END IF; 

我不知道在MySQL存儲過程語言的有限範圍內解決這個問題的方法。對我來說,這不是在存儲過程中使用動態SQL的另一個好理由。


回覆您的意見:

我不能做上述建議 - 我使用的系統具有約7個模塊。

我看看......你可以使用一個CASE statement代替IF/THEN/ELSE,但實際上你有查詢字符串2 = 128條不同的情況,因爲我假定這7個模塊的既可以被搜索或不。

,將允許您使用的查詢參數的選擇是忘記使用UNION,而是寫在運行長達7個獨立SELECT查詢並返回所有的人都爲多個結果集這樣的過程。這是存儲過程打算做的事情。但是你必須在你的PHP層編寫代碼來輪流獲取每個結果集。也就是說,循環遍歷結果集,並在該循環內循環遍歷當前結果集的行。請參閱PDO::nextRowset()mysqli::next_result()上的示例。

我認爲我很安全簡單地串聯搜索詞中的動態SQL

不,你如果你這樣做不是安全!在PHP中使用查詢參數將字符串傳遞給CALL WEBSITE_mainSearch(?)對於防止SQL注入是沒有用的,如果您然後將該參數值連接到過程中的另一個字符串並執行動態SQL分析並執行。使用查詢參數不會使參數值「安全」,它們只是將這些值從SQL分析階段中分離出來。

如果在連接字符串時使用MySQL的內置函數QUOTE(),則更安全。 QUOTE()確實會轉義特殊字符,就像mysql_real_escape_string()一樣。除了略有不同,因爲它也會產生分隔字符串的單引號,就像PDO::quote()一樣。

SET @query = CONCAT(@query, 'SELECT blockName AS itemName, blockPath AS seoName, 
    blockID AS itemID, MATCH(blockName, blockBody) AGAINST (', 
    QUOTE(searchWordIn), ') AS relevance, \'block\' AS itemType 
    FROM content_blocks WHERE MATCH(blockName, blockBody) AGAINST (', 
    QUOTE(searchWordIn),')') ; 

更新:多了一個選擇:用UNION添加更多的子查詢,並保持模塊的數量。然後使用CASE根據累計計數使用不同數量的參數執行準備好的查詢。

SET @n = 0; 
IF articlesModule = 1 THEN 
    SET @query = ... UNION ... 
    SET @n = @n+1; 
END IF; 

IF newsModule = 1 THEN 
    SET @query = ... UNION ... 
    SET @n = @n+1; 
END IF; 

... and similar for the other 5 modules ... 

PREPARE stmt FROM @query; 

CASE @n 
WHEN 1: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn; 
WHEN 2: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn; 
WHEN 3: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn; 
WHEN 4: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn; 
WHEN 5: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn; 
WHEN 6: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn; 
WHEN 7: 
    EXECUTE stmt USING @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn, @searchWordIn, @searchWordIn, 
     @searchWordIn, @searchWordIn; 
END; 
+0

嘿比爾,非常感謝這 - 不幸的是我不能做上面的建議 - 我使用的系統有大約7個模塊。我使用動態SQL的全部原因是允許我將這些模塊中的任何一個組合起來並執行全文搜索。我在存儲過程中做這件事的原因是分離 - 我只是希望能夠從應用程序中爲數據庫提供搜索條件。 –

+0

由於我將通過一個消毒功能並通過PHP中的參數化準備語句傳遞搜索詞,因此我認爲我很安全,只需將搜索詞連接到動態SQL - 看起來並不那麼優雅。 :-) –

+0

@BillKarwin,爲什麼['QUOTE'](http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_quote)轉義字符「ASCII NUL」和「控制+ Z「?是不是這個矯枉過正,因爲[MySQL字符串](https://dev.mysql.com/doc/refman/5.7/en/string-literals.html)是字節安全的,我們不會有上述兩個字符的問題甚至而非轉義? – Pacerier