Advertisement
Guest User

Untitled

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