简体   繁体   中英

Binding parameter values - PDO Invalid parameter number

I'm writing an API class to query data. I have a function in the class that uses a SELECT statement to query data for a specific, hardcoded table name (ie eventLog).

The query is listed below, where :value references a paremeter passed to the function:

// query
$sql = "SELECT :selectType 
        FROM  `log` :clause
        ORDER BY `:orderByColumn` :orderByClause
        LIMIT :limitStart, :limitStep";

I'm trying to use PDO statements to prevent SQL injection. I have read several helpful documents regarding how to correctly write PDO statements, including bindValue / bindParam.

Below is the full class file:

<?php

    // set requirements
    require_once 'Database.php';

    /*  EventLogsAPI class
    *  This class is used to query data from the eventLog table, and handle other data processing
    */
    class EventLogsAPI {

        // set class member variables
        private $connection;    // database connection
        private $records;       // records from query

        /*  Constructor function
        */
        public function __construct() {
              // create DB object
              $this->connection = new DBConnection();
        }

        /*  Collect records function
         *  Get the records from this prep statement, and store them in $this->records
         * 
         *  @param object - database object
        */
        public function collectRecords($prep) {
              // clear records from previous query
              $this->records = array();

              // execute query 
              $prep->execute();

              // for each record
              while (false !== ($row = $prep->fetch(PDO::FETCH_ASSOC))) {
                    $this->records[] = $row;
              }
        }

        /*  getEventLogData function 
         *  Get event log data with a optional (where) clause
         *
         *  @param string - select state (*, distinct, etc...)
         *  @param string - conditional SQL clause (e.g. where ID = 2)
         *  @param string - order by column (e.g. user, ID, date, etc...)
         *  @param string - order by clause (e.g. asc, desc)
         *  @param integer - starting limit param (i.e. 0)
         *  @param integer - limit step param (i.e. 25)
         *  @param boolean - used to debug SQL
         *  @return JSON - json containing array of records
        */
       public function getEventLogData($selectType, $clause, $orderByColumn, $orderByClause, $limitStart, $limitStep) {

              // query
              $sql = "SELECT :selectType 
                      FROM  `log` :clause
                      ORDER BY `:orderByColumn` :orderByClause
                      LIMIT :limitStart, :limitStep";

              // prep the query
              $prep = $this->connection->DB('log')->prepare($sql);

              // for each function argument 
              foreach ($bind = func_get_args() as $key => $value) {
                    // prevent null values
                    if ($value == NULL) {
                          // set to empty strings
                          $bind[$key] = "";
                    }

                    // bind value
                    $prep->bindValue(":$bind[$key]", $bind[$key]); 

                    // debug
                    echo ($key . " - " . $value . "\n");
              }

              // collect the records
              $this->collectRecords($prep);            
              // return records
              return json_encode($this->records);
        }
    }

?>

Returned network response in Chrome console:

0 - *
1 - 
2 - date
3 - DESC
4 - 0
5 - 20
<br />
<b>Warning</b>:  PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in <b>EventLogsAPI.class.php</b> on line <b>32</b><br />
[]

So, based on this execution, the bound SQL query should be:

// query
$sql = "SELECT * 
        FROM  `log` 
        ORDER BY `date` DESC
        LIMIT 0, 20";

However, I'm getting the error: Invalid parameter number: parameter was not defined .

I have checked the following:

  1. The :parameter name matches the bind value
  2. Ensuring the parameter number matches the PDO values in the query
  3. Binding the correct value
  4. Ensuring that there are no null values

I know there are several other questions regarding this, but I have yet to find a solution to this problem. Any help with debugging is much appreciated. Thank you for reading.

Placeholders can represent VALUES only. You cannot use them for SQL keywords/identifiers.

    FROM  `eventLog` :clause
                       ^--keyword/identifier

    ORDER BY `:orderByColumn` :orderByClause
             ^--------------^--- also wrong

You also can NOT quote placeholders. Once they're quoted, they're not placeholders anymore, they're literal strings.

If you want to insert that kind of thing dynmamically, you have to build the query string yourself:

$order_by = 'ASC':
$sql = "SELECT ... ORDER BY $order_by";

And yes, this leaves you open to potential sql injection attacks . Placeholders are perfect for data, but they're utterly useless for many other kinds of queries.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM