Категории: Хозяйке на заметку

Выбор хостинга для сайта организации

Выбор хостинг-провайдера, которому можно доверить сайт и корпоративную почту — непростая и ответственная задача, которая стоит перед всеми организациями. От качества услуг хостера зависит стабильность многих бизнес-процессов современной компании.

Надоест – уйду?

Если вдруг оказывается, что хостинг не удовлетворяет предъявляемым требованиям, организации, в отличие от частных лиц, редко могут себе позволить раз в несколько месяцев переносить сайт с одного хостинга на другой: это дорого, утомительно и небезопасно.

Читать далее

Замена хотсвопом диска в зеркале gmirror под FreeBSD

Ситуация: есть RAID-массив из двух SATA-дисков в зеркале, созданном с помощью gmirror под FreeBSD.

Необходимо заменить один диск, не останавливая работы сервера.

Капля теории

На тему собственно создания зеркала на GEOM есть много статей.

При создании зеркала gmirror синхронизирует все данные, включая MBR, гласит http://people.freebsd.org/~rse/mirror/ (раздел Summary -> GEOM mirror on whole disk). Если при отказе диска сервер умер, можно загрузиться с оставшегося диска, вне зависимости от того, какой диск вышел из строя. Важно только при загрузке правильно выбрать, с какого диска грузиться.

При работе массива команда

# gmirror list

практически постоянно показывает Flags: DIRTY. Это нормально: флаг выставляется, когда на диск записывается информация, и в этот момент состояние данных на дисках массива не совпадает. Если на диск постоянно ведётся запись, флаг DIRTY постоянно будет выставлен.

Процедура замены

Предположим, в массиве gm0 присутствуют два диска: da0 и da1. Заменить нужно da0.

  1. Определяем, какой диск физически нужно заменить.
  2. Не выключая сервер, вытаскиваем диск.
  3. Сервер несколько секунд ничего не понимает, а потом на полминуты впадает в кому. Нужно немного подождать.
  4. После этого команды
    # geom disk list
    # gmirror list

    помогут обнаружить, что одного диска нет (самое время убедиться в том, что вытащили правильный диск :).

  5. Просим gmirror забыть обо всех дисках, которые сейчас неактивны в зеркале:
    # gmirror forget gm0
  6. gmirror обнаруживает, что da0 нет и забывает про него.
  7. Вставляем новый диск (желательно идентичный тому, с которым в паре он будет работать, вплоть до модели).
  8. Сканируем шину, чтобы система обнаружила новый подключённый диск:
    # : что имеем сейчас?
    # camcontrol devlist 
    
    # : сканируем
    # camcontrol rescan all
    
    # : что получилось?
    # camcontrol devlist
  9. Добавляем в массив новый da0:
    # gmirror insert gm0 da0
  10. gmirror обнаружит новый диск и начнёт синхронизацию данных. Смотрим состав массива:
    # gmirror list
  11. Не пугаемся, если нам кажется, что синхронизация идёт не в том направлении 🙂 Если заменялся da0, то теперь он в списке ПОСЛЕ da1, а не ДО, как был раньше.
  12. Испытываем счастье.

Почему mod_rewrite это вуду, и в каком на самом деле порядке выполняются правила RewriteRule

Сегодня мне пришлось составлять довольно хитрый редирект: если пользователь запросил /news/some-section/, то его нужно было перенаправить на просто /section/, но потом всё равно сделать внутренний редирект на /news/some-section/, так как сам движок новостей лежит именно там.

Я написал простое правило, обновил страничку… и получил от mod_rewrite по полной программе, потому что он ушёл в бесконечный цикл и не собирался из него возвращаться. Я открыл документацию и начал разбираться. Потом включил RewriteLog. Сначала я был озадачен. Потом стал откровенно злиться. А к тому моменту, когда задача была решена, я успел пережить такое количество разных чувств, что кроме равнодушного вздоха ничем больше не смог отметить достигнутый результат.

Оказывается, mod_rewrite называют вуду не потому, что он волшебный. А потому что для того, чтобы осознать, как он работает, нужно три раза прочитать по нему документацию. Вслух. С выражением! Потом найти все параграфы, начинающиеся со слова «Note» и пересказать их своими словами. Потом нужно найти все параграфы, в которых больше одного предложения и тоже пересказать их своими словами. Тоже вслух. И с выражением тоже.

Но и это ещё не всё. После этого нужно пойти по ссылке «detailed mod_rewrite documentation» и почитать там. А потом отправиться впитывать полезный опыт в гугл.

Так много слов выше написано оттого, что сам я только что всё это проделал и мне нужно высказаться. Вы, наверное, думаете — ну и где же обещанное «как на самом деле»? Подождите, сейчас расскажу.

По работе мне приходится составлять довольно простые правила, зато их довольно много. Приходится следить, чтобы они не пересекались друг с другом. Директив использую немного — RewriteCond, RewriteRule и флаги [L], [R], изредка [NC] и [QSA]. Без усложний с map’ами, chain’ами и subreq’ами.

Опыт программирования подсказывал мне (и некоторые другие программисты были со мной согласны), что если я сказал [R], то в этом месте должен начаться редирект. А если указано [L], то разбор правил должен прекратиться (совсем-совсем прекратиться). Ну и когда все правила пройдены, разбор прекращается, отдаётся скрипт, на который смотрит получившийся адрес.

Ага. Щаз.

Оказывается, всё работает несколько иначе.

[R] на самом деле не делает редирект. Он просто делает текущий адрес абсолютным (дописывает к нему http://хост/) и где-то себе запоминает, что потом нужно будет сделать внешний редирект. После этого разбор правил продолжается до конца .htaccess, и вот уже тут происходит перенаправление.

[L] на самом деле не останавливает полностью разбор правил.
Если разбор происходит в .htaccess (как это обычно бывает), то совершается переход в конец .htaccess, и вот тут уже… происходит перенаправление? Ну да, только в его результате мы с большой вероятностью опять попадаем на тот же .htaccess, и начинается проход по всем правилам заново (даже при внутреннем редиректе!). И этот цикл будет продолжаться до тех пор, пока не настанет момент, когда ни одно правило не сработает (или пока мы редиректом не выйдем из директории, в которой лежит наш .htaccess). Вот тогда уже сервер отдаст страничку.

Единственно предсказуемое поведение дают [R,L] вместе взятые. В этом случае отмечается, что должен произойти редирект, пропускаются все следующие правила и юзеру отдаётся перенаправление на указанную страницу.

Какой из этого вывод? Не надо везде подряд ставить [L]. Если, конечно, хотите понимать, в каком порядке обрабатываются правила. Если [L] нигде не указан, то проход осуществляется строго подряд. Правда, когда правила закончатся, и окажется, что какое-то из них поменяло ссылку, всё равно будет запущен проход по всем правилам ещё раз. Но это уже гораздо проще контролировать.

Например. Обычно ссылка после изменения не подходит под то же или под какое-либо другое правило. То есть, если вы перенаправляете /news в index.php/news:

RewriteRule ^news/$ index.php/news

то второй раз это правило уже не сработает.

Однако в моём случае нужно было запрос пользователя /news/section-name/ перенаправлять в /section-name/, а потом делать внутренний редирект обратно с /section-name/ на /news/section-name/, где находился обработчик новостей. То есть:

RewriteRule ^news/section-name/$ section-name/ [R=301,L]
RewriteRule ^section-name/ news/section-name/

Первый редирект внешний, второй внутренний. Если бы всё происходило в один проход, всё было бы нормально. Но так как проходы длятся пока срабатывает хотя бы одно правило, происходило следующее. Пользователь набрал /news/section-name/. Его внешним редиректом перенаправило на /section-name/. Потом сработало второе правило и произошёл внутренний редирект на news/section-name/. Потом mod_rewrite обнаружил, что ссылка изменилась, и инициировал повторную обработку запроса. Опять сработало первое правило, пользователь получил внешний редирект. Круг замкнулся.

Для того, чтобы разрешить внешний редирект только в том случае, если запрос /news/section-name/ прислан пользователем, а не сгенерирован RewriteRule, приходится проверять %{THE_REQUEST}:

RewriteCond %{THE_REQUEST} ^(GET|HEAD)\ /news/section-name/
RewriteRule ^news/(.*) /$1 [R=301,L]

Работает: после внешнего редиректа пользователь запрашивает /section-name/, этот запрос попадает в THE_REQUEST и для первого правила не выполняется RewriteCond.

За информацию спасибо следующим ссылкам:

* http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html
* http://www.askapache.com/htaccess/mod_rewrite-basic-examples.html
* http://httpd.apache.org/docs/2.2/rewrite/rewrite_tech.html
* http://www.google.com

Там написано, почему при обработке правил в .htaccess происходят повторные запросы с повторным проходом по всем правилам, и почему при указании директив редиректа в <VirtualHost> или в глобальном конфиге Apache не в разделе <Directory> проход происходит только один раз.

Передача ссылки во flash-баннер из html

Бывает так: есть flash-баннер, который должен ссылаться на какую-то странцу сайта. А адрес этой страницы неизвестен и станет известен только тогда, когда баннер собственно будет внедряться в код сайта. Или нужно иметь возможность менять ссылку во flash-баннере время от времени.

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

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

Как?

А вот как!

Подготовка flash-баннера

В сам баннер в первый кадр нужно добавить код для приёма параметра. А кнопку, которая осуществляет переход, изменить соответствующим образом.

Первый кадр flash-баннера

В него нужно добавить такой код:

// _level0.bannerLink is passed via FlashVars
if (_level0.bannerLink == undefined) {
	// Default link will be used if no other link was specified via params
	var bannerLink:String = "http://www.sprinthost.ru";
} else {
	var bannerLink:String = _level0.bannerLink;
}

bannerLink — это параметр, который будет передаваться в ролик. В коде также предусмотрена ссылка по умолчанию.

Код кнопки

Сама кнопка для клика получает следующий код:

on(release) {
    getURL(bannerLink);
}

На этом с самим роликом всё. Осталось ещё добавить собственно передачу параметра в html-код.

Добавление параметров баннера в код html

В тэг <object>, который используется для внедрения баннера, нужно будет добавить код, который выделен жирным:

<object
  type="application/x-shockwave-flash"
  data="banner.swf"
  width="170" height="250">
    <param name="movie" value="banner.swf">
    <param name="wmode" value="transparent">
    <param name="allowScriptAccess" value="sameDomain" />
    <param name="FlashVars" value="bannerLink=http://www.google.com">
</object>

В данном примере ролику передаётся параметр, согласно которому он будет ссылаться на www.google.com.

Всё!

Поздравляю с достигнутым счастьем.

Следующие записи »