WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

404 заглушка для несуществующих файлов

Начну с того, что этот пост, по сути, не несет какой-либо практической пользы для сайтов уже "установленных" на сервер и полностью готовых.

Делая как-то «один сайт» я скопировал его на локалку (все кроме медиафайлов), а на сайте было много картинок: минимум две к записи плюс галереи. Получалось, что ни страница, то минимум 2-3 картинки. Для того, чтобы работать над сайтом картинки мне не нужны, поэтому их я с сервера не брал. Таким образом, при работе на локалке на каждой странице у меня было минимум 2 битые ссылки на картинки, а то и 20.

Я заметил, что чем больше картинок на странице, тем дольше грузится страница, вплоть до 10 секунд. Это стало раздражать и пришлось разобраться в причине такого безобразия. Причина оказалась в том, что каждая битая ссылка на картинку «скрыто» генерировала 404 страницу. В качестве примера можете попробовать вписать ссылку типа: http://вашдомен/kartinka.jpg и вы получите страницу с ошибкой, страницу со всем содержимым сайта, с сайдбаром(и) и прочим...

меню

Закрываем ненужные 404 страницы

Получается, чтобы сгенерировать страницу с одной битой ссылкой на файл, WordPress генерирует две страницы: саму страницу и страницу с ошибкой 404. Если на странице 2 битые ссылки, то будут созданы 3 страницы и т.д.

Конечно, на рабочем сайте битых ссылок обычно нет, поэтому и проблемы такой нет, но на локалке не грузить страницу 404, если это файл очень может пригодится. Впрочем, это может пригодится и на рабочем сайте см. ниже.

Вариант на .htaccess (рекомендую)

Эту проблему можно решить добавив следующий код в файл functions.php и сбросить правила ЧПУ:

# Добавим условия в .htaccess, которые будут выдавать 404 ответ сервера для несуществующих файлов.
# Заметка: чтобы код начал работать нужно сбросить правила перезаписи (ЧПУ).
if( is_admin() ){

	add_filter( 'mod_rewrite_rules', 'block_nonexistent_files' );
	function block_nonexistent_files( $rules ) {

		$add_rules = '
		# 404 для несуществующих файлов.
		<IfModule mod_rewrite.c>
		RewriteEngine On
		RewriteBase /
		RewriteRule ^index\.php$ - [L]
		RewriteCond %{REQUEST_FILENAME} !-f
		RewriteCond %{REQUEST_URI} !^/robots\.txt$
		RewriteCond %{REQUEST_URI} \.(php|s?htm|shtml|css|js|yml|swp|txt|jpe?g|png|gif|ico|pdf)(.*)?$
		RewriteRule . - [R=404,L]
		</IfModule>
		';

		$add_rules = trim( $add_rules );
		$add_rules = preg_replace( '/^\t+/m', '', $add_rules );

		return "\n$add_rules\n\n" . $rules;
	}
}

Чтобы убедится, что все работает пишем в браузер http://мой-домен/kartinka.jpg и видим 404 ответ:

Что делает код?

Как только запрашивается файл (страница содержащая в конце ссылки .jpg, .gif, .png, .zip...), он проверяется на физическое существование, если его нет, работа скрипта обрывается со статусом 404 и до PHP, а значит и WordPress дело вообще не доходит. Такая заглушка генерируется за доли секунды.

Задать шаблон 404 странице в этом случае можно через директиву ErrorDocument 404 /404.html и создание файла 404.html в корне сайта.

меню

Вариант на php (не рекомендую)

Код нужно вставить в самое начало файла index.php в корневой директории сайта, там где wp-config.php.

// Проверка на тип ошибки 404, если это файл не генерировать страницу,
// а просто писать об ошибке
$URIreq = $_SERVER['REQUEST_URI'];
if ( preg_match('/\.(jpg|jpeg|gif|png|zip)(\?.+)?$/', $URIreq ) ){

	$PathToFileFromRoot = $_SERVER['DOCUMENT_ROOT'].$URIreq;
	$PathToFileFromRoot = str_replace( '//', '/', $PathToFileFromRoot );
	if ( !file_exists($PathToFileFromRoot) ){
		echo "<div style='margin:100px 10% 0 10%; padding:20px; text-align:center; border:1px solid #42A6FF; background:#DEF0FF; white-space:nowrap;'>
		<b>File not found:</b> $URIreq<br>
		<b>From Page:</b> <a href='{$_SERVER["HTTP_REFERER"]}'>{$_SERVER["HTTP_REFERER"]}</a><br>
		<div style='font-size:25px; padding-top:30px;'>Go to WebSite: <a href='http://{$_SERVER['HTTP_HOST']}'>http://{$_SERVER['HTTP_HOST']}</a></div>
		</div>";
		exit();
	}
}
меню

Внимание, для уже рабочих сайтов!

Такому же эффекту подвергаются:

  1. Битые ссылки на несуществующие файлы: картинки вызываемые из css стилей и ссылки на css, js и другие файлы.
  2. Несуществующие файлы, к которым не редко обращаются различные боты-сборщики, например site.ru/absd.php.
  3. Ваши удаленные картинки, которые были скопированы и используются на других сайтах.

Поэтому, если чувствуете, что ваша страница грузится подозрительно долго, проверьте все ссылки со страницы. Я так находил по несколько битых ссылок и не раз. Для примера возьмем вот этот сайт: wordpressinside.ru, который возможно вам известен, здесь, на вскидку, я нашел как минимум 2 битые ссылки, вот они (были до написания этой статьи smile ):

  1. http://wordpressinside.ru/wp-content/plugins/simple-counters/js/sc.js.php
  2. http://wordpressinside.ru/wp-content/plugins/simple-counters/js/jquery.qtip.js
    Эти ссылки вшиты в шаблон и при генерации любой страницы, параллельно генерируется 2 страницы 404. Думаю не сложно представить насколько дольше генерируется страница, о лишних, абсолютно ненужных нагрузках на сервер я уже и не говорю...

Для решения проблемы, можно просто удалить битые ссылки - они просто не нужны...

26 комментов
Полезные 1 Вопросы 1 Все
  • Andrews32

    Проверил тестовую страницу своего сайта (с битой картинкой) в сервисе tools.pingdom.com - без кода в .htaccess и с ним. Как говорится, "найдите 10 отличий" - результат 5,5 с против 1,5 с!

    1
    Ответить31.Авг.2018 17:31 #
  • Ещё актуально для последней версии WP?

    Ответить16.Авг.2019 23:33 #
  • kolshix615 paxtoy.com

    наблюдается проблема со вхождениями по URL

    if ( preg_match('/.(jpg|jpeg|gif|png|zip)/', $URIreq ) ){

    было в url слово "a-gift-" - на что wordpress выдал вместо статьи сообщение "File not found". Такая же проблема с другими вхождениями, в итоге добавил обратный слеш, а так же php расширение - часто идет перебор уязвимостей, теперь нагрузка уменьшилась. Из-за того что вставлено расширение .php и чтоб злоумышленник не выявил присутствие файлов, поправил сообщение на "URL not found: $URIreq "

    if ( preg_match('/.(\.jpg|\.jpeg|\.gif|\.png|\.zip|\.php|\.js)/', $URIreq ) ){
    1
    Ответить6.Ноя.2019 01:39 #
    • Kama7746

      Подправил регулярку на такую, была неправильная...

      preg_match('/\.(jpg|jpeg|gif|png|zip)(\?.+)?$/', $URIreq )
      Ответить5.Мар.2020 22:12 #
  • Сергей

    Еще одно мелкое добавление.
    В списке присутствует txt - т.е. при отсутствии файла robots.txt на сервере апач не пропустит запрос к ВП и тот не сможет создать виртуальный файл robots.txt (как раз по ошибке 404) - надо этот файл исключить из обработки апачем - через еще одно условие - между filename и списком расширений

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} !^/robots.txt
    RewriteCond %{REQUEST_URI} \.(php|s?htm|shtml|css|js|yml|swp|txt|jpe?g|png|gif|ico|pdf)(\/?~?)(/?\?.*)?$
    RewriteRule . - [R=404,L]

    у меня еще добавлена конструкция
    (\/?~?) - добавляет вариант (может быть а может и не быть) на конце расширения файлов или слеш или тильду
    т.е.

    test.php/
    test.php~

    тоже роботы подборщики любят
    и еще часть расширений добавил для отпинывания апачем

    1
    Ответить20.Май.2020 00:23 #