Guest User

ssp.class.php

a guest
Oct 31st, 2018
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.29 KB | None | 0 0
  1. <?php
  2. /*
  3.  * Helper functions for building a DataTables server-side processing SQL query
  4.  *
  5.  * The static functions in this class are just helper functions to help build
  6.  * the SQL used in the DataTables demo server-side processing scripts. These
  7.  * functions obviously do not represent all that can be done with server-side
  8.  * processing, they are intentionally simple to show how it works. More complex
  9.  * server-side processing operations will likely require a custom script.
  10.  *
  11.  * See http://datatables.net/usage/server-side for full details on the server-
  12.  * side processing requirements of DataTables.
  13.  *
  14.  * @license MIT - http://datatables.net/license_mit
  15.  */
  16. // REMOVE THIS BLOCK - used for DataTables test environment only!
  17. /*
  18. $file = $_SERVER['DOCUMENT_ROOT'].'/datatables/mysql.php';
  19. if ( is_file( $file ) ) {
  20.     include( $file );
  21. }
  22. */
  23. class SSP {
  24.     /**
  25.      * Create the data output array for the DataTables rows
  26.      *
  27.      *  @param  array $columns Column information array
  28.      *  @param  array $data    Data from the SQL get
  29.      *  @return array          Formatted data in a row based format
  30.      */
  31.     static function data_output ( $columns, $data )
  32.     {
  33.         $out = array();
  34.         for ( $i=0, $ien=count($data) ; $i<$ien ; $i++ ) {
  35.             $row = array();
  36.             for ( $j=0, $jen=count($columns) ; $j<$jen ; $j++ ) {
  37.                 $column = $columns[$j];
  38.                 // Is there a formatter?
  39.                 if ( isset( $column['formatter'] ) ) {
  40.                     $row[ $column['dt'] ] = $column['formatter']( $data[$i][ $column['db'] ], $data[$i] );
  41.                 }
  42.                 else {
  43.                     $row[ $column['dt'] ] = $data[$i][ $columns[$j]['db'] ];
  44.                 }
  45.             }
  46.             $out[] = $row;
  47.         }
  48.         return $out;
  49.     }
  50.     /**
  51.      * Paging
  52.      *
  53.      * Construct the LIMIT clause for server-side processing SQL query
  54.      *
  55.      *  @param  array $request Data sent to server by DataTables
  56.      *  @param  array $columns Column information array
  57.      *  @return string SQL limit clause
  58.      */
  59.     static function limit ( $request, $columns )
  60.     {
  61.         $limit = '';
  62.         if ( isset($request['start']) && $request['length'] != -1 ) {
  63.             $limit = "OFFSET ".intval($request['start'])." LIMIT ".intval($request['length']);
  64.         }
  65.         return $limit;
  66.     }
  67.     /**
  68.      * Ordering
  69.      *
  70.      * Construct the ORDER BY clause for server-side processing SQL query
  71.      *
  72.      *  @param  array $request Data sent to server by DataTables
  73.      *  @param  array $columns Column information array
  74.      *  @return string SQL order by clause
  75.      */
  76.     static function order ( $request, $columns )
  77.     {
  78.         $order = '';
  79.         if ( isset($request['order']) && count($request['order']) ) {
  80.             $orderBy = array();
  81.             $dtColumns = SSP::pluck( $columns, 'dt' );
  82.             for ( $i=0, $ien=count($request['order']) ; $i<$ien ; $i++ ) {
  83.                 // Convert the column index into the column data property
  84.                 $columnIdx = intval($request['order'][$i]['column']);
  85.                 $requestColumn = $request['columns'][$columnIdx];
  86.                 $columnIdx = array_search( $requestColumn['data'], $dtColumns );
  87.                 $column = $columns[ $columnIdx ];
  88.                 if ( $requestColumn['orderable'] == 'true' ) {
  89.                     $dir = $request['order'][$i]['dir'] === 'asc' ?
  90.                         'ASC' :
  91.                         'DESC';
  92.                     $orderBy[] = ''.$column['db'].' '.$dir;
  93.                 }
  94.             }
  95.             $order = 'ORDER BY '.implode(', ', $orderBy);
  96.         }
  97.         return $order;
  98.     }
  99.     /**
  100.      * Searching / Filtering
  101.      *
  102.      * Construct the WHERE clause for server-side processing SQL query.
  103.      *
  104.      * NOTE this does not match the built-in DataTables filtering which does it
  105.      * word by word on any field. It's possible to do here performance on large
  106.      * databases would be very poor
  107.      *
  108.      *  @param  array $request Data sent to server by DataTables
  109.      *  @param  array $columns Column information array
  110.      *  @param  array $bindings Array of values for PDO bindings, used in the
  111.      *    sql_exec() function
  112.      *  @return string SQL where clause
  113.      */
  114.     static function filter ( $request, $columns, &$bindings )
  115.     {
  116.         $globalSearch = array();
  117.         $columnSearch = array();
  118.         $dtColumns = SSP::pluck( $columns, 'dt' );
  119.         if ( isset($request['search']) && $request['search']['value'] != '' ) {
  120.             $str = $request['search']['value'];
  121.             for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
  122.                 $requestColumn = $request['columns'][$i];
  123.                 $columnIdx = array_search( $requestColumn['data'], $dtColumns );
  124.                 $column = $columns[ $columnIdx ];
  125.                 if ( $requestColumn['searchable'] == 'true' ) {
  126.                     $binding = SSP::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
  127.                     $globalSearch[] = "text(".$column['db'].") LIKE ".$binding;
  128.                 }
  129.             }
  130.         }
  131.         // Individual column filtering
  132.         for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
  133.             $requestColumn = $request['columns'][$i];
  134.             $columnIdx = array_search( $requestColumn['data'], $dtColumns );
  135.             $column = $columns[ $columnIdx ];
  136.             $str = $requestColumn['search']['value'];
  137.             if ( $requestColumn['searchable'] == 'true' &&
  138.              $str != '' ) {
  139.                 $binding = SSP::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
  140.                 $columnSearch[] = "text(".$column['db'].") LIKE ".$binding;
  141.             }
  142.         }
  143.         // Combine the filters into a single string
  144.         $where = '';
  145.         if ( count( $globalSearch ) ) {
  146.             $where = '('.implode(' OR ', $globalSearch).')';
  147.         }
  148.         if ( count( $columnSearch ) ) {
  149.             $where = $where === '' ?
  150.                 implode(' AND ', $columnSearch) :
  151.                 $where .' AND '. implode(' AND ', $columnSearch);
  152.         }
  153.         if ( $where !== '' ) {
  154.             $where = 'WHERE '.$where;
  155.         }
  156.         return $where;
  157.     }
  158.     /**
  159.      * Perform the SQL queries needed for an server-side processing requested,
  160.      * utilising the helper functions of this class, limit(), order() and
  161.      * filter() among others. The returned array is ready to be encoded as JSON
  162.      * in response to an SSP request, or can be modified if needed before
  163.      * sending back to the client.
  164.      *
  165.      *  @param  array $request Data sent to server by DataTables
  166.      *  @param  array $sql_details SQL connection details - see sql_connect()
  167.      *  @param  string $table SQL table to query
  168.      *  @param  string $primaryKey Primary key of the table
  169.      *  @param  array $columns Column information array
  170.      *  @return array          Server-side processing response array
  171.      */
  172.     static function simple ( $request, $sql_details, $table, $primaryKey, $columns )
  173.     {
  174.         $bindings = array();
  175.         $db = SSP::sql_connect( $sql_details );
  176.         // Build the SQL query string from the request
  177.         $limit = SSP::limit( $request, $columns );
  178.         $order = SSP::order( $request, $columns );
  179.         $where = SSP::filter( $request, $columns, $bindings );
  180.         // Main query to actually get the data
  181.         $psql = "SELECT ".implode(", ", SSP::pluck($columns, 'db')).", count(*) OVER() AS total_count
  182.              FROM $table
  183.              $where
  184.              $order
  185.              $limit";
  186.         $data = SSP::sql_exec( $db, $bindings,$psql);
  187.        
  188.         // Data set length after filtering
  189.         $recordsFiltered = $data[0]["total_count"];
  190.         // Total data set length
  191.         $resTotalLength = SSP::sql_exec( $db,
  192.             "SELECT COUNT({$primaryKey})
  193.              FROM   $table"
  194.         );
  195.         $recordsTotal = $resTotalLength[0][0];
  196.         /*
  197.          * Output
  198.          */
  199.         return array(
  200.             "draw"            => intval( $request['draw'] ),
  201.             "recordsTotal"    => intval( $recordsTotal ),
  202.             "recordsFiltered" => intval( $recordsFiltered ),
  203.             "data"            => SSP::data_output( $columns, $data )
  204.             //"sql"           => $psql
  205.         );
  206.     }
  207.     /**
  208.      * Connect to the database
  209.      *
  210.      * @param  array $sql_details SQL server connection details array, with the
  211.      *   properties:
  212.      *     * host - host name
  213.      *     * db   - database name
  214.      *     * user - user name
  215.      *     * pass - user password
  216.      * @return resource Database connection handle
  217.      */
  218.     static function sql_connect ( $sql_details )
  219.     {
  220.         try {
  221.             $db = @new PDO(
  222.                 "pgsql:host={$sql_details['host']};dbname={$sql_details['db']}",
  223.                 $sql_details['user'],
  224.                 $sql_details['pass'],
  225.                 array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )
  226.             );
  227.         }
  228.         catch (PDOException $e) {
  229.             SSP::fatal(
  230.                 json_encode($e)
  231.             );
  232.         }
  233.         return $db;
  234.     }
  235.     /**
  236.      * Execute an SQL query on the database
  237.      *
  238.      * @param  resource $db  Database handler
  239.      * @param  array    $bindings Array of PDO binding values from bind() to be
  240.      *   used for safely escaping strings. Note that this can be given as the
  241.      *   SQL query string if no bindings are required.
  242.      * @param  string   $sql SQL query to execute.
  243.      * @return array         Result from the query (all rows)
  244.      */
  245.     static function sql_exec ( $db, $bindings, $sql=null )
  246.     {
  247.         // Argument shifting
  248.         if ( $sql === null ) {
  249.             $sql = $bindings;
  250.         }
  251.         $stmt = $db->prepare( $sql );
  252.         //echo $sql;
  253.         // Bind parameters
  254.         if ( is_array( $bindings ) ) {
  255.             for ( $i=0, $ien=count($bindings) ; $i<$ien ; $i++ ) {
  256.                 $binding = $bindings[$i];
  257.                 $stmt->bindValue( $binding['key'], $binding['val'], $binding['type'] );
  258.             }
  259.         }
  260.         // Execute
  261.         try {
  262.             $stmt->execute();
  263.         }
  264.         catch (PDOException $e) {
  265.             SSP::fatal( "An SQL error occurred: ".$e->getMessage()." [with] '".$sql."'" );
  266.         }
  267.         // Return all
  268.         return $stmt->fetchAll();
  269.     }
  270.     /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  271.      * Internal methods
  272.      */
  273.     /**
  274.      * Throw a fatal error.
  275.      *
  276.      * This writes out an error message in a JSON string which DataTables will
  277.      * see and show to the user in the browser.
  278.      *
  279.      * @param  string $msg Message to send to the client
  280.      */
  281.     static function fatal ( $msg )
  282.     {
  283.         echo json_encode( array(
  284.             "error" => $msg
  285.         ) );
  286.         exit(0);
  287.     }
  288.     /**
  289.      * Create a PDO binding key which can be used for escaping variables safely
  290.      * when executing a query with sql_exec()
  291.      *
  292.      * @param  array &$a    Array of bindings
  293.      * @param  *      $val  Value to bind
  294.      * @param  int    $type PDO field type
  295.      * @return string       Bound key to be used in the SQL where this parameter
  296.      *   would be used.
  297.      */
  298.     static function bind ( &$a, $val, $type )
  299.     {
  300.         $key = ':binding_'.count( $a );
  301.         $a[] = array(
  302.             'key' => $key,
  303.             'val' => $val,
  304.             'type' => $type
  305.         );
  306.         return $key;
  307.     }
  308.     /**
  309.      * Pull a particular property from each assoc. array in a numeric array,
  310.      * returning and array of the property values from each item.
  311.      *
  312.      *  @param  array  $a    Array to get data from
  313.      *  @param  string $prop Property to read
  314.      *  @return array        Array of property values
  315.      */
  316.     static function pluck ( $a, $prop )
  317.     {
  318.         $out = array();
  319.         for ( $i=0, $len=count($a) ; $i<$len ; $i++ ) {
  320.             $out[] = $a[$i][$prop];
  321.         }
  322.         return $out;
  323.     }
  324. }
  325. ?>
Add Comment
Please, Sign In to add comment