Мой первый собственный движок для сайта достопримечательностей
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: Фотографии Украины, фото Руднично, г. Кривой Рог, Днепропетровская область, достопримечательности Руднично, почтовый индекс Руднично в У
В общем нет ничего проще, чем сгенерировать такое на лету! Единственное, нужно знать расположение (район, область).
- Для комментирования войдите или зарегистрируйтесь
