From 1e737ae888f7797667e05294ba77a17cc915f2d6 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Mon, 7 Oct 2019 14:27:20 -0400 Subject: [PATCH] Move mod/search to src/Module/Search/Index - Update BaseSeachModule not to depend on a single query string parameter --- mod/search.php | 194 ------------------------------- src/Module/BaseSearchModule.php | 7 +- src/Module/Search/Directory.php | 5 +- src/Module/Search/Index.php | 198 ++++++++++++++++++++++++++++++++ static/routes.config.php | 1 + 5 files changed, 207 insertions(+), 198 deletions(-) delete mode 100644 mod/search.php create mode 100644 src/Module/Search/Index.php diff --git a/mod/search.php b/mod/search.php deleted file mode 100644 index 7cd5233bf..000000000 --- a/mod/search.php +++ /dev/null @@ -1,194 +0,0 @@ -page['aside'])) { - $a->page['aside'] = ''; - } - - $a->page['aside'] .= \Friendica\Content\Widget\SavedSearches::getHTML('search?q=' . $search, $search); - } -} - -function search_content(App $a) { - if (Config::get('system','block_public') && !Session::isAuthenticated()) { - notice(L10n::t('Public access denied.') . EOL); - return; - } - - if (Config::get('system','local_search') && !Session::isAuthenticated()) { - $e = new \Friendica\Network\HTTPException\ForbiddenException(L10n::t("Only logged in users are permitted to perform a search.")); - $e->httpdesc = L10n::t("Public access denied."); - throw $e; - } - - if (Config::get('system','permit_crawling') && !Session::isAuthenticated()) { - // Default values: - // 10 requests are "free", after the 11th only a call per minute is allowed - - $free_crawls = intval(Config::get('system','free_crawls')); - if ($free_crawls == 0) - $free_crawls = 10; - - $crawl_permit_period = intval(Config::get('system','crawl_permit_period')); - if ($crawl_permit_period == 0) - $crawl_permit_period = 10; - - $remote = $_SERVER["REMOTE_ADDR"]; - $result = Cache::get("remote_search:".$remote); - if (!is_null($result)) { - $resultdata = json_decode($result); - if (($resultdata->time > (time() - $crawl_permit_period)) && ($resultdata->accesses > $free_crawls)) { - throw new \Friendica\Network\HTTPException\TooManyRequestsException(L10n::t("Only one search per minute is permitted for not logged in users.")); - } - Cache::set("remote_search:".$remote, json_encode(["time" => time(), "accesses" => $resultdata->accesses + 1]), Cache::HOUR); - } else - Cache::set("remote_search:".$remote, json_encode(["time" => time(), "accesses" => 1]), Cache::HOUR); - } - - Nav::setSelected('search'); - - $search = (!empty($_REQUEST['q']) ? Strings::escapeTags(trim(rawurldecode($_REQUEST['q']))) : ''); - - $tag = false; - if (!empty($_GET['tag'])) { - $tag = true; - $search = (!empty($_GET['tag']) ? '#' . Strings::escapeTags(trim(rawurldecode($_GET['tag']))) : ''); - } - - // contruct a wrapper for the search header - $o = Renderer::replaceMacros(Renderer::getMarkupTemplate("content_wrapper.tpl"),[ - 'name' => "search-header", - '$title' => L10n::t("Search"), - '$title_size' => 3, - '$content' => HTML::search($search,'search-box',false) - ]); - - if (strpos($search,'#') === 0) { - $tag = true; - $search = substr($search,1); - } - if (strpos($search,'@') === 0) { - return BaseSearchModule::performSearch(); - } - if (strpos($search,'!') === 0) { - return BaseSearchModule::performSearch(); - } - - if (parse_url($search, PHP_URL_SCHEME) != '') { - $id = Item::fetchByLink($search); - if (!empty($id)) { - $item = Item::selectFirst(['guid'], ['id' => $id]); - if (DBA::isResult($item)) { - $a->internalRedirect('display/' . $item['guid']); - } - } - } - - if (!empty($_GET['search-option'])) - switch($_GET['search-option']) { - case 'fulltext': - break; - case 'tags': - $tag = true; - break; - case 'contacts': - return BaseSearchModule::performSearch('@'); - case 'forums': - return BaseSearchModule::performSearch('!'); - } - - if (!$search) - return $o; - - if (Config::get('system','only_tag_search')) - $tag = true; - - // Here is the way permissions work in the search module... - // Only public posts can be shown - // OR your own posts if you are a logged in member - // No items will be shown if the member has a blocked profile wall. - - $pager = new Pager($a->query_string); - - if ($tag) { - Logger::log("Start tag search for '".$search."'", Logger::DEBUG); - - $condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`)) - AND `otype` = ? AND `type` = ? AND `term` = ?", - local_user(), TERM_OBJ_POST, TERM_HASHTAG, $search]; - $params = ['order' => ['received' => true], - 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]; - $terms = DBA::select('term', ['oid'], $condition, $params); - - $itemids = []; - while ($term = DBA::fetch($terms)) { - $itemids[] = $term['oid']; - } - DBA::close($terms); - - if (!empty($itemids)) { - $params = ['order' => ['id' => true]]; - $items = Item::selectForUser(local_user(), [], ['id' => $itemids], $params); - $r = Item::inArray($items); - } else { - $r = []; - } - } else { - Logger::log("Start fulltext search for '".$search."'", Logger::DEBUG); - - $condition = ["(`uid` = 0 OR (`uid` = ? AND NOT `global`)) - AND `body` LIKE CONCAT('%',?,'%')", - local_user(), $search]; - $params = ['order' => ['id' => true], - 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]; - $items = Item::selectForUser(local_user(), [], $condition, $params); - $r = Item::inArray($items); - } - - if (!DBA::isResult($r)) { - info(L10n::t('No results.') . EOL); - return $o; - } - - - if ($tag) { - $title = L10n::t('Items tagged with: %s', $search); - } else { - $title = L10n::t('Results for: %s', $search); - } - - $o .= Renderer::replaceMacros(Renderer::getMarkupTemplate("section_title.tpl"),[ - '$title' => $title - ]); - - Logger::log("Start Conversation for '".$search."'", Logger::DEBUG); - $o .= conversation($a, $r, $pager, 'search', false, false, 'commented', local_user()); - - $o .= $pager->renderMinimal(count($r)); - - Logger::log("Done '".$search."'", Logger::DEBUG); - - return $o; -} diff --git a/src/Module/BaseSearchModule.php b/src/Module/BaseSearchModule.php index ed39f071c..902f2e8a0 100644 --- a/src/Module/BaseSearchModule.php +++ b/src/Module/BaseSearchModule.php @@ -23,13 +23,14 @@ class BaseSearchModule extends BaseModule /** * Performs a search with an optional prefix * + * @param string $search Search query * @param string $prefix A optional prefix (e.g. @ or !) for searching * * @return string * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function performSearch($prefix = '') + public static function performSearch($search, $prefix = '') { $a = self::getApp(); $config = $a->getConfig(); @@ -38,7 +39,7 @@ class BaseSearchModule extends BaseModule $localSearch = $config->get('system', 'poco_local_search'); - $search = $prefix . Strings::escapeTags(trim(defaults($_REQUEST, 'search', ''))); + $search = $prefix . $search; if (!$search) { return ''; @@ -62,7 +63,7 @@ class BaseSearchModule extends BaseModule $header = L10n::t('Forum Search - %s', $search); } - $pager = new Pager($a->query_string); + $pager = new Pager(self::getArgs()->getQueryString()); if ($localSearch && empty($results)) { $pager->setItemsPerPage(80); diff --git a/src/Module/Search/Directory.php b/src/Module/Search/Directory.php index 20cdd5492..405fb0cc8 100644 --- a/src/Module/Search/Directory.php +++ b/src/Module/Search/Directory.php @@ -6,6 +6,7 @@ use Friendica\Content\Widget; use Friendica\Core\L10n; use Friendica\Module\BaseSearchModule; use Friendica\Module\Login; +use Friendica\Util\Strings; /** * Directory search module @@ -19,6 +20,8 @@ class Directory extends BaseSearchModule return Login::form(); } + $search = Strings::escapeTags(trim(rawurldecode($_REQUEST['search'] ?? ''))); + $a = self::getApp(); if (empty($a->page['aside'])) { @@ -28,6 +31,6 @@ class Directory extends BaseSearchModule $a->page['aside'] .= Widget::findPeople(); $a->page['aside'] .= Widget::follow(); - return self::performSearch(); + return self::performSearch($search); } } diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php new file mode 100644 index 000000000..93eeca90f --- /dev/null +++ b/src/Module/Search/Index.php @@ -0,0 +1,198 @@ +httpdesc = L10n::t('Public access denied.'); + throw $e; + } + + if (Config::get('system', 'permit_crawling') && !Session::isAuthenticated()) { + // Default values: + // 10 requests are "free", after the 11th only a call per minute is allowed + + $free_crawls = intval(Config::get('system', 'free_crawls')); + if ($free_crawls == 0) + $free_crawls = 10; + + $crawl_permit_period = intval(Config::get('system', 'crawl_permit_period')); + if ($crawl_permit_period == 0) + $crawl_permit_period = 10; + + $remote = $_SERVER['REMOTE_ADDR']; + $result = Cache::get('remote_search:' . $remote); + if (!is_null($result)) { + $resultdata = json_decode($result); + if (($resultdata->time > (time() - $crawl_permit_period)) && ($resultdata->accesses > $free_crawls)) { + throw new HTTPException\TooManyRequestsException(L10n::t('Only one search per minute is permitted for not logged in users.')); + } + Cache::set('remote_search:' . $remote, json_encode(['time' => time(), 'accesses' => $resultdata->accesses + 1]), CacheClass::HOUR); + } else { + Cache::set('remote_search:' . $remote, json_encode(['time' => time(), 'accesses' => 1]), CacheClass::HOUR); + } + } + + if (local_user()) { + self::getApp()->page['aside'] .= Widget\SavedSearches::getHTML('search?q=' . $search, $search); + } + + Nav::setSelected('search'); + + $tag = false; + if (!empty($_GET['tag'])) { + $tag = true; + $search = '#' . Strings::escapeTags(trim(rawurldecode($_GET['tag']))); + } + + // contruct a wrapper for the search header + $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('content_wrapper.tpl'), [ + 'name' => 'search-header', + '$title' => L10n::t('Search'), + '$title_size' => 3, + '$content' => HTML::search($search, 'search-box', false) + ]); + + if (strpos($search, '#') === 0) { + $tag = true; + $search = substr($search, 1); + } + + if (strpos($search, '@') === 0 || strpos($search, '!') === 0) { + return self::performSearch($search); + } + + if (parse_url($search, PHP_URL_SCHEME) != '') { + $id = Item::fetchByLink($search); + if (!empty($id)) { + $item = Item::selectFirst(['guid'], ['id' => $id]); + if (DBA::isResult($item)) { + self::getApp()->internalRedirect('display/' . $item['guid']); + } + } + } + + if (!empty($_GET['search-option'])) { + switch ($_GET['search-option']) { + case 'fulltext': + break; + case 'tags': + $tag = true; + break; + case 'contacts': + return self::performSearch($search, '@'); + case 'forums': + return self::performSearch($search, '!'); + } + } + + if (!$search) { + return $o; + } + + $tag = $tag || Config::get('system', 'only_tag_search'); + + // Here is the way permissions work in the search module... + // Only public posts can be shown + // OR your own posts if you are a logged in member + // No items will be shown if the member has a blocked profile wall. + + $pager = new Pager(self::getArgs()->getQueryString()); + + if ($tag) { + Logger::info('Start tag search for "' . $search . '"'); + + $condition = [ + "(`uid` = 0 OR (`uid` = ? AND NOT `global`)) + AND `otype` = ? AND `type` = ? AND `term` = ?", + local_user(), Term::OBJECT_TYPE_POST, Term::HASHTAG, $search + ]; + $params = [ + 'order' => ['received' => true], + 'limit' => [$pager->getStart(), $pager->getItemsPerPage()] + ]; + $terms = DBA::select('term', ['oid'], $condition, $params); + + $itemids = []; + while ($term = DBA::fetch($terms)) { + $itemids[] = $term['oid']; + } + + DBA::close($terms); + + if (!empty($itemids)) { + $params = ['order' => ['id' => true]]; + $items = Item::selectForUser(local_user(), [], ['id' => $itemids], $params); + $r = Item::inArray($items); + } else { + $r = []; + } + } else { + Logger::info('Start fulltext search for "' . $search . '"'); + + $condition = [ + "(`uid` = 0 OR (`uid` = ? AND NOT `global`)) + AND `body` LIKE CONCAT('%',?,'%')", + local_user(), $search + ]; + $params = [ + 'order' => ['id' => true], + 'limit' => [$pager->getStart(), $pager->getItemsPerPage()] + ]; + $items = Item::selectForUser(local_user(), [], $condition, $params); + $r = Item::inArray($items); + } + + if (!DBA::isResult($r)) { + info(L10n::t('No results.')); + return $o; + } + + if ($tag) { + $title = L10n::t('Items tagged with: %s', $search); + } else { + $title = L10n::t('Results for: %s', $search); + } + + $o .= Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), [ + '$title' => $title + ]); + + Logger::info('Start Conversation for "' . $search . '"'); + $o .= conversation(self::getApp(), $r, $pager, 'search', false, false, 'commented', local_user()); + + $o .= $pager->renderMinimal(count($r)); + + Logger::info('Done "'.$search.'"'); + + return $o; + } +} diff --git a/static/routes.config.php b/static/routes.config.php index 18144d799..f688a1a86 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -189,6 +189,7 @@ return [ ], '/search' => [ + '[/]' => [Module\Search\Index::class, [R::GET]], '/acl' => [Module\Search\Acl::class, [R::GET, R::POST]], '/saved/add/{term}' => [Module\Search\Saved::class, [R::GET]], '/saved/remove/{term}' => [Module\Search\Saved::class, [R::GET]],