开发者

prepared statements - creating a single method*

FYI. ended up going with PDO solution as this was simpler.

I'm trying to add a single method to handle all queries to the database. I want the queries to use parameter binding. How do I handle a variable amount of function parameters in mysqli_stmt_bind_param()?

This post here led me to understand the pros of parameter binding.

Here is my example code..where I am currently stuck at is marked.

INPUT PARAMETERS

  $query = "INSERT INTO b0 VALUES (?, ?, ?)"
  $par_arr = {'bookmark', 'http://www.bookmark.com', 'tag'}

PROTOTYPE CODE

  p开发者_运维百科rotected static function query($query, $par_arr)
    {
    if($statement=mysqli_prepare(one::$db, $query) 
      {
      mysqli_stmt_bind_param($statement, "s", ...variable amount of parameters...);<----how should this be handled?
      ...


Update 2: If you experience any further problems with this code, then you should probably follow this advice and use PDO instead.

This is how you should be using call_user_func_array [docs]:

protected static function query($query, $types, $values) {
    if($statement = mysqli_prepare(one::$db, $query) {
        $parameters = array_merge(array($statement, $types), $values);    
        call_user_func_array('mysqli_stmt_bind_param', $parameters);
        // ...
    }
}

where $types is a string indicating the type of each value, as described in the mysqli_stmt_bind_param documentation (call_user_func_array is even mentioned there).


Update: It seems it is not that easy after all, and you have to create references to the values first:

 foreach($values as $k => $v) {
     $values[$k] = &$v;
 }

 $parameters = array_merge(array($statement, $types), $values);
 call_user_func_array('mysqli_stmt_bind_param', $parameters);
 // ...

call_user_func_array is for user defined functions per php.net

No it's not. The first parameter is of type callback, and the documentation says (emphasis mine):

A PHP function is passed by its name as a string. Any built-in or user-defined function can be used, except language constructs such as: array(), echo(), empty(), eval(), exit(), isset(), list(), print() or unset().

Next remark:

is just used to simplify syntax for passing arrays to user defined functions

Have you had a look at the examples? Each element of the array you pass to call_user_func_array will be passed as argument to the function you specify. Arrays are the only way to have a collection of values of variable size.


Because i find prepared statements boring, I am processing placeholders manually, and experience not a single problem of yours

private function prepareQuery($args)
{
    $raw = $query = array_shift($args);
    preg_match_all('~(\?[a-z?])~',$query,$m,PREG_OFFSET_CAPTURE);
    $pholders = $m[1];
    $count = 0;
    foreach ($pholders as $i => $p)
    {
        if ($p[0] != '??')
        {
             $count++;
        }
    }
    if ( $count != count($args) )
    {
        throw new E_DB_MySQL_parser("Number of args (".count($args).") doesn't match number of placeholders ($count) in [$raw]");
    }
    $shift  = 0;
    $qmarks = 0;
    foreach ($pholders as $i => $p)
    {
        $pholder = $p[0];
        $offset  = $p[1] + $shift;
        if ($pholder != '??')
        {
            $value   = $args[$i-$qmarks];
        }
        switch ($pholder)
        {
            case '?n':
                $value = $this->escapeIdent($value);
                break;
            case '?s':
                $value = $this->escapeString($value);
                break;
            case '?i':
                $value = $this->escapeInt($value);
                break;
            case '?a':
                $value = $this->createIN($value);
                break;
            case '?u':
                $value = $this->createSET($value);
                break;
            case '??':
                $value = '?';
                $qmarks++;
                break;
            default:
                throw new E_DB_MySQL_parser("Unknown placeholder type ($pholder) in [$raw]");
        }
        $query = substr_replace($query,$value,$offset,2);
        $shift+= strlen($value) - strlen($pholder);
    }
    $this->lastquery = $query;
    return $query;
}

and thus an insert query can be called as simple as

$db->run("INSERT INTO table SET ?u",$data);


I have added the complete code to create a single method for select prepared statement and insert prepared statement, Please follow the instruction and read all the comments. create database with the name 'test' and add the following query to create "users" table in the

CREATE TABLE IF NOT EXISTS `users` (
  `users_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(100) NOT NULL,
  `last_name` varchar(100) NOT NULL,
  PRIMARY KEY (`users_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;


INSERT INTO `users` (`users_id`, `first_name`, `last_name`) VALUES
(1, 'daniel', 'martin'),
(2, 'daniel', 'martin');



<?php
error_reporting(E_ALL);
ini_set('display_errors',1);
session_start();

 class mysqli_access extends mysqli{    

        private $ip1;
        private $dbconn;
        private $hostname = HST;    // hostname
        private $username = USR;    // username
        private $password = PWD;    // password
        private $dbname   = DBN;    // datbase name 


        function mysqli_access()
        {


                $ip= $_SERVER['REMOTE_ADDR'];
                $ip1="ip_".str_replace('.', "", $ip);

                if(!is_resource($_SESSION[$ip1]))
                {
                        $this->dbconn = new mysqli($this->hostname,$this->username,$this->password,$this->dbname);
                        $_SESSION[$ip1] = $this->dbconn;
                        $dbconn = $this->dbconn;
                        if( $this->connect_error ) {
                                $this->Display_error('', $this->connect_errno, $this->connect_error, __FUNCTION__);
                        }
                }
                else {

                        $this->dbconn = $_SESSION[$ip1];        // success
                }

                return $this->dbconn;
        }


        function SelectPrepared($sql,$types,$params,$rows = '') 
        {
                $results = array();
                if ($stmt = $this->dbconn->prepare($sql)) {

                                if($types&&$params)
                                {
                                        $bind_names[] = $types;
                                        for ($i=0; $i<count($params);$i++) 
                                        {
                                                $bind_name = 'bind' . $i;
                                                $$bind_name = $params[$i];
                                                $bind_names[] = &$$bind_name;
                                        }
                                        $return = call_user_func_array(array($stmt,'bind_param'),$bind_names);
                                }
                                $stmt->execute(); /* execute query */
                                $meta = $stmt->result_metadata();
                                while ($field = $meta->fetch_field()) { 
                                        $var = $field->name; 
                                        $$var = null; 
                                        $fields_arr[$var] = &$$var;
                                }

                                call_user_func_array(array($stmt,'bind_result'),$fields_arr);
                                if($rows == 1){

                                        while ($stmt->fetch()) {
                                                $results = array();
                                                foreach($fields_arr as $k => $v)
                                                        $results[$k] = $v;
                                        }

                                }else{
                                        $i = 0;
                                        while ($stmt->fetch()) {
                                                $results[$i] = array();
                                                foreach($fields_arr as $k => $v)
                                                        $results[$i][$k] = $v;
                                                $i++;
                                        }

                                }

                                return $results;

                }
        }


        public function InsertPrepared($tblName,$arrFieldNameValue,$replace_flag=0){
            $TableName = $tblName;
                if($replace_flag==0)  
                {
                        $sqlFirst ="INSERT INTO " . $TableName . "(";
                }
                if($replace_flag==1)
                {
                        $sqlFirst ="INSERT IGNORE INTO " . $TableName . "(";                        
                }
                if($replace_flag==2)
                {
                        $sqlFirst ="REPLACE INTO " . $TableName . "(";                      
                }

                $sqlSecond =" values(";
                $params = array();
                $types = '';
                while(list($key,$value) = each($arrFieldNameValue))
                {                   
                        $sqlFirst   = $sqlFirst . $key . ",";
                        $sqlSecond  = $sqlSecond . '?' . ",";
                        $params[]   = $value;
                        $types      = $types . $this->GetValType($value);
                }               

                $sqlFirst   = substr($sqlFirst,0,strlen($sqlFirst)-1) . ") ";
                $sqlSecond  = substr($sqlSecond,0,strlen($sqlSecond)-1) .")";
                $sql        = $sqlFirst . $sqlSecond;

                if ($stmt = $this->dbconn->prepare($sql)) {

                    if($types&&$params)
                    {
                            $bind_names[] = $types;
                            for ($i=0; $i<count($params);$i++) 
                            {
                                    $bind_name      = 'bind' . $i;
                                    $$bind_name     = $params[$i];
                                    $bind_names[]   = &$$bind_name;
                            }
                            $return = call_user_func_array(array($stmt,'bind_param'),$bind_names);
                    }
                    $stmt->execute(); /* execute query */

                }                       
                return mysqli_insert_id($this->dbconn); 
        }

        private function GetValType($Item)
        {

             switch (gettype($Item)) {
                case 'NULL':
                case 'string':
                    return 's';
                    break;

                case 'integer':
                    return 'i';
                    break;

                case 'blob':
                    return 'b';
                    break;

                case 'double':
                    return 'd';
                    break;
            }
            return 's';

        }
 }






class Model_NAME extends mysqli_access
{   
        function Model_NAME() { 
                $this->tablename = TABLENAME;
                $this->mysqli_access();
        }

        ##---------------------------- Custom function start from here -----------------#

        ## fetch settings values
        function getUserRow($id,$key) {
            $sql ="SELECT first_name,last_name FROM ".$this->tablename." WHERE first_name=? and users_id  = ?";
            $param = "si";
            $array_of_params[] = addslashes($key);
            $array_of_params[] = addslashes($id);
            $result= $this->SelectPrepared($sql,$param,$array_of_params,1);
            //last parameter 1 use if want fetch single row , other wise function will return multi dimensional array
            return $result;
        }


        ## fetch settings values
        function getUserRows($last_name) {
            $sql ="SELECT first_name,last_name FROM ".$this->tablename." WHERE last_name= ?";
            $param = "s";
            $array_of_params[] = addslashes($last_name);
            $result= $this->SelectPrepared($sql,$param,$array_of_params);
            //last parameter 1 use if want fetch single row , other wise function will return multi dimensional array
            return $result;
        }

        function addValue($Array) {
            return $this->InsertPrepared( $this->tablename , $Array);
        }
}       


// configuration
define('HST','localhost');
define('USR','root');
define('PWD','techmodi');
define('DBN','test');
define('TABLENAME','users');

$obj =  new Model_NAME();
$arr = array();
$arr['first_name'] = addslashes("daniel");
$arr['last_name'] = addslashes("martin");
$obj->addValue($arr); // for insert records

// after inserting get the records
$singleRow = $obj->getUserRow(1,'daniel'); // for select single records
$multiRow =$obj->getUserRows('martin'); // for select records
echo '<pre>';
echo '<br/>-------- Single Records -----------------<br/>';
print_r($singleRow);
echo '<br/>-------- Multiple Records-----------------<br/>';
print_r($multiRow);
?>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜