2017-04-17 68 views
1

我從來沒有想過我會絆倒這麼簡單的任務,我正在做的是從MySQL獲取行,並將它們顯示在窗體上,然後用戶可以根據需要更新值:更新MySQL表拋出錯誤

<?php 
include('includes/db_connection.php'); 
include('includes/sessions.php'); 
include('includes/functions.php'); 
include('includes/header.php'); 
include('includes/navbar-logged.php'); 

// AUTHENTICATION // 
$row  = DB::getInstance()->selectOneByField('membership', 'member_username', $member); 
if ($row['member_user_class'] != 'Site Administrator') { 
    stderr("Sorry, <b>no authorization</b> to access this page."); 
} 
// AUTHENTICATION // 

// CLOUD KEYS // 
if (isset($_POST['submitCloudKeys'])) 
{ 
    // TRY/CATCH // 
    try { 
     foreach ($_POST['cloudId'] as $val) { 
      DB::getInstance()->update(
       'clouds', 
       'cloud_id', 
       $val, 
      [ 
       'cloud_key' => $_POST['cloud_key'][$val] 
      ]); 
      stdmsg('Cloud keys \'<b>'.$_POST['cloud_key'][$val].'</b>\' have been <b>updated</b>.'); 
     } 
    } catch (Exception $e) { 
     stderr($e); 
    } 
} 
    $rows = DB::getInstance()->select('SELECT * FROM `clouds`'); 
?> 
    <div class="panel panel-primary"> 
     <div class="panel-heading">Current cloud hosts.</div> 
     <div class="panel-body"> 

      <form action="clouds.php" method="post" class="form-horizontal container-fluid" role="form"> 
       <?php $x = 0; ?> 
       <?php $z = 0; ?> 
       <?php foreach ($rows as $row) { ?>    
       <div class="row form-group"> 
        <div class="col-sm-4 text-right"><label for="txtNetwork" class="control-label"><?php echo htmlspecialchars($row['cloud_name']) ?>:</div> 
        <div class="col-sm-8"> 
         <input type="text" name="cloud_key[]" value="<?php echo htmlspecialchars($row['cloud_key']) ?>" size="30" class="form-control" /> 
         <input type="hidden" name="cloudId[]" value="<?php echo $row['cloud_id']; ?>" /> 
        </div> 
       </div>      
       <?php } ?> 

       <div class="row form-group"> 
        <div class="col-sm-12 text-right"> 
         <button type="submit" name="submitCloudKeys" class="btn btn-default">Update</button> 
        </div> 
       </div>   
      </form> 
     </div> 
     <div class="panel-footer">Update the <b>cloud hosts</b> keys.</div> 
    </div> 
<?php 
include('includes/footer.php'); 

我得到一個錯誤:

PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'b447297ddb6be7377......................' in 'field list' in /home/admin/web/wraithpbns.com/public_html/includes/DB.php:268 
Stack trace: #0 /home/admin/web/wraithpbns.com/public_html/includes/DB.php(268): PDOStatement->execute() 
#1 /home/admin/web/wraithpbns.com/public_html/clouds.php(26): DB->update('clouds', 'cloud_id', '1', Array) 
#2 {main} 

在MySQL的表名是正確的,我不明白爲什麼我不能更新表單值,將「未知列「部分向我展示了我正在嘗試更新的關鍵價值,我之前從未遇到過這個問題,任何幫助都將不勝感激夥計們!

已更新方法:

<?php 

class DB 
{ 

    private static $instance; 

    public static function getInstance() { 
     if(is_null(self::$instance)) { 
      self::$instance = new DB(); 
     } 

     return self::$instance; 
    } 

    public static function map(array $rows = array(), $keyColumn, $valueColumn = null) { 
     $result = array(); 
     foreach($rows as $row) { 
      if(is_null($valueColumn)) { 
       $result[$row[$keyColumn]] = $row; 
      } else { 
       $result[$row[$keyColumn]] = $row[$valueColumn]; 
      } 
     } 

     return $result; 
    } 

    private $pdo; 

    private function __construct() { 
     try { 
      $this->pdo = new PDO(
       sprintf('%s:host=%s;dbname=%s', 
        DRIVER, 
        HOST, 
        DATA 
       ), 
       USER, 
       PASS, 
       array(
        PDO::ATTR_PERSISTENT => true, 
        PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, 
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8; SET CHARACTER SET utf8;' 
       ) 
      ); 
     } catch(Exception $ex) { 
      throw new Exception('Cannot connect to database.'); 
     } 
    } 

    public function execute($query, array $params = []) { 
     $normParams = $this->normalizeParams($params); 

     $command = $this->pdo->prepare($query); 

     $command->closeCursor(); 

     $status = $command->execute($normParams); 

     if(!$status) { 
      throw new Exception('DB::execute(): Can\'t execute query:'); 
     } 

     return $status; 
    } 

    public function select($query, array $params = [], $fetchType = PDO::FETCH_ASSOC) { 
     $normParams = $this->normalizeParams($params); 

     $command = $this->pdo->prepare($query); 

     $command->closeCursor(); 

     foreach($normParams as $paramName => $paramValue) { 
      if(is_array($paramValue) 
        && isset($paramValue['type']) 
        && isset($paramValue['value'])) { 
       $command->bindValue($paramName, $paramValue['value'], $paramValue['type']); 
      } else { 
       $command->bindValue($paramName, $paramValue); 
      } 
     } 

     if(!$command->execute()) { 
      throw new Exception('DB::select(): Can\'t execute query.'); 
     } 

     return $command->fetchAll($fetchType); 
    } 

    public function selectValues($query, array $params = [], $fetchType = PDO::FETCH_ASSOC) { 
     $row = $this->selectOne($query, $params, $fetchType); 
     if(empty($row)) { 
      throw new Exception('DB::selectValues(): No values selected.'); 
     } else { 
      return $row; 
     } 
    } 

    public function selectValue($query, array $params = []) { 
     $values = $this->selectValues($query, $params, PDO::FETCH_NUM); 

     return $values[0]; 
    } 

    public function selectAll($tableName, $fetchType = PDO::FETCH_ASSOC) { 
     return $this->select(
      sprintf(' 
       SELECT * 
       FROM `%s`', 
       $tableName 
      ), 
      [], 
      $fetchType 
     ); 
    } 

    public function selectByField($tableName, $fieldName, $value, $fetchType = PDO::FETCH_ASSOC) { 
     return $this->select(
      sprintf(' 
       SELECT * 
       FROM `%s` 
       WHERE `%s` = :value', 
       $tableName, 
       $fieldName 
      ), 
      [ 
       ':value' => $value 
      ], 
      $fetchType 
     ); 
    } 

    public function selectOne($query, array $params = [], $fetchType = PDO::FETCH_ASSOC) { 
     $rows = $this->select($query, $params, $fetchType); 

     return array_shift($rows); 
    } 

    public function selectOneByField($tableName, $fieldName, $value, $fetchType = PDO::FETCH_ASSOC) { 
     $rows = $this->selectByField($tableName, $fieldName, $value, $fetchType); 

     return array_shift($rows); 
    } 

    public function get($tableName, $fieldName, $value, $fetchType = PDO::FETCH_ASSOC) { 
     return $this->selectOneByField($tableName, $fieldName, $value, $fetchType); 
    } 

    public function insert($tableName, array $fields) { 
     $normParams = $this->normalizeParams($fields); 

     $paramNames = implode(', ', array_keys($normParams)); 
     $fieldNames = '`' . implode('`, `', array_keys($fields)) . '`'; 

     $command = $this->pdo->prepare(
      sprintf(' 
       INSERT INTO `%s` (%s) 
       VALUES (%s)', 
       $tableName, 
       $fieldNames, 
       $paramNames 
      ) 
     ); 

     $command->closeCursor(); 

     if(!$command->execute($normParams)) { 
      throw new Exception('DB::insert(): Can\'t execute query.'); 
     } 

     return $this->pdo->lastInsertId(); 
    } 

    public function bulkInsert($tableName, array $rows = []) { 
     if(empty($rows)) { 
      return; 
     } 

     $fieldNames = array_keys($this->normalizeParams($rows[0])); 

     $normParams = []; 
     $paramNames = ''; 
     $counter = 0; 
     foreach($rows as $row) { 
      $paramNames .= ((0 < $counter)? ',': '') . '('; 

      $nextParamNames = []; 
      foreach($row as $paramKey => $paramValue) { 
       $nextParamNames[] = ':' . $paramKey . $counter; 
       $normParams[':' . $paramKey . $counter] = $paramValue; 
      } 

      $paramNames .= implode(',', $nextParamNames); 
      $paramNames .= ')'; 

      $counter++; 
     } 

     $command = $this->pdo->prepare(
      sprintf(' 
       INSERT INTO `%s` %s 
       VALUES %s', 
       $tableName, 
       $fieldNames, 
       $paramNames 
      ) 
     ); 

     $command->closeCursor(); 

     if(!$command->execute($normParams)) { 
      throw new Exception('DB::bulkInsert(): Can\'t execute query.'); 
     } 
    } 

    public function update($tableName, $fieldName, $fieldValue, array $updateFields, $updateAll = false) { 
     if(is_null($fieldName)) { 
      if(!$updateAll) { 
       throw new SystemException('Attempt to update all table records without confirmation.'); 
      } 

      $sqlWhere = ''; 
     } else { 
      $sqlWhere = sprintf('WHERE `%s` = %s', $fieldName, $fieldValue); 
     } 
//   echo $sqlWhere; 
// 
//  exit; 
     $normUpdateFields = $this->normalizeParams($updateFields); 
     $sqlSetRows = []; 
     foreach($updateFields as $updateFieldName => $updateFieldValue) { 
      $sqlSetRows[] = sprintf('`%s` = %s', $updateFieldName, $updateFieldValue); 
     } 

     $sqlSet = implode(', ', $sqlSetRows); 

     $command = $this->pdo->prepare(
      $sql = sprintf(' 
       UPDATE `%s` 
       SET  %s 
       %s', 
       $tableName, 
       $sqlSet, 
       $sqlWhere 
      ) 
     ); 
     $command->closeCursor(); 

     foreach($normUpdateFields as $updateFieldName => $updateFieldValue) { 
      if(is_array($updateFieldValue) 
        && isset($updateFieldValue['type']) 
        && isset($updateFieldValue['value'])) { 
       $command->bindValue($updateFieldName, $updateFieldValue['value'], $updateFieldValue['type']); 
      } else { 
       $command->bindValue($updateFieldName, $updateFieldValue); 
      } 
     } 



     if(!empty($sqlWhere)) { 
      $command->bindValue(':' . $fieldName, $fieldValue); 
     } 

     if(!$command->execute()) { 
      throw new Exception('DB::update(): Can\'t execute query.'); 
     } 
    } 

    public function remove($tableName, $fieldName = null, $value = null, $removeAll = false) { 
     $isExecuted = false; 

     if(is_null($fieldName) 
       && is_null($value) 
       && $removeAll) { 
      $isExecuted = $this->execute(sprintf('DELETE FROM `%s`', $tableName)); 
     } else if(!is_null($fieldName) 
       && !is_null($value)) { 
      $isExecuted = $this->execute(
       sprintf(' 
        DELETE FROM `%s` 
        WHERE `%s` = :value', 
        $tableName, 
        $fieldName 
       ), 
       [ 
        ':value' => $value 
       ] 
      ); 
     } 

     if(!$isExecuted) { 
      throw new Exception('DB::remove(): Can\'t execute query.'); 
     } 
    } 

    protected function normalizeParams(array $params = []) { 
     $normParams = []; 
     foreach($params as $paramKey => $paramValue) { 
      $normParams[(strlen($paramKey) && (':' === $paramKey{0}))? $paramKey: ':' . $paramKey] = $paramValue; 
     } 

     return $normParams; 
    } 

    /** 
    * Replaces any parameter placeholders in a query with the value of that 
    * parameter. Useful for debugging. Assumes anonymous parameters from 
    * $params are are in the same order as specified in $query 
    * 
    * @param string $query The sql query with parameter placeholders 
    * @param array $params The array of substitution parameters 
    * @return string The interpolated query 
    */ 
    public function interpolateQuery($query, $params) { 
    $keys = array(); 

    # build a regular expression for each parameter 
    foreach ($params as $key => $value) { 
     if (is_string($key)) { 
      $keys[] = '/:'.$key.'/'; 
     } else { 
      $keys[] = '/[?]/'; 
     } 
    } 

    $query = preg_replace($keys, $params, $query, 1, $count); 

    #trigger_error('replaced '.$count.' keys'); 

    return $query; 
} 
} 
+0

你如何實現'update'方法? – hassan

+0

剛編輯更新方法,謝謝。 – colinreedy674

+1

這是相當多的代碼來處理,但錯誤明確指出,你試圖更新一個不存在的列(你試圖更新一列'b447297ddb6be7377 ........'這可能是一個價值?)。無論如何,將它分解爲多個函數真的很乾嗎?它可能造成比解決頭痛更多的麻煩。如果你這樣做,爲什麼不擴展PDO類呢? – Qirel

回答

1

你有你的更新方法中的邏輯問題,

首先,你分配一個值,那麼您要綁定一個值,

$sqlWhere = sprintf('WHERE `%s` = %s', $fieldName, $fieldValue); 
//        ^^    ^^^^^^^^^^^^ 

和您設置的子句相同:

$sqlSetRows[] = sprintf('`%s` = %s', $updateFieldName, $updateFieldValue); 
//        ^^      ^^^^^^^^^^^^^^^^^^ 

那麼我告訴你正在試圖綁定在再次使用bindValue是否這些值的where子句:

$command->bindValue(':' . $fieldName, $fieldValue); 

或在您的這個循環:

foreach($normUpdateFields as $updateFieldName => $updateFieldValue) { 
.... 
$command->bindValue($updateFieldName, $updateFieldValue); 

解決您有兩種方法:

1)通過傳遞寫入密鑰來修復此問題,如下所示:

$sqlWhere = sprintf('WHERE `%s` = :%s', $fieldName, $fieldName); 

爲您組子句:

$sqlSetRows[] = sprintf('`%s` = :%s', $updateFieldName, $updateFieldName); 

2)直接注入這些值並留下bindValue方法這不是優選的

$sqlSetRows[] = sprintf('`%s`="%s"', $updateFieldName, $updateFieldValue); 

$sqlWhere = sprintf('WHERE%S ="%s"', $fieldName, $fieldValue);

+0

謝謝哈桑他們都工作得很好:) – colinreedy674