109 lines
3.2 KiB
PHP
109 lines
3.2 KiB
PHP
<?php
|
||
|
||
class sphinx {
|
||
|
||
public static function execute(string $sql) {
|
||
$link = self::getLink();
|
||
|
||
if (func_num_args() > 1) {
|
||
$mark_count = substr_count($sql, '?');
|
||
$positions = array();
|
||
$last_pos = -1;
|
||
for ($i = 0; $i < $mark_count; $i++) {
|
||
$last_pos = strpos($sql, '?', $last_pos + 1);
|
||
$positions[] = $last_pos;
|
||
}
|
||
for ($i = $mark_count - 1; $i >= 0; $i--) {
|
||
$arg = func_get_arg($i + 1);
|
||
if (is_string($arg))
|
||
$arg = self::normalize($arg);
|
||
$v = '\''.$link->real_escape_string($arg).'\'';
|
||
$sql = substr_replace($sql, $v, $positions[$i], 1);
|
||
}
|
||
}
|
||
|
||
$q = $link->query($sql);
|
||
|
||
$error = self::getError();
|
||
if ($error)
|
||
logError(__FUNCTION__, $error);
|
||
|
||
return $q;
|
||
}
|
||
|
||
public static function getError() {
|
||
$link = self::getLink(auto_create: false);
|
||
return $link?->error;
|
||
}
|
||
|
||
public static function mkquery($q, array $opts = []) {
|
||
$defaults = [
|
||
'any_word' => false,
|
||
'star' => false,
|
||
'and' => false,
|
||
'exact_first' => false
|
||
];
|
||
$opts = array_merge($defaults, $opts);
|
||
$q = preg_replace('/\s+/', ' ', $q);
|
||
$q = self::normalize($q);
|
||
$q = trim($q);
|
||
$q = self::getClient()->escapeString($q);
|
||
if ($opts['star']) {
|
||
$words = explode(' ', $q);
|
||
$words = array_map(fn($word) => $word.'*', $words);
|
||
$q = implode(' ', $words);
|
||
}
|
||
if ($opts['any_word']) {
|
||
$q = str_replace(' ', ' | ', $q);
|
||
} else if ($opts['and']) {
|
||
$q = str_replace(' ', ' AND ', $q);
|
||
}
|
||
if ($opts['exact_first']) {
|
||
$q = '"^'.$q.'$" | "'.$q.'" | ('.$q.')';
|
||
}
|
||
return $q;
|
||
}
|
||
|
||
public static function getClient(): Sphinx\SphinxClient {
|
||
static $cl = null;
|
||
if (!is_null($cl))
|
||
return $cl;
|
||
return $cl = new Sphinx\SphinxClient;
|
||
}
|
||
|
||
protected static function normalize(string $origstr): string {
|
||
$buf = preg_replace('/[Ёё]/iu', 'е', $origstr);
|
||
if (!pcreNoError($buf, no_error: true)) {
|
||
$origstr = mb_convert_encoding($origstr, 'UTF-8', 'UTF-8');
|
||
$buf = preg_replace('/[Ёё]/iu', 'е', $origstr);
|
||
pcreNoError($buf);
|
||
}
|
||
if ($buf === null) {
|
||
logError(__METHOD__.': preg_replace() failed with error: '.preg_last_error().': '.preg_last_error_msg());
|
||
$buf = $origstr;
|
||
}
|
||
return preg_replace('/[!\?]/', '', $buf);
|
||
}
|
||
|
||
protected static function getLink($auto_create = true) {
|
||
global $config;
|
||
|
||
/** @var ?mysqli $link */
|
||
static $link = null;
|
||
if (!is_null($link) || !$auto_create)
|
||
return $link;
|
||
|
||
$link = new mysqli();
|
||
$link->real_connect(
|
||
$config['sphinx']['host'],
|
||
ini_get('mysql.default_user'),
|
||
ini_get('mysql.default_password'),
|
||
null,
|
||
9306);
|
||
$link->set_charset('utf8');
|
||
|
||
return $link;
|
||
}
|
||
|
||
|
||
} |