Nginx, Opencart проблема с кириллицей в route=product/search
Моя голова уже вся сломалась на раздумьях о том, почему не проходит запрос в product/search на кириллице.
Opencart 2 на nginx + php-fpm.
Вбиваю русское слово в строку поиска (или прямо в адресную строку в /index.php?route=product/search&search=слово). Русское слово кодируется методом URIencode, например "погрузчик" -> "%D0%BF%D0%BE%D0%B3%D1%80%D1%83%D0%B7%D1%87%D0%B8%D0%BA"
Идет запрос /index.php?route=product/search&search=%D0%BF%D0%BE%D0%B3%D1%80%D1%83%D0%B7%D1%87%D0%B8%D0%BA
В этой строке почему то последовательности "%8?" подменяются на "_" (посмотрела в логах), соответственно, запрос превращается в /search/?search=%D0%BF%D0%BE%D0%B3%D1_%D1_%D0%B7%D1_%D0%B8%D0%BA
При раскодировании получается пустая строка, которая отправляется в базу данных, поиск ничего не находит.
Запросы на английском языке - работают. Запросы на русском языке - работают, если закодированное слово не содержит последовательностей "%8?", например, запрос "мини" пройдет.
Статические страницы с кириллицей (которые без route) - работают. На локали на http - все работает.
Подозрения на какие то особенности конфига. Конфиг домена:
server {
charset UTF-8;
listen IP:443 ssl http2;
server_name domen.ru www.domen.ru;
root $root-path;
index index.php index.html index.htm;
ssl_certificate $ssl_certificate-path;
ssl_certificate_key $ssl_certificate_key-path;
location / {
try_files $uri $uri/ @opencart;
location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|css|js)$ {
expires max;
}
}
location ~ \.php$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass 127.0.0.1:9002;
fastcgi_index index.php;
include /etc/nginx/fastcgi_params;
}
location @opencart {
rewrite ^/(.+)$ /index.php?_route_=$1 last;
}
location /vstats/ {
alias $home-path/web/domen.ru/stats/;
include $home-path/conf/web/domen.ru.auth*;
}
location ~* "/\.(htaccess|htpasswd)$" {
deny all;
return 404;
}
if ($http_host = www.domen.ru){
rewrite ^(.*)$ https://domen.ru$1 permanent;
}
#Редирект на https
if ($scheme != "https"){
return 301 https://$host$request_uri;
}
include /etc/nginx/conf.d/phpmyadmin.inc*;
include /etc/nginx/conf.d/phppgadmin.inc*;
include /etc/nginx/conf.d/webmail.inc*;
include $home-path/conf/web/snginx.domen.ru.conf*;
}
Ответы (3 шт):
Пишу итоговое решение.
Не удалось найти, где происходит подмена символов, но проблема явно в SEO_URL, так как если его отключить, все работает. Решили отключить ЧПУ-ссылки именно на странице поиска. Страницы, связанные с поиском, все равно перекрыты в robots.txt и не влияют на сео сайта:
Disallow: /*route=product/search Disallow: /search/
В файле\catalog\controller\startup\seo_pro.php в функции validate():
if (rawurldecode($url) != rawurldecode($seo) && isset($this->request->server['SERVER_PROTOCOL'])) { header($this->request->server['SERVER_PROTOCOL'] . ' 301 Moved Permanently'); $this->response->redirect($seo, 301); } замена на:
if (strripos($url, '/search')){ //со страниц поиска не редиректить на чпу, то есть ничего не делать }
elseif ( rawurldecode($url) != rawurldecode($seo) && isset($this->request->server['SERVER_PROTOCOL'])) { header($this->request->server['SERVER_PROTOCOL'] . ' 301 Moved Permanently'); $this->response->redirect($seo, 301); }
Примечание, сюда $url и $seo доходят еще нормальные и даже правильно расшифрованы, но во время редиректа с ними что-то происходит. Возможно, в WINDOWS-1251 перекодирует (хотя все страницы сайта, все таблицы базы данных, сама база, в настройке nginx установлено utf-8)
Найдена причина бага в seo_url.php файле. При переходе на страницу, схожую с такой: example.com/index.php?route=product/search&search=что_то_на_кириллице Происходит обрезание и/или искажение кириллических символов (например в такой вид: example.com/index.php?route=product/search&search=).
Это из-за работы функции parse_url() - она не поддерживает кириллические значения get-параметров url.
parse_url используется в example.com/catalog/controller/startup/seo_url.php (метод rewrite($link))
Для исправления нужно перед вызовом функции parse_url сделать url_encode для проблемных значений или же заменить parse_url на аналогичную совместимую с utf-8 функцию
На debian 11, nginx, php7.4-fpm была та же проблема.
Системная локаль по умолчанию стояла en_US и в lacales.gen en_US ISO-8859-1
apt remove locales-all
dpkg-reconfigure locales
Выбирать только UTF локали, по умолчанию поставил en_US.UTF8
reboot