mirror of
https://github.com/Neetpone/ponepaste.git
synced 2025-03-12 06:30:07 +01:00
Some work for SSP replacement
This commit is contained in:
parent
7ed9f53573
commit
9ac3a2ab4e
4 changed files with 82 additions and 459 deletions
|
@ -1,45 +1,55 @@
|
|||
<?php
|
||||
require_once('../includes/config.php');
|
||||
// DB table to use
|
||||
$table = 'pastes';
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
|
||||
// Table's primary key
|
||||
$primaryKey = 'id';
|
||||
define('IN_PONEPASTE', 1);
|
||||
//require_once('../includes/config.php');
|
||||
require_once('../includes/common.php');
|
||||
require_once('../includes/NonRetardedSSP.class.php');
|
||||
|
||||
// Array of database columns which should be read and sent back to DataTables.
|
||||
// The `db` parameter represents the column name in the database, while the `dt`
|
||||
// parameter represents the DataTables column identifier. In this case simple
|
||||
// indexes
|
||||
$columns = array(
|
||||
array('db' => 'id', 'dt' => 0),
|
||||
array('db' => 'title', 'dt' => 1),
|
||||
array('db' => 'member', 'dt' => 2),
|
||||
array('db' => 'tagsys', 'dt' => 3),
|
||||
array('db' => 'visible', 'dt' => 4),
|
||||
);
|
||||
function tagsToHtml(string $tags) : string {
|
||||
$output = "";
|
||||
$tagsSplit = explode(",", $tags);
|
||||
foreach ($tagsSplit as $tag) {
|
||||
if (stripos($tag, 'nsfw') !== false) {
|
||||
$tag = strtoupper($tag);
|
||||
$tagcolor = "tag is-danger";
|
||||
} elseif (stripos($tag, 'SAFE') !== false) {
|
||||
$tag = strtoupper($tag);
|
||||
$tagcolor = "tag is-success";
|
||||
} elseif (str_contains($tag, '/')) {
|
||||
$tagcolor = "tag is-primary";
|
||||
} else {
|
||||
$tagcolor = "tag is-info";
|
||||
}
|
||||
$output .= '<a href="/archive?q=' . urlencode($tag) . '"><span class="' . $tagcolor . '">' . pp_html_escape(ucfirst($tag)) . '</span></a>';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
$columns2 = array(
|
||||
array('db' => 'title', 'dt' => 0),
|
||||
array('db' => 'member', 'dt' => 1),
|
||||
array('db' => 'tagsys', 'dt' => 2),
|
||||
|
||||
function transformDataRow($row) {
|
||||
$titleHtml = '<a href="/' . urlencode($row[0]) . '">' . pp_html_escape($row[1]) . '</a>';
|
||||
$authorHtml = '<a href="' . urlencode($row[2]) . '">' . pp_html_escape($row[2]) . '</a>';
|
||||
$tagsHtml = tagsToHtml($row[3]);
|
||||
|
||||
return [
|
||||
$titleHtml,
|
||||
$authorHtml,
|
||||
$tagsHtml
|
||||
];
|
||||
}
|
||||
|
||||
$data = NonRetardedSSP::run(
|
||||
$conn, $_GET,
|
||||
'SELECT COUNT(*) FROM pastes',
|
||||
'SELECT pastes.id AS id, title, users.username, GROUP_CONCAT(tags.name SEPARATOR \',\') AS tagsys FROM pastes
|
||||
INNER JOIN users ON users.id = pastes.user_id
|
||||
INNER JOIN paste_taggings on pastes.id = paste_taggings.paste_id
|
||||
INNER JOIN tags ON tags.id = paste_taggings.tag_id
|
||||
GROUP BY pastes.id'
|
||||
);
|
||||
|
||||
|
||||
// SQL server connection information
|
||||
$sql_details = array(
|
||||
'user' => $db_user,
|
||||
'pass' => $db_pass,
|
||||
'db' => $db_schema,
|
||||
'host' => $db_host
|
||||
);
|
||||
$data['data'] = array_map('transformDataRow', $data['data']);
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* If you just want to use the basic configuration for DataTables with PHP
|
||||
* server-side, there is no need to edit below this line.
|
||||
*/
|
||||
|
||||
require('ssp.pastes.php');
|
||||
echo json_encode(
|
||||
SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2)
|
||||
);
|
||||
echo json_encode($data);
|
||||
|
|
|
@ -1,419 +0,0 @@
|
|||
<?php
|
||||
// Turn off all error reporting
|
||||
//error_reporting(0);
|
||||
?>
|
||||
<?php
|
||||
|
||||
function sandwitch($str) {
|
||||
$output = "";
|
||||
$arr = explode(",", $str);
|
||||
foreach ($arr as $word) {
|
||||
$word = ucfirst($word);
|
||||
if (stripos($word, 'nsfw') !== false) {
|
||||
$word = strtoupper($word);
|
||||
$tagcolor = "tag is-danger";
|
||||
} elseif (stripos($word, 'SAFE') !== false) {
|
||||
$word = strtoupper($word);
|
||||
$tagcolor = "tag is-success";
|
||||
} elseif (strstr($word, '/')) {
|
||||
$tagcolor = "tag is-primary";
|
||||
} else {
|
||||
$tagcolor = "tag is-info";
|
||||
}
|
||||
$output .= '<a href="/archive?q=' . trim($word) . '"><span class="' . $tagcolor . '">' . trim($word) . '</span></a>';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
|
||||
// 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'] === 'DESC' ?
|
||||
'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;
|
||||
}
|
||||
|
||||
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, $columns2) {
|
||||
$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::Ssql_exec($db, $bindings,
|
||||
"SELECT SQL_CALC_FOUND_ROWS pastes.id AS id, users.username AS member, tagsys, title, visible
|
||||
FROM `$table`
|
||||
INNER JOIN users ON users.id = pastes.user_id WHERE visible='0' AND tagsys IS NOT NULL AND NOT title LIKE ''
|
||||
$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" => isset($request['draw']) ? intval($request['draw']) : 0,
|
||||
"recordsTotal" => intval($recordsTotal),
|
||||
"recordsFiltered" => intval($recordsFiltered),
|
||||
"data" => self::data_output($columns2, $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 PDO 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 $stmt->fetchAll();
|
||||
}
|
||||
|
||||
static function Ssql_exec($db, $bindings, $sql = null) {
|
||||
// Argument shifting
|
||||
if ($sql === null) {
|
||||
$sql = $bindings;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare($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());
|
||||
}
|
||||
$loop = '0';
|
||||
|
||||
|
||||
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$result[$loop]['id'] = $arr['id'];
|
||||
$result[$loop]['member'] = $arr['member'];
|
||||
$result[$loop]['tagsys'] = sandwitch($arr['tagsys']);
|
||||
$date_time = strtotime($arr['date'] ?? '0');
|
||||
$result[$loop]['date'] = date("d F Y", $date_time);
|
||||
$myid = $arr['id'];
|
||||
$mytitle = $arr['title'];
|
||||
$mymember = $arr['member'];
|
||||
$result[$loop]['title'] = "<a href=/" . $myid . ">" . $mytitle . "</a>";
|
||||
$result[$loop]['member'] = "<a href=/user/" . $mymember . ">" . $mymember . "</a>";
|
||||
$loop = $loop + 1;
|
||||
}
|
||||
|
||||
// Return all
|
||||
return $result;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -26,10 +26,10 @@ class DatabaseHandle {
|
|||
return $stmt;
|
||||
}
|
||||
|
||||
public function querySelectOne(string $query, array $params = null) : array|null {
|
||||
public function querySelectOne(string $query, array $params = null, int $fetchMode = PDO::FETCH_ASSOC) : array|null {
|
||||
$stmt = $this->query($query, $params);
|
||||
|
||||
if ($row = $stmt->fetch()) {
|
||||
if ($row = $stmt->fetch($fetchMode)) {
|
||||
return $row;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,36 @@
|
|||
<?php
|
||||
class NonRetardedSSP {
|
||||
public static function run(DatabaseHandle $conn, array $request, string $countQuery, string $query) {
|
||||
/* Some of these parameters might not be passed; zero is an OK default */
|
||||
$draw = (int) @$request['draw'];
|
||||
$start = (int) @$request['start'];
|
||||
$length = (int) @$request['length'];
|
||||
|
||||
/* figure out total records */
|
||||
$recordsTotal = (int) $conn->querySelectOne($countQuery, [], PDO::FETCH_NUM)[0];
|
||||
|
||||
/* build query */
|
||||
$params = [];
|
||||
|
||||
if ($length != 0) {
|
||||
$query .= ' LIMIT ?';
|
||||
array_push($params, $length);
|
||||
|
||||
if ($start != 0) {
|
||||
$query .= ' OFFSET ?';
|
||||
array_push($params, $start);
|
||||
}
|
||||
}
|
||||
|
||||
/* fire it off */
|
||||
$stmt = $conn->query($query, $params);
|
||||
$data = $stmt->fetchAll(PDO::FETCH_NUM);
|
||||
|
||||
return [
|
||||
'draw' => $draw,
|
||||
'recordsTotal' => $recordsTotal,
|
||||
'recordsFiltered' => ($recordsTotal - count($data)),
|
||||
'data' => $data
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue