简体   繁体   English

数据表1.10.1-服务器端-仅单个列搜索无效

[英]Datatable 1.10.1 - server-side - only individual column search not working

First the error [response] i am getting is: 首先,我得到的错误[响应]是:

{"error":"An SQL error occurred: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined"}

if I echo the query in ssp.class.php I get: 如果我在ssp.class.php中回显查询,则会得到:

SELECT SQL_CALC_FOUND_ROWS `conNo`, `name`, `areaName`, `vc`, `stv`, `joinDate`, state`, `pack`, `cId FROM customers LEFT JOIN areas ON areas.areaId = customers.areaId LEFT JOIN boxes ON boxes.boxId = customers.boxId WHERE `conNo` LIKE :binding_0AND customers.opId = 11 AND customers.state != 3 AND customers.subId = 1 ORDER BY conNo ASC LIMIT 0, 10

which is certainly wrong at :binding_0 在:binding_0上肯定是错误的
This happens only when i use the footer search, the other search and all other functions are fine. 仅当我使用页脚搜索,其他搜索和所有其他功能时,才会发生这种情况。

My JQUERY Implementation 我的JQUERY实施

$(document).ready(function() {
    // Example 1: From an element in DOM

    //tfoot input create
    $('#customers tfoot th').each(function() {
        var title = $('#customers thead th').eq($(this).index()).text();
        $(this).html('<input class="span12" type="text" placeholder="Search ' + title + '" />');
    });

    //datatable initialisation
    var table = $('#customers').DataTable({
        "processing": true,
        "serverSide": true,
        "ajax": "functions/get_customers.php",
        "paginationType": "full_numbers",
        "dom": '<"pad5"CT><"clear"><lf<"clear">r<t>ip>',
        tableTools: {
            "sSwfPath": "assets/swf/copy_csv_xls_pdf.swf"
        },
        "language": {
            "processing": "<img src='assets/images/loaders/loader27.gif' class='loader'>"
        },
        "columns": [
            {"data": 0},
            {"data": 1},
            {"data": 2},
            {"data": 3},
            {"data": 4, "sortable": false},
            {"data": 5},
            {"data": 6},
            {"data": 7},
            {"data": 8, "sortable": false}
        ]

    });

    //tfooter search
    table.columns().eq(0).each(function(colIdx) {
        $('input', table.column(colIdx).footer()).on('keyup change', function() {
            table
                    .column(colIdx)
                    .search(this.value)
                    .draw();
        });
    });

});

my ssp.class.php 我的ssp.class.php

//licence skipped 
class SSP {

    /**
     * Create the data output array for the DataTables rows
     *
     *  @param  array $columns Column information array
     *  @param  array $data    Data from the SQL get
     *  @return array          Formatted data in a row based format
     */
    static function data_output($columns, $data) {
        $out = array();

        for ($i = 0, $ien = count($data); $i < $ien; $i++) {
            $row = array();

            for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
                $column = $columns[$j];
                if ($j == 4) {
                    if ($data[$i][$columns[$j]['db']] == '') {
                        $data[$i][$columns[$j]['db']] = 'NULL';
                    } else {

                        $get_conNo = get_conNo($data[$i][$columns[$j]['db']]);
                        $count_boxes = count_boxes($get_conNo);

                        $data[$i][$columns[$j]['db']] = '';

                        for ($x = 0; $x < $count_boxes; $x++) {
                            $data[$i][$columns[$j]['db']] .= '<span class="icon-storage tab-icons"></span>';
                        }
                    }
                } else if ($j == 6) {
                    if ($data[$i][$columns[$j]['db']] == 1) {
                        $data[$i][$columns[$j]['db']] = '<label class="btn-danger disabled btn">Stopped</label>';
                    } else {
                        $data[$i][$columns[$j]['db']] = '<label class="btn-success disabled btn">Running</label>';
                    }
                } else if ($j == 8) {
                    $cId = $data[$i][$columns[$j]['db']];
                    $data[$i][$columns[$j]['db']] = ''
                            . '<div class="dropdown">'
                            . ' <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">Tools'
                            . '  <span class="caret"></span>'
                            . ' </button>'
                            . ' <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">'
                            . '  <li role="presentation"><a onclick="return loadIframe(\'paypop\', this.rel)"; rel="pay_popup.php?cId='.$cId.'" role="menuitem" tabindex="-1" >Pay</a></li>'
                            . '  <li role="presentation"><a role="menuitem" tabindex="-1" target="_blank" href="cust_details.php?cId='.$cId.'">View Details</a></li>'
                            . '  <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Edit Details</a></li>'
                            . '  <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Deactivate</a></li>'
                            . '  <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Delete</a></li>'
                            . ' </ul>'
                            . '</div>';
                }

                // Is there a formatter?
                if (isset($column['formatter'])) {
                    $row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
                } else {
                    $row[$column['dt']] = $data[$i][$columns[$j]['db']];
                }
            }

            $out[] = $row;
        }

        return $out;
    }

    /**
     * Paging
     *
     * Construct the LIMIT clause for server-side processing SQL query
     *
     *  @param  array $request Data sent to server by DataTables
     *  @param  array $columns Column information array
     *  @return string SQL limit clause
     */
    static function limit($request, $columns) {
        $limit = '';

        if (isset($request['start']) && $request['length'] != -1) {
            $limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
        }

        return $limit;
    }

    /**
     * Ordering
     *
     * Construct the ORDER BY clause for server-side processing SQL query
     *
     *  @param  array $request Data sent to server by DataTables
     *  @param  array $columns Column information array
     *  @return string SQL order by clause
     */
    static function order($request, $columns) {
        $order = '';

        if (isset($request['order']) && count($request['order'])) {
            $orderBy = array();
            $dtColumns = self::pluck($columns, 'dt');

            for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
                // Convert the column index into the column data property
                $columnIdx = intval($request['order'][$i]['column']);
                $requestColumn = $request['columns'][$columnIdx];

                $columnIdx = array_search($requestColumn['data'], $dtColumns);
                $column = $columns[$columnIdx];

                if ($requestColumn['orderable'] == 'true') {
                    $dir = $request['order'][$i]['dir'] === 'asc' ?
                            'ASC' :
                            'DESC';

                    $orderBy[] = '`' . $column['db'] . '` ' . $dir;
                }
            }

            $order = 'ORDER BY ' . implode(', ', $orderBy);
        }

        return $order;
    }

    /**
     * Searching / Filtering
     *
     * Construct the WHERE clause for server-side processing SQL query.
     *
     * 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 performance on large
     * databases would be very poor
     *
     *  @param  array $request Data sent to server by DataTables
     *  @param  array $columns Column information array
     *  @param  array $bindings Array of values for PDO bindings, used in the
     *    sql_exec() function
     *  @return string SQL where clause
     */
    static function filter($request, $columns, &$bindings) {
        $globalSearch = array();
        $columnSearch = array();
        $dtColumns = self::pluck($columns, 'dt');

        if (isset($request['search']) && $request['search']['value'] != '') {
            $str = $request['search']['value'];

            for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
                $requestColumn = $request['columns'][$i];
                $columnIdx = array_search($requestColumn['data'], $dtColumns);
                $column = $columns[$columnIdx];

                if ($requestColumn['searchable'] == 'true') {
                    $binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
                    $globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
                }
            }
        }

        // Individual column filtering
        for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
            $requestColumn = $request['columns'][$i];
            $columnIdx = array_search($requestColumn['data'], $dtColumns);
            $column = $columns[$columnIdx];

            $str = $requestColumn['search']['value'];

            if ($requestColumn['searchable'] == 'true' &&
                    $str != '') {
                $binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
                $columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
            }
        }

        // Combine the filters into a single string
        $where = '';
        if (count($globalSearch)) {
            $where = '(' . implode(' OR ', $globalSearch) . ')';
        }

        if (count($columnSearch)) {
            $where = $where === '' ?
                    implode(' AND ', $columnSearch) :
                    $where . ' AND ' . implode(' AND ', $columnSearch);
        }

        if ($where !== '') {
            $where = 'WHERE ' . $where;
        }

        if ($where == '') {
            $where = 'WHERE ';
        } else {
            $where .= 'AND ';
        }
        $where .= ' customers.opId = ' . $_SESSION['dcn_id'] . '';
        $where .= ' AND customers.state != 3';
        $where .= ' AND customers.subId = 1';

        return $where;
    }

    /**
     * Perform the SQL queries needed for an server-side processing requested,
     * utilising the helper functions of this class, limit(), order() and
     * filter() among others. The returned array is ready to be encoded as JSON
     * in response to an SSP request, or can be modified if needed before
     * sending back to the client.
     *
     *  @param  array $request Data sent to server by DataTables
     *  @param  array $sql_details SQL connection details - see sql_connect()
     *  @param  string $table SQL table to query
     *  @param  string $primaryKey Primary key of the table
     *  @param  array $columns Column information array
     *  @return array          Server-side processing response array
     */
    static function simple($request, $sql_details, $table, $primaryKey, $columns) {
        $bindings = array();
        $db = self::sql_connect($sql_details);

        // Build the SQL query string from the request
        $limit = self::limit($request, $columns);
        $order = self::order($request, $columns);
        $where = self::filter($request, $columns, $bindings);

        // Main query to actually get the data
        $data = self::sql_exec($db, $bindings, "SELECT SQL_CALC_FOUND_ROWS `" . implode("`, `", self::pluck($columns, 'db')) . "`
             FROM $table
             $where
             $order
             $limit"
        );

        // Data set length after filtering
        $resFilterLength = self::sql_exec($db, "SELECT FOUND_ROWS()"
        );
        $recordsFiltered = $resFilterLength[0][0];

        // Total data set length
        $resTotalLength = self::sql_exec($db, "SELECT COUNT(`{$primaryKey}`)
             FROM   $table"
        );
        $recordsTotal = $resTotalLength[0][0];


        /*
         * Output
         */
        return array(
            "draw" => intval($request['draw']),
            "recordsTotal" => intval($recordsTotal),
            "recordsFiltered" => intval($recordsFiltered),
            "data" => self::data_output($columns, $data)
        );
    }

    /**
     * Connect to the database
     *
     * @param  array $sql_details SQL server connection details array, with the
     *   properties:
     *     * host - host name
     *     * db   - database name
     *     * user - user name
     *     * pass - user password
     * @return resource Database connection handle
     */
    static function sql_connect($sql_details) {
        try {
            $db = @new PDO(
                    "mysql:host={$sql_details['host']};dbname={$sql_details['db']}", $sql_details['user'], $sql_details['pass'], array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
            );
        } catch (PDOException $e) {
            self::fatal(
                    "An error occurred while connecting to the database. " .
                    "The error reported by the server was: " . $e->getMessage()
            );
        }

        return $db;
    }

    /**
     * Execute an SQL query on the database
     *
     * @param  resource $db  Database handler
     * @param  array    $bindings Array of PDO binding values from bind() to be
     *   used for safely escaping strings. Note that this can be given as the
     *   SQL query string if no bindings are required.
     * @param  string   $sql SQL query to execute.
     * @return array         Result from the query (all rows)
     */
    static function sql_exec($db, $bindings, $sql = null) {
        // Argument shifting
        if ($sql === null) {
            $sql = $bindings;
        }

        $stmt = $db->prepare($sql);
        echo $sql;
        // Bind parameters
        if (is_array($bindings)) {
            for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
                $binding = $bindings[$i];
                $stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
            }
        }

        // Execute
        try {
            $stmt->execute();
        } catch (PDOException $e) {
            self::fatal("An SQL error occurred: " . $e->getMessage());
        }

        // Return all
        return $stmt->fetchAll();
    }

    /*     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * Internal methods
     */

    /**
     * Throw a fatal error.
     *
     * This writes out an error message in a JSON string which DataTables will
     * see and show to the user in the browser.
     *
     * @param  string $msg Message to send to the client
     */
    static function fatal($msg) {
        echo json_encode(array(
            "error" => $msg
        ));

        exit(0);
    }

    /**
     * Create a PDO binding key which can be used for escaping variables safely
     * when executing a query with sql_exec()
     *
     * @param  array &$a    Array of bindings
     * @param  *      $val  Value to bind
     * @param  int    $type PDO field type
     * @return string       Bound key to be used in the SQL where this parameter
     *   would be used.
     */
    static function bind(&$a, $val, $type) {
        $key = ':binding_' . count($a);

        $a[] = array(
            'key' => $key,
            'val' => $val,
            'type' => $type
        );

        return $key;
    }

    /**
     * Pull a particular property from each assoc. array in a numeric array, 
     * returning and array of the property values from each item.
     *
     *  @param  array  $a    Array to get data from
     *  @param  string $prop Property to read
     *  @return array        Array of property values
     */
    static function pluck($a, $prop) {
        $out = array();

        for ($i = 0, $len = count($a); $i < $len; $i++) {
            $out[] = $a[$i][$prop];
        }

        return $out;
    }

}

I think i have found an workaround of this problem but i do not know of any consequences this may cause as of yet. 我认为我已经找到了解决此问题的方法 ,但目前尚不知道可能会导致的任何后果。
at line number 191 in ssp.class.php I changed 在ssp.class.php中的第191行,我更改了

$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;

to

$columnSearch[] = "`" . $column['db'] . "` LIKE '%" . $str ."%'";

this will remove the binding_0 and i am manually adding the string that is searched, enclosed in % as i have to do only partial search. 这将删除binding_0,并且我手动添加要搜索的字符串,并用%括起来,因为我只需要部分搜索即可。

I am not sure if this will cause any error with any other plugin i might use hence i do need a better solution if possible 我不确定这是否会导致我可能使用的任何其他插件出现任何错误,因此,如果可能的话,我确实需要更好的解决方案

EDIT 编辑

This method gives an error when searching from both, the universal search box and the individual search box. 从通用搜索框和单个搜索框进行搜索时,此方法都会出错。 So I need a better solution. 所以我需要一个更好的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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