2016-02-10 33 views
0

我正在嘗試學習如何使用以下示例代碼來執行準備語句。mysqli準備聲明中的致命錯誤

我有一個初始的SQL語句,並且對於每個返回的記錄,對返回的結果進行另一次SQL檢查。

<?php 

$sql_b = "SELECT fld_title, fld_tag FROM j_oracle_cat WHERE fld_tag IS NOT NULL ORDER BY fld_title"; 

if (!$result_b = $conn -> query($sql_b)) { 

    die('There was an error running the query [' . $conn -> error . ']'); 

} else { 

    if (!$result_b -> num_rows) { 

     echo "<h4>No Categories Defined</h4>"; 

    } else { 

     while($row_b = $result_b -> fetch_assoc()) { 

      $cat_ttl = $row_b["fld_title"]; 
      $cat_tag = $row_b["fld_tag"]; 

      echo "<h4><a href='category.php?tag=" . $cat_tag . "'>" . $cat_ttl . "</a></h4>"; 

      $sql_c = "SELECT p.fld_tag FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = ?"; 

      /* Prepare statement */ 
      $stmt = $conn->prepare($sql_c); 
      if($stmt === false) { 
       trigger_error('Wrong SQL: ' . $sql_c . '<hr />Error: ' . $conn->error, E_USER_ERROR); 
      } 

      /* Bind parameters. Types: s = string, i = integer, d = double, b = blob */ 
      $stmt->bind_param('s',$cat_tag); 

      /* Execute statement */ 
      $stmt->execute();      

     } 

     $result_b -> free(); 

    } 

} 

?> 

當我運行的代碼,它得到這麼遠:

<h4><a href='category.php?tag=accounts-payable'>Accounts Payable</a></h4> 
<h4><a href='category.php?tag=accounts-receivable'>Accounts Receivable</a></h4> 

但隨後的錯誤有:

Fatal error: Wrong SQL: SELECT p.fld_is_parent FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = ? Error: in C:\xampp\htdocs\php\a.php on line 95

95號線是這個:

trigger_error('Wrong SQL: ' . $sql_c . '<hr />Error: ' . $conn->error, E_USER_ERROR); 

表結構:

CREATE TABLE `j_oracle_cat` (
    `fld_id` int(11) NOT NULL AUTO_INCREMENT, 
    `fld_title` varchar(255) DEFAULT NULL, 
    `fld_desc` varchar(255) DEFAULT NULL, 
    `fld_tag` varchar(255) DEFAULT NULL, 
    `fld_label` varchar(255) DEFAULT NULL, 
    `fld_parent` int(2) DEFAULT '0', 
    PRIMARY KEY (`fld_id`) 
) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=latin1 

CREATE TABLE `j_oracle_pages` (
    `fld_id` int(11) NOT NULL AUTO_INCREMENT, 
    `fld_title` varchar(255) DEFAULT NULL, 
    `fld_catid` int(11) DEFAULT NULL, 
    `fld_cols` int(2) DEFAULT '1', 
    `fld_left` text, 
    `fld_content` text, 
    `fld_tag` varchar(255) DEFAULT NULL, 
    `fld_date` date DEFAULT NULL, 
    `fld_is_parent` char(1) DEFAULT NULL, 
    PRIMARY KEY (`fld_id`) 
) ENGINE=MyISAM AUTO_INCREMENT=83 DEFAULT CHARSET=latin1 

我試過運行sql直接並且它沒有錯誤,對於一個示例標籤,它返回例如3行:

SELECT p.fld_tag FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = 'accounts-receivable'; 

連接到數據庫:

<?php 
error_reporting(E_ALL); 
ini_set('display_errors', 1); 

$servername = "localhost"; 
$username = "root"; 
$password = ""; 
$dbname = "mydb"; 

// Create connection 
$conn = new mysqli($servername, $username, $password, $dbname); 

if($conn -> connect_errno > 0){ 
    die('Unable to connect to database [' . $conn->connect_error . ']'); 
} 

?> 

想必我做一些愚蠢的,但我不能看到什麼?

+0

您確定您的數據庫連接寫入正確嗎? – kojow7

+0

如果你發佈了你的表結構和MySQL的實際錯誤消息,這不僅僅是「錯誤:在某些文件中在某行上」。如果直接使用該參數的適當值運行此SQL,會發生什麼情況? –

+0

對不起 - 我已更新顯示錶結構的問題。如果我在例如SQLyog,它不會報錯,併爲「accounts-receivable」標籤返回3行。 – 4532066

回答

1

所以這裏是我的建議;我沒有發現你的代碼有什麼明顯的錯誤,但是這些步驟應該能夠更容易地診斷問題,如果沒有徹底修復它。首先,將prepare()呼叫移出循環*。接下來,explicitly create the statement object,以便如果準備有問題,則可以直接從語句對象中獲取錯誤。最後,在流程的每個階段檢查有效回報,包括parameter bindingstatement execution

$sql_b = "SELECT fld_title, fld_tag FROM j_oracle_cat WHERE fld_tag IS NOT NULL ORDER BY fld_title"; 
if (!$result_b = $conn->query($sql_b)) { 
    trigger_error("Error executing query: $conn->error<br/>SQL query: $sql_b", E_USER_ERROR); 
} else { 
    if (!$result_b->num_rows) { 
     echo "<h4>No Categories Defined</h4>"; 
    } else { 
     /* Prepare statement */ 
     $sql_c = "SELECT p.fld_tag FROM j_oracle_cat c, j_oracle_pages p WHERE c.fld_id = p.fld_catid AND c.fld_tag = ?";  
     $stmt = $conn->stmt_init(); 
     if (!$stmt) { 
      trigger_error("Error creating statement: $conn->error", E_USER_ERROR); 
     } 
     $result = $stmt->prepare($sql_c); 
     if(!$result) { 
      trigger_error("Error preparing statement: $stmt->error<br/>SQL query: $sql_c", E_USER_ERROR); 
     } 
     /* Bind parameters. Types: s = string, i = integer, d = double, b = blob */ 
     // needs a dummy value for the initial bind 
     $row_b = array("fld_tag"=>""); 
     $result = $stmt->bind_param("s", $row_b["fld_tag"]); 
     if(!$result) { 
      trigger_error("Error binding parameter: $stmt->error<br/>", E_USER_ERROR); 
     } 

     while($row_b = $result_b -> fetch_assoc()) { 
      $cat_ttl = htmlspecialchars($row_b["fld_title"]); 
      $cat_tag = htmlspecialchars($row_b["fld_tag"]); 
      echo "<h4><a href='category.php?tag=$cat_tag'>$cat_ttl</a></h4>"; 
      /* Execute statement */ 
      $result = $stmt->execute(); 
      if(!$result) { 
       trigger_error("Error executing statement: $stmt->error<br/>Bound parameter value: $row_b[fld_tag]", E_USER_ERROR); 
      } 
      // I assume you'll be doing something with $result down here? 
     } 
     $result_b->free(); 
     $stmt->close(); 
    } 
} 

夫婦的旁註:你應該總是逃避數據庫結果與htmlspecialchars()把它們轉換成HTML之前,以避免注射的風險。你可以在use double quotes to include variables的字符串內部,並避免在各處有幾十個不必要的.操作符。這是個人喜好的問題,但許多人認爲它更具可讀性。

*準備語句的一大優點是它們separate the preparation of the query from its execution,避免了設置MySQL運行查詢所涉及的開銷。通過反覆準備一份聲明,您可以完全消除這種好處。

+0

非常感謝您花費大量時間和精力爲您提供這樣一個有用且徹底的答案。我已經學到了一些東西,並且您的修訂代碼也可以正常工作。謝謝! – 4532066