Advertisement
dropbox1349

change OR condition to an extended AND condition

Apr 17th, 2015
494
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 14.37 KB | None | 0 0
  1. <?php
  2.  
  3. /*
  4.  * Helper functions for building a DataTables server-side processing SQL query
  5.  *
  6.  * The static functions in this class are just helper functions to help build
  7.  * the SQL used in the DataTables demo server-side processing scripts. These
  8.  * functions obviously do not represent all that can be done with server-side
  9.  * processing, they are intentionally simple to show how it works. More complex
  10.  * server-side processing operations will likely require a custom script.
  11.  *
  12.  * See http://datatables.net/usage/server-side for full details on the server-
  13.  * side processing requirements of DataTables.
  14.  *
  15.  * @license MIT - http://datatables.net/license_mit
  16.  */
  17.  
  18.  
  19. // REMOVE THIS BLOCK - used for DataTables test environment only!
  20. $file = $_SERVER['DOCUMENT_ROOT'].'/datatables/mysql.php';
  21. if ( is_file( $file ) ) {
  22.     include( $file );
  23. }
  24.  
  25.  
  26. class SSP {
  27.     /**
  28.      * Create the data output array for the DataTables rows
  29.      *
  30.      *  @param  array $columns Column information array
  31.      *  @param  array $data    Data from the SQL get
  32.      *  @return array          Formatted data in a row based format
  33.      */
  34.     static function data_output ( $columns, $data )
  35.     {
  36.         $out = array();
  37.  
  38.         for ( $i=0, $ien=count($data) ; $i<$ien ; $i++ ) {
  39.             $row = array();
  40.  
  41.             for ( $j=0, $jen=count($columns) ; $j<$jen ; $j++ ) {
  42.                 $column = $columns[$j];
  43.  
  44.                 // Is there a formatter?
  45.                 if ( isset( $column['formatter'] ) ) {
  46.                     $row[ $column['dt'] ] = $column['formatter']( $data[$i][ $column['db'] ], $data[$i] );
  47.                 }
  48.                 else {
  49.                     $row[ $column['dt'] ] = $data[$i][ $columns[$j]['db'] ];
  50.                 }
  51.             }
  52.  
  53.             $out[] = $row;
  54.         }
  55.  
  56.         return $out;
  57.     }
  58.  
  59.  
  60.     /**
  61.      * Database connection
  62.      *
  63.      * Obtain an PHP PDO connection from a connection details array
  64.      *
  65.      *  @param  array $conn SQL connection details. The array should have
  66.      *    the following properties
  67.      *     * host - host name
  68.      *     * db   - database name
  69.      *     * user - user name
  70.      *     * pass - user password
  71.      *  @return resource PDO connection
  72.      */
  73.     static function db ( $conn )
  74.     {
  75.         if ( is_array( $conn ) ) {
  76.             return self::sql_connect( $conn );
  77.         }
  78.  
  79.         return $conn;
  80.     }
  81.  
  82.  
  83.     /**
  84.      * Paging
  85.      *
  86.      * Construct the LIMIT clause for server-side processing SQL query
  87.      *
  88.      *  @param  array $request Data sent to server by DataTables
  89.      *  @param  array $columns Column information array
  90.      *  @return string SQL limit clause
  91.      */
  92.     static function limit ( $request, $columns )
  93.     {
  94.         $limit = '';
  95.  
  96.         if ( isset($request['start']) && $request['length'] != -1 ) {
  97.             $limit = "LIMIT ".intval($request['start']).", ".intval($request['length']);
  98.         }
  99.  
  100.         return $limit;
  101.     }
  102.  
  103.  
  104.     /**
  105.      * Ordering
  106.      *
  107.      * Construct the ORDER BY clause for server-side processing SQL query
  108.      *
  109.      *  @param  array $request Data sent to server by DataTables
  110.      *  @param  array $columns Column information array
  111.      *  @return string SQL order by clause
  112.      */
  113.     static function order ( $request, $columns )
  114.     {
  115.         $order = '';
  116.  
  117.         if ( isset($request['order']) && count($request['order']) ) {
  118.             $orderBy = array();
  119.             $dtColumns = self::pluck( $columns, 'dt' );
  120.  
  121.             for ( $i=0, $ien=count($request['order']) ; $i<$ien ; $i++ ) {
  122.                 // Convert the column index into the column data property
  123.                 $columnIdx = intval($request['order'][$i]['column']);
  124.                 $requestColumn = $request['columns'][$columnIdx];
  125.  
  126.                 $columnIdx = array_search( $requestColumn['data'], $dtColumns );
  127.                 $column = $columns[ $columnIdx ];
  128.  
  129.                 if ( $requestColumn['orderable'] == 'true' ) {
  130.                     $dir = $request['order'][$i]['dir'] === 'asc' ?
  131.                         'ASC' :
  132.                         'DESC';
  133.  
  134.                     $orderBy[] = '`'.$column['db'].'` '.$dir;
  135.                 }
  136.             }
  137.  
  138.             $order = 'ORDER BY '.implode(', ', $orderBy);
  139.         }
  140.  
  141.         return $order;
  142.     }
  143.  
  144.  
  145.     /**
  146.      * Searching / Filtering
  147.      *
  148.      * Construct the WHERE clause for server-side processing SQL query.
  149.      *
  150.      * NOTE this does not match the built-in DataTables filtering which does it
  151.      * word by word on any field. It's possible to do here performance on large
  152.      * databases would be very poor
  153.      *
  154.      *  @param  array $request Data sent to server by DataTables
  155.      *  @param  array $columns Column information array
  156.      *  @param  array $bindings Array of values for PDO bindings, used in the
  157.      *    sql_exec() function
  158.      *  @return string SQL where clause
  159.      */
  160.      
  161.     static function filter ( $request, $columns, &$bindings )
  162.     {
  163.         $globalSearch = array();
  164.         $columnSearch = array();
  165.         $dtColumns = self::pluck( $columns, 'dt' );
  166.  
  167.         if ( isset($request['search']) && $request['search']['value'] != '' ) {
  168.             $str = $request['search']['value'];
  169.  
  170.             for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
  171.                 $requestColumn = $request['columns'][$i];
  172.                 $columnIdx = array_search( $requestColumn['data'], $dtColumns );
  173.                 $column = $columns[ $columnIdx ];
  174.  
  175.                 if ( $requestColumn['searchable'] == 'true' ) {
  176.                     $binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
  177.                     $globalSearch[] = "match(".$column['db'].") against (".$binding.")";
  178.                 }
  179.             }
  180.         }
  181.  
  182.         // Individual column filtering
  183.         for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
  184.             $requestColumn = $request['columns'][$i];
  185.             $columnIdx = array_search( $requestColumn['data'], $dtColumns );
  186.             $column = $columns[ $columnIdx ];
  187.  
  188.             $str = $requestColumn['search']['value'];
  189.  
  190.             if ( $requestColumn['searchable'] == 'true' &&
  191.              $str != '' ) {
  192.                 $binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
  193.                 $columnSearch[] = "match(".$column['db'].") against (".$binding.")";
  194.             }
  195.         }
  196.  
  197.         // Combine the filters into a single string
  198.         $where = '';
  199.  
  200.         if ( count( $globalSearch ) ) {
  201.             $where = '('.implode(' OR ', $globalSearch).')';
  202.         }
  203.  
  204.         if ( count( $columnSearch ) ) {
  205.             $where = $where === '' ?
  206.                 implode(' AND ', $columnSearch) :
  207.                 $where .' AND '. implode(' AND ', $columnSearch);
  208.         }
  209.  
  210.         if ( $where !== '' ) {
  211.             $where = 'WHERE '.$where;
  212.         }
  213.  
  214.         return $where;
  215.     }
  216.  
  217.  
  218.     /**
  219.      * Perform the SQL queries needed for an server-side processing requested,
  220.      * utilising the helper functions of this class, limit(), order() and
  221.      * filter() among others. The returned array is ready to be encoded as JSON
  222.      * in response to an SSP request, or can be modified if needed before
  223.      * sending back to the client.
  224.      *
  225.      *  @param  array $request Data sent to server by DataTables
  226.      *  @param  array|PDO $conn PDO connection resource or connection parameters array
  227.      *  @param  string $table SQL table to query
  228.      *  @param  string $primaryKey Primary key of the table
  229.      *  @param  array $columns Column information array
  230.      *  @return array          Server-side processing response array
  231.      */
  232.     static function simple ( $request, $conn, $table, $primaryKey, $columns )
  233.     {
  234.         $bindings = array();
  235.         $db = self::db( $conn );
  236.  
  237.         // Build the SQL query string from the request
  238.         $limit = self::limit( $request, $columns );
  239.         $order = self::order( $request, $columns );
  240.         $where = self::filter( $request, $columns, $bindings );
  241.  
  242.         // Main query to actually get the data
  243.         $data = self::sql_exec( $db, $bindings,
  244.             "SELECT SQL_CALC_FOUND_ROWS `".implode("`, `", self::pluck($columns, 'db'))."`
  245.              FROM `$table`
  246.              $where
  247.              $order
  248.              $limit"
  249.         );
  250.  
  251.         // Data set length after filtering
  252.         $resFilterLength = self::sql_exec( $db,
  253.             "SELECT FOUND_ROWS()"
  254.         );
  255.         $recordsFiltered = $resFilterLength[0][0];
  256.  
  257.         // Total data set length
  258.         $resTotalLength = self::sql_exec( $db,
  259.             "SELECT COUNT(`{$primaryKey}`)
  260.              FROM   `$table`"
  261.         );
  262.         $recordsTotal = $resTotalLength[0][0];
  263.  
  264.  
  265.         /*
  266.          * Output
  267.          */
  268.         return array(
  269.             "draw"            => intval( $request['draw'] ),
  270.             "recordsTotal"    => intval( $recordsTotal ),
  271.             "recordsFiltered" => intval( $recordsFiltered ),
  272.             "data"            => self::data_output( $columns, $data )
  273.         );
  274.     }
  275.  
  276.  
  277.     /**
  278.      * The difference between this method and the `simple` one, is that you can
  279.      * apply additional `where` conditions to the SQL queries. These can be in
  280.      * one of two forms:
  281.      *
  282.      * * 'Result condition' - This is applied to the result set, but not the
  283.      *   overall paging information query - i.e. it will not effect the number
  284.      *   of records that a user sees they can have access to. This should be
  285.      *   used when you want apply a filtering condition that the user has sent.
  286.      * * 'All condition' - This is applied to all queries that are made and
  287.      *   reduces the number of records that the user can access. This should be
  288.      *   used in conditions where you don't want the user to ever have access to
  289.      *   particular records (for example, restricting by a login id).
  290.      *
  291.      *  @param  array $request Data sent to server by DataTables
  292.      *  @param  array|PDO $conn PDO connection resource or connection parameters array
  293.      *  @param  string $table SQL table to query
  294.      *  @param  string $primaryKey Primary key of the table
  295.      *  @param  array $columns Column information array
  296.      *  @param  string $whereResult WHERE condition to apply to the result set
  297.      *  @param  string $whereAll WHERE condition to apply to all queries
  298.      *  @return array          Server-side processing response array
  299.      */
  300.     static function complex ( $request, $conn, $table, $primaryKey, $columns, $whereResult=null, $whereAll=null )
  301.     {
  302.         $bindings = array();
  303.         $db = self::db( $conn );
  304.         $localWhereResult = array();
  305.         $localWhereAll = array();
  306.         $whereAllSql = '';
  307.  
  308.         // Build the SQL query string from the request
  309.         $limit = self::limit( $request, $columns );
  310.         $order = self::order( $request, $columns );
  311.         $where = self::filter( $request, $columns, $bindings );
  312.  
  313.         $whereResult = self::_flatten( $whereResult );
  314.         $whereAll = self::_flatten( $whereAll );
  315.  
  316.         if ( $whereResult ) {
  317.             $where = $where ?
  318.                 $where .' AND '.$whereResult :
  319.                 'WHERE '.$whereResult;
  320.         }
  321.  
  322.         if ( $whereAll ) {
  323.             $where = $where ?
  324.                 $where .' AND '.$whereAll :
  325.                 'WHERE '.$whereAll;
  326.  
  327.             $whereAllSql = 'WHERE '.$whereAll;
  328.         }
  329.  
  330.         // Main query to actually get the data
  331.         $data = self::sql_exec( $db, $bindings,
  332.             "SELECT SQL_CALC_FOUND_ROWS `".implode("`, `", self::pluck($columns, 'db'))."`
  333.              FROM `$table`
  334.              $where
  335.              $order
  336.              $limit"
  337.         );
  338.  
  339.         // Data set length after filtering
  340.         $resFilterLength = self::sql_exec( $db,
  341.             "SELECT FOUND_ROWS()"
  342.         );
  343.         $recordsFiltered = $resFilterLength[0][0];
  344.  
  345.         // Total data set length
  346.         $resTotalLength = self::sql_exec( $db, $bindings,
  347.             "SELECT COUNT(`{$primaryKey}`)
  348.              FROM   `$table` ".
  349.             $whereAllSql
  350.         );
  351.         $recordsTotal = $resTotalLength[0][0];
  352.  
  353.         /*
  354.          * Output
  355.          */
  356.         return array(
  357.             "draw"            => intval( $request['draw'] ),
  358.             "recordsTotal"    => intval( $recordsTotal ),
  359.             "recordsFiltered" => intval( $recordsFiltered ),
  360.             "data"            => self::data_output( $columns, $data )
  361.         );
  362.     }
  363.  
  364.  
  365.     /**
  366.      * Connect to the database
  367.      *
  368.      * @param  array $sql_details SQL server connection details array, with the
  369.      *   properties:
  370.      *     * host - host name
  371.      *     * db   - database name
  372.      *     * user - user name
  373.      *     * pass - user password
  374.      * @return resource Database connection handle
  375.      */
  376.     static function sql_connect ( $sql_details )
  377.     {
  378.         try {
  379.             $db = @new PDO(
  380.                 "mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
  381.                 $sql_details['user'],
  382.                 $sql_details['pass'],
  383.                 array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )
  384.             );
  385.         }
  386.         catch (PDOException $e) {
  387.             self::fatal(
  388.                 "An error occurred while connecting to the database. ".
  389.                 "The error reported by the server was: ".$e->getMessage()
  390.             );
  391.         }
  392.  
  393.         return $db;
  394.     }
  395.  
  396.  
  397.     /**
  398.      * Execute an SQL query on the database
  399.      *
  400.      * @param  resource $db  Database handler
  401.      * @param  array    $bindings Array of PDO binding values from bind() to be
  402.      *   used for safely escaping strings. Note that this can be given as the
  403.      *   SQL query string if no bindings are required.
  404.      * @param  string   $sql SQL query to execute.
  405.      * @return array         Result from the query (all rows)
  406.      */
  407.     static function sql_exec ( $db, $bindings, $sql=null )
  408.     {
  409.         // Argument shifting
  410.         if ( $sql === null ) {
  411.             $sql = $bindings;
  412.         }
  413.  
  414.         $stmt = $db->prepare( $sql );
  415.         //echo $sql;
  416.  
  417.         // Bind parameters
  418.         if ( is_array( $bindings ) ) {
  419.             for ( $i=0, $ien=count($bindings) ; $i<$ien ; $i++ ) {
  420.                 $binding = $bindings[$i];
  421.                 $stmt->bindValue( $binding['key'], $binding['val'], $binding['type'] );
  422.             }
  423.         }
  424.  
  425.         // Execute
  426.         try {
  427.             $stmt->execute();
  428.         }
  429.         catch (PDOException $e) {
  430.             self::fatal( "An SQL error occurred: ".$e->getMessage() );
  431.         }
  432.  
  433.         // Return all
  434.         return $stmt->fetchAll();
  435.     }
  436.  
  437.  
  438.     /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  439.      * Internal methods
  440.      */
  441.  
  442.     /**
  443.      * Throw a fatal error.
  444.      *
  445.      * This writes out an error message in a JSON string which DataTables will
  446.      * see and show to the user in the browser.
  447.      *
  448.      * @param  string $msg Message to send to the client
  449.      */
  450.     static function fatal ( $msg )
  451.     {
  452.         echo json_encode( array(
  453.             "error" => $msg
  454.         ) );
  455.  
  456.         exit(0);
  457.     }
  458.  
  459.     /**
  460.      * Create a PDO binding key which can be used for escaping variables safely
  461.      * when executing a query with sql_exec()
  462.      *
  463.      * @param  array &$a    Array of bindings
  464.      * @param  *      $val  Value to bind
  465.      * @param  int    $type PDO field type
  466.      * @return string       Bound key to be used in the SQL where this parameter
  467.      *   would be used.
  468.      */
  469.     static function bind ( &$a, $val, $type )
  470.     {
  471.         $key = ':binding_'.count( $a );
  472.  
  473.         $a[] = array(
  474.             'key' => $key,
  475.             'val' => $val,
  476.             'type' => $type
  477.         );
  478.  
  479.         return $key;
  480.     }
  481.  
  482.  
  483.     /**
  484.      * Pull a particular property from each assoc. array in a numeric array,
  485.      * returning and array of the property values from each item.
  486.      *
  487.      *  @param  array  $a    Array to get data from
  488.      *  @param  string $prop Property to read
  489.      *  @return array        Array of property values
  490.      */
  491.     static function pluck ( $a, $prop )
  492.     {
  493.         $out = array();
  494.  
  495.         for ( $i=0, $len=count($a) ; $i<$len ; $i++ ) {
  496.             $out[] = $a[$i][$prop];
  497.         }
  498.  
  499.         return $out;
  500.     }
  501.  
  502.  
  503.     /**
  504.      * Return a string from an array or a string
  505.      *
  506.      * @param  array|string $a Array to join
  507.      * @param  string $join Glue for the concatenation
  508.      * @return string Joined string
  509.      */
  510.     static function _flatten ( $a, $join = ' AND ' )
  511.     {
  512.         if ( ! $a ) {
  513.             return '';
  514.         }
  515.         else if ( $a && is_array($a) ) {
  516.             return implode( $join, $a );
  517.         }
  518.         return $a;
  519.     }
  520. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement