[Решено] Кто знает синтаксис mod_rewrite в .htaccess, помогите?

Главные вкладки

Аватар пользователя Айдар Айдар 19 ноября 2011 в 23:30

Люди добрые, помгите!

Пока не знай, выйдет ли чего из этого, но пробую - необходимо правило, чтобы вместо адреса 'node/nid' подставлялся адрес 'my_page/my_doc/?id=nid'

прописываю в .htaccess:

RewriteCond %{REQUEST_URI} ^node/%1
RewriteRule ^(.*)$ index.php?q=$1 [L]

Не выходит. Пробовал кучу других вариантов: либо 500, либо не подставляется.

Комментарии

Аватар пользователя flank flank 20 ноября 2011 в 0:24

Здравствуйте. Я недавно сталкивался с похожей задачей, нужно было перенаправлять с адресов вида /catalog на адреса вида /index.php?page=catalog
Средствами mod rewrite это не решается, т.к. гет-запросы он попросту игнорирует
Я написал небольшой скрипт на пхп, который считывает гет-запрос и редиректит 301-м редиректом на новые адреса.
Вставил его в index.php, в основной файл друпала. Хоть это и хак ядра, но сработало, индексация сайта не пострадала.
Если вас это устраивает, могу и скрипт скинуть. Хотя там всего 10 строк кода))

Аватар пользователя Айдар Айдар 20 ноября 2011 в 0:39

Киньте, если не сложно, плиз!

"flank" wrote:
редиректит 301-м редиректом на новые адреса

Т.е. именно с /catalog на /index.php?page=catalog редиректит, правильно? А, скажем, заголовок ноды в тизере ссылается все еще на /catalog, правильно понимаю?

Аватар пользователя bsyomov bsyomov 20 ноября 2011 в 12:25

Во-первых, mod rewrite никаких запросов не игнорирует, можно в частности работать с условиями по параметрам запроса. И как раз задача

"flank" wrote:
адресов вида /catalog на адреса вида /index.php?page=catalog

Прекрасно им решается.

А для решения этой задачи

"Айдар" wrote:
Пока не знай, выйдет ли чего из этого, но пробую - необходимо правило, чтобы вместо адреса 'node/nid' подставлялся адрес 'my_page/my_doc/?id=nid'

eсть pathauto, и если дополнительно нужны редиректы, то global redirect.

Аватар пользователя flank flank 20 ноября 2011 в 12:31

"bsyomov" wrote:
Прекрасно им решается.

Значит я не знал этого. И решил методом топора) Подскажете, где можно мануалов на эту тему покурить?

Аватар пользователя Айдар Айдар 20 ноября 2011 в 12:39

"bsyomov" wrote:
eсть pathauto

Спасибо за отклик! Но в том то и дело, что Друпал не пропускает знаки '?' и '='. Можно разрешить эти символы, в урле они будут как есть, при переходе на страницу в символом '?' отдает 404, т.к., видимо, друпал обрабатывает '?' как параметр. А как отключить обработку, к примеру, только в одном типе материала, не знаю. Вот и хотел схитрить с помощью .htaccess.

Мануал есть здесь. Мне он не помог, т.к. там как раз наоборот делают от того, что нужно мне.

Аватар пользователя bsyomov bsyomov 20 ноября 2011 в 13:18

Мануалы там, где они и должны быть: http://httpd.apache.org/docs/current/mod/mod_rewrite.html, http://httpd.apache.org/docs/2.0/misc/rewriteguide.html
Ну и если воспользоваться гуглом, то можно накопать очень много примеров и описаний.

"Айдар" wrote:
Можно разрешить эти символы, в урле они будут как есть, при переходе на страницу в символом '?' отдает 404, т.к., видимо, друпал обрабатывает '?' как параметр.

Да, естественно. А вы хотите добиться не такого поведения?
Если вам надо, чтобы придя по старой ссылке, пользователь попал на нужную страницу, тогда действительно можно написать реврайт, только будет дублирование контента и ссылки на сайте будут вести на нормальные адреса, а не на такие, как вы указали.

Как-то так тогда будет выглядеть правило:

RewriteCond %{REQUEST_URI} ^/my_page/my_doc/$
RewriteCond %{QUERY_STRING} ^id=%1$
RewriteRule ^(.*)$ /node/$1

Вставить до реврайта для чистых ссылок.
Естественно почитать доку по mod_rewirete и подредактировать при необходимости, т.к. написано по памяти, и не проверялось.

Аватар пользователя Айдар Айдар 20 ноября 2011 в 13:51

Суть траблы в том, что переношу старый сайт на друпал - 80% путей сайта как раз имеют эти символы, и их необходимо сохранить (именно сохранить, а не редиректнуть).

Вот и думаю, как схитрить!

Т.е. не чтобы пользователь попадал на правильную друпал-стайл страницу, а именно на старый сохраненный путь 'my_doc/?id=1'. Я даже могу импортнуть документы так, чтобы новые ноды в друпале имели тот же nid, что и id старого сайта, но вот как указать старый путь, при этом не редиректом, а как бы подстановкой, я не знаю. А по докам непонятно, делает ли .htaccess именно замену/подстановку адреса, а не реврайт.

Ну и не нашел примера в доках для замены адреса с 'node/nid' на 'my_doc/?id=nid' - только наоборот.

Аватар пользователя bsyomov bsyomov 20 ноября 2011 в 14:13

То что я вам выше написал, собственно и не делает редиректа, а переписывает uri вида my_doc/?id=nid в node/nid для внутреннего использования.
Т.е. пользователь перейдя по my_doc/?id=nid, увидит тоже самое, что и по node/nid. При этом это не редирект, т.е. в адресной строке останется my_doc/?id=nid.

Хотя в вашем случае, не надо сохранять старые пути, правильно как раз редиректить на новые адреса, 301 редиректом (добавить [R=301, L] в строку реврайта). Таким образом не будет ненужного дублирования контента. И это как раз правильный способ, с точки зрения поисковика, таким образом вы говорите - этот контент теперь лежит по другому адресу. И все довольны. И поисковик, и пользователи, переходящие по старым линкам и попадающие туда, куда надо.

Аватар пользователя Айдар Айдар 20 ноября 2011 в 15:12

Да как-то цыкотно 18к посещаемых страниц, и такой риск.
И оптимизатор говорит о том, что тыцы с пиарами будут очень долго передаваться, плюс сапа на этих страницах.

Еще раз Огромное Спасибо! Буду пробовать.

Аватар пользователя Dan Dan 20 ноября 2011 в 15:19

Я ту же задачу решал собственным модулем. Только у меня был 301-й редирект, чтобы поисковики обновились. Это решение хорошо тем, что у меня id != nid, плюс была дополнительная логика при разный значениях в пути.

Аватар пользователя Айдар Айдар 20 ноября 2011 в 18:22

"bsyomov" wrote:
RewriteCond %{REQUEST_URI} ^/my_page/my_doc/$
RewriteCond %{QUERY_STRING} ^id=%1$
RewriteRule ^(.*)$ /node/$1

Блин, не отрабатывает этот код. Я так понимаю, что если url остается неизменным (т.е. ничего не меняется в путях), то в любом случае только условие может быть неправильным, верно?

Пробовал по-разному описывать условия - не хочет и все.

Аватар пользователя bsyomov bsyomov 20 ноября 2011 в 18:33

"Айдар" wrote:

Да как-то цыкотно 18к посещаемых страниц, и такой риск.
И оптимизатор говорит о том, что тыцы с пиарами будут очень долго передаваться, плюс сапа на этих страницах.


Это не эксперимент, это штатное средство решения таких проблем (http 301), а оптимизаторы очень часто несут откровенный бред, делая умное лицо.

По поводу редиректа, подебажте. Найдите где не проходит условие.

RewriteLog "нужный вам путь/rewrite.log"
RewriteLogLevel 3

P.S. Замените ^id=%1$ на $id=([0-9]+)$

Аватар пользователя Айдар Айдар 20 ноября 2011 в 19:01

Прописывая RewriteLog, отдает 500 ошибку. В error_log: "RewriteLog not allowed here"

Прописывал самые разные пути, в т.ч. на папки с правами 777.

Аватар пользователя bsyomov bsyomov 20 ноября 2011 в 19:12

"RewriteLog not allowed here" означает, что это прописывается в vhost или на уровне сервера, а не то, что не записать в какую-то папку.

Аватар пользователя Айдар Айдар 20 ноября 2011 в 19:15

А вообще, нельзя как-то запретить Друпалу обрабатывать '?' как параметр, скажем, только для одного типа материала? Вот реально решение так близко и так далеко! Sad

Про запрет уже понял, что у меня как у пользователя нет прав вроде как вести такие логи.

Аватар пользователя bsyomov bsyomov 20 ноября 2011 в 19:31

"Айдар" wrote:
Про запрет уже понял, что у меня как у пользователя нет прав вроде как вести такие логи.

Это не должно быть проблемой - разработку надо вести не на продакшен сайте, а у себя, в полностью контролируемых условиях.

"Айдар" wrote:
А вообще, нельзя как-то запретить Друпалу обрабатывать '?' как параметр, скажем, только для одного типа материала? Вот реально решение так близко и так далеко! Sad

Это обрабатывает php а не друпал.

Всё же вам уже расписано, как и что делать, только приспособить реврайт под собственные нужды осталось. Smile Вот зачем вы пытаетесь фигню всякую выдумать? Smile Почитайте доку, подправьте под свой случай, пользуйтесь.

Аватар пользователя Айдар Айдар 20 ноября 2011 в 19:37

"bsyomov" wrote:
разработку надо вести не на продакшен сайте

Взял шаред, пока не перевел сайт.
"bsyomov" wrote:
приспособить реврайт под собственные нужды

Вот в этом и проблема - то, что, казалось бы, должно работать - не работает. Я уже несколько раз сверял код с манами, и на шару подставлял другие синтаксические элементы (перепробовал уже более 50 вариантов). Sad

Аватар пользователя Айдар Айдар 20 ноября 2011 в 19:39

"bsyomov" wrote:
Это обрабатывает php

А есть какое-либо определенное место в коде, где это задается, или таких функций много? Мне кажется, если операторов 'if else' определить тип материала, то должно помочь, нет (сам плохо знаю API)?

Аватар пользователя Dan Dan 20 ноября 2011 в 20:39

А в чём проблема сделать через друпал-то?

function hook_menu(){
  $items['my_page/my_doc'] = array(
    'type' => MENU_CALLBACK,
    'access arguments' => array('access content'),
    'page callback' => 'my_module_old_site_page',
  );
}

function my_module_old_site_page(){
  if(isset($_GET['id']) && is_numeric($_GET['id']) && ($node = node_load($_GET['id']))){
    return node_view($node);
  }else{
    return drupal_not_found();
  }
}

Это весь код. Не проверял, конечно же - допилить по фффкусу.

Аватар пользователя Айдар Айдар 20 ноября 2011 в 22:08

Dan, Спасибо за код! Только у меня с ним ничего не изменилось. Как были 2 документа доступны по node/nid, так и есть, а по 'my_page/my_doc/?id=nid' - 404.

Или это только набросок?

Аватар пользователя Айдар Айдар 20 ноября 2011 в 23:07

Мне уже кажется, что что-то где-то нечисто - ну просто не может сайт не принимать никаких изменений (хотя 500 при ошибках все же отдает) в .htaccess. Sad

Аватар пользователя Dan Dan 21 ноября 2011 в 1:54

"Айдар" wrote:
Или это только набросок?

Да, это концепт, а не рабочий код. Прикрепи что ты сделал, скажу где ошибка.
Ещё надо чистить кэш меню при работе с меню.

Аватар пользователя Айдар Айдар 21 ноября 2011 в 10:56

Dan, Спасибо за помощь!

Но может оно того и не стоит, т.к. я в php далеко не силен. Фактически код я изменил только там, где понял, что надо менять: создал модуль (info файл и файл модуля) и прописал в нем твой код:

<?php
function hook_menu(){
  
$items['newst/news'] = array(
    
'type' => MENU_CALLBACK,
    
'access arguments' => array('access content'),
    
'page callback' => 'my_module_old_site_page',
  );
}
 
function 
my_module_old_site_page(){
  if(isset(
$_GET['id']) && is_numeric($_GET['id']) && ($node node_load($_GET['id']))){
    return 
node_view($node);
  }
  else {
    return 
drupal_not_found();
  }
}
?>

А мне точно нужно работать с меню? Еще раз уточню: мне нужно, чтобы, к примеру, на этой странице: http://kazanvoyage.ru/node/121 внутренний адрес выглядел вот так: http://kazanvoyage.ru/newst/news/?ID=121, и чтобы на страницу можно было явно попасть по этому адресу.

Если там много кода писать, то может быть и не стоит оно того?

Аватар пользователя Dan Dan 21 ноября 2011 в 12:12

Во первых, вместо hook_menu() надо писать ИМЯМОДУЛЯ_menu()
Во-вторых, прикрепи файлы модуля, дабы можно было посмотреть где ошибка.

Да, тебе надо именно с меню работать )

Аватар пользователя Айдар Айдар 21 ноября 2011 в 20:15

Dan, огромное человеческое Спасибо (в очередной раз)!

Теперь путь доступен (не редиректит, но теперь он хотя бы отдает реальный id документа по прямому запросу, да еще и со статусом 200ок).

А этого вполне достаточно! Smile