更新MySQL表抛出错误

时间:2017-04-17 10:18:12

标签: php

我从没想过我会在这么简单的任务中绊倒,我正在做的是从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;
}
}

1 个答案:

答案 0 :(得分:1)

您的更新方法中存在逻辑问题,

首先,您要分配一个值,然后尝试绑定一个值,

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

和你的set子句相同:

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

然后正如我所说的那样,无论是在where子句中,您都试图使用bindValue再次绑定这些值:

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

或在你的循环中:

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

解决你有两种方法:

1)通过传递写密钥来解决此问题:

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

和你的set子句:

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

2)直接注入这些值并保留bindValue方法,这是不可取的

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

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