UserPostQueries.php: rewrite of searchPosts
This commit is contained in:
parent
73c62b1088
commit
20bf8b542e
1 changed files with 84 additions and 48 deletions
|
@ -13,6 +13,36 @@ class UserPostQueries {
|
|||
|
||||
private \PDO $pdo;
|
||||
|
||||
|
||||
/**
|
||||
* Escapes wildcards from LIKE operators using the default escape character.
|
||||
*/
|
||||
private static function escapeLike(string $str): string {
|
||||
// Escape any existing escape characters.
|
||||
$str = \str_replace('\\', '\\\\', $str);
|
||||
// Escape wildcard characters.
|
||||
$str = \str_replace('%', '\\%', $str);
|
||||
$str = \str_replace('_', '\\_', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the fragments of filter into a single LIKE operand string.
|
||||
* Given prefix = cat and fragments_count = 3, we get "%:cat0%:cat1%:cat2%"
|
||||
*
|
||||
* @param string $prefix The prefix for the parameter binding
|
||||
* @param int $fragments_count MUST BE >= 1.
|
||||
* @return string
|
||||
*/
|
||||
private static function joinFragments(string $prefix, int $fragments_count): string {
|
||||
// With prefix = cat and fragments = 2 it becomes: "%:cat0%:cat1%"
|
||||
$s = '%';
|
||||
for ($i = 0; $i < $fragments_count; $i++) {
|
||||
$s .= ":$prefix$i%";
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
public function __construct(\PDO $pdo) {
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
@ -157,63 +187,69 @@ class UserPostQueries {
|
|||
});
|
||||
}
|
||||
|
||||
public function searchPosts(string $board, ?string $subject, ?string $name, ?array $flags, ?int $id, ?int $thread, array $text_chunks, int $limit): array {
|
||||
$filters_acc = [];
|
||||
if ($subject !== null) {
|
||||
$acc[] = " WHERE subject LIKE '%?%'";
|
||||
}
|
||||
if ($name !== null) {
|
||||
$acc[] = " WHERE name LIKE '%?%'";
|
||||
}
|
||||
if ($id !== null) {
|
||||
$acc[] = " WHERE id = ?";
|
||||
}
|
||||
if ($thread !== null) {
|
||||
$acc[] = " WHERE thread = ?";
|
||||
}
|
||||
if ($flags !== null) {
|
||||
$f_acc = [];
|
||||
for ($i = 0; $i < \count($flags); $i++) {
|
||||
// Yes, vichan stores the flag inside the generated HTML.
|
||||
// English lacks the words to express my feelings about it in a satisfying manner.
|
||||
$f_acc[] = " WHERE body_nomarkup LIKE = '%<tinyboard>?</tinyboard>%'";
|
||||
}
|
||||
$acc[] = '(' . \implode(' OR ', $f_acc) . ')';
|
||||
}
|
||||
for ($i = 0; $i < \count($text_chunks); $i++) {
|
||||
$filters_acc = " WHERE body LIKE = '%?%'";
|
||||
}
|
||||
$sql = "'SELECT * FROM `posts_$board` " . \implode(' AND ', $filters_acc) . ' LIMIT ?';
|
||||
public function searchPosts(string $board, array $subject, array $name, array $flags, ?int $id, ?int $thread, array $bodies, int $limit): array {
|
||||
$where_acc = [];
|
||||
|
||||
$query = $this->pdo->prepare($sql);
|
||||
$bound_i = 0;
|
||||
if ($subject !== null) {
|
||||
$query->bindValue($bound_i, $subject);
|
||||
$bound_i++;
|
||||
if (!empty($subject)) {
|
||||
$like_op = self::joinFragments('subj', \count($subject));
|
||||
$where_acc[] = "WHERE subject LIKE '$like_op'";
|
||||
}
|
||||
if ($name !== null) {
|
||||
$query->bindValue($bound_i, $name);
|
||||
$bound_i++;
|
||||
if (!empty($name)) {
|
||||
$like_op = self::joinFragments('name', \count($name));
|
||||
$where_acc[] = "WHERE name LIKE '$like_op'";
|
||||
}
|
||||
if (!empty($flags)) {
|
||||
$flag_acc = [];
|
||||
for ($i = 0; $i < \count($flags); $i++) {
|
||||
// Yes, vichan stores the flag inside the generated HTML. Now you know why it's slow as shit.
|
||||
// English lacks the words to express my feelings about it in a satisfying manner.
|
||||
$flag_acc[] = "LIKE = '%<tinyboard>:flag$i</tinyboard>%'";
|
||||
}
|
||||
$where_acc[] = 'WHERE body_nomarkup (' . \implode(' OR ', $flag_acc) . ')';
|
||||
}
|
||||
if ($id !== null) {
|
||||
$query->bindValue($bound_i, $id, \PDO::PARAM_INT);
|
||||
$bound_i++;
|
||||
$where_acc[] = 'WHERE id = :id';
|
||||
}
|
||||
if ($thread !== null) {
|
||||
$query->bindValue($bound_i, $thread, \PDO::PARAM_INT);
|
||||
$bound_i++;
|
||||
$where_acc[] = 'WHERE thread = :thread';
|
||||
}
|
||||
if ($flags !== null) {
|
||||
foreach ($flags as $flag) {
|
||||
$query->bindValue($bound_i, $flag);
|
||||
$bound_i++;
|
||||
for ($i = 0; $i < \count($bodies); $i++) {
|
||||
$body = $bodies[$i];
|
||||
$like_op = self::joinFragments("body_{$i}_", \count($body));
|
||||
$where_acc[] = "WHERE body LIKE '$like_op'";
|
||||
}
|
||||
|
||||
if (empty($where_acc)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$sql = "SELECT * FROM `posts_$board` " . \implode(' AND ', $where_acc) . ' LIMIT ?';
|
||||
$query = $this->pdo->prepare($sql);
|
||||
|
||||
for ($i = 0; $i < \count($subject); $i++) {
|
||||
$query->bindValue(":subj$i", $subject[$i]);
|
||||
}
|
||||
for ($i = 0; $i < \count($name); $i++) {
|
||||
$query->bindValue(":name$i", $name[$i]);
|
||||
}
|
||||
for ($i = 0; $i < \count($flags); $i++) {
|
||||
$query->bindValue(":flag$i", $flags[$i]);
|
||||
}
|
||||
if ($id !== null) {
|
||||
$query->bindValue(':id', $id, \PDO::PARAM_INT);
|
||||
}
|
||||
if ($thread !== null) {
|
||||
$query->bindValue(':thread', $thread, \PDO::PARAM_INT);
|
||||
}
|
||||
for ($body_i = 0; $body_i < \count($bodies); $body_i++) {
|
||||
$body = $bodies[$body_i];
|
||||
|
||||
for ($i = 0; $i < \count($body); $i++) {
|
||||
$query->bindValue(":body_{$body_i}_{$i}", $body[$i]);
|
||||
}
|
||||
}
|
||||
foreach ($text_chunks as $chunk) {
|
||||
$query->bindValue($bound_i, $chunk);
|
||||
$bound_i++;
|
||||
}
|
||||
$query->bindValue($bound_i, $limit, \PDO::PARAM_INT);
|
||||
|
||||
$query->bindValue(':limit', $limit, \PDO::PARAM_INT);
|
||||
|
||||
$query->execute();
|
||||
return $query->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue