Правило mod_rewrite для обеспечения канонического процентного кодирования - PullRequest
3 голосов
/ 25 сентября 2010

У нас есть приложение PHP с динамической схемой URL, которая требует, чтобы символы кодировались в процентах, даже « незарезервированные символы », такие как круглые скобки или апострофы, которые фактически не требуется кодировать.URL-адреса, которые приложение считает закодированным «неправильным» способом, канонизируются, а затем перенаправляются на «правильное» кодирование.

Но Google и другие пользовательские агенты могут канонизировать процентное кодирование / декодирование по-разному, то есть, когда запросит робот Googleстраницу, на которой он будет запрашивать «неправильный» URL, и когда он получит перенаправление на «правильный» URL, робот Googlebot откажется следовать за перенаправлением и откажется проиндексировать страницу.

Да, это ошибка с нашей стороны.Спецификации HTTP требуют, чтобы серверы обрабатывали процентно-не кодированные процентами незарезервированные символы одинаково.Но исправить проблему в коде приложения прямо сейчас непросто, поэтому я надеялся избежать изменения кода с помощью правила перезаписи Apache, которое обеспечило бы правильное кодирование URL-адресов с точки зрения приложения.Это означает, что все апопстры, скобки и т. д. кодируются в процентах, а пробелы кодируются как +, а не %20.

. Вот один из примеров, где я хочу переписать первый и в итогевторая форма:

  • www.splunkbase.com / apps / All / 4.x / Add-On / app: OPSEC + LEA + для + Check + Point + (Linux)
  • www.splunkbase.com / apps / All / 4.x / надстройка / app: OPSEC + LEA + для + Check + Point +% 28Linux% 29

Вот еще один:

  • www.splunkbase.com / apps / All / 4.x / app: Benford's + Law + Fraud + Detection + Add-on
  • www.splunkbase.com / apps / All / 4.x / app: Benford% 27s + Law + Fraud + Detection + Add-on

Вот еще:

  • www.splunkbase.com / apps / All / 4.х / приложение: Benford% 27s% 20Law% 20Fraud% 20Detection% 20Add-на
  • www.splunkbase.com / apps / All / 4.x / app: Benford% 27s + Law + Fraud + Detection + Add-on

Если приложение видит только вторую формуиз этих URL-адресов, то он не будет отправлять никаких перенаправлений, и Google сможет проиндексировать страницу.

Я новичок с правилами перезаписи, и из моего прочтения документации перезаписи модов стало ясно, что mod_rewrite выполняет некоторое автоматическое кодирование / декодирование, которое может помочь или навредить тому, что я хочуделать, хотя и не уверен.

Какой совет по правилам переписывания для обработки вышеуказанных случаев?Я согласен с правилом для каждого специального символа, так как их не так много, но одно правило (если возможно) будет идеальным.

Ответы [ 2 ]

2 голосов
/ 28 сентября 2010

Решение на самом деле может быть довольно простым, хотя оно будет работать только в Apache 2.2 и более поздних версиях из-за использования флага B .Я не уверен, правильно ли он заботится о каждом случае (по общему признанию, я немного скептически отношусь к тому, что это не требует больше работы, чем эта), но я уверен, что это следует из исходного кода.

Имейте в виду, что значение REQUEST_URI не обновляется преобразованиями mod_rewrite, поэтому, если ваше приложение использует это значение для определения запрошенного URL-адреса, сделанные вами изменения в любом случае не будут видны.

Хорошая новость заключается в том, что это можно сделать в .htaccess, поэтому у вас есть возможность оставить основную конфигурацию без изменений, если она работает лучше для вас.

RewriteEngine On

# Make sure this is only done once to avoid escaping the escapes...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
# Check if we have anything to bother escaping (likely unnecessary...)
RewriteCond $0 [^\w]+
# Rewrite the entire URL by escaping the backreference
RewriteRule ^.*$ $0 [B]

Итак, почему есть необходимость?использовать флаг B вместо того, чтобы позволить mod_rewrite экранировать переписанный URL автоматически?Когда mod_rewrite автоматически экранирует URL-адрес, он использует ap_escape_uri (который по некоторым причинам был превращен в макрос для ap_os_escape_path), функцию, которая экранирует ограниченное подмножество символов.Однако флаг B использует внутреннюю функцию модуля под названием escape_uri, которая смоделирована на PHP urlencode функция.

Реализация escape_uri в модуле предполагаетчто буквенно-цифровые символы и символы подчеркивания остаются как есть, пробелы преобразуются в +, а все остальное преобразуется в его экранированный эквивалент.Похоже, это поведение, которое вам нужно, поэтому, вероятно, оно должно работать.

Если нет, у вас есть возможность настроить внешнюю программу RewriteMap, которая может манипулировать вашим входящимURL-адреса в правильном формате.Однако это требует манипулирования конфигурацией Apache, а скрипт-отступник может вызвать проблемы для сервера в целом, поэтому я не считаю его идеальным решением, если его можно избежать.

1 голос
/ 27 сентября 2010

mod_rewrite - не лучший инструмент для такой работы. Потому что с mod_rewrite вы можете заменить только фиксированное количество вхождений за раз. Но это возможно:

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?\ ]*)%20([^?\ ]*)
RewriteRule ^ /%1+%2 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?'\ ]*)'([^?'\ ]*)
RewriteRule ^ /%1\%27%2 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?(\ ]*)\(([^?(\ ]*)
RewriteRule ^ /%1\%28%2 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?)\ ]*)\)([^?)\ ]*)
RewriteRule ^ /%1\%29%2 [R=301,NE]

Это заменит один %20, ', ( или ) за раз и ответит перенаправлением 301. Поэтому, если путь URL-адреса содержит 10 символов, которые необходимо заменить, для этого требуется 10 перенаправлений.

Поскольку это может быть не лучшим решением, можно выполнить все замены, кроме последней внутренней, используя флаг N и только последнюю внешнюю замену с перенаправлением:

RewriteCond %{THE_REQUEST} ^[A-Z]+\ /(([^?%\ ]|%(2[1-9a-fA-F]|[013-9][0-9a-fA-F]))*)%20(([^?%\ ]|%(2[1-9a-fA-F]|[013-9][0-9a-fA-F]))*%20[^?\ ]*)
RewriteRule ^ /%1+%4 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?\ ]*)%20([^?\ ]*)[?\ ]
RewriteRule ^ /%1+%2 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?'\ ]*)'([^?'\ ]*'[^?\ ]*)
RewriteRule ^ /%1\%27%2 [N,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?'\ ]*)'([^?'\ ]*)[?\ ]
RewriteRule ^ /%1\%27%2 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?(\ ]*)\(([^?(\ ]*\([^?\ ]*)
RewriteRule ^ /%1\%28%2 [N,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?(\ ]*)\(([^?(\ ]*)[?\ ]
RewriteRule ^ /%1\%28%2 [R=301,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?)\ ]*)\)([^?)\ ]*\)[^?\ ]*)
RewriteRule ^ /%1\%29%2 [N,NE]
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^?)\ ]*)\)([^?)\ ]*)[?\ ]
RewriteRule ^ /%1\%29%2 [R=301,NE]

Но использование флага N может быть опасным, поскольку оно не увеличивает внутренний счетчик рекурсии и, следовательно, может легко привести к бесконечной рекурсии.

...