├── README.md └── ssp.class.php /README.md: -------------------------------------------------------------------------------- 1 | # Datatables Server-side Processing 2 | Helps to enable server-side processing for the DataTables plugin and fetch data from the server-side script using PHP and MySQL. 3 | 4 | Go to [our website](https://www.codexworld.com/datatables-server-side-processing-with-php-mysql/) to get the step-by-step tutorial and download the source code. 5 | 6 | 7 | -------------------------------------------------------------------------------- /ssp.class.php: -------------------------------------------------------------------------------- 1 | isset ( $request['draw'] ) ? 288 | intval( $request['draw'] ) : 289 | 0, 290 | "recordsTotal" => intval( $recordsTotal ), 291 | "recordsFiltered" => intval( $recordsFiltered ), 292 | "data" => self::data_output( $columns, $data ) 293 | ); 294 | } 295 | 296 | 297 | /** 298 | * The difference between this method and the `simple` one, is that you can 299 | * apply additional `where` conditions to the SQL queries. These can be in 300 | * one of two forms: 301 | * 302 | * * 'Result condition' - This is applied to the result set, but not the 303 | * overall paging information query - i.e. it will not effect the number 304 | * of records that a user sees they can have access to. This should be 305 | * used when you want apply a filtering condition that the user has sent. 306 | * * 'All condition' - This is applied to all queries that are made and 307 | * reduces the number of records that the user can access. This should be 308 | * used in conditions where you don't want the user to ever have access to 309 | * particular records (for example, restricting by a login id). 310 | * 311 | * @param array $request Data sent to server by DataTables 312 | * @param array|PDO $conn PDO connection resource or connection parameters array 313 | * @param string $table SQL table to query 314 | * @param string $primaryKey Primary key of the table 315 | * @param array $columns Column information array 316 | * @param string $whereResult WHERE condition to apply to the result set 317 | * @param string $whereAll WHERE condition to apply to all queries 318 | * @return array Server-side processing response array 319 | */ 320 | static function complex ( $request, $conn, $table, $primaryKey, $columns, $whereResult=null, $whereAll=null ) 321 | { 322 | $bindings = array(); 323 | $db = self::db( $conn ); 324 | $localWhereResult = array(); 325 | $localWhereAll = array(); 326 | $whereAllSql = ''; 327 | 328 | // Build the SQL query string from the request 329 | $limit = self::limit( $request, $columns ); 330 | $order = self::order( $request, $columns ); 331 | $where = self::filter( $request, $columns, $bindings ); 332 | 333 | $whereResult = self::_flatten( $whereResult ); 334 | $whereAll = self::_flatten( $whereAll ); 335 | 336 | if ( $whereResult ) { 337 | $where = $where ? 338 | $where .' AND '.$whereResult : 339 | 'WHERE '.$whereResult; 340 | } 341 | 342 | if ( $whereAll ) { 343 | $where = $where ? 344 | $where .' AND '.$whereAll : 345 | 'WHERE '.$whereAll; 346 | 347 | $whereAllSql = 'WHERE '.$whereAll; 348 | } 349 | 350 | // Main query to actually get the data 351 | $data = self::sql_exec( $db, $bindings, 352 | "SELECT `".implode("`, `", self::pluck($columns, 'db'))."` 353 | FROM `$table` 354 | $where 355 | $order 356 | $limit" 357 | ); 358 | 359 | // Data set length after filtering 360 | $resFilterLength = self::sql_exec( $db, $bindings, 361 | "SELECT COUNT(`{$primaryKey}`) 362 | FROM `$table` 363 | $where" 364 | ); 365 | $recordsFiltered = $resFilterLength[0][0]; 366 | 367 | // Total data set length 368 | $resTotalLength = self::sql_exec( $db, $bindings, 369 | "SELECT COUNT(`{$primaryKey}`) 370 | FROM `$table` ". 371 | $whereAllSql 372 | ); 373 | $recordsTotal = $resTotalLength[0][0]; 374 | 375 | /* 376 | * Output 377 | */ 378 | return array( 379 | "draw" => isset ( $request['draw'] ) ? 380 | intval( $request['draw'] ) : 381 | 0, 382 | "recordsTotal" => intval( $recordsTotal ), 383 | "recordsFiltered" => intval( $recordsFiltered ), 384 | "data" => self::data_output( $columns, $data ) 385 | ); 386 | } 387 | 388 | 389 | /** 390 | * Connect to the database 391 | * 392 | * @param array $sql_details SQL server connection details array, with the 393 | * properties: 394 | * * host - host name 395 | * * db - database name 396 | * * user - user name 397 | * * pass - user password 398 | * @return resource Database connection handle 399 | */ 400 | static function sql_connect ( $sql_details ) 401 | { 402 | try { 403 | $db = @new PDO( 404 | "mysql:host={$sql_details['host']};dbname={$sql_details['db']}", 405 | $sql_details['user'], 406 | $sql_details['pass'], 407 | array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ) 408 | ); 409 | } 410 | catch (PDOException $e) { 411 | self::fatal( 412 | "An error occurred while connecting to the database. ". 413 | "The error reported by the server was: ".$e->getMessage() 414 | ); 415 | } 416 | 417 | return $db; 418 | } 419 | 420 | 421 | /** 422 | * Execute an SQL query on the database 423 | * 424 | * @param resource $db Database handler 425 | * @param array $bindings Array of PDO binding values from bind() to be 426 | * used for safely escaping strings. Note that this can be given as the 427 | * SQL query string if no bindings are required. 428 | * @param string $sql SQL query to execute. 429 | * @return array Result from the query (all rows) 430 | */ 431 | static function sql_exec ( $db, $bindings, $sql=null ) 432 | { 433 | // Argument shifting 434 | if ( $sql === null ) { 435 | $sql = $bindings; 436 | } 437 | 438 | $stmt = $db->prepare( $sql ); 439 | //echo $sql; 440 | 441 | // Bind parameters 442 | if ( is_array( $bindings ) ) { 443 | for ( $i=0, $ien=count($bindings) ; $i<$ien ; $i++ ) { 444 | $binding = $bindings[$i]; 445 | $stmt->bindValue( $binding['key'], $binding['val'], $binding['type'] ); 446 | } 447 | } 448 | 449 | // Execute 450 | try { 451 | $stmt->execute(); 452 | } 453 | catch (PDOException $e) { 454 | self::fatal( "An SQL error occurred: ".$e->getMessage() ); 455 | } 456 | 457 | // Return all 458 | return $stmt->fetchAll( PDO::FETCH_BOTH ); 459 | } 460 | 461 | 462 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 463 | * Internal methods 464 | */ 465 | 466 | /** 467 | * Throw a fatal error. 468 | * 469 | * This writes out an error message in a JSON string which DataTables will 470 | * see and show to the user in the browser. 471 | * 472 | * @param string $msg Message to send to the client 473 | */ 474 | static function fatal ( $msg ) 475 | { 476 | echo json_encode( array( 477 | "error" => $msg 478 | ) ); 479 | 480 | exit(0); 481 | } 482 | 483 | /** 484 | * Create a PDO binding key which can be used for escaping variables safely 485 | * when executing a query with sql_exec() 486 | * 487 | * @param array &$a Array of bindings 488 | * @param * $val Value to bind 489 | * @param int $type PDO field type 490 | * @return string Bound key to be used in the SQL where this parameter 491 | * would be used. 492 | */ 493 | static function bind ( &$a, $val, $type ) 494 | { 495 | $key = ':binding_'.count( $a ); 496 | 497 | $a[] = array( 498 | 'key' => $key, 499 | 'val' => $val, 500 | 'type' => $type 501 | ); 502 | 503 | return $key; 504 | } 505 | 506 | 507 | /** 508 | * Pull a particular property from each assoc. array in a numeric array, 509 | * returning and array of the property values from each item. 510 | * 511 | * @param array $a Array to get data from 512 | * @param string $prop Property to read 513 | * @return array Array of property values 514 | */ 515 | static function pluck ( $a, $prop ) 516 | { 517 | $out = array(); 518 | 519 | for ( $i=0, $len=count($a) ; $i<$len ; $i++ ) { 520 | if(empty($a[$i][$prop])){ 521 | continue; 522 | } 523 | //removing the $out array index confuses the filter method in doing proper binding, 524 | //adding it ensures that the array data are mapped correctly 525 | $out[$i] = $a[$i][$prop]; 526 | } 527 | 528 | return $out; 529 | } 530 | 531 | 532 | /** 533 | * Return a string from an array or a string 534 | * 535 | * @param array|string $a Array to join 536 | * @param string $join Glue for the concatenation 537 | * @return string Joined string 538 | */ 539 | static function _flatten ( $a, $join = ' AND ' ) 540 | { 541 | if ( ! $a ) { 542 | return ''; 543 | } 544 | else if ( $a && is_array($a) ) { 545 | return implode( $join, $a ); 546 | } 547 | return $a; 548 | } 549 | } 550 | --------------------------------------------------------------------------------