View source
<?php
namespace Drupal\search404\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\search\Entity\SearchPage;
use Drupal\Component\Utility\Html;
use Drupal\search\Form\SearchPageForm;
use Drupal\Core\Messenger\MessengerInterface;
class Search404Controller extends ControllerBase {
protected $logger;
protected $messenger;
public function __construct(LoggerChannelFactoryInterface $logger_factory, MessengerInterface $messenger) {
$this->logger = $logger_factory
->get('search404');
$this->messenger = $messenger;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('logger.factory'), $container
->get('messenger'));
}
public function getTitle() {
$search_404_page_title = \Drupal::config('search404.settings')
->get('search404_page_title');
$title = !empty($search_404_page_title) ? $search_404_page_title : 'Page not found ';
return $title;
}
public function search404Page(Request $request) {
$keys = $this
->search404GetKeys();
$paths_to_ignore = \Drupal::config('search404.settings')
->get('search404_ignore_paths');
if (!empty($paths_to_ignore)) {
$path_array = preg_split('/\\R/', $paths_to_ignore);
if (\Drupal::config('search404.settings')
->get('search404_use_or')) {
$keywords = str_replace(' OR ', '/', $keys);
}
else {
$keywords = str_replace(' ', '/', $keys);
}
$keywords = strtolower($keywords);
$ignore_paths = [];
foreach ($path_array as $key => $path) {
$path = preg_replace('[ |-|_]', '/', $path);
$path = strtolower($path);
$ignore_paths[$key] = trim($path, '/');
}
$requested_path = $request
->getPathInfo();
$is_matched = $is_wildcard = FALSE;
foreach ($path_array as $key => $ignored_path) {
$pattern = '/^\\/?([a-z0-9\\-\\/]*[a-z0-9\\-])+(\\/\\*)?/i';
$find_ignored_path = preg_match($pattern, $ignored_path, $matches);
if ($find_ignored_path === 1) {
$cleaned_ignored_path = '/' . $matches[1];
if ($cleaned_ignored_path === $requested_path) {
$is_matched = TRUE;
}
if (array_key_exists(2, $matches) && substr($matches[2], -1) === '*' && strpos($requested_path, $cleaned_ignored_path) === 0) {
$is_wildcard = TRUE;
}
}
}
if ($is_matched || $is_wildcard) {
$build['#title'] = 'Page not found';
$build['#markup'] = 'The requested page could not be found.';
return $build;
}
}
if (\Drupal::moduleHandler()
->moduleExists('search') && (\Drupal::currentUser()
->hasPermission('search content') || \Drupal::currentUser()
->hasPermission('search by page'))) {
$search_page_repository = \Drupal::service('search.search_page_repository');
$default_search_page = $search_page_repository
->getDefaultSearchPage();
$entity = SearchPage::load($default_search_page);
$plugin = $entity
->getPlugin();
$build = [];
$results = [];
$plugin
->setSearch($keys, $request->query
->all(), $request->attributes
->all());
if ($keys && !\Drupal::config('search404.settings')
->get('search404_skip_auto_search')) {
if (\Drupal::moduleHandler()
->moduleExists('search_by_page') && \Drupal::config('search404.settings')
->get('search404_do_search_by_page')) {
$this
->search404CustomErrorMessage($keys);
return $this
->search404Goto('search_pages/' . $keys);
}
else {
if ($plugin
->isSearchExecutable()) {
if ($this
->config('search.settings')
->get('logging')) {
$this->logger
->notice('Searched %type for %keys.', [
'%keys' => $keys,
'%type' => $entity
->label(),
]);
}
$results = $plugin
->buildResults();
}
if (isset($results)) {
$patterns = \Drupal::config('search404.settings')
->get('search404_first_on_paths');
$path_matches = TRUE;
if (!empty($patterns)) {
$path = str_replace(' ', '/', $keys);
$path_matches = \Drupal::service('path.matcher')
->matchPath($path, $patterns);
}
if (is_array($results) && (count($results) == 1 && \Drupal::config('search404.settings')
->get('search404_jump') || count($results) >= 1 && \Drupal::config('search404.settings')
->get('search404_first') && $path_matches)) {
$this
->search404CustomErrorMessage($keys);
if (isset($results[0]['#result']['link'])) {
$result_path = $results[0]['#result']['link'];
}
return $this
->search404Goto($result_path);
}
else {
$this
->search404CustomErrorMessage($keys);
if (!count($results) && \Drupal::config('search404.settings')
->get('search404_page_redirect')) {
$redirect_path = \Drupal::config('search404.settings')
->get('search404_page_redirect');
return $this
->search404Goto($redirect_path);
}
}
}
}
}
else {
$this
->search404CustomErrorMessage($keys);
}
$build['search_form'] = $this
->formBuilder()
->getForm(SearchPageForm::class, $entity);
$search_404_page_text = \Drupal::config('search404.settings')
->get('search404_page_text');
if (!empty($search_404_page_text)) {
$build['content']['#markup'] = '<div id="search404-page-text">' . $search_404_page_text . '</div>';
$build['content']['#weight'] = -100;
}
$no_results = '';
if (!\Drupal::config('search404.settings')
->get('search404_skip_auto_search')) {
$no_results = t('<ul>
<li>Check if your spelling is correct.</li>
<li>Remove quotes around phrases to search for each word individually. <em>bike shed</em> will often show more results than <em>"bike shed"</em>.</li>
<li>Consider loosening your query with <em>OR</em>. <em>bike OR shed</em> will often show more results than <em>bike shed</em>.</li>
</ul>');
}
$build['search_results'] = [
'#theme' => [
'item_list__search_results__' . $plugin
->getPluginId(),
'item_list__search_results',
],
'#items' => $results,
'#empty' => [
'#markup' => '<h3>' . $this
->t('Your search yielded no results.') . '</h3>' . $no_results,
],
'#list_type' => 'ol',
'#attributes' => [
'class' => [
'search-results',
$plugin
->getPluginId() . '-results',
],
],
'#cache' => [
'tags' => $entity
->getCacheTags(),
],
];
$build['pager_pager'] = [
'#type' => 'pager',
];
$build['#attached']['library'][] = 'search/drupal.search.results';
}
if (\Drupal::config('search404.settings')
->get('search404_do_custom_search') && !\Drupal::config('search404.settings')
->get('search404_skip_auto_search')) {
$custom_search_path = \Drupal::config('search404.settings')
->get('search404_custom_search_path');
$custom_search_path_no_query = preg_replace('/\\?.*/', '', $custom_search_path);
$current_path = \Drupal::service('path.current')
->getPath();
$current_path = preg_replace('/[!@#$^&*();\'"+_,]/', '', $current_path);
$search_keys = '';
if (\Drupal::config('search404.settings')
->get('search404_use_or')) {
$search_details = $this
->search404CustomRedirection(' OR ', $current_path, $keys);
}
else {
$search_details = $this
->search404CustomRedirection(' ', $current_path, $keys);
}
$current_path = $search_details['path'];
$search_keys = $search_details['keys'];
if ($current_path == "/" . $keys || $current_path == "/" . $search_keys) {
$this
->search404CustomErrorMessage($keys);
if ($search_keys != '') {
$custom_search_path = str_replace('@keys', $search_keys, $custom_search_path);
}
return $this
->search404Goto("/" . $custom_search_path);
}
}
if (empty($build)) {
$build = [
'#markup' => 'The page you requested does not exist.',
];
}
return $build;
}
public function search404Goto($path = '') {
$response = new RedirectResponse($path);
if (\Drupal::config('search404.settings')
->get('search404_redirect_301')) {
$response
->setStatusCode(301);
}
return $response
->send();
}
public function search404SearchEngineQuery() {
$engines = [
'altavista' => 'q',
'aol' => 'query',
'google' => 'q',
'bing' => 'q',
'lycos' => 'query',
'yahoo' => 'p',
];
$parsed_url = !empty($_SERVER['HTTP_REFERER']) ? parse_url($_SERVER['HTTP_REFERER']) : FALSE;
$remote_host = !empty($parsed_url['host']) ? $parsed_url['host'] : '';
$query_string = !empty($parsed_url['query']) ? $parsed_url['query'] : '';
parse_str($query_string, $query);
if (!$parsed_url === FALSE && !empty($remote_host) && !empty($query_string) && count($query)) {
foreach ($engines as $host => $key) {
if (strpos($remote_host, $host) !== FALSE && array_key_exists($key, $query)) {
return trim($query[$key]);
}
}
}
return '';
}
public function search404GetKeys() {
$keys = [];
if (\Drupal::config('search404.settings')
->get('search404_use_search_engine')) {
$keys = $this
->search404SearchEngineQuery();
}
if (empty($keys)) {
$path = \Drupal::service('path.current')
->getPath();
$path = urldecode($path);
$path = preg_replace('/[_+-.,!@#$^&*();\'"?=]|[|]|[{}]|[<>]/', '/', $path);
$paths = explode('/', $path);
if (\Drupal::config('search404.settings')
->get('search404_do_custom_search')) {
$custom_search_path = \Drupal::config('search404.settings')
->get('search404_custom_search_path');
$custom_search = explode('/', $custom_search_path);
$search_path = array_diff($custom_search, [
"@keys",
]);
$keywords = array_diff($paths, $search_path);
$keys = array_filter($keywords);
}
else {
$keys = array_filter($paths);
}
$keys = preg_replace('/-/', ' ', $keys);
foreach ($keys as $key => $value) {
$keys_with_space_hypen[$key] = explode(' ', $value);
$keys_with_space_hypen[$key] = array_filter($keys_with_space_hypen[$key]);
}
if (!empty($keys)) {
$keys = call_user_func_array('array_merge', $keys_with_space_hypen);
}
}
$extensions = explode(' ', \Drupal::config('search404.settings')
->get('search404_ignore_query'));
$extensions = trim(implode('|', $extensions));
if (!empty($extensions)) {
foreach ($keys as $key) {
if (preg_match("/\\.({$extensions})\$/i", $key)) {
return FALSE;
}
}
}
$regex_filter = \Drupal::config('search404.settings')
->get('search404_regex');
if (!empty($regex_filter)) {
$filter_data = explode('[', $regex_filter);
for ($i = 0; $i < count($filter_data); $i++) {
if (!empty($filter_data[$i])) {
$filter_query = explode(']', $filter_data[$i]);
$regex_pattern[0] = '/' . $filter_query[0] . '/ix';
$filter_patterns[] = trim($regex_pattern[0]);
}
}
$keys = preg_replace($filter_patterns, '', $keys);
$keys = array_filter($keys);
}
$extensions = explode(' ', \Drupal::config('search404.settings')
->get('search404_ignore_extensions'));
if (!empty($extensions)) {
$keys = array_diff($keys, $extensions);
}
$keys = array_udiff($keys, explode(' ', \Drupal::config('search404.settings')
->get('search404_ignore')), 'strcasecmp');
foreach ($keys as $a => $b) {
$keys[$a] = Html::escape($b);
}
if (\Drupal::config('search404.settings')
->get('search404_use_or')) {
$keys = trim(implode(' OR ', $keys));
if (\Drupal::config('search404.settings')
->get('search404_do_custom_search')) {
$custom_search_path = \Drupal::config('search404.settings')
->get('search404_custom_search_path');
$custom_search = explode('/', $custom_search_path);
$custom_path = array_diff($custom_search, [
"@keys",
]);
$keys = str_replace($custom_path[0], '', $keys);
$keys = trim(rtrim($keys, ' OR '));
}
}
else {
$keys = trim(implode(' ', $keys));
if (\Drupal::config('search404.settings')
->get('search404_do_custom_search')) {
$custom_search_path = \Drupal::config('search404.settings')
->get('search404_custom_search_path');
$custom_search = explode('/', $custom_search_path);
$custom_path = array_diff($custom_search, [
"@keys",
]);
$keys = trim(str_replace($custom_path[0], '', $keys));
}
}
return $keys;
}
public function search404CustomRedirection($search_type, $path, $keys) {
$search['keys'] = $keys;
$search['path'] = $path;
if (preg_match('/-|%20/', $search['path']) || stripos($search['path'], '/') !== FALSE) {
$search['keys'] = str_replace($search_type, '-', $search['keys']);
if (preg_match('/%20/', $search['path'])) {
$search['path'] = str_replace('%20', '-', $search['path']);
}
if (stripos($search['path'], '/') !== FALSE) {
$search['keys'] = str_replace($search_type, '-', $search['keys']);
$search['path'] = str_replace('/', '-', $search['path']);
$search['path'] = substr_replace($search['path'], '/', 0, 1);
$search['path'] = rtrim($search['path'], "-");
}
}
return $search;
}
public function search404CustomErrorMessage($keys) {
$error_message = '';
$disable_error = \Drupal::config('search404.settings')
->get('search404_disable_error_message');
if ($disable_error) {
return;
}
if ($custom_error_message = \Drupal::config('search404.settings')
->get('search404_custom_error_message')) {
if (empty($keys)) {
$error_message = str_replace('@keys', 'Invalid keys used', $custom_error_message);
}
else {
$error_message = str_replace('@keys', $keys, $custom_error_message);
}
}
else {
if (empty($keys)) {
$error_message = $this
->t('The page you requested does not exist. Invalid keywords used.');
}
else {
$error_message = $this
->t('The page you requested does not exist. For your convenience, a search was performed using the query %keys.', [
'%keys' => Html::escape($keys),
]);
}
}
if (!empty($error_message)) {
$this->messenger
->addError($error_message);
}
}
}