php - 如何创建 MySQLi_prep 函数

标签 php mysql

我有以下代码,适用于使用 mysql_connect 的早​​期 PHP 版本。有谁知道如何编辑它以使用新的 mysqli 函数?或者类似地,您是否知道任何其他功能也能完成这项工作。

function mySQLiReady( $value ) {
    $magic_quotes_active = get_magic_quotes_gpc();
    $new_enough_php = function_exists( "mysql_real_escape_string" ); // i.e. PHP >= v4.3.0
    if( $new_enough_php ) { // PHP v4.3.0 or higher
        // undo any magic quote effects so mysql_real_escape_string can do the work
        if( $magic_quotes_active ) { 
            $value = stripslashes( $value ); 
        }
        $value = mysql_real_escape_string( $value );
    } else { // before PHP v4.3.0
        // if magic quotes aren't already on then add slashes manually
        if( !$magic_quotes_active ) { 
            $value = addslashes( $value ); 
        }
        // if magic quotes are active, then the slashes already exist
    }
    return $value;
}

最佳答案

// lib/DatabaseException.php
<?php

namespace Database;

/**
 * Class DatabaseException
 * This is the exception class that will be thrown whenever a PDOException occurs.
 * The exception will have the prepared statement with the values inside.
 *
 * @package  Database
 */
class DatabaseException extends \PDOException {

    protected $sql_code = null;

    /**
     *
     * @param string             $message
     * @param null               $sql_code
     * @param null               $prepare
     * @param null|\PDOException $previous_exception
     */
    public function __construct($message = "", $sql_code = null, $prepare = null, \PDOException $previous_exception = null){
        if(is_array($prepare)){
            foreach($prepare as $key => $value) {
                $sql_code = str_replace($key, "'".addslashes($value)."'", $sql_code);
            }
        }
        $this->sql_code = $sql_code;
        parent::__construct($message.$this->getTrace()." --- \n [ Query: [  ".$this->sql_code."  ] ]", ($previous_exception && is_int($previous_exception->getCode()) ? $previous_exception->getCode() : 0));
    }
}
?>


// lib/QueryStatement.php
<?php

namespace Database;

/**
 * Class QueryStatement
 * This class's purpose is to extend \PDOStatement, save the prepared statement's data
 * and trigger DatabaseException exceptions on errors.
 *
 * @package Database
 */
class QueryStatement extends \PDOStatement {

    /**
     * This variable holds all of the bindParam/bindColumn/bindValue values
     * @var array
     */
    protected $values = array();

    protected function __construct() {
        // Set the default fetch mode to \PDO::FETCH_ASSOC
        $this->setFetchMode( \PDO::FETCH_ASSOC );
    }

    /**
     * Overwrite the default \PDOStatement::bindParam so that the param & variables are stored in $this->values
     *
     * @param mixed $parameter
     * @param mixed $value
     * @param int   $data_type
     *
     * @return bool|void
     * @throws DatabaseException
     */
    public function bindValue($parameter, $value, $data_type = \PDO::PARAM_STR){
        try {
            $this->values[$parameter] = $value;
            parent::bindValue($parameter, $value, $data_type);
        } catch(\PDOException $e) {
            throw new DatabaseException($e->getMessage(), $this->queryString, $this->values, $e);
        }
    }

    public function execute(array $input_parameters = null){
        try {
            if($input_parameters != null)
                $this->values = array_merge($input_parameters, $this->values);
            parent::execute($input_parameters);
        } catch(\PDOException $e) {
            throw new DatabaseException($e->getMessage(), $this->queryString, $this->values, $e);
        }
    }

}

?>


// lib/Database.php
<?php

namespace Database;

require_once('DatabaseException.php');
require_once('QueryStatement.php');

use Database\QueryStatement;
use Database\DatabaseException;

/**
 * Class Database
 * This is a wrapper class - it's like a proxy to the default PDO methods, but
 * the methods have a try/catch block. In case a PDOException is thrown, this will
 * trigger a DatabaseException where the prepared query will be visible with the
 * prepared values.
 *
 * @package Database
 */
class Database extends \PDO {

    /**
     * Initialize database connection
     *
     * @param $dsn
     * @param $user (optional - in some drivers you can define the user&pass within the dsn string)
     * @param $pass (optional - in some drivers you can define the user&pass within the dsn string)
     *
     * @throws DatabaseException
     */
    public function __construct( $dsn, $user = null, $pass = null ) {
        if ( $dsn ) {
            try {
                parent::__construct( $dsn, $user, $pass );
                $this->setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
                $this->setAttribute( \PDO::ATTR_STATEMENT_CLASS, array('Database\QueryStatement', array($this)) );
            } catch ( \PDOException $e ) {
                throw new DatabaseException( "Could not connect to db!", 'Not available!', null, $e );
            }
        }
        else {
            throw new DatabaseException( 'Connection to database cannot be established! Missing parameters!' );
        }
    }

    public function prepare($statement, array $driver_options = array()){
        try {
            return parent::prepare( $statement, $driver_options );
        } catch ( \PDOException $e ) {
            throw new DatabaseException( $e->getMessage(), $statement, null, $e );
        }
    }

    public function exec($statement){
        try {
            return parent::exec( $statement );
        } catch ( \PDOException $e ) {
            throw new DatabaseException( $e->getMessage(), $statement, null, $e );
        }
    }
}


?>

这是一个示例用法:

// a_script_that_uses_db_connection.php
<?php

// Example usage.
require_once('lib/Database.php');
use Database\Database;

/**
 * Enter a valid DSN connection string. The strings for all supported databases
 * can be found at http://php.net/manual/en/pdo.drivers.php
 *
 * Most used DSN strings
 *
 * MySQL DSN string:
 * mysql:host=localhost;port=3306;dbname=testdb
 * OR
 * mysql:unix_socket=/tmp/mysql.sock;dbname=testdb
 * (http://php.net/manual/en/ref.pdo-mysql.connection.php)
 *
 * PostgreSQL DSN string:
 * pgsql:host=localhost;port=5432;dbname=testdb;user=bruce;password=mypass
 * (http://php.net/manual/en/ref.pdo-pgsql.connection.php)
 *
 * SQLite DSN string:
 * sqlite:/opt/databases/mydb.sq3
 * sqlite::memory:
 * sqlite2:/opt/databases/mydb.sq2
 * sqlite2::memory:
 * (http://php.net/manual/en/ref.pdo-sqlite.connection.php)
 *
 */
$connect_string = "pgsql:host=127.0.0.1;port=5432;dbname=testing_database";
$db = new Database($connect_string, 'my_username', 'my_password');

// Create a prepared statement
$ps = $db->prepare('SELECT * FROM users WHERE username = :username');
$ps->bindValue(':username', 'admin');
$ps->execute();
$ps->fetchAll(PDO::FETCH_ASSOC);

// An invalid query (i.e. the query throws PDOException)
$ps = $db->prepare('SELECT * FROM users WHERE usernamee = :username');
$ps->bindValue(':username', 'admin');
$ps->execute();
$ps->fetchAll(PDO::FETCH_ASSOC);
// The result will be a DatabaseException with the following message
// Database\DatabaseException: SQLSTATE[42703]: Undefined column: 7 ERROR: column "usernamee" does not exist LINE 1: SELECT * FROM users WHERE usernamee = $1 ^ --- [ Query: [ SELECT * FROM users WHERE usernamee = 'admin' ] ] in /path/to/lib/QueryStatement.php on line 51
// and a stack trace which will show you exactly where the query was executed.

?>

这几乎是一个扩展 PDO 类的包装器类。如果在准备好的语句中抛出 PDOException,则使用实际查询生成新的DatabaseException

您可以使用 git 从 here 克隆代码

希望这可以帮助您和所有其他试图解决这个问题的开发者。

关于php - 如何创建 MySQLi_prep 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17054888/

相关文章:

php - IF/THEN 的 Python 语法与 PHP 相比

PHP打包一些数据

javascript - Ajax/Javascript - 仅刷新一次

php - SMTP 连接失败并激活 TLS

php - MySQL查询不符合查询条件时返回第0行

mysql - 此简单查询的正确 MySQL 索引

mysql - 无法启动 MySQL 社区服务器

php - 如何在 symfony yml 配置文件中从 docker 获取环境变量

php Codeception 启动不那么快 : [PHPUnit\Framework\Exception] Undefined index: ELEMENT

mysql - SQL:如何计算有多少行包含多个关键字