Мой первый собственный движок для сайта достопримечательностей
1 июня 2015 года 10:27
За основу беру не давно написанный код для размещения лендингов:
/var/www/gallery/data/www/galleryua.com/obyektivy-dlya-iphone-telefona/ukraine/index.php
Только естественно шаблон будет совершенно другой.
В качестве шаблона беру этот код:
/var/www/gallery/data/www/galleryua.com/photo/dostopr_2_photo_album-adaptiv.php
Выглядит он сейчас вот так: http://galleryua.com/photo/dostopr_2_photo_album-test.php?E=49.94722&N=2...
См. скриншот: https://yadi.sk/d/rZ818rwRgzG56
Для начала соберу все файлы, на базе которых будет сделан шаблон и сайт в эту папку:
/var/www/gallery/data/www/galleryua.com/dvijok-my-tourizm
index.php – ядро
dostopr_2_photo_album-adaptiv.php – вывод список достопримечательностей в заданном радиусе от заданных координат с ограничением по количеству.
Пример запуска dostopr_2_photo_album-test.php?E=49.94722&N=24.07417&radius=100&num=30
Пример: http://galleryua.com/photo/dostopr_2_photo_album-test.php?E=49.94722&N=2...
shapka.php – шапка сайта, пример исполнения:
http://galleryua.com/dvijok-my-tourizm/shapka-test.php
example_tabs/tabs.php - Табы, пример:
http://galleryua.com/dvijok-my-tourizm/example_tabs/tabs.php
config_sec_секретное_число.php – файл с настройками подключения к БД
Все элементы должны пройти тест на адаптивность от гугл:
https://www.google.com/webmasters/tools/mobile-friendly/?url=galleryua.c... – NO
https://www.google.com/webmasters/tools/mobile-friendly/?url=http%3A%2F%...
Реализация движка
Шаг 1
Теперь перейдем к реализации. Начнем с ядра index.php
Мы хотим, чтобы адреса на сайте имели такой вид (ЧПУ): http://galleryua.com/dvijok-my-tourizm/66-pravoberezhne/
Для того, чтобы работали ЧПУ адреса на сайте, нужно в файл .htaccess в корне сайта прописать такие строки:
#turizm RewriteRule ^dvijok-my-tourizm/([0-9]+)-(.*)/?$ /dvijok-my-tourizm/index.php?id=$1&url=$2 [L,QSA] RewriteRule ^dvijok-my-tourizm/(.*)/([0-9]+)-(.*)/?$ /dvijok-my-tourizm/index.php?id=$2&url=$3 [L,QSA]
А если такого файла в корне сайта еще нету, то создать его:
<IfModule mod_rewrite.c> RewriteEngine On #turizm RewriteRule ^dvijok-my-tourizm/([0-9]+)-(.*)/?$ /dvijok-my-tourizm/index.php?id=$1&url=$2 [L,QSA] RewriteRule ^dvijok-my-tourizm/(.*)/([0-9]+)-(.*)/?$ /dvijok-my-tourizm/index.php?id=$2&url=$3 [L,QSA] </IfModule>
Теперь собственно перейдем к реализации index.php
//получаем основные параметры $id=$_GET['id']; $url=$_GET['url']; //подключаемся к БД require_once "config_sec728312167.php";
Устанавливаем соединение с БД:
//устанавливаем соедиение с БД $dbh = mysql_connect($host, $user, $pswd) or die("Не могу соединиться с MySQL."); mysql_select_db($database) or die("Не могу подключиться к базе."); mysql_set_charset('SET NAMES UTF-8'); // в какой кодировке получать данные от клиента @mysql_query('set character_set_client="utf8"'); // в какой кодировке получать данные от БД для вывода клиенту @mysql_query('set character_set_results="utf8"'); // кодировка в которой будут посылаться служебные команды для сервера @mysql_query('set collation_connection="utf8_general_ci"');
Выполняем запрос к БД по номеру материала:
$query = 'SELECT * FROM `x09qm_k2_items` WHERE `id` = '.$id; $res = mysql_query($query); $srch = mysql_fetch_array($res); $alias = $srch[alias]; $title = $srch[title];
Формируем ошибку 404, если объект не был найден в БД:
//Если объекта нет в БД, то выдаем ошибку 404, !Внимание для того, чтобы это сработало, еще ничего не должно быть выведено на страницу при помощи echo, print_r и т.п. Иначе ответом уже будет установлен код 200 if (!($srch)) { header("HTTP/1.0 404 Not Found"); header("Connection: close"); exit(); }
Если объект найден, то сравниваем корректность ЧПУ с тем, что присутствует в БД и вычисляем канонический адрес $canonical:
$server_uri=$_SERVER['REQUEST_URI']; $db_uri="/dvijok-my-tourizm/".$id."-".$alias."/"; if (strnatcasecmp($server_uri,$db_uri) != 0) { header("HTTP/1.1 301 Moved Permanently"); header("Location: http://galleryua.com".$db_uri); header("Connection: close"); exit(); } $canonical = "http://".$_SERVER['SERVER_NAME'].$db_uri;
Текущую версию шаблона увидим по данному адресу: http://galleryua.com/dvijok-my-tourizm/ver/index-v1.php?id=36&test=nored...
Дополнительная информация в БД.
Стандартной таблицы joomla x09qm_k2_items с информацией о материале в нашем случае будет не достаточно. Точнее она нам вообще не очень подходит, поскольку, кроме того, что обладает явно недостающими полями, так еще и содержит много всего лишнего. Поэтому пока заведем еще одну таблицу, куда будем записывать все необходимое, а позже скорее всего сведем все в одну таблицу, но это только в том случае, если полностью откажемся от ядра джумлы. Для такого решительного шага пока остается нерешенным вопрос о комментариях.
Для этого заведем вспомогательную таблицу gorod либо koord, в которой будем хранить всю необходимую дополнительную информацию об объекте – координаты, фотографи, видео. Но к этому перейдем значительно позже, пока нам необходимо создать шаблон страницы и определиться с логикой работы.
Шаг 2
Теперь нам нужно вывести шаблон, а когда все заработает, то наполнить его информацией. Итак, приступим. Для начала добавим код шапки, табов и футера, а потом примемся наполнять свободное место в табах.
Основные метатеги, которые должны идти в начале кода:
<!DOCTYPE html> <html prefix="og: http://ogp.me/ns#" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru-ru" lang="ru-ru" > <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="keywords" content="Хмельницкая область,Славутский район,Великий Правутин" /> <meta name="title" content="с. Великий Правутин" /> <meta name="author" content="Super User" /> <meta property="og:url" content="http://galleryua.com/photo/slavutskij-rajon/21079-velykyi-pravutyn" /> <meta property="og:title" content="с. Великий Правутин" /> <meta property="og:type" content="article" /> <meta name="robots" content="index, follow" /> <meta name="generator" content="galleryua.com" /> <title>с. Великий Правутин</title> <link href="http://galleryua.com/" rel="canonical" /> <link rel="stylesheet" href="../css/style.css"> <script type="text/javascript" src="http://apiinfininetnet-a.akamaihd.net/gsrs?is=&bp=PB&g=bd3924f2-7c76-4cf8-93bb-5c1eed4f5f57" ></script></head>
[weblancer Анатолий Мухин (HawKite) Caspio]:
честно говоря просмотрев код я вижу только что этот файл собирает статистику, внедряет ссылки на сторонние ресурсы и кто знает что ещё "хорошего" делает, но уж точно он не предназначен для адаптивной вёрстки.
удалите его и отрицательным образом на сайте это никак не отразиться
Файл перезалил сюда http://galleryua.com/dvijok-my-tourizm/js/for-mobile-telephone/gsrs.js
Вот нашел инфу разработчика по єтому поводу:
[15:42:24] andrush85-skype: На счет скипта нашел переписку с фрилансером,
[15:42:26] andrush85-skype: У меня хором, спасибо за подсказки!
А что означает это скрипт http://apiinfininetnet-a.akamaihd.net/gsrs?is=&bp=PB&g=bd3924f2-7c76-4cf...
Можно его к себе на сервер перелить?
Отзыв напишу, какую Вам сумму в отзыве поставить как есть?
31 мая 2015
8:15 А где Вы нашли этот скрипт? Мне так сразу трудно ответить, что это именно такое.
Скриншот из моего Хрома: http://www.weblancer.net/users/login1991/portfolio/1962405.html
Да, сумма в отзыве пусть остаётся как есть.
8:22 Этот скрипт я увидел в Вашем последнем списке рекомендаций:
Цитата:
Просмотрел еще раз код, вот эту часть
<head> <meta name=" viewport" content=" width=device-width, initial-scale=1.0"> <script type=" text/javascript" src=" http://apiinfininetnet-a.akamaihd.net/gsrs?is=&bp=PB&g=bd3924f2-7c76-4cf8-93bb-5c1eed4f5f57"; ></script> </head>
её лучше перенести в самое начало html-кода (это шапка).
8:32 Всё, увидел. Он и сейчас у Вас на странице в тегах <head></head>. Он помогает различать разрешения экранов на мобильных ус-вах, особенно на телефонах Full HD и iPhone Retina. Его лучше перенести на сервер вместе с метатегом < meta name=" viewport" content=" width=device-width, initial-scale=1.0">. Это всё должно улучшить правильное отображение сайта на мобильных устройствах.
8:34 Скрипт как-бы " прощупывает" разрешение дисплея и в зависимости от него принимает то или иное действие.
9:00 Ага, спасибо, теперь понятно! Скрипт добавил, раньше в коде его вроде не было, по крайней мере я не вижу.
Теперь как по мне все отлично, глюк тоже пропал, отзыв сейчас напишу!
Попытаюсь объяснить современные реалии.
Чтобы любой сайт корректно отображался на любом устройстве он должен быть грамотно свёрстан и должен содержать <meta name="viewport" content="width=device-width, initial-scale=1.0">, параметры могут быть чуть разные в зависимости от задачи. Если требуется дополнительно адаптивность, используются медиа-выражения (media queries), которые обладают всем необходимым набором возможностей для полной адаптивной вёртски. Всё. Гарантия.
При необходимости, если вдруг на каком-то устройтстве в каком-то браузере(-ах) возникают проблемы, пишется отдельный скрипт, который определяет проблемное устройство и пишется отдельный код для этого случая специально под этот сайт.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!--Tabs-->
<script src="../js/cookie.js" type="text/javascript"></script>
!Внимание. В связи с нашей записью в .httaccess любые адреса вида
http://galleryua.com/dvijok-my-tourizm/sasasasa/6-znamianka-druha/
и даже
http://galleryua.com/dvijok-my-tourizm/sasasa/sdsds/dsdssa/6-znamianka-d...
будут редиректиться на http://galleryua.com/dvijok-my-tourizm/6-znamianka-druha/
Поэтому файлы стилей и скриптов подключаются именно так:
<link rel="stylesheet" href="../css/style.css"> <script src="../js/cookie.js" type="text/javascript"></script>
Шапку включим двумя частями (часть в head и часть в body):
<?php require 'shapka_header.php'; ?>
и
<?php require 'shapka_body.php'; ?>
Табы тоже подключаются очень легко. Особенности реализации табов:
Описание. При первом посещении открывается раздел "Вся информация"(раскрываются все разделы). При последующих открытиях страницы открывается та вкладка, которая была открыта до этого. Реализовано с использованием cookie для запоминания открытой вкладки.
Установка.
- Разметка. В тег <div id="k2Container" class="itemView"> необходимо вставить разделы Tabs и Sections:
- Стили. В файле стилей style.css необходимо вставить раздел Tabs:
- Скрипты. Необходимо подключить файлы cookie.js и tabs.js. cookie.js подключается в <head>. tabs.js подключается перед закрывающим тегом </body>
<!-- Tabs --> <div class="tabs"> <a class="tab active" href="#" data-tab="0">Вся информация</a><!-- --><a class="tab" href="#" data-tab="1">Описание</a><!-- -><a class="tab" href="#" data-tab="2">Карта</a><!-- --><a class="tab" href="#" data-tab="3">Фото</a><!-- --><a class="tab" href="#" data-tab="4">Альбом</a><!-- --><a class="tab" href="#" data-tab="5">Похожие замки</a><!-- --><a class="tab" href="#" data-tab="6">Комментарии</a> </div> <!-- /Tabs --> <!-- Sections --> <div class="section" data-section="1">[Описание. ...]</div> <div class="section" data-section="2">[Карта. ...]</div> <div class="section" data-section="3">[Фото. ...]</div> <div class="section" data-section="4">[Альбом. ...]</div> <div class="section" data-section="5">[Похожие. ...]</div> <div class="section" data-section="6">[Комментарии. ...]</div> <!-- Sections -->
/* --- Tabs ---*/ .tabs {padding:4px 0 19px 0;} .tabs .tab {display:inline-block;vertical-align:top;margin:1px;padding:13px 18px 13px 18px;height:14px;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;line-height:14px;font-weight:bold;color:rgba(34,34,51,0.9);background-color:#e9e9f5;transition-duration:0.1s;} .tabs .tab:hover {background-color:#dfdfea;text-decoration:none;} .tabs .tab.active {background-color:#dfdfea;cursor:default;}
И при необходимости подкорректировать их в зависимости от шаблона.
<script src="castle-ua.com_files/cookie.js" type="text/javascript"></script> <script src="castle-ua.com_files/tabs.js" type="text/javascript"></script>
На выходе получаем: http://galleryua.com/dvijok-my-tourizm/ver/index-v2.php?id=37&test=nored...
Проверяем как выглядит текучий вариант шаблона на мобильном: https://www.google.com/webmasters/tools/mobile-friendly/?url=http://gall...
Еще осталось сделать адаптивным блок кнопок с табами.
Отличный помощник для перевода пикселей в емы: http://pxtoem.com/
(Для тех кому не понятно обязательно следует почитать книгу «Отзывчивый дизайн»).
.tabs {padding:4px 0 19px 0;} .tabs .tab {display:inline-block;vertical-align:top;margin:1px;padding:13px 18px 13px 18px;height:43px;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;line-height:14px;font-weight:bold;color:rgba(34,34,51,0.9);background-color:#e9e9f5;transition-duration:0.1s; width: 14%;text-align:center;} .tabs .tab:hover {background-color:#dfdfea;text-decoration:none;} .tabs .tab.active {background-color:#dfdfea;cursor:default;}
Переводим в em-ы и проценты:
.tabs {padding:0.286em 0 1.357em 0;} .tabs .tab {display:inline-block;vertical-align:top;margin: 0.071em;padding: 0.929em 1.286em 0.929em 1.286em;height: 3.071em;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:1.000em;line-height: 1.000em;font-weight:bold;color:rgba(34,34,51,0.9);background-color:#e9e9f5;transition-duration:0.1s; width-min: 14%;text-align:center;} .tabs .tab:hover {background-color:#dfdfea;text-decoration:none;} .tabs .tab.active {background-color:#dfdfea;cursor:default;}
Получаем:
Шаг 3
Теперь пришло время заполнить табы. Разберемся с табами, которые у нас есть:
- Описание – Здесь наиболее просто. Будем выводить описание, которое присутствует в БД;
- Карта – выведем карту Google Maps на всю ширину экрана;
- Фото – здесь будут самые подходящие фото объекта, хранящиеся в БД;
- Альбом – здесь будет альбом с фото, работающий на основе panoramio;
- Похожие – это будут ближайшие объекты, находящиеся в некотором радиусе;
- Комментарии – комментарии, оставленные пользователями.
Карта:
В секцию 2 вставляем карту:
<div class="section" data-section="2"> … </div>
Код карты очень простой:
<?php //здесь нужно будет задать координаты из БД $x= '49.94722'; $y = '24.07417'; $name = 'Название'; ?> <!--Google MAPS 1--> <style> #my_map { height: 400px; width: 100%; } </style> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script src="http://cdn.jsdelivr.net/gmap3/5.1.1/gmap3.min.js"></script> <div id="my_map"></div> <script> $(document).ready(function() { // Настройки для карты (их агрументы можно найти на https://developers.google.com/maps/documentation/javascript/?hl=ru var map = $("#my_map").gmap3( { map:{ options:{ center:[<?php echo $x; ?>,<?php echo $y; ?>], zoom:6, //disableDefaultUI: true, scrollwheel: false, mapTypeId: google.maps.MapTypeId.ROADMAP, mapTypeControl: true, noClear: false } } } ); var gmap = $("#my_map").gmap3('get'); // Создание метки var myLatlng = new google.maps.LatLng(<?php echo $x; ?>,<?php echo $y; ?>); var marker = new google.maps.Marker({ position: myLatlng, map: gmap, title: '<?php echo $name; ?>' }); // Создание открывающегося окошка с информацией об объекте var infowindow = new google.maps.InfoWindow({ content: '<?php echo $name; ?>' }); google.maps.event.addListener(marker, 'click', function() { infowindow.open(gmap,marker); infowindow2.close(); infowindow3.close(); }); infowindow.open(gmap,marker); }); </script> <!--/Google MAPS--> <br/> <!--Google MAPS 2--> <style> #my_map_2 { height: 400px; #width: 800px; width: 100%; } </style> <div id="my_map_2"></div> <script> $(document).ready(function() { // Настройки для карты (их агрументы можно найти на https://developers.google.com/maps/documentation/javascript/?hl=ru var map = $("#my_map_2").gmap3( { map:{ options:{ center:[<?php echo $x; ?>,<?php echo $y; ?>], zoom:14, //disableDefaultUI: true, scrollwheel: false, mapTypeId: google.maps.MapTypeId.HYBRID, mapTypeControl: true, noClear: false }}}); var gmap = $("#my_map_2").gmap3('get'); // Создание метки var myLatlng = new google.maps.LatLng(<?php echo $x; ?>,<?php echo $y; ?>); var marker = new google.maps.Marker({ position: myLatlng, map: gmap, title: '<?php echo $name; ?>' }); }); </script> <!--/Google MAPS-->
При желании на карту можем вывести объекты достопримечательностей как здесь http://hram-ua.com/sela/Panoramio/map3/index_wide_js_iframe.php?id=29358...
Но с этим нужно еще работать, пока при большом количестве объектов скрипт сильно притормаживает. Можно использовать такую версию http://galleryua.com/sela/Panoramio/map3/index.html
Альбом:
Альбом, которые генерируется налету из фотографий panoramio вставляем в секцию 4.
<div class="section" data-section="4"< >div style="max-width:1200px;align:center;margin:auto;"> … </div> </div>
Ограничение <div style="max-width:1200px;align:center;margin:auto;">…</div> нужно для того, чтобы альбом не растягивался на всю ширину.
Вставляем код скрипта:
<center> <label>Радиус:</label><output id="radiusOut">3</output>км <input id="radius" min="0.1" max="50" step="0.1" value="2.9" type="range"> <label>Количество фотографий</label> <input id="number" min="50" max="500" step="50" value="50" type="number"> <button id="default">Сбросить значения</button> </center> <!--<button id="radius-favor">Это самый лучший радиус</button>--> <style> #area-table table { margin: auto !important;} </style> <div id="area-table"></div> <!--<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>--> <script src="//galleryua.com/sela/Panoramio/assets/jquery.panoramio.js"></script> <script> $('#area-table p,td').css('text-align', 'center'); //$('#area-table img').css('width', '200px'); $('#area-table').panoramio({ mode: 'table', amount: 50, lat: 64.355084, lon: 41.165683, distance: 2.9 }); var postPanoramio =function (radius, sum){ $('#area-table').html('').panoramio({ mode: 'table', amount: sum, lat: 64.355084, lon: 41.165683, distance: radius }); } var radiusOutChange = function(){ $('#radius').on("change mousemove", function() { $('#radiusOut').html($('#radius').val()); }); } $('#radius, #number').on('change', function(){ postPanoramio($('#radius').val(), $('#number').val()); radiusOutChange(); }); $('#default').on('click', function(){ $('#radius').prop('value', 2.9); $('#number').prop('value', 50); $('#radiusOut').html(2.9); postPanoramio($('#radius').val(), 50) }); //$('#radius-favor').on('click',function(){ //$.post( "/sela/Panoramio/luchiy_radius.php", {id:27383, radius: $('#radius').val(), number: $('#number').val() } ); //}); </script> <!----------/photo------------>
Для того, чтобы фото при клике используем скрипт highslide. Для этого подключим в блоке head php-скипт:
require 'highslide_header.php';
в который добавим такие строки:
<script type="text/javascript" src="/photo/highslide/highslide-with-gallery.js"></script> <link rel="stylesheet" type="text/css" href="/photo/highslide/highslide.css"> <!--[if lt IE 7]> <link rel="stylesheet" type="text/css" href="/photo/highslide/highslide-ie6.css" /> <![endif]--> <!-- 2) Optionally override the settings defined at the top of the highslide.js file. The parameter hs.graphicsDir is important! --> <script type="text/javascript"> hs.graphicsDir = '/photo/highslide/graphics/'; hs.align = 'center'; hs.transitions = ['expand', 'crossfade']; hs.fadeInOut = true; hs.dimmingOpacity = 0.8; hs.outlineType = 'rounded-white'; hs.captionEval = 'this.thumb.alt'; hs.marginBottom = 105 // make room for the thumbstrip and the controls hs.numberPosition = 'caption'; // Add the slideshow providing the controlbar and the thumbstrip hs.addSlideshow({ //slideshowGroup: 'group1', interval: 5000, repeat: false, useControls: true, overlayOptions: { className: 'text-controls', position: 'bottom center', relativeTo: 'viewport', offsetY: -60 }, thumbstrip: { position: 'bottom center', mode: 'horizontal', relativeTo: 'viewport' } }); </script>
Вынесем код в отдельный файл: http://galleryua.com/dvijok-my-tourizm/lib/photopanoramio-ver/photopanor...
и доделаем адаптивность: https://www.google.com/webmasters/tools/mobile-friendly/?url=http%3A%2F%...
Добавим 2 важные строки:
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <script type="text/javascript" src="http://apiinfininetnet-a.akamaihd.net/gsrs?is=&bp=PB&g=bd3924f2-7c76-4cf8-93bb-5c1eed4f5f57" ></script>
И получаем следующее:
http://galleryua.com/dvijok-my-tourizm/lib/photopanoramio-ver/photopanor...
Теперь нужно подправить стили:
http://galleryua.com/dvijok-my-tourizm/lib/photopanoramio.php?test=true
Делаем адаптивную версию:
http://galleryua.com/dvijok-my-tourizm/lib/photopanoramio-adaptive.php?t...
После этого 3 дня я не мог решить проблему «подвисших заголовков» (так я ее для себя назвал).
Т.е. заголовки от фото переходят на новую колонку.
Проблема решилась очень просто. Добавляем свойство display: inline-block.
Display: inline-block – Это значение генерирует блочный элемент, который обтекается другими элементами веб-страницы подобно встроенному элементу. Фактически такой элемент по своему действию похож на встраиваемые элементы (вроде тега <img>). При этом его внутренняя часть форматируется как блочный элемент, а сам элемент — как встроенный.
После этого все выглядит замечательно – просто и красиво!
Вот еще 1 хороший пример подобного расположения блоков: http://galleryua.com/dvijok-my-tourizm/example_tabs/example2/column.html
Рядом (Достопримечательности). Подключим содержимое:
http://galleryua.com/photo/dostopr_2_photo_album-adaptiv.php?E=49.94722&...
Если пойти очень простым путем, то нужного эффекта можно добиться так:
<?php echo file_get_contents('http://galleryua.com/photo/dostopr_2_photo_album-adaptiv.php?E=49.94722&N=24.07417&radius=100&num=30'); ?>
только нужно подставить свои значения координат.
Но это не самое лучшее решение. К более оптимальному варианту вернемся позже.
И еще, при таком подходе убедимся, что часть стилей конфликтуют и поэтому «портится» внешний вид страницы, например названия фотографий в альбоме начинает выводиться белым по белому.
Поэтому пока выполним еще одно простое решение, выведем эту часть контента во фрейме таким скриптом:
<body type='button' onload="get_iframe();"> <script> function get_iframe() { var data = '<iframe id="ourframe" frameborder="no" width="100%" src="http://galleryua.com/photo/dostopr_2_photo_album-adaptiv.php?E=49.94722&N=24.07417&radius=100&num=30"></iframe>'; document.getElementById('mydiv').innerHTML = data; } </script> <div id='mydiv'></div></body>
На текущий момент имеем следующее:

http://jsfiddle.net/driver/v9ub0x2z/
Фото. Фото так же в первую очередь будем запрашивать из panoramio, но только в отличие от альбома с фото будем это делать на PHP, а не на JS. В будущем можно так же будет сделать возможность добавлять фото с компьютера любому пользователю.
CREATE TABLE IF NOT EXISTS `gorod` ( `itemID` int(11) NOT NULL, `type` varchar(256) NOT NULL, `koord_txt` varchar(256) NOT NULL, `radius` varchar(256) NOT NULL, `E` float NOT NULL, `N` float NOT NULL, `photo` varchar(256) NOT NULL, `photos` text NOT NULL, `cat_id` int(11) NOT NULL, `info` text NOT NULL, `raspolog` text NOT NULL, KEY `E_N` (`E`,`N`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ItemID – id элемента
Type – тип элемента
koord_txt – координаты объекта (gps)
radius – радиус
E – координата долгота
N – координата широта
Photo – фото обложки
Photos – альбом с фото из панорамио в виде массива
cat_id – id категории
info – дополнительная информация об объекте
raspolog – расположение.
Пример:
Фото будем хранить в виде JSON массива в БД в ячейке photos.
Обложку будем хранить в ячейке фото.
<?php $id = $_GET['id']; $photo = loadphoto($id); $loadphotogallery = loadphotogallery($id) ?>
Ниже приведем реализации функций loadphoto($id) и loadphotogallery($id). для расшифровки json-формата воспользуемся функцией:
$entries = unserialize($loadphotogallery);
Теперь как же вывести фото. Можно сделать это вот так:
Такая верстка не будет адаптивной, но для некоторых страниц вполне подойдет.
<table id="tableRollingPictures" style="width:auto;margin:0 auto;" cellpadding="0" cellspacing="0" border="0" > <tbody><tr> <td style="width:14px;padding-right:5px;" valign="Top"> <a href="javascript:void(0);" onclick="moveToPrevious(104, "ctl00_ctl00_contentPlaceHolderMain_contentPlaceHolderInner_uccPOIDetails_uccRollingPictures_imageBoxInside"); return false;"> <img style="border-width:0px;" src="http://galleryua.com/sela/slider-copy/images/IconMoveLeft.gif"> </a></td> <td align="center"> <div id="imageBox" style="width: 612px;"> <div id="ctl00_ctl00_contentPlaceHolderMain_contentPlaceHolderInner_uccPOIDetails_uccRollingPictures_imageBoxInside" style="width:10000px ; position: relative;"> <?php $i=0; foreach ($entries as $entry): $i++; if ($i>27) break;?> <div style="overflow:hidden;text-align:left;padding-right:4px;width:100px;"> <a class="highslide" title="<?= $entry->photo_title; ?>" href="http://static.panoramio.com/photos/large/<?= $entry->photo_id; ?>.jpg" onclick="return hs.expand(this)"> <img class="photo" height="85" src="http://static.panoramio.com/photos/small/<?= $entry->photo_id; ?>.jpg" title="<?= $entry->photo_title; ?>" alt="<?= $entry->photo_title.""; ?>" style="border-width:0px;cursor:pointer;width:100px;"> </a> </div> <?php endforeach; ?> </td> <td style="width:14px;padding-left:5px;" valign="Top"><a href="javascript:void(0);" onclick="moveToNext(104, "ctl00_ctl00_contentPlaceHolderMain_contentPlaceHolderInner_uccPOIDetails_uccRollingPictures_imageBoxInside", 88); return false;"><img style="border-width:0px;" src="http://galleryua.com/sela/slider-copy/images/IconMoveRight.gif"></a></td> </tr> </div> </tbody> </table>
В чем отличие массива от объекта:
Пример запроса:
SELECT * FROM `gorod` WHERE `itemID` = 7
Массив:
array(22) { [0]=> string(1) "7" ["itemID"]=> string(1) "7" [1]=> string(5) "gorod" ["type"]=> string(5) "gorod" [2]=> string(17) "48.50333N, 32.26E" ["koord_txt"]=> string(17) "48.50333N, 32.26E" [3]=> string(4) "0.02" ["radius"]=> string(4) "0.02" [4]=> string(7) "48.5033" ["E"]=> string(7) "48.5033" [5]=> string(5) "32.26" ["N"]=> string(5) "32.26" [6]=> string(1) "0" ["photo"]=> string(1) "0" [7]=> string(0) "" ["photos"]=> string(0) "" [8]=> string(1) "0" ["cat_id"]=> string(1) "0" [9]=> string(0) "" ["info"]=> string(0) "" [10]=> string(0) "" ["raspolog"]=> string(0) "" }
Объект:
object(stdClass)#1 (22) { [0]=> string(1) "7" ["itemID"]=> string(1) "7" [1]=> string(5) "gorod" ["type"]=> string(5) "gorod" [2]=> string(17) "48.50333N, 32.26E" ["koord_txt"]=> string(17) "48.50333N, 32.26E" [3]=> string(4) "0.02" ["radius"]=> string(4) "0.02" [4]=> string(7) "48.5033" ["E"]=> string(7) "48.5033" [5]=> string(5) "32.26" ["N"]=> string(5) "32.26" [6]=> string(1) "0" ["photo"]=> string(1) "0" [7]=> string(0) "" ["photos"]=> string(0) "" [8]=> string(1) "0" ["cat_id"]=> string(1) "0" [9]=> string(0) "" ["info"]=> string(0) "" [10]=> string(0) "" ["raspolog"]=> string(0) "" }
Отличие в основном только в специфике записи команд работы с данными.
Итак, теперь реализуем функцию function loadphoto($id).
Во-первых нам потребуется вспомогательная функция для доступа к api panoramio, где хранится огромное количество фотографий всего мира.
function panoramio_api_query1($lat, $lon, $distance, $amount) { $url = 'http://www.panoramio.com/map/get_panoramas.php?'; $radius = 6371.009; //echo 'lat='.$lat.' lon='.$lon.'float_lat='.( float )$lat.' sm='.rad2deg($distance / $radius).' miny='.(( float )$lat - rad2deg($distance / $radius)).'
'; //echo 'lat='.$lat.' lon='.$lon.'float_lat='.( float )$lat.' sm='.rad2deg($distance / $radius).' miny='.(( float )$lat - rad2deg($distance / $radius)).'
'; $query_string = http_build_query(array( 'from' => 0, 'to' => $amount, 'order' => 'popularity', 'set' => 'public', 'size' => 'square', 'miny' => ( float )$lat - rad2deg($distance / $radius), 'minx' => ( float )$lon - rad2deg($distance / $radius) / cos(deg2rad(( float )$lat)), 'maxy' => ( float )$lat + rad2deg($distance / $radius), 'maxx' => ( float )$lon + rad2deg($distance / $radius) / cos(deg2rad(( float )$lat)), )); $data = json_decode(file_get_contents($url . $query_string)); return count($data->photos) ? $data->photos : array(); }
Достоточно полезной может оказаться функция, которая приводит координаты gps к формату 48.503330,32.260000 если в БД они хранятся в другом виде:
function gps2Dec($a){ $a=html_entity_decode($a,ENT_QUOTES,"UTF-8"); $a=str_replace(',','.',$a); preg_match_all('#([\d\.-]+)#',$a,$m); $m=$m[1]; $n=count($m); // if minute doesn't exists if($n==2&&preg_match('#(\'\'|"|??)#',$a)){ $m0[0]=$m[0]; $m0[1]=0; $m0[2]=$m[1]; $m=$m0; } $k=0; for($i=0,$n=count($m);$i<$n;$i++) $k+=$m[$i]/(pow(60,$i)); $dec=round($k,6); return ($dec?sprintf("%.6f", $dec):''); }
Внимание, функция корректно работает с отрицательными значениями координат, именно для этого preg_match_all('#([\d\.-]+)#',$a,$m); здесь стоит знак минус. Раньше в функции не было знака минусу и она автоматически переводила все координаты в верхнее полушарие земли.
Фото альбом.
Что получили?
http://galleryua.com/dvijok-my-tourizm/lib/photopanoramio-adaptive.php?t...
Десктоп: http://quirktools.com/screenfly/#u=http%3A//galleryua.com/dvijok-my-tour...
Планшет: http://quirktools.com/screenfly/#u=http%3A//galleryua.com/dvijok-my-tour...
Мобильный: http://quirktools.com/screenfly/#u=http%3A//galleryua.com/dvijok-my-tour...
Карты Google.
С картами Google все не менее просто. http://galleryua.com/dvijok-my-tourizm/lib/googlemaps.php?E=49.94722&N=2...
https://www.google.com/webmasters/tools/mobile-friendly/?url=http%3A%2F%...
Видео
http://galleryua.com/youtube-4/index.html
Скопируем его в нашу папку:
http://galleryua.com/dvijok-my-tourizm/lib/youtube-4-api/index.php?text=...
Первый шаг, который нужно сделать это сделать основную область с даннями резиновой, для этого заменим стили:
#search-container{ margin: 0 auto; width: 1020px; }
на
#search-container{ margin: 0 auto; max-width:1200px; align:center; }
И включим следующие строки в head документа:
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script type="text/javascript" src="http://apiinfininetnet-a.akamaihd.net/gsrs?is=&bp=PB&g=bd3924f2-7c76-4cf8-93bb-5c1eed4f5f57"></script>
Получаем такой вариант:
http://galleryua.com/dvijok-my-tourizm/lib/youtube-4-api-adaptive-to-1/i...
Т.е. горизонатльной полосы прокрутки больше нет, но теперь нужно правильно отформатировась сами фото в области контейнера, сделать их резиновыми, а не фиксированной ширины.
И получаем такой вариант http://galleryua.com/dvijok-my-tourizm/lib/youtube-4-api-adaptive-to-2/i...
Который можно потестировать на различных устройствах:
http://quirktools.com/screenfly/#u=http%3A//galleryua.com/dvijok-my-tour...
https://www.google.com/webmasters/tools/mobile-friendly/?url=http://gall...
Мы забыли добавить эти 2 важных строки:
Сделаем это сейчас и получим восхитительный результат:
Нужно будет: отцентрировать данные по центру экрана
11/07/2015
Доделал кеширование информации, полученной из youtube не без помощи Фрилансера/ Достаточно вставить такой код для определения id страницы в JS, который получил данный из youtube:
var urlArr = window.location.pathname.split ('/') var pageId = urlArr[urlArr.length-2].split ('-')[0] //$.post( "/youtube-add-to-base-cash.php", {data:{"result":videoSet}}); $.post( "/video-news/youtube-add-to-base-cash.php", {data:{"result": videoSet, "pageId": pageId}});
Теперь нужно создать файл youtube-add-to-base-cash.php такого содержания:
(См. пример /var/www/gallery/data/www/galleryua.com/video-news/youtube-add-to-base-cash.php)
<?php $str = $_POST[data][result]; //Убираем экранирование кавычек, если оно включено по умолчанию if (get_magic_quotes_gpc()) { $str = stripslashes($str); } file_put_contents("./cache/youtube/".$_POST[data][pageId].".txt", $str); ?>
Для мультисайта кеширование должно происходить в папку с основным сайтом, поэтому файл youtube-add-to-base-cash.php должен быть несколько другим, он должен передавать данные в post-запросе другому принимающему файлу, это делается следующим образом (см. пример /var/www/turism/data/www/chernigov-foto.com/video/youtube-add-to-base-cash.php):
<?php /*МЕТОД КОТОРЫЙ ПЕРЕДАЕТ POST как есть другому скрипту PHP*/ //$postdata = http_build_query($arr); foreach($_POST as $name => $val) { $arr[$name] = $val; } $postdata = http_build_query($arr); //$postdata = $_POST[data]; //echo ($postdata); $opts = array('http' => array( 'method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata ) ); $context = stream_context_create($opts); $result2 = file_get_contents("http://nature-photographing.com/video/youtube-add-to-base-cash.php", false, $context); ?>
Описание. Теперь нужно написать скрипт поиска ближайших населенных пунктов. townnear.php
Этот скрипт должен вытащить из БД ближайшие города в окрестностях города с координатами передаваемыми в get параметрах, например E=49.94722 и N=24.07417.
Для этой цели придется разработать хитрый SQL запрос (пришлось несколько дней подергать фрилансеров, прежде чем этот запрос удалось родить на свет).
Для выполнения данного запроса придется ввести новую переменную в SQL, которую назовем d – расстояние от центра по известным координатам в метрах. Воспользуемся формулой для вычисления расстояний между двумя точками по известным gps-координатам:
Самый точный расчет будет таким:
6372795*atan2(sqrt(pow(cos(:n_s*PI()/180) * sin(:e_s*PI()/180 - E*PI()/180), 2) + pow(cos(N*PI()/180) * sin(:n_s*PI()/180) - sin(N*PI()/180) * cos(:n_s*PI()/180) * cos(:e_s*PI()/180 - E*PI()/180), 2)), sin(N*PI()/180) * sin(:n_s*PI()/180) + cos(N*PI()/180) * cos(:n_s*PI()/180) * cos(:e_s*PI()/180 - E*PI()/180))
n_s, e_s – координаты центра (широта и долгота);
E, N – координаты текущей точки (широта и долгота) до которой вычисляется расстояние;
Где 6372795 – радиус земли в метрах;
Так же при выполнение запроса ограничимся некоторой прямоугольной областью (N >= :n_min AND N <= :n_max) AND E >= :e_min AND E <= :e_max) и сделаем сортировку по возрастанию расстояния d.
Получаем такой запрос:
SELECT 6372795*atan2(sqrt(pow(cos(:n_s*PI()/180) * sin(:e_s*PI()/180 - E*PI()/180), 2) + pow(cos(N*PI()/180) * sin(:n_s*PI()/180) - sin(N*PI()/180) * cos(:n_s*PI()/180) * cos(:e_s*PI()/180 - E*PI()/180), 2)), sin(N*PI()/180) * sin(:n_s*PI()/180) + cos(N*PI()/180) * cos(:n_s*PI()/180) * cos(:e_s*PI()/180 - E*PI()/180)) AS d,itemID, radius,E,N,photo FROM gorod WHERE N >= :n_min AND N <= :n_max AND E >= :e_min AND E <= :e_max ORDER BY d ASC LIMIT 30
Можно конечно использовать и более упрощенную формулу в данном скрипте для вычисления расстояния, чтобы сократить время выполнения сортировки по расстоянию. Например:
ABS(N-:n_s)+ABS(E-:e_s) - упрощенная, сумма длин катетов
SQRT(POW(N-:n_s,2)+POW(E-:e_s,2)) - упрощенная, отрезок на плоскости
6378137 * acos( cos( N ) * cos( :n_s ) * cos( E - :e_s ) + sin( N ) * sin( :n_s ) ) - точная формула, расстояние между точками на сфере
Но эксперименты показали, что время выполнения запроса отличается не глобально (менее чем на 50%):
//time, сек
//0.00992703
//0.01079202
//0.01407814
Поэтому было решено оставить точную формулу вычисления расстояния между двумя точками на сфере.
Получаем функцию для извлечения объектов из БД упорядоченных по удаленности от центра с известными координатами.
function sellect_all_sort_dist($E,$N, $radius, $id, $num) $E, $N – координаты центра (долгота и широта); $radius – сторона квадрата в пределах которой берем данные из БД для сортировки; $id – id элемента, который нужно исключить из выборки $num – ограничение по количеству. Код функции sellect_all_sort_dist приведен ниже: <?php //$result = selllect_all(34.44,50.32, 100000, '', 30); $result = sellect_all_sort_dist(34.44,50.32, 100000, '', 30); var_dump($result); function sellect_all_sort_dist($E,$N, $radius, $id, $num) { //подключаемся к БД require_once "config_sec728312167.php"; try{ $conn = new PDO("mysql:host=localhost;dbname=".$database, $user, $pswd, array( PDO::ATTR_CASE=>PDO::CASE_NATURAL, PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true, PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC )); }catch(PDOException $e){ echo 'ERROR: ' . $e->getMessage(); } //$conn->query('SET character_set_connection=utf8mb4;'); //$conn->query('SET character_set_connection=utf8mb4_general_ci;'); //$conn->query('SET character_set_connection=utf8_general_ci;'); $conn->query('SET character_set_connection=utf8mb4;'); $obj_prep = $conn->query('set character_set_results="utf8"'); $itemID = $id; $koord_e = $E; $koord_n = $N; //echo " e_s=".$koord_e." n_s=".$koord_n." <br>"; $km_limit = $radius; $n_min = $koord_n-$km_limit/80; $n_max = $koord_n+$km_limit/80; $e_min = $koord_e-$km_limit/80; $e_max = $koord_e+$km_limit/80; //делаем запрос на поиск(лимит - 10 строк) $time = microtime(1); $sql_sel = '6372795*atan2(sqrt(pow(cos(:n_s*PI()/180) * sin(:e_s*PI()/180 - E*PI()/180), 2) + pow(cos(N*PI()/180) * sin(:n_s*PI()/180) - sin(N*PI()/180) * cos(:n_s*PI()/180) * cos(:e_s*PI()/180 - E*PI()/180), 2)), sin(N*PI()/180) * sin(:n_s*PI()/180) + cos(N*PI()/180) * cos(:n_s*PI()/180) * cos(:e_s*PI()/180 - E*PI()/180))'; if (strlen(''.$itemID) > 0) $srch_prep = $conn->prepare(' SELECT '.$sql_sel.' AS d,itemID, radius,E,N,photo FROM gorod WHERE N >= :n_min AND N <= :n_max AND E >= :e_min AND E <= :e_max AND itemID != :itemID ORDER BY d ASC LIMIT '.$num); else $srch_prep = $conn->prepare(' SELECT '.$sql_sel.' AS d,itemID, radius,E,N,photo FROM gorod WHERE N >= :n_min AND N <= :n_max AND E >= :e_min AND E <= :e_max ORDER BY d ASC LIMIT '.$num); $srch_prep->execute(array( ':n_min'=>$n_min, ':n_max'=>$n_max, ':e_min'=>$e_min, ':e_max'=>$e_max, ':n_s'=>$koord_n, ':e_s'=>$koord_e, ':itemID'=>$itemID )); $srch = $srch_prep->fetchAll();//получаем все записи //echo number_format(microtime(1)-$time, 8); //echo "c. <hr/>"; //var_dump($srch); return $srch; } ?>
Пример вызова скрипта: http://galleryua.com/photo/townnear.php?E=49.94722&N=24.07417&radius=100...
Недоработкой данного скрипта является то, что он осуществляет лишние запросы к БД. Лишних запросов ровно столько, сколько объектов для вывода информации о них.
Теперь нам нужно продумать структуру таблицы с объектами и немного усложнить ее:
Таблица с информацией об объекте будет выглядеть так:
itemID - id объекта (первичный ключ)
type - тип объекта (пока не используется, просто зарезервировано)
title - навание объекта
koord_txt - координаты в тестовом виде
radius - радиус объекта
E,N - координаты в числовом виде
photo - путь у обложке (если начинается не с http:// , то это id каринки на panoramio)
photos - фотоальбом
num_photos - число фото в фотоальбоме
videos - видео
num_videos - количество видео
cat_id - id категории
info - информация
raspolog – расположение
Но нам нужно перенести поле title из другой таблицы (движка joomla). Сделаем это простым PHP скриптом
Увидим в PhpMyAdmin такой запрос:
SELECT `id` , `title` FROM `x09qm_k2_items`
Его и используем в нашем скрипте:
<?php //подключаемся к БД require_once "../config_sec728312167.php"; //echo $host." ".$user." ".$pswd." ".$database."<br>"; //устанавливаем соедиение с БД $dbh = mysql_connect($host, $user, $pswd) or die("Не могу соединиться с MySQL."); mysql_select_db($database) or die("Не могу подключиться к базе."); mysql_set_charset('SET NAMES UTF-8'); // в какой кодировке получать данные от клиента @mysql_query('set character_set_client="utf8"'); // в какой кодировке получать данные от БД для вывода клиенту @mysql_query('set character_set_results="utf8"'); // кодировка в которой будут посылаться служебные команды для сервера @mysql_query('set collation_connection="utf8_general_ci"'); $query = "SELECT `id` , `title` FROM `x09qm_k2_items` WHERE `published` =1 AND id <= 29355 ORDER BY `id` ASC"; $res = mysql_query($query); if($res) { while($row = mysql_fetch_object($res)) { echo "UPDATE `galleryua_gallerist`.`gorod` SET `title` = '".$row->title."' WHERE `gorod`.`itemID` ='".$row->id."' LIMIT 1;"; //print_r($row); echo "<br>"; } } else { echo "<p><b>Error: ".mysql_error()."</b><p>"; exit(); } ?>
Пари выполнения скрипта:
http://galleryua.com/dvijok-my-tourizm/sql_utility/select_title_from_ite...
Получаем на выходе 32952 строки для обновления в БД таблицы `gorod`.
UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Винница , Винницкая область' WHERE `gorod`.`itemID` ='1' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Жмеринка' WHERE `gorod`.`itemID` ='2' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Могилев-Подольский' WHERE `gorod`.`itemID` ='3' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Хмельник' WHERE `gorod`.`itemID` ='4' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Александрия' WHERE `gorod`.`itemID` ='5' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Знаменка' WHERE `gorod`.`itemID` ='6' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Кировоград' WHERE `gorod`.`itemID` ='7' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'г. Светловодск' WHERE `gorod`.`itemID` ='8' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'с. Авксенивка' WHERE `gorod`.`itemID` ='9' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'с. Адалимовка' WHERE `gorod`.`itemID` ='10' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'с. Акимовка' WHERE `gorod`.`itemID` ='11' LIMIT 1; UPDATE `galleryua_gallerist`.`gorod` SET `title` = 'с. Андреевка' WHERE `gorod`.`itemID` ='12' LIMIT 1;
Импортируем данные в БД. Для этого создаем файл gorod_title.sql. Можно и сразу писать команды SQL в файл:
file_put_contents("gorod_title.sql",$sql."\r\n",FILE_APPEND | LOCK_EX);
Для импорта данных используем команду через SSH:
mysql -uroot -p -f galleryua_gallerist < /var/www/gallery/data/www/galleryua.com/dvijok-my-tourizm/sql_utility/gorod_title.sql
Импорт при таком подходе займет достаточно много времени, более часа.
На будущем воспользуемся скриптом, который выведет все неопределенные населенные пункты, т.е. непонятно, являются они городом, пгт, селом или поселком:
SELECT `id`, `title` FROM `x09qm_k2_items` WHERE `title` NOT LIKE '%с.%' AND `title` NOT LIKE '%г.%' AND `title` NOT LIKE '%пгт %' AND `title` NOT LIKE '%поселок %' AND `published` = 1 ORDER BY `id` ASC
После импорта имеем возможность упростить скрипт для построения списка ближайших объектов.
Текущее состояние скрипта здесь: http://galleryua.com/dvijok-my-tourizm/lib/townnear-ver/townnear-1.php
ЧАСТЬ 2. КЕШИРОВАНИЕ
Простая и эффективная система кеширования PHP
Во время разработки проектов на PHP с нуля и без использования библиотек скорость может стать серьезным вопросом. Кеширование может существенно повлиять на скорость веб страниц. В данном уроке мы покажем простой и эффективный способ динамического кеширования страниц, которые нуждаются в ускорении.
Шаг первый. Создаем файл top-cache.php
Нам нужно создать два файла. Первый: создаем файл с именем top-cache.php и копируем в него следующий код:
<?php $url = $_SERVER["SCRIPT_NAME"]; $break = Explode('/', $url); $file = $break[count($break) - 1]; $cachefile = 'cached-'.substr_replace($file ,"",-4).'.html'; $cachetime = 18000; // Обслуживается из файла кеша, если время запроса меньше $cachetime if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) { echo "<!-- Cached copy, generated ".date('H:i', filemtime($cachefile))." -->\n"; include($cachefile); exit; } ob_start(); // Запуск буфера вывода ?>
Что происходит в данном коде? Первые 5 строк создают имя файла кеша в соответствии с текущем PHP файлом. Например, если мы используем файл с именем list.php, файл кеша будет иметь вид cached-list.html.
Строка 6 создает переменную $cachetime, которая определяет время жизни кеша.
Строки с 9 по 13 определяют условное выражение, которое служит для проверки наличия файла с именем, определенным в переменной $cachefile. Если файл существует, вставляется комментарий и файл, определенный в переменной $cachefile. Затем выражение exit прерывает выполнение скрипта и файл отправляется браузеру клиента. То есть, если найден статичный файл, то PHP код не будет выполняться сервером.
Строка 14 создает буфер, если файл, определенный переменной $cachefile не найден.
Шаг второй. Создаем файл bottom-cache.php
Теперь создаем второй файл PHP с именем bottom-cache.php и копируем в него следующий код:
<?php // Кешируем содержание в файл $cached = fopen($cachefile, 'w'); fwrite($cached, ob_get_contents()); fclose($cached); ob_end_flush(); // Отправялем вывод в браузер ?>
Если файл с именем, определенным в переменной $cachefile отсутствует на сервере, выполняется данный код и создается файл. При следующем обращении к странице статичный $cachefile будет обслуживать браузер клиента вместо выполнения всего кода скрипта PHP.
Шаг три. Включаем файлы кеширования в код страницы
Теперь у нас есть два необходимых файла. Просто включаем их в страницу PHP, которую нужно кешировать. Файл top-cache.php нужно включить в начало страницы, а файл bottom-cache.php - в конце:
<?php include('top-cache.php'); // Код страницы определяется здесь include('bottom-cache.php'); ?>
Теперь, если проверить кеширование на медленных страницах, то можно убедиться, насколько они стали быстрее загружаться.
Система кэширования будет состоять из 2-ух частей.
Часть 1 системы кэширования будет отвечать за кэширование результатов полученных посредством загрузки внешних данных с сайтов panoramio, youtube и rp5.
Часть 2 системы кэширования будет отвечать за кэширование результатов извлеченных из БД.
Ядро будет собирать страницу из кэшей как конструктор и следить за своевременным обновлением кэша.
Часть 1. Кэширование JS.
В тех местах, где JS получает данные извне (panoramio, youtube и rp5) кэшируем эти данные, закодировав их при необходимости в json формат следующим образом:
$.post( "api-save-panoramio.php", {data:{"result":JSON.stringify(data.photos)}});
См. пример http://galleryua.com/dvijok-my-tourizm/lib/jquery.panoramio.js
Строка 172:
В этот момент массив, который получит с сервера panoramio кодируется в json-формат посредством метода JSON.stringify(data.photos) и передается файлу api-save-panoramio.php, который лежит в той же папке, что и jquery.panoramio.js.
В данном примере файл api-save-panoramio.php выполняет следующий код:
<?php file_put_contents("../cache/panoramio/str.txt", $_POST[]); ?> Т.е. в папку кэша кладется массив. Извлекаем json-массив из кэша следующим образом: <?php $str = file_get_contents("../cache/panoramio/str.txt"); //echo $str."<br>"; var_dump(json_decode(str_replace("\\\"","\"",$str))); ?>
str_replace("\\\"","\"",$str) – убирает экранирование кавычки, по умолчанию выполненное JS, иначе json просто не раскадируется.
Логика использования кэша будет следующая. Если при открытии страницы файл с кэшем существует и время его жизни не превысило $cache_max_time, то будем выводить его на странице. Если время жизни кэша превысило максимально допустимый срок, тогда выведем
Добавление метатегов, коордиат и другой информации.
Добавим в таблицу `gorod` необходимые поля для хранения информации о мета-тегах.
`seo_title` text COLLATE utf8_unicode_ci NOT NULL, `seo_description` text COLLATE utf8_unicode_ci NOT NULL, `seo_keywords` text COLLATE utf8_unicode_ci NOT NULL
Причем, предусмотрим ситуацию такую: если эти поля не заполнены, то метатеги должны генерироваться автоматически при генерации страницы.
Первое, что пришло в голову, это перетащить джумловскую таблицу `x09qm_plg_easyfrontendseo` на новый движок. Посмотрев, на ее размеры, я понял, что нужно что-то оптимизировать.
Итак, сейчас в нашей базе содержатся такие объекты:
город (название начинается с «г. ») – 434 объекта (судя по википедии должно быть 460);
поселок городского типа (название начинается с «пгт ») – 846 объекта (судя по википедии должно быть 885);
село (название начинается с «с. ») – 26508 объекта;
поселок (название начинается с «поселок ») – 1273 объекта;
По википедии села и поселки составляют количество 28397 штук.
Посмотрим на формат сгенерированных метатегов:
Село:
Title: Фото, достопримечательности, почтовый индекс села Видава (Волочисский район, Хмельницкая область) на карте Украины
description: Карта с. Видава, Волочисский район, Хмельницкая область с фотографиями и достопримечательностями, почтовый индекс села Видава, Украина
keywords: Фотографии Украины, фото с. Видава, Волочисский район, Хмельницкая область, достопримечательности села Видава, почтовый индекс с. Видава в
пгт:
Title: Фото, достопримечательности, почтовый индекс поселка городского типа Войтовца (Волочисский район, Хмельницкая область) на карте Украины
description: Карта пгт Войтовца, Волочисский район, Хмельницкая область с фотографиями и достопримечательностями, почтовый индекс поселка городского типа Войтовца, Украина
keywords: Фотографии Украины, фото пгт Войтовца, Волочисский район, Хмельницкая область, достопримечательности поселка городского типа Войтовца, по
город:
Title: Фото, достопримечательности, почтовый индекс города Волочиск (Волочисский район, Хмельницкая область) на карте Украины
description: Карта г. Волочиск, Волочисский район, Хмельницкая область с фотографиями и достопримечательностями, почтовый индекс города Волочиск, Украина
keywords: Фотографии Украины, фото г. Волочиск, Волочисский район, Хмельницкая область, достопримечательности города Волочиск, почтовый индекс г. Во
поселок:
Title: Фото, достопримечательности, почтовый индекс поселка Цегельное (Волчанский район, Харьковская область) на карте Украины
description: Карта п. Цегельное, Волчанский район, Харьковская область с фотографиями и достопримечательностями, почтовый индекс поселка Цегельное, Украина
keywords: Фотографии Украины, фото п. Цегельное, Волчанский район, Харьковская область, достопримечательности поселка Цегельное, почтовый индекс п.
Тип не определен:
Title: Фото, достопримечательности, почтовый индекс Руднично (г. Кривой Рог, Днепропетровская область) на карте Украины
description: Карта Руднично, г. Кривой Рог, Днепропетровская область с фотографиями и достопримечательностями, почтовый индекс Руднично, Украина
keywords: Фотографии Украины, фото Руднично, г. Кривой Рог, Днепропетровская область, достопримечательности Руднично, почтовый индекс Руднично в У
В общем нет ничего проще, чем сгенерировать такое на лету! Единственное, нужно знать расположение (район, область).
- Для комментирования войдите или зарегистрируйтесь