New search system, including date: and pubdate: and combination

Now also accepts combination of #tag and intitle: and inurl: and author:
and the new date: and pubdate:
https://github.com/marienfressinaud/FreshRSS/issues/511
Each search prefix stop at the first space (we should add a possibility
to have quotes for multiple words)
So if you want two words in title, write "intitle:word1 intitle:word2"

Examples of dates:
date:2014
date:2014-02/2014-04 or date:201402/201404
date:P1W for the last week
pull/517/head
Alexandre Alapetite 10 years ago
parent 08ceeb1bcd
commit ecac55d3d3
  1. 70
      app/Models/EntryDAO.php
  2. 130
      lib/lib_date.php

@ -478,48 +478,50 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
}
$search = '';
if ($filter !== '') {
require_once(LIB_PATH . '/lib_date.php');
$filter = trim($filter);
$filter = addcslashes($filter, '\\%_');
if (stripos($filter, 'intitle:') === 0) {
$filter = substr($filter, strlen('intitle:'));
$intitle = true;
} else {
$intitle = false;
}
if (stripos($filter, 'inurl:') === 0) {
$filter = substr($filter, strlen('inurl:'));
$inurl = true;
} else {
$inurl = false;
}
if (stripos($filter, 'author:') === 0) {
$filter = substr($filter, strlen('author:'));
$author = true;
} else {
$author = false;
}
$terms = array_unique(explode(' ', $filter));
sort($terms); //Put #tags first
foreach ($terms as $word) {
$word = trim($word);
if (strlen($word) > 0) {
if ($intitle) {
$search .= 'AND e1.title LIKE ? ';
$values[] = '%' . $word .'%';
} elseif ($inurl) {
$search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
$values[] = '%' . $word .'%';
} elseif ($author) {
$search .= 'AND e1.author LIKE ? ';
if (stripos($word, 'intitle:') === 0) {
$word = substr($word, strlen('intitle:'));
$search .= 'AND e1.title LIKE ? ';
$values[] = '%' . $word .'%';
} elseif (stripos($word, 'inurl:') === 0) {
$word = substr($word, strlen('inurl:'));
$search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
$values[] = '%' . $word .'%';
} elseif (stripos($word, 'author:') === 0) {
$word = substr($word, strlen('author:'));
$search .= 'AND e1.author LIKE ? ';
$values[] = '%' . $word .'%';
} elseif (stripos($word, 'date:') === 0) {
$word = substr($word, strlen('date:'));
list($minDate, $maxDate) = parseDateInterval($word);
if ($minDate) {
$search .= 'AND e1.id >= ' . $minDate . '000000 ';
}
if ($maxDate) {
$search .= 'AND e1.id <= ' . $maxDate . '000000 ';
}
} elseif (stripos($word, 'pubdate:') === 0) {
$word = substr($word, strlen('pubdate:'));
list($minDate, $maxDate) = parseDateInterval($word);
if ($minDate) {
$search .= 'AND e1.date >= ' . $minDate . ' ';
}
if ($maxDate) {
$search .= 'AND e1.date <= ' . $maxDate . ' ';
}
} else {
if ($word[0] === '#' && isset($word[1])) {
$search .= 'AND e1.tags LIKE ? ';
$values[] = '%' . $word .'%';
} else {
if ($word[0] === '#' && isset($word[1])) {
$search .= 'AND e1.tags LIKE ? ';
$values[] = '%' . $word .'%';
} else {
$search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
$values[] = '%' . $word .'%';
}
$search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
$values[] = '%' . $word .'%';
}
}
}

@ -0,0 +1,130 @@
<?php
/**
* Author: Alexandre Alapetite http://alexandre.alapetite.fr
* 2014-06-01
* License: GNU AGPLv3 http://www.gnu.org/licenses/agpl-3.0.html
*
* Parser of ISO 8601 time intervals http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
* Examples: "2014-02/2014-04", "2014-02/04", "2014-06", "P1M"
*/
/*
example('2014-03');
example('201403');
example('2014-03-30');
example('2014-05-30T13');
example('2014-05-30T13:30');
example('2014-02/2014-04');
example('2014-02--2014-04');
example('2014-02/04');
example('2014-02-03/05');
example('2014-02-03T22:00/22:15');
example('2014-02-03T22:00/15');
example('2014-03/');
example('/2014-03');
example('2014-03/P1W');
example('P1W/2014-05-25T23:59:59');
example('P1Y/');
example('P1Y');
example('P2M/');
example('P3W/');
example('P4D/');
example('PT5H/');
example('PT6M/');
example('PT7S/');
example('P1DT1H/');
function example($dateInterval) {
$dateIntervalArray = parseDateInterval($dateInterval);
echo $dateInterval, "\t=>\t",
$dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/',
$dateIntervalArray[1] == null ? 'null' : @date('c', $dateIntervalArray[1]), "\n";
}
*/
function _dateFloor($isoDate) {
$x = explode('T', $isoDate, 2);
$t = isset($x[1]) ? str_pad($x[1], 6, '0') : '000000';
return str_pad($x[0], 8, '01') . 'T' . $t;
}
function _dateCeiling($isoDate) {
$x = explode('T', $isoDate, 2);
$t = isset($x[1]) && strlen($x[1]) > 1 ? str_pad($x[1], 6, '59') : '235959';
switch (strlen($x[0])) {
case 4:
return $x[0] . '1231T' . $t;
case 6:
$d = @strtotime($x[0] . '01');
return $x[0] . date('t', $d) . 'T' . $t;
default:
return $x[0] . 'T' . $t;
}
}
function _noDelimit($isoDate) {
return $isoDate === null || $isoDate === '' ? null :
str_replace(array('-', ':'), '', $isoDate); //FIXME: Bug with negative time zone
}
function _dateRelative($d1, $d2) {
if ($d2 === null) {
return $d1 !== null && $d1[0] !== 'P' ? $d1 : null;
} elseif ($d2 !== '' && $d2[0] != 'P' && $d1 !== null && $d1[0] !== 'P') {
$y2 = substr($d2, 0, 4);
if (strlen($y2) < 4 || !ctype_digit($y2)) { //Does not start by a year
$d2 = _noDelimit($d2);
return substr($d1, 0, -strlen($d2)) . $d2; //Add prefix from $d1
}
}
return _noDelimit($d2);
}
/**
* Parameter $dateInterval is a string containing an ISO 8601 time intervals.
* Returns an array with the minimum and maximum Unix timestamp of this interval, or null if open interval.
*/
function parseDateInterval($dateInterval) {
$dateInterval = trim($dateInterval);
$dateInterval = str_replace('--', '/', $dateInterval);
$dateInterval = strtoupper($dateInterval);
$min = null;
$max = null;
$x = explode('/', $dateInterval, 2);
$d1 = _noDelimit($x[0]);
$d2 = _dateRelative($d1, count($x) > 1 ? $x[1] : null);
if ($d1 !== null && $d1[0] !== 'P') {
$min = @strtotime(_dateFloor($d1));
}
if ($d2 !== null) {
if ($d2[0] === 'P') {
try {
$di2 = new DateInterval($d2);
$dt1 = @date_create(); //new DateTime() would create an Exception if the default time zone is not defined
if ($min !== null && $min !== false) {
$dt1->setTimestamp($min);
}
$max = $dt1->add($di2)->getTimestamp() - 1;
} catch (Exception $e) {
$max = false;
}
} elseif ($d1 === null || $d1[0] !== 'P') {
$max = @strtotime(_dateCeiling($d2));
} else {
$max = @strtotime($d2);
}
}
if ($d1 !== null && $d1[0] === 'P') {
try {
$di1 = new DateInterval($d1);
$dt2 = @date_create();
if ($max !== null && $max !== false) {
$dt2->setTimestamp($max);
}
$min = $dt2->sub($di1)->getTimestamp() + 1;
} catch (Exception $e) {
$min = false;
}
}
return array($min, $max);
}
Loading…
Cancel
Save