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

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 для запоминания открытой вкладки.

Установка.

  1. Разметка. В тег <div id="k2Container" class="itemView"> необходимо вставить разделы Tabs и Sections:
  2. <!-- 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 -->
    
  3. Стили. В файле стилей style.css необходимо вставить раздел Tabs:
  4. /* --- 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;}
    

    И при необходимости подкорректировать их в зависимости от шаблона.

  5. Скрипты. Необходимо подключить файлы cookie.js и tabs.js. cookie.js подключается в <head>. tabs.js подключается перед закрывающим тегом </body>
  6. <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...

карты google

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 скриптом

перенос поля title

Увидим в 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. КЕШИРОВАНИЕ

http://ruseller.com/lessons.php?rub=37&id=1555

Простая и эффективная система кеширования 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:

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

В общем нет ничего проще, чем сгенерировать такое на лету! Единственное, нужно знать расположение (район, область).

Print Friendly Version of this pagePrint Get a PDF version of this webpagePDF