[英]PHP function to use prepared SQL statements - using implode to enter values of array separated by commas as arguments for function
我最近問了一些有關針對SQL注入漏洞的安全性的問題。 我決定創建一個函數,該函數將使用准備好的語句執行sql查詢,因此我不必為每個查詢寫出這么多行代碼:
function secure_sql($query, $values, $datatypes){
global $link;
$stmt = mysqli_prepare($link, $query);
foreach($values as &$value){
$value = mysqli_real_escape_string($link, $value);
mysqli_stmt_bind_param($stmt, substr($datatypes, 0), $value);
$datatypes = substr($datatypes, -(strlen($datatypes)-1));
}
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, implode(", ", $values));
$results = mysqli_stmt_get_result($stmt);
return $results;
}
其中query是准備好的查詢(帶有?s),$ values是所有變量的數組(按順序替換占位符?s),$ datatypes是包含變量的所有數據類型的字符串。 $ link是一個數據庫連接。
所以我有兩個主要問題。
1)它不起作用。 我認為這一定是因為內爆可能無法在此情況下正確使用。 我將使用什么呢? 我不能使用call_user_func_array,因為我還需要使用$ stmt作為參數。 我嘗試使用array_unshift將$ stmt添加到參數的開頭,但是它不起作用。
2)如果我確實可以使用它,該如何改進呢? 我仍然是PHP和SQL的初學者。
編輯:我已經解決了問題。 謝謝大家的寶貴意見和答案!
我覺得沒有必要直接給出我想出的代碼,而是要解釋它是有必要的,看看您的某些思維方式是多么不正確。
首先,使用mysqli_stmt_bind_param()
使我感到困惑-您的第二個參數表達式( substr($datatypes, 0)
)返回所有數據類型的值,但您只綁定了一個。 我認為您的意思是:
mysqli_stmt_bind_param($stmt, $datatypes[0] /* <-- retrieves the first character */, $value);
但是更重要的是,您只應該調用一次 mysqli_stmt_bind_param()
,這給您帶來了更大的困難...要省略foreach
循環,那么call_user_func_array()
呢? (實際上,很有可能保留$stmt
作為參數):
call_user_func_array("mysqli_stmt_bind_param", array_merge(array($stmt, $datatypes), $values));
//calls mysqli_stmt_bind_param($stmt, $datatypes, $values[0], $values[1]... values[n]);
如果您對以上內容感到困惑,請按照以下方式查看:
call_user_func_array //a call to mysqli_stmt_bind_param, with all the appropriate parameters
(
"mysqli_stmt_bind_param", //the function to call
array_merge //an array consisting of the statement, the datatype and all the values
(
array($stmt, $datatypes), //statement and datatype-parameters
$values //all the values
)
);
但是,這確實需要您的$values
mysqli_stmt_bind_param
包含引用,因為mysqli_stmt_bind_param
期望您的值是這樣。 如果您仍然想將它們作為值傳遞給函數,則可以添加它,然后將$ref_values
傳遞給call_user_func_array()
函數:
foreach ($values as &$value) $ref_values[] = &$value;
現在我們來使用implode()
,這也是不正確的。 要從PHP手冊中引用:
放大(返回值):
返回一個字符串,其中包含以相同順序表示所有數組元素的字符串表示形式,並且每個元素之間都有粘合字符串。
mysqli_stmt_bind_result(第二個參數):
要綁定的變量。
因此,您要在此處執行的操作是使implode()
返回的string
成為變量,這沒有任何意義。 幸運的是, mysqli_stmt_get_result()
返回一個在執行后獲取的對象,這意味着不需要bind_result-function。 因此,請嘗試刪除該行。
總之,我將像這樣重新編寫代碼:
function secure_sql($query, $values, $datatypes) {
global $link;
$stmt = mysqli_prepare($link, $query);
foreach ($values as &$value) $ref_values[] = &$value;
call_user_func_array("mysqli_stmt_bind_param", array_merge(array($stmt, $datatypes), $ref_values));
mysqli_stmt_execute($stmt);
return mysqli_stmt_get_result($stmt);
}
對我來說,聽起來應該可行,但是如果不行,請告訴我(我可能在某處缺少某些東西或在錯誤地思考)。
為了回答第二個問題,一切看起來都不錯,但是我不建議您使用mysqli_
,因為它們最終會被刪除(如PHP手冊中所述 )。 如果您打算使用對象代替,則在我進行更改時,大多數情況都類似(除了需要使用對象屬性和對象方法來代替它們的事實……),但call_user_func_array()
功能。 不過,幸運的是,也可以通過指定一個數組作為第一個參數來調用該方法,該數組由對象和方法名稱( call_user_func_array($prepared_obj, "bind_param") ...)
)組成。
編輯:考慮到它的必要性,我做了一個功能相同的功能,但改為在mysqli對象上工作:
function secure_sql($query, $values, $datatypes) {
global $mysqli_object; //declared with $mysql_object = new mysqli(...)
$stmt = $mysqli_object->prepare($query);
foreach ($values as &$value) $ref_values[] = &$value;
call_user_func_array(array($stmt, "bind_param"), array_merge(array($datatypes), $ref_values));
$stmt->execute();
return $stmt->get_result();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.