使用预准备语句查询获取错误

时间:2014-06-08 04:41:13

标签: php mysqli prepared-statement

我现在面临一个问题好几天了,而且我盯着它看,似乎无法自己找到这个来源。

我做了一个类来执行我的查询。实际的查询执行部分如下所示:

<?php
public function query( $method, $table, $data, $where_text='', $where_data='' ) {
    $this->check_db_status();

    $method = strtoupper( $method );

    $fieldsArray = array();
    $valuesArray = array();
    $paramsArray = array();
    $format = '';
    $queryText = '';

    switch( $method ) {
        case 'SELECT' :
            $queryText = 'SELECT %s FROM ' . $table . ' ';
            foreach( $data as $field => $value ) {
                $fieldsArray[] = $value;
            }
        break;
        case 'UPDATE' :
            $queryText = 'UPDATE ' . $table . ' SET %s ';
            foreach( $data as $field => $value ) {
                $fieldsArray[] = $field.'=?';
                $format .= $this->get_value_type( $value );
                $paramsArray[] = $value;
            }
        break;
        case 'DELETE' :
            $queryText = 'DELETE FROM ' . $table . ' ';
        break;
        case 'INSERT' :
            $queryText = 'INSERT INTO ' . $table . ' (%s) VALUES (%s) ';
            foreach( $data as $field => $value ) {
                $fieldsArray[] = $field;
                $format .= $this->get_value_type( $value );
                $valuesArray[] = '?';
                $paramsArray[] = $value;
            }
        break;
        default :
            $this->get_error( 'Error in method switch' );
        break;
    }

    if( $where_text ) {
        $queryText .= $where_text;
        if( $where_data ) {
            foreach( $where_data as $value ) {
                $format .= $this->get_value_type( $value );
                $paramsArray[] = $value;
            }
        }
    }

    $fields = implode( ',', $fieldsArray );
    $values = implode( ',', $valuesArray );

    $query = sprintf( $queryText, $fields, $values );

    // DEBUG
    echo '<pre>';
    echo 'query: ' . $query . '<br />
    echo 'format: ' .' . $format . '<br />';
    print_r( $paramsArray );
    echo '</pre>';


    $stmt = $this->mysqli->prepare( $query );

    if( $stmt === false or $stmt == NULL ) {
        $this->get_error( 'Error while preparing the statement' );
    }

    if( $format and $paramsArray )
        call_user_func_array( 'mysqli_stmt_bind_param', array_merge( array( $stmt, $format ), $paramsArray ) ); 

    if( $stmt->execute() ) {
        $result = 0;
        switch( $method ) {
            case 'INSERT' :
                $result = ($stmt->insert_id) ? $stmt->insert_id : true;
            break;
            case 'UPDATE' :
            case 'DELETE' :
                $result = ($stmt->affected_rows) ? $stmt->affected_rows : true;
            break;
            case 'SELECT' :
                $meta = $stmt->result_metadata();
                $fields = $result = array();
                while ($field = $meta->fetch_field()) { 
                    $var = $field->name; 
                    $$var = null; 
                    $fields[$var] = &$$var; 
                }
                call_user_func_array(array($stmt,'bind_result'),$fields);
                $i = 0;
                while( $stmt->fetch() ) {
                    $result[$i] = array();
                    foreach( $fields as $k => $v)
                        $result[$i][$k] = $v;
                    $i++;
                }
            break;
        }
        $stmt->close();
        $this->query_cnt++;

        return $result;
    }
    else {
        $this->get_error();
    }
}
?>

现在我正在尝试创建另一个类来将我的会话存储在我自己的数据库中。 write函数如下所示:

<?php
public function write_session( $session_id, $session_data ) {

    $query  = $this->sql->query( 'INSERT', 'sessions', array( 'ses_id'=>$session_id, 'ses_time'=>time(), 'ses_start'=>time(), 'ses_data'=>$session_data, 'ses_check'=>$this->check ), 'ON DUPLICATE KEY UPDATE ses_time=?, ses_data=?', array(time(),$session_data));

    if($query) {
        return true;
    }
    else {
        return false;
    }
}
?>

我一直收到这个错误:

Warning: mysqli::prepare() [mysqli.prepare]: Couldn't fetch mysqli in /.../class.db.php on line 124

第124行是$stmt = $this->mysqli->prepare( $query );的行。它由write_session的第一行触发。

如果放入数据库类的调试部分以显示查询,则会提供此输出:

query: INSERT INTO sessions (ses_id,ses_time,ses_start,ses_data,ses_check) VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE ses_time=?, ses_data=?
format: [siissis]
Array
(
    [0] => a98696a8416fc898f2c07e05f39735dc
    [1] => 1402201705
    [2] => 1402201705
    [3] => test|s:11:"someValuess";
    [4] => 40b17cb572d9bf5eaadad99b7904e0a4889a31d0
    [5] => 1402201705
    [6] => test|s:11:"someValuess";
)

对我来说这似乎很好......我在忽视什么?

修改

会话的表定义:

 sessions (
   ses_id varchar(32) NOT NULL,
   ses_time int(11) NOT NULL,
   ses_start int(11) NOT NULL,
   ses_data text NOT NULL,
   ses_check varchar(40) NOT NULL,
  PRIMARY KEY  (ses_id)
 ) 

1 个答案:

答案 0 :(得分:1)

在评论中提供的link中指出,您的问题似乎是

<强> 4。您将OOP和函数调用混合到数据库对象中。

具体来说,您在这里使用mysqli对象

$stmt = $this->mysqli->prepare( $query );

然后继续在这里进行功能mysqli调用

if( $format and $paramsArray )
    call_user_func_array( 'mysqli_stmt_bind_param', array_merge( array( $stmt, $format ), $paramsArray ) );

所以尝试用相应的OOP版本替换上面的代码

if($format and $paramsArray) {
    $stmt->bind_param($format,$paramsArray);
}

同时替换

call_user_func_array(array($stmt,'bind_result'),$fields);

使用

$stmt->bind_param($format,$fields);

http://www.php.net//manual/en/mysqli-stmt.bind-param.php

实施__wakeup

另一种可能是由于序列化,您的数据库连接可能已关闭。尝试通过实施__wakup

重新连接
public function __wakeup()
{
    $this->mysqli = new mysqli('localhost', 'my_user', 'my_password', 'my_db');
}