Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

The code I've written so far works fine if there is only one named place holder for a prepared statement but if there are multiple conditions for a query, it doesn't return any results from the database.

For instance:

$query = array();
$query['columns'] = array('*');
$query['tables'] = array('esl_comments');
$query['where'] = array(
    'esl_comments.commentVisible' => array('=', 'Y')
);

Works fine. But if I try:

$query = array();
$query['columns'] = array('*');
$query['tables'] = array('esl_comments');
$query['where'] = array(
    'esl_comments.commentVisible' => array('=', 'Y'),
    'esl_comments.commentID' => array('=', '1'),
);

(Note the additional commentID parameter) it fails to return anything despite there being data in the mySQL database that satisfies the conditions.

The PDO code i've written is:

$sql ='SELECT ';
                foreach($query['columns'] as $column){ //What columnns do we want to fetch?
                    $sql.=$column . ", ";
                }
                $sql = rtrim($sql, " ,");
                $sql .=' FROM '; //Which tables will we be accessing?
                foreach($query['tables'] as $tables){
                    $sql.=$tables . ", ";
                }
                $sql = rtrim($sql, " ,"); //Get rid of the last comma
                $sql .=' WHERE ';

                if(array_key_exists('where', $query)) //check if a where clause was provided
                {
                    $fieldnames = array_keys($query['where']);
                    $count = 0;
                    $size = sizeof($fieldnames);
                    $bindings = array();
                    foreach($query['where'] as $where){

                        $cleanPlaceholder = str_replace("_", "", $fieldnames[$count]);
                        $cleanPlaceholder = str_replace(".", "", $cleanPlaceholder);
                        $sql.=$fieldnames[$count].$where[0].":".$cleanPlaceholder." AND ";
                        $bindings[$cleanPlaceholder]=$where[1];
                        $count++;
                    }
                    $sql = substr($sql, 0, -5);  //Remove the last AND
                }
                else{ //no where clause so set it to an always true check
                    $sql.='1=1';
                    $bindings=array('1'=>'1'); //Provide default bindings for the statement
                }

                $sql .= ';'; //Add the semi-colon to note the end of the query
                echo $sql . "<br/><br/>";
            //  exit();
                $stmt = $this->_connection->prepare($sql);

                foreach($bindings as $placeholder=>$bound){
                    echo $placeholder . " - " . $bound."<br/>";
                    $stmt->bindParam($placeholder, $bound);
                }

                $result = $stmt->execute();
                echo $stmt->rowCount() . " records<br/>";

                $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

I'm building queries dynamically and therefore I am cleaning the placeholders, by stripping them of periods and underscores - hence the use of the 'cleanPlaceholder' variable.

The query being generated looks like this:

SELECT * FROM esl_comments WHERE esl_comments.commentVisible=:eslcommentscommentVisible AND esl_comments.commentID=:eslcommentscommentID;

And the parameters being bound look like this:

eslcommentscommentVisible - Y
eslcommentscommentID - 1
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
246 views
Welcome To Ask or Share your Answers For Others

1 Answer

bindParam Requires a reference

The problem is caused by the way you bind parameters in the foreach loop.

foreach($bindings as $placeholder=>$bound){
    echo $placeholder . " - " . $bound."<br/>";
    $stmt->bindParam($placeholder, $bound);
}

bindParam requires a reference. It binds the variable, not the value, to the statement. Since the variable in a foreach loop is reset at the start of each iteration, only the last reference to $bound is left intact, and you end up binding all your placeholders to it.

That's why your code works when $query['where'] contains only one entry, but fails when it contains more than one.

You can solve the problem in 2 ways:

Pass by reference

foreach($bindings as $placeholder => &$bound) {  //pass $bound as a reference (&)
    $stmt->bindParam($placeholder, $bound);     // bind the variable to the statement
}

Pass by value

Use bindValue instead of bindParam:

foreach($bindings as $placeholder => $bound) {  
    $stmt->bindValue($placeholder, $bound);     // bind the value to the statement
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...