Вставить / обновить вспомогательную функцию с помощью PDO

php mysql pdo

13709 просмотра

11 ответа

У меня есть очень простая вспомогательная функция для создания оператора SET для традиционного простого использования драйвера mysql:

function dbSet($fields) {
  $set='';
  foreach ($fields as $field) {
    if (isset($_POST[$field])) {
      $set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
    }
  }
  return substr($set, 0, -2); 
}

используется как это

$id = intval($_POST['id']);
$fields = explode(" ","name surname lastname address zip fax phone");
$_POST['date'] = $_POST['y']."-".$_POST['m']."-".$_POST['d'];
$query  = "UPDATE $table SET ".dbSet($fields)." stamp=NOW() WHERE id=$id";

это делает код довольно СУХИМ и легким, но в то же время гибким.

Я должен спросить, хочет ли кто-нибудь разделить подобную функцию, используя функцию подготовленных заявлений PDO?

Я все еще сомневаюсь, как этого добиться.
Существует ли прямой и простой способ использовать подготовленные операторы PDO для вставки данных? В какой форме это должно быть? Помощник строителя запросов? Или вставить запрос помощника? Какие параметры это должно принять?

Я надеюсь, что это может быть достаточно легко, чтобы быть использован в качестве ответа здесь на SO. Потому что в каждой теме мы видим рекомендации по использованию готовых операторов, но нет ни одного хорошего примера. Я имею в виду пример из реальной жизни. Я считаю, что набирать bind_param () 20 раз - не очень хороший стиль программирования. И даже 20 вопросительных знаков тоже.

Автор: Your Common Sense Источник Размещён: 12.11.2019 09:17

Ответы (11)


10 плюса

Решение

У меня обычно есть класс, расширяющий PDO, но мой класс довольно индивидуален. Если я его почистю и протестирую, я опубликую это позже. Вот решение для вашей системы, однако.

function dbSet($fields, &$values) {
    $set = '';
    $values = array();

    foreach ($fields as $field) {
        if (isset($_POST[$field])) {
            $set .= "`$field` = ?,";
            $values[] = $_POST[$field];
        }
    }

    return rtrim($set, ',');
}

$fields = explode(" ","name surname lastname address zip fax phone date");
$_POST['date'] = $_POST['y']."-".$_POST['m']."-"$_POST['d'];

$query  = "UPDATE $table SET ".dbSet($fields, $values).", stamp=NOW() WHERE id=?";
$values[] = $id;

$dbh->prepare($query);
$dbh->execute($values);  

Это не может быть идеальным и может использовать настройки. Принимает во внимание, что $dbhэто настройка с подключением PDO. В ожидании любых незначительных синтаксических проблем, которые я сделал, это должно работать.

РЕДАКТИРОВАТЬ

На самом деле, я думаю, я бы пошел на доктрину ORM (или другой ORM). Когда вы настраиваете модель и добавляете туда все проверки, это так же просто, как:

$table = new Table();
$table->fromArray($_POST);
$table->save();

Это должно заполнить содержимое легко. Это, конечно, с ORM, как Doctrine.

ОБНОВЛЕНО

Сделал некоторые незначительные твики первого кода, например, положить issetобратно и использование rtrimболее substr. Чтобы приступить к созданию макета класса расширения PDO, нужно просто разработать макет и сделать несколько модульных тестов, чтобы убедиться, что он работает.

Автор: Jim W. Размещён: 22.09.2010 08:46

5 плюса

Спасибо всем.
Каждый ответ был полезным, и я хотел бы разделить награду.

В конце, к моему удивлению, я смог сделать это так же, как и раньше, основываясь на принятом ответе

$fields = array("login","password");
$_POST['password'] = MD5($_POST['login'].$_POST['password']);
$stmt = $dbh->prepare("UPDATE users SET ".pdoSet($fields,$values)." WHERE id = :id");
$values["id"] = $_POST['id'];
$stmt->execute($values);

Его можно включить в вспомогательную функцию, но я сомневаюсь, что это необходимо. Это сократит код всего на одну строку.

Код pdoSet:

function pdoSet($fields, &$values, $source = array()) {
  $set = '';
  $values = array();
  if (!$source) $source = &$_POST;
  foreach ($fields as $field) {
    if (isset($source[$field])) {
      $set.="`$field`=:$field, ";
      $values[$field] = $source[$field];
    }
  }
  return substr($set, 0, -2); 
}
Автор: Your Common Sense Размещён: 13.10.2010 08:09

4 плюса

Я бы расширил Core PDO Class и применил такой метод:

class Database extends PDO
{
    public function QueryFromPost($Query,$items)
    {
        $params = array();
        $Query .= ' WHERE ';

        foreach($items as $key => $default)
        {
             $Query .= ' :' . $key. ' = ' . $key;
             if(isset($_POST[$key]))
             {
                  $params[':' . $key] = $_POST[$key];
             }else
             {
                 $params[':' . $key] = $default;
             }
        }
        $s = $this->prepare($Query);
        return $s->execute($params);
    }
}

Тогда используйте так

$db = new Database(/*..Default PDO Params*/);
$statement = $db->QueryFromPost('SELECT * FROM employees',array('type' => 'plc'));
foreach($preparedStatement->fetchAll() as $row)
{
    //...
}

Но, как уже было сказано, вам следует ОЧЕНЬ устать от того, что вы пытаетесь сделать, вам нужно проверить свои данные, они были очищены, но вы не проверены.

Автор: RobertPitt Размещён: 22.09.2010 09:02

2 плюса

Я исправлял что-то тривиальное для того, что я считаю повторяющимися случаями привязки параметров. http://fossil.include-once.org/hybrid7/wiki/db

Так или иначе; это обеспечивает некоторые альтернативные подготовленные операторы-заполнители . Ваш пример может быть сокращен до:

db("UPDATE table SET :, WHERE id=:id", $columns[], $where[]);

Этот случай работает только с именованными параметрами, поэтому $ set будет array ("name" => ..) и $ where = array ("id" => 123). :,Получает расширен на первом массиве вы проходите. Он заменяется парами name =: name, разделенными запятыми (поэтому его мнемоника равна ).:,

Есть еще несколько заполнителей :, :& ::и :?для разных вариантов использования. Только ??это действительно что-то вроде стандарта. Так что к этому нужно привыкнуть, но это значительно упрощает подготовленные операторы и привязку массива (чего PDO не делает изначально).

Автор: mario Размещён: 22.09.2010 09:09

1 плюс

Вот мой общий класс абстракции базы данных. Посмотрите на autoExecute()функцию. Он предлагает массу гибкости для всего, что вы, возможно, захотите достичь. Я должен предупредить, что это было написано для PHP 5.3, и было немного адаптировано для PostgreSQL.

<?php
/**
 * Database abstraction and query result classes
 * Requires PHP 5.3
 *
 * Events:
 *  - on_commit - Dispatched when the transaction is successfully committed to the DB
 *  - on_rollback - Dispatched when the transaction is rolled back in the DB
 *
 * @author Kenaniah Cerny <kenaniah@gmail.com>
 * @version 1.1.2
 * @license http://creativecommons.org/licenses/by/3.0/us/
 * @copyright Copyright (c) 2009, Kenaniah Cerny
 */
class Database extends PDO {

    private $stmt;
    private $good_trans = null;
    private $nested_transactions = 0; //Keeps track of virtual transaction nesting level
    private $callbacks = array();

    private static $connections = array(); //Keeps track of opened connections

    /**
     * Returns a database instance using lazy instantiation
     * @param string $name a database connection name
     * @param array $config database config details for a new connection
     */
    static function getInstance($name = 'main', $config=array()){

        //Attempt to return an existing connection
        if(array_key_exists($name, self::$connections)):
            return self::$connections[$name];
        endif;

        //Attempt to create a new connection
        $host = in_array($config['host'], array('localhost', '127.0.0.1')) ? "" : ";host=" . $config['host'];
        $db = new Database($config['driver'].":dbname=".$config['name'].$host, $config['user'], $config['pass']);

        //Save to connection pool
        self::$connections[$name] = $db;

        return $db;

    }

    /**
     * Registers a callback to be run when the given event is invoked
     * @param string $event Event name
     * @param callable $callable
     */
    public function register_listener($event, $callable){

        if(!array_key_exists($event, $this->callbacks)):
            $this->callbacks[$event] = array($callable);
        else:
            $this->callbacks[$event][] = $callable;
        endif;

    }

    /**
     * Invokes callbacks for the given event type
     * @param string $event Event name
     * @param boolean $stop_on_false Stops bubbling this event if one of the handlers returns false
     */
    protected function dispatch_event($event, $stop_on_false = true){

        if(!array_key_exists($event, $this->callbacks)) return;

        foreach($this->callbacks[$event] as $callable):

            $res = call_user_func($callable, $this, $event);
            if($stop_on_false && $res === false) return false;

        endforeach;

        return true;

    }

    /**
     * PDO Constructor
     * @param $dsn
     * @param $username
     * @param $password
     */
    function __construct($dsn, $username, $password) {
        parent::__construct($dsn, $username, $password);
    }

    /**
     * Prepares an SQL statement
     * @param string $sql
     */
    function prepare($sql) {
        $stmt = parent::prepare($sql, array(PDO::ATTR_STATEMENT_CLASS => array(__NAMESPACE__.'\DatabaseStatement')));
        $stmt->setFetchMode(PDO::FETCH_ASSOC);
        return $stmt;
    }

    /**
     * Prepares an executes an SQL statement with the parameters provided
     * @param string $sql
     * @param array $params
     */
    function execute($sql, $params = array()) {

        if($this->debug):
            var_dump("Statement:\n".$sql."\nParams: ".$this->fmt($params));
        endif;

        try {
            $stmt = $this->prepare($sql);
            $val = $stmt->execute((array) $params);
            if($stmt->errorCode() != '00000') error_log($this->errormsg());
            if($this->debug && $stmt->errorCode() != '00000'){
                var_dump($stmt->errorInfo());
                Errors::add("Database error: ".$this->errormsg(), E_USER_ERROR);
            }
            if(!$val) return false;
        } catch (PDOException $e){
            if($this->debug) var_dump($stmt->errorInfo());
            error_log($this->errormsg());
            Errors::add("Database error: ".$this->errormsg(), E_USER_ERROR);
            if($this->nested_transactions) $this->failTrans();
            else throw $e;
        }

        $this->stmt = $stmt;

        return $stmt;

    }    

    /**
     * Returns the value of the first column of the first row
     * of the database result.
     * @param $sql
     * @param $params
     */
    function getOne($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getOne() : false;
    }

    /**
     * Fetches a single column (the first column) of a result set
     * @param $sql
     * @param $params
     */
    function getCol($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getCol() : false;
    }

    /**
     * Fetches rows in associative array format
     * @param $sql
     * @param $params
     */
    function getAssoc($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getAssoc() : false;
    }

    /**
     * Fetches rows in array format with columns
     * indexed by ordinal position
     * @param $sql
     * @param $params
     */
    function getArray($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getArray() : false;
    }

    /**
     * Fetches all rows in associative array format
     * @param $sql
     * @param $params
     */
    function getAll($sql, $params = array()){
        return $this->getAssoc($sql, $params);
    }

    /**
     * Fetches rows in array format where the first column
     * is the key name and all other columns are values
     * @param $sql
     * @param $params
     */
    function getKeyPair($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getKeyPair() : false;
    }

    /**
     * Fetches rows in multi-dimensional format where the first
     * column is the key name and all other colums are grouped
     * into associative arrays for each row
     * @param $sql
     * @param $params
     */
    function getGroup($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getGroup() : false;
    }

    /**
     * Fetches only the first row and returns it as an
     * associative array
     * @param $sql
     * @param $params
     */
    function getRow($sql, $params = array()){
        $stmt = $this->execute($sql, $params);
        return $stmt ? $stmt->getRow() : false;
    }

    /**
     * Internal function used for formatting parameters in debug output
     * @param unknown_type $params
     */
    private function fmt($params){
        $arr = array();
        foreach((array) $params as $k=>$v){
            if(is_null($v)) $v = "NULL";
            elseif(is_bool($v)) $v = $v ? "TRUE" : "FALSE";
            $arr[] = "[".$k."] => ".$v;
        }
        return "Array(".join(", ", $arr).")";
    }

    /**
     * Returns the number of affected rows from an executed statement
     */
    function affected_rows(){
        return $this->stmt ? $this->stmt->rowcount() : false;
    }

    /**
     * Automated statement processing
     *
     * Params array takes the following fields:
     *
     *  - table         The name of the table to run the query on
     *
     *  - data          A key-value paired array of table data
     *
     *  - mode          INSERT, UPDATE, REPLACE, or NEW
     *
     *  - where         Can be a string or key-value set. Not used on INSERTs
     *                  If key-value set and numerically indexed, uses values from data
     *                  If key-value and keys are named, uses its own values
     *
     *  - params        An array of param values for the where clause
     *
     *  - returning     Optional string defining what to return from query.
     *                  Uses PostgreSQL's RETURNING construct
     *
     *  This method will return either a boolean indicating success, an array
     *  containing the data requested by returning, or a boolean FALSE indicating
     *  a failed query.
     *
     */
    function autoExecute($table, $params, $data){

        $fields = array(); //Temp array for field names
        $values = array(); //Temp array for field values
        $set = array(); //Temp array for update sets
        $ins = array(); //Insert value arguments

        $params['table'] = $table;
        $params['data'] = $data;

        $params['params'] = (array) $params['params'];

        //Parse the data set and prepare it for different query types
        foreach((array) $params['data'] as $field => $val):

            $fields[] = $field;
            $values[] = $val;
            $ins[] = "?";
            $set[] = $field . " = ?";

        endforeach;

        //Check for and convert the array/object version of the where clause param
        if(is_object($params['where']) || is_array($params['where'])):

            $clause = array();
            $params['params'] = array(); //Reset the parameters list

            foreach($params['where'] as $key => $val):

                if(is_numeric($key)):
                    //Numerically indexed elements use their values as field names
                    //and values from the data array as param values
                    $field = $val;
                    $params['params'][] = $params['data'][$val];
                else:
                    //Named elements use their own names and values
                    $field = $key;
                    $params['params'][] = $val;
                endif;

                $clause[] = $field . " = ?";

            endforeach;

            $params['where'] = join(" AND ", $clause);

        endif;

        //Figure out what type of query we want to run
        $mode = strtoupper($params['mode']);
        switch($mode):
            case 'NEW':
            case 'INSERT':

                //Build the insert query
                if(count($fields)):
                    $sql =  "INSERT INTO " . $params['table']
                            . " (" . join(", ", $fields) . ")"
                            . " SELECT " . join(", ", $ins);
                else:
                    $sql =  "INSERT INTO " . $params['table']
                            . " DEFAULT VALUES";
                endif;

                //Do we need to add a conditional check?
                if($mode == "NEW" && count($fields)):
                    $sql .= " WHERE NOT EXISTS ("
                            . " SELECT 1 FROM " . $params['table']
                            . " WHERE " . $params['where']
                            . " )";
                    //Add in where clause params
                    $values = array_merge($values, $params['params']);
                endif;

                //Do we need to add a returning clause?
                if($params['returning']):
                    $sql .= " RETURNING " . $params['returning'];
                endif;

                //Execute our query
                $result = $this->getRow($sql, $values);

                //Return our result
                if($params['returning']):
                    return $result;
                else:
                    return $result !== false;
                endif;

                break;
            case 'UPDATE':

                if(!count($fields)) return false;

                //Build the update query
                $sql =  "UPDATE " . $params['table']
                        . " SET " . join(", ", $set)
                        . " WHERE " . $params['where'];

                //Do we need to add a returning clause?
                if($params['returning']):
                    $sql .= " RETURNING " . $params['returning'];
                endif;

                //Add in where clause params
                $values = array_merge($values, $params['params']);

                //Execute our query
                $result = $this->getRow($sql, $values);

                //Return our result
                if($params['returning']):
                    return $result;
                else:
                    return $result !== false;
                endif;

                break;
            case 'REPLACE': //UPDATE or INSERT

                //Attempt an UPDATE
                $params['mode'] = "UPDATE";
                $result = $this->autoExecute($params['table'], $params, $params['data']);

                //Attempt an INSERT if UPDATE didn't match anything
                if($this->affected_rows() === 0):
                    $params['mode'] = "INSERT";
                    $result = $this->autoExecute($params['table'], $params, $params['data']);
                endif;

                return $result;

                break;
            case 'DELETE':

                //Don't run if we don't have a where clause
                if(!$params['where']) return false;

                //Build the delete query
                $sql =  "DELETE FROM " . $params['table']
                        . " WHERE " . $params['where'];

                //Do we need to add a returning clause?
                if($params['returning']):
                    $sql .= " RETURNING " . $params['returning'];
                endif;

                //Execute our query
                $result = $this->getRow($sql, $params['params']);

                //Return our result
                if($params['returning']):
                    return $result;
                else:
                    return $result !== false;
                endif;

                break;
            default:
                user_error('AutoExecute called incorrectly', E_USER_ERROR);
                break;
        endswitch;

    }

    /**
     * @see $this->startTrans()
     */
    function beginTransaction(){
        $this->startTrans();
    }

    /**
     * Starts a smart transaction handler. Transaction nesting is emulated
     * by this class.
     */
    function startTrans(){

        $this->nested_transactions++;
        if($this->debug) var_dump("Starting transaction. Nesting level: " . $this->nested_transactions);

        //Do we need to begin an actual transaction?
        if($this->nested_transactions === 1):
            parent::beginTransaction();
            $this->good_trans = true;
            $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        endif;

    }

    /**
     * Returns TRUE if the transaction will attempt to commit, and
     * FALSE if the transaction will be rolled back upon completion.
     */
    function isGoodTrans(){
        return $this->good_trans;
    }

    /**
     * Marks a transaction as a failure. Transaction will be rolled back
     * upon completion.
     */
    function failTrans(){
        if($this->nested_transactions) $this->good_trans = false;
        if($this->debug):
            Errors::add("Database transaction failed: ".$this->errorMsg());
        endif;
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
    }

    /**
     * @see $this->rollbackTrans()
     */
    function rollback(){
        $this->rollbackTrans();
    }

    /**
     * Rolls back the entire transaction and completes the current nested
     * transaction. If there are no more nested transactions, an actual
     * rollback is issued to the database.
     */
    function rollbackTrans(){
        if($this->nested_transactions):
            $this->nested_transactions--;
            if($this->debug) var_dump("Rollback requested. New nesting level: " . $this->nested_transactions);
            $this->good_trans = false;
            if($this->nested_transactions === 0):
                $this->good_trans = null;
                $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
                if($this->debug) var_dump("Transaction rolled back.");
                parent::rollback();
                $this->dispatch_event('on_rollback');
            endif;
        endif;
    }

    /**
     * Clears the nested transactions stack and issues a rollback to the database.
     */
    function fullRollback(){
        while($this->nested_transactions) $this->rollbackTrans();
    }

    /**
     * Returns the number of nested transactions:
     * 0 - There is no transaction in progress
     * 1 - There is one transaction pending
     * >1 - There are nested transactions in progress
     */
    function pending_trans(){
        return $this->nested_transactions;
    }

    /**
     * @see $this->completeTrans()
     */
    function commit($fail_on_user_errors = false){
        return $this->completeTrans($fail_on_user_errors);
    }

    /**
     * Completes the current transaction and issues a commit or rollback to the database
     * if there are no more nested transactions. If $fail_on_user_errors is set, the
     * transaction will automatically fail if any errors are queued in the Errors class.
     * @param boolean $fail_on_user_errors
     */
    function completeTrans($fail_on_user_errors = false){

        if(!$this->nested_transactions) return;

        //Fail the transaction if we have user errors in the queue
        if($fail_on_user_errors && Errors::exist()) $this->good_trans = false;

        //Do we actually need to attempt to commit the transaction?
        if($this->nested_transactions === 1):

            if(!$this->good_trans || !parent::commit()){
                if($this->debug) var_dump("Transaction failed: " . $this->errormsg());
                $this->rollbackTrans();
                return false;
            }

            //Transaction was good
            $this->nested_transactions--;
            $this->good_trans = null;
            $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
            if($this->debug) var_dump("Transaction committed.");
            $this->dispatch_event('on_commit', false);
            return true;
        else:
            //Don't take action just yet as we are still nested
            $this->nested_transactions--;
            if($this->debug) var_dump("Virtual commit. New nesting level: " . $this->nested_transactions);
        endif;

        return $this->good_trans;

    }

    /**
     * Returns the text of the most recently encountered error
     */
    function errormsg(){
        $msg = $this->errorInfo();
        return $msg[2];
    }

}

class DatabaseStatement extends \PDOStatement implements \Countable {

    /**
     * Binds passed parameters according to their PHP type and executes
     * the prepared statement
     */
    function execute($params = array()) {
        $i = 1;
        foreach($params as $k => $v):
            $mode = PDO::PARAM_STR;
            if(is_null($v)) $mode = PDO::PARAM_NULL;
            elseif(is_bool($v)) $mode = PDO::PARAM_BOOL;
            elseif(is_resource($v)) $mode = PDO::PARAM_LOB;
            $this->bindParam($i, $params[$k], $mode);
            $i++;
        endforeach;
        $ok = parent::execute();
        return $ok ? $this : false;
    }

    /**
     * Returns the value of the first column of the first row
     */
    function getOne() {
        return $this->fetchColumn(0);
    }

    /**
     * Returns an array of values of the column found at $index
     * position.
     * @param $index
     */
    function getCol($index=0) {
        return $this->fetchAll(PDO::FETCH_COLUMN, $index);
    }

    /**
     * Returns all rows in numeric array format
     */
    function getArray(){
        return $this->fetchAll(PDO::FETCH_NUM);
    }

    /*
     * Returns all rows in associative array format
     */
    function getAll(){
        return $this->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Returns all rows in associative array format
     */
    function getAssoc() {
        return $this->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Returns rows in multi-dimensional format where the first
     * column is the key name and all other colums are grouped
     * into associative arrays for each row
     */
    function getGroup() {
        return $this->fetchAll(PDO::FETCH_GROUP);
    }

    /**
     * Returns a single row in associative format
     */
    function getRow(){
        return $this->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * Fetches rows in array format where the first column
     * is the key name and all other columns are values
     */
    function getKeyPair(){
        //Emulate it
        $tmp = $this->fetchAll(PDO::FETCH_ASSOC);
        $arr = array();
        for($i = 0; $i < count($tmp); $i++){
            $arr[array_shift($tmp[$i])] = count($tmp[$i]) > 1 ? $tmp[$i] : array_shift($tmp[$i]);
        }
        return $arr;
    }

    /**
     * Returns the number of rows returned by this statement
     */
    function recordCount(){

        return $this->rowCount();

    }

    /**
     * Returns the number of rows returned by this statement
     */
    function count(){

        return $this->rowCount();

    }
}
Автор: Kenaniah Размещён: 02.10.2010 12:09

1 плюс

Хотя мой класс БД не использует подготовленные операторы, я все же хочу упомянуть об этом здесь. Я не вижу никакой причины реализовывать все с готовыми заявлениями. Я знаю, что подготовленные заявления быстрее , но только при многократном использовании . Если вы выполняете запрос только один раз (и это единственный тип запроса, который мне обычно нужно использовать), это будет медленнее . Таким образом, контрпродуктивно использовать готовые заявления везде.

Правильное описание класса можно найти в другом месте в stackoverflow . Но вот некоторые из хороших вещей:

  • Уровень базы данных менее 100 строк
  • DB::xдля DB::instance()->executeи DB::qдляDB::instance()->query
  • autoQuoting с двумя типами заполнителей ?и ?x(где xможет быть ,, &и |). ?,Заполнитель может быть использован в качестве UPDATE помощника здесь.

Но для полной информации см. Сообщение от stackoverflow, связанное выше;)

PS: README в репо не распространяется на этот класс. Это для нормальных DB.php, а не для DB_intelligent.php. PPS: класс написан для PHP 5.3. Если вы хотите использовать его в PHP 5.2, просто скопируйте все эти методы PDO DB_forPHP52.phpв DB_intelligent.phpи удалите __callStaticметод.

Автор: NikiC Размещён: 02.10.2010 07:15

1 плюс

Просто в дополнение к другим ответам: метод правильной кавычки имен столбцов:

/**
 * Escape identifier (database/table/column name) - ie. if you're using MySQL:
 * db_name.tbl_name.col_name -> `db_name`.`tbl_name`.`col_name`
 **/
protected function quoteIdentifier($identifier) {
    static $escapeChars = array(
        'mysql'  => '``',
        'oracle' => '""',
        'mssql'  => '[]',
        //...
    );

    $escape = $escapeChars[$this->getAttribute(self::ATTR_DRIVER_NAME)];
    $identifier = (array) explode('.', $identifier);
    $identifier = array_map(function($segment) use($escape) {
        return $escape[0] . $segment . $escape[1];
    }, $identifier);

    return implode('.', $identifier);
}
Автор: Crozin Размещён: 02.10.2010 07:45

0 плюса

Вы можете расширить PDO следующим образом:

class CustomPDO extends PDO {

    public function updateTable($sTable, array $aValues = array()){

        if (!empty($aValues) && !empty($sTable)){

            # validation of table / columns name
            $sTable = mysql_real_escape_string($sTable);

            $aColumns = array_map('mysql_real_escape_string',array_keys($aValues));

            $aElements = array();

            foreach ($aColumns as $sColumn){

                $aElements[] = "`$sColumn`= :$sColumn";

            } // foreach

            $sStatement = "UPDATE $sTable SET " . implode(',', $aElements);

            $oPDOStatement = $this->prepare($sStatement);

            if ($oPDOStatement){

                return $oPDOStatement->execute($aValues);

            } // if

        } // if

        return false;

    } // updateTable

}

# usage :
# $oDb->updateTable('tbl_name',$_POST);


# test

error_reporting (E_ALL);
ini_Set('display_errors',1);

$oDb = new CustomPDO('sqlite::memory:');

$oDb->exec('CREATE TABLE t1(c1 TEXT, c2 INTEGER)');

$oDb->exec("INSERT INTO t1(c1, c2) VALUES ('X1',1)");

var_dump($oDb->query('SELECT * FROM t1')->fetchAll(PDO::FETCH_ASSOC));

$oDb->updateTable('t1', array('c1'=>'f1','c2**2'=>2));

var_dump($oDb->query('SELECT * FROM t1')->fetchAll(PDO::FETCH_ASSOC));
Автор: ts. Размещён: 29.09.2010 08:26

0 плюса

Как и другие, я расширил стандартный класс PDO для своих нужд. Что-то вроде этого может подойти вам:

Class ExtendedPDO extends PDO
{

    public function prepareArray($sql, array $data)
    {
        // Call the standard prepare method
        $statement = parent::prepare($sql);

        foreach ($data as $field=>$value) {
            $statement->bindValue(':' . $field, $value);
        }

        return $statement;
    }

}

Тогда вы можете использовать его довольно просто:

// Include connection variables
include '../includes/config/database.php';

// The data to use in the query
$data = array(
    'title' => 'New value',
    'id'    => 1,
);

// The query you want to run
$sql = '
    UPDATE
        test
    SET
        title = :title
    WHERE
        id = :id
';

try {
    // Connect to the database
    $dbh = new ExtendedPDO(PDO_DSN, PDO_USERNAME, PDO_PASSWORD);

    // Attach the data to your query
    $stmt = $dbh->prepareArray($sql, $data);

    // Run it
    $stmt->execute();
} catch (PDO Exception $e) {
    echo $e->getMessage();
}
Автор: Nev Stokes Размещён: 01.10.2010 04:18

0 плюса

Запросы на вставку часто требуют много заполнителей. В таком случае стиль вопросительного знака трудно читать, а именованные параметры повторяются и подвержены ошибкам ввода. Итак, я создал функцию для всего запроса вставки:

function insert($table, $col_val){
    global $db;
    $table = preg_replace('/[^\da-z_]/i', '', $table);
    $smt = $db->prepare("DESCRIBE `$table`");
    $smt->execute();
    $columns = $smt->fetchAll(PDO::FETCH_COLUMN);
    $sets = array();
    $exec = array();
    foreach($col_val as $col => $val){
        if(!in_array($col, $columns))
            return false;
        $sets[] .= "`$col`=?";
        $exec[] = $val;
    }
    $set = implode(',', $sets);
    $smt = $db->prepare("INSERT INTO `$table` SET $set");
    $smt->execute($exec);
    return $db->lastInsertId();
}

Использование простое:

insert('table_name', array(
    'msg'   =>  'New message',
    'added' =>  date('Y-m-d H:i:s'),
));

И если вам нужно lastInsertId():

$new_id = insert(...
Автор: rybo111 Размещён: 10.03.2016 10:54

-1 плюса

Ссылка: Как я могу предотвратить внедрение SQL в PHP?

$preparedStatement = $db->prepare('SELECT * FROM employees WHERE name = :name');
$preparedStatement->execute(array(':name' => $name));
$rows = $preparedStatement->fetchAll();
Автор: Phill Pafford Размещён: 22.09.2010 08:47
32x32