<?php
/* Sphinx Search for database driven websites
* Copyright 2010, Richard Carson
*
* This search method uses a regular expression search of a character tree, and gives each object a weighted score.
* Scores are determined by string length, where matches of 1 char is 1 point, 2 chars are 10 points, 3 chars are 100 points, etc
* A value of 1001, or 101 is a good starting point
* Objects below the minimum score are dropped, and the rest are sorted by score.
* Please note that depending on the minimum score, some queries may be too short.
* Use the GetShortestGood method to determine the minimum length a query string must have
* The dataset must be in the form of:
* Dataset(
* object
* (
* string
* string
* }
* object
* (
* string
* string
* string
* )
* )
*
* SetScore($score) //Set the minimum score
* GetScore() //Get the current minimum score
* SetData($Dataset, $checkit=true) //Set the dataset, verification of dataset formatting is optional, and on by default
* GetData($index=-1) //Get the current dataset, or the object at index
* Search($Query, $debug=false) //Perform a search, debug mode is available.
* GetShortestGood() //Get the shortest query length that can return results
*/
class Ssearch
{
private $Dataset=array();
private $MinScore=0;
function __construct()
{
}
private function BuildQtree($query, $debug)
{
$query = strtolower($query);
$Qtree = array();
$Qtree["words"][0] = $query;
$q = strlen($query) - 1;
$i = 0;
$cQ = &$Qtree;
$ilim = 0;
while ($q > 0)
{
$cur = array();
$ilim = strlen($query) - $q;
$i = 0;
while ( $i <= $ilim)
{
$cur["words"][] = substr($query, $i, $q);
$i++;
}
$q--;
$cQ["child"] = $cur;
$cQ = &$cQ["child"];
}
if ($debug) var_dump($Qtree);
return $Qtree;
}
public function SetScore($score)
{
$this->MinScore = $score;
}
public function GetScore()
{
return $this->MinScore;
}
public function SetData($Data, $checkit=true)
{
//Check Dataset
if ($checkit)
{
if (is_array($Data))
{
foreach($Data as $obj)
{
if (is_array($obj))
{
foreach($obj as $line)
{
if (is_array($line))
{
return false;
}
}
}
else
{
return false;
}
}
}
else
{
return false;
}
}
$this->Dataset = $Data;
}
public function GetData($index=-1)
{
if ($index >= 0 && $index <count($this->Dataset))
{
return $this->Dataset[$index];
}
return $this->Dataset;
}
//Function by Fedak (http://php.net/manual/en/function.sort.php)
private function array_sort($array, $on, $order='SORT_DESC')
{
$new_array = array();
$sortable_array = array();
if (count($array) > 0) {
foreach ($array as $k => $v) {
if (is_array($v)) {
foreach ($v as $k2 => $v2) {
if ($k2 == $on) {
$sortable_array[$k] = $v2;
}
}
} else {
$sortable_array[$k] = $v;
}
}
switch($order)
{
case 'SORT_ASC':
asort($sortable_array);
break;
case 'SORT_DESC':
arsort($sortable_array);
break;
}
foreach($sortable_array as $k => $v) {
$new_array[] = $array[$k];
}
}
return $new_array;
}
//Compare a string to the query using REGEX
private function QCompare($Qtree, $DataStr, $debug)
{
$DataStr = strtolower($DataStr);
$Score = 0;
$Levels = 0;
$tmp = $Qtree;
while (isset($tmp["child"]))
{
$Levels++;
$tmp = $tmp["child"];
}
while ($Levels >= 0)
{
$set = false;
foreach($Qtree["words"] as $word)
{
if (preg_match("/$word/", $DataStr))
{
if ($debug) echo "\n$DataStr - $word - $Score\n";
$Score += pow(10, $Levels);
$set = true;
}
}
if ($debug && $set) echo "\n$DataStr - $Score\n";
if ($set)
return $Score;
$Qtree = $Qtree["child"];
$Levels--;
}
if ($debug) echo "\n$DataStr - $Score\n";
return $Score;
}
//Evaluate a series of strings as one object, or set -- for multiple column support
private function QEval($Qtree, $Row, $debug)
{
$Score = 0;
foreach ($Row as $str)
{
$Score += $this->QCompare($Qtree, $str, $debug);
}
if ($debug) echo $Score . "\n";
return $Score;
}
public function Search($Query, $debug=false)
{
$dataret = $this->Dataset;
$Qret = $this->BuildQtree($Query, $debug);
$Query = $Qret;
$i = 0;foreach($dataret as $row)
{
if(isset($row['id'])) unset($row['id']);
if(isset($row['ntp'])) unset($row['ntp']);
$dataret[$i++]["score"] = $this->QEval($Query, $row, $debug);
if ($dataret[$i-1]["score"] < $this->MinScore) unset($dataret[$i-1]);
}
$dataret = $this->array_sort($dataret, "score", 'SORT_DESC');
return $dataret;
}
public function GetShortestGood()
{
$i = 1;
while ($MinScore % pow(10,$i-1) > 0)
{
$i++;
}
return $i-1;
}
}
?>