5月
22
2007
分類:
最近更新:
2007-05-22
To Prepare SQL Statements and Read Data
試作一個 PHP 程式,可以從用戶端取得使用者輸入的資料,接著讀入一份外部的 SQL 指令稿。 將 PHP 中的變數值代入 SQL 指令之中 (prepares SQL statements),以之查詢資料庫取回查詢結果。
第一階段試作
利用 preg_match_all()
找出 SQL 敘述中的變數內容,判斷 PHP 程序中有無定義同名變數(16行)。
分別建立兩份表,一份是要代換的變數名稱($patterns),一份是變數值($replacements)。
接著以 preg_replace()
完成 SQL 敘述的變數代換動作。
<?php
$start_date = '2007-01-01'; //假設這些變數是使用者輸入的資料
$end_date = '2007-04-30';
$customer_id = 101;
$sheetsFilePath = 'test.sql'; //外部 SQL 指令稿
$s = file_get_contents($sheetsFilePath);
preg_match_all('/@(\w+)/', $s, $m);
print_r($m[1]);
$patterns = array();
$replacements = array();
foreach ($m[1] as $name) {
if (!isset($$name))
continue; /*Not Replace*/
$patterns[$name] = '/@' . $name . '([^\w])/';
$replacements[$name] = (is_numeric($$name) ? $$name : "'{$$name}'") . '$1';
}
print_r($patterns);
print_r($replacements);
/*
注意: 有一種符合 REGEX 語意但不合 SQL 語意的替代情形,即 @var 被包括在
單引號中的情形。
按 SQL 語意,單引號中的 @var 被視為字串內容而非變數。
按 REGEX 語意,仍然符合替代條件而替換為變數值。
*/
$sqlQuery = preg_replace($patterns, $replacements, $s);
echo $sqlQuery;
?>
改成函數形式(sql_sheets_read.php)
將上述的直述程式重整為函數形式。將每一道查詢指令之結果視為一個試算表($sheet),存入一個陣列中。 最後傳回所有結果的總表($sheets)。
<?php
function &sql_sheets_read($pdoDb, $sqlFilePath, $sqlParameters) {
if (constant('INTERNAL_TEST'))
global $testCaseSet;
$rcFalse = false;
if (!($s = file_get_contents($sqlFilePath)))
return $rcFalse;
preg_match_all('/SELECT [^;]+/i', $s, $sqlSet); //分析查詢指令個數
//print_r($sqlSet);
if (get_magic_quotes_gpc()) {
foreach ($sqlParameters as $k => &$v) {
$v = addslashes($v);
}
}
//print_r($sqlParameters);
$sheets = array(); //每一道查詢指令之結果將分別存在不同的表格
$indexOfSheets = 0;
foreach ($sqlSet[0] as &$sqlText) {
preg_match_all('/@(\w+)/', $sqlText, $m);
//print_r($m[1]);
$patterns = array();
$replacements = array();
foreach ($m[1] as &$name) {
if (!isset($sqlParameters[$name]))
continue; /*Not Replace*/
$patterns[$name] = '/@' . $name . '([^\w]|\b)/';
$replacements[$name] = (
is_numeric($sqlParameters[$name])
? $sqlParameters[$name]
: "'{$sqlParameters[$name]}'"
) . '$1';
}
//print_r($patterns);
//print_r($replacements);
/*
注意: 有一種符合 REGEX 語意但不合 SQL 語意的替代情形,即 @var 被包括在
單引號中的情形。
按 SQL 語意,單引號中的 @var 被視為字串內容而非變數。
按 REGEX 語意,仍然符合替代條件而替換為變數值。
*/
$sqlQuery = preg_replace($patterns, $replacements, $sqlText) . ';';
//echo $sqlQuery, "\n";
if (constant('INTERNAL_TEST'))
PHPUnit_Framework_Assert::assertEquals($sqlQuery,
$testCaseSet['sql_sheets_read'][$indexOfSheets]);
$sheet = &$sheets[$indexOfSheets];
foreach ($pdoDb->query($sqlQuery) as &$row) {
$sheet[] = $row;
}
++$indexOfSheets;
}
return $sheets;
}
?>
函數測試案例
測試案例使用 PHPUnit3 做為單元測試工具。 由於要測試的內容位於函數之中,所以此處採用 PHPUnit 用例中較少見的測試作法。
<?php
define('INTERNAL_TEST', true);
require 'PHPUnit/Framework.php';
require 'sql_sheets_read.php';
$sp['start_date'] = '2007-01-01';
$sp['end_date'] = '2007-04-30';
$sp['customer_id'] = 101;
$sp['note'] = "';SELECT * FROM users";
$testCaseSet = array(
'sql_sheets_read' => array(
"SELECT * FROM orders
WHERE sdate = '2007-01-01' AND edate = '2007-04-30' AND note LIKE '\';SELECT * FROM users';"
,
"SELECT * FROM customers WHERE customer = 101
;"
)
);
$sheetsFilePath = 'test.sql';
$pdoDb = new PDO('pgsql:host=localhost port=5432 dbname=testdb user=rock password=mypass');
sql_sheets_read($pdoDb, $sheetsFilePath, $sp);
?>
樂多舊網址: http://blog.roodo.com/rocksaying/archives/3321763.html