91 lines
2.7 KiB
PHP
91 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace Core\Objects\Search;
|
|
|
|
use Html2Text\Html2Text;
|
|
use Core\Objects\Context;
|
|
use function PHPUnit\Framework\stringContains;
|
|
|
|
trait Searchable {
|
|
|
|
public static function searchArray(array $arr, SearchQuery $query): array {
|
|
$results = [];
|
|
foreach ($arr as $key => $value) {
|
|
$results = array_merge($results, self::searchHtml($key, $query));
|
|
if (is_array($value)) {
|
|
$results = array_merge($results, self::searchArray($value, $query));
|
|
} else {
|
|
$results = array_merge($results, self::searchHtml(strval($value), $query));
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
public abstract function doSearch(Context $context, SearchQuery $query): array;
|
|
|
|
public static function searchHtml(string $document, SearchQuery $query): array {
|
|
if (stringContains($document, "<")) {
|
|
$converter = new Html2Text($document);
|
|
$text = trim($converter->getText());
|
|
} else {
|
|
$text = $document;
|
|
}
|
|
|
|
$text = trim(preg_replace('!\s+!', ' ', $text));
|
|
return self::searchText($text, $query);
|
|
}
|
|
|
|
public static function searchText(string $content, SearchQuery $query): array {
|
|
$offset = 0;
|
|
$searchTerm = $query->getQuery();
|
|
$stringLength = strlen($searchTerm);
|
|
$contentLength = strlen($content);
|
|
$lastPos = 0;
|
|
|
|
$results = [];
|
|
do {
|
|
$pos = stripos($content, $searchTerm, $offset);
|
|
if ($pos !== false) {
|
|
if ($lastPos === 0 || $pos > $lastPos + 192 + $stringLength) {
|
|
$extract = self::viewExtract($content, $pos, $searchTerm);
|
|
$results[] = array(
|
|
"text" => $extract,
|
|
"pos" => $pos,
|
|
"lastPos" => $lastPos
|
|
);
|
|
$lastPos = $pos;
|
|
}
|
|
|
|
$offset = $pos + $stringLength;
|
|
}
|
|
} while ($pos !== false && $offset < $contentLength);
|
|
|
|
return $results;
|
|
}
|
|
|
|
private static function viewExtract(string $content, int $pos, $string): array|string|null {
|
|
$length = strlen($string);
|
|
$start = max(0, $pos - 32);
|
|
$end = min(strlen($content) - 1, $pos + $length + 192);
|
|
|
|
if ($start > 0) {
|
|
if (!ctype_space($content[$start - 1]) &&
|
|
!ctype_space($content[$start])) {
|
|
$start = $start + strpos(substr($content, $start, $end), ' ');
|
|
}
|
|
}
|
|
|
|
if ($end < strlen($content) - 1) {
|
|
if (!ctype_space($content[$end + 1]) &&
|
|
!ctype_space($content[$end])) {
|
|
$end = $start + strrpos(substr($content, $start, $end - $start), ' ');
|
|
}
|
|
}
|
|
|
|
$extract = trim(substr($content, $start, $end - $start + 1));
|
|
if ($start > 0) $extract = ".. " . $extract;
|
|
if ($end < strlen($content) - 1) $extract .= " ..";
|
|
return preg_replace("/" . preg_quote($string) . "(?=[^>]*(<|$))/i", "<span class=\"highlight\">\$0</span>", $extract);
|
|
}
|
|
} |