Boot0: error, как избавиться от ошибки при загрузке

boot0-error

После успешной установки хакинтоша может возникнуть ошибка при загрузке с жесткого диска, вот такая:

Loading Operating System …

boot0: GPT
boot0: test
boot0: test
boot0: GPT
boot0: test
boot0: test
boot0: error

В чем заключается проблема:
Т.к. объем жестких дисков с каждым годом увеличивается, производители вынуждены менять стандартный размер блока диска с 512 байт до 4096 байт. Эти жесткие диски известны как «Advanced Format» или 4K. Сначала размер увеличивали на дисках больше 1 ТБ, однако в скором времени изменения затронут все выпускаемые диски. Из-за этого загрузчик Chimera не может загрузиться как положено.

Прим.: Chimera не грузится, а вот разработчики Clover-загрузчика уже давно исправили эту проблему и загрузка происходит автоматически, без изменений.

Решение №1: Использовать флешку с UniBeast

Решение очень простое, но потребует наличие флешки с установщиком Mac OS.

Прим.: я советую всегда хранить флешку с установщиком Mac OS, в случае, если потребуется распаковать бэкап или выполнить доп. настройку, например, при апгрейде оборудования

Как исправить:
1. Загрузиться в установку Mac OS с флешки с UniBeast
2. Не запуская установку, запустить из меню сверху Дисковую Утилиту (Disk Utility), в ней размонтировать жесткий диск, на который установлена Mac OS X.
3. Запустить Терминал и выполнить следующую комманду:

dd if=/usr/standalone/i386/boot1h of=/dev/disk0s2

4. Теперь можно выйти из терминала и перезагрузить компьютер

ВАЖНОЕ ЗАМЕЧАНИЕ: Пример кода выше работает в том случае, если ваш жесткий диск подключен к SATA порту 0. Если у вас используется другой порт, то вы можете узнать его из Дисковой Утилиты.

Решение №2: Использовать SATA > USB Адаптер

Это решение сработает, если у вас есть под рукой другой работающий Mac.

Как починить:
1. Установить жесткий диск в запасной Mac, установить систему на этот жесткий диск.
2. После установки, выключить запасной Mac, вытащить жесткий, и подключить его с помощью USB-адаптера к новому Mac
3. Загрузить новый Mac
4. Запустить MultiBeast, произвести установку загрузчика
5. Теперь можно установить жесткий диск как обычно, без адаптеров

sata-usb-adapterПриобрести переходник-адаптер SATA-USB можно в большинстве компьютерных магазинов или заказать на Aliexpress или подобных сайтах.

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

Общая инструкция по установке OS X Yosemite на Intel-совместимые компьютеры

Данный пост является моим переводом гайда с сайта tonymacx86.com

Данное руководство поможет новичкам пошагово установить свежую версию OS X Yosemite, Все необходимые программы и утилиты для установки можно сказать с сайта tonymacx86.com.

os-x-yosemite-design-large

UniBeast — это утилита, которая поможет создать загрузочный диск с Mac OS для установки. Для создания вам потребуется уже существующий ПК с Mac OS, либо виртуальная VmWare с предустановленной Mac OS. Виртуальную машину с Mac OS можно найти на rutracker.org, там же и инструкции по установке.

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

Оглавление

  1. Шаг №1: Скачайте OS X Yosemite
  2. Шаг №2: Создайте загрузочный USB с UniBeast
  3. Шаг №3: Настройки BIOS
  4. Шаг №4: Установка Yosemite
  5. Шаг №5: Настройка с MultiBeast
  6. Описание проблем и их решений

Перед тем как начать

  1. Зарегистрируйтесь на сайте tonymacx86
  2. Скачайте с tonymacx86 последние версии MultiBeast и UniBeast
  3. Понадобится флешка минимум на 8GB
  4. На всякий случай, сделайте резервную копию данных на компьютере, на который собираетесь устанавливать Mac OS

[wpanchor id=»step-1″]

Шаг №1: Скачайте OS X Yosemite

OS X Yosemite бесплатна для скачивания для всех, кто приобретал Snow Leopard, Lion, Mountain Lion или имеет Mac с предустановленным Mavericks. Скачайте Yosemite с Mac App Store используя свою учетную запись Apple ID. После скачивания приложение появится в папке Applications (Программы) под названием Install OS X Yosemite (Установка OS X Yosemite).

[wpanchor id=»step-2″]

Шаг №2: Создайте загрузочный USB с UniBeast

1) Вставьте USB флешку
2) Откройте программу Disk Utility (Дисковая утилита)
3) Выделите USB флешку слева
4) Откройте вкладку Partition (Разделы)
5) Выберите 1 Раздел, так, как на скриншоте

yosemite-install-1

yosemite-install-2

6) Далее нажмите Options… (Параметры)
7) И выберите Master Boot Record (Главная загрузочная запись)

yosemite-install-3
8) В поле Name (Имя): введите USB (Позднее можно будет переименовать)
9) В поле Format (Формат): Выберите Mac OS Extended (Journaled — журнальный)
10) Нажмите Apply (Применить) и подтвердите действие

yosemite-install-4

11) Скачайте и запустите UniBeast
12) Continue, Continue, Continue, Agree: тут, я думаю, ясно :)

yosemite-install-5
13) В качестве Destination, выбираем нашу флешку USB и жмем Continue

yosemite-install-6
14) На следующем экране выберите Yosemite
15) Жмите Continue

yosemite-install-7
16) Если вы используете старый ПК 5-6 серии с AWARD BIOS, выберите опцию Legacy USB Support
17) Если у вас ноутбук, выберите Laptop Support
18) Жмите Continue

yosemite-install-819) Вводим пароль и жмем Install
yosemite-install-9

UniBeast создаст загрузочную флешку. Этот процесс займет длительное время (возможно до 10-15 мин), наберитесь терпения, не закрывайте окно установки и не вытаскивайте флешку!

20) После установки, перетащите MultiBeast на флешку USB, он понадобится позднее.

[wpanchor id=»step-3″]

Шаг №3: Настройки BIOS

Если вы устанавливаете Mac OS на одну из рекомендуемых нами конфигураций с AMI UEFI BIOS, то все достаточно просто. Если нет, то убедитесь в том, что у вас установлены значения по-умолчанию в BIOS (Optimized Defaults) и в том, что жесткий диск работает в AHCI режиме.

Ниже приводятся стандартные настройки BIOS для Gigabyte AMI UEFI BIOS, Gigabyte AWARD BIOS, ASUS AMI UEFI BIOS, и MSI AMI UEFI BIOS.

  1. Зайдите в BIOS/UEFI
  2. Установите все значения по-умолчанию (Optimized Defaults)
  3. Если ваш процессор поддерживает VT-d, выключите эту опцию
  4. Если в вашей системе есть CFG-Lock, выключите эту опцию
  5. Если в вашей системе есть Secure Boot Mode, выключите эту опцию
  6. Установите OS Type в значение Other OS
  7. Сохраните значения

[wpanchor id=»step-4″]

Шаг №4: Установка Yosemite

Вы готовы к установке! Теперь необходимо загрузиться с USB и начать установку.

1) Выключите компьютер
2) Во время включения нажимайте клавишу для выбора загрузочного диска (обычно это клавишка F12 или F8, зависит от производителя)
3) В окошке дисков выберите USB
4) Должен произойти запуск загрузчика Chimera. Выберите USB и нажмите Enter

yosemite-install-10

Возможно вы столкнетесь с проблемами до загрузки установщика Mac OS. Выяснить в чем проблема помогут специальные загрузочные опции, которые можно вводить на экране Chimera, до того как вы выберите USB, напечатайте ключ, а затем нажмите Enter.

yosemite-install-11

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

  • GraphicsEnabler=Yes
  • PCIRootUID=1
  • maxmem=4096
  • maxmem=8192
  • npci=0x2000

Системы на X58 и X79 всегда требуют ключа npci=0x2000.

5) Наконец, когда вы дойдете до установщика, выберите язык:

yosemite-install-12

6) Для свежей установки вы должны стереть и отформатировать жесткий диск:

  • В верхнем меню выберите Utilities (Утилиты), и откройте Disk Utility (Дисковая утилита)
  • Выберите ваш жесткий диск в колонке слева.
  • Кликните по вкладке Partition (Раздел диска)
  • Выберите в выпадающем списке 1 Partition (Раздел: 1)
  • Нажмите Options… (Параметры)
  • Выберите схему GUID Partition Method
  • В поле Name (Имя): введите Yosemite (Можно будет переименовать позднее)
  • В поле Format (Формат): Выберите Mac OS Extended (Journaled — журнальный)
  • Нажмите Apply (Применить) и подтвердите действие
  • Закройте окно Disk Utility

yosemite-install-13
7) Когда установщик спросит, на какой жесткий устанавливать систему, выберите Yosemite.
8) После завершения установки перезагрузите компьютер.

[wpanchor id=»step-5″]

Шаг №5: Настройка с MultiBeast

MultiBeast — это установщик, содержащий в себе набор инструментов и драйверов для оборудования: Аудио, Видео, Сетевые карты, загрузчик и прочее.

Установка прошла успешно, но жесткий диск с Mac OS еще не загрузочный, на него нужно установить загрузчик Chimera, с помощью MutiBeast, а также установить необходимые драйвера для полноценной работы оборудования.

Необходимо загрузиться с помощью загрузчика флешки, но на этот раз выбрать не установщик USB, а уже наш жесткий диск с установленной Mac OS.

1) Перезагрузите компьютер
2) Во время загрузки нажимайте на клавишу для выбора загрузочного диска
3) Выберите USB
4) На экране Chimera выберите диск Yosemite
5) Пройдите первоначальную настройку Yosemite

 

yosemite-install-14

6) Перетащите с флешки MustiBeast на рабочий стол и запустите его

yosemite-install-15

7) If this is a fresh installation, click Quick Start to choose EasyBeast, UserDSDT, or DSDT-Free. For 7/8/9 series recommended builds choose DSDT-Free.

yosemite-install-168) На вкладке Drivers можно установить необходимые драйвера для звука и сети, видео и пр.

yosemite-install-179) Во вкладке Customize можно выбрать дополнительные параметры

yosemite-install-1810) Нажмите Print или Save, чтобы сохранить текущую конфигурацию, в случае если что-то придется изменить
11) Нажмите Build, затем Install

yosemite-install-19

yosemite-install-2012) Перезагрузите компьютер. Проверьте как работает оборудование (звук, сеть, видео)

yosemite-install-21

Ура, система установлена! Не спешите форматировать флешку, она вам пригодится в случае бэкапов или других неприятностей. Если у вас возникли сложности во время установки или после, заходите на форум tonymacx86, наверняка кто-то сталкивался с похожими проблемами.

[wpanchor id=»step-6″]

Описание проблем и их решений

Такие вещи как HDMI-звук и iMessage обычно не работают из коробки и требуют настройки.

Прим.: Советую не тратить время на настройку iMessage, а пользоваться открытыми мессенджерами типа Telegram или Viber. Для включения iMessage может потребоваться звонок в службу поддержки Apple, телефон которой в России не отвечает все время.

Возможно вы столкнетесь и с другими проблемами, в этом случае рекомендуем ознакомиться со следующими материалами:

HDMI-звук
boot0 Error: Руководство по исправлению ошибки
Issuing Boot Flags
Как узнать что ставить с помощью MultiBeast

Установка загрузчика и Extra на EFI раздел
База DSDT
Как починить iMessage
Ключи загрузки Chimera для HD графики: IGPEnabler, IGPlatformID, and IGPDeviceID
Основы

Альтернативные графические драйвера NVIDIA
NVIDIA выпускает альтернативные графические драйвера для совместимых устройств. Они отличаются от тех, что идут при установке, по сути являются экспериментальными версиями. Раньше с помощью этих драйверов решали проблемы с OpenCL в некоторых приложениях, а так же они лучше справлялись с управлениям питания в некоторых моделях.

Еще с этими драйверами можно включить последние ‘Maxwell’ карты с полной поддержкой, например такие: NVIDIA GeForce GTX 750, GTX 750 Ti, GTX 970, and GTX 980.

NVIDIA Alternate Graphics Drivers для Mac OS X 10.10.3 (346.01.02)

Как работают «оптимизаторы» в «SEO-компании №1» или небольшой отзыв на Demis Group

Есть у меня товарищ с сайтом на Joomla, который я сделал год назад. Т.к. я не занимался и не занимаюсь продвижением сайтов, на вопрос о повышении позиций в поисковиках, порекомендовал товарищу самостоятельно найти компанию, которая профессионально этим занимается.

logo

Такая компания нашлась, называется она Demis Group. Предоставили им доступы и начали работу. Тут стоит отметить, что все это время ко мне не обращались с правками, поэтому я не застал процесс «оптимизации», и очень зря, как оказалось.

Проблемы обнаружились, когда меня попросили сделать адаптивную версию сайта. Клиенту оптимизатор посоветовал, мол, Гуглу нравятся такие сайты, они выше в выдаче, да и в целом удобнее. Сайт тогда мы сделали фиксированным, был ограничен бюджет. Ну не проблема, сказано — сделано!

Открываю сайт, смотрю внешне, в админке. Параллельно запускаю PhpStorm, гружу проект к себе на компьютер с SFTP, ведь были изменения со стороны оптимизатора. Смотрю на тайтлы, как были при мне, такими же и остались. WTF? Где продвижение? В админке, в пунктах меню все тоже самое. Никаких компонентов SEO не установлено. Ооокей, смотрю корень сайта и нахожу чужеродные файлы:

_adminer.php
_varvara.php
d-seo.php
d-url-rewriter.php

Думаю, некоторые по названию уже начали понимать, с чем мне пришлось столкнуться.

_adminer.php — это менеджер БД, взят отсюда http://www.adminer.org/
_varvara.php — самописная хрень, которая делает поиск и замену во всех файлах на хостинге

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

Ок, смотрим файлы d-seo.php.

/**
* Оптимизаторский файл. Подключать только include_once!!! Не забываем global $aSEOData, где нужно.
*
* if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/d-seo.php')) {
* include_once($_SERVER['DOCUMENT_ROOT'] . '/d-seo.php');
* }
*
* Изменяемые параметры массива $aSEOData (квадратными скобками выделены неактивные)
* title - title страницы
* descr - meta descr
* keywr - meta keywords
*
*/

//Глобальные значения (по умолчанию)
$aSEOData['title'] = '';
$aSEOData['descr'] = '';
$aSEOData['keywr'] = '';
$aSEOData['h1'] = '';
$aSEOData['text-top'] = '';
$aSEOData['text-bot'] = '';

//Определяем адрес (REQUEST_URI есть не всегда)
$sSEOUrl = $_SERVER['REQUEST_URI'];
//$sSEOUrl = DUR_REQUEST_URI;

//Собственно вариации для страниц
switch ($sSEOUrl) {
case '/': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Металлопрокат — купить в «МТК» в Новосибирске | Цены на металлопрокат без надбавок';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить металлопрокат оптом и в розницу. Цены свободны от лишних надбавок. На всю металлопродукцию действует гарантия качества. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'купить металлопрокат в новосибирске цена стоимость металл';
break;

case '/metalloprokat/chernyi-prokat.html': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Черный металлопрокат — купить в «МТК» в Новосибирске | Продажа черного металлопроката: цены';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить черный металлопрокат. Цены на черный металлопрокат представлены на сайте. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'черный черный металлопрокат новосибирск цена продажа';
break;

case '/metalloprokat/listovoy-prokat.html': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Листовой прокат — купить в «МТК» в Новосибирске | Продажа листового проката: цены';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить листовой прокат. Цены на листовой прокат представлены на сайте. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'листовой прокат купить продажа цена';
$aSEOData['h1'] = 'Листовой прокат с доставкой по Новосибирску';
break;

case '/metalloprokat/armaturniy-prokat.html': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Стальная арматура — продажа в «МТК» в Новосибирске | Арматурный прокат: цены, характеристики';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить стальную арматуру. Цены на арматурный прокат представлены на сайте. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'арматура стальная цена арматурный прокат';
$aSEOData['h1'] = 'Арматурный прокат разных типов';
break;

case '/metalloprokat/trubniy-prokat.html': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Трубный прокат: цены, характеристики | Продажа трубного металлопроката в «МТК» в Новосибирске';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить трубный прокат. Цены на трубный прокат представлены на сайте. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'трубный прокат';
$aSEOData['h1'] = 'Трубный прокат различных типоразмеров';
break;

case '/metalloprokat/perfometall.html': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Перфорированный металл — продажа в «МТК» в Новосибирске | Продажа перфометалла';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить перфорированный металл. Цены на перфометалл представлены на сайте. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'перфорированный металл цена перфометалл';
$aSEOData['h1'] = 'Легкий и износостойкий перфометалл по индивидуальным эскизам';
break;

case '/metalloprokat/nerzhaveushiy-prokat.html': // Добавлено 28 January 2015 в 10:36
$aSEOData['title'] = 'Нержавеющий металлопрокат — продажа в Новосибирске | Прокат из нержавеющей стали';
$aSEOData['descr'] = 'В ООО «МТК» вы можете купить нержавеющий металлопрокат. Цены на нержавеющий металлопрокат представлены на сайте. Телефоны в Новосибирске: (383) 361-26-34, (383) 361-21-74.';
$aSEOData['keywr'] = 'нержавеющий металлопрокат новосибирск цена';
$aSEOData['h1'] = 'Нержавеющий металлопрокат';
break;

default:
break;
}

// // генерация мета-тегов
// $arExceptions = array (
// '/catalogue/shiny/dlya-pogruzchikov/',
// '/catalogue/arenda-pogruzchikov/',
// );

//if(!in_array($sSEOUrl, $arExceptions)) {
if (empty($aSEOData['title']) or empty($aSEOData['descr'])) {
if (preg_match('%<h1[^>]*>(.*)</h1>%siU', $sContent, $h1)) {
//чистим h1 от лишних тегов
$h1[1] = preg_replace('%<[^>]*>%siU', '', $h1[1]);
$h1[1] = trim($h1[1]);

//if (empty($aSEOData['title']))
// $aSEOData['title'] = $h1[1] .' | Мебель для офиса';

if (empty($aSEOData['descr']))
$aSEOData['descr'] = 'Продажа изделий черного металлопроката, услуги раскройки металла, помощь в транспортировке. '. $h1[1] .'. Наш телефон в Новосибирске: +7 (383) 361-26-34';
}
}
//}

///РЕПЛЕЙСЫ
///////////

// вставка текста до каталога
// if (isset($aSEOData['text-top']) && !empty($aSEOData['text-top'])) {
// $sContent = str_replace('<!--text-top-->', '<div id="text-top" class="seo">'.$aSEOData['text-top'].'</div>', $sContent);
// }
// // вставка текста после каталога
// if (isset($aSEOData['text-bot']) && !empty($aSEOData['text-bot'])) {
// $sContent = str_replace('<!--text-bot-->', '<div id="text-bot" class="seo">'.$aSEOData['text-bot'].'</div>', $sContent);
// }

// замена тегов на css (не расскоменчивать - пропадают заголовки)
//$sContent = preg_replace('%<h3 class="chg-to-css">(.*)</h3>%siU', '<div class="kak_h3">$1</div>', $sContent);

// цели
$sContent = str_replace('<input type="submit" value="Отправить" name="form[send]" id="send" class="rsform-submit-button" />',
'<input type="submit" value="Отправить" name="form[send]" id="send" class="rsform-submit-button" onclick="yaCounter25698332.reachGoal(\'zvonok\'); ga(\'send\', \'event\', \'knopka\', \'звонок\'); return true;"/>',
$sContent);

// реплейсы для конкретных страниц
// switch ($sSEOUrl) {
// case '/index.php':
// break;
// case '/kontakty.php':
// break;
// }

//Обработка
function changeHeadBlock ($sContent, $sRegExp, $sBlock) {
if (preg_match($sRegExp, $sContent)) {
return preg_replace($sRegExp, $sBlock, $sContent);
}
else {
return str_replace('<head>', '<head>' . $sBlock, $sContent);
}
}
if(isset($_SERVER['X_DUSYA']) || isset($_SERVER['HTTP_X_DUSYA'])) {
$sContent = str_replace('<head>', '<head><!--origUrl="' . $sSEOUrl . '"-->' , $sContent);
}
if (isset($aSEOData['title']) && !empty($aSEOData['title'])) {
$aSEOData['title'] = htmlspecialchars($aSEOData['title']);
$sContent = changeHeadBlock($sContent, '#<title>.*</title>#siU', '<title>' . $aSEOData['title'] . '</title>');
}
if (isset($aSEOData['descr']) && !empty($aSEOData['descr'])) {
$aSEOData['descr'] = htmlspecialchars($aSEOData['descr']);
$sContent = changeHeadBlock($sContent, '#<meta[^>]+name[^>]{1,7}description[^>]*>#siU', '<meta name="description" content="' . $aSEOData['descr'] . '" />');
}
if (isset($aSEOData['keywr']) && !empty($aSEOData['keywr'])) {
$aSEOData['keywr'] = htmlspecialchars($aSEOData['keywr']);
$sContent = changeHeadBlock($sContent, '#<meta[^>]+name[^>]{1,7}keywords[^>]*>#siU', '<meta name="keywords" content="' . $aSEOData['keywr'] . '" />');
}
if (isset($aSEOData['h1']) && !empty($aSEOData['h1'])) {
$sContent = preg_replace('#(<h1[^>]*>).*(</h1>)#siU', '$1'.$aSEOData['h1'].'$2', $sContent);
}

 

Великолепно, Demis! Заместо того, чтобы воспользоваться встроенными SEO функциями Joomla, мы сделаем свой велосипед!

velosiped-sdelay-samЧто, если клиент поменяет алиас URL у пункта меню? Ничего страшного, мы ведь об этом не узнаем, да и клиент не сразу догадается об отвалившихся тайтлах, а если и узнает, ну так что стоит зайти и исправить? Ну да, клиент сам не полезет в этот ужас, для этого ведь существуем мы!

Теперь файл d-url-rewriter.php

// Раздел настройки ЧПУ (Все пути начинаются с ведущего слеша от корневой директории)
$aURLRewriter = array (
// '/test1' => '/test-OK',
);
//Сквозные редиректы
$aR301SkipCheck = array (
// '/test2' => '/test-OK',
'/sitemap' => '/sitemap.html',
);
//Удаленные страницы
$a410Response = array (
// '/test3',
'/contacts.html/',
);
$a404Response = array (
// '/test4',
);
// if(in_array($_SERVER['REQUEST_URI'], $a404)) {
// header("HTTP/1.1 404 Not Found");
// echo file_get_contents('http://uitek.ru/rus/404');
// exit;
// }
// Только замена ссылок
$aURLRewriterOnly = array (
// '/test5' => '/test-OK',
);

define('DUR_DEBUG', 0); //Включение режима отладки (вывод инфо в конце исходного текста на странице)
define('DUR_PREPEND_APPEND', 0); //Единая точка входа (.htaccess) Не рекомендуется
define('DUR_BASE_ROOT', 0); //Прописать принудительно <base href="http://domain.com/"> Бывает полезно при ссылках вида href="?page=2". При указании строки, пропишет ее
define('DUR_LINK_PARAM', 0); //Дописать путь перед ссылками вида href="?page=2"
define('DUR_ANC_HREF', 0); //Пофиксить ссылки вида href="#ancor"
define('DUR_ROOT_HREF', 1); //Пофиксить ссылки вида href="./"
define('DUR_REGISTER_GLOBALS', 0); //Регистрировать глобальные переменные
define('DUR_SKIP_POST', 1); //Не выполнять подмену при запросе POST
define('DUR_CMS_TYPE', 'NONE'); //Включение особенностей для CMS, возможные значения: NONE, NETCAT, JOOMLA, HTML, DRUPAL, WEBASYST, ICMS
define('DUR_OUTPUT_COMPRESS', 'NONE'); //Сжатие выходного потока, возможные значения: NONE, GZIP, DEFLATE, AUTO, SKIP
define('DUR_SUBDOMAINS', 0); //Обрабатывать поддомены, указываем здесь основной домен!
define('DUR_SKIP_USERAGENT', '#^(|mirror)$#'); //Не выполнять редиректы при указанном HTTP_USER_AGENT (регулярка)
define('DUR_SKIP_URLS', '#^/_?(admin|manag|bitrix|indy|cms|phpshop|varvara.php|captcha|jscripts/|modules|includes|templates|wp-admin)#siU'); //Skip URLS
define('DUR_FIX_CONTLEN', 1); //Фиксить Content-Length
define('DUR_PATHINFO', 0); //Регистрировать переменные для передачи вида /index.php/uri

///new
define('DUR_FIX_RELATIVE', 1); //Фиксить относительные ссылки (только для DUR_MAIN_CYCLE = ortodox)
define('DUR_FIX_DOTTED', 0); //Фиксить ссылки от "./" (только для DUR_MAIN_CYCLE = ortodox)
define('DUR_FIX_HTTP_HOST', $_SERVER['HTTP_HOST']); //Фиксить HTTP_HOSTв ссылках, прописываем, например, значение "www.mysite.ru", чтобы сократить количество host-зависимых подмен ссылок
define('DUR_CACHE_REWRITED', 0); //Кэшировать все замены в этом рерайтере, должна быть создана папка d-cache в корне с правами на запись
define('DUR_CACHE_MEMORY', 40960000); //Критическая масса кеша (в байтах), при превышении этого значения кеш очищается
define('DUR_CACHE_TIME', 3); //Критическое время жизни кеша, при превышении этого значения кеш очищается
define('DUR_MAIN_CYCLE', 'ortodox'); //Константа для выбора типа основного цикла, значения: callback, str_replace, ortodox

// Раздел обработки
define('DUR_TIME_START', microtime(true));
define('DUR_REQUEST_URI', $_SERVER['REQUEST_URI']);
define('DUR_HTTP_HOST', $_SERVER['HTTP_HOST']);
define('DUR_FULL_URI', $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
define('BX_COMPRESSION_DISABLED', true); //Hack for bitrix
define('DUR_SKIP_THIS', preg_match(DUR_SKIP_URLS, DUR_REQUEST_URI, $aM));
define('DUR_SKIP_R301', !isset($_SERVER['HTTP_USER_AGENT']) || preg_match(DUR_SKIP_USERAGENT, $_SERVER['HTTP_USER_AGENT']));
if (defined('DUR_DEBUG') && DUR_DEBUG) {
ini_set('display_errors', 1);
ini_set('error_reportings', E_ALL);
}
if (isset($_GET['_openstat'])) {
unset($_GET['_openstat']);
unset($_REQUEST['_openstat']);
unset($HTTP_GET_VARS['_openstat']);
$_SERVER['REQUEST_URI'] = preg_replace('%[&?]_openstat=[^&]+(&|$)%siU', '', $_SERVER['REQUEST_URI']);
}
if (in_array($_SERVER['REQUEST_URI'], $a410Response) && !DUR_SKIP_THIS) {
header('HTTP/1.0 410 Gone');
echo '<h1 style="font-size: 18pt;">Ошибка 410</h1><p>Страница удалена</p><p style="text-align: right; margin: 10px;"><a href="/">На главную</a></p>';
exit;
}
if (in_array($_SERVER['REQUEST_URI'], $a404Response) && !DUR_SKIP_THIS) {
dur404native();
}
if (isset($aR301SkipCheck[$_SERVER['REQUEST_URI']]) && !DUR_SKIP_THIS && !DUR_SKIP_R301) {
if (!defined('DUR_SKIP_POST') || !DUR_SKIP_POST || (strtoupper($_SERVER['REQUEST_METHOD']) != 'POST')) {
header('Location: ' . $aR301SkipCheck[$_SERVER['REQUEST_URI']], true, 301);
exit;
}
}
foreach ($aURLRewriter as $sKey => $sVal) {
$aURLRewriter[$sKey] = str_replace(
array('р', 'у', 'к', 'е', 'н', 'х', 'в', 'а', 'о', 'ч', 'с', 'м', 'и', 'т', ' '),
array('p', 'y', 'k', 'e', 'h', 'x', 'b', 'a', 'o', '4', 'c', 'm', 'n', 't', '_'),
$sVal
);
if (!defined('DUR_SEO_REQUEST_URI') && ($sVal == $_SERVER['REQUEST_URI'])) {
define('DUR_SEO_REQUEST_URI', $sKey);
}
}
$aURFlip = array_flip($aURLRewriter);
//Многократная вложенность замен (до 10)
for ($i = 0; $i < 10; $i++) {
foreach ($aURLRewriter as $sFrom => $sTo) {
if (isset($aURLRewriter[$sTo])) {
$aURLRewriter[$sFrom] = $aURLRewriter[$sTo];
$aURFlip[$aURLRewriter[$sTo]] = $sFrom;
}
}
}
//Joomla hack! (Против защиты от register globals)
if (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'JOOMLA')) {
$_SERVER['dur'] = array($aURLRewriter, $aURFlip, $aURLRewriterOnly);
}
//Единая точка входа
if (defined('DUR_PREPEND_APPEND') && DUR_PREPEND_APPEND && !DUR_SKIP_THIS) {
durRun ();
}

// Функции
function durRun () {
if (defined('DUR_RUNNED')) return;
// if (isset())
define('DUR_RUNNED', 1);
durR301();
ob_start('durLinkChanger');
durIFRewrite();
}

function dur404 () {
$aPages404 = array('404.php', '404.html', '404.htm', 'index.php', 'index.html', 'index.htm');
header('HTTP/1.1 404 Not found');
foreach ($aPages404 as $sPage404) {
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $sPage404)) {
include($_SERVER['DOCUMENT_ROOT'] . '/' . $sPage404);
exit;
}
}
echo '<h1>Ошибка 404</h1><p>Страница не найдена</p><p style="text-align: right; margin: 10px;"><a href="/">На главную</a></p>';
exit;
}
function dur404native() {
$_SERVER['REQUEST_URI'] = '/thispagewasdeleted';
$_GET = $_REQUEST = array();
}
function durRewrite ($sURL) {
global $QUERY_STRING, $REQUEST_URI, $REDIRECT_URL, $HTTP_GET_VARS;
define('DUR_DEBUG_BEFORE', "SERVER:\n" . durDebugVar($_SERVER) . "\n\nGET:\n" . durDebugVar($_GET) . "\n\nREQUEST:\n" . durDebugVar($_REQUEST) . "\n");
if (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'WEBASYST')) {
$sURL = '/?__furl_path=' . substr($sURL, 1) . '&frontend=1';
}
if (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'ICMS')) {
$sURL = '/index.php?path=' . substr($sURL, 1, -5) . '&frontend=1';
}
$QUERY_STRING = strpos($sURL, '?') ? substr($sURL, strpos($sURL, '?') + 1) : '';
$REQUEST_URI = $sURL;
$REDIRECT_URL = $sURL;
$_SERVER['QUERY_STRING'] = $QUERY_STRING;
$_SERVER['REDIRECT_URL'] = $sURL;
$_SERVER['REQUEST_URI'] = $sURL;
if (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'NETCAT')) {
putenv('REQUEST_URI=' . $sURL);
//$_ENV['REQUEST_URI'] = $sURL;
}
if (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'DRUPAL')) {
$_GET['q'] = substr($sURL, 1);
$_REQUEST['q'] = substr($sURL, 1);
}
if (preg_match_all('%[\?&]([^\=]+)\=([^&]*)%', $sURL, $aM)) {
$aParams = array();
foreach ($aM[1] as $iKey => $sName) {
$sVal = urldecode($aM[2][$iKey]);
if (preg_match('#^(.+)\[\]$#siU', $sName, $aMatch)) {
$aParams[$aMatch[1]][] = $sVal;
}
elseif (preg_match('#^(.+)\[([\w-]+)\]$#siU', $sName, $aMatch)) {
$aParams[$aMatch[1]][$aMatch[2]] = $sVal;
}
else {
$aParams[$sName] = $sVal;
}
}
foreach ($aParams as $sKey => $mVal) {
$_GET[$sKey] = $mVal;
$HTTP_GET_VARS[$sKey] = $mVal;
$_REQUEST[$sKey] = $mVal;
if (defined('DUR_REGISTER_GLOBALS') && DUR_REGISTER_GLOBALS) {
global $$sKey;
$$sKey = $mVal;
}
}
}
if (defined('DUR_PATHINFO') && DUR_PATHINFO) {
$_SERVER['PATH_INFO'] = substr($sURL, 1);
$_SERVER['PHP_SELF'] = $sURL;
}
if (DUR_CMS_TYPE == 'HTML') {
$sFName = $sURL;
if ($iPos = strpos($sFName, '?')) {
$sFName = substr($sFName, 0, $iPos);
}
if (file_exists($_SERVER['DOCUMENT_ROOT'] . $sFName)) {
include($_SERVER['DOCUMENT_ROOT'] . $sFName);
exit;
}
else {
dur404();
}
}
}

function durIFRewrite () {
global $aURFlip, $aURLRewriter;
if (DUR_SKIP_THIS) return;
$sKey = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
if (defined('DUR_SUBDOMAINS') && DUR_SUBDOMAINS && isset($aURFlip[$sKey])) {
if (!defined('DUR_ORIG_RURI')) {
define('DUR_ORIG_RURI', $aURFlip[$sKey]);
}
durRewrite ($aURFlip[$sKey]);
}
elseif (isset($aURFlip[$_SERVER['REQUEST_URI']])) {
if (!defined('DUR_ORIG_RURI')) {
define('DUR_ORIG_RURI', $aURFlip[$_SERVER['REQUEST_URI']]);
}
durRewrite ($aURFlip[$_SERVER['REQUEST_URI']]);
}
elseif (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'HTML')) {
if (file_exists($_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI'])) {
durRewrite ($_SERVER['REQUEST_URI']);
}
else {
dur404();
}
}
}

function durR301 () {
global $aURFlip, $aURLRewriter;
if (DUR_SKIP_THIS || DUR_SKIP_R301) return;
if (defined('DUR_SKIP_POST') && DUR_SKIP_POST && (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST')) {
return;
}
if (isset($aURLRewriter[$_SERVER['REQUEST_URI']])) {
if ('http://' . DUR_HTTP_HOST == trim($aURLRewriter[$_SERVER['REQUEST_URI']], '/')) {
return;
}
header('Location: ' . $aURLRewriter[$_SERVER['REQUEST_URI']], true, 301);
exit;
}
}

function durRExpEscape ($sStr) {
return str_replace(array('?', '.', '-', ':', '%', '[', ']', '(', ')'), array('\\?', '\\.', '\\-', '\\:', '\\%', '\\[', '\\]', '\\(', '\\)'), $sStr);
}

function durReplaceOnceLink ($sLink, $sNewLink, $sContent) {
$sContent = preg_replace('%(href\s*=\s*[\'"]?)\s*' . durRExpEscape ($sLink) . '([#\'"\s>])%siU', '$1' . $sNewLink . '$2', $sContent);
if (strpos($sLink,'&'))
$sContent = preg_replace('%(href\s*=\s*[\'"]?)\s*' . durRExpEscape (str_replace('&', '&amp;', $sLink)) . '([#\'"\s>])%siU', '$1' . $sNewLink . '$2', $sContent);
return $sContent;
}

function durReplaceLink ($sHost, $sBase, $sFrom, $sTo, $sContent) {
$sNewLink = $sTo;
// Link type: "http://domain/link"
$sContent = durReplaceOnceLink ('http://' . $sHost . $sFrom, $sNewLink, $sContent);
// Link type: "https://domain.com/link"
// $sContent = durReplaceOnceLink ('https://' . $sHost . $sFrom, $sNewLink, $sContent);
// Link type: "//domain.com/link"
// $sContent = durReplaceOnceLink ('//' . $sHost . $sFrom, $sNewLink, $sContent);
if (!defined('DUR_FIRST_TIC'))
{
// Link type: "/link"
$sContent = durReplaceOnceLink ($sFrom, $sNewLink, $sContent);
// Link type: "./link"
if (defined('DUR_FIX_DOTTED') && DUR_FIX_DOTTED) {
$sContent = durReplaceOnceLink ('.' . $sFrom, $sNewLink, $sContent);
}
if (defined('DUR_FIX_RELATIVE') && DUR_FIX_RELATIVE) {
// Link type: "link" (Calc fromlink)
$aLink = explode('/', $sFrom);
$aBase = empty($sBase) ? array('') : explode('/', str_replace('//', '/', '/' . $sBase));
$sReplLnk = '';
for ($i = 0; $i < max(count($aLink), count($aBase)); $i++) {
if (isset($aBase[$i]) && isset($aLink[$i])) {
if ($aLink[$i] == $aBase[$i]) {
continue;
}
else {
for ($j = $i; $j < count($aBase); $j++) {
$sReplLnk .= '../';
}
for ($j = $i; $j < count($aLink); $j++) {
$sReplLnk .= $aLink[$j] . '/';
}
break;
}
}
elseif (isset($aLink[$i])) {
$sReplLnk .= $aLink[$i] . '/';
}
elseif (isset($aBase[$i])) {
$sReplLnk .= '../';
}
}
$sReplLnk = preg_replace('%/+%', '/', $sReplLnk);
$sReplLnk2 = trim($sReplLnk, '/');
$sReplLnk3 = rtrim($sReplLnk2, '.');
if (strlen($sReplLnk) > 1) {
$sContent = durReplaceOnceLink ($sReplLnk, $sNewLink, $sContent);
if (defined('DUR_FIX_DOTTED') && DUR_FIX_DOTTED) {
$sContent = durReplaceOnceLink ('./' . $sReplLnk, $sNewLink, $sContent);
}
}
if (($sReplLnk2 != $sReplLnk) && (strlen($sReplLnk2) > 1)) {
$sContent = durReplaceOnceLink ($sReplLnk2, $sNewLink, $sContent);
if (defined('DUR_FIX_DOTTED') && DUR_FIX_DOTTED) {
$sContent = durReplaceOnceLink ('./' . $sReplLnk2, $sNewLink, $sContent);
}
}
if (($sReplLnk3 != $sReplLnk2) && (strlen($sReplLnk3) > 1)) {
$sContent = durReplaceOnceLink ($sReplLnk3, $sNewLink, $sContent);
if (defined('DUR_FIX_DOTTED') && DUR_FIX_DOTTED) {
$sContent = durReplaceOnceLink ('./' . $sReplLnk3, $sNewLink, $sContent);
}
}
}
}
return $sContent;
}

function durGZDecode($sS) {
$sM = ord(substr($sS,2,1)); $iF = ord(substr($sS,3,1));
if ($iF & 31 != $iF) return null;
$iLH = 10; $iLE = 0;
if ($iF & 4) {
if ($iL - $iLH - 2 < 8) return false;
$iLE = unpack('v',substr($sS,8,2));
$iLE = $iLE[1];
if ($iL - $iLH - 2 - $iLE < 8) return false;
$iLH += 2 + $iLE;
}
$iFCN = $iFNL = 0;
if ($iF & 8) {
if ($iL - $iLH - 1 < 8) return false;
$iFNL = strpos(substr($sS,8+$iLE),chr(0));
if ($iFNL === false || $iL - $iLH - $iFNL - 1 < 8) return false;
$iLH += $iFNL + 1;
}
if ($iF & 16) {
if ($iL - $iLH - 1 < 8) return false;
$iFCN = strpos(substr($sS,8+$iLE+$iFNL),chr(0));
if ($iFCN === false || $iL - $iLH - $iFCN - 1 < 8) return false;
$iLH += $iFCN + 1;
}
$sHCRC = '';
if ($iF & 2) {
if ($iL - $iLH - 2 < 8) return false;
$calccrc = crc32(substr($sS,0,$iLH)) & 0xffff;
$sHCRC = unpack('v', substr($sS,$iLH,2));
$sHCRC = $sHCRC[1];
if ($sHCRC != $calccrc) return false;
$iLH += 2;
}
$sScrc = unpack('V',substr($sS,-8,4));
$sScrc = $sScrc[1];
$iSZ = unpack('V',substr($sS,-4));
$iSZ = $iSZ[1];
$iLBD = $iL-$iLH-8;
if ($iLBD < 1) return null;
$sB = substr($sS,$iLH,$iLBD);
$sS = '';
if ($iLBD > 0) {
if ($sM == 8) $sS = gzinflate($sB);
else return false;
}
if ($iSZ != strlen($sS) || crc32($sS) != $sScrc) return false;
return $sS;
}

function durGZDecode2($sS) {
$iLen = strlen($sS);
$sDigits = substr($sS, 0, 2);
$iMethod = ord(substr($sS, 2, 1));
$iFlags = ord(substr($sS, 3, 1));
if ($iFlags & 31 != $iFlags) return false;
$aMtime = unpack('V', substr($sS, 4, 4));
$iMtime = $aMtime[1];
$sXFL = substr($sS, 8, 1);
$sOS = substr($sS, 8, 1);
$iHeaderLen = 10;
$iExtraLen = 0;
$sExtra = '';
if ($iFlags & 4) {
if ($iLen - $iHeaderLen - 2 < 8) return false;
$iExtraLen = unpack('v', substr($sS, 8, 2));
$iExtraLen = $iExtraLen[1];
if ($iLen - $iHeaderLen - 2 - $iExtraLen < 8) return false;
$sExtra = substr($sS, 10, $iExtraLen);
$iHeaderLen += 2 + $iExtraLen;
}
$iFilenameLen = 0;
$sFilename = '';
if ($iFlags & 8) {
if ($iLen - $iHeaderLen - 1 < 8) return false;
$iFilenameLen = strpos(substr($sS, $iHeaderLen), chr(0));
if ($iFilenameLen === false || $iLen - $iHeaderLen - $iFilenameLen - 1 < 8) return false;
$sFilename = substr($sS, $iHeaderLen, $iFilenameLen);
$iHeaderLen += $iFilenameLen + 1;
}
$iCommentLen = 0;
$sComment = '';
if ($iFlags & 16) {
if ($iLen - $iHeaderLen - 1 < 8) return false;
$iCommentLen = strpos(substr($sS, $iHeaderLen), chr(0));
if ($iCommentLen === false || $iLen - $iHeaderLen - $iCommentLen - 1 < 8) return false;
$sComment = substr($sS, $iHeaderLen, $iCommentLen);
$iHeaderLen += $iCommentLen + 1;
}
$sCRC = '';
if ($iFlags & 2) {
if ($iLen - $iHeaderLen - 2 < 8) return false;
$sCalcCRC = crc32(substr($sS, 0, $iHeaderLen)) & 0xffff;
$sCRC = unpack('v', substr($sS, $iHeaderLen, 2));
$sCRC = $sCRC[1];
if ($sCRC != $sCalcCRC) return false;
$iHeaderLen += 2;
}
$sDataCRC = unpack('V', substr($sS, -8, 4));
$sDataCRC = sprintf('%u', $sDataCRC[1] & 0xFFFFFFFF);
$iSize = unpack('V', substr($sS, -4));
$iSize = $iSize[1];
$iBodyLen = $iLen - $iHeaderLen - 8;
if ($iBodyLen < 1) return false;
$sBody = substr($sS, $iHeaderLen, $iBodyLen);
$sS = '';
if ($iBodyLen > 0) {
switch ($iMethod) {
case 8: $sS = gzinflate($sBody); break;
default: return false;
}
}
$sCRC = sprintf('%u', crc32($sS));
$bCRCOK = ($sCRC == $sDataCRC);
$bLenOK = ($iSize == strlen($sS));
if (!$bLenOK || !$bCRCOK) return false;
return $sS;
}

function durGZCheck ($sContent) {
$iLen = strlen($sContent);
if ($iLen < 18 || strcmp(substr($sContent, 0, 2), "\x1f\x8b")) {
return $sContent;
}
$sData = durGZDecode2($sContent);
if (!$sData) {
$sData = durGZDecode($sContent);
}
return $sData ? $sData : $sContent;
}

function durOutputCompress ($sContent) {
if (!defined('DUR_OUTPUT_COMPRESS')) {
define('DUR_OUTPUT_COMPRESS', 'SKIP');
}
if (DUR_OUTPUT_COMPRESS == 'SKIP') {
return $sContent;
}
$aAccept = array();
if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
$aAccept = array_map('trim', explode(',', strtolower($_SERVER['HTTP_ACCEPT_ENCODING'])));
}
$bGZIP = in_array('gzip', $aAccept) && function_exists('gzencode');
$bDEFL = in_array('deflate', $aAccept) && function_exists('gzdeflate');
$sCompress = DUR_OUTPUT_COMPRESS;
if ((!$bGZIP && !$bDEFL) || (!$bGZIP && ($sCompress == 'GZIP')) || (!$bDEFL && ($sCompress == 'DEFLATE'))) {
$sCompress = 'NONE';
}
if ($sCompress == 'AUTO') {
$sCompress = $bGZIP ? 'GZIP' : ($bDEFL ? 'DEFLATE' : 'NONE');
}
switch ($sCompress) {
case 'GZIP':
header('Content-Encoding: gzip');
$sContent = gzencode($sContent);
break;
case 'DEFLATE':
header('Content-Encoding: deflate');
$sContent = gzdeflate($sContent, 9);
break;
default:
//header('Content-Encoding: none');
}
return $sContent;
}

function durDebugEscape ($sText) {
return str_replace(array('--', '-->'), array('==', '==}'), $sText);
}

function durDebugVar ($mVar, $sPref = ' ') {
$Ret = '';
foreach ($mVar as $sKey => $sVal) {
$Ret .= "{$sPref}{$sKey} => ";
if (is_array($sVal)) {
$Ret .= "ARRAY (\n" . durDebugVar($sVal, $sPref.' ') . "{$sPref})\n";
}
else {
$Ret .= "{$sVal}\n";
}
}
return durDebugEscape($Ret);
}

function durLinkChanger ($sContent) {
global $aURFlip, $aURLRewriter, $aURLRewriterOnly;

if (DUR_SKIP_THIS) return $sContent;
if (strlen($sContent) < 500) return $sContent;
if (DUR_CACHE_REWRITED && file_exists($_SERVER['DOCUMENT_ROOT'].'/d-cache')) {

/// Модуль кеширования контента - start

$aDataStore = array();

$icachedays = DUR_CACHE_TIME*60*60*24;

$sMD5Content = md5($sContent); // MD5 от контента составляет часть имени файла кэша; это значение нужно для поиска готового к выводу контента в кеше
$sCacheFName = $_SERVER['DOCUMENT_ROOT'].'/d-cache/'.$sMD5Content.'.html.cache'; // имя файла кеша текущего контента
$sTimeFName = $_SERVER['DOCUMENT_ROOT'].'/d-cache/time.cache'; // имя файла данных кеша

$aStoredData = array();
$aStoredData = unserialize(file_get_contents($sTimeFName)); // массив из файла данных кеша
$timestamp = $aStoredData['d_scripts_time']; // время последнего изменения файлов d-seo и d-url-rewriter
$tOverallLenght = $aStoredData['cache_weight']; // Занимаемое кешем место на диске
$tLastClear = $aStoredData['last_clear_time'];
$dtimestamp = filemtime($_SERVER['DOCUMENT_ROOT'].'/d-url-rewriter.php'); // время изменения d-url-rewriter

// если есть файл d-seo, то берем его время изменения и записываем в переменную $dtimestamp максимум от времени последнего изменения скриптов
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/d-seo.php')) {
$dTMPtimestamp = filemtime($_SERVER['DOCUMENT_ROOT'].'/d-seo.php');
if ($dTMPtimestamp > $dtimestamp)
$dtimestamp = $dTMPtimestamp;
}

// если время последнего изменения, записанное в файл данных кеша отличается от реального, чистим весь кеш.
if ($timestamp != $dtimestamp || $tOverallLenght > DUR_CACHE_MEMORY || time() - $tLastClear > $icachedays) {
if($dh = @opendir($_SERVER['DOCUMENT_ROOT'].'/d-cache/')) {
while (($obj = readdir($dh)) !== false) {
if($obj=='.' || $obj=='..') continue;
@unlink($_SERVER['DOCUMENT_ROOT'].'/d-cache/'.$obj);
}
closedir($dh);
}
$aDataToStore['d_scripts_time'] = $dtimestamp; // записываем в массив время последнего изменения файлов d-seo и d-url-rewriter
$aDataToStore['last_clear_time'] = $tLastClear = time();
$aDataToStore['cache_weight'] = $tOverallLenght = 0;
file_put_contents($sTimeFName,serialize($aDataToStore));
}
}
// если есть соотв. файл в кеше, записываем его содержимое в $sContent
if (isset($sCacheFName) && file_exists($sCacheFName)) {
$sContent = file_get_contents($sCacheFName);
}

/// Модуль кеширования контента - break

else {

$iTimeStart = microtime(true);
$sContent = durGZCheck($sContent);
if (defined('DUR_CMS_TYPE') && (DUR_CMS_TYPE == 'JOOMLA') && isset($_SERVER['dur'])) {
$aURLRewriter = $_SERVER['dur'][0];
$aURFlip = $_SERVER['dur'][1];
$aURLRewriterOnly = $_SERVER['dur'][2];
unset($_SERVER['dur']);
}
$aURLRewriter = array_merge($aURLRewriter, $aURLRewriterOnly);
//Base path
if (preg_match('%<[^<>]*base[^<>]*href=[\'"]?([\w_\-\.\:/]+)[\'"\s>][^<>]*>%siU', $sContent, $aM)) {
$sBase = $aM[1];
$sBaseHref = $aM[1];
}
else {
$sBase = 'http://' . $_SERVER['HTTP_HOST'] . substr($_SERVER['REQUEST_URI'], 0, strrpos($_SERVER['REQUEST_URI'], '/'));
$sBaseHref = '';
}
$sBase = trim(str_replace(array('http://', 'https://'), '', $sBase), '/');
$aHosts = array($_SERVER['HTTP_HOST']);
if (substr($_SERVER['HTTP_HOST'], 0, 4) == 'www.') {
$aHosts[] = substr($_SERVER['HTTP_HOST'], 4);
}
if (defined('DUR_SUBDOMAINS') && DUR_SUBDOMAINS) {
$sExtHost = str_replace('www.www.', 'www.', 'www.' . DUR_SUBDOMAINS);
$aHosts[] = $sExtHost;
$aHosts[] = str_replace('www.', '', $sExtHost);
}
$aHosts = array_unique($aHosts);
$sBase = str_replace($aHosts, '', $sBase);
//href="?..."
if (defined('DUR_LINK_PARAM') && defined('DUR_ORIG_RURI') && DUR_LINK_PARAM) {
$sContent = preg_replace('%(href\s*=\s*[\'"]?)\s*([?#].*[#\'"\s>])%siU', '$1' . DUR_ORIG_RURI . '$2', $sContent);
}

if (defined('DUR_FIX_HTTP_HOST') && DUR_FIX_HTTP_HOST) {
$aHosts = array(DUR_FIX_HTTP_HOST);
$sFalseHost = str_replace('www.www.','','www.'.DUR_FIX_HTTP_HOST);
$sContent = str_replace('http://'.$sFalseHost, 'http://'.DUR_FIX_HTTP_HOST, $sContent);

}

//Main cicle
if (defined('DUR_MAIN_CYCLE'))
{
if (DUR_MAIN_CYCLE == 'str_replace' || DUR_MAIN_CYCLE == 'callback')
{
///Нормализация ссылок, все ссылки на сайте должны прийти к виду href="http://HTTP_HOST/REQUEST_URI" , т.е. в кавычках, без пробелов и с хостом
///Опасносте начинается здесь
$sContent = preg_replace('#\shref\s*=[\s]?([A-Za-z0-9\?\/][^\s]*)(\s|/>|>)#siU',' href="http://'.DUR_FIX_HTTP_HOST.'/$1"$2',$sContent);
$sContent = preg_replace('#\shref\s*=[\s]?"([A-Za-z0-9\?\/][^"]*)"#siU',' href="http://'.DUR_FIX_HTTP_HOST.'/$1"',$sContent);
$sContent = str_replace(array(
'http://'.DUR_FIX_HTTP_HOST.'/http://'.DUR_FIX_HTTP_HOST.'',
'http://'.DUR_FIX_HTTP_HOST.'//',
'http://'.DUR_FIX_HTTP_HOST.'/http',
'http://'.DUR_FIX_HTTP_HOST.'/mailto:',
'http://'.DUR_FIX_HTTP_HOST.'/javascript',
'http://'.DUR_FIX_HTTP_HOST.'/skype',
'http://'.DUR_FIX_HTTP_HOST.'/tel',
),
array(
'http://'.DUR_FIX_HTTP_HOST.'',
'http://'.DUR_FIX_HTTP_HOST.'/',
'http',
'mailto:',
'javascript',
'skype',
'tel',
),
$sContent
);
/// - end
}

if (DUR_MAIN_CYCLE == 'str_replace')
{
foreach ($aURLRewriter as $sFrom => $sTo) {
if (strpos($sContent, 'href="http://'.DUR_FIX_HTTP_HOST.$sFrom.'"'))
$sContent = str_replace('href="http://'.DUR_FIX_HTTP_HOST.$sFrom.'"','href="http://'.DUR_FIX_HTTP_HOST.$sTo.'"',$sContent);
}
}
else if(DUR_MAIN_CYCLE == 'callback')
{
function durMainCycleCallback($href) {
global $aURLRewriter;
if (isset($aURLRewriter[$href[1]])) return 'href="http://'.DUR_FIX_HTTP_HOST.$aURLRewriter[$href[1]].'"';
else return $href[0];
}

$sContent = preg_replace_callback('#href="http://'.DUR_FIX_HTTP_HOST.'([^"]*)"#siU','durMainCycleCallback',$sContent);
}
else if(DUR_MAIN_CYCLE == 'ortodox')
{
foreach ($aHosts as $sHost) {
foreach ($aURLRewriter as $sFrom => $sTo) {
$sContent = durReplaceLink ($sHost, $sBase, $sFrom, $sTo, $sContent);
}
if (!defined("DUR_FIRST_TIC")) define("DUR_FIRST_TIC", true);
}
}
else {
$sContent .= "<!--Nothing to do here!-->";
}
}

if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/d-seo.php')) {
include_once($_SERVER['DOCUMENT_ROOT'] . '/d-seo.php');
}
if ((defined('DUR_BASE_ROOT') && DUR_BASE_ROOT) || !empty($sBaseHref)) {
if (strlen(DUR_BASE_ROOT) > 7) {
$sBaseHref = DUR_BASE_ROOT;
}
else {
$sBaseHref = (empty($sBaseHref) ? 'http://' . $aHosts[0] : $sBaseHref) . '/';
}
$sBaseHref = trim($sBaseHref, '/') . '/';
$sBaseHref = '<base href="' . $sBaseHref . '">';
$sContent = preg_replace('%<base[^>]+href[^>]+>%siU', '', $sContent);
$sContent = preg_replace('%(<head(\s.*)?>)%siU', "$1" . $sBaseHref, $sContent);
}
if (defined('DUR_ANC_HREF') && DUR_ANC_HREF) {
$sContent = preg_replace('%(href\s*=\s*["\']+)(#\w)%siU', '$1' . DUR_REQUEST_URI . '$2', $sContent);
}
if (defined('DUR_ROOT_HREF') && DUR_ROOT_HREF) {
$sContent = preg_replace('%(href\s*=\s*["\']*)\./(\w)%siU', '$1http://' . $_SERVER['HTTP_HOST'] . $sBase . '/$2', $sContent);
}
if (function_exists('durOtherReplacer')) {
$sContent = durOtherReplacer ($sContent);
}
}

if (DUR_CACHE_REWRITED && file_exists($_SERVER['DOCUMENT_ROOT'].'/d-cache')) {
/// Модуль кеширования контента - continue
file_put_contents($sCacheFName, $sContent);
// $aDataToStore = $aStoredData;
$aDataToStore['last_clear_time'] = $tLastClear;
$aDataToStore['d_scripts_time'] = $dtimestamp;
$aDataToStore['cache_weight'] = (int)$tOverallLenght + (int)strlen($sContent);
file_put_contents($sTimeFName,serialize($aDataToStore));
/// Модуль кеширования контента - end
}

if (defined('DUR_DEBUG') && DUR_DEBUG) {
$sContent .= "\n<!--\n";
if (defined('DUR_DEBUG_BEFORE') && DUR_DEBUG_BEFORE) {
$sContent .= " ===== VARS BEFORE REWRITE =====\n\n" . DUR_DEBUG_BEFORE;
}
$sContent .= "===== VARS AFTER REWRITE =====\n\nSERVER:\n" . durDebugVar($_SERVER) . "\n\nGET:\n" . durDebugVar($_GET) . "\n\nREQUEST:\n" . durDebugVar($_REQUEST) . "\n";
$sContent .= "\nCONSTANTS:\n" .
' DUR_REQUEST_URI => ' . durDebugEscape(DUR_REQUEST_URI) . "\n" .
' DUR_HTTP_HOST => ' . durDebugEscape(DUR_HTTP_HOST) . "\n" .
' DUR_FULL_URI => ' . durDebugEscape(DUR_FULL_URI) . "\n" .
' DUR_ORIG_RURI => ' . (defined('DUR_ORIG_RURI') ? durDebugEscape(DUR_ORIG_RURI) : 'NOT-SET') . "\n" .
' DUR_SEO_REQUEST_URI => ' . (defined('DUR_SEO_REQUEST_URI') ? durDebugEscape(DUR_SEO_REQUEST_URI) : 'NOT-SET') . "\n";

$iTimeNow = microtime(true);
$iTimeAll = ($iTimeNow - DUR_TIME_START) / 1000;
$iTimeContent = ($iTimeStart - DUR_TIME_START) / 1000;
$iTimeLinks = ($iTimeNow - $iTimeStart) / 1000;
$sContent .= "\nTIME:\n" .
' ALL: ' . number_format($iTimeAll, 8) . " sec. (100%)\n" .
' CMS: ' . number_format($iTimeContent, 8) . ' sec. (' . number_format($iTimeContent / $iTimeAll * 100, 2) . "%)\n" .
' DUR: ' . number_format($iTimeLinks, 8) . ' sec. (' . number_format($iTimeLinks / $iTimeAll * 100, 2) . "%)\n";

$sContent .= "\nD-Data:\n" . durDebugVar($aDataToStore);
$sContent .= '-->';
}

$sContent = durOutputCompress($sContent);
if (defined('DUR_FIX_CONTLEN') && DUR_FIX_CONTLEN) {
header('Content-Length: ' . strlen($sContent));
}

return $sContent;
}

//ХУК ДЛЯ СКАНИРОВАНИЯ КСЕНЕЙ
/*if (strpos($_SERVER['HTTP_USER_AGENT'],'Xenu') === 0) {
$sContent = preg_replace('#src\s*=\s*[\'"]?[^\s]+[\'"]#','',$sContent);
$sContent = preg_replace('#<link[^>]*>#','',$sContent);
$robotsname = 'http://'.DUR_FIX_HTTP_HOST.'/robots.txt';
$sRobots = file_get_contents($robotsname);
$aRobots = explode("\n",$sRobots);
foreach($aRobots as $sRule) {
if (strpos($sRule,'Disallow: ') === 0) {
$sRepFrom = array('Disallow: ', '*','?');
$sRepTo = array('', '[^>]*','\?');
$sRule = str_replace($sRepFrom,$sRepTo,$sRule);
if (!strpos($sRule,'$')) $sRule.= '[^>]*';
$sContent = preg_replace('#href\s*=\s*[\'"]?\s*'.$sRule.'[\#\'"\s>]#siU','',$sContent);
$sContent = preg_replace('#href\s*=\s*[\'"]?\s*http://'.$_SERVER['HTTP_HOST'].$sRule.'[\#\'"\s>]#siU','',$sContent);
}
}
}*/

function durOtherReplacer ($sContent) {

// // закрываем от индексации внешние ссылки
// function outerlinks($matches) {
// $sEq = false; //есть ли совпадения
// $res = $matches[0];
//
// $arMassIndex = array(
// 'www.tkrus.ru',
// 'www.tidici.com',
// 'www.thermoking.com',
// );
//
// foreach($arMassIndex as $item) {
// if (preg_match('%'.quotemeta($item).'%siU',$matches[0])) {$sEq = true; break;}
// }
//
// if ($sEq){ // если совпадение нашлось
// //если отсутствует rel, то добавляем его
// if (!strpos($res, 'rel=')) {
// $res = str_replace('<a ','<a rel=nofollow ',$res);
// //$res = str_replace('<A', '<a rel="nofollow" ', $res);
// }
// }
//
// return $res;
// }
//
// //закрываем исходящие ссылки в ноиндекс и нофоллоу
// $sContent = preg_replace_callback('%<a[^>]*href=[\'"]?https?://.*</a>%siU','outerlinks',$sContent);
//
// // красивый аналог
// $sContent = preg_replace('#href="(http://(?!www\.kovea\.ru|kovea\.ru)[^"]*)"#siU','href="$1" rel="nofollow"',$sContent);

// // удаление битых ссылок
// $aDelLNK=array(
// //ссылки для удаления (img, script, a, link)
// '/test',
// );
//
// foreach($aDelLNK as $del)
// {
// $sContent = preg_replace('%<(a|script) [^>]*(href|src)\s*=\s*[\'"]?\s*[^\'"]*' . durRExpEscape ($del) . '[#\'"\s][^>]*>(.*)</(a|script)[^>]*>%siU', '$3', $sContent);
// $sContent = preg_replace('%<img [^>]*src\s*=\s*[\'"]?\s*[^\'"]*' . durRExpEscape ($del) . '[#\'"\s][^>]*>%siU', '', $sContent);
// $sContent = preg_replace('%<link [^>]*href\s*=\s*[\'"]?\s*[^\'"]*' . durRExpEscape ($del) . '[#\'"\s][^>]*>%siU', '', $sContent);
// }

// // замена внешних ссылок загружаемых ресурсов
// $aReplaceImageLink = array (
// //ссылки для замены
// 'http://www.google.ru/images/img.jpg' => '/images/img.jpg',
// );
//
// foreach ($aReplaceImageLink as $before => $after) {
// $sContent = preg_replace('%(<img [^>]*src\s*=\s*[\'"]?\s*[^\'"]*)' . durRExpEscape ($before) . '([#\'"\s][^>]*>)%siU', '$1'. $after. '$2', $sContent);
// }

return $sContent;
}

/* Подключение в начале файла

// ЧПУ ---
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/d-url-rewriter.php')) {
include_once($_SERVER['DOCUMENT_ROOT'] . '/d-url-rewriter.php');
durRun ();
}
// --- ЧПУ

/* Для поддоменов неплохо было прописывать
RewriteCond %{HTTP_HOST} ^www.(.{4,}.nickon.ru)$
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

RewriteCond %{HTTP_HOST} ^(.{4,}).nickon.ru$
RewriteRule ^robots\.txt$ robots-%1.txt [L]
*/

/* Подключение с единой точкой входа
RemoveHandler .html .htm
AddType application/x-httpd-php .php .htm .html .phtml
php_value auto_prepend_file "d-url-rewriter.php"
*/

 

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

Меня лично заинтересовала эта строчка:

define('DUR_SKIP_URLS', '#^/_?(admin|manag|bitrix|indy|cms|phpshop|varvara.php|captcha|jscripts/|modules|includes|templates|wp-admin)#siU'); //Skip URLS

Судя по всему, Demis Group использует данное решение не только с Joomla, но и в других популярных CMS, таких как Bitrix.

Но страшно не это. Страшно то, что заместо того, чтобы поменять заголовки в материалах или в шаблонах, Demis Group пишет ультра-костыль, который автоматически находит все найденные заголовки и обрабатывает их через свои preg_replace с жуткими регэкпами.

Далее, Demis Group проявила профессионализм, написав ВРУЧНУЮ файл sitemap.xml. Это при том, что в админке уже существовал компонент, который генерирует sitemap.xml автоматически из существующих пунктов меню. Интересно, оптимизатор заглядывал в админку?

Немного успокоившись от увиденного, я начал делать адаптивную версию. Но и тут меня ждал сюрприз. Дело в том, что я использую LESS-препроцессор для генерации CSS. Потому, что удобно и быстро. Догадываетесь, о чем я? Интуиция и тут не подвела. Бэкаплю текущий template.css, затем генерирую новый через LESS, делаю DIFF и что я вижу?

«Оптимизатор» проявил чудеса усердия! Он вставил переносы между каждыми правилами, после закрывающихся фигурных скобок. Честно, мне даже стало немного его жалко.

2015-05-15 13-15-13 Clipboard vs  Applications MAMP htdocs mtk-met.ru templates mtk delete-css template.css_

Естественно «оптимизатор» не знал, что такое normalize.css, поэтому свои правила он вставлял и выше и ниже и в сам normalize, который был импортирован при компиляции. При этом не обошлось без ошибок (подчеркнуты красным). Удивительно, но все браузеры переварили без проблем. 2015-05-15 13-13-12 template.css - mtk-met.ru - [ Applications MAMP htdocs mtk-met.ru]

На просьбы поменять все это безобразие, Demis Group всего лишь переподключили свои скрипты и они как-то заработали. На резонное замечание о костылях, Demis ответили, что скрипты нужны и что они выполняют важную задачу генерации заголовков. Что же, с этим сложно спорить. Все мои претензии в итоге оказались монологом со стеной. Demis Group, насколько я понял, не выгодно делать оптимизацию хорошо.

Какие выводы можно сделать из всего этого? Для себя лично я вынес вот что:

1) Если вы ведете проект как разработчик, но не занимаетесь продвижением, то имеет смысл пристально наблюдать за тем, как ведется продвижение, чтобы не столкнуться с описанным выше.

2) Всю компиляцию я делаю в Grunt, там же, отныне, использую minify для сжатия CSS и JS-файлов. Это немного уменьшит шанс того, что идиот начнет править файлы (хотя, мне попадались и такие).

UPD: Спустя пару недель, после того, как я переделал все CSS файлы в сжатые, Demis Group не постеснялись и их поменять. :/ Еще и CSS файлы, которые компилируются удалили. Действильно, зачем они нужны, если есть минифицированный? Клинический случай.

3) Рейтинг SEO компаний — пустой треп. Чем больше клиентов, тем больше текучка, качество на нуле, ответственность тоже. Я об этом догадывался, но теперь на личном примере убедился.

2015-05-15 13-52-27 ПРОДВИЖЕНИЕ САЙТОВ

2015-05-15 13-49-03 Seo-компания Demis Group

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