0

Managed to get PDO style working with DataTables and everything works fine, BUT the search box functionality. Display, paging, column sorting, etc all works, but as soon as I try to use the search box I get this error retrieved from firebug :

<br />
<b>Fatal error</b>:  Uncaught exception 'PDOException' with message 'SQLSTATE[HY093]: Invalid parameter number' in /home/test/public_html/assets/data-tables/test-pdo.php:94
Stack trace:
#0 /home/test/public_html/assets/data-tables/test-pdo.php(94): PDOStatement-&gt;execute()
#1 /home/test/public_html/assets/data-tables/test-pdo.php(140): TableData-&gt;get('accounts', 'account_id', Array)
#2 {main}
thrown in <b>/home/test/public_html/assets/data-tables/test-pdo.php</b> on line <b>94</b><br />

Any ideas with this?

<?php

/*
 * Script:    DataTables server-side script for PHP and MySQL
 * Copyright: 2012 - John Becker, Beckersoft, Inc.
 * Copyright: 2010 - Allan Jardine
 * License:   GPL v2 or BSD (3-point)
 */

define('INCLUDE_CHECK',true);

// These files can be included only if INCLUDE_CHECK is defined
require '/home/test/public_html/assets/functions/connect.php';

//inject bd connection into class
class TableData {
    /** @var \PDO */
    protected $_db;

    public function __construct(\PDO $_db) {
         $this->_db = $_db;
    }

    public function get($table, $index_column, $columns) {

        // Paging
        $sLimit = "";
        if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' ) {
            $sLimit = "LIMIT ".intval( $_GET['iDisplayStart'] ).", ".intval( $_GET['iDisplayLength'] );
        }

        // Ordering
        $sOrder = "";
        if ( isset( $_GET['iSortCol_0'] ) ) {
            $sOrder = "ORDER BY  ";
            for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ ) {
                if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" ) {
                    $sortDir = (strcasecmp($_GET['sSortDir_'.$i], 'ASC') == 0) ? 'ASC' : 'DESC';
                    $sOrder .= "`".$columns[ intval( $_GET['iSortCol_'.$i] ) ]."` ". $sortDir .", ";
                }
            }

            $sOrder = substr_replace( $sOrder, "", -2 );
            if ( $sOrder == "ORDER BY" ) {
                $sOrder = "";
            }
        }

        /* 
         * Filtering
         * NOTE this does not match the built-in DataTables filtering which does it
         * word by word on any field. It's possible to do here, but concerned about efficiency
         * on very large tables, and MySQL's regex functionality is very limited
         */
        $sWhere = "";
        if ( isset($_GET['sSearch']) && $_GET['sSearch'] != "" ) {
            $sWhere = "WHERE (";
            for ( $i=0 ; $i<count($columns) ; $i++ ) {
                if ( isset($_GET['bSearchable_'.$i]) && $_GET['bSearchable_'.$i] == "true" ) {
                    $sWhere .= "`".$columns[$i]."` LIKE :search OR ";
                }
            }
            $sWhere = substr_replace( $sWhere, "", -3 );
            $sWhere .= ')';
        }

        // Individual column filtering
        for ( $i=0 ; $i<count($columns) ; $i++ ) {
            if ( isset($_GET['bSearchable_'.$i]) && $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' ) {
                if ( $sWhere == "" ) {
                    $sWhere = "WHERE ";
                }
                else {
                    $sWhere .= " AND ";
                }
                $sWhere .= "`".$columns[$i]."` LIKE :search".$i." ";
            }
        }

        // SQL queries get data to display
        $sQuery = "SELECT SQL_CALC_FOUND_ROWS `".str_replace(" , ", " ", implode("`, `", $columns))."` FROM `".$table."` ".$sWhere." ".$sOrder." ".$sLimit;
        $statement = $this->_db->prepare($sQuery);

        // Bind parameters
        if ( isset($_GET['sSearch']) && $_GET['sSearch'] != "" ) {
            $statement->bindValue(':search', '%'.$_GET['sSearch'].'%', PDO::PARAM_STR);
        }
        for ( $i=0 ; $i<count($columns) ; $i++ ) {
            if ( isset($_GET['bSearchable_'.$i]) && $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' ) {
                $statement->bindValue(':search'.$i, '%'.$_GET['sSearch_'.$i].'%', PDO::PARAM_STR);
            }
        }

        $statement->execute();
        $rResult = $statement->fetchAll();

        $iFilteredTotal = current($this->_db->query('SELECT FOUND_ROWS()')->fetch());

        // Get total number of rows in table
        $sQuery = "SELECT COUNT(`".$index_column."`) FROM `".$table."`";
        $iTotal = current($this->_db->query($sQuery)->fetch());

        // Output
        $output = array(
            "sEcho" => intval($_GET['sEcho']),
            "iTotalRecords" => $iTotal,
            "iTotalDisplayRecords" => $iFilteredTotal,
            "aaData" => array()
        );

        // Return array of values
        foreach($rResult as $aRow) {
            $row = array();         
            for ( $i = 0; $i < count($columns); $i++ ) {
                if ( $columns[$i] == "version" ) {
                    // Special output formatting for 'version' column
                    $row[] = ($aRow[ $columns[$i] ]=="0") ? '-' : $aRow[ $columns[$i] ];
                }
                else if ( $columns[$i] != ' ' ) {
                    $row[] = $aRow[ $columns[$i] ];
                }
            }
            $output['aaData'][] = $row;
        }

        echo json_encode( $output );
    }

}

header('Pragma: no-cache');
header('Cache-Control: no-store, no-cache, must-revalidate');

// Create instance of TableData class
//$table_data = new TableData();
$table_data = new TableData($db);

// Get the data
//$table_data->get('table_name', 'index_column', array('column1', 'column2', 'columnN'));
$table_data->get('accounts', 'account_id', array('account_id', 'account_username', 'account_password', 'account_email'));

?>
user756659
  • 3,372
  • 13
  • 55
  • 110
  • Removing "PDO::ATTR_EMULATE_PREPARES => false" from my db connection settings solves the problem... however, from what I read I do not want to remove this setting. – user756659 Nov 27 '13 at 04:38
  • what certainly you have read? – Your Common Sense Nov 27 '13 at 08:08
  • From my understanding if you do not use PDO::ATTR_EMULATE_PREPARES => false in your connection setting then the statements are emulated. What is the point of using pdo then? – user756659 Nov 27 '13 at 14:37
  • There is not, if you can emulate prepared statements yourself. I still see no reason why can't you turn it ON – Your Common Sense Nov 27 '13 at 14:40
  • Not following your response. Turning it on (default value) causes no errors, however, I want to keep it off. From what I can gather the statements are not being formed properly in this script so the error is being thrown as it should when set to false. PDO is new to me as of a week ago, but I understand now that the '// SQL queries get data to display' section is the problem. – user756659 Nov 27 '13 at 14:50
  • There is no difference, what mode is used. I still can't get what is exact problem you are feared of. – Your Common Sense Nov 27 '13 at 14:57
  • The error listed at the top of the post. The statement can't be written in proper format if it is returning that error with PDO::ATTR_EMULATE_PREPARES => false set for the connection. Removing the setting (turning it on) and it works fine as is. – user756659 Nov 27 '13 at 15:04
  • to solve that error just turn emulation mode ON – Your Common Sense Nov 27 '13 at 15:06
  • I realize that, but I do not want emulation turned on. http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php is just one example I came across when researching this. – user756659 Nov 27 '13 at 15:09
  • There is nothing particular said, why emulation is wrong. Just one groundless and proofless statement. – Your Common Sense Nov 27 '13 at 15:13
  • Well that may be, but for peace of mind I would prefer to use pdo with emulation off as I have gone about other aspects of this project. With that said, I need to make the above script work with it off. – user756659 Nov 27 '13 at 15:18
  • Well, use search then. There are dozens similar questions asked already. – Your Common Sense Nov 27 '13 at 15:20
  • Never thought of that... – user756659 Nov 27 '13 at 15:25
  • Anyone else care to chime in with some advice on changing this to work with emulation off in PDO? – user756659 Nov 27 '13 at 23:31

0 Answers0