diff --git a/core/src/Controllers/Search.php b/core/src/Controllers/Search.php index 8e5a972804..b9e903e639 100644 --- a/core/src/Controllers/Search.php +++ b/core/src/Controllers/Search.php @@ -9,6 +9,8 @@ use EvolutionCMS\Models\SiteTemplate; use EvolutionCMS\Models\SiteTmplvar; use EvolutionCMS\Models\SiteTmplvarContentvalue; +use Illuminate\Database\Query\Builder as QueryBuilder; +use Illuminate\Database\Eloquent\Builder as EloquentBuilder; class Search extends AbstractController implements ManagerTheme\PageControllerInterface { @@ -53,13 +55,12 @@ protected function parameterActionButtons() protected function getResults() { - $results = null; - $searchQuery = SiteContent::query() - ->select('site_content.id', 'pagetitle', 'longtitle', 'description', 'introtext', 'menutitle', 'deleted', 'published', 'isfolder', 'type'); + ->select('site_content.id', 'pagetitle', 'longtitle', 'description', 'introtext', 'menutitle', + 'deleted', 'published', 'isfolder', 'type'); $searchfields = trim(get_by_key($_REQUEST, 'searchfields', '', 'is_scalar')); - $articul_id = []; + $contentIds = []; $templateid = isset($_REQUEST['templateid']) && $_REQUEST['templateid'] !== '' ? (int)$_REQUEST['templateid'] : ''; @@ -80,23 +81,22 @@ protected function getResults() if (substr($url, 0, 4) === 'http') { $url = preg_replace('@^' . $site_url . '@', '', $url); } - $idFromAlias = $this->managerTheme->getCore() - ->getIdFromAlias($url); + $idFromAlias = \UrlProcessor::getIdFromAlias($url); } if ($searchfields != '') { $tvs = SiteTmplvarContentvalue::query() - ->where('value', 'LIKE', '%' . $searchfields . '%'); + ->where(function ($query) use ($searchfields) { + $this->ciLikeConditions($query, ['value'], $searchfields); + }); if ($tvs->count() > 0) { - $i = 1; - foreach ($tvs->pluck('contentid') - ->toArray() as $articul) { - $articul_id[] = $articul; + foreach ($tvs->pluck('contentid')->toArray() as $contentId) { + $contentIds[] = $contentId; } } - $searchQuery = $searchQuery->where(function ($query) use ($searchfields, $idFromAlias, $articul_id) { + $searchQuery = $searchQuery->where(function ($query) use ($searchfields, $idFromAlias, $contentIds) { $hasClause = false; if (ctype_digit($searchfields)) { @@ -118,12 +118,11 @@ protected function getResults() if (!ctype_digit($searchfields)) { $condition = function ($nested) use ($searchfields) { - $nested->where('pagetitle', 'LIKE', '%' . $searchfields . '%') - ->orWhere('longtitle', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('introtext', 'LIKE', '%' . $searchfields . '%') - ->orWhere('menutitle', 'LIKE', '%' . $searchfields . '%') - ->orWhere('alias', 'LIKE', '%' . $searchfields . '%'); + $this->ciLikeConditions( + $nested, + ['pagetitle', 'longtitle', 'description', 'introtext', 'menutitle', 'alias'], + $searchfields + ); }; if ($hasClause) { @@ -134,11 +133,11 @@ protected function getResults() } } - if (!empty($articul_id)) { + if (!empty($contentIds)) { if ($hasClause) { - $query->orWhereIn('site_content.id', $articul_id); + $query->orWhereIn('site_content.id', $contentIds); } else { - $query->whereIn('site_content.id', $articul_id); + $query->whereIn('site_content.id', $contentIds); } } }); @@ -160,11 +159,12 @@ protected function getResults() $mgrRole = (isset ($_SESSION['mgrRole']) && $_SESSION['mgrRole'] == 1) ? 1 : 0; if ($mgrRole != 1) { if (isset($_SESSION['mgrDocgroups']) && is_array($_SESSION['mgrDocgroups'])) { - $searchQuery = $searchQuery->leftJoin('document_groups', 'site_content.id', '=', 'document_groups.document') - ->where(function ($query) use ($searchfields) { - $query->where('privatemgr', 0) - ->orWhereIn('document_group', $_SESSION['mgrDocgroups']); - }); + $searchQuery = $searchQuery->leftJoin( + 'document_groups', 'site_content.id', '=', 'document_groups.document' + )->where(function ($query) use ($searchfields) { + $query->where('privatemgr', 0) + ->orWhereIn('document_group', $_SESSION['mgrDocgroups']); + }); } else { $searchQuery = $searchQuery->where('privatemgr', 0); } @@ -186,9 +186,9 @@ protected function getResults() 'application/vnd.ms-excel' => $this->managerTheme->getStyle('icon_excel'), ]; - if (!empty($articul_id)) { - $searchQuery = $searchQuery->orWhere(function ($query) use ($articul_id) { - $query->whereIn('site_content.id', $articul_id); + if (!empty($contentIds)) { + $searchQuery = $searchQuery->orWhere(function ($query) use ($contentIds) { + $query->whereIn('site_content.id', $contentIds); }); } @@ -299,9 +299,11 @@ protected function getAjaxResults() ->select('id', 'templatename', 'locked') ->where(function ($query) use ($searchfields) { $query->where('id', 'LIKE', '%' . $searchfields . '%') - ->orWhere('templatename', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('content', 'LIKE', '%' . $searchfields . '%'); + ->orWhere(function ($nested) use ($searchfields) { + $this->ciLikeConditions( + $nested, ['templatename', 'description', 'content'], $searchfields + ); + }); }); $count = $results->count(); @@ -334,13 +336,13 @@ protected function getAjaxResults() ->select('id', 'name', 'locked') ->where(function ($query) use ($searchfields) { $query->where('id', 'LIKE', '%' . $searchfields . '%') - ->orWhere('name', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('type', 'LIKE', '%' . $searchfields . '%') - ->orWhere('elements', 'LIKE', '%' . $searchfields . '%') - ->orWhere('display', 'LIKE', '%' . $searchfields . '%') - ->orWhere('display_params', 'LIKE', '%' . $searchfields . '%') - ->orWhere('default_text', 'LIKE', '%' . $searchfields . '%'); + ->orWhere(function ($nested) use ($searchfields) { + $this->ciLikeConditions( + $nested, + ['name', 'description', 'type', 'elements', 'display', 'display_params', 'default_text'], + $searchfields + ); + }); }); $count = $results->count(); @@ -370,9 +372,9 @@ protected function getAjaxResults() ->select('id', 'name', 'locked', 'disabled') ->where(function ($query) use ($searchfields) { $query->where('id', 'LIKE', '%' . $searchfields . '%') - ->orWhere('name', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('snippet', 'LIKE', '%' . $searchfields . '%'); + ->orWhere(function ($nested) use ($searchfields) { + $this->ciLikeConditions($nested, ['name', 'description', 'snippet'], $searchfields); + }); }); $count = $results->count(); @@ -402,11 +404,11 @@ protected function getAjaxResults() ->select('id', 'name', 'locked', 'disabled') ->where(function ($query) use ($searchfields) { $query->where('id', 'LIKE', '%' . $searchfields . '%') - ->orWhere('name', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('snippet', 'LIKE', '%' . $searchfields . '%') - ->orWhere('properties', 'LIKE', '%' . $searchfields . '%') - ->orWhere('moduleguid', 'LIKE', '%' . $searchfields . '%'); + ->orWhere(function ($nested) use ($searchfields) { + $this->ciLikeConditions( + $nested, ['name', 'description', 'snippet', 'properties', 'moduleguid'], $searchfields + ); + }); }); $count = $results->count(); @@ -436,11 +438,13 @@ protected function getAjaxResults() ->select('id', 'name', 'locked', 'disabled') ->where(function ($query) use ($searchfields) { $query->where('id', 'LIKE', '%' . $searchfields . '%') - ->orWhere('name', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('plugincode', 'LIKE', '%' . $searchfields . '%') - ->orWhere('properties', 'LIKE', '%' . $searchfields . '%') - ->orWhere('moduleguid', 'LIKE', '%' . $searchfields . '%'); + ->orWhere(function ($nested) use ($searchfields) { + $this->ciLikeConditions( + $nested, + ['name', 'description', 'plugincode', 'properties', 'moduleguid'], + $searchfields + ); + }); }); $count = $results->count(); @@ -470,12 +474,13 @@ protected function getAjaxResults() ->select('id', 'name', 'locked', 'disabled') ->where(function ($query) use ($searchfields) { $query->where('id', 'LIKE', '%' . $searchfields . '%') - ->orWhere('name', 'LIKE', '%' . $searchfields . '%') - ->orWhere('description', 'LIKE', '%' . $searchfields . '%') - ->orWhere('modulecode', 'LIKE', '%' . $searchfields . '%') - ->orWhere('properties', 'LIKE', '%' . $searchfields . '%') - ->orWhere('guid', 'LIKE', '%' . $searchfields . '%') - ->orWhere('resourcefile', 'LIKE', '%' . $searchfields . '%'); + ->orWhere(function ($nested) use ($searchfields) { + $this->ciLikeConditions( + $nested, + ['name', 'description', 'modulecode', 'properties', 'guid', 'resourcefile'], + $searchfields + ); + }); }); $count = $results->count(); @@ -522,6 +527,29 @@ protected function addClassForItemList($locked = '', $disabled = '', $deleted = return $class; } + /** + * Force text searches to behave case-insensitively on SQLite instead of depending on connection-level LIKE. + */ + protected function ciLikeConditions(EloquentBuilder|QueryBuilder $query, array $columns, string $search): void + { + $driver = $query->getConnection()->getDriverName(); + $searchPattern = '%' . $search . '%'; + $loweredPattern = '%' . mb_strtolower($search, 'UTF-8') . '%'; + $baseQuery = $query instanceof EloquentBuilder ? $query->getQuery() : $query; + $grammar = $baseQuery->getGrammar(); + + foreach ($columns as $index => $column) { + if (in_array($driver, ['sqlite', 'sqlite3'], true)) { + $method = $index === 0 ? 'whereRaw' : 'orWhereRaw'; + $query->{$method}('LOWER(' . $grammar->wrap($column) . ') LIKE ?', [$loweredPattern]); + continue; + } + + $method = $index === 0 ? 'where' : 'orWhere'; + $query->{$method}($column, 'LIKE', $searchPattern); + } + } + protected function highlightingCoincidence($text, $search) { $escapedSearch = preg_quote(entities(trim($search), $this->managerTheme->getCore()->getConfig('modx_charset')), diff --git a/manager/actions/files.dynamic.php b/manager/actions/files.dynamic.php index b90959cd2b..64996cd1c2 100755 --- a/manager/actions/files.dynamic.php +++ b/manager/actions/files.dynamic.php @@ -66,7 +66,8 @@ $uploadablefiles = array_merge($upload_files, $upload_images, $upload_media); $uploadablefiles = add_dot($uploadablefiles); $upload_maxsize = evo()->getConfig('upload_maxsize'); -$filemanager_path = rtrim(str_replace('\\', '/', realpath(evo()->getConfig('filemanager_path', EVO_BASE_PATH))), '/'); +$filemanager_path = rtrim(str_replace('\\', '/', + realpath(evo()->getConfig('filemanager_path')) ?: realpath(EVO_BASE_PATH)), '/'); $base_path = rtrim(str_replace('\\', '/', realpath(EVO_BASE_PATH)), '/'); // end settings // get the current work directory