*/
private function filterFulltext($searchterms, $privateonly = false)
{
- // FIXME: explode(' ',$searchterms) and perform a AND search.
- // FIXME: accept double-quotes to search for a string "as is"?
- $filtered = array();
- $search = mb_convert_case($searchterms, MB_CASE_LOWER, 'UTF-8');
+ $search = mb_convert_case(html_entity_decode($searchterms), MB_CASE_LOWER, 'UTF-8');
$explodedSearch = explode(' ', trim($search));
$keys = array('title', 'description', 'url', 'tags');
+ $found = true;
+ $searchExactPhrase = false;
+ // Check if we're using double-quotes to search for the exact string
+ if ($search[0] == '"' && $search[strlen($search) - 1] == '"') {
+ $searchExactPhrase = true;
+
+ // Remove the double-quotes as they are not what we search for
+ $search = substr($search, 1, -1);
+ }
// Iterate over every stored link.
foreach ($this->links as $link) {
- $found = false;
// ignore non private links when 'privatonly' is on.
if (! $link['private'] && $privateonly === true) {
// Iterate over searchable link fields.
foreach ($keys as $key) {
- // Search full expression.
- if (strpos(
- mb_convert_case($link[$key], MB_CASE_LOWER, 'UTF-8'),
- $search
- ) !== false) {
- $found = true;
- }
+ // Be optimistic
+ $found = true;
+
+ // FIXME: Find a better word for where you're searching in
+ $haystack = mb_convert_case($link[$key], MB_CASE_LOWER, 'UTF-8');
+ // When searching for the phrase, check if it's in the haystack...
+ if ( $searchExactPhrase && strpos($haystack, $search) !== false) {
+ break;
+ }
+ else {
+ // Iterate over keywords, if keyword is not found,
+ // no need to check for the others. We want all or nothing.
+ foreach($explodedSearch as $keyword) {
+ if(strpos($haystack, $keyword) === false) {
+ $found = false;
+ break;
+ }
+ }
+ }
+
+ // One of the fields of the link matches, no need to check the other.
if ($found) {
break;
}
}
-
+
if ($found) {
$filtered[$link['linkdate']] = $link;
}
*/
public function filterTags($tags, $casesensitive = false, $privateonly = false)
{
- $searchtags = $this->tagsStrToArray($tags, $casesensitive);
+ $searchtags = self::tagsStrToArray($tags, $casesensitive);
$filtered = array();
+ if (empty($searchtags)) {
+ return $filtered;
+ }
- foreach ($this->links as $l) {
+ foreach ($this->links as $link) {
// ignore non private links when 'privatonly' is on.
- if (! $l['private'] && $privateonly === true) {
+ if (! $link['private'] && $privateonly === true) {
continue;
}
- $linktags = $this->tagsStrToArray($l['tags'], $casesensitive);
+ $linktags = self::tagsStrToArray($link['tags'], $casesensitive);
- if (count(array_intersect($linktags, $searchtags)) == count($searchtags)) {
- $filtered[$l['linkdate']] = $l;
+ $found = true;
+ for ($i = 0 ; $i < count($searchtags) && $found; $i++) {
+ // Exclusive search, quit if tag found.
+ // Or, tag not found in the link, quit.
+ if (($searchtags[$i][0] == '-' && in_array(substr($searchtags[$i], 1), $linktags))
+ || ($searchtags[$i][0] != '-') && ! in_array($searchtags[$i], $linktags)
+ ) {
+ $found = false;
+ }
+ }
+
+ if ($found) {
+ $filtered[$link['linkdate']] = $link;
}
}
krsort($filtered);
* Convert a list of tags (str) to an array. Also
* - handle case sensitivity.
* - accepts spaces commas as separator.
- * - remove private tags for loggedout users.
*
* @param string $tags string containing a list of tags.
* @param bool $casesensitive will convert everything to lowercase if false.
*
* @return array filtered tags string.
*/
- public function tagsStrToArray($tags, $casesensitive)
+ public static function tagsStrToArray($tags, $casesensitive)
{
// We use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek)
$tagsOut = $casesensitive ? $tags : mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8');
$tagsOut = str_replace(',', ' ', $tagsOut);
- return explode(' ', trim($tagsOut));
+ return array_filter(explode(' ', trim($tagsOut)), 'strlen');
}
}