Кириллические символы в правилах перезаписи вызывают ошибки 404 Not Found
У меня есть правило перезаписи, которое включает URI страницы:
(<page-uri>)/someaction/(\d+)
Если URI страницы содержит кириллические символы, например доска-объявлений
, правило сохраняется как:
(%d0%b4%d0%be%d1%81%d0%ba%d0%b0-%d0%be%d0%b1%d1%8a%d1%8f%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9)/someaction/(\d+)
Если перейти на страницу, содержащую ссылку на URL, соответствующий правилу, и кликнуть по этой ссылке, браузер загрузит целевую страницу без проблем, и WordPress сможет сопоставить правило с запрошенным URL.
Однако в Safari (Mac), если скопировать URL через Правой Кнопкой > Копировать Ссылку и затем попытаться загрузить целевую страницу, вставив скопированный URL в новую вкладку, вы получите ошибку 404 Not Found.
При копировании URL в Safari, URL сохраняется с процентным кодированием, где символы, представляющие октеты для кириллических символов, записываются в верхнем регистре:
%D0%B4%D0%BE%D1%81%D0%BA%D0%B0-%D0%BE%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9/someaction/1
Мне не удалось воспроизвести эту проблему в Chrome или Firefox (оба на Mac), потому что они сохраняют URL, используя символы в нижнем регистре для представления октетов.
Этот URL с процентным кодированием передается в WordPress через переменную $_SERVER['REQUEST_URI']
. Проблема в том, что код, отвечающий за сопоставление запрошенного URI с правилами перезаписи, выполняет сравнение с учетом регистра (см. метод parse_request
в /wp-includes/class-wp.php
), из-за чего WordPress не может распознать мое правило, несмотря на то что
%D0%B4%D0%BE%D1%81%D0%BA%D0%B0-%D0%BE%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9
и
%d0%b4%d0%be%d1%81%d0%ba%d0%b0-%d0%be%d0%b1%d1%8a%d1%8f%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9
представляют одну и ту же последовательность символов.
- Кто-нибудь знает, как предотвратить ошибки 404 Not Found, когда браузеры отправляют запрос с октетами в разном регистре?
- Должен ли WordPress поддерживать это? Или мне стоит попытаться исключить URI страниц из моих правил перезаписи, чтобы избежать проблемы?

В итоге я последовал совету @Коли Коробочкина и добавил правила перезаписи в верхнем и нижнем регистрах, включающие экранированные октеты.
$regular_page_uri = get_page_uri( $page->ID );
$uppercase_page_uri = preg_replace_callback(
'/%[0-9a-zA-Z]{2}/',
create_function( '$x', 'return strtoupper( $x[0] );' ),
$regular_page_uri
);
Плагин Percent Encode Capital Letter использует аналогичный подход для преобразования октетов в каждом URL в их версию в верхнем регистре. Однако плагин устарел и может не выполнять преобразование во всех необходимых местах. Кроме того, я считаю, что большинство пользователей плагина, над которым я работаю, не имеют URL с закодированными октетами, поэтому выполнение preg_replace_callback
для всех URL — это излишняя нагрузка.
Использование символов в верхнем регистре для представления октетов является рекомендованным способом процентного кодирования (см. RFC3986, раздел 2.1). Поэтому лучшее решение — заставить WordPress обновить их функцию utf8_uri_encode
, чтобы экранировать октеты с их использованием. Большинство протестированных мной браузеров сохраняют исходный регистр, в то время как другие, такие как Safari, преобразуют его в верхний регистр, если у них есть возможность.
